use std::collections::HashMap; use std::convert::Into; use serde::{Serialize, Deserialize}; use libpso::character::settings; use libpso::util::vec_to_array; use crate::entity::account::*; use crate::entity::character::*; use crate::entity::item::*; use crate::ship::map::MapArea; #[derive(Debug, sqlx::FromRow)] pub struct PgUserAccount { id: i32, username: String, password: String, banned: Option>, muted: Option>, created_at: chrono::DateTime, flags: i32, activated: bool, at_login: bool, at_character: bool, at_ship: bool, } impl Into for PgUserAccount { fn into(self) -> UserAccountEntity { UserAccountEntity { id: UserAccountId(self.id as u32), username: self.username, password: self.password, banned_until: self.banned, muted_until: self.muted, created_at: self.created_at, flags: self.flags as u32, guildcard: self.id as u32 + 1, team_id: None, activated: self.activated, at_login: self.at_login, at_character: self.at_character, at_ship: self.at_ship, } } } #[derive(Debug, sqlx::FromRow)] pub struct PgUserSettings { id: i32, user_account: i32, blocked_users: Vec, //[u32; 0x1E], key_config: Vec, //[u8; 0x16C], joystick_config: Vec, //[u8; 0x38], option_flags: i32, shortcuts: Vec, //[u8; 0xA40], symbol_chats: Vec, //[u8; 0x4E0], team_name: Vec, //[u16; 0x10], } impl Into for PgUserSettings { fn into(self) -> UserSettingsEntity { UserSettingsEntity { id: UserSettingsId(self.id as u32), user_id: UserAccountId(self.user_account as u32), settings: settings::UserSettings { blocked_users: vec_to_array(self.blocked_users.chunks(4).map(|b| u32::from_le_bytes([b[0], b[1], b[2], b[3]])).collect()), key_config: vec_to_array(self.key_config), joystick_config: vec_to_array(self.joystick_config), option_flags: self.option_flags as u32, shortcuts: vec_to_array(self.shortcuts), symbol_chats: vec_to_array(self.symbol_chats), team_name: vec_to_array(self.team_name.chunks(2).map(|b| u16::from_le_bytes([b[0], b[1]])).collect()), } } } } #[derive(sqlx::Type, Debug)] #[sqlx(rename_all = "lowercase")] pub enum PgCharacterClass { HUmar, HUnewearl, HUcast, HUcaseal, RAmar, RAmarl, RAcast, RAcaseal, FOmar, FOmarl, FOnewm, FOnewearl, } impl Into for PgCharacterClass { fn into(self) -> CharacterClass { match self { PgCharacterClass::HUmar => CharacterClass::HUmar, PgCharacterClass::HUnewearl => CharacterClass::HUnewearl, PgCharacterClass::HUcast => CharacterClass::HUcast, PgCharacterClass::HUcaseal => CharacterClass::HUcaseal, PgCharacterClass::RAmar => CharacterClass::RAmar, PgCharacterClass::RAmarl => CharacterClass::RAmarl, PgCharacterClass::RAcast => CharacterClass::RAcast, PgCharacterClass::RAcaseal => CharacterClass::RAcaseal, PgCharacterClass::FOmar => CharacterClass::FOmar, PgCharacterClass::FOmarl => CharacterClass::FOmarl, PgCharacterClass::FOnewm => CharacterClass::FOnewm, PgCharacterClass::FOnewearl => CharacterClass::FOnewearl, } } } impl From for PgCharacterClass { fn from(other: CharacterClass) -> PgCharacterClass { match other { CharacterClass::HUmar => PgCharacterClass::HUmar, CharacterClass::HUnewearl => PgCharacterClass::HUnewearl, CharacterClass::HUcast => PgCharacterClass::HUcast, CharacterClass::HUcaseal => PgCharacterClass::HUcaseal, CharacterClass::RAmar => PgCharacterClass::RAmar, CharacterClass::RAmarl => PgCharacterClass::RAmarl, CharacterClass::RAcast => PgCharacterClass::RAcast, CharacterClass::RAcaseal => PgCharacterClass::RAcaseal, CharacterClass::FOmar => PgCharacterClass::FOmar, CharacterClass::FOmarl => PgCharacterClass::FOmarl, CharacterClass::FOnewm => PgCharacterClass::FOnewm, CharacterClass::FOnewearl => PgCharacterClass::FOnewearl, } } } #[derive(sqlx::Type, Debug)] #[sqlx(rename_all = "lowercase")] pub enum PgSectionId { Viridia, Greenill, Skyly, Bluefull, Purplenum, Pinkal, Redria, Oran, Yellowboze, Whitill, } impl Into for PgSectionId { fn into(self) -> SectionID { match self { PgSectionId::Viridia => SectionID::Viridia, PgSectionId::Greenill => SectionID::Greenill, PgSectionId::Skyly => SectionID::Skyly, PgSectionId::Bluefull => SectionID::Bluefull, PgSectionId::Purplenum => SectionID::Purplenum, PgSectionId::Pinkal => SectionID::Pinkal, PgSectionId::Redria => SectionID::Redria, PgSectionId::Oran => SectionID::Oran, PgSectionId::Yellowboze => SectionID::Yellowboze, PgSectionId::Whitill => SectionID::Whitill, } } } impl From for PgSectionId { fn from(other: SectionID) -> PgSectionId { match other { SectionID::Viridia => PgSectionId::Viridia, SectionID::Greenill => PgSectionId::Greenill, SectionID::Skyly => PgSectionId::Skyly, SectionID::Bluefull => PgSectionId::Bluefull, SectionID::Purplenum => PgSectionId::Purplenum, SectionID::Pinkal => PgSectionId::Pinkal, SectionID::Redria => PgSectionId::Redria, SectionID::Oran => PgSectionId::Oran, SectionID::Yellowboze => PgSectionId::Yellowboze, SectionID::Whitill => PgSectionId::Whitill, } } } #[derive(Debug, sqlx::FromRow)] pub struct PgCharacter { pub id: i32, user_account: i32, pub slot: i16, name: String, exp: i32, class: String, section_id: String, costume: i16, skin: i16, face: i16, head: i16, hair: i16, hair_r: i16, hair_g: i16, hair_b: i16, prop_x: f32, prop_y: f32, techs: Vec, config: Vec, infoboard: String, guildcard: String, option_flags: i32, power: i16, mind: i16, def: i16, evade: i16, luck: i16, hp: i16, tp: i16, tech_menu: Vec, meseta: i32, bank_meseta: i32, } impl Into for PgCharacter { fn into(self) -> CharacterEntity { CharacterEntity { id: CharacterEntityId(self.id as u32), user_id: UserAccountId(self.user_account as u32), slot: self.slot as u32, name: self.name, exp: self.exp as u32, char_class: self.class.parse().unwrap(), section_id: self.section_id.parse().unwrap(), appearance: CharacterAppearance { costume: self.costume as u16, skin: self.skin as u16, face: self.face as u16, head: self.head as u16, hair: self.hair as u16, hair_r: self.hair_r as u16, hair_g: self.hair_g as u16, hair_b: self.hair_b as u16, prop_x: self.prop_x, prop_y: self.prop_y, }, techs: CharacterTechniques { techs: self.techs.iter().enumerate().take(19).filter(|(_, t)| **t != 0xFF).map(|(i, t)| (tech::Technique::from_value(i as u8), TechLevel(*t)) ).collect() }, config: CharacterConfig { raw_data: vec_to_array(self.config) }, info_board: CharacterInfoboard { board: libpso::utf8_to_utf16_array!(self.infoboard, 172), }, guildcard: CharacterGuildCard { description: self.guildcard, }, option_flags: self.option_flags as u32, materials: CharacterMaterials { power: self.power as u32, mind: self.mind as u32, def: self.def as u32, evade: self.evade as u32, luck: self.luck as u32, hp: self.hp as u32, tp: self.tp as u32, }, tech_menu: CharacterTechMenu { tech_menu: vec_to_array(self.tech_menu) }, meseta: self.meseta as u32, bank_meseta: self.bank_meseta as u32, } } } #[derive(Debug, sqlx::FromRow)] pub struct PgGuildCard { } #[derive(Debug, Serialize, Deserialize)] pub struct PgWeapon { weapon: weapon::WeaponType, special: Option, grind: u8, attrs: HashMap, tekked: bool, } impl From for PgWeapon { fn from(other: weapon::Weapon) -> PgWeapon { PgWeapon { weapon: other.weapon, special: other.special, grind: other.grind, attrs: other.attrs.iter().flatten().map(|attr| (attr.attr, attr.value)).collect(), tekked: other.tekked, } } } impl Into for PgWeapon { fn into(self) -> weapon::Weapon { let mut attrs: [Option; 3] = [None; 3]; for (attr, (atype, value)) in attrs.iter_mut().zip(self.attrs.iter()) { *attr = Some(weapon::WeaponAttribute { attr: *atype, value: *value }); } weapon::Weapon { weapon: self.weapon, special: self.special, grind: self.grind, attrs: attrs, tekked: self.tekked, modifiers: Vec::new(), } } } #[derive(Debug, Serialize, Deserialize)] pub struct PgArmor { armor: armor::ArmorType, dfp: u8, evp: u8, slots: u8, } impl From for PgArmor { fn from(other: armor::Armor) -> PgArmor { PgArmor { armor: other.armor, dfp: other.dfp, evp: other.evp, slots: other.slots, } } } impl Into for PgArmor { fn into(self) -> armor::Armor { armor::Armor { armor: self.armor, dfp: self.dfp, evp: self.evp, slots: self.slots, modifiers: Vec::new(), } } } #[derive(Debug, Serialize, Deserialize)] pub struct PgShield { shield: shield::ShieldType, dfp: u8, evp: u8, } impl From for PgShield { fn from(other: shield::Shield) -> PgShield { PgShield { shield: other.shield, dfp: other.dfp, evp: other.evp, } } } impl Into for PgShield { fn into(self) -> shield::Shield { shield::Shield { shield: self.shield, dfp: self.dfp, evp: self.evp, } } } #[derive(Debug, Serialize, Deserialize)] pub struct PgUnit { unit: unit::UnitType, modifier: Option, armor_slot: u8, } impl From for PgUnit { fn from(other: unit::Unit) -> PgUnit { PgUnit { unit: other.unit, modifier: other.modifier, armor_slot: other.armor_slot, } } } impl Into for PgUnit { fn into(self) -> unit::Unit { unit::Unit { unit: self.unit, modifier: self.modifier, armor_slot: self.armor_slot, } } } #[derive(Debug, Serialize, Deserialize)] pub struct PgTool { pub tool: tool::ToolType, } impl From for PgTool { fn from(other: tool::Tool) -> PgTool { PgTool { tool: other.tool, } } } impl Into for PgTool { fn into(self) -> tool::Tool { tool::Tool { tool: self.tool, } } } #[derive(Debug, Serialize, Deserialize)] pub struct PgTechDisk { tech: tech::Technique, level: u32, } impl From for PgTechDisk { fn from(other: tech::TechniqueDisk) -> PgTechDisk { PgTechDisk { tech: other.tech, level: other.level, } } } impl Into for PgTechDisk { fn into(self) -> tech::TechniqueDisk { tech::TechniqueDisk { tech: self.tech, level: self.level } } } #[derive(Debug, Serialize, Deserialize)] pub struct PgMag { mag: mag::MagType, synchro: u8, color: u8, } impl From for PgMag { fn from(other: mag::Mag) -> PgMag { PgMag { mag: other.mag, synchro: other.synchro, color: other.color, } } } impl Into for PgMag { fn into(self) -> mag::Mag { /*mag::Mag { mag: self.mag, synchro: self.synchro, color: self.color, def: 500, pow: 0, dex: 0, mnd: 0, iq: 0, photon_blast: [None; 3], class: CharacterClass::HUmar, id: SectionID::Viridia, }*/ let mut mag = mag::Mag::baby_mag(self.color as u16); mag.mag = self.mag; mag.synchro = self.synchro; mag } } #[derive(Debug, Serialize, Deserialize)] pub struct PgESWeapon { esweapon: esweapon::ESWeaponType, special: Option, name: String, grind: u8, } impl From for PgESWeapon { fn from(other: esweapon::ESWeapon) -> PgESWeapon { PgESWeapon { esweapon: other.esweapon, special: other.special, name: other.name, grind: other.grind, } } } impl Into for PgESWeapon { fn into(self) -> esweapon::ESWeapon { esweapon::ESWeapon { esweapon: self.esweapon, special: self.special, name: self.name, grind: self.grind, } } } #[derive(Debug, Serialize, Deserialize)] pub enum PgItemDetail { Weapon(PgWeapon), Armor(PgArmor), Shield(PgShield), Unit(PgUnit), Tool(PgTool), TechDisk(PgTechDisk), Mag(PgMag), ESWeapon(PgESWeapon), } impl From for PgItemDetail { fn from(other: ItemDetail) -> PgItemDetail { match other { ItemDetail::Weapon(weapon) => PgItemDetail::Weapon(weapon.into()), ItemDetail::Armor(armor) => PgItemDetail::Armor(armor.into()), ItemDetail::Shield(shield) => PgItemDetail::Shield(shield.into()), ItemDetail::Unit(unit) => PgItemDetail::Unit(unit.into()), ItemDetail::Tool(tool) => PgItemDetail::Tool(tool.into()), ItemDetail::TechniqueDisk(tech_disk) => PgItemDetail::TechDisk(tech_disk.into()), ItemDetail::Mag(mag) => PgItemDetail::Mag(mag.into()), ItemDetail::ESWeapon(esweapon) => PgItemDetail::ESWeapon(esweapon.into()), } } } impl Into for PgItemDetail { fn into(self) -> ItemDetail { match self { PgItemDetail::Weapon(weapon) => ItemDetail::Weapon(weapon.into()), PgItemDetail::Armor(armor) => ItemDetail::Armor(armor.into()), PgItemDetail::Shield(shield) => ItemDetail::Shield(shield.into()), PgItemDetail::Unit(unit) => ItemDetail::Unit(unit.into()), PgItemDetail::Tool(tool) => ItemDetail::Tool(tool.into()), PgItemDetail::TechDisk(tech_disk) => ItemDetail::TechniqueDisk(tech_disk.into()), PgItemDetail::Mag(mag) => ItemDetail::Mag(mag.into()), PgItemDetail::ESWeapon(esweapon) => ItemDetail::ESWeapon(esweapon.into()), } } } #[derive(Debug, sqlx::FromRow)] pub struct PgItem { pub id: i32, pub item: sqlx::types::Json, } #[derive(Debug, Serialize, Deserialize)] pub enum PgItemLocationDetail { Inventory { character_id: u32, #[serde(skip_serializing)] slot: usize, equipped: bool, }, Bank { character_id: u32, name: String, }, LocalFloor { character_id: u32, map_area: MapArea, x: f32, y: f32, z: f32, }, SharedFloor { map_area: MapArea, x: f32, y: f32, z: f32, }, Consumed, FedToMag { mag: u32, }, Shop, } impl From for PgItemLocationDetail { fn from(other: ItemLocation) -> PgItemLocationDetail { match other { ItemLocation::Inventory{character_id, slot, equipped} => PgItemLocationDetail::Inventory{character_id: character_id.0, slot, equipped}, ItemLocation::Bank{character_id, name} => PgItemLocationDetail::Bank{character_id: character_id.0, name: name.0}, ItemLocation::LocalFloor{character_id, map_area, x,y,z} => PgItemLocationDetail::LocalFloor{character_id: character_id.0, map_area, x,y,z}, ItemLocation::SharedFloor{map_area, x,y,z} => PgItemLocationDetail::SharedFloor{map_area, x,y,z}, ItemLocation::Consumed => PgItemLocationDetail::Consumed, ItemLocation::FedToMag{mag} => PgItemLocationDetail::FedToMag{mag: mag.0}, ItemLocation::Shop => PgItemLocationDetail::Shop, } } } impl Into for PgItemLocationDetail { fn into(self) -> ItemLocation { match self { PgItemLocationDetail::Inventory{character_id, slot, equipped} => ItemLocation::Inventory{character_id: CharacterEntityId(character_id), slot, equipped}, PgItemLocationDetail::Bank{character_id, name} => ItemLocation::Bank{character_id: CharacterEntityId(character_id), name: BankName(name)}, PgItemLocationDetail::LocalFloor{character_id, map_area, x,y,z} => ItemLocation::LocalFloor{character_id: CharacterEntityId(character_id), map_area, x,y,z}, PgItemLocationDetail::SharedFloor{map_area, x,y,z} => ItemLocation::SharedFloor{map_area, x,y,z}, PgItemLocationDetail::Consumed => ItemLocation::Consumed, PgItemLocationDetail::FedToMag{mag} => ItemLocation::FedToMag{mag: ItemEntityId(mag)}, PgItemLocationDetail::Shop => ItemLocation::Shop, } } } #[derive(Debug, sqlx::FromRow)] pub struct PgItemLocation { //pub id: i32, pub location: sqlx::types::Json, created_at: chrono::DateTime, } #[derive(Debug, Serialize, Deserialize)] pub enum PgMagModifierDetail { FeedMag(i32), BankMag, MagCell(i32), OwnerChange(CharacterClass, SectionID) } impl From for PgMagModifierDetail { fn from(other: mag::MagModifier) -> PgMagModifierDetail { match other { mag::MagModifier::FeedMag{food} => PgMagModifierDetail::FeedMag(food.0 as i32), mag::MagModifier::BankMag => PgMagModifierDetail::BankMag, mag::MagModifier::MagCell(cell) => PgMagModifierDetail::MagCell(cell.0 as i32), mag::MagModifier::OwnerChange(class, section_id) => PgMagModifierDetail::OwnerChange(class, section_id), } } } impl Into for PgMagModifierDetail { fn into(self) -> mag::MagModifier { match self { PgMagModifierDetail::FeedMag(food) => mag::MagModifier::FeedMag{food: ItemEntityId(food as u32)}, PgMagModifierDetail::BankMag => mag::MagModifier::BankMag, PgMagModifierDetail::MagCell(cell) => mag::MagModifier::MagCell(ItemEntityId(cell as u32)), PgMagModifierDetail::OwnerChange(class, section_id) => mag::MagModifier::OwnerChange(class, section_id), } } } #[derive(Debug, sqlx::FromRow)] pub struct PgMagModifier { mag: i32, pub modifier: sqlx::types::Json, created_at: chrono::DateTime, } #[derive(Debug, sqlx::FromRow)] pub struct PgItemWithLocation { pub id: i32, pub item: sqlx::types::Json, pub location: sqlx::types::Json, } #[derive(Debug, sqlx::FromRow)] pub struct PgMagModifierWithParameters { pub mag: i32, pub modifier: sqlx::types::Json, pub feed: Option>, pub cell: Option>, }