Browse Source

use ClientLocation refactor

pbs
jake 5 years ago
parent
commit
9c643e2aae
  1. 524
      src/ship/location.rs
  2. 221
      src/ship/ship.rs

524
src/ship/location.rs

@ -1,79 +1,15 @@
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use std::convert::Into;
use std::time::SystemTime;
use crate::common::serverstate::ClientId;
// TODO: room passwords?
// TODO: remove clients from areas (or upon insert, remove that id from anywhere else)
pub const MAX_ROOMS: usize = 128;
#[derive(Copy, Clone)]
pub struct AreaClient {
client_id: ClientId,
time_join: SystemTime,
}
#[derive(Copy, Clone)]
pub struct InnerClientArea<const N: usize> {
clients: [Option<AreaClient>; N],
}
impl<const N: usize> InnerClientArea<{N}> {
pub fn new() -> InnerClientArea<{N}> {
let mut clients: [std::mem::MaybeUninit<Option<AreaClient>>; N] = unsafe {
std::mem::MaybeUninit::uninit().assume_init()
};
for i in clients.iter_mut() {
i.write(None);
}
InnerClientArea {
clients: unsafe { (&clients as *const _ as *const [Option<AreaClient>; N]).read()}
}
}
fn add(&mut self, id: ClientId) -> Option<usize> {
for (i, client) in self.clients.iter_mut().enumerate() {
if client.is_none() {
*client = Some(AreaClient{
client_id: id,
time_join: SystemTime::now(),
});
return Some(i);
}
}
return None;
}
fn remove(&mut self, id: ClientId) -> bool {
for areaclient in self.clients.iter_mut() {
if let Some(client) = *areaclient {
if client.client_id == id {
*areaclient = None;
return true;
}
}
}
false
}
fn contains(&self, id: ClientId) -> bool {
self.clients.iter()
.filter(|k| k.is_some())
.map(|k| k.unwrap() )
.fold(false, |acc, k| {
if acc {
acc
}
else if k.client_id == id {
true
}
else {
false
}
})
}
pub enum AreaType {
Room,
Lobby,
}
@ -82,101 +18,12 @@ pub struct LobbyId(pub usize);
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct RoomId(pub usize);
pub type Lobby = InnerClientArea<12>;
pub type Room = InnerClientArea<4>;
trait ClientArea {
fn clients(&self) -> std::slice::Iter<'_, Option<AreaClient>>;
fn remove(&mut self, id: ClientId) -> bool;
}
impl ClientArea for Lobby {
fn clients(& self) -> std::slice::Iter<'_, Option<AreaClient>> {
self.clients.iter()
}
fn remove(&mut self, id: ClientId) -> bool {
self.remove(id)
impl LobbyId {
pub fn id(&self) -> u8 {
self.0 as u8
}
}
impl<'a> ClientArea for Room {
fn clients(& self) -> std::slice::Iter<'_, Option<AreaClient>> {
self.clients.iter()
}
fn remove(&mut self, id: ClientId) -> bool {
self.remove(id)
}
}
pub enum AreaType {
Lobby,
Room,
}
#[derive(Debug)]
pub struct ClientAtLocation {
pub client_id: ClientId,
pub index: usize,
}
pub struct Area {
pub area_type: AreaType,
area: Arc<RwLock<dyn ClientArea>>,
index: usize,
}
impl Area {
fn new(area_type: AreaType, area: Arc<RwLock<dyn ClientArea>>, index: usize) -> Area {
Area {
area_type: area_type,
area: area,
index: index,
}
}
pub fn clients(&self) -> Vec<ClientAtLocation> {
self.area.read().unwrap().clients()
.enumerate()
.filter(|(_i, k)| k.is_some())
.map(|(i, k)| (i, k.unwrap()) )
.map(|(i, k)| ClientAtLocation {
client_id: k.client_id,
index: i
}).collect()
}
// TODO: Result in cases where no one is in the area?
pub fn leader(&self) -> ClientAtLocation {
self.area.read().unwrap().clients()
.enumerate()
.filter(|(_i, k)| k.is_some())
.map(|(i, k)| (i, k.unwrap()) )
.fold((ClientAtLocation {
client_id: ClientId(0),
index: 0
}, SystemTime::UNIX_EPOCH),
|(acc, time), (i, k)| {
if time > k.time_join {
(ClientAtLocation {
client_id: k.client_id,
index: i,
}, k.time_join)
}
else {
(acc, time)
}
}).0
}
pub fn remove(&mut self, id: ClientId) -> bool {
self.area.write().unwrap().remove(id)
}
pub fn id(&self) -> usize {
self.index
}
}
#[derive(Debug, PartialEq)]
pub enum CreateRoomError {
@ -199,146 +46,38 @@ pub enum JoinLobbyError {
ClientInAreaAlready,
}
pub struct ClientLocation {
lobbies: [Arc<RwLock<Lobby>>; 15],
rooms: [Option<Arc<RwLock<Room>>>; MAX_ROOMS],
}
impl ClientLocation {
pub fn new() -> ClientLocation {
ClientLocation {
//lobbies: [Arc::new(RwLock::new(Lobby::new())); 15],
lobbies: crate::init_array!(Arc<RwLock<Lobby>>, 15, Arc::new(RwLock::new(Lobby::new()))),
rooms: [None; MAX_ROOMS],
}
}
fn err_if_client_is_in_area<E>(&mut self, id: ClientId, err: E) -> Result<(), E> {
let in_lobby = self.lobbies.iter()
.any(|k| k.read().unwrap().contains(id));
let in_room = self.rooms.iter()
.filter(|k| k.is_some())
.map(|k| k.as_ref().unwrap())
.any(|k| k.read().unwrap().contains(id));
if in_lobby || in_room {
Err(err)
}
else {
Ok(())
}
}
pub fn add_to_lobby(&mut self, id: ClientId, lobby: LobbyId) -> Result<usize, JoinLobbyError> {
self.err_if_client_is_in_area(id, JoinLobbyError::ClientInAreaAlready)?;
self.lobbies.get_mut(lobby.0)
.ok_or(JoinLobbyError::LobbyDoesNotExist)?
.write().unwrap()
.add(id)
.ok_or(JoinLobbyError::LobbyFull)
}
pub fn new_room(&mut self, id: ClientId) -> Result<RoomId, CreateRoomError> {
let (room_id, empty_room) = self.rooms.iter_mut()
.enumerate()
.filter(|(_, k)| k.is_none())
.nth(0)
.ok_or(CreateRoomError::NoOpenSlots)?;
let mut new_room = Room::new();
new_room.add(id);
*empty_room = Some(Arc::new(RwLock::new(new_room)));
self.remove_from_location(id);
Ok(RoomId(room_id))
}
pub fn add_to_room(&mut self, id: ClientId, room: RoomId) -> Result<usize, JoinRoomError> {
self.err_if_client_is_in_area(id, JoinRoomError::ClientInAreaAlready)?;
self.rooms.get_mut(room.0)
.ok_or(JoinRoomError::RoomDoesNotExist)?
.as_mut()
.ok_or(JoinRoomError::RoomDoesNotExist)?
.write().unwrap()
.add(id)
.ok_or(JoinRoomError::RoomFull)
}
pub fn get_area_by_user(&mut self, id: ClientId) -> Area {
for (i, lobby) in self.lobbies.iter().enumerate() {
if lobby.read().unwrap().contains(id) {
return Area::new(AreaType::Lobby, lobby.clone(), i);
}
}
for (i, room) in self.rooms.iter().enumerate() {
if let Some(room) = room {
if room.read().unwrap().contains(id){
return Area::new(AreaType::Room, room.clone(), i);
}
}
}
panic!("client is not in a room/lobby")
}
pub fn remove_from_location(&mut self, id: ClientId) {
let in_lobby = self.lobbies.iter_mut()
.map(|lobby| lobby.write().unwrap().remove(id))
.any(|k| k);
if in_lobby {
return;
}
self.rooms.iter_mut()
.filter(|lobby| lobby.is_some())
.map(|lobby| lobby.as_ref().unwrap())
.map(|lobby| lobby.write().unwrap().remove(id))
.any(|k| k);
}
pub fn get_client_count_in_room(&self, room_id: RoomId) -> u8 {
self.rooms[room_id.0].as_ref()
.unwrap()
.read()
.unwrap()
.clients()
.filter(|k| k.is_some())
.count() as u8
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct LocalClientId(usize);
#[derive(Debug, Copy, Clone, PartialEq)]
struct RoomClient {
client: ClientId,
local_client: LocalClientId,
time_join: SystemTime,
impl LocalClientId {
pub fn id(&self) -> u8 {
self.0 as u8
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
struct AreaClient2 {
client: ClientId,
local_client: LocalClientId,
pub struct AreaClient {
pub client: ClientId,
pub local_client: LocalClientId,
time_join: SystemTime,
}
#[derive(Debug, Copy, Clone, PartialEq)]
struct Lobby2([Option<AreaClient2>; 12]);
struct Lobby([Option<AreaClient>; 12]);
#[derive(Debug, Copy, Clone, PartialEq)]
struct Room2([Option<AreaClient2>; 4]);
struct Room([Option<AreaClient>; 4]);
#[derive(Debug, Copy, Clone, PartialEq)]
enum RoomLobby {
pub enum RoomLobby {
Room(RoomId),
Lobby(LobbyId),
}
#[derive(Debug, PartialEq)]
pub enum GetAreaError {
InvalidClient,
}
#[derive(Debug, PartialEq)]
pub enum ClientRemovalError {
ClientNotInArea,
@ -347,6 +86,7 @@ pub enum ClientRemovalError {
#[derive(Debug, PartialEq)]
pub enum GetClientsError {
InvalidClient,
InvalidArea,
}
@ -363,16 +103,16 @@ pub enum GetLeaderError {
NoClientInArea,
}
pub struct ClientLocation2 {
lobbies: [Lobby2; 15],
rooms: [Option<Room2>; MAX_ROOMS],
pub struct ClientLocation {
lobbies: [Lobby; 15],
rooms: [Option<Room>; MAX_ROOMS],
client_location: HashMap<ClientId, RoomLobby>,
}
impl ClientLocation2 {
pub fn new() -> ClientLocation2 {
ClientLocation2 {
lobbies: [Lobby2([None; 12]); 15],
impl ClientLocation {
pub fn new() -> ClientLocation {
ClientLocation {
lobbies: [Lobby([None; 12]); 15],
rooms: [None; MAX_ROOMS],
client_location: HashMap::new(),
}
@ -385,7 +125,7 @@ impl ClientLocation2 {
.filter(|(_, k)| k.is_none())
.nth(0)
.ok_or(JoinLobbyError::LobbyFull)?;
*empty_slot = Some(AreaClient2 {
*empty_slot = Some(AreaClient {
client: id,
local_client: LocalClientId(index),
time_join: SystemTime::now(),
@ -411,19 +151,19 @@ impl ClientLocation2 {
Ok(l.0)
}
fn create_new_room(&mut self, id: ClientId) -> Result<RoomId, CreateRoomError> {
pub fn create_new_room(&mut self, id: ClientId) -> Result<RoomId, CreateRoomError> {
let (index, empty_slot) = self.rooms.iter_mut()
.enumerate()
.filter(|(_, r)| r.is_none())
.nth(0)
.ok_or(CreateRoomError::NoOpenSlots)?;
*empty_slot = Some(Room2([None; 4]));
*empty_slot = Some(Room([None; 4]));
self.add_client_to_room(id, RoomId(index)).map_err(|err| CreateRoomError::JoinError)?;
Ok(RoomId(index))
}
fn add_client_to_room(&mut self, id: ClientId, room: RoomId) -> Result<(), JoinRoomError> {
pub fn add_client_to_room(&mut self, id: ClientId, room: RoomId) -> Result<(), JoinRoomError> {
let r = self.rooms.get_mut(room.0)
.ok_or(JoinRoomError::RoomDoesNotExist)?
.as_mut()
@ -433,7 +173,7 @@ impl ClientLocation2 {
.filter(|(_, k)| k.is_none())
.nth(0)
.ok_or(JoinRoomError::RoomFull)?;
*empty_slot = Some(AreaClient2 {
*empty_slot = Some(AreaClient {
client: id,
local_client: LocalClientId(index),
time_join: SystemTime::now(),
@ -444,69 +184,129 @@ impl ClientLocation2 {
}
fn get_client_neighbors(&self, id: ClientId) -> Result<Vec<(ClientId, LocalClientId)>, GetNeighborError> {
pub fn get_all_clients_by_client(&self, id: ClientId) -> Result<Vec<AreaClient>, GetNeighborError> {
let area = self.client_location.get(&id).ok_or(GetNeighborError::InvalidClient)?;
match area {
RoomLobby::Room(room) => {
Ok(self.get_clients_in_room(*room).map_err(|_| GetNeighborError::InvalidArea)?
.into_iter()
.filter(|c| c.0 != id)
.collect())
.into_iter()
.collect())
},
RoomLobby::Lobby(lobby) => {
Ok(self.get_clients_in_lobby(*lobby).map_err(|_| GetNeighborError::InvalidArea)?
.into_iter()
.filter(|c| c.0 != id)
.collect())
.into_iter()
.collect())
}
}
}
fn get_room_leader_by_client(&self, id: ClientId) -> Result<(ClientId, LocalClientId), GetLeaderError> {
pub fn get_client_neighbors(&self, id: ClientId) -> Result<Vec<AreaClient>, GetNeighborError> {
let area = self.client_location.get(&id).ok_or(GetNeighborError::InvalidClient)?;
match area {
RoomLobby::Room(room) => {
Ok(self.get_clients_in_room(*room).map_err(|_| GetNeighborError::InvalidArea)?
.into_iter()
.filter(|c| c.client != id)
.collect())
},
RoomLobby::Lobby(lobby) => {
Ok(self.get_clients_in_lobby(*lobby).map_err(|_| GetNeighborError::InvalidArea)?
.into_iter()
.filter(|c| c.client != id)
.collect())
}
}
}
pub fn get_room_leader(&self, room: RoomId) -> Result<AreaClient, GetLeaderError> {
let mut r = self.rooms[room.0]
.as_ref()
.ok_or(GetLeaderError::InvalidArea)?
.0.iter().flat_map(|k| k)
.collect::<Vec<_>>();
r.sort_by_key(|k| k.time_join);
let c = r.get(0).ok_or(GetLeaderError::NoClientInArea)?;
Ok(**c)
}
pub fn get_lobby_leader(&self, lobby: LobbyId) -> Result<AreaClient, GetLeaderError> {
let mut l = self.lobbies[lobby.0]
.0.iter().flat_map(|k| k)
.collect::<Vec<_>>();
l.sort_by_key(|k| k.time_join);
let c = l.get(0).ok_or(GetLeaderError::NoClientInArea)?;
Ok(**c)
}
pub fn get_area_leader(&self, roomlobby: RoomLobby) -> Result<AreaClient, GetLeaderError> {
match roomlobby {
RoomLobby::Room(room) => {
self.get_room_leader(room)
},
RoomLobby::Lobby(lobby) => {
self.get_lobby_leader(lobby)
}
}
}
pub fn get_leader_by_client(&self, id: ClientId) -> Result<AreaClient, GetLeaderError> {
let area = self.client_location.get(&id).ok_or(GetLeaderError::InvalidClient)?;
match area {
RoomLobby::Room(room) => {
let mut r = self.rooms[room.0]
.as_ref()
.ok_or(GetLeaderError::InvalidArea)?
.0.iter().flat_map(|k| k)
.collect::<Vec<_>>();
//r.sort_by(|a, b| a.time_join.cmp(&b.time_join));
r.sort_by_key(|k| k.time_join);
let c = r.get(0).ok_or(GetLeaderError::NoClientInArea)?;
Ok((c.client, c.local_client))
self.get_room_leader(*room)
},
RoomLobby::Lobby(lobby) => {
let mut l = self.lobbies[lobby.0]
.0.iter().flat_map(|k| k)
.collect::<Vec<_>>();
l.sort_by_key(|k| k.time_join);
let c = l.get(0).ok_or(GetLeaderError::NoClientInArea)?;
Ok((c.client, c.local_client))
self.get_lobby_leader(*lobby)
}
}
}
pub fn get_clients_in_lobby(&self, lobby: LobbyId) -> Result<Vec<(ClientId, LocalClientId)>, GetClientsError> {
pub fn get_clients_in_lobby(&self, lobby: LobbyId) -> Result<Vec<AreaClient>, GetClientsError> {
Ok(self.lobbies.get(lobby.0).ok_or(GetClientsError::InvalidArea)?.0
.iter()
.filter_map(|client| {
client.map(|c| {
(c.client, c.local_client)
})
}).collect())
.filter_map(|client| {
client.map(|c| {
c
})
}).collect())
}
pub fn get_clients_in_room(&self, room: RoomId) -> Result<Vec<(ClientId, LocalClientId)>, GetClientsError> {
pub fn get_clients_in_room(&self, room: RoomId) -> Result<Vec<AreaClient>, GetClientsError> {
Ok(self.rooms.get(room.0)
.ok_or(GetClientsError::InvalidArea)?
.ok_or(GetClientsError::InvalidArea)?.0
.iter()
.filter_map(|client| {
client.map(|c| {
(c.client, c.local_client)
})
}).collect())
.filter_map(|client| {
client.map(|c| {
c
})
}).collect())
}
pub fn get_local_client(&self, id: ClientId) -> Result<AreaClient, GetClientsError> {
let area = self.client_location.get(&id).ok_or(GetClientsError::InvalidClient)?;
match area {
RoomLobby::Room(room) => {
self.get_clients_in_room(*room).map_err(|_| GetClientsError::InvalidArea)?
.into_iter()
.filter(|c| c.client == id)
.nth(0)
.ok_or(GetClientsError::InvalidClient)
},
RoomLobby::Lobby(lobby) => {
self.get_clients_in_lobby(*lobby).map_err(|_| GetClientsError::InvalidArea)?
.into_iter()
.filter(|c| c.client == id)
.nth(0)
.ok_or(GetClientsError::InvalidClient)
}
}
}
pub fn get_area(&self, id: ClientId) -> Result<RoomLobby, GetAreaError> {
self.client_location.get(&id)
.ok_or(GetAreaError::InvalidClient)
.map(Clone::clone)
}
pub fn remove_client_from_area(&mut self, id: ClientId) -> Result<(), ClientRemovalError> {
@ -549,20 +349,20 @@ mod test {
#[test]
fn test_add_client_to_lobby() {
let mut cl = ClientLocation2::new();
let mut cl = ClientLocation::new();
cl.add_client_to_lobby(ClientId(12), LobbyId(0));
cl.add_client_to_lobby(ClientId(13), LobbyId(1));
cl.add_client_to_lobby(ClientId(14), LobbyId(0));
assert!(cl.get_clients_in_lobby(LobbyId(0)) == Ok(vec![
assert!(cl.get_clients_in_lobby(LobbyId(0)).into_iter().flatten().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
(ClientId(12), LocalClientId(0)),
(ClientId(14), LocalClientId(1)),
]));
]);
}
#[test]
fn test_add_client_to_full_lobby() {
let mut cl = ClientLocation2::new();
let mut cl = ClientLocation::new();
(0..12).for_each(|i| {
cl.add_client_to_lobby(ClientId(i), LobbyId(0));
});
@ -571,7 +371,7 @@ mod test {
#[test]
fn test_add_client_to_next_available_lobby() {
let mut cl = ClientLocation2::new();
let mut cl = ClientLocation::new();
(1..4).for_each(|lobby| {
(0..12).for_each(|i| {
cl.add_client_to_lobby(ClientId(lobby*12+i), LobbyId(lobby));
@ -582,7 +382,7 @@ mod test {
#[test]
fn test_add_to_lobby_when_all_are_full() {
let mut cl = ClientLocation2::new();
let mut cl = ClientLocation::new();
(0..15).for_each(|lobby| {
(0..12).for_each(|i| {
cl.add_client_to_lobby(ClientId(lobby*12+i), LobbyId(lobby));
@ -593,24 +393,24 @@ mod test {
#[test]
fn test_new_room() {
let mut cl = ClientLocation2::new();
let mut cl = ClientLocation::new();
assert!(cl.create_new_room(ClientId(12)) == Ok(RoomId(0)));
}
#[test]
fn test_add_client_to_room() {
let mut cl = ClientLocation2::new();
let mut cl = ClientLocation::new();
let room = cl.create_new_room(ClientId(12)).unwrap();
assert!(cl.add_client_to_room(ClientId(234), room) == Ok(()));
assert!(cl.get_clients_in_room(room) == Ok(vec![
assert!(cl.get_clients_in_room(room).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
(ClientId(12), LocalClientId(0)),
(ClientId(234), LocalClientId(1)),
]));
]);
}
#[test]
fn test_no_new_room_slots() {
let mut cl = ClientLocation2::new();
let mut cl = ClientLocation::new();
for i in 0..128 {
cl.create_new_room(ClientId(i));
}
@ -619,7 +419,7 @@ mod test {
#[test]
fn test_joining_full_room() {
let mut cl = ClientLocation2::new();
let mut cl = ClientLocation::new();
let room = cl.create_new_room(ClientId(0)).unwrap();
assert!(cl.add_client_to_room(ClientId(1), room) == Ok(()));
assert!(cl.add_client_to_room(ClientId(2), room) == Ok(()));
@ -629,7 +429,7 @@ mod test {
#[test]
fn test_adding_client_to_room_removes_from_lobby() {
let mut cl = ClientLocation2::new();
let mut cl = ClientLocation::new();
cl.add_client_to_lobby(ClientId(93), LobbyId(0));
cl.add_client_to_lobby(ClientId(23), LobbyId(0));
cl.add_client_to_lobby(ClientId(51), LobbyId(0));
@ -637,75 +437,75 @@ mod test {
let room = cl.create_new_room(ClientId(51)).unwrap();
assert!(cl.add_client_to_room(ClientId(93), room) == Ok(()));
assert!(cl.get_clients_in_lobby(LobbyId(0)) == Ok(vec![
assert!(cl.get_clients_in_lobby(LobbyId(0)).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
(ClientId(23), LocalClientId(1)),
(ClientId(12), LocalClientId(3)),
]));
assert!(cl.get_clients_in_room(room) == Ok(vec![
]);
assert!(cl.get_clients_in_room(room).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
(ClientId(51), LocalClientId(0)),
(ClientId(93), LocalClientId(1)),
]));
]);
}
#[test]
fn test_getting_neighbors() {
let mut cl = ClientLocation2::new();
let mut cl = ClientLocation::new();
cl.add_client_to_lobby(ClientId(93), LobbyId(0));
cl.add_client_to_lobby(ClientId(23), LobbyId(0));
cl.add_client_to_lobby(ClientId(51), LobbyId(0));
cl.add_client_to_lobby(ClientId(12), LobbyId(0));
assert!(cl.get_client_neighbors(ClientId(23)) == Ok(vec![
assert!(cl.get_client_neighbors(ClientId(23)).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
(ClientId(93), LocalClientId(0)),
(ClientId(51), LocalClientId(2)),
(ClientId(12), LocalClientId(3)),
]));
]);
}
#[test]
fn test_failing_to_join_lobby_does_not_remove_from_current_area() {
let mut cl = ClientLocation2::new();
let mut cl = ClientLocation::new();
(0..12).for_each(|i| {
cl.add_client_to_lobby(ClientId(i), LobbyId(0));
});
cl.add_client_to_lobby(ClientId(99), LobbyId(1));
cl.add_client_to_lobby(ClientId(99), LobbyId(0));
assert!(cl.get_clients_in_lobby(LobbyId(0)).unwrap().len() == 12);
assert!(cl.get_clients_in_lobby(LobbyId(1)) == Ok(vec![
assert!(cl.get_clients_in_lobby(LobbyId(1)).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
(ClientId(99), LocalClientId(0)),
]));
]);
}
#[test]
fn test_room_leader() {
let mut cl = ClientLocation2::new();
fn test_get_leader() {
let mut cl = ClientLocation::new();
cl.add_client_to_lobby(ClientId(93), LobbyId(0));
cl.add_client_to_lobby(ClientId(23), LobbyId(0));
cl.add_client_to_lobby(ClientId(51), LobbyId(0));
cl.add_client_to_lobby(ClientId(12), LobbyId(0));
assert!(cl.get_room_leader_by_client(ClientId(51)) == Ok((ClientId(93), LocalClientId(0))));
assert!(cl.get_leader_by_client(ClientId(51)).map(|c| (c.client, c.local_client)) == Ok((ClientId(93), LocalClientId(0))));
}
#[test]
fn test_remove_client_from_room() {
let mut cl = ClientLocation2::new();
let mut cl = ClientLocation::new();
let room = cl.create_new_room(ClientId(51)).unwrap();
cl.add_client_to_room(ClientId(93), room);
cl.add_client_to_room(ClientId(23), room);
cl.remove_client_from_area(ClientId(51));
cl.add_client_to_room(ClientId(12), room);
assert!(cl.get_clients_in_room(room) == Ok(vec![
assert!(cl.get_clients_in_room(room).unwrap().into_iter().map(|c| (c.client, c.local_client)).collect::<Vec<_>>() == vec![
(ClientId(12), LocalClientId(0)),
(ClientId(93), LocalClientId(1)),
(ClientId(23), LocalClientId(2)),
]));
]);
}
#[test]
fn test_room_leader_changes_on_leader_leaving() {
let mut cl = ClientLocation2::new();
fn test_leader_changes_on_leader_leaving() {
let mut cl = ClientLocation::new();
let room = cl.create_new_room(ClientId(51)).unwrap();
cl.add_client_to_room(ClientId(93), room);
cl.add_client_to_room(ClientId(23), room);
@ -714,6 +514,6 @@ mod test {
cl.remove_client_from_area(ClientId(23));
cl.add_client_to_room(ClientId(99), room);
assert!(cl.get_room_leader_by_client(ClientId(12)) == Ok((ClientId(93), LocalClientId(1))));
assert!(cl.get_leader_by_client(ClientId(12)).map(|c| (c.client, c.local_client)) == Ok((ClientId(93), LocalClientId(1))));
}
}

221
src/ship/ship.rs

@ -21,7 +21,7 @@ use crate::entity::account::{UserAccountEntity, UserSettingsEntity, USERFLAG_NEW
use crate::entity::character::CharacterEntity;
use crate::entity::item::{ItemLocation, ItemEntity};
use crate::login::login::get_login_status;
use crate::ship::location::{ClientLocation, LobbyId, RoomId, AreaType, MAX_ROOMS};
use crate::ship::location::{ClientLocation, LobbyId, RoomId, RoomLobby, MAX_ROOMS};
use crate::ship::character::{CharacterBytesBuilder, FullCharacterBytesBuilder};
use crate::ship::items;
use crate::ship::room;
@ -33,6 +33,8 @@ pub enum ShipError {
ClientNotFound(ClientId),
NoCharacterInSlot(ClientId, u32),
InvalidSlot(ClientId, u32),
TooManyClients,
ClientError,
}
#[derive(Debug)]
@ -216,14 +218,11 @@ impl<EG: EntityGateway> ShipServerState<EG> {
}
fn send_player_to_lobby(&mut self, id: ClientId, _pkt: &CharData) -> Result<Vec<(ClientId, SendShipPacket)>, ShipError> {
self.client_location.add_to_lobby(id, LobbyId(0)).unwrap();
let lobby = self.client_location.get_area_by_user(id);
let clients = lobby.clients();
println!("clients in lobby: {:?}", clients);
let lobby = self.client_location.add_client_to_next_available_lobby(id, LobbyId(0)).map_err(|_| ShipError::TooManyClients)?;
let clients = self.client_location.get_clients_in_lobby(lobby).map_err(|_| ShipError::ClientError)?;
let playerinfo = clients.iter()
.map(|room_client| {
let client = self.clients.get(&room_client.client_id).ok_or(ShipError::ClientNotFound(id)).unwrap();
let client = self.clients.get(&room_client.client).ok_or(ShipError::ClientNotFound(id)).unwrap();
let (level, stats) = self.level_table.get_stats_from_exp(client.character.char_class, client.character.exp);
let c = CharacterBytesBuilder::new()
.character(&client.character)
@ -235,7 +234,7 @@ impl<EG: EntityGateway> ShipServerState<EG> {
tag: 0x100,
guildcard: client.user.id.0,
_unknown1: [0; 5],
client_id: room_client.index as u32,
client_id: room_client.local_client.id() as u32,
name: c.name,
_unknown2: 2,
},
@ -249,28 +248,21 @@ impl<EG: EntityGateway> ShipServerState<EG> {
character: c,
}
});
let client_id = clients.iter()
.fold(0, |acc, k| {
if k.client_id == id {
k.index
}
else {
acc
}
});
let area_client = self.client_location.get_local_client(id).map_err(|_| ShipError::ClientError)?;
let leader = self.client_location.get_lobby_leader(lobby).map_err(|_| ShipError::ClientError)?;
let join_lobby = JoinLobby {
client: client_id as u8,
leader: lobby.leader().index as u8,
client: area_client.local_client.id(),
leader: leader.local_client.id(),
one: 1,
lobby: lobby.id() as u8,
lobby: lobby.id(),
block: 1,
event: 0,
padding: 0,
playerinfo: playerinfo.collect(),
};
let client = self.clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap();
let client = self.clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
let (level, stats) = self.level_table.get_stats_from_exp(client.character.char_class, client.character.exp);
let c = CharacterBytesBuilder::new()
.character(&client.character)
@ -279,10 +271,10 @@ impl<EG: EntityGateway> ShipServerState<EG> {
.build();
let addto = AddToLobby {
flag: 1,
client: client_id as u8,
leader: lobby.leader().index as u8,
client: area_client.local_client.id(),
leader: leader.local_client.id(),
one: 1,
lobby: lobby.id() as u8,
lobby: lobby.id(),
block: 1,
event: 0,
padding: 0,
@ -291,7 +283,7 @@ impl<EG: EntityGateway> ShipServerState<EG> {
tag: 0x100,
guildcard: client.user.id.0,
_unknown1: [0; 5],
client_id: client_id as u32,
client_id: area_client.local_client.id() as u32,
name: c.name,
_unknown2: 2,
},
@ -306,26 +298,40 @@ impl<EG: EntityGateway> ShipServerState<EG> {
},
};
let mut v = Vec::new();
v.push((id, SendShipPacket::JoinLobby(join_lobby)));
for client in clients {
if client.client_id != id {
v.push((client.client_id, SendShipPacket::AddToLobby(addto.clone()))
)}
}
Ok(v)
let neighbors = self.client_location.get_client_neighbors(id).unwrap();
Ok(vec![(id, SendShipPacket::JoinLobby(join_lobby))]
.into_iter()
.chain(neighbors.into_iter()
.map(|c| (c.client, SendShipPacket::AddToLobby(addto.clone())))).collect())
}
fn message(&mut self, id: ClientId, msg: &Message) -> Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send> {
match &msg.msg {
GameMessage::RequestExp(killmonster) => {
match self.client_location.get_area(id).unwrap() {
RoomLobby::Room(room) => {
let r = self.rooms[room.0].as_ref().unwrap();
warn!("killed a {:?}", r.maps.enemy_by_id(killmonster.enemy_id as usize).monster);
},
_ => {}
}
},
_ => {},
}
let cmsg = msg.clone();
Box::new(self.client_location.get_area_by_user(id).clients().iter()
.filter(|client| client.client_id != id)
Box::new(self.client_location.get_client_neighbors(id).unwrap().into_iter()
.filter(move |client| client.client != id)
.map(move |client| {
(client.client_id, SendShipPacket::Message(cmsg.clone()))
}).collect::<Vec<_>>().into_iter())
(client.client, SendShipPacket::Message(cmsg.clone()))
}))
}
/*fn generate_item_drop(&mut self, id: ClientId, monster: MonsterType) -> Option<ActiveItem> {
let room = self.rooms[self.client_location.get_area_by_user(id).index];
let item_drop = room.drop_table.get_drop()
}*/
fn direct_message(&mut self, id: ClientId, msg: &DirectMessage) -> Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send> {
let cmsg = msg.clone();
let client = self.clients.get_mut(&id).unwrap();
@ -346,50 +352,60 @@ impl<EG: EntityGateway> ShipServerState<EG> {
class: client.character.char_class.into(),
}),
};
Box::new(self.client_location.get_area_by_user(id).clients().iter()
.filter(|client| client.index == cmsg.flag as usize)
.map(|client| {
(client.client_id, SendShipPacket::DirectMessage(out_msg.clone()))
}).collect::<Vec<_>>().into_iter())
let msg_flag = cmsg.flag as u8;
Box::new(self.client_location.get_all_clients_by_client(id).unwrap().into_iter()
.filter(move |client| client.local_client.id() == msg_flag)
.map(move |client| {
(client.client, SendShipPacket::DirectMessage(out_msg.clone()))
}))
},
/*GameMessage::RequestItem(req_item) => {
let item = self.generate_item_drop(id);
Box::new(vec![(id, SendShipPacket::Message(Message::new(GameMessage::ItemDrop(ItemDrop {
client: req_item.client,
target: req_item.target,
area: req_item.area,
variety: 0,
unknown: 0,
x: req_item.x,
z: req_item.z,
unknown2: 0,
item_bytes: item[0..12].try_into().unwrap(),
item_id: 0,
item_bytes2: item[12..16].try_into().unwrap(),
unknown3: 0,
}))))].into_iter())
},*/
_ => {
Box::new(self.client_location.get_area_by_user(id).clients().iter()
.filter(|client| client.index == cmsg.flag as usize)
.map(|client| {
(client.client_id, SendShipPacket::DirectMessage(cmsg.clone()))
}).collect::<Vec<_>>().into_iter())
let msg_flag = cmsg.flag as u8;
Box::new(self.client_location.get_all_clients_by_client(id).unwrap().into_iter()
.filter(move |client| client.local_client.id() == msg_flag)
.map(move |client| {
(client.client, SendShipPacket::DirectMessage(cmsg.clone()))
}))
},
}
}
fn player_chat(&mut self, id: ClientId, msg: &PlayerChat) -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> {
let client = self.clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
let cmsg = PlayerChat::new(client.user.id.0, msg.message.clone());
Ok(Box::new(self.client_location.get_area_by_user(id).clients().iter()
Ok(Box::new(self.client_location.get_all_clients_by_client(id).unwrap().into_iter()
.map(move |client| {
(client.client_id, SendShipPacket::PlayerChat(cmsg.clone()))
}).collect::<Vec<_>>().into_iter()))
(client.client, SendShipPacket::PlayerChat(cmsg.clone()))
})))
}
fn create_room(&mut self, id: ClientId, create_room: &CreateRoom) -> Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send> {
let area = self.client_location.get_area_by_user(id);
let area_client = area.clients().into_iter().filter(|client| {
client.client_id == id
}).next().unwrap();
let other_clients = area.clients().into_iter()
.filter(move |c| {
c.client_id != id
});
let room_id = match self.client_location.new_room(id) {
Ok(room_id) => room_id,
Err(err) => return Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new(format!("could not create room: {:?}", err))))].into_iter())
};
let room = room::RoomState::from_create_room(create_room).unwrap();
let area = self.client_location.get_area(id).unwrap();
let area_client = self.client_location.get_local_client(id).unwrap();
let neighbors = self.client_location.get_client_neighbors(id).unwrap();
let room_id = self.client_location.create_new_room(id).unwrap();
let client = self.clients.get_mut(&id).unwrap();//.ok_or(ShipError::ClientNotFound(id)).unwrap();
let room = room::RoomState::from_create_room(create_room, client.character.section_id).unwrap();
let players = [PlayerHeader {
tag: 0x00010000,
guildcard: client.user.id.0,
@ -419,16 +435,22 @@ impl<EG: EntityGateway> ShipServerState<EG> {
};
self.rooms[room_id.0] = Some(room);
let leader = area.leader();
Box::new(vec![(id, SendShipPacket::JoinRoom(join_room))].into_iter().chain(other_clients.map(move |c| {
(c.client_id, SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.index as u8, leader.index as u8)))
})))
let leader = self.client_location.get_area_leader(area).unwrap();
Box::new(vec![(id, SendShipPacket::JoinRoom(join_room))]
.into_iter()
.chain(neighbors
.into_iter()
.map(move |c| {
(c.client, SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())))
})))
}
fn room_name_request(&mut self, id: ClientId) -> Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send> {
let area = self.client_location.get_area_by_user(id);
let room_state = self.rooms[area.id()].as_ref().unwrap();
Box::new(vec![(id, SendShipPacket::RoomNameResponse(RoomNameResponse {name: room_state.name.clone()}))].into_iter())
let area = self.client_location.get_area(id).unwrap();
match area {
RoomLobby::Room(room) => Box::new(vec![(id, SendShipPacket::RoomNameResponse(RoomNameResponse {name: self.rooms[room.0].as_ref().unwrap().name.clone()}))].into_iter()),
RoomLobby::Lobby(_) => panic!()
}
}
fn update_config(&mut self, id: ClientId, update_config: &UpdateConfig) -> Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send> {
@ -439,21 +461,17 @@ impl<EG: EntityGateway> ShipServerState<EG> {
}
fn request_infoboard(&mut self, id: ClientId, request_infoboard: &ViewInfoboardRequest) -> Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send> {
let lobby = self.client_location.get_area_by_user(id);
let clients = lobby.clients();
let r = clients
.iter()
.filter(|c| c.client_id != id)
let clients = self.client_location.get_client_neighbors(id).unwrap();
let r = clients.iter()
.filter_map(|c| {
self.clients.get(&c.client_id)
self.clients.get(&c.client)
})
.map(|c| {
.map(|client| {
InfoboardResponse {
name: libpso::utf8_to_utf16_array!(c.character.name, 16),
message: c.character.info_board.as_bytes(),
name: libpso::utf8_to_utf16_array!(client.character.name, 16),
message: client.character.info_board.as_bytes(),
}
})
.collect();
}).collect();
Box::new(vec![(id, SendShipPacket::ViewInfoboardResponse(ViewInfoboardResponse {response: r}))].into_iter())
}
@ -473,7 +491,7 @@ impl<EG: EntityGateway> ShipServerState<EG> {
menu_id: ROOM_MENU_ID,
item_id: i as u32,
difficulty: room.get_difficulty_for_room_list(),
players: self.client_location.get_client_count_in_room(RoomId(i)), // TODO
players: self.client_location.get_clients_in_room(RoomId(i)).unwrap().len() as u8,
name: libpso::utf8_to_utf16_array!(room.name, 16),
episode: room.get_episode_for_room_list(),
flags: room.get_flags_for_room_list(),
@ -566,25 +584,24 @@ impl<EG: EntityGateway> ServerState for ShipServerState<EG> {
}
fn on_disconnect(&mut self, id: ClientId) -> Vec<(ClientId, SendShipPacket)> {
let mut area = self.client_location.get_area_by_user(id);
let client = area.clients().into_iter().filter(|client| {
client.client_id == id
//}).collect::<Vec<_>>()[0];
}).next().unwrap();
let other_clients = area.clients().into_iter().filter(|client| {
client.client_id != id
});
//self.client_location.remove_from_location(id);
area.remove(id);
let leader = area.leader();
let pkt = match area.area_type {
AreaType::Lobby => SendShipPacket::LeaveLobby(LeaveLobby::new(client.index as u8, leader.index as u8)),
AreaType::Room => SendShipPacket::LeaveRoom(LeaveRoom::new(client.index as u8, leader.index as u8)),
let client = self.client_location.get_local_client(id).unwrap();
let neighbors = self.client_location.get_client_neighbors(id).unwrap();
let pkt = match self.client_location.get_area(id).unwrap() {
RoomLobby::Room(room) => {
let leader = self.client_location.get_room_leader(room).unwrap();
SendShipPacket::LeaveRoom(LeaveRoom::new(client.local_client.id(), leader.local_client.id()))
},
RoomLobby::Lobby(lobby) => {
let leader = self.client_location.get_lobby_leader(lobby).unwrap();
SendShipPacket::LeaveLobby(LeaveLobby::new(client.local_client.id(), leader.local_client.id()))
}
};
other_clients.map(|client| {
(client.client_id, pkt.clone())
self.client_location.remove_client_from_area(id);
neighbors.into_iter().map(|n| {
(n.client, pkt.clone())
}).collect()
}
}
Loading…
Cancel
Save