From 24fdd705c5354028e1b92175e9588cca64bf8c78 Mon Sep 17 00:00:00 2001 From: andy Date: Sun, 24 Apr 2022 23:32:21 +0000 Subject: [PATCH 1/5] f is for friends who do stuff together --- Cargo.lock | 2 -- src/entity/account.rs | 29 ++++++++++++++++++------ src/entity/gateway/entitygateway.rs | 4 ++++ src/entity/gateway/inmemory.rs | 23 +++++++++++++++++-- src/entity/gateway/postgres/postgres.rs | 3 +-- src/login/character.rs | 4 +--- src/ship/packet/handler/communication.rs | 14 ++++++++++++ src/ship/ship.rs | 5 ++++ 8 files changed, 68 insertions(+), 16 deletions(-) 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 + }, }) } -- 2.36.0 From f3294dfce84ab4597cd7240f02c4d6f431194a8e Mon Sep 17 00:00:00 2001 From: andy Date: Fri, 29 Apr 2022 00:33:38 +0000 Subject: [PATCH 2/5] a test i guess --- tests/test_communication.rs | 55 +++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 tests/test_communication.rs diff --git a/tests/test_communication.rs b/tests/test_communication.rs new file mode 100644 index 0000000..2e7e63b --- /dev/null +++ b/tests/test_communication.rs @@ -0,0 +1,55 @@ +use elseware::common::serverstate::{ClientId, ServerState}; +use elseware::entity::gateway::{EntityGateway, InMemoryGateway}; +use elseware::ship::ship::{ShipServerState, RecvShipPacket}; +use libpso::packet::ship::*; + +#[path = "common.rs"] +mod common; +use common::*; + +#[async_std::test] +async fn test_guildcard_add_friend() { + let mut entity_gateway = InMemoryGateway::default(); + let (user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await; + + let mut ship = Box::new(ShipServerState::builder() + .gateway(entity_gateway.clone()) + .build()); + + log_in_char(&mut ship, ClientId(1), "a1", "a").await; + join_lobby(&mut ship, ClientId(1)).await; + + // Accept friend request from "Test Char 2" + ship.handle(ClientId(1), &RecvShipPacket::GuildcardAccept(GuildcardAccept { + id: 2, + name: [84, 101, 115, 116, 32, 67, 104, 97, 114, 32, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + team: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + desc: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + one: 1, + language: 0, + section_id: 0, + class: 0, + })).await.unwrap().for_each(drop); + + let friendlist = entity_gateway.get_guild_card_data_by_user(&user1).await.unwrap(); + + assert!(friendlist.guildcard_data.friends[0].name == [84, 101, 115, 116, 32, 67, 104, 97, 114, 32, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); +} + + +/* +TODO: actually write these tests at some point. also add a test for transmute/repr(C)? + +#[async_std::test] +async fn test_guildcard_block_rival() {} + +#[async_std::test] +async fn test_guildcard_write_comment() {} + +#[async_std::test] +async fn test_player_chat() {} + +#[async_std::test] +async fn test_update_infoboard() {} + +*/ \ No newline at end of file -- 2.36.0 From f2c4094b8f510c55b0c04228d7a8b4ea6e903c53 Mon Sep 17 00:00:00 2001 From: andy Date: Fri, 29 Apr 2022 22:41:12 +0000 Subject: [PATCH 3/5] andy vs clippy round 8 --- src/entity/gateway/inmemory.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/entity/gateway/inmemory.rs b/src/entity/gateway/inmemory.rs index 5e65047..0af09bb 100644 --- a/src/entity/gateway/inmemory.rs +++ b/src/entity/gateway/inmemory.rs @@ -126,7 +126,7 @@ impl EntityGateway for InMemoryGateway { let guildcard = GuildCardDataEntity::new(UserAccountId(id)); // TODO: NewGuildcardDataEntity ? users.insert(user.id, user.clone()); - guildcards.insert(user.id, guildcard.clone()); + guildcards.insert(user.id, guildcard); Ok(user) } -- 2.36.0 From 5898a8120a137856610de83b33581b75aaaac6e3 Mon Sep 17 00:00:00 2001 From: andy Date: Fri, 29 Apr 2022 22:54:34 +0000 Subject: [PATCH 4/5] ci pls work --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 582634f..8f6b805 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Jake Probst "] edition = "2018" [dependencies] -libpso = { git = "http://git.sharnoth.com/jake/libpso" } +libpso = { git = "http://git.sharnoth.com/jake/libpso", branch = "sendgc" } async-std = { version = "1.9.0", features = ["unstable", "attributes"] } futures = "0.3.5" rand = "0.7.3" -- 2.36.0 From ee7382e8e4f4907856dd71808e63b575de12d763 Mon Sep 17 00:00:00 2001 From: andy Date: Sat, 30 Apr 2022 19:35:15 +0000 Subject: [PATCH 5/5] pr changes --- src/entity/account.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/entity/account.rs b/src/entity/account.rs index 90311cc..8247352 100644 --- a/src/entity/account.rs +++ b/src/entity/account.rs @@ -11,11 +11,10 @@ pub struct UserAccountId(pub u32); #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct UserSettingsId(pub u32); -// TODO: use these #[derive(Debug)] pub enum GuildcardError { - GuildcardAlreadyFriend(u32), - GuildcardAlreadyBlocked(u32), + GuildcardAlreadyFriend(UserAccountId), + GuildcardAlreadyBlocked(UserAccountId), GuildcardListFull, } @@ -130,7 +129,6 @@ impl NewGuildCardDataEntity { } } -// TODO: implement this properly #[derive(Clone, Debug)] pub struct GuildCardDataEntity { pub user_id: UserAccountId, @@ -148,10 +146,8 @@ impl GuildCardDataEntity { 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; + .position(|&g| g.id == 0) + .ok_or(GuildcardError::GuildcardListFull)?; self.guildcard_data.friends[next_open_spot] = guildcard::GuildCard::from(new_friend); Ok(()) // TODO: implement a real error } -- 2.36.0