1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-05-04 03:57:45 +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,
};
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(),

View file

@ -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<Zone>,
pub spawn_index: u8,
pub inventory: Inventory,
pub status_effects: StatusEffects,
pub event: Option<Event>,
@ -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,

View file

@ -11,7 +11,7 @@ use crate::{
},
};
use super::PlayerData;
use super::{Inventory, PlayerData};
pub struct WorldDatabase {
connection: Mutex<Connection>,
@ -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();

View file

@ -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