mirror of
https://github.com/redstrate/Kawari.git
synced 2025-07-09 15:37:45 +00:00
Attempt to improve the accuracy of a couple things (#105)
Attempt to improve the accuracy of: -ItemOperation: Now sends back ItemAcknowledgeAck as well as InventorySlotDiscard and *Fin when discarding items -ClientTrigger::EventRelatedUnk -> send back commonly observed ActorControlSelf responses
This commit is contained in:
parent
c292033960
commit
17967c9d6a
6 changed files with 160 additions and 0 deletions
|
@ -239,6 +239,16 @@
|
|||
"name": "UnkResponse2",
|
||||
"opcode": 772,
|
||||
"size": 8
|
||||
},
|
||||
{
|
||||
"name": "InventorySlotDiscard",
|
||||
"opcode": 851,
|
||||
"size": 48
|
||||
},
|
||||
{
|
||||
"name": "InventorySlotDiscardFin",
|
||||
"opcode": 854,
|
||||
"size": 16
|
||||
}
|
||||
],
|
||||
"ClientZoneIpcType": [
|
||||
|
|
|
@ -36,6 +36,10 @@ use tokio::sync::mpsc::{Receiver, UnboundedReceiver, UnboundedSender, channel, u
|
|||
use tokio::sync::oneshot;
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
use kawari::{
|
||||
INVENTORY_ACTION_ACK_GENERAL, /*INVENTORY_ACTION_ACK_SHOP,*/ INVENTORY_ACTION_DISCARD,
|
||||
};
|
||||
|
||||
fn spawn_main_loop() -> (ServerHandle, JoinHandle<()>) {
|
||||
let (send, recv) = channel(64);
|
||||
|
||||
|
@ -789,7 +793,80 @@ async fn client_loop(
|
|||
ClientZoneIpcData::ItemOperation(action) => {
|
||||
tracing::info!("Client is modifying inventory! {action:#?}");
|
||||
|
||||
let ipc = ServerZoneIpcSegment {
|
||||
op_code: ServerZoneIpcType::InventoryActionAck,
|
||||
timestamp: timestamp_secs(),
|
||||
data: ServerZoneIpcData::InventoryActionAck {
|
||||
sequence: action.context_id,
|
||||
action_type: INVENTORY_ACTION_ACK_GENERAL as u16,
|
||||
},
|
||||
..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: SegmentData::Ipc { data: ipc },
|
||||
})
|
||||
.await;
|
||||
if action.operation_type == INVENTORY_ACTION_DISCARD {
|
||||
tracing::info!("Player is discarding from their inventory!");
|
||||
let sequence = 0; // TODO: How is this decided? It seems to be a sequence value but it's not sent by the client! Perhaps it's a 'lifetime-of-the-character' value that simply gets increased for every inventory action ever taken?
|
||||
let ipc = ServerZoneIpcSegment {
|
||||
op_code: ServerZoneIpcType::InventorySlotDiscard,
|
||||
timestamp: timestamp_secs(),
|
||||
data: ServerZoneIpcData::InventorySlotDiscard {
|
||||
unk1: sequence,
|
||||
operation_type: action.operation_type,
|
||||
src_actor_id: action.src_actor_id,
|
||||
src_storage_id: action.src_storage_id,
|
||||
src_container_index: action.src_container_index,
|
||||
src_stack: action.src_stack,
|
||||
src_catalog_id: action.src_catalog_id,
|
||||
dst_actor_id: 0xE0000000,
|
||||
dst_storage_id: 0xFFFF,
|
||||
dst_container_index: 0xFFFF,
|
||||
dst_catalog_id: 0x0000FFFF,
|
||||
},
|
||||
..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: SegmentData::Ipc { data: ipc },
|
||||
})
|
||||
.await;
|
||||
|
||||
let ipc = ServerZoneIpcSegment {
|
||||
op_code: ServerZoneIpcType::InventorySlotDiscard,
|
||||
timestamp: timestamp_secs(),
|
||||
data: ServerZoneIpcData::InventorySlotDiscardFin {
|
||||
unk1: sequence,
|
||||
unk2: sequence, // yes, this repeats, it's not a copy paste error
|
||||
unk3: 0x90,
|
||||
unk4: 0x200,
|
||||
},
|
||||
..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: SegmentData::Ipc { data: ipc },
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
connection.player_data.inventory.process_action(action);
|
||||
|
||||
// TODO: This seems incorrect, the server wasn't observed to send updates here, but if we don't then the client doesn't realize the items have been modified
|
||||
connection.send_inventory(true).await;
|
||||
}
|
||||
// TODO: Likely rename this opcode if non-gil shops also use this same opcode
|
||||
|
|
|
@ -109,6 +109,16 @@ pub enum ActorControlCategory {
|
|||
#[brw(pad_before = 2)] // padding
|
||||
emote: u32,
|
||||
},
|
||||
#[brw(magic = 0x1ffu16)]
|
||||
EventRelatedUnk1 {
|
||||
#[brw(pad_before = 2)] // padding
|
||||
unk1: u32,
|
||||
},
|
||||
#[brw(magic = 0x200u16)]
|
||||
EventRelatedUnk2 {
|
||||
#[brw(pad_before = 2)] // padding
|
||||
unk1: u32,
|
||||
},
|
||||
Unknown {
|
||||
category: u16,
|
||||
#[brw(pad_before = 2)] // padding
|
||||
|
|
|
@ -92,6 +92,7 @@ use crate::common::ObjectTypeId;
|
|||
use crate::common::Position;
|
||||
use crate::common::read_string;
|
||||
use crate::common::write_string;
|
||||
use crate::inventory::ContainerType;
|
||||
use crate::opcodes::ClientZoneIpcType;
|
||||
use crate::opcodes::ServerZoneIpcType;
|
||||
use crate::packet::IPC_HEADER_SIZE;
|
||||
|
@ -347,6 +348,42 @@ pub enum ServerZoneIpcData {
|
|||
#[brw(pad_after = 7)]
|
||||
unk1: u8,
|
||||
},
|
||||
#[br(pre_assert(*magic == ServerZoneIpcType::InventorySlotDiscard))]
|
||||
InventorySlotDiscard {
|
||||
/// This is later reused in InventorySlotDiscardFin, so it might be some sort of sequence or context id, but it's not the one sent by the client
|
||||
unk1: u32,
|
||||
/// Same as the one sent by the client, not the one that the server responds with in inventoryactionack!
|
||||
operation_type: u8,
|
||||
#[br(pad_before = 3)]
|
||||
src_actor_id: u32,
|
||||
src_storage_id: ContainerType,
|
||||
src_container_index: u16,
|
||||
#[br(pad_before = 2)]
|
||||
src_stack: u32,
|
||||
src_catalog_id: u32,
|
||||
|
||||
/// This is all static as far as I can tell, across two captures and a bunch of discards these never changed
|
||||
/// seems to always be 3758096384 / E0 00 00 00
|
||||
dst_actor_id: u32,
|
||||
/// seems to always be 65535/0xFFFF
|
||||
dst_storage_id: u16,
|
||||
/// seems to always be 65535/0xFFFF
|
||||
dst_container_index: u16,
|
||||
/// seems to always be 0x0000FFFF
|
||||
#[br(pad_after = 8)]
|
||||
dst_catalog_id: u32,
|
||||
},
|
||||
#[br(pre_assert(*magic == ServerZoneIpcType::InventorySlotDiscardFin))]
|
||||
InventorySlotDiscardFin {
|
||||
/// Same value as unk1 in InventorySlotDiscard
|
||||
unk1: u32,
|
||||
/// Repeated unk1 value?
|
||||
unk2: u32,
|
||||
/// Unknown, seems to always be 0x00000090
|
||||
unk3: u32,
|
||||
/// Unknown, seems to always be 0x00000200
|
||||
unk4: u32,
|
||||
},
|
||||
Unknown {
|
||||
#[br(count = size - 32)]
|
||||
unk: Vec<u8>,
|
||||
|
|
|
@ -87,3 +87,11 @@ pub const INVENTORY_ACTION_MOVE: u8 = 146;
|
|||
|
||||
/// The operation opcode/type when moving an item to a slot occupied by another in the inventory.
|
||||
pub const INVENTORY_ACTION_EXCHANGE: u8 = 147;
|
||||
|
||||
/// The server's acknowledgement of a shop item being purchased.
|
||||
pub const INVENTORY_ACTION_ACK_SHOP: u8 = 6;
|
||||
|
||||
/// The server's acknowledgement of the client modifying their inventory.
|
||||
/// In the past, many more values were used according to Sapphire:
|
||||
/// https://github.com/SapphireServer/Sapphire/blob/044bff026c01b4cc3a37cbc9b0881fadca3fc477/src/common/Common.h#L83
|
||||
pub const INVENTORY_ACTION_ACK_GENERAL: u8 = 7;
|
||||
|
|
|
@ -323,6 +323,24 @@ pub async fn server_main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::i
|
|||
to_remove.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
if let ClientTriggerCommand::EventRelatedUnk { .. } = &trigger.trigger
|
||||
{
|
||||
let msg = FromServer::ActorControlSelf(ActorControlSelf {
|
||||
category: ActorControlCategory::EventRelatedUnk1 { unk1: 1 },
|
||||
});
|
||||
|
||||
if handle.send(msg).is_err() {
|
||||
to_remove.push(id);
|
||||
}
|
||||
let msg = FromServer::ActorControlSelf(ActorControlSelf {
|
||||
category: ActorControlCategory::EventRelatedUnk2 { unk1: 0 },
|
||||
});
|
||||
|
||||
if handle.send(msg).is_err() {
|
||||
to_remove.push(id);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue