1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-07-17 10:47:44 +00:00

Add support for sending the title list, when requested

This doesn't allow you to set them yet, just show them in the menu.
This commit is contained in:
Joshua Goins 2025-07-13 10:15:40 -04:00
parent c339c89c41
commit 8be1fefa53
5 changed files with 49 additions and 3 deletions

View file

@ -279,6 +279,11 @@
"name": "FreeCompanyInfo", "name": "FreeCompanyInfo",
"opcode": 892, "opcode": 892,
"size": 80 "size": 80
},
{
"name": "TitleList",
"opcode": 731,
"size": 112
} }
], ],
"ClientZoneIpcType": [ "ClientZoneIpcType": [

View file

@ -2,7 +2,6 @@ use std::net::SocketAddr;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use kawari::RECEIVE_BUFFER_SIZE;
use kawari::common::Position; use kawari::common::Position;
use kawari::common::{GameData, timestamp_secs}; use kawari::common::{GameData, timestamp_secs};
use kawari::config::get_config; use kawari::config::get_config;
@ -27,6 +26,7 @@ use kawari::world::{
ClientHandle, Event, FromServer, LuaPlayer, PlayerData, ServerHandle, StatusEffects, ToServer, ClientHandle, Event, FromServer, LuaPlayer, PlayerData, ServerHandle, StatusEffects, ToServer,
WorldDatabase, handle_custom_ipc, server_main_loop, WorldDatabase, handle_custom_ipc, server_main_loop,
}; };
use kawari::{RECEIVE_BUFFER_SIZE, TITLE_UNLOCK_BITMASK_SIZE};
use mlua::{Function, Lua}; use mlua::{Function, Lua};
use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::io::{AsyncReadExt, AsyncWriteExt};
@ -415,8 +415,33 @@ async fn client_loop(
connection.player_data.teleport_query.aetheryte_id = aetheryte_id as u16; connection.player_data.teleport_query.aetheryte_id = aetheryte_id as u16;
} }
// inform the server of our trigger, it will handle sending it to other clients match trigger.trigger {
connection.handle.send(ToServer::ClientTrigger(connection.id, connection.player_data.actor_id, trigger.clone())).await; ClientTriggerCommand::RequestTitleList {} => {
// send full title list for now
let ipc = ServerZoneIpcSegment {
op_code: ServerZoneIpcType::TitleList,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::TitleList {
unlock_bitmask: [0xFF; TITLE_UNLOCK_BITMASK_SIZE]
},
..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;
},
_ => {
// inform the server of our trigger, it will handle sending it to other clients
connection.handle.send(ToServer::ClientTrigger(connection.id, connection.player_data.actor_id, trigger.clone())).await;
}
}
} }
ClientZoneIpcData::Unk2 { .. } => { ClientZoneIpcData::Unk2 { .. } => {
// no-op // no-op

View file

@ -59,6 +59,8 @@ pub enum ClientTriggerCommand {
unk3: u32, unk3: u32,
unk4: u32, unk4: u32,
}, },
#[brw(magic = 0x12Fu16)]
RequestTitleList {},
Unknown { Unknown {
category: u16, category: u16,
// seen in haircut event // seen in haircut event

View file

@ -92,6 +92,7 @@ mod object_spawn;
pub use object_spawn::ObjectSpawn; pub use object_spawn::ObjectSpawn;
use crate::COMPLETED_QUEST_BITMASK_SIZE; use crate::COMPLETED_QUEST_BITMASK_SIZE;
use crate::TITLE_UNLOCK_BITMASK_SIZE;
use crate::common::ObjectTypeId; use crate::common::ObjectTypeId;
use crate::common::Position; use crate::common::Position;
use crate::common::read_string; use crate::common::read_string;
@ -462,6 +463,10 @@ pub enum ServerZoneIpcData {
}, },
#[br(pre_assert(*magic == ServerZoneIpcType::FreeCompanyInfo))] #[br(pre_assert(*magic == ServerZoneIpcType::FreeCompanyInfo))]
FreeCompanyInfo { unk: [u8; 80] }, FreeCompanyInfo { unk: [u8; 80] },
#[br(pre_assert(*magic == ServerZoneIpcType::TitleList))]
TitleList {
unlock_bitmask: [u8; TITLE_UNLOCK_BITMASK_SIZE],
},
Unknown { Unknown {
#[br(count = size - 32)] #[br(count = size - 32)]
unk: Vec<u8>, unk: Vec<u8>,
@ -928,6 +933,12 @@ mod tests {
message: String::default(), message: String::default(),
}, },
), ),
(
ServerZoneIpcType::TitleList,
ServerZoneIpcData::TitleList {
unlock_bitmask: [0; TITLE_UNLOCK_BITMASK_SIZE],
},
),
( (
ServerZoneIpcType::FreeCompanyInfo, ServerZoneIpcType::FreeCompanyInfo,
ServerZoneIpcData::FreeCompanyInfo { unk: [0; 80] }, ServerZoneIpcData::FreeCompanyInfo { unk: [0; 80] },

View file

@ -76,6 +76,9 @@ pub const AETHERYTE_UNLOCK_BITMASK_SIZE: usize = 30;
/// The size of the completed quest bitmask. /// The size of the completed quest bitmask.
pub const COMPLETED_QUEST_BITMASK_SIZE: usize = 691; pub const COMPLETED_QUEST_BITMASK_SIZE: usize = 691;
/// The size of the unlocked title bitmask.
pub const TITLE_UNLOCK_BITMASK_SIZE: usize = 112;
/// The size of various classjob arrays. /// The size of various classjob arrays.
pub const CLASSJOB_ARRAY_SIZE: usize = 32; pub const CLASSJOB_ARRAY_SIZE: usize = 32;