mirror of
https://github.com/redstrate/Kawari.git
synced 2025-04-19 22:36:49 +00:00
Allow unequipping items, add packet for updating equipped model ids
The unequipped item currently disappears into the aether, but this works now!
This commit is contained in:
parent
bc8535cce2
commit
0c76d847d5
8 changed files with 150 additions and 19 deletions
|
@ -149,6 +149,11 @@
|
|||
"name": "ActionResult",
|
||||
"opcode": 508,
|
||||
"size": 124
|
||||
},
|
||||
{
|
||||
"name": "Equip",
|
||||
"opcode": 468,
|
||||
"size": 72
|
||||
}
|
||||
],
|
||||
"ClientZoneIpcType": [
|
||||
|
@ -260,7 +265,7 @@
|
|||
{
|
||||
"name": "InventoryModify",
|
||||
"opcode": 564,
|
||||
"size": 112
|
||||
"size": 48
|
||||
}
|
||||
],
|
||||
"ServerLobbyIpcType": [
|
||||
|
|
BIN
resources/tests/equip.bin
Normal file
BIN
resources/tests/equip.bin
Normal file
Binary file not shown.
|
@ -19,8 +19,8 @@ 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, Item, LuaPlayer, PlayerData,
|
||||
ServerHandle, StatusEffects, ToServer, WorldDatabase,
|
||||
};
|
||||
use kawari::world::{
|
||||
ChatHandler, Inventory, Zone, ZoneConnection,
|
||||
|
@ -283,7 +283,7 @@ async fn client_loop(
|
|||
);
|
||||
|
||||
// Send inventory
|
||||
connection.send_inventory().await;
|
||||
connection.send_inventory(false).await;
|
||||
|
||||
// set chara gear param
|
||||
connection
|
||||
|
@ -815,6 +815,9 @@ async fn client_loop(
|
|||
}
|
||||
ClientZoneIpcData::InventoryModify(action) => {
|
||||
tracing::info!("Client is modifying inventory! {action:#?}");
|
||||
|
||||
connection.inventory.process_action(&action);
|
||||
connection.send_inventory(true).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ use super::{
|
|||
chat_handler::CUSTOMIZE_DATA,
|
||||
ipc::{
|
||||
ActorControlSelf, ActorMove, ActorSetPos, BattleNpcSubKind, ClientZoneIpcSegment,
|
||||
CommonSpawn, ContainerInfo, ContainerType, InitZone, ItemInfo, NpcSpawn, ObjectKind,
|
||||
CommonSpawn, ContainerInfo, ContainerType, Equip, InitZone, ItemInfo, NpcSpawn, ObjectKind,
|
||||
ServerZoneIpcData, ServerZoneIpcSegment, StatusEffect, StatusEffectList, UpdateClassInfo,
|
||||
WeatherChange,
|
||||
},
|
||||
|
@ -447,7 +447,7 @@ impl ZoneConnection {
|
|||
self.spawn_index
|
||||
}
|
||||
|
||||
pub async fn send_inventory(&mut self) {
|
||||
pub async fn send_inventory(&mut self, send_appearance_update: bool) {
|
||||
// item list
|
||||
{
|
||||
let equipped = self.inventory.equipped;
|
||||
|
@ -510,6 +510,46 @@ impl ZoneConnection {
|
|||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
// send them an appearance update
|
||||
if send_appearance_update {
|
||||
let ipc;
|
||||
{
|
||||
let mut game_data = self.gamedata.lock().unwrap();
|
||||
let equipped = &self.inventory.equipped;
|
||||
|
||||
ipc = ServerZoneIpcSegment {
|
||||
op_code: ServerZoneIpcType::Equip,
|
||||
timestamp: timestamp_secs(),
|
||||
data: ServerZoneIpcData::Equip(Equip {
|
||||
main_weapon_id: 0,
|
||||
sub_weapon_id: 0,
|
||||
crest_enable: 0,
|
||||
pattern_invalid: 0,
|
||||
model_ids: [
|
||||
game_data.get_primary_model_id(equipped.head.id) as u32,
|
||||
game_data.get_primary_model_id(equipped.body.id) as u32,
|
||||
game_data.get_primary_model_id(equipped.hands.id) as u32,
|
||||
game_data.get_primary_model_id(equipped.legs.id) as u32,
|
||||
game_data.get_primary_model_id(equipped.feet.id) as u32,
|
||||
game_data.get_primary_model_id(equipped.ears.id) as u32,
|
||||
game_data.get_primary_model_id(equipped.neck.id) as u32,
|
||||
game_data.get_primary_model_id(equipped.wrists.id) as u32,
|
||||
game_data.get_primary_model_id(equipped.left_ring.id) as u32,
|
||||
game_data.get_primary_model_id(equipped.right_ring.id) as u32,
|
||||
],
|
||||
}),
|
||||
..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;
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn send_message(&mut self, message: &str) {
|
||||
|
|
|
@ -5,6 +5,8 @@ use physis::{
|
|||
|
||||
use crate::config::get_config;
|
||||
|
||||
use super::ipc::InventoryModify;
|
||||
|
||||
#[derive(Default, Copy, Clone)]
|
||||
pub struct Item {
|
||||
pub quantity: u32,
|
||||
|
@ -111,4 +113,29 @@ impl Inventory {
|
|||
self.equipped.right_ring = Item::new(1, 0x0000114a);
|
||||
self.equipped.left_ring = Item::new(1, 0x00003b1d);
|
||||
}
|
||||
|
||||
pub fn process_action(&mut self, action: &InventoryModify) {
|
||||
// equipped
|
||||
if action.src_storage_id == 1000 {
|
||||
let slot = match action.src_container_index {
|
||||
0 => &mut self.equipped.main_hand,
|
||||
1 => &mut self.equipped.off_hand,
|
||||
2 => &mut self.equipped.head,
|
||||
3 => &mut self.equipped.body,
|
||||
4 => &mut self.equipped.hands,
|
||||
6 => &mut self.equipped.legs,
|
||||
7 => &mut self.equipped.feet,
|
||||
8 => &mut self.equipped.ears,
|
||||
9 => &mut self.equipped.neck,
|
||||
10 => &mut self.equipped.wrists,
|
||||
11 => &mut self.equipped.right_ring,
|
||||
12 => &mut self.equipped.left_ring,
|
||||
13 => &mut self.equipped.soul_crystal,
|
||||
_ => panic!("Not a valid src_container_index?!?"),
|
||||
};
|
||||
|
||||
// it only unequips for now, doesn't move the item
|
||||
*slot = Item::default();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
48
src/world/ipc/equip.rs
Normal file
48
src/world/ipc/equip.rs
Normal file
|
@ -0,0 +1,48 @@
|
|||
use binrw::binrw;
|
||||
|
||||
#[binrw]
|
||||
#[brw(little)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Equip {
|
||||
pub main_weapon_id: u64,
|
||||
pub sub_weapon_id: u64,
|
||||
pub crest_enable: u8,
|
||||
#[brw(pad_before = 1)]
|
||||
pub pattern_invalid: u16,
|
||||
#[brw(pad_after = 12)]
|
||||
pub model_ids: [u32; 10],
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{fs::read, io::Cursor, path::PathBuf};
|
||||
|
||||
use binrw::BinRead;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn read_containerinfo() {
|
||||
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
d.push("resources/tests/equip.bin");
|
||||
|
||||
let buffer = read(d).unwrap();
|
||||
let mut buffer = Cursor::new(&buffer);
|
||||
|
||||
let equip = Equip::read_le(&mut buffer).unwrap();
|
||||
assert_eq!(equip.main_weapon_id, 4297785545);
|
||||
assert_eq!(equip.sub_weapon_id, 0);
|
||||
assert_eq!(equip.crest_enable, 0);
|
||||
assert_eq!(equip.pattern_invalid, 1);
|
||||
assert_eq!(equip.model_ids[0], 0);
|
||||
assert_eq!(equip.model_ids[1], 0);
|
||||
assert_eq!(equip.model_ids[2], 131156);
|
||||
assert_eq!(equip.model_ids[3], 131156);
|
||||
assert_eq!(equip.model_ids[4], 131156);
|
||||
assert_eq!(equip.model_ids[5], 131073);
|
||||
assert_eq!(equip.model_ids[6], 131073);
|
||||
assert_eq!(equip.model_ids[7], 131073);
|
||||
assert_eq!(equip.model_ids[8], 0);
|
||||
assert_eq!(equip.model_ids[9], 131073);
|
||||
}
|
||||
}
|
|
@ -3,21 +3,20 @@ use binrw::binrw;
|
|||
#[binrw]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct InventoryModify {
|
||||
context_id: u32,
|
||||
operation_type: u8,
|
||||
pub context_id: u32,
|
||||
pub operation_type: u8,
|
||||
#[brw(pad_before = 3)]
|
||||
src_actor_id: u32,
|
||||
src_storage_id: u32,
|
||||
src_container_index: i16,
|
||||
pub src_actor_id: u32,
|
||||
pub src_storage_id: u32,
|
||||
pub src_container_index: i16,
|
||||
#[brw(pad_before = 4)]
|
||||
src_stack: u32,
|
||||
src_catalog_id: u32,
|
||||
dst_actor_id: u32,
|
||||
dst_storage_id: u32,
|
||||
dst_container_index: i16,
|
||||
#[brw(pad_before = 2)]
|
||||
dst_stack: u32,
|
||||
dst_catalog_id: u32,
|
||||
pub src_stack: u32,
|
||||
pub src_catalog_id: u32,
|
||||
pub dst_actor_id: u32,
|
||||
pub dst_storage_id: u32,
|
||||
pub dst_container_index: i16,
|
||||
pub dst_stack: u32,
|
||||
pub dst_catalog_id: u32,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -71,6 +71,9 @@ pub use actor_set_pos::ActorSetPos;
|
|||
mod inventory_modify;
|
||||
pub use inventory_modify::InventoryModify;
|
||||
|
||||
mod equip;
|
||||
pub use equip::Equip;
|
||||
|
||||
use crate::common::Position;
|
||||
use crate::common::read_string;
|
||||
use crate::common::write_string;
|
||||
|
@ -207,6 +210,8 @@ pub enum ServerZoneIpcData {
|
|||
},
|
||||
/// Sent to inform the client the consequences of their actions
|
||||
ActionResult(ActionResult),
|
||||
/// Sent to to the client to update their appearance
|
||||
Equip(Equip),
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
|
@ -458,6 +463,10 @@ mod tests {
|
|||
ServerZoneIpcType::ActionResult,
|
||||
ServerZoneIpcData::ActionResult(ActionResult::default()),
|
||||
),
|
||||
(
|
||||
ServerZoneIpcType::Equip,
|
||||
ServerZoneIpcData::Equip(Equip::default()),
|
||||
),
|
||||
];
|
||||
|
||||
for (opcode, data) in &ipc_types {
|
||||
|
|
Loading…
Add table
Reference in a new issue