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:
parent
fed21b3617
commit
b1653f0808
4 changed files with 60 additions and 29 deletions
|
@ -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(),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue