1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-05-04 12:07:44 +00:00

Commit and restore inventory from the World databse

This commit is contained in:
Joshua Goins 2025-04-01 18:49:42 -04:00
parent fed21b3617
commit b1653f0808
4 changed files with 60 additions and 29 deletions

View file

@ -19,11 +19,11 @@ use kawari::world::ipc::{
ServerZoneIpcData, ServerZoneIpcSegment, SocialListRequestType, ServerZoneIpcData, ServerZoneIpcSegment, SocialListRequestType,
}; };
use kawari::world::{ use kawari::world::{
Actor, ClientHandle, ClientId, EffectsBuilder, FromServer, LuaPlayer, PlayerData, ServerHandle, Actor, ClientHandle, ClientId, EffectsBuilder, FromServer, Inventory, LuaPlayer, PlayerData,
StatusEffects, ToServer, WorldDatabase, ServerHandle, StatusEffects, ToServer, WorldDatabase,
}; };
use kawari::world::{ use kawari::world::{
ChatHandler, Inventory, Zone, ZoneConnection, ChatHandler, Zone, ZoneConnection,
ipc::{ ipc::{
ActorControlCategory, ActorControlSelf, PlayerEntry, PlayerSetup, PlayerSpawn, PlayerStats, ActorControlCategory, ActorControlSelf, PlayerEntry, PlayerSetup, PlayerSpawn, PlayerStats,
SocialList, SocialList,
@ -276,12 +276,6 @@ async fn client_loop(
let chara_details = let chara_details =
database.find_chara_make(connection.player_data.content_id); 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 // Send inventory
connection.send_inventory(false).await; connection.send_inventory(false).await;
@ -389,7 +383,7 @@ async fn client_loop(
let ipc; let ipc;
{ {
let mut game_data = game_data.lock().unwrap(); let mut game_data = game_data.lock().unwrap();
let equipped = &connection.inventory.equipped; let equipped = &connection.player_data.inventory.equipped;
ipc = ServerZoneIpcSegment { ipc = ServerZoneIpcSegment {
op_code: ServerZoneIpcType::PlayerSpawn, op_code: ServerZoneIpcType::PlayerSpawn,
@ -656,8 +650,8 @@ async fn client_loop(
}) })
.await, .await,
GameMasterCommandType::GiveItem => { GameMasterCommandType::GiveItem => {
connection.inventory.extra_slot.id = *arg; connection.player_data.inventory.extra_slot.id = *arg;
connection.inventory.extra_slot.quantity = 1; connection.player_data.inventory.extra_slot.quantity = 1;
connection.send_inventory(false).await; connection.send_inventory(false).await;
} }
} }
@ -821,7 +815,7 @@ async fn client_loop(
ClientZoneIpcData::InventoryModify(action) => { ClientZoneIpcData::InventoryModify(action) => {
tracing::info!("Client is modifying inventory! {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; connection.send_inventory(true).await;
} }
} }
@ -857,11 +851,20 @@ async fn client_loop(
game_data.get_citystate(chara_make.classjob_id as u16); 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( let (content_id, actor_id) = database.create_player_data(
name, name,
chara_make_json, chara_make_json,
city_state, city_state,
determine_initial_starting_zone(city_state), determine_initial_starting_zone(city_state),
inventory
); );
tracing::info!("Created new player: {content_id} {actor_id}"); tracing::info!("Created new player: {content_id} {actor_id}");
@ -1117,7 +1120,6 @@ async fn main() {
player_data: PlayerData::default(), player_data: PlayerData::default(),
spawn_index: 0, spawn_index: 0,
zone: None, zone: None,
inventory: Inventory::new(),
status_effects: StatusEffects::default(), status_effects: StatusEffects::default(),
event: None, event: None,
actors: Vec::new(), actors: Vec::new(),

View file

@ -47,6 +47,7 @@ pub struct PlayerData {
/// In radians. /// In radians.
pub rotation: f32, pub rotation: f32,
pub zone_id: u16, pub zone_id: u16,
pub inventory: Inventory,
} }
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
@ -128,7 +129,6 @@ pub struct ZoneConnection {
pub zone: Option<Zone>, pub zone: Option<Zone>,
pub spawn_index: u8, pub spawn_index: u8,
pub inventory: Inventory,
pub status_effects: StatusEffects, pub status_effects: StatusEffects,
pub event: Option<Event>, pub event: Option<Event>,
@ -450,7 +450,7 @@ impl ZoneConnection {
pub async fn send_inventory(&mut self, send_appearance_update: bool) { pub async fn send_inventory(&mut self, send_appearance_update: bool) {
// page 1 // 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 mut send_slot = async |slot_index: u16, item: &Item| {
let ipc = ServerZoneIpcSegment { let ipc = ServerZoneIpcSegment {
@ -480,7 +480,7 @@ impl ZoneConnection {
// equipped // equipped
{ {
let equipped = self.inventory.equipped; let equipped = self.player_data.inventory.equipped;
let mut send_slot = async |slot_index: u16, item: &Item| { let mut send_slot = async |slot_index: u16, item: &Item| {
let ipc = ServerZoneIpcSegment { let ipc = ServerZoneIpcSegment {
@ -548,7 +548,7 @@ impl ZoneConnection {
timestamp: timestamp_secs(), timestamp: timestamp_secs(),
data: ServerZoneIpcData::ContainerInfo(ContainerInfo { data: ServerZoneIpcData::ContainerInfo(ContainerInfo {
container: ContainerType::Equipped, container: ContainerType::Equipped,
num_items: self.inventory.equipped.num_items(), num_items: self.player_data.inventory.equipped.num_items(),
sequence: 1, sequence: 1,
..Default::default() ..Default::default()
}), }),
@ -568,7 +568,7 @@ impl ZoneConnection {
let ipc; let ipc;
{ {
let mut game_data = self.gamedata.lock().unwrap(); let mut game_data = self.gamedata.lock().unwrap();
let equipped = &self.inventory.equipped; let equipped = &self.player_data.inventory.equipped;
ipc = ServerZoneIpcSegment { ipc = ServerZoneIpcSegment {
op_code: ServerZoneIpcType::Equip, op_code: ServerZoneIpcType::Equip,

View file

@ -11,7 +11,7 @@ use crate::{
}, },
}; };
use super::PlayerData; use super::{Inventory, PlayerData};
pub struct WorldDatabase { pub struct WorldDatabase {
connection: Mutex<Connection>, connection: Mutex<Connection>,
@ -43,7 +43,7 @@ impl WorldDatabase {
// Create characters data table // 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(); connection.execute(query, ()).unwrap();
} }
@ -111,7 +111,14 @@ impl WorldDatabase {
}; };
// TODO: extract city-state // 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); tracing::info!("{} added to the world!", character.name);
} }
@ -127,9 +134,16 @@ impl WorldDatabase {
.unwrap(); .unwrap();
stmt = connection 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(); .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| { .query_row((content_id,), |row| {
Ok(( Ok((
row.get(0)?, row.get(0)?,
@ -137,10 +151,13 @@ impl WorldDatabase {
row.get(2)?, row.get(2)?,
row.get(3)?, row.get(3)?,
row.get(4)?, row.get(4)?,
row.get(5)?,
)) ))
}) })
.unwrap(); .unwrap();
let inventory = serde_json::from_str(&inventory_json).unwrap();
PlayerData { PlayerData {
actor_id, actor_id,
content_id, content_id,
@ -152,6 +169,7 @@ impl WorldDatabase {
}, },
rotation, rotation,
zone_id, zone_id,
inventory,
..Default::default() ..Default::default()
} }
} }
@ -161,7 +179,7 @@ impl WorldDatabase {
let connection = self.connection.lock().unwrap(); let connection = self.connection.lock().unwrap();
let mut stmt = connection 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(); .unwrap();
stmt.execute(( stmt.execute((
data.zone_id, data.zone_id,
@ -169,6 +187,7 @@ impl WorldDatabase {
data.position.y, data.position.y,
data.position.z, data.position.z,
data.rotation, data.rotation,
serde_json::to_string(&data.inventory).unwrap(),
data.content_id, data.content_id,
)) ))
.unwrap(); .unwrap();
@ -293,6 +312,7 @@ impl WorldDatabase {
chara_make: &str, chara_make: &str,
city_state: u8, city_state: u8,
zone_id: u16, zone_id: u16,
inventory: Inventory,
) -> (u64, u32) { ) -> (u64, u32) {
let content_id = Self::generate_content_id(); let content_id = Self::generate_content_id();
let actor_id = Self::generate_actor_id(); let actor_id = Self::generate_actor_id();
@ -310,8 +330,15 @@ impl WorldDatabase {
// insert char data // insert char data
connection connection
.execute( .execute(
"INSERT INTO character_data VALUES (?1, ?2, ?3, ?4, ?5, 0.0, 0.0, 0.0, 0.0);", "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), (
content_id,
name,
chara_make,
city_state,
zone_id,
serde_json::to_string(&inventory).unwrap(),
),
) )
.unwrap(); .unwrap();

View file

@ -2,12 +2,13 @@ use physis::{
common::{Language, Platform}, common::{Language, Platform},
gamedata::GameData, gamedata::GameData,
}; };
use serde::{Deserialize, Serialize};
use crate::config::get_config; use crate::config::get_config;
use super::ipc::{ContainerType, InventoryModify}; use super::ipc::{ContainerType, InventoryModify};
#[derive(Default, Copy, Clone)] #[derive(Default, Copy, Clone, Serialize, Deserialize, Debug)]
pub struct Item { pub struct Item {
pub quantity: u32, pub quantity: u32,
pub id: 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 struct EquippedContainer {
pub main_hand: Item, pub main_hand: Item,
pub off_hand: Item, pub off_hand: Item,
@ -73,6 +74,7 @@ impl EquippedContainer {
} }
} }
#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
pub struct Inventory { pub struct Inventory {
pub equipped: EquippedContainer, pub equipped: EquippedContainer,
pub extra_slot: Item, // WIP for inventory pages pub extra_slot: Item, // WIP for inventory pages