use proper data structs that convert to what pso wants
This commit is contained in:
		
							parent
							
								
									81043891a1
								
							
						
					
					
						commit
						a74941441b
					
				| @ -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<Class, [CharacterLevelEntry; 200]>, | ||||
|     table: HashMap<CharacterClass, [CharacterLevelEntry; 200]>, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -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 })); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -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<u8> 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<u8> 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<u8> 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<u8> 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<Techniques, TechLevel> | ||||
| } | ||||
| 
 | ||||
| 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(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -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<EG: EntityGateway> { | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| fn new_character<EG: EntityGateway>(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<EG: EntityGateway> CharacterServerState<EG> { | ||||
|         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<EG: EntityGateway> ServerState for CharacterServerState<EG> { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 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<u32>, | ||||
| } | ||||
| 
 | ||||
| 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::*; | ||||
|  | ||||
							
								
								
									
										17
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								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 { | ||||
|  | ||||
| @ -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<u32>, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 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<u32>, | ||||
|     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(), | ||||
|  | ||||
| @ -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<EG: EntityGateway> ShipServerState<EG> { | ||||
|         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<EG: EntityGateway> ShipServerState<EG> { | ||||
|         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<EG: EntityGateway> ShipServerState<EG> { | ||||
|         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<EG: EntityGateway> ShipServerState<EG> { | ||||
|         }; | ||||
| 
 | ||||
|         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<EG: EntityGateway> ShipServerState<EG> { | ||||
| 
 | ||||
|     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.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<EG: EntityGateway> ShipServerState<EG> { | ||||
|             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()]; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user