1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-05-12 14:47:46 +00:00

Add commands to unlock actions, and aetherytes

This doesn't mean teleporting works *yet*, as it needs to be scripted.
The unlocked action/aetheryte is also not persisted yet.
This commit is contained in:
Joshua Goins 2025-05-11 09:27:29 -04:00
parent 1605098c2e
commit 1914531d89
5 changed files with 40 additions and 3 deletions

View file

@ -87,6 +87,7 @@ These special debug commands start with `!` and are custom to Kawari.
* Territory `183`, Event `1245186` plays the Gridania opening sequence
* `!spawnclone`: Spawn a clone of yourself
* `!classjob <id>`: Changes to another class/job
* `!unlockaction <id>`: Unlock an action, for example: `1` for Return and `4` for Teleport.
### GM commands
@ -97,3 +98,4 @@ These GM commands are implemented in the FFXIV protocol, but only some of them a
* `//gm wireframe`: Toggle wireframe rendering for the environment
* `//gm item <id>`: Gives yourself an item. This can only place a single item in the first page of your inventory currently.
* `//gm lv <level>`: Sets your current level
* `//gm aetheryte <on/off> <id>`: Unlock an Aetheryte.

View file

@ -521,7 +521,7 @@ async fn client_loop(
.await;
}
}
ClientZoneIpcData::GMCommand { command, arg0, .. } => {
ClientZoneIpcData::GMCommand { command, arg0, arg1, .. } => {
tracing::info!("Got a game master command!");
match &command {
@ -555,6 +555,13 @@ async fn client_loop(
connection.player_data.inventory.add_in_next_free_slot(Item { id: *arg0, quantity: 1 });
connection.send_inventory(false).await;
}
GameMasterCommandType::Aetheryte => {
let on = *arg0 == 0;
let id = *arg1;
connection.actor_control_self(ActorControlSelf {
category: ActorControlCategory::LearnTeleport { id, unlocked: on } }).await;
}
}
}
ClientZoneIpcData::ZoneJump {

View file

@ -47,6 +47,22 @@ pub enum ActorControlCategory {
unk1: u32,
pose: u32,
},
#[brw(magic = 0x1FDu16)]
LearnTeleport {
#[brw(pad_before = 2)] //padding
id: u32,
#[br(map = read_bool_from::<u32>)]
#[bw(map = write_bool_as::<u32>)]
unlocked: bool,
},
#[brw(magic = 0x29u16)]
ToggleActionUnlock {
#[brw(pad_before = 2)] //padding
id: u32,
#[br(map = read_bool_from::<u32>)]
#[bw(map = write_bool_as::<u32>)]
unlocked: bool,
},
}
#[binrw]

View file

@ -144,6 +144,7 @@ pub enum GameMasterCommandType {
ToggleWireframe = 0x26,
ChangeTerritory = 0x58,
GiveItem = 0xC8,
Aetheryte = 0x5E,
}
#[binrw]

View file

@ -1,8 +1,9 @@
use crate::{
common::{CustomizeData, ObjectId, ObjectTypeId, timestamp_secs},
ipc::zone::{
ActorControl, ActorControlCategory, BattleNpcSubKind, ChatMessage, CommonSpawn, EventStart,
NpcSpawn, ObjectKind, OnlineStatus, ServerZoneIpcData, ServerZoneIpcSegment,
ActorControl, ActorControlCategory, ActorControlSelf, BattleNpcSubKind, ChatMessage,
CommonSpawn, EventStart, NpcSpawn, ObjectKind, OnlineStatus, ServerZoneIpcData,
ServerZoneIpcSegment,
},
opcodes::ServerZoneIpcType,
packet::{PacketSegment, SegmentData, SegmentType},
@ -203,6 +204,16 @@ impl ChatHandler {
})
.await;
}
"!unlockaction" => {
let parts: Vec<&str> = chat_message.message.split(' ').collect();
let id = parts[1].parse::<u32>().unwrap();
connection
.actor_control_self(ActorControlSelf {
category: ActorControlCategory::ToggleActionUnlock { id, unlocked: true },
})
.await;
}
_ => {}
}
}