mirror of
https://github.com/redstrate/Kawari.git
synced 2025-04-22 15:27:44 +00:00
Add !setpos debug command to forcefully move the player
This is useful in some territories where you might not spawn in the correct position. It currently locks up movement afterwards, but it's still useful.
This commit is contained in:
parent
74f7554aa8
commit
1141f6fb35
2 changed files with 64 additions and 2 deletions
|
@ -1,14 +1,14 @@
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use kawari::client_select_data::ClientCustomizeData;
|
use kawari::client_select_data::ClientCustomizeData;
|
||||||
use kawari::ipc::{GameMasterCommandType, IPCOpCode, IPCSegment, IPCStructData};
|
use kawari::ipc::{ActorSetPos, GameMasterCommandType, IPCOpCode, IPCSegment, IPCStructData};
|
||||||
use kawari::oodle::FFXIVOodle;
|
use kawari::oodle::FFXIVOodle;
|
||||||
use kawari::packet::{
|
use kawari::packet::{
|
||||||
CompressionType, PacketSegment, SegmentType, State, parse_packet, send_keep_alive, send_packet,
|
CompressionType, PacketSegment, SegmentType, State, parse_packet, send_keep_alive, send_packet,
|
||||||
};
|
};
|
||||||
use kawari::world::{
|
use kawari::world::{
|
||||||
ActorControlSelf, ActorControlType, CustomizeData, InitZone, PlayerSetup, PlayerSpawn,
|
ActorControlSelf, ActorControlType, CustomizeData, InitZone, PlayerSetup, PlayerSpawn,
|
||||||
PlayerStats, UpdateClassInfo,
|
PlayerStats, Position, UpdateClassInfo,
|
||||||
};
|
};
|
||||||
use kawari::{CONTENT_ID, WORLD_ID, ZONE_ID};
|
use kawari::{CONTENT_ID, WORLD_ID, ZONE_ID};
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
|
@ -483,6 +483,53 @@ async fn main() {
|
||||||
}
|
}
|
||||||
IPCStructData::ChatMessage { message, .. } => {
|
IPCStructData::ChatMessage { message, .. } => {
|
||||||
tracing::info!("Client sent chat message: {message}!");
|
tracing::info!("Client sent chat message: {message}!");
|
||||||
|
|
||||||
|
let parts: Vec<&str> = message.split(' ').collect();
|
||||||
|
match parts[0] {
|
||||||
|
"!setpos" => {
|
||||||
|
let pos_x = parts[1].parse::<f32>().unwrap();
|
||||||
|
let pos_y = parts[2].parse::<f32>().unwrap();
|
||||||
|
let pos_z = parts[3].parse::<f32>().unwrap();
|
||||||
|
|
||||||
|
// set pos
|
||||||
|
{
|
||||||
|
let ipc = IPCSegment {
|
||||||
|
unk1: 14,
|
||||||
|
unk2: 0,
|
||||||
|
op_code: IPCOpCode::ActorSetPos,
|
||||||
|
server_id: WORLD_ID,
|
||||||
|
timestamp: timestamp_secs(),
|
||||||
|
data: IPCStructData::ActorSetPos(
|
||||||
|
ActorSetPos {
|
||||||
|
unk: 0x020fa3b8,
|
||||||
|
position: Position {
|
||||||
|
x: pos_x,
|
||||||
|
y: pos_y,
|
||||||
|
z: pos_z,
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
let response_packet = PacketSegment {
|
||||||
|
source_actor: state.player_id.unwrap(),
|
||||||
|
target_actor: state.player_id.unwrap(),
|
||||||
|
segment_type: SegmentType::Ipc {
|
||||||
|
data: ipc,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
send_packet(
|
||||||
|
&mut write,
|
||||||
|
&[response_packet],
|
||||||
|
&mut state,
|
||||||
|
CompressionType::Oodle,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => tracing::info!("Unrecognized debug command!"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
IPCStructData::GameMasterCommand { command, arg, .. } => {
|
IPCStructData::GameMasterCommand { command, arg, .. } => {
|
||||||
tracing::info!("Got a game master command!");
|
tracing::info!("Got a game master command!");
|
||||||
|
|
15
src/ipc.rs
15
src/ipc.rs
|
@ -81,6 +81,8 @@ pub enum IPCOpCode {
|
||||||
ChatMessage = 0xCA,
|
ChatMessage = 0xCA,
|
||||||
// Sent by the client when they send a GM command. This can only be sent by the client if they are sent a GM rank.
|
// Sent by the client when they send a GM command. This can only be sent by the client if they are sent a GM rank.
|
||||||
GameMasterCommand = 0x3B3,
|
GameMasterCommand = 0x3B3,
|
||||||
|
// Sent by the server to modify the client's position
|
||||||
|
ActorSetPos = 0x223,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
|
@ -112,6 +114,15 @@ pub struct Server {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[binrw]
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct ActorSetPos {
|
||||||
|
pub unk: u32,
|
||||||
|
pub layer_id: u32,
|
||||||
|
pub position: Position,
|
||||||
|
pub unk3: u32,
|
||||||
|
}
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct CharacterDetails {
|
pub struct CharacterDetails {
|
||||||
|
@ -417,6 +428,8 @@ pub enum IPCStructData {
|
||||||
// TODO: guessed
|
// TODO: guessed
|
||||||
unk: [u8; 8],
|
unk: [u8; 8],
|
||||||
},
|
},
|
||||||
|
#[br(pre_assert(false))]
|
||||||
|
ActorSetPos(ActorSetPos),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
|
@ -474,6 +487,7 @@ impl IPCSegment {
|
||||||
IPCStructData::Disconnected { .. } => todo!(),
|
IPCStructData::Disconnected { .. } => todo!(),
|
||||||
IPCStructData::ChatMessage { .. } => 1056,
|
IPCStructData::ChatMessage { .. } => 1056,
|
||||||
IPCStructData::GameMasterCommand { .. } => todo!(),
|
IPCStructData::GameMasterCommand { .. } => todo!(),
|
||||||
|
IPCStructData::ActorSetPos { .. } => 24,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -523,6 +537,7 @@ mod tests {
|
||||||
IPCStructData::PlayerSetup(PlayerSetup::default()),
|
IPCStructData::PlayerSetup(PlayerSetup::default()),
|
||||||
IPCStructData::UpdateClassInfo(UpdateClassInfo::default()),
|
IPCStructData::UpdateClassInfo(UpdateClassInfo::default()),
|
||||||
IPCStructData::PlayerSpawn(PlayerSpawn::default()),
|
IPCStructData::PlayerSpawn(PlayerSpawn::default()),
|
||||||
|
IPCStructData::ActorSetPos(ActorSetPos::default()),
|
||||||
];
|
];
|
||||||
|
|
||||||
for ipc in &ipc_types {
|
for ipc in &ipc_types {
|
||||||
|
|
Loading…
Add table
Reference in a new issue