1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-05-03 11:37:45 +00:00

Create Inventory struct, move inventory filling logic to ZoneConnection

This still uses hardcoded item ids, but this should much more extensible.
This commit is contained in:
Joshua Goins 2025-03-23 17:43:06 -04:00
parent a36c6dff90
commit 8a03c82480
4 changed files with 155 additions and 77 deletions

View file

@ -17,7 +17,7 @@ use kawari::world::ipc::{
StatusEffect,
};
use kawari::world::{
ChatHandler, Zone, ZoneConnection,
ChatHandler, Inventory, Zone, ZoneConnection,
ipc::{
ActorControl, ActorControlCategory, ActorControlSelf, PlayerEntry, PlayerSetup,
PlayerSpawn, PlayerStats, SocialList,
@ -63,6 +63,7 @@ async fn main() {
spawn_index: 0,
zone: None,
position: Position::default(),
inventory: Inventory::new(),
};
tokio::spawn(async move {
@ -85,8 +86,6 @@ async fn main() {
connection.player_data =
database.find_player_data(actor_id.parse::<u32>().unwrap());
println!("player data: {:#?}", connection.player_data);
// We have send THEM a keep alive
{
connection
@ -189,75 +188,16 @@ async fn main() {
.await;
}
let item_ids = [
(12, 0x00003b1d),
(11, 0x0000114a),
(10, 0x00003b1c),
(9, 0x00003b1a),
(8, 0x00003b1b),
(7, 0x00000ea7),
(6, 0x00000ce1),
(4, 0x00000dc1),
(3, 0x00000ba8),
(0, 0x00000641),
];
let chara_details = database
.find_chara_make(connection.player_data.content_id);
// send inventory
{
for (slot, id) in &item_ids {
let ipc = ServerZoneIpcSegment {
op_code: ServerZoneIpcType::ItemInfo,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::ItemInfo(ItemInfo {
container: ContainerType::Equipped,
slot: *slot,
quantity: 1,
catalog_id: *id,
condition: 30000,
..Default::default()
}),
..Default::default()
};
// fill inventory
connection.inventory.equip_racial_items(
chara_details.chara_make.customize.race,
);
connection
.send_segment(PacketSegment {
source_actor: connection
.player_data
.actor_id,
target_actor: connection
.player_data
.actor_id,
segment_type: SegmentType::Ipc {
data: ipc,
},
})
.await;
}
}
// inform the client they have 10 items equipped
{
let ipc = ServerZoneIpcSegment {
op_code: ServerZoneIpcType::ContainerInfo,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::ContainerInfo(
ContainerInfo {
container: ContainerType::Equipped,
num_items: item_ids.len() as u32,
..Default::default()
},
),
..Default::default()
};
connection
.send_segment(PacketSegment {
source_actor: connection.player_data.actor_id,
target_actor: connection.player_data.actor_id,
segment_type: SegmentType::Ipc { data: ipc },
})
.await;
}
// Send inventory
connection.send_inventory().await;
// Control Data
{
@ -308,11 +248,7 @@ async fn main() {
.await;
}
let chara_details = database
.find_chara_make(connection.player_data.content_id);
let zone_id = chara_details.zone_id;
connection.zone = Some(Zone::load(zone_id));
// Player Setup

View file

@ -9,10 +9,10 @@ use crate::{
};
use super::{
Zone,
Inventory, Item, Zone,
ipc::{
ActorSetPos, ClientZoneIpcSegment, InitZone, ServerZoneIpcData, ServerZoneIpcSegment,
ServerZoneIpcType, UpdateClassInfo, WeatherChange,
ActorSetPos, ClientZoneIpcSegment, ContainerInfo, ContainerType, InitZone, ItemInfo,
ServerZoneIpcData, ServerZoneIpcSegment, ServerZoneIpcType, UpdateClassInfo, WeatherChange,
},
};
@ -34,6 +34,7 @@ pub struct ZoneConnection {
pub spawn_index: u8,
pub position: Position,
pub inventory: Inventory,
}
impl ZoneConnection {
@ -169,4 +170,69 @@ impl ZoneConnection {
self.spawn_index += 1;
self.spawn_index
}
pub async fn send_inventory(&mut self) {
// item list
{
let equipped = self.inventory.equipped.clone();
let mut send_slot = async |slot_index: u16, item: &Item| {
let ipc = ServerZoneIpcSegment {
op_code: ServerZoneIpcType::ItemInfo,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::ItemInfo(ItemInfo {
container: ContainerType::Equipped,
slot: slot_index,
quantity: item.quantity,
catalog_id: item.id,
condition: 30000,
..Default::default()
}),
..Default::default()
};
self.send_segment(PacketSegment {
source_actor: self.player_data.actor_id,
target_actor: self.player_data.actor_id,
segment_type: SegmentType::Ipc { data: ipc },
})
.await;
};
send_slot(0, &equipped.main_hand).await;
send_slot(1, &equipped.off_hand).await;
send_slot(2, &equipped.head).await;
send_slot(3, &equipped.body).await;
send_slot(4, &equipped.hands).await;
send_slot(6, &equipped.legs).await;
send_slot(7, &equipped.feet).await;
send_slot(8, &equipped.ears).await;
send_slot(9, &equipped.neck).await;
send_slot(10, &equipped.wrists).await;
send_slot(11, &equipped.right_ring).await;
send_slot(12, &equipped.left_ring).await;
send_slot(13, &equipped.soul_crystal).await;
}
// inform the client they have items equipped
{
let ipc = ServerZoneIpcSegment {
op_code: ServerZoneIpcType::ContainerInfo,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::ContainerInfo(ContainerInfo {
container: ContainerType::Equipped,
num_items: self.inventory.equipped.num_items(),
..Default::default()
}),
..Default::default()
};
self.send_segment(PacketSegment {
source_actor: self.player_data.actor_id,
target_actor: self.player_data.actor_id,
segment_type: SegmentType::Ipc { data: ipc },
})
.await;
}
}
}

73
src/world/inventory.rs Normal file
View file

@ -0,0 +1,73 @@
#[derive(Default, Copy, Clone)]
pub struct Item {
pub quantity: u32,
pub id: u32,
}
impl Item {
pub fn new(quantity: u32, id: u32) -> Self {
Self { quantity, id }
}
}
#[derive(Default, Clone, Copy)]
pub struct EquippedContainer {
pub main_hand: Item,
pub off_hand: Item,
pub head: Item,
pub body: Item,
pub hands: Item,
pub legs: Item,
pub feet: Item,
pub ears: Item,
pub neck: Item,
pub wrists: Item,
pub right_ring: Item,
pub left_ring: Item,
pub soul_crystal: Item,
}
impl EquippedContainer {
pub fn num_items(&self) -> u32 {
self.main_hand.quantity
+ self.off_hand.quantity
+ self.head.quantity
+ self.body.quantity
+ self.hands.quantity
+ self.legs.quantity
+ self.feet.quantity
+ self.ears.quantity
+ self.neck.quantity
+ self.wrists.quantity
+ self.right_ring.quantity
+ self.left_ring.quantity
+ self.soul_crystal.quantity
}
}
pub struct Inventory {
pub equipped: EquippedContainer,
}
impl Inventory {
pub fn new() -> Self {
Self {
equipped: EquippedContainer::default(),
}
}
/// Equip the starting items for a given race
pub fn equip_racial_items(&mut self, race_id: u8) {
// TODO: don't hardcode
self.equipped.main_hand = Item::new(1, 0x00000641);
self.equipped.body = Item::new(1, 0x00000ba8);
self.equipped.hands = Item::new(1, 0x00000dc1);
self.equipped.legs = Item::new(1, 0x00000ce1);
self.equipped.feet = Item::new(1, 0x00000ea7);
self.equipped.ears = Item::new(1, 0x00003b1b);
self.equipped.neck = Item::new(1, 0x00003b1a);
self.equipped.wrists = Item::new(1, 0x00003b1c);
self.equipped.right_ring = Item::new(1, 0x0000114a);
self.equipped.left_ring = Item::new(1, 0x00003b1d);
}
}

View file

@ -11,3 +11,6 @@ pub use connection::{PlayerData, ZoneConnection};
mod database;
pub use database::{CharacterData, WorldDatabase};
mod inventory;
pub use inventory::{EquippedContainer, Inventory, Item};