diff --git a/Cargo.lock b/Cargo.lock index c6e1df1..682d18a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1001,7 +1001,6 @@ checksum = "739e9d7726dc32173fed2d69d17eef3c54682169e4e20ff1d0a45dcd37063cef" [[package]] name = "libpso" version = "0.1.0" -source = "git+http://git.sharnoth.com/jake/libpso#892d2ed220369f0ff7b7530fa734e722c2b21c2c" dependencies = [ "chrono", "psopacket", @@ -1401,7 +1400,6 @@ dependencies = [ [[package]] name = "psopacket" version = "1.0.0" -source = "git+http://git.sharnoth.com/jake/libpso#892d2ed220369f0ff7b7530fa734e722c2b21c2c" dependencies = [ "proc-macro2", "quote", diff --git a/src/entity/account.rs b/src/entity/account.rs index 3958412..90311cc 100644 --- a/src/entity/account.rs +++ b/src/entity/account.rs @@ -1,6 +1,7 @@ use serde::{Serialize, Deserialize}; use libpso::character::settings; use libpso::character::guildcard; +use libpso::packet::ship::{GuildcardAccept}; pub const USERFLAG_NEWCHAR: u32 = 0x00000001; pub const USERFLAG_DRESSINGROOM: u32 = 0x00000002; @@ -9,9 +10,14 @@ pub const USERFLAG_DRESSINGROOM: u32 = 0x00000002; pub struct UserAccountId(pub u32); #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct UserSettingsId(pub u32); -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct GuildCardDataId(pub u32); +// TODO: use these +#[derive(Debug)] +pub enum GuildcardError { + GuildcardAlreadyFriend(u32), + GuildcardAlreadyBlocked(u32), + GuildcardListFull, +} #[derive(Clone, Debug)] pub struct NewUserAccountEntity { @@ -125,19 +131,28 @@ impl NewGuildCardDataEntity { } // TODO: implement this properly -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct GuildCardDataEntity { - pub id: GuildCardDataId, pub user_id: UserAccountId, - pub guildcard: guildcard::GuildCardData, + pub guildcard_data: Box, } impl GuildCardDataEntity { pub fn new(user_id: UserAccountId) -> GuildCardDataEntity { GuildCardDataEntity { - id: GuildCardDataId(0), user_id, - guildcard: guildcard::GuildCardData::default(), + guildcard_data: Box::new(guildcard::GuildCardData::default()), } } + + pub fn add_friend(&mut self, new_friend: &GuildcardAccept) -> Result<(), GuildcardError> { + let next_open_spot = self.guildcard_data.friends + .iter() + .enumerate() + .find(|(_i, g)| g.id == 0) + .ok_or(GuildcardError::GuildcardListFull)? + .0; + self.guildcard_data.friends[next_open_spot] = guildcard::GuildCard::from(new_friend); + Ok(()) // TODO: implement a real error + } } diff --git a/src/entity/gateway/entitygateway.rs b/src/entity/gateway/entitygateway.rs index fd8b1aa..cd4d699 100644 --- a/src/entity/gateway/entitygateway.rs +++ b/src/entity/gateway/entitygateway.rs @@ -61,6 +61,10 @@ pub trait EntityGateway: Send + Sync + Clone { unimplemented!(); } + async fn set_guild_card(&mut self, _id: UserAccountId, _gc_data: GuildCardDataEntity) -> Result<(), GatewayError> { + unimplemented!(); + } + async fn create_item(&mut self, _item: NewItemEntity) -> Result { unimplemented!(); } diff --git a/src/entity/gateway/inmemory.rs b/src/entity/gateway/inmemory.rs index 3d37761..5e65047 100644 --- a/src/entity/gateway/inmemory.rs +++ b/src/entity/gateway/inmemory.rs @@ -21,6 +21,7 @@ pub struct InMemoryGateway { equips: Arc>>, mag_modifiers: Arc>>>, weapon_modifiers: Arc>>>, + guildcard_entities: Arc>>, } impl Default for InMemoryGateway { @@ -37,6 +38,7 @@ impl Default for InMemoryGateway { equips: Arc::new(Mutex::new(BTreeMap::new())), mag_modifiers: Arc::new(Mutex::new(BTreeMap::new())), weapon_modifiers: Arc::new(Mutex::new(BTreeMap::new())), + guildcard_entities: Arc::new(Mutex::new(BTreeMap::new())), } } } @@ -101,6 +103,7 @@ impl InMemoryGateway { impl EntityGateway for InMemoryGateway { async fn create_user(&mut self, user: NewUserAccountEntity) -> Result { let mut users = self.users.lock().unwrap(); + let mut guildcards = self.guildcard_entities.lock().unwrap(); let id = users .iter() .fold(0, |sum, (i, _)| std::cmp::max(sum, i.0)) @@ -109,7 +112,7 @@ impl EntityGateway for InMemoryGateway { id: UserAccountId(id), username: user.username, password: user.password, - guildcard: user.guildcard, + guildcard: id, team_id: user.team_id, banned_until: user.banned_until, muted_until: user.muted_until, @@ -120,7 +123,11 @@ impl EntityGateway for InMemoryGateway { at_character: false, at_ship: false, }; + + let guildcard = GuildCardDataEntity::new(UserAccountId(id)); // TODO: NewGuildcardDataEntity ? users.insert(user.id, user.clone()); + guildcards.insert(user.id, guildcard.clone()); + Ok(user) } @@ -213,8 +220,14 @@ impl EntityGateway for InMemoryGateway { Ok(()) } + // TODO: ok_or a real error ? async fn get_guild_card_data_by_user(&self, user: &UserAccountEntity) -> Result { - Ok(GuildCardDataEntity::new(user.id)) + let guildcards = self.guildcard_entities.lock().unwrap(); + guildcards + .iter() + .find(|(_, g)| g.user_id == user.id) + .map(|(_, g)| g.clone()) + .ok_or(GatewayError::Error) } async fn create_item(&mut self, item: NewItemEntity) -> Result { @@ -347,4 +360,10 @@ impl EntityGateway for InMemoryGateway { Err(GatewayError::Error) } } + + async fn set_guild_card(&mut self, id: UserAccountId, gc_data: GuildCardDataEntity) -> Result<(), GatewayError> { + let mut guildcard = self.guildcard_entities.lock().unwrap(); + guildcard.insert(id, gc_data); + Ok(()) + } } diff --git a/src/entity/gateway/postgres/postgres.rs b/src/entity/gateway/postgres/postgres.rs index bbf116a..516088c 100644 --- a/src/entity/gateway/postgres/postgres.rs +++ b/src/entity/gateway/postgres/postgres.rs @@ -278,9 +278,8 @@ impl EntityGateway for PostgresGateway { async fn get_guild_card_data_by_user(&self, user: &UserAccountEntity) -> Result { Ok(GuildCardDataEntity { - id: GuildCardDataId(0), user_id: user.id, - guildcard: guildcard::GuildCardData::default(), + guildcard_data: Box::new(guildcard::GuildCardData::default()), }) } diff --git a/src/login/character.rs b/src/login/character.rs index 69d43e7..610318c 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -441,12 +441,10 @@ impl CharacterServerState { async fn guildcard_data_header(&mut self, id: ClientId) -> Result, anyhow::Error> { let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; let guildcard_data = self.entity_gateway.get_guild_card_data_by_user(client.user.as_ref().unwrap()).await.map_err(|_| CharacterError::CouldNotLoadGuildcard)?; - - let bytes = guildcard_data.guildcard.as_bytes(); + let bytes = guildcard_data.guildcard_data.as_bytes(); let mut crc = crc32::Digest::new(crc32::IEEE); crc.write(&bytes[..]); client.guildcard_data_buffer = Some(bytes.to_vec()); - Ok(vec![SendCharacterPacket::GuildcardDataHeader(GuildcardDataHeader::new(bytes.len(), crc.sum32()))]) } diff --git a/src/ship/packet/handler/communication.rs b/src/ship/packet/handler/communication.rs index 087913b..13aa276 100644 --- a/src/ship/packet/handler/communication.rs +++ b/src/ship/packet/handler/communication.rs @@ -45,3 +45,17 @@ pub async fn write_infoboard(id: ClientId, entity_gateway.save_character(&client.character).await.unwrap(); Box::new(None.into_iter()) } + +// TODO: return Result> so ship can do await? and catch errors? +pub async fn accept_guildcard(id: ClientId, + accepted_card: &GuildcardAccept, + clients: &mut Clients, + entity_gateway: &mut EG) + -> Box + Send> { + let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); + + let mut gc_data = entity_gateway.get_guild_card_data_by_user(&client.user).await.unwrap(); + gc_data.add_friend(accepted_card).unwrap(); + entity_gateway.set_guild_card(client.user.id, gc_data).await.unwrap(); + Box::new(None.into_iter()) // TODO: does the server need to return anything to any client? everything seems to work fine like this... +} \ No newline at end of file diff --git a/src/ship/ship.rs b/src/ship/ship.rs index ae0fd08..5baf3c4 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -114,6 +114,7 @@ pub enum RecvShipPacket { RequestShipBlockList(RequestShipBlockList), ItemsToTrade(ItemsToTrade), TradeConfirmed(TradeConfirmed), + GuildcardAccept(GuildcardAccept), } impl RecvServerPacket for RecvShipPacket { @@ -155,6 +156,7 @@ impl RecvServerPacket for RecvShipPacket { 0xD2 => Ok(RecvShipPacket::TradeConfirmed(TradeConfirmed::from_bytes(data)?)), 0xE7 => Ok(RecvShipPacket::FullCharacterData(Box::new(FullCharacterData::from_bytes(data)?))), 0x1ED => Ok(RecvShipPacket::SaveOptions(SaveOptions::from_bytes(data)?)), + 0x4E8 => Ok(RecvShipPacket::GuildcardAccept(GuildcardAccept::from_bytes(data)?)), _ => Err(PacketParseError::WrongPacketForServerType(u16::from_le_bytes([data[2], data[3]]), data.to_vec())) } } @@ -743,6 +745,9 @@ impl ServerState for ShipServerState { let block = self.blocks.with_client(id, &self.clients)?; handler::trade::trade_confirmed(id, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut self.item_manager, &mut self.trades).await? }, + RecvShipPacket::GuildcardAccept(guildcard_accept) => { + handler::communication::accept_guildcard(id, guildcard_accept, &mut self.clients, &mut self.entity_gateway).await + }, }) }