From a74941441b8903dd0cee1f74fed20d87c2d5c263 Mon Sep 17 00:00:00 2001 From: jake Date: Sat, 25 Jan 2020 13:01:34 -0800 Subject: [PATCH] use proper data structs that convert to what pso wants --- src/common/leveltable.rs | 34 +++--- src/entity/character.rs | 246 ++++++++++++++++++++++++++++++++++++++- src/login/character.rs | 105 +++++++++++++++-- src/main.rs | 17 +-- src/ship/character.rs | 96 ++++++++++----- src/ship/ship.rs | 37 +++--- 6 files changed, 449 insertions(+), 86 deletions(-) diff --git a/src/common/leveltable.rs b/src/common/leveltable.rs index 325d6d0..997b83e 100644 --- a/src/common/leveltable.rs +++ b/src/common/leveltable.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::fs::File; use serde_json::Value; -use libpso::character::character::Class; +use crate::entity::character::CharacterClass; #[derive(Default, Copy, Clone, Debug, PartialEq)] pub struct CharacterStats { @@ -27,7 +27,7 @@ struct CharacterLevelEntry { } pub struct CharacterLevelTable { - table: HashMap, + table: HashMap, } @@ -39,18 +39,18 @@ impl CharacterLevelTable { for it in json.as_object().unwrap().iter(){ let cl = match it.0.as_str() { - "HUmar" => Class::HUmar, - "HUnewearl" => Class::HUnewearl, - "HUcast" => Class::HUcast, - "HUcaseal" => Class::HUcaseal, - "RAmar" => Class::RAmar, - "RAmarl" => Class::RAmarl, - "RAcast" => Class::RAcast, - "RAcaseal" => Class::RAcaseal, - "FOmar" => Class::FOmar, - "FOmarl" => Class::FOmarl, - "FOnewm" => Class::FOnewm, - "FOnewearl" => Class::FOnewearl, + "HUmar" => CharacterClass::HUmar, + "HUnewearl" => CharacterClass::HUnewearl, + "HUcast" => CharacterClass::HUcast, + "HUcaseal" => CharacterClass::HUcaseal, + "RAmar" => CharacterClass::RAmar, + "RAmarl" => CharacterClass::RAmarl, + "RAcast" => CharacterClass::RAcast, + "RAcaseal" => CharacterClass::RAcaseal, + "FOmar" => CharacterClass::FOmar, + "FOmarl" => CharacterClass::FOmarl, + "FOnewm" => CharacterClass::FOnewm, + "FOnewearl" => CharacterClass::FOnewearl, _ => panic!("unexpected class in char stats"), }; @@ -76,7 +76,7 @@ impl CharacterLevelTable { } } - pub fn get_stats_from_exp(&self, ch_class: Class, exp: u32) -> (u32, CharacterStats) { + pub fn get_stats_from_exp(&self, ch_class: CharacterClass, exp: u32) -> (u32, CharacterStats) { if let Some(statlist) = self.table.get(&ch_class) { statlist .iter() @@ -107,7 +107,7 @@ mod test { #[test] fn test_stat_levels() { let table = CharacterLevelTable::new(); - assert!(table.get_stats_from_exp(Class::FOmarl, 0) == (1, CharacterStats { hp: 20, atp: 13, mst: 53, evp: 35, dfp: 10, ata: 15, lck: 10 })); - assert!(table.get_stats_from_exp(Class::FOmarl, 1 << 17) == (36, CharacterStats { hp: 125, atp: 114, mst: 219, evp: 182, dfp: 42, ata: 213, lck: 10 })); + assert!(table.get_stats_from_exp(CharacterClass::FOmarl, 0) == (1, CharacterStats { hp: 20, atp: 13, mst: 53, evp: 35, dfp: 10, ata: 15, lck: 10 })); + assert!(table.get_stats_from_exp(CharacterClass::FOmarl, 1 << 17) == (36, CharacterStats { hp: 125, atp: 114, mst: 219, evp: 182, dfp: 42, ata: 213, lck: 10 })); } } diff --git a/src/entity/character.rs b/src/entity/character.rs index 1596bd4..6014515 100644 --- a/src/entity/character.rs +++ b/src/entity/character.rs @@ -1,9 +1,251 @@ +use std::convert::{From, Into, TryFrom, TryInto}; +use std::collections::HashMap; + use libpso::character::character; -#[derive(Copy, Clone, Debug, Default)] +#[derive(Copy, Clone, Hash, PartialEq, Eq)] +pub enum CharacterClass { + HUmar, + HUnewearl, + HUcast, + HUcaseal, + RAmar, + RAmarl, + RAcast, + RAcaseal, + FOmar, + FOmarl, + FOnewm, + FOnewearl, +} + +// TODO: TryFrom +impl From for CharacterClass { + fn from(f: u8) -> CharacterClass { + match f { + 0 => CharacterClass::HUmar, + 1 => CharacterClass::HUnewearl, + 2 => CharacterClass::HUcast, + 3 => CharacterClass::RAmar, + 4 => CharacterClass::RAcast, + 5 => CharacterClass::RAcaseal, + 6 => CharacterClass::FOmarl, + 7 => CharacterClass::FOnewm, + 8 => CharacterClass::FOnewearl, + 9 => CharacterClass::HUcaseal, + 10 => CharacterClass::RAmarl, + 11 => CharacterClass::FOmar, + _ => panic!("unknown class") + } + } +} + +impl Into for CharacterClass { + fn into(self) -> u8 { + match self { + CharacterClass::HUmar => 0, + CharacterClass::HUnewearl => 1, + CharacterClass::HUcast => 2, + CharacterClass::RAmar => 3, + CharacterClass::RAcast => 4, + CharacterClass::RAcaseal => 5, + CharacterClass::FOmarl => 6, + CharacterClass::FOnewm => 7, + CharacterClass::FOnewearl => 8, + CharacterClass::HUcaseal => 9, + CharacterClass::RAmarl => 10, + CharacterClass::FOmar => 11, + } + } +} + + + +#[derive(Copy, Clone, Hash, PartialEq, Eq)] +pub enum SectionID { + Viridia, + Greenill, + Skyly, + Bluefull, + Purplenum, + Pinkal, + Redria, + Oran, + Yellowboze, + Whitill, +} + +impl From for SectionID { + fn from(id: u8) -> SectionID { + match id { + 0 => SectionID::Viridia, + 1 => SectionID::Greenill, + 2 => SectionID::Skyly, + 3 => SectionID::Bluefull, + 4 => SectionID::Purplenum, + 5 => SectionID::Pinkal, + 6 => SectionID::Redria, + 7 => SectionID::Oran, + 8 => SectionID::Yellowboze, + 9 => SectionID::Whitill, + _ => panic!(), + } + } +} + +impl Into for SectionID { + fn into(self) -> u8 { + match self { + SectionID::Viridia => 0, + SectionID::Greenill => 1, + SectionID::Skyly => 2, + SectionID::Bluefull => 3, + SectionID::Purplenum => 4, + SectionID::Pinkal => 5, + SectionID::Redria => 6, + SectionID::Oran => 7, + SectionID::Yellowboze => 8, + SectionID::Whitill => 9, + } + } +} + + +#[derive(Clone, Debug, Default)] +pub struct CharacterAppearance { + pub costume: u16, + pub skin: u16, + pub face: u16, + pub head: u16, + pub hair: u16, + pub hair_r: u16, + pub hair_g: u16, + pub hair_b: u16, + pub prop_x: f32, + pub prop_y: f32, +} + + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum Techniques { + Foie, + Gifoie, + Rafoie, + Zonde, + Gizonde, + Razonde, + Barta, + Gibarta, + Rabarta, + Grants, + Megid, + Shifta, + Deband, + Jellen, + Zalure, + Resta, + Anti, + Reverser, + Ryuker, +} + +#[derive(Clone, Debug)] +pub struct TechLevel(u8); + +#[derive(Clone, Debug)] +pub struct CharacterTechniques { + techs: HashMap +} + +impl CharacterTechniques { + fn new() -> CharacterTechniques { + CharacterTechniques { + techs: HashMap::new(), + } + } + + fn set_tech(&mut self, tech: Techniques, level: TechLevel) { + self.techs.insert(tech, level); + } + + // from_bytes + + fn as_bytes(&self) -> [u8; 20] { + self.techs.iter() + .fold([0xFF; 20], |mut techlist, (tech, level)| { + let index = match tech { + Techniques::Foie => 0, + Techniques::Gifoie => 1, + Techniques::Rafoie => 2, + Techniques::Zonde => 3, + Techniques::Gizonde => 4, + Techniques::Razonde => 5, + Techniques::Barta => 6, + Techniques::Gibarta => 7, + Techniques::Rabarta => 8, + Techniques::Grants => 9, + Techniques::Megid => 10, + Techniques::Shifta => 11, + Techniques::Deband => 12, + Techniques::Jellen => 13, + Techniques::Zalure => 14, + Techniques::Resta => 15, + Techniques::Anti => 16, + Techniques::Reverser => 17, + Techniques::Ryuker => 18, + }; + + techlist[index] = level.0; + techlist + }) + } +} + + +#[derive(Clone)] +pub struct CharacterConfig { + raw_data: [u8; 0xE8], +} + +impl CharacterConfig { + fn new() -> CharacterConfig { + CharacterConfig { + raw_data: [0; 0xE8], + } + } +} + + +#[derive(Clone)] pub struct Character { pub id: u32, pub user_id: u32, pub slot: u32, - pub character: character::Character, + + pub name: String, + pub exp: u32, + + pub char_class: CharacterClass, + pub section_id: SectionID, + + pub appearance: CharacterAppearance, + pub techs: CharacterTechniques, + pub config: CharacterConfig, +} + +impl std::default::Default for Character { + fn default() -> Character { + Character { + id: 0, + user_id: 0, + slot: 0, + name: "".into(), + exp: 0, + char_class: CharacterClass::HUmar, + section_id: SectionID::Viridia, + appearance: CharacterAppearance::default(), + techs: CharacterTechniques::new(), + config: CharacterConfig::new(), + } + } } diff --git a/src/login/character.rs b/src/login/character.rs index d1de8c3..555807f 100644 --- a/src/login/character.rs +++ b/src/login/character.rs @@ -8,6 +8,7 @@ use libpso::packet::login::*; use libpso::{PacketParseError, PSOPacket}; use libpso::crypto::bb::PSOBBCipher; use libpso::item; +use libpso::character::character; use crate::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; @@ -17,7 +18,7 @@ use libpso::{utf8_to_array, utf8_to_utf16_array}; use crate::entity::gateway::EntityGateway; use crate::entity::account::{UserAccount, USERFLAG_NEWCHAR, USERFLAG_DRESSINGROOM}; use crate::entity::item::{ItemDetail, ItemLocation, Weapon, Armor, Shield, Tool}; -use crate::entity::character::Character; +use crate::entity::character::{Character, CharacterClass}; use crate::login::login::get_login_status; @@ -183,19 +184,15 @@ pub struct CharacterServerState { } - - fn new_character(entity_gateway: &mut EG, user: &UserAccount, preview: &CharacterPreview) { let mut char = entity_gateway.new_character_by_user(&user); - char.slot = preview.slot; - char.character = preview.character.as_character(); + new_character_from_preview(&mut char, preview); entity_gateway.set_character(&char); - let new_weapon = match char.character.ch_class { - 0 | 1 | 2 | 9 => item::weapon::WeaponType::Saber, - 3 | 4 | 5 | 11 => item::weapon::WeaponType::Handgun, - 6 | 7 | 8 | 10 => item::weapon::WeaponType::Cane, - _ => panic!() + let new_weapon = match char.char_class { + CharacterClass::HUmar | CharacterClass::HUnewearl | CharacterClass::HUcast | CharacterClass::HUcaseal => item::weapon::WeaponType::Saber, + CharacterClass::RAmar | CharacterClass::RAmarl | CharacterClass::RAcast | CharacterClass::RAcaseal => item::weapon::WeaponType::Handgun, + CharacterClass::FOmar| CharacterClass::FOmarl| CharacterClass::FOnewm | CharacterClass::FOnewearl => item::weapon::WeaponType::Cane, }; entity_gateway.new_item( @@ -330,9 +327,13 @@ impl CharacterServerState { if select.reason == 0 { let chars = client.characters.as_ref().unwrap(); Ok(if let Some(char) = &chars[select.slot as usize] { + let (level, stats) = self.level_table.get_stats_from_exp(char.char_class, char.exp); vec![SendCharacterPacket::CharacterPreview(CharacterPreview { slot: select.slot, - character: char.character.as_select_screen(), + character: SelectScreenCharacterBuilder::new() + .character(&char) + .level(level) + .build() })] } else { @@ -525,6 +526,88 @@ impl ServerState for CharacterServerState { } } + +fn new_character_from_preview(character: &mut Character, preview: &CharacterPreview) { + character.slot = preview.slot; + character.name = String::from_utf16_lossy(&preview.character.name); + character.section_id = preview.character.section_id.into(); + character.char_class = preview.character.ch_class.into(); + character.appearance.costume = preview.character.costume; + character.appearance.skin = preview.character.skin; + character.appearance.face = preview.character.face; + character.appearance.head = preview.character.head; + character.appearance.hair = preview.character.hair; + character.appearance.hair_r = preview.character.hair_r; + character.appearance.hair_g = preview.character.hair_g; + character.appearance.hair_b = preview.character.hair_b; + character.appearance.prop_x = preview.character.prop_x; + character.appearance.prop_y = preview.character.prop_y; +} + + +struct SelectScreenCharacterBuilder<'a> { + character: Option<&'a Character>, + level: Option, +} + +impl<'a> SelectScreenCharacterBuilder<'a> { + fn new() -> SelectScreenCharacterBuilder<'a> { + SelectScreenCharacterBuilder { + character: None, + level: None, + } + } + + fn character(self, character: &'a Character) -> SelectScreenCharacterBuilder<'a> { + SelectScreenCharacterBuilder { + character: Some(character), + ..self + } + } + + fn level(self, level: u32) -> SelectScreenCharacterBuilder<'a> { + SelectScreenCharacterBuilder { + level: Some(level), + ..self + } + } + + fn build(self) -> character::SelectScreenCharacter { + let character = self.character.unwrap(); + let level = self.level.unwrap(); + + character::SelectScreenCharacter { + //exp: character.exp, + level: level - 1, + //guildcard: character.guildcard, + //_unknown: character._unknown3, + //name_color: character.name_color, + //model: character.model, + //_unused: [0; 15], + //name_color_checksum: character.name_color_checksum, + section_id: character.section_id.into(), + ch_class: character.char_class.into(), + //v2flags: character.v2flags, + //version: character.version, + //v1flags: character.v1flags, + costume: character.appearance.costume, + skin: character.appearance.skin, + face: character.appearance.face, + head: character.appearance.head, + hair: character.appearance.hair, + hair_r: character.appearance.hair_r, + hair_g: character.appearance.hair_g, + hair_b: character.appearance.hair_b, + prop_x: character.appearance.prop_x, + prop_y: character.appearance.prop_y, + name: utf8_to_utf16_array!(character.name, 16), + //play_time: character.play_time, + ..character::SelectScreenCharacter::default() + } + } +} + + #[cfg(test)] mod test { use super::*; diff --git a/src/main.rs b/src/main.rs index fa534e3..78e1b75 100644 --- a/src/main.rs +++ b/src/main.rs @@ -75,11 +75,12 @@ fn main() { entity_gateway.set_user(&fake_user); entity_gateway.create_user_settings_by_user(&fake_user); let mut character = entity_gateway.new_character_by_user(&fake_user); - character.character.name = utf8_to_utf16_array!("Test Char 1", 0x10); + character.name = "Test Char 1".into(); entity_gateway.set_character(&character); let mut character = entity_gateway.new_character_by_user(&fake_user); character.slot = 2; - character.character.name = utf8_to_utf16_array!("Test Char 2", 0x10); + character.name = "\tE12345678".into(); + character.exp = 80000000; entity_gateway.set_character(&character); let fake_user2 = UserAccount { @@ -96,11 +97,11 @@ fn main() { entity_gateway.set_user(&fake_user2); entity_gateway.create_user_settings_by_user(&fake_user2); let mut character = entity_gateway.new_character_by_user(&fake_user2); - character.character.name = utf8_to_utf16_array!("Test Char 3", 0x10); + character.name = "Test Char 3".into(); entity_gateway.set_character(&character); let mut character = entity_gateway.new_character_by_user(&fake_user2); character.slot = 2; - character.character.name = utf8_to_utf16_array!("Test Char 4", 0x10); + character.name = "Test Char 4".into(); entity_gateway.set_character(&character); let fake_user3 = UserAccount { @@ -117,11 +118,11 @@ fn main() { entity_gateway.set_user(&fake_user3); entity_gateway.create_user_settings_by_user(&fake_user3); let mut character = entity_gateway.new_character_by_user(&fake_user3); - character.character.name = utf8_to_utf16_array!("Test Char 5", 0x10); + character.name = "Test Char 5".into(); entity_gateway.set_character(&character); let mut character = entity_gateway.new_character_by_user(&fake_user3); character.slot = 2; - character.character.name = utf8_to_utf16_array!("Test Char 6", 0x10); + character.name = "Test Char 6".into(); entity_gateway.set_character(&character); let fake_user4 = UserAccount { @@ -138,11 +139,11 @@ fn main() { entity_gateway.set_user(&fake_user4); entity_gateway.create_user_settings_by_user(&fake_user4); let mut character = entity_gateway.new_character_by_user(&fake_user4); - character.character.name = utf8_to_utf16_array!("Test Char 7", 0x10); + character.name = "Test Char 7".into(); entity_gateway.set_character(&character); let mut character = entity_gateway.new_character_by_user(&fake_user4); character.slot = 2; - character.character.name = utf8_to_utf16_array!("Test Char 8", 0x10); + character.name = "Test Char 8".into(); entity_gateway.set_character(&character); async_std::task::block_on(async move { diff --git a/src/ship/character.rs b/src/ship/character.rs index 23c4645..784d1ef 100644 --- a/src/ship/character.rs +++ b/src/ship/character.rs @@ -1,40 +1,41 @@ -use crate::common::leveltable::CharacterStats; use libpso::character::character; +use crate::common::leveltable::CharacterStats; +use crate::entity::character::Character; use crate::ship::items::Inventory; - -pub struct CharacterBuilder<'a> { - character: Option<&'a character::Character>, +// TODO: exp +pub struct CharacterBytesBuilder<'a> { + character: Option<&'a Character>, stats: Option<&'a CharacterStats>, level: Option, } -impl<'a> CharacterBuilder<'a> { - pub fn new() -> CharacterBuilder<'a> { - CharacterBuilder { +impl<'a> CharacterBytesBuilder<'a> { + pub fn new() -> CharacterBytesBuilder<'a> { + CharacterBytesBuilder { character: None, stats: None, level: None, } } - pub fn character(self, character: &'a character::Character) -> CharacterBuilder<'a> { - CharacterBuilder { + pub fn character(self, character: &'a Character) -> CharacterBytesBuilder<'a> { + CharacterBytesBuilder { character: Some(character), ..self } } - pub fn stats(self, stats: &'a CharacterStats) -> CharacterBuilder<'a> { - CharacterBuilder { + pub fn stats(self, stats: &'a CharacterStats) -> CharacterBytesBuilder<'a> { + CharacterBytesBuilder { stats: Some(stats), ..self } } - pub fn level(self, level: u32) -> CharacterBuilder<'a> { - CharacterBuilder { + pub fn level(self, level: u32) -> CharacterBytesBuilder<'a> { + CharacterBytesBuilder { level: Some(level), ..self } @@ -45,6 +46,7 @@ impl<'a> CharacterBuilder<'a> { let stats = self.stats.unwrap(); let level = self.level.unwrap(); character::Character { + name: libpso::utf8_to_utf16_array!(character.name, 16), hp: stats.hp, atp: stats.atp, mst: stats.mst, @@ -53,53 +55,83 @@ impl<'a> CharacterBuilder<'a> { ata: stats.ata, lck: stats.lck, level: level, - ..*character + section_id: character.section_id.into(), + ch_class: character.char_class.into(), + costume: character.appearance.costume, + skin: character.appearance.skin, + face: character.appearance.face, + head: character.appearance.head, + hair: character.appearance.hair, + hair_r: character.appearance.hair_r, + hair_g: character.appearance.hair_g, + hair_b: character.appearance.hair_b, + prop_x: character.appearance.prop_x, + prop_y: character.appearance.prop_y, + ..character::Character::default() } } } -pub struct FullCharacterBuilder<'a> { - character: Option<&'a character::Character>, +pub struct FullCharacterBytesBuilder<'a> { + character: Option<&'a Character>, + stats: Option<&'a CharacterStats>, + level: Option, inventory: Option<&'a Inventory>, key_config: Option<&'a [u8; 0x16C]>, joystick_config: Option<&'a [u8; 0x38]>, } -impl<'a> FullCharacterBuilder<'a> { - pub fn new() -> FullCharacterBuilder<'a> { - FullCharacterBuilder { +impl<'a> FullCharacterBytesBuilder<'a> { + pub fn new() -> FullCharacterBytesBuilder<'a> { + FullCharacterBytesBuilder { character: None, + stats: None, + level: None, inventory: None, key_config: None, joystick_config: None, } } - pub fn character(self, character: &'a character::Character) -> FullCharacterBuilder<'a> { - FullCharacterBuilder { + pub fn character(self, character: &'a Character) -> FullCharacterBytesBuilder<'a> { + FullCharacterBytesBuilder { character: Some(character), ..self } } - pub fn inventory(self, inventory: &'a Inventory) -> FullCharacterBuilder<'a> { - FullCharacterBuilder { + pub fn stats(self, stats: &'a CharacterStats) -> FullCharacterBytesBuilder<'a> { + FullCharacterBytesBuilder { + stats: Some(stats), + ..self + } + } + + pub fn level(self, level: u32) -> FullCharacterBytesBuilder<'a> { + FullCharacterBytesBuilder { + level: Some(level), + ..self + } + } + + pub fn inventory(self, inventory: &'a Inventory) -> FullCharacterBytesBuilder<'a> { + FullCharacterBytesBuilder { inventory: Some(inventory), ..self } } - pub fn key_config(self, key_config: &'a [u8; 0x16C]) -> FullCharacterBuilder<'a> { - FullCharacterBuilder { + pub fn key_config(self, key_config: &'a [u8; 0x16C]) -> FullCharacterBytesBuilder<'a> { + FullCharacterBytesBuilder { key_config: Some(key_config), ..self } } - pub fn joystick_config(self, joystick_config: &'a [u8; 0x38]) -> FullCharacterBuilder<'a> { - FullCharacterBuilder { + pub fn joystick_config(self, joystick_config: &'a [u8; 0x38]) -> FullCharacterBytesBuilder<'a> { + FullCharacterBytesBuilder { joystick_config: Some(joystick_config), ..self } @@ -107,12 +139,18 @@ impl<'a> FullCharacterBuilder<'a> { pub fn build(self) -> character::FullCharacter { let character = self.character.unwrap(); + let stats = self.stats.unwrap(); + let level = self.level.unwrap(); let inventory = self.inventory.unwrap(); let key_config = self.key_config.unwrap(); let joystick_config = self.joystick_config.unwrap(); - + character::FullCharacter { - character: *character, + character: CharacterBytesBuilder::new() + .character(&character) + .stats(&stats) + .level(level - 1) + .build(), inventory: character::Inventory { item_count: inventory.count() as u8, items: inventory.as_client_inventory_items(), diff --git a/src/ship/ship.rs b/src/ship/ship.rs index ba22e50..1bf140d 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -20,7 +20,7 @@ use crate::entity::character::Character; use crate::entity::item::{ItemLocation, Item}; use crate::login::login::get_login_status; use crate::ship::location::{ClientLocation, LobbyId, RoomId, AreaType, MAX_ROOMS}; -use crate::ship::character::{CharacterBuilder, FullCharacterBuilder}; +use crate::ship::character::{CharacterBytesBuilder, FullCharacterBytesBuilder}; use crate::ship::items; use crate::ship::room; @@ -162,13 +162,14 @@ impl ShipServerState { Ok(match get_login_status(&self.entity_gateway, pkt) { Ok(user) => { let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::new()); - response.guildcard = user.guildcard.map_or(24, |gc| gc) as u32; + response.guildcard = user.id as u32; response.team_id = user.team_id.map_or(31, |ti| ti) as u32; let characters = self.entity_gateway.get_characters_by_user(&user); let character = characters .get(pkt.session.character_slot as usize) - .ok_or(ShipError::InvalidSlot(id, pkt.session.character_slot as u32))? - .ok_or(ShipError::NoCharacterInSlot(id, pkt.session.character_slot as u32))?; + .ok_or(ShipError::InvalidSlot(id, pkt.session.character_slot as u32))?.as_ref() + .ok_or(ShipError::NoCharacterInSlot(id, pkt.session.character_slot as u32))? + .clone(); let settings = self.entity_gateway.get_user_settings_by_user(&user) .ok_or(ShipError::ClientNotFound(id))?; @@ -191,14 +192,12 @@ impl ShipServerState { let client = self.clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; client.block = pkt.item as u32; - let (level, stats) = self.level_table.get_stats_from_exp(character::Class::from(client.character.character.ch_class), client.character.character.exp); + let (level, stats) = self.level_table.get_stats_from_exp(client.character.char_class, client.character.exp); - let fc = FullCharacterBuilder::new() - .character(&CharacterBuilder::new() - .character(&client.character.character) - .stats(&stats) - .level(level - 1) - .build()) + let fc = FullCharacterBytesBuilder::new() + .character(&client.character) + .stats(&stats) + .level(level) .inventory(&client.inventory) .key_config(&client.settings.settings.key_config) .joystick_config(&client.settings.settings.joystick_config) @@ -221,9 +220,9 @@ impl ShipServerState { let playerinfo = clients.iter() .map(|room_client| { let client = self.clients.get(&room_client.client_id).ok_or(ShipError::ClientNotFound(id)).unwrap(); - let (level, stats) = self.level_table.get_stats_from_exp(character::Class::from(client.character.character.ch_class), client.character.character.exp); - let c = CharacterBuilder::new() - .character(&client.character.character) + let (level, stats) = self.level_table.get_stats_from_exp(client.character.char_class, client.character.exp); + let c = CharacterBytesBuilder::new() + .character(&client.character) .stats(&stats) .level(level - 1) .build(); @@ -268,9 +267,9 @@ impl ShipServerState { }; let client = self.clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); - let (level, stats) = self.level_table.get_stats_from_exp(character::Class::from(client.character.character.ch_class), client.character.character.exp); - let c = CharacterBuilder::new() - .character(&client.character.character) + let (level, stats) = self.level_table.get_stats_from_exp(client.character.char_class, client.character.exp); + let c = CharacterBytesBuilder::new() + .character(&client.character) .stats(&stats) .level(level - 1) .build(); @@ -334,7 +333,7 @@ impl ShipServerState { fn player_chat(&mut self, id: ClientId, msg: &PlayerChat) -> Result + Send>, ShipError> { let client = self.clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - let cmsg = PlayerChat::new(client.user.guildcard.unwrap(), msg.message.clone()); + let cmsg = PlayerChat::new(client.user.id, msg.message.clone()); Ok(Box::new(self.client_location.get_area_by_user(id).clients().iter() .map(move |client| { @@ -364,7 +363,7 @@ impl ShipServerState { guildcard: client.user.id, _unknown1: [0; 5], client_id: 0, - name: client.character.character.name, + name: libpso::utf8_to_utf16_array!(client.character.name, 16), _unknown2: 2, }, PlayerHeader::default(), PlayerHeader::default(), PlayerHeader::default()];