2025-03-22 16:15:29 -04:00
|
|
|
use std::sync::Arc;
|
2025-03-21 19:56:16 -04:00
|
|
|
|
|
|
|
use kawari::common::custom_ipc::{CustomIpcData, CustomIpcSegment, CustomIpcType};
|
2025-03-22 18:53:53 -04:00
|
|
|
use kawari::common::timestamp_secs;
|
2025-03-23 07:25:23 -04:00
|
|
|
use kawari::common::{Position, determine_initial_starting_zone, get_citystate, get_world_name};
|
2025-03-19 00:28:47 -04:00
|
|
|
use kawari::config::get_config;
|
2025-03-22 18:34:27 -04:00
|
|
|
use kawari::lobby::CharaMake;
|
2025-03-17 17:22:09 -04:00
|
|
|
use kawari::oodle::OodleNetwork;
|
2025-03-21 21:26:32 -04:00
|
|
|
use kawari::packet::{
|
|
|
|
CompressionType, ConnectionType, PacketSegment, PacketState, SegmentType, send_keep_alive,
|
|
|
|
send_packet,
|
|
|
|
};
|
2025-03-16 17:43:29 -04:00
|
|
|
use kawari::world::ipc::{
|
2025-03-23 18:14:14 -04:00
|
|
|
ClientZoneIpcData, CommonSpawn, DisplayFlag, GameMasterCommandType, GameMasterRank, ObjectKind,
|
|
|
|
OnlineStatus, PlayerSubKind, ServerZoneIpcData, ServerZoneIpcSegment, ServerZoneIpcType,
|
|
|
|
SocialListRequestType, StatusEffect,
|
2025-03-16 17:43:29 -04:00
|
|
|
};
|
2025-03-12 18:05:41 -04:00
|
|
|
use kawari::world::{
|
2025-03-23 17:43:06 -04:00
|
|
|
ChatHandler, Inventory, Zone, ZoneConnection,
|
2025-03-16 17:43:29 -04:00
|
|
|
ipc::{
|
2025-03-23 18:14:14 -04:00
|
|
|
ActorControlCategory, ActorControlSelf, PlayerEntry, PlayerSetup, PlayerSpawn, PlayerStats,
|
|
|
|
SocialList,
|
2025-03-16 17:43:29 -04:00
|
|
|
},
|
2025-03-12 18:05:41 -04:00
|
|
|
};
|
2025-03-22 16:15:29 -04:00
|
|
|
use kawari::world::{PlayerData, WorldDatabase};
|
2025-03-19 00:28:47 -04:00
|
|
|
use physis::common::{Language, Platform};
|
|
|
|
use physis::gamedata::GameData;
|
2025-03-09 11:07:01 -04:00
|
|
|
use tokio::io::AsyncReadExt;
|
|
|
|
use tokio::net::TcpListener;
|
|
|
|
|
|
|
|
#[tokio::main]
|
|
|
|
async fn main() {
|
|
|
|
tracing_subscriber::fmt::init();
|
|
|
|
|
2025-03-22 16:47:21 -04:00
|
|
|
let config = get_config();
|
2025-03-09 11:07:01 -04:00
|
|
|
|
2025-03-22 16:47:21 -04:00
|
|
|
let addr = config.world.get_socketaddr();
|
|
|
|
|
|
|
|
let listener = TcpListener::bind(addr).await.unwrap();
|
|
|
|
|
|
|
|
tracing::info!("World server started on {addr}");
|
2025-03-09 11:07:01 -04:00
|
|
|
|
2025-03-22 16:15:29 -04:00
|
|
|
let database = Arc::new(WorldDatabase::new());
|
2025-03-21 19:56:16 -04:00
|
|
|
|
2025-03-09 11:07:01 -04:00
|
|
|
loop {
|
|
|
|
let (socket, _) = listener.accept().await.unwrap();
|
|
|
|
|
2025-03-22 16:15:29 -04:00
|
|
|
let database = database.clone();
|
2025-03-21 19:56:16 -04:00
|
|
|
|
2025-03-16 17:43:29 -04:00
|
|
|
let state = PacketState {
|
2025-03-09 11:07:01 -04:00
|
|
|
client_key: None,
|
2025-03-17 17:22:09 -04:00
|
|
|
clientbound_oodle: OodleNetwork::new(),
|
|
|
|
serverbound_oodle: OodleNetwork::new(),
|
2025-03-09 11:07:01 -04:00
|
|
|
};
|
|
|
|
|
2025-03-15 19:34:29 -04:00
|
|
|
let mut exit_position = None;
|
|
|
|
|
2025-03-15 20:36:39 -04:00
|
|
|
let mut connection = ZoneConnection {
|
|
|
|
socket,
|
|
|
|
state,
|
2025-03-21 19:56:16 -04:00
|
|
|
player_data: PlayerData::default(),
|
2025-03-16 14:07:56 -04:00
|
|
|
spawn_index: 0,
|
2025-03-22 18:53:53 -04:00
|
|
|
zone: None,
|
2025-03-23 10:33:49 -04:00
|
|
|
position: Position::default(),
|
2025-03-23 17:43:06 -04:00
|
|
|
inventory: Inventory::new(),
|
2025-03-15 20:36:39 -04:00
|
|
|
};
|
|
|
|
|
2025-03-09 11:07:01 -04:00
|
|
|
tokio::spawn(async move {
|
|
|
|
let mut buf = [0; 2056];
|
|
|
|
loop {
|
2025-03-15 20:36:39 -04:00
|
|
|
let n = connection
|
|
|
|
.socket
|
|
|
|
.read(&mut buf)
|
|
|
|
.await
|
|
|
|
.expect("Failed to read data!");
|
2025-03-09 11:07:01 -04:00
|
|
|
|
|
|
|
if n != 0 {
|
2025-03-15 20:36:39 -04:00
|
|
|
let (segments, connection_type) = connection.parse_packet(&buf[..n]).await;
|
2025-03-09 11:07:01 -04:00
|
|
|
for segment in &segments {
|
|
|
|
match &segment.segment_type {
|
2025-03-21 19:56:16 -04:00
|
|
|
SegmentType::InitializeSession { actor_id } => {
|
|
|
|
tracing::info!("actor id to parse: {actor_id}");
|
|
|
|
|
|
|
|
// collect actor data
|
2025-03-22 16:15:29 -04:00
|
|
|
connection.player_data =
|
|
|
|
database.find_player_data(actor_id.parse::<u32>().unwrap());
|
2025-03-21 19:56:16 -04:00
|
|
|
|
2025-03-10 21:31:21 -04:00
|
|
|
// We have send THEM a keep alive
|
|
|
|
{
|
2025-03-15 20:36:39 -04:00
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
|
|
|
source_actor: 0,
|
|
|
|
target_actor: 0,
|
|
|
|
segment_type: SegmentType::KeepAlive {
|
|
|
|
id: 0xE0037603u32,
|
2025-03-17 17:31:22 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-03-15 20:36:39 -04:00
|
|
|
},
|
|
|
|
})
|
|
|
|
.await;
|
2025-03-10 21:31:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
match connection_type {
|
|
|
|
kawari::packet::ConnectionType::Zone => {
|
|
|
|
tracing::info!(
|
2025-03-21 19:56:16 -04:00
|
|
|
"Client {actor_id} is initializing zone session..."
|
2025-03-10 21:31:21 -04:00
|
|
|
);
|
|
|
|
|
2025-03-15 20:36:39 -04:00
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
|
|
|
source_actor: 0,
|
|
|
|
target_actor: 0,
|
|
|
|
segment_type: SegmentType::ZoneInitialize {
|
2025-03-21 19:56:16 -04:00
|
|
|
player_id: connection.player_data.actor_id,
|
2025-03-16 14:07:56 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-03-15 20:36:39 -04:00
|
|
|
},
|
|
|
|
})
|
|
|
|
.await;
|
2025-03-10 21:31:21 -04:00
|
|
|
}
|
|
|
|
kawari::packet::ConnectionType::Chat => {
|
|
|
|
tracing::info!(
|
2025-03-21 19:56:16 -04:00
|
|
|
"Client {actor_id} is initializing chat session..."
|
2025-03-10 21:31:21 -04:00
|
|
|
);
|
|
|
|
|
|
|
|
{
|
2025-03-15 20:36:39 -04:00
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
|
|
|
source_actor: 0,
|
|
|
|
target_actor: 0,
|
|
|
|
segment_type: SegmentType::ZoneInitialize {
|
2025-03-21 19:56:16 -04:00
|
|
|
player_id: connection.player_data.actor_id,
|
2025-03-16 14:07:56 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-03-15 20:36:39 -04:00
|
|
|
},
|
|
|
|
})
|
|
|
|
.await;
|
2025-03-10 21:31:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2025-03-16 17:43:29 -04:00
|
|
|
let ipc = ServerZoneIpcSegment {
|
|
|
|
op_code: ServerZoneIpcType::InitializeChat,
|
2025-03-16 14:07:56 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-03-16 17:43:29 -04:00
|
|
|
data: ServerZoneIpcData::InitializeChat {
|
|
|
|
unk: [0; 8],
|
|
|
|
},
|
2025-03-16 14:07:56 -04:00
|
|
|
..Default::default()
|
2025-03-10 21:31:21 -04:00
|
|
|
};
|
|
|
|
|
2025-03-15 20:36:39 -04:00
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
2025-03-21 19:56:16 -04:00
|
|
|
source_actor: connection.player_data.actor_id,
|
|
|
|
target_actor: connection.player_data.actor_id,
|
2025-03-15 20:36:39 -04:00
|
|
|
segment_type: SegmentType::Ipc { data: ipc },
|
|
|
|
})
|
|
|
|
.await;
|
2025-03-10 21:31:21 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => panic!(
|
|
|
|
"The client is trying to initialize the wrong connection?!"
|
|
|
|
),
|
|
|
|
}
|
|
|
|
}
|
2025-03-09 11:07:01 -04:00
|
|
|
SegmentType::Ipc { data } => {
|
2025-03-10 21:31:21 -04:00
|
|
|
match &data.data {
|
2025-03-16 17:43:29 -04:00
|
|
|
ClientZoneIpcData::InitRequest { .. } => {
|
2025-03-10 21:31:21 -04:00
|
|
|
tracing::info!(
|
|
|
|
"Client is now requesting zone information. Sending!"
|
|
|
|
);
|
|
|
|
|
|
|
|
// IPC Init(?)
|
|
|
|
{
|
2025-03-16 17:43:29 -04:00
|
|
|
let ipc = ServerZoneIpcSegment {
|
|
|
|
op_code: ServerZoneIpcType::InitResponse,
|
2025-03-10 21:31:21 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-03-16 17:43:29 -04:00
|
|
|
data: ServerZoneIpcData::InitResponse {
|
2025-03-10 21:31:21 -04:00
|
|
|
unk1: 0,
|
2025-03-21 19:56:16 -04:00
|
|
|
character_id: connection.player_data.actor_id,
|
2025-03-10 21:31:21 -04:00
|
|
|
unk2: 0,
|
|
|
|
},
|
2025-03-16 14:07:56 -04:00
|
|
|
..Default::default()
|
2025-03-10 21:31:21 -04:00
|
|
|
};
|
|
|
|
|
2025-03-15 20:36:39 -04:00
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
2025-03-21 19:56:16 -04:00
|
|
|
source_actor: connection.player_data.actor_id,
|
|
|
|
target_actor: connection.player_data.actor_id,
|
2025-03-23 17:10:47 -04:00
|
|
|
segment_type: SegmentType::Ipc { data: ipc },
|
|
|
|
})
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
|
2025-03-23 17:43:06 -04:00
|
|
|
let chara_details = database
|
|
|
|
.find_chara_make(connection.player_data.content_id);
|
2025-03-23 17:10:47 -04:00
|
|
|
|
2025-03-23 17:43:06 -04:00
|
|
|
// fill inventory
|
|
|
|
connection.inventory.equip_racial_items(
|
|
|
|
chara_details.chara_make.customize.race,
|
2025-03-23 17:49:53 -04:00
|
|
|
chara_details.chara_make.customize.gender,
|
2025-03-23 17:43:06 -04:00
|
|
|
);
|
2025-03-23 17:10:47 -04:00
|
|
|
|
2025-03-23 17:43:06 -04:00
|
|
|
// Send inventory
|
|
|
|
connection.send_inventory().await;
|
2025-03-10 21:31:21 -04:00
|
|
|
|
|
|
|
// Control Data
|
|
|
|
{
|
2025-03-16 17:43:29 -04:00
|
|
|
let ipc = ServerZoneIpcSegment {
|
|
|
|
op_code: ServerZoneIpcType::ActorControlSelf,
|
2025-03-10 21:31:21 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-03-16 17:43:29 -04:00
|
|
|
data: ServerZoneIpcData::ActorControlSelf(
|
2025-03-12 18:05:41 -04:00
|
|
|
ActorControlSelf {
|
|
|
|
category:
|
2025-03-23 15:28:53 -04:00
|
|
|
ActorControlCategory::SetCharaGearParamUI {
|
|
|
|
unk1: 1,
|
|
|
|
unk2: 1,
|
|
|
|
}
|
2025-03-12 18:05:41 -04:00
|
|
|
},
|
|
|
|
),
|
2025-03-16 14:07:56 -04:00
|
|
|
..Default::default()
|
2025-03-10 21:31:21 -04:00
|
|
|
};
|
|
|
|
|
2025-03-15 20:36:39 -04:00
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
2025-03-21 19:56:16 -04:00
|
|
|
source_actor: connection.player_data.actor_id,
|
|
|
|
target_actor: connection.player_data.actor_id,
|
2025-03-15 20:36:39 -04:00
|
|
|
segment_type: SegmentType::Ipc { data: ipc },
|
|
|
|
})
|
|
|
|
.await;
|
2025-03-10 21:31:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Stats
|
|
|
|
{
|
2025-03-16 17:43:29 -04:00
|
|
|
let ipc = ServerZoneIpcSegment {
|
|
|
|
op_code: ServerZoneIpcType::PlayerStats,
|
2025-03-10 21:31:21 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-03-16 17:43:29 -04:00
|
|
|
data: ServerZoneIpcData::PlayerStats(PlayerStats {
|
2025-03-10 21:31:21 -04:00
|
|
|
strength: 1,
|
|
|
|
hp: 100,
|
|
|
|
mp: 100,
|
2025-03-12 18:05:41 -04:00
|
|
|
..Default::default()
|
|
|
|
}),
|
2025-03-16 14:07:56 -04:00
|
|
|
..Default::default()
|
2025-03-10 21:31:21 -04:00
|
|
|
};
|
|
|
|
|
2025-03-15 20:36:39 -04:00
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
2025-03-21 19:56:16 -04:00
|
|
|
source_actor: connection.player_data.actor_id,
|
|
|
|
target_actor: connection.player_data.actor_id,
|
2025-03-15 20:36:39 -04:00
|
|
|
segment_type: SegmentType::Ipc { data: ipc },
|
|
|
|
})
|
|
|
|
.await;
|
2025-03-10 21:31:21 -04:00
|
|
|
}
|
|
|
|
|
2025-03-22 19:05:29 -04:00
|
|
|
let zone_id = chara_details.zone_id;
|
2025-03-22 18:53:53 -04:00
|
|
|
connection.zone = Some(Zone::load(zone_id));
|
|
|
|
|
2025-03-10 21:31:21 -04:00
|
|
|
// Player Setup
|
|
|
|
{
|
2025-03-16 17:43:29 -04:00
|
|
|
let ipc = ServerZoneIpcSegment {
|
|
|
|
op_code: ServerZoneIpcType::PlayerSetup,
|
2025-03-10 21:31:21 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-03-16 17:43:29 -04:00
|
|
|
data: ServerZoneIpcData::PlayerSetup(PlayerSetup {
|
2025-03-21 19:56:16 -04:00
|
|
|
content_id: connection.player_data.content_id,
|
2025-03-10 21:31:21 -04:00
|
|
|
exp: [10000; 32],
|
|
|
|
levels: [100; 32],
|
2025-03-21 19:56:16 -04:00
|
|
|
name: chara_details.name,
|
|
|
|
char_id: connection.player_data.actor_id,
|
|
|
|
race: chara_details.chara_make.customize.race,
|
|
|
|
gender: chara_details
|
|
|
|
.chara_make
|
|
|
|
.customize
|
|
|
|
.gender,
|
|
|
|
tribe: chara_details
|
|
|
|
.chara_make
|
|
|
|
.customize
|
|
|
|
.subrace,
|
2025-03-22 18:34:27 -04:00
|
|
|
city_state: chara_details.city_state,
|
2025-03-21 19:56:16 -04:00
|
|
|
nameday_month: chara_details
|
|
|
|
.chara_make
|
|
|
|
.birth_month
|
|
|
|
as u8,
|
|
|
|
nameday_day: chara_details.chara_make.birth_day
|
|
|
|
as u8,
|
|
|
|
deity: chara_details.chara_make.guardian as u8,
|
2025-03-12 18:05:41 -04:00
|
|
|
..Default::default()
|
|
|
|
}),
|
2025-03-16 14:07:56 -04:00
|
|
|
..Default::default()
|
2025-03-10 21:31:21 -04:00
|
|
|
};
|
|
|
|
|
2025-03-15 20:36:39 -04:00
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
2025-03-21 19:56:16 -04:00
|
|
|
source_actor: connection.player_data.actor_id,
|
|
|
|
target_actor: connection.player_data.actor_id,
|
2025-03-15 20:36:39 -04:00
|
|
|
segment_type: SegmentType::Ipc { data: ipc },
|
|
|
|
})
|
|
|
|
.await;
|
2025-03-10 21:31:21 -04:00
|
|
|
}
|
|
|
|
|
2025-03-22 18:53:53 -04:00
|
|
|
connection.change_zone(zone_id).await;
|
2025-03-11 23:52:55 -04:00
|
|
|
|
2025-03-13 21:11:20 -04:00
|
|
|
// send welcome message
|
|
|
|
{
|
2025-03-16 17:43:29 -04:00
|
|
|
let ipc = ServerZoneIpcSegment {
|
|
|
|
op_code: ServerZoneIpcType::ServerChatMessage,
|
2025-03-13 21:11:20 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-03-16 17:43:29 -04:00
|
|
|
data: ServerZoneIpcData::ServerChatMessage {
|
2025-03-13 21:11:20 -04:00
|
|
|
message: "Welcome to Kawari!".to_string(),
|
|
|
|
unk: 0,
|
|
|
|
},
|
2025-03-16 14:07:56 -04:00
|
|
|
..Default::default()
|
2025-03-13 21:11:20 -04:00
|
|
|
};
|
|
|
|
|
2025-03-15 20:36:39 -04:00
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
2025-03-21 19:56:16 -04:00
|
|
|
source_actor: connection.player_data.actor_id,
|
|
|
|
target_actor: connection.player_data.actor_id,
|
2025-03-15 20:36:39 -04:00
|
|
|
segment_type: SegmentType::Ipc { data: ipc },
|
|
|
|
})
|
|
|
|
.await;
|
2025-03-13 21:11:20 -04:00
|
|
|
}
|
2025-03-16 14:49:18 -04:00
|
|
|
}
|
2025-03-16 17:43:29 -04:00
|
|
|
ClientZoneIpcData::FinishLoading { .. } => {
|
2025-03-16 14:49:18 -04:00
|
|
|
tracing::info!(
|
|
|
|
"Client has finished loading... spawning in!"
|
|
|
|
);
|
2025-03-13 21:11:20 -04:00
|
|
|
|
2025-03-22 16:15:29 -04:00
|
|
|
let chara_details = database
|
|
|
|
.find_chara_make(connection.player_data.content_id);
|
2025-03-21 19:56:16 -04:00
|
|
|
|
2025-03-12 00:32:37 -04:00
|
|
|
// send player spawn
|
|
|
|
{
|
2025-03-16 17:43:29 -04:00
|
|
|
let ipc = ServerZoneIpcSegment {
|
|
|
|
op_code: ServerZoneIpcType::PlayerSpawn,
|
2025-03-11 23:52:55 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-03-16 17:43:29 -04:00
|
|
|
data: ServerZoneIpcData::PlayerSpawn(PlayerSpawn {
|
2025-03-23 12:16:15 -04:00
|
|
|
account_id: connection.player_data.account_id,
|
2025-03-22 17:06:16 -04:00
|
|
|
content_id: connection.player_data.content_id,
|
2025-03-23 12:16:15 -04:00
|
|
|
current_world_id: config.world.world_id,
|
|
|
|
home_world_id: config.world.world_id,
|
|
|
|
gm_rank: GameMasterRank::Debug,
|
|
|
|
online_status: OnlineStatus::GameMasterBlue,
|
2025-03-18 22:13:28 -04:00
|
|
|
common: CommonSpawn {
|
|
|
|
class_job: 35,
|
2025-03-21 19:56:16 -04:00
|
|
|
name: chara_details.name,
|
2025-03-18 22:13:28 -04:00
|
|
|
hp_curr: 100,
|
|
|
|
hp_max: 100,
|
|
|
|
mp_curr: 100,
|
|
|
|
mp_max: 100,
|
2025-03-23 12:16:15 -04:00
|
|
|
object_kind: ObjectKind::Player(
|
|
|
|
PlayerSubKind::Player,
|
|
|
|
),
|
2025-03-21 19:56:16 -04:00
|
|
|
look: chara_details.chara_make.customize,
|
2025-03-18 22:13:28 -04:00
|
|
|
fc_tag: "LOCAL".to_string(),
|
2025-03-23 12:54:04 -04:00
|
|
|
display_flags: DisplayFlag::UNK,
|
2025-03-18 22:13:28 -04:00
|
|
|
models: [
|
|
|
|
0, // head
|
|
|
|
89, // body
|
|
|
|
89, // hands
|
|
|
|
89, // legs
|
|
|
|
89, // feet
|
|
|
|
0, // ears
|
|
|
|
0, // neck
|
|
|
|
0, // wrists
|
|
|
|
0, // left finger
|
|
|
|
0, // right finger
|
|
|
|
],
|
|
|
|
pos: exit_position
|
|
|
|
.unwrap_or(Position::default()),
|
|
|
|
..Default::default()
|
|
|
|
},
|
2025-03-12 18:22:17 -04:00
|
|
|
..Default::default()
|
|
|
|
}),
|
2025-03-16 14:07:56 -04:00
|
|
|
..Default::default()
|
2025-03-11 23:52:55 -04:00
|
|
|
};
|
|
|
|
|
2025-03-15 20:36:39 -04:00
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
2025-03-21 19:56:16 -04:00
|
|
|
source_actor: connection.player_data.actor_id,
|
|
|
|
target_actor: connection.player_data.actor_id,
|
2025-03-15 20:36:39 -04:00
|
|
|
segment_type: SegmentType::Ipc { data: ipc },
|
|
|
|
})
|
|
|
|
.await;
|
2025-03-12 00:32:37 -04:00
|
|
|
}
|
2025-03-15 19:34:29 -04:00
|
|
|
|
|
|
|
// fade in?
|
|
|
|
{
|
2025-03-16 17:43:29 -04:00
|
|
|
let ipc = ServerZoneIpcSegment {
|
|
|
|
op_code: ServerZoneIpcType::PrepareZoning,
|
2025-03-15 19:34:29 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-03-16 17:43:29 -04:00
|
|
|
data: ServerZoneIpcData::PrepareZoning {
|
2025-03-15 19:34:29 -04:00
|
|
|
unk: [0, 0, 0, 0],
|
|
|
|
},
|
2025-03-16 14:07:56 -04:00
|
|
|
..Default::default()
|
2025-03-15 19:34:29 -04:00
|
|
|
};
|
|
|
|
|
2025-03-15 20:36:39 -04:00
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
2025-03-21 19:56:16 -04:00
|
|
|
source_actor: connection.player_data.actor_id,
|
|
|
|
target_actor: connection.player_data.actor_id,
|
2025-03-15 20:36:39 -04:00
|
|
|
segment_type: SegmentType::Ipc { data: ipc },
|
|
|
|
})
|
|
|
|
.await;
|
2025-03-15 19:34:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// wipe any exit position so it isn't accidentally reused
|
|
|
|
exit_position = None;
|
2025-03-12 00:32:37 -04:00
|
|
|
}
|
2025-03-16 17:43:29 -04:00
|
|
|
ClientZoneIpcData::Unk1 { .. } => {
|
2025-03-12 00:32:37 -04:00
|
|
|
tracing::info!("Recieved Unk1!");
|
|
|
|
}
|
2025-03-16 17:43:29 -04:00
|
|
|
ClientZoneIpcData::Unk2 { .. } => {
|
2025-03-12 00:32:37 -04:00
|
|
|
tracing::info!("Recieved Unk2!");
|
|
|
|
}
|
2025-03-16 17:43:29 -04:00
|
|
|
ClientZoneIpcData::Unk3 { .. } => {
|
2025-03-12 00:32:37 -04:00
|
|
|
tracing::info!("Recieved Unk3!");
|
|
|
|
}
|
2025-03-16 17:43:29 -04:00
|
|
|
ClientZoneIpcData::Unk4 { .. } => {
|
2025-03-12 00:32:37 -04:00
|
|
|
tracing::info!("Recieved Unk4!");
|
|
|
|
}
|
2025-03-16 17:43:29 -04:00
|
|
|
ClientZoneIpcData::SetSearchInfoHandler { .. } => {
|
2025-03-12 00:32:37 -04:00
|
|
|
tracing::info!("Recieved SetSearchInfoHandler!");
|
|
|
|
}
|
2025-03-16 17:43:29 -04:00
|
|
|
ClientZoneIpcData::Unk5 { .. } => {
|
2025-03-12 00:32:37 -04:00
|
|
|
tracing::info!("Recieved Unk5!");
|
|
|
|
}
|
2025-03-16 17:43:29 -04:00
|
|
|
ClientZoneIpcData::SocialListRequest(request) => {
|
2025-03-16 14:07:56 -04:00
|
|
|
tracing::info!("Recieved social list request!");
|
|
|
|
|
|
|
|
match &request.request_type {
|
2025-03-16 17:43:29 -04:00
|
|
|
SocialListRequestType::Party => {
|
|
|
|
let ipc = ServerZoneIpcSegment {
|
|
|
|
op_code: ServerZoneIpcType::SocialList,
|
2025-03-16 14:07:56 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-03-16 17:43:29 -04:00
|
|
|
data: ServerZoneIpcData::SocialList(
|
|
|
|
SocialList {
|
|
|
|
request_type: request.request_type,
|
|
|
|
sequence: request.count,
|
|
|
|
entries: vec![PlayerEntry {
|
2025-03-22 17:06:16 -04:00
|
|
|
// TODO: fill with actual player data, it also shows up wrong in game
|
|
|
|
content_id: connection
|
|
|
|
.player_data
|
|
|
|
.content_id,
|
2025-03-22 18:53:53 -04:00
|
|
|
zone_id: connection
|
|
|
|
.zone
|
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
|
|
|
.id,
|
2025-03-16 17:43:29 -04:00
|
|
|
zone_id1: 0x0100,
|
|
|
|
class_job: 36,
|
|
|
|
level: 100,
|
|
|
|
one: 1,
|
2025-03-22 17:06:16 -04:00
|
|
|
name: "INVALID".to_string(),
|
2025-03-16 17:43:29 -04:00
|
|
|
fc_tag: "LOCAL".to_string(),
|
|
|
|
..Default::default()
|
|
|
|
}],
|
|
|
|
},
|
|
|
|
),
|
2025-03-16 14:07:56 -04:00
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
2025-03-21 19:56:16 -04:00
|
|
|
source_actor: connection
|
|
|
|
.player_data
|
|
|
|
.actor_id,
|
|
|
|
target_actor: connection
|
|
|
|
.player_data
|
|
|
|
.actor_id,
|
2025-03-16 14:07:56 -04:00
|
|
|
segment_type: SegmentType::Ipc {
|
|
|
|
data: ipc,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
.await;
|
|
|
|
}
|
2025-03-16 17:43:29 -04:00
|
|
|
SocialListRequestType::Friends => {
|
|
|
|
let ipc = ServerZoneIpcSegment {
|
|
|
|
op_code: ServerZoneIpcType::SocialList,
|
2025-03-16 14:07:56 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-03-16 17:43:29 -04:00
|
|
|
data: ServerZoneIpcData::SocialList(
|
|
|
|
SocialList {
|
|
|
|
request_type: request.request_type,
|
|
|
|
sequence: request.count,
|
|
|
|
entries: Default::default(),
|
|
|
|
},
|
|
|
|
),
|
2025-03-16 14:07:56 -04:00
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
2025-03-21 19:56:16 -04:00
|
|
|
source_actor: connection
|
|
|
|
.player_data
|
|
|
|
.actor_id,
|
|
|
|
target_actor: connection
|
|
|
|
.player_data
|
|
|
|
.actor_id,
|
2025-03-16 14:07:56 -04:00
|
|
|
segment_type: SegmentType::Ipc {
|
|
|
|
data: ipc,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
}
|
2025-03-12 00:32:37 -04:00
|
|
|
}
|
2025-03-16 17:43:29 -04:00
|
|
|
ClientZoneIpcData::Unk7 {
|
2025-03-13 21:49:03 -04:00
|
|
|
timestamp, unk1, ..
|
|
|
|
} => {
|
|
|
|
tracing::info!("Recieved Unk7! {:#?}", unk1);
|
|
|
|
|
|
|
|
// send unk11 in response
|
|
|
|
{
|
2025-03-16 17:43:29 -04:00
|
|
|
let ipc = ServerZoneIpcSegment {
|
|
|
|
op_code: ServerZoneIpcType::Unk11,
|
2025-03-13 21:49:03 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-03-16 17:43:29 -04:00
|
|
|
data: ServerZoneIpcData::Unk11 {
|
2025-03-13 21:49:03 -04:00
|
|
|
timestamp: *timestamp,
|
|
|
|
unk: 333,
|
|
|
|
},
|
2025-03-16 14:07:56 -04:00
|
|
|
..Default::default()
|
2025-03-13 21:49:03 -04:00
|
|
|
};
|
|
|
|
|
2025-03-15 20:36:39 -04:00
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
2025-03-21 19:56:16 -04:00
|
|
|
source_actor: connection.player_data.actor_id,
|
|
|
|
target_actor: connection.player_data.actor_id,
|
2025-03-15 20:36:39 -04:00
|
|
|
segment_type: SegmentType::Ipc { data: ipc },
|
|
|
|
})
|
|
|
|
.await;
|
2025-03-13 21:49:03 -04:00
|
|
|
}
|
2025-03-12 00:32:37 -04:00
|
|
|
}
|
2025-03-23 10:33:49 -04:00
|
|
|
ClientZoneIpcData::UpdatePositionHandler {
|
|
|
|
position, ..
|
|
|
|
} => {
|
|
|
|
tracing::info!("Character moved to {position:#?}");
|
|
|
|
|
|
|
|
connection.position = *position;
|
2025-03-10 21:31:21 -04:00
|
|
|
}
|
2025-03-16 17:43:29 -04:00
|
|
|
ClientZoneIpcData::LogOut { .. } => {
|
2025-03-12 18:44:05 -04:00
|
|
|
tracing::info!("Recieved log out from client!");
|
|
|
|
|
|
|
|
// tell the client to disconnect
|
|
|
|
{
|
2025-03-16 17:43:29 -04:00
|
|
|
let ipc = ServerZoneIpcSegment {
|
|
|
|
op_code: ServerZoneIpcType::LogOutComplete,
|
2025-03-12 18:44:05 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-03-16 17:43:29 -04:00
|
|
|
data: ServerZoneIpcData::LogOutComplete {
|
|
|
|
unk: [0; 8],
|
|
|
|
},
|
2025-03-16 14:07:56 -04:00
|
|
|
..Default::default()
|
2025-03-12 18:44:05 -04:00
|
|
|
};
|
|
|
|
|
2025-03-15 20:36:39 -04:00
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
2025-03-21 19:56:16 -04:00
|
|
|
source_actor: connection.player_data.actor_id,
|
|
|
|
target_actor: connection.player_data.actor_id,
|
2025-03-15 20:36:39 -04:00
|
|
|
segment_type: SegmentType::Ipc { data: ipc },
|
|
|
|
})
|
|
|
|
.await;
|
2025-03-12 18:44:05 -04:00
|
|
|
}
|
|
|
|
}
|
2025-03-16 17:43:29 -04:00
|
|
|
ClientZoneIpcData::Disconnected { .. } => {
|
2025-03-12 18:44:05 -04:00
|
|
|
tracing::info!("Client disconnected!");
|
|
|
|
}
|
2025-03-16 17:43:29 -04:00
|
|
|
ClientZoneIpcData::ChatMessage(chat_message) => {
|
2025-03-15 20:36:39 -04:00
|
|
|
ChatHandler::handle_chat_message(
|
|
|
|
&mut connection,
|
|
|
|
chat_message,
|
|
|
|
)
|
|
|
|
.await
|
2025-03-12 19:34:15 -04:00
|
|
|
}
|
2025-03-16 17:43:29 -04:00
|
|
|
ClientZoneIpcData::GameMasterCommand {
|
|
|
|
command, arg, ..
|
|
|
|
} => {
|
2025-03-13 00:41:16 -04:00
|
|
|
tracing::info!("Got a game master command!");
|
|
|
|
|
|
|
|
match &command {
|
2025-03-18 23:48:00 -04:00
|
|
|
GameMasterCommandType::ChangeWeather => {
|
|
|
|
connection.change_weather(*arg as u16).await
|
|
|
|
}
|
2025-03-13 00:41:16 -04:00
|
|
|
GameMasterCommandType::ChangeTerritory => {
|
2025-03-15 20:49:07 -04:00
|
|
|
connection.change_zone(*arg as u16).await
|
2025-03-13 00:41:16 -04:00
|
|
|
}
|
2025-03-23 15:28:53 -04:00
|
|
|
GameMasterCommandType::ToggleInvisibility => {
|
|
|
|
// Control Data
|
|
|
|
{
|
|
|
|
let ipc = ServerZoneIpcSegment {
|
|
|
|
op_code: ServerZoneIpcType::ActorControlSelf,
|
|
|
|
timestamp: timestamp_secs(),
|
|
|
|
data: ServerZoneIpcData::ActorControlSelf(
|
|
|
|
ActorControlSelf {
|
|
|
|
category:
|
|
|
|
ActorControlCategory::ToggleInvisibility {
|
|
|
|
invisible: 1
|
|
|
|
},
|
|
|
|
},
|
|
|
|
),
|
|
|
|
..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: ipc,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
}
|
2025-03-13 00:41:16 -04:00
|
|
|
}
|
|
|
|
}
|
2025-03-16 17:43:29 -04:00
|
|
|
ClientZoneIpcData::Unk12 { .. } => {
|
2025-03-14 00:30:37 -04:00
|
|
|
tracing::info!("Recieved Unk12!");
|
|
|
|
}
|
2025-03-16 17:43:29 -04:00
|
|
|
ClientZoneIpcData::EnterZoneLine {
|
2025-03-15 19:34:29 -04:00
|
|
|
exit_box_id,
|
|
|
|
position,
|
|
|
|
..
|
|
|
|
} => {
|
|
|
|
tracing::info!(
|
|
|
|
"Character entered {exit_box_id} with a position of {position:#?}!"
|
|
|
|
);
|
|
|
|
|
|
|
|
// find the exit box id
|
2025-03-15 20:49:07 -04:00
|
|
|
let new_territory;
|
|
|
|
{
|
|
|
|
let (_, exit_box) = connection
|
|
|
|
.zone
|
2025-03-22 18:53:53 -04:00
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
2025-03-15 20:49:07 -04:00
|
|
|
.find_exit_box(*exit_box_id)
|
|
|
|
.unwrap();
|
|
|
|
tracing::info!("exit box: {:#?}", exit_box);
|
|
|
|
|
|
|
|
// find the pop range on the other side
|
|
|
|
let new_zone = Zone::load(exit_box.territory_type);
|
|
|
|
let (destination_object, _) = new_zone
|
|
|
|
.find_pop_range(exit_box.destination_instance_id)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
// set the exit position
|
|
|
|
exit_position = Some(Position {
|
|
|
|
x: destination_object.transform.translation[0],
|
|
|
|
y: destination_object.transform.translation[1],
|
|
|
|
z: destination_object.transform.translation[2],
|
|
|
|
});
|
|
|
|
new_territory = exit_box.territory_type;
|
|
|
|
}
|
2025-03-15 19:34:29 -04:00
|
|
|
|
|
|
|
// fade out?
|
|
|
|
{
|
2025-03-16 17:43:29 -04:00
|
|
|
let ipc = ServerZoneIpcSegment {
|
|
|
|
op_code: ServerZoneIpcType::PrepareZoning,
|
2025-03-15 19:34:29 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-03-16 17:43:29 -04:00
|
|
|
data: ServerZoneIpcData::PrepareZoning {
|
2025-03-15 19:34:29 -04:00
|
|
|
unk: [0x01000000, 0, 0, 0],
|
|
|
|
},
|
2025-03-16 14:07:56 -04:00
|
|
|
..Default::default()
|
2025-03-15 19:34:29 -04:00
|
|
|
};
|
|
|
|
|
2025-03-15 20:36:39 -04:00
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
2025-03-21 19:56:16 -04:00
|
|
|
source_actor: connection.player_data.actor_id,
|
|
|
|
target_actor: connection.player_data.actor_id,
|
2025-03-15 20:36:39 -04:00
|
|
|
segment_type: SegmentType::Ipc { data: ipc },
|
|
|
|
})
|
|
|
|
.await;
|
2025-03-15 19:34:29 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// fade out? x2
|
|
|
|
{
|
2025-03-16 17:43:29 -04:00
|
|
|
let ipc = ServerZoneIpcSegment {
|
|
|
|
op_code: ServerZoneIpcType::PrepareZoning,
|
2025-03-15 19:34:29 -04:00
|
|
|
timestamp: timestamp_secs(),
|
2025-03-16 17:43:29 -04:00
|
|
|
data: ServerZoneIpcData::PrepareZoning {
|
2025-03-15 19:34:29 -04:00
|
|
|
unk: [0, 0x00000085, 0x00030000, 0x000008ff], // last thing is probably a float?
|
|
|
|
},
|
2025-03-16 14:07:56 -04:00
|
|
|
..Default::default()
|
2025-03-15 19:34:29 -04:00
|
|
|
};
|
|
|
|
|
2025-03-15 20:36:39 -04:00
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
2025-03-21 19:56:16 -04:00
|
|
|
source_actor: connection.player_data.actor_id,
|
|
|
|
target_actor: connection.player_data.actor_id,
|
2025-03-15 20:36:39 -04:00
|
|
|
segment_type: SegmentType::Ipc { data: ipc },
|
|
|
|
})
|
|
|
|
.await;
|
2025-03-15 19:34:29 -04:00
|
|
|
}
|
|
|
|
|
2025-03-15 20:49:07 -04:00
|
|
|
tracing::info!("sending them to {:#?}", new_territory);
|
2025-03-15 19:34:29 -04:00
|
|
|
|
2025-03-15 20:49:07 -04:00
|
|
|
connection.change_zone(new_territory).await;
|
2025-03-15 19:34:29 -04:00
|
|
|
}
|
2025-03-16 17:43:29 -04:00
|
|
|
ClientZoneIpcData::Unk13 { .. } => {
|
2025-03-15 19:34:29 -04:00
|
|
|
tracing::info!("Recieved Unk13!");
|
|
|
|
}
|
2025-03-16 17:43:29 -04:00
|
|
|
ClientZoneIpcData::Unk14 { .. } => {
|
2025-03-15 19:34:29 -04:00
|
|
|
tracing::info!("Recieved Unk14!");
|
|
|
|
}
|
2025-03-19 00:28:47 -04:00
|
|
|
ClientZoneIpcData::ActionRequest(request) => {
|
|
|
|
tracing::info!("Recieved action request: {:#?}!", request);
|
|
|
|
|
|
|
|
let config = get_config();
|
|
|
|
|
|
|
|
let mut game_data = GameData::from_existing(
|
|
|
|
Platform::Win32,
|
|
|
|
&config.game_location,
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
let exh =
|
|
|
|
game_data.read_excel_sheet_header("Action").unwrap();
|
|
|
|
let exd = game_data
|
|
|
|
.read_excel_sheet("Action", &exh, Language::English, 0)
|
|
|
|
.unwrap();
|
|
|
|
|
2025-03-21 19:56:16 -04:00
|
|
|
let action_row =
|
|
|
|
&exd.read_row(&exh, request.action_id).unwrap()[0];
|
2025-03-19 00:28:47 -04:00
|
|
|
|
|
|
|
println!("Found action: {:#?}", action_row);
|
|
|
|
|
|
|
|
// send new status list
|
|
|
|
{
|
|
|
|
let ipc = ServerZoneIpcSegment {
|
|
|
|
op_code: ServerZoneIpcType::StatusEffectList,
|
|
|
|
timestamp: timestamp_secs(),
|
|
|
|
data: ServerZoneIpcData::StatusEffectList(
|
|
|
|
kawari::world::ipc::StatusEffectList {
|
|
|
|
statues: [StatusEffect {
|
|
|
|
effect_id: 50,
|
|
|
|
param: 0,
|
|
|
|
duration: 50.0,
|
2025-03-21 19:56:16 -04:00
|
|
|
source_actor_id: connection
|
|
|
|
.player_data
|
|
|
|
.actor_id,
|
2025-03-19 00:28:47 -04:00
|
|
|
};
|
|
|
|
30],
|
|
|
|
..Default::default()
|
|
|
|
},
|
|
|
|
),
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
2025-03-21 19:56:16 -04:00
|
|
|
source_actor: connection.player_data.actor_id,
|
|
|
|
target_actor: connection.player_data.actor_id,
|
2025-03-19 00:28:47 -04:00
|
|
|
segment_type: SegmentType::Ipc { data: ipc },
|
|
|
|
})
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
}
|
2025-03-23 10:33:49 -04:00
|
|
|
ClientZoneIpcData::Unk15 { .. } => {
|
|
|
|
tracing::info!("Recieved Unk15!");
|
|
|
|
}
|
2025-03-10 21:31:21 -04:00
|
|
|
}
|
2025-03-09 11:07:01 -04:00
|
|
|
}
|
|
|
|
SegmentType::KeepAlive { id, timestamp } => {
|
2025-03-16 17:43:29 -04:00
|
|
|
send_keep_alive::<ServerZoneIpcSegment>(
|
2025-03-15 20:36:39 -04:00
|
|
|
&mut connection.socket,
|
|
|
|
&mut connection.state,
|
2025-03-18 19:49:52 -04:00
|
|
|
ConnectionType::Zone,
|
2025-03-15 20:36:39 -04:00
|
|
|
*id,
|
|
|
|
*timestamp,
|
|
|
|
)
|
|
|
|
.await
|
2025-03-10 21:31:21 -04:00
|
|
|
}
|
|
|
|
SegmentType::KeepAliveResponse { .. } => {
|
|
|
|
tracing::info!("Got keep alive response from client... cool...");
|
2025-03-09 11:07:01 -04:00
|
|
|
}
|
2025-03-21 19:56:16 -04:00
|
|
|
SegmentType::CustomIpc { data } => {
|
|
|
|
match &data.data {
|
|
|
|
CustomIpcData::RequestCreateCharacter {
|
|
|
|
name,
|
|
|
|
chara_make_json,
|
|
|
|
} => {
|
|
|
|
tracing::info!(
|
|
|
|
"creating character from: {name} {chara_make_json}"
|
|
|
|
);
|
|
|
|
|
2025-03-23 18:14:14 -04:00
|
|
|
let chara_make = CharaMake::from_json(chara_make_json);
|
2025-03-22 18:34:27 -04:00
|
|
|
|
|
|
|
let city_state =
|
|
|
|
get_citystate(chara_make.classjob_id as u16);
|
|
|
|
|
|
|
|
let (content_id, actor_id) = database.create_player_data(
|
|
|
|
name,
|
|
|
|
chara_make_json,
|
|
|
|
city_state,
|
2025-03-22 19:05:29 -04:00
|
|
|
determine_initial_starting_zone(city_state),
|
2025-03-22 18:34:27 -04:00
|
|
|
);
|
2025-03-21 19:56:16 -04:00
|
|
|
|
|
|
|
tracing::info!(
|
|
|
|
"Created new player: {content_id} {actor_id}"
|
|
|
|
);
|
|
|
|
|
|
|
|
// send them the new actor and content id
|
|
|
|
{
|
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
|
|
|
source_actor: 0,
|
|
|
|
target_actor: 0,
|
|
|
|
segment_type: SegmentType::CustomIpc {
|
|
|
|
data: CustomIpcSegment {
|
|
|
|
unk1: 0,
|
|
|
|
unk2: 0,
|
|
|
|
op_code:
|
|
|
|
CustomIpcType::CharacterCreated,
|
|
|
|
server_id: 0,
|
|
|
|
timestamp: 0,
|
|
|
|
data: CustomIpcData::CharacterCreated {
|
|
|
|
actor_id,
|
|
|
|
content_id,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CustomIpcData::GetActorId { content_id } => {
|
2025-03-22 16:15:29 -04:00
|
|
|
let actor_id = database.find_actor_id(*content_id);
|
2025-03-21 19:56:16 -04:00
|
|
|
|
|
|
|
tracing::info!("We found an actor id: {actor_id}");
|
|
|
|
|
|
|
|
// send them the actor id
|
|
|
|
{
|
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
|
|
|
source_actor: 0,
|
|
|
|
target_actor: 0,
|
|
|
|
segment_type: SegmentType::CustomIpc {
|
|
|
|
data: CustomIpcSegment {
|
|
|
|
unk1: 0,
|
|
|
|
unk2: 0,
|
|
|
|
op_code: CustomIpcType::ActorIdFound,
|
|
|
|
server_id: 0,
|
|
|
|
timestamp: 0,
|
|
|
|
data: CustomIpcData::ActorIdFound {
|
|
|
|
actor_id,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
CustomIpcData::CheckNameIsAvailable { name } => {
|
2025-03-22 16:15:29 -04:00
|
|
|
let is_name_free = database.check_is_name_free(name);
|
2025-03-21 19:56:16 -04:00
|
|
|
let is_name_free = if is_name_free { 1 } else { 0 };
|
|
|
|
|
|
|
|
// send response
|
|
|
|
{
|
|
|
|
connection
|
|
|
|
.send_segment(PacketSegment {
|
|
|
|
source_actor: 0,
|
|
|
|
target_actor: 0,
|
|
|
|
segment_type: SegmentType::CustomIpc {
|
|
|
|
data: CustomIpcSegment {
|
|
|
|
unk1: 0,
|
|
|
|
unk2: 0,
|
|
|
|
op_code: CustomIpcType::NameIsAvailableResponse,
|
|
|
|
server_id: 0,
|
|
|
|
timestamp: 0,
|
|
|
|
data: CustomIpcData::NameIsAvailableResponse {
|
|
|
|
free: is_name_free,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
}
|
2025-03-21 21:26:32 -04:00
|
|
|
CustomIpcData::RequestCharacterList { service_account_id } => {
|
2025-03-22 17:00:21 -04:00
|
|
|
let config = get_config();
|
|
|
|
|
|
|
|
let characters = database.get_character_list(
|
|
|
|
*service_account_id,
|
|
|
|
config.world.world_id,
|
|
|
|
&get_world_name(config.world.world_id),
|
|
|
|
);
|
2025-03-21 21:26:32 -04:00
|
|
|
|
|
|
|
// send response
|
|
|
|
{
|
|
|
|
send_packet::<CustomIpcSegment>(
|
|
|
|
&mut connection.socket,
|
|
|
|
&mut connection.state,
|
|
|
|
ConnectionType::None,
|
|
|
|
CompressionType::Uncompressed,
|
|
|
|
&[PacketSegment {
|
|
|
|
source_actor: 0,
|
|
|
|
target_actor: 0,
|
|
|
|
segment_type: SegmentType::CustomIpc {
|
|
|
|
data: CustomIpcSegment {
|
|
|
|
unk1: 0,
|
|
|
|
unk2: 0,
|
|
|
|
op_code: CustomIpcType::RequestCharacterListRepsonse,
|
|
|
|
server_id: 0,
|
|
|
|
timestamp: 0,
|
|
|
|
data: CustomIpcData::RequestCharacterListRepsonse {
|
|
|
|
characters
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}],
|
|
|
|
)
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
}
|
2025-03-22 17:32:00 -04:00
|
|
|
CustomIpcData::DeleteCharacter { content_id } => {
|
|
|
|
database.delete_character(*content_id);
|
|
|
|
|
|
|
|
// send response
|
|
|
|
{
|
|
|
|
send_packet::<CustomIpcSegment>(
|
|
|
|
&mut connection.socket,
|
|
|
|
&mut connection.state,
|
|
|
|
ConnectionType::None,
|
|
|
|
CompressionType::Uncompressed,
|
|
|
|
&[PacketSegment {
|
|
|
|
source_actor: 0,
|
|
|
|
target_actor: 0,
|
|
|
|
segment_type: SegmentType::CustomIpc {
|
|
|
|
data: CustomIpcSegment {
|
|
|
|
unk1: 0,
|
|
|
|
unk2: 0,
|
|
|
|
op_code:
|
|
|
|
CustomIpcType::CharacterDeleted,
|
|
|
|
server_id: 0,
|
|
|
|
timestamp: 0,
|
|
|
|
data: CustomIpcData::CharacterDeleted {
|
|
|
|
deleted: 1,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}],
|
|
|
|
)
|
|
|
|
.await;
|
|
|
|
}
|
|
|
|
}
|
2025-03-21 19:56:16 -04:00
|
|
|
_ => panic!(
|
|
|
|
"The server is recieving a response or unknown custom IPC!"
|
|
|
|
),
|
|
|
|
}
|
|
|
|
}
|
2025-03-09 11:07:01 -04:00
|
|
|
_ => {
|
|
|
|
panic!("The server is recieving a response or unknown packet!")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|