From b1653f080865d7fe8e3b33556386682149960e72 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Tue, 1 Apr 2025 18:49:42 -0400 Subject: [PATCH] Commit and restore inventory from the World databse --- src/bin/kawari-world.rs | 30 ++++++++++++++-------------- src/world/connection.rs | 10 +++++----- src/world/database.rs | 43 +++++++++++++++++++++++++++++++++-------- src/world/inventory.rs | 6 ++++-- 4 files changed, 60 insertions(+), 29 deletions(-) diff --git a/src/bin/kawari-world.rs b/src/bin/kawari-world.rs index 671c96e..4da3875 100644 --- a/src/bin/kawari-world.rs +++ b/src/bin/kawari-world.rs @@ -19,11 +19,11 @@ use kawari::world::ipc::{ ServerZoneIpcData, ServerZoneIpcSegment, SocialListRequestType, }; use kawari::world::{ - Actor, ClientHandle, ClientId, EffectsBuilder, FromServer, LuaPlayer, PlayerData, ServerHandle, - StatusEffects, ToServer, WorldDatabase, + Actor, ClientHandle, ClientId, EffectsBuilder, FromServer, Inventory, LuaPlayer, PlayerData, + ServerHandle, StatusEffects, ToServer, WorldDatabase, }; use kawari::world::{ - ChatHandler, Inventory, Zone, ZoneConnection, + ChatHandler, Zone, ZoneConnection, ipc::{ ActorControlCategory, ActorControlSelf, PlayerEntry, PlayerSetup, PlayerSpawn, PlayerStats, SocialList, @@ -276,12 +276,6 @@ async fn client_loop( let chara_details = database.find_chara_make(connection.player_data.content_id); - // fill inventory - connection.inventory.equip_racial_items( - chara_details.chara_make.customize.race, - chara_details.chara_make.customize.gender, - ); - // Send inventory connection.send_inventory(false).await; @@ -389,7 +383,7 @@ async fn client_loop( let ipc; { let mut game_data = game_data.lock().unwrap(); - let equipped = &connection.inventory.equipped; + let equipped = &connection.player_data.inventory.equipped; ipc = ServerZoneIpcSegment { op_code: ServerZoneIpcType::PlayerSpawn, @@ -656,8 +650,8 @@ async fn client_loop( }) .await, GameMasterCommandType::GiveItem => { - connection.inventory.extra_slot.id = *arg; - connection.inventory.extra_slot.quantity = 1; + connection.player_data.inventory.extra_slot.id = *arg; + connection.player_data.inventory.extra_slot.quantity = 1; connection.send_inventory(false).await; } } @@ -821,7 +815,7 @@ async fn client_loop( ClientZoneIpcData::InventoryModify(action) => { tracing::info!("Client is modifying inventory! {action:#?}"); - connection.inventory.process_action(&action); + connection.player_data.inventory.process_action(&action); connection.send_inventory(true).await; } } @@ -857,11 +851,20 @@ async fn client_loop( game_data.get_citystate(chara_make.classjob_id as u16); } + let mut inventory = Inventory::new(); + + // fill inventory + inventory.equip_racial_items( + chara_make.customize.race, + chara_make.customize.gender, + ); + let (content_id, actor_id) = database.create_player_data( name, chara_make_json, city_state, determine_initial_starting_zone(city_state), + inventory ); tracing::info!("Created new player: {content_id} {actor_id}"); @@ -1117,7 +1120,6 @@ async fn main() { player_data: PlayerData::default(), spawn_index: 0, zone: None, - inventory: Inventory::new(), status_effects: StatusEffects::default(), event: None, actors: Vec::new(), diff --git a/src/world/connection.rs b/src/world/connection.rs index 963024c..befad2e 100644 --- a/src/world/connection.rs +++ b/src/world/connection.rs @@ -47,6 +47,7 @@ pub struct PlayerData { /// In radians. pub rotation: f32, pub zone_id: u16, + pub inventory: Inventory, } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] @@ -128,7 +129,6 @@ pub struct ZoneConnection { pub zone: Option, pub spawn_index: u8, - pub inventory: Inventory, pub status_effects: StatusEffects, pub event: Option, @@ -450,7 +450,7 @@ impl ZoneConnection { pub async fn send_inventory(&mut self, send_appearance_update: bool) { // page 1 { - let extra_slot = self.inventory.extra_slot; + let extra_slot = self.player_data.inventory.extra_slot; let mut send_slot = async |slot_index: u16, item: &Item| { let ipc = ServerZoneIpcSegment { @@ -480,7 +480,7 @@ impl ZoneConnection { // equipped { - let equipped = self.inventory.equipped; + let equipped = self.player_data.inventory.equipped; let mut send_slot = async |slot_index: u16, item: &Item| { let ipc = ServerZoneIpcSegment { @@ -548,7 +548,7 @@ impl ZoneConnection { timestamp: timestamp_secs(), data: ServerZoneIpcData::ContainerInfo(ContainerInfo { container: ContainerType::Equipped, - num_items: self.inventory.equipped.num_items(), + num_items: self.player_data.inventory.equipped.num_items(), sequence: 1, ..Default::default() }), @@ -568,7 +568,7 @@ impl ZoneConnection { let ipc; { let mut game_data = self.gamedata.lock().unwrap(); - let equipped = &self.inventory.equipped; + let equipped = &self.player_data.inventory.equipped; ipc = ServerZoneIpcSegment { op_code: ServerZoneIpcType::Equip, diff --git a/src/world/database.rs b/src/world/database.rs index 6e1bd55..e9c7b00 100644 --- a/src/world/database.rs +++ b/src/world/database.rs @@ -11,7 +11,7 @@ use crate::{ }, }; -use super::PlayerData; +use super::{Inventory, PlayerData}; pub struct WorldDatabase { connection: Mutex, @@ -43,7 +43,7 @@ impl WorldDatabase { // Create characters data table { - let query = "CREATE TABLE IF NOT EXISTS character_data (content_id INTEGER PRIMARY KEY, name STRING, chara_make STRING, city_state INTEGER, zone_id INTEGER, pos_x REAL, pos_y REAL, pos_z REAL, rotation REAL);"; + let query = "CREATE TABLE IF NOT EXISTS character_data (content_id INTEGER PRIMARY KEY, name STRING, chara_make STRING, city_state INTEGER, zone_id INTEGER, pos_x REAL, pos_y REAL, pos_z REAL, rotation REAL, inventory STRING);"; connection.execute(query, ()).unwrap(); } @@ -111,7 +111,14 @@ impl WorldDatabase { }; // TODO: extract city-state - self.create_player_data(&character.name, &chara_make.to_json(), 2, 132); + // TODO: import inventory + self.create_player_data( + &character.name, + &chara_make.to_json(), + 2, + 132, + Inventory::new(), + ); tracing::info!("{} added to the world!", character.name); } @@ -127,9 +134,16 @@ impl WorldDatabase { .unwrap(); stmt = connection - .prepare("SELECT pos_x, pos_y, pos_z, rotation, zone_id FROM character_data WHERE content_id = ?1") + .prepare("SELECT pos_x, pos_y, pos_z, rotation, zone_id, inventory FROM character_data WHERE content_id = ?1") .unwrap(); - let (pos_x, pos_y, pos_z, rotation, zone_id) = stmt + let (pos_x, pos_y, pos_z, rotation, zone_id, inventory_json): ( + f32, + f32, + f32, + f32, + u16, + String, + ) = stmt .query_row((content_id,), |row| { Ok(( row.get(0)?, @@ -137,10 +151,13 @@ impl WorldDatabase { row.get(2)?, row.get(3)?, row.get(4)?, + row.get(5)?, )) }) .unwrap(); + let inventory = serde_json::from_str(&inventory_json).unwrap(); + PlayerData { actor_id, content_id, @@ -152,6 +169,7 @@ impl WorldDatabase { }, rotation, zone_id, + inventory, ..Default::default() } } @@ -161,7 +179,7 @@ impl WorldDatabase { let connection = self.connection.lock().unwrap(); let mut stmt = connection - .prepare("UPDATE character_data SET zone_id=?1, pos_x=?2, pos_y=?3, pos_z=?4, rotation=?5 WHERE content_id = ?6") + .prepare("UPDATE character_data SET zone_id=?1, pos_x=?2, pos_y=?3, pos_z=?4, rotation=?5, inventory=?6 WHERE content_id = ?7") .unwrap(); stmt.execute(( data.zone_id, @@ -169,6 +187,7 @@ impl WorldDatabase { data.position.y, data.position.z, data.rotation, + serde_json::to_string(&data.inventory).unwrap(), data.content_id, )) .unwrap(); @@ -293,6 +312,7 @@ impl WorldDatabase { chara_make: &str, city_state: u8, zone_id: u16, + inventory: Inventory, ) -> (u64, u32) { let content_id = Self::generate_content_id(); let actor_id = Self::generate_actor_id(); @@ -310,8 +330,15 @@ impl WorldDatabase { // insert char data connection .execute( - "INSERT INTO character_data VALUES (?1, ?2, ?3, ?4, ?5, 0.0, 0.0, 0.0, 0.0);", - (content_id, name, chara_make, city_state, zone_id), + "INSERT INTO character_data VALUES (?1, ?2, ?3, ?4, ?5, 0.0, 0.0, 0.0, 0.0, ?6);", + ( + content_id, + name, + chara_make, + city_state, + zone_id, + serde_json::to_string(&inventory).unwrap(), + ), ) .unwrap(); diff --git a/src/world/inventory.rs b/src/world/inventory.rs index 4f8127e..076eb78 100644 --- a/src/world/inventory.rs +++ b/src/world/inventory.rs @@ -2,12 +2,13 @@ use physis::{ common::{Language, Platform}, gamedata::GameData, }; +use serde::{Deserialize, Serialize}; use crate::config::get_config; use super::ipc::{ContainerType, InventoryModify}; -#[derive(Default, Copy, Clone)] +#[derive(Default, Copy, Clone, Serialize, Deserialize, Debug)] pub struct Item { pub quantity: u32, pub id: u32, @@ -19,7 +20,7 @@ impl Item { } } -#[derive(Default, Clone, Copy)] +#[derive(Default, Clone, Copy, Deserialize, Serialize, Debug)] pub struct EquippedContainer { pub main_hand: Item, pub off_hand: Item, @@ -73,6 +74,7 @@ impl EquippedContainer { } } +#[derive(Debug, Clone, Copy, Deserialize, Serialize)] pub struct Inventory { pub equipped: EquippedContainer, pub extra_slot: Item, // WIP for inventory pages