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

Move custom IPC handling to a separate file

This commit is contained in:
Joshua Goins 2025-05-05 21:03:47 -04:00
parent 3139d63b91
commit 873d7f5951
4 changed files with 248 additions and 227 deletions

View file

@ -86,7 +86,7 @@ async fn world_status() -> Html<String> {
async fn setup() -> Html<String> { async fn setup() -> Html<String> {
let environment = setup_default_environment(); let environment = setup_default_environment();
let template = environment.get_template("setup.html").unwrap(); let template = environment.get_template("setup.html").unwrap();
Html(template.render({}).unwrap()) Html(template.render(()).unwrap())
} }
#[derive(Deserialize)] #[derive(Deserialize)]
@ -101,7 +101,7 @@ async fn launcher_config(Query(params): Query<Params>) -> String {
let environment = setup_default_environment(); let environment = setup_default_environment();
let template = environment.get_template("launchertweaks.toml").unwrap(); let template = environment.get_template("launchertweaks.toml").unwrap();
template template
.render(context! { launcher_url => config.launcher.server_name, enable_webview2 => if params.r#type == "webview2" { false } else { true }, game_patch_server => config.patch.game_server_name, boot_patch_server => config.patch.boot_server_name, lobby_port => config.lobby.port }) .render(context! { launcher_url => config.launcher.server_name, enable_webview2 => params.r#type != "webview2", game_patch_server => config.patch.game_server_name, boot_patch_server => config.patch.boot_server_name, lobby_port => config.lobby.port })
.unwrap() .unwrap()
} }

View file

@ -3,13 +3,11 @@ use std::net::SocketAddr;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use kawari::RECEIVE_BUFFER_SIZE; use kawari::RECEIVE_BUFFER_SIZE;
use kawari::common::workdefinitions::{CharaMake, RemakeMode}; use kawari::common::Position;
use kawari::common::{GameData, ObjectId, timestamp_secs}; use kawari::common::{GameData, ObjectId, timestamp_secs};
use kawari::common::{Position, determine_initial_starting_zone};
use kawari::config::get_config; use kawari::config::get_config;
use kawari::inventory::{Inventory, Item}; use kawari::inventory::Item;
use kawari::ipc::chat::{ServerChatIpcData, ServerChatIpcSegment}; use kawari::ipc::chat::{ServerChatIpcData, ServerChatIpcSegment};
use kawari::ipc::kawari::{CustomIpcData, CustomIpcSegment, CustomIpcType};
use kawari::ipc::zone::{ use kawari::ipc::zone::{
ActionEffect, ActionResult, ClientZoneIpcData, EffectKind, EventStart, GameMasterCommandType, ActionEffect, ActionResult, ClientZoneIpcData, EffectKind, EventStart, GameMasterCommandType,
GameMasterRank, OnlineStatus, ServerZoneIpcData, ServerZoneIpcSegment, SocialListRequestType, GameMasterRank, OnlineStatus, ServerZoneIpcData, ServerZoneIpcSegment, SocialListRequestType,
@ -20,12 +18,11 @@ use kawari::ipc::zone::{
use kawari::opcodes::{ServerChatIpcType, ServerZoneIpcType}; use kawari::opcodes::{ServerChatIpcType, ServerZoneIpcType};
use kawari::packet::oodle::OodleNetwork; use kawari::packet::oodle::OodleNetwork;
use kawari::packet::{ use kawari::packet::{
CompressionType, ConnectionType, PacketSegment, PacketState, SegmentData, SegmentType, ConnectionType, PacketSegment, PacketState, SegmentData, SegmentType, send_keep_alive,
send_keep_alive, send_packet,
}; };
use kawari::world::{ use kawari::world::{
Actor, ClientHandle, EffectsBuilder, FromServer, LuaPlayer, PlayerData, ServerHandle, Actor, ClientHandle, EffectsBuilder, FromServer, LuaPlayer, PlayerData, ServerHandle,
StatusEffects, ToServer, WorldDatabase, server_main_loop, StatusEffects, ToServer, WorldDatabase, handle_custom_ipc, server_main_loop,
}; };
use kawari::world::{ChatHandler, Zone, ZoneConnection}; use kawari::world::{ChatHandler, Zone, ZoneConnection};
@ -759,7 +756,7 @@ async fn client_loop(
let state = lua.app_data_ref::<ExtraLuaState>().unwrap(); let state = lua.app_data_ref::<ExtraLuaState>().unwrap();
if let Some(event_script) = if let Some(event_script) =
state.event_scripts.get(&event_id) state.event_scripts.get(event_id)
{ {
// run script // run script
lua.scope(|scope| { lua.scope(|scope| {
@ -856,223 +853,7 @@ async fn client_loop(
SegmentData::KeepAliveResponse { .. } => { SegmentData::KeepAliveResponse { .. } => {
tracing::info!("Got keep alive response from client... cool..."); tracing::info!("Got keep alive response from client... cool...");
} }
SegmentData::KawariIpc { data } => { SegmentData::KawariIpc { data } => handle_custom_ipc(&mut connection, data).await,
match &data.data {
CustomIpcData::RequestCreateCharacter {
service_account_id,
name,
chara_make_json,
} => {
tracing::info!("creating character from: {name} {chara_make_json}");
let chara_make = CharaMake::from_json(chara_make_json);
let city_state;
{
let mut game_data = game_data.lock().unwrap();
city_state =
game_data.get_citystate(chara_make.classjob_id as u16);
}
let mut inventory = Inventory::default();
{
let mut game_data = game_data.lock().unwrap();
// fill inventory
inventory.equip_racial_items(
chara_make.customize.race,
chara_make.customize.gender,
&mut game_data,
);
}
let (content_id, actor_id) = database.create_player_data(
*service_account_id,
name,
chara_make_json,
city_state,
determine_initial_starting_zone(city_state),
inventory
);
tracing::info!("Created new player: {content_id} {actor_id}");
// send them the new actor and content id
{
connection
.send_segment(PacketSegment {
segment_type: SegmentType::KawariIpc,
data: SegmentData::KawariIpc {
data: CustomIpcSegment {
op_code: CustomIpcType::CharacterCreated,
data: CustomIpcData::CharacterCreated {
actor_id,
content_id,
},
..Default::default()
},
},
..Default::default()
})
.await;
}
}
CustomIpcData::GetActorId { content_id } => {
let actor_id = database.find_actor_id(*content_id);
tracing::info!("We found an actor id: {actor_id}");
// send them the actor id
{
connection
.send_segment(PacketSegment {
segment_type: SegmentType::KawariIpc,
data: SegmentData::KawariIpc {
data: CustomIpcSegment {
op_code: CustomIpcType::ActorIdFound,
data: CustomIpcData::ActorIdFound { actor_id },
..Default::default()
},
},
..Default::default()
})
.await;
}
}
CustomIpcData::CheckNameIsAvailable { name } => {
let is_name_free = database.check_is_name_free(name);
// send response
{
connection
.send_segment(PacketSegment {
segment_type: SegmentType::KawariIpc,
data: SegmentData::KawariIpc {
data: CustomIpcSegment {
op_code: CustomIpcType::NameIsAvailableResponse,
data: CustomIpcData::NameIsAvailableResponse {
free: is_name_free,
},
..Default::default()
},
},
..Default::default()
})
.await;
}
}
CustomIpcData::RequestCharacterList { service_account_id } => {
let config = get_config();
let world_name;
{
let mut game_data = game_data.lock().unwrap();
world_name = game_data.get_world_name(config.world.world_id);
}
let characters;
{
let mut game_data = game_data.lock().unwrap();
characters = database.get_character_list(
*service_account_id,
config.world.world_id,
&world_name,
&mut game_data,
);
}
// send response
{
send_packet::<CustomIpcSegment>(
&mut connection.socket,
&mut connection.state,
ConnectionType::None,
CompressionType::Uncompressed,
&[PacketSegment {
segment_type: SegmentType::KawariIpc,
data: SegmentData::KawariIpc {
data: CustomIpcSegment {
op_code: CustomIpcType::RequestCharacterListRepsonse,
data: CustomIpcData::RequestCharacterListRepsonse {
characters
},
..Default::default()
},
},
..Default::default()
}],
)
.await;
}
}
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 {
segment_type: SegmentType::KawariIpc,
data: SegmentData::KawariIpc {
data: CustomIpcSegment {
op_code: CustomIpcType::CharacterDeleted,
data: CustomIpcData::CharacterDeleted {
deleted: 1,
},
..Default::default()
},
},
..Default::default()
}],
)
.await;
}
}
CustomIpcData::ImportCharacter { service_account_id, path } => {
database.import_character(*service_account_id, path);
}
CustomIpcData::RemakeCharacter { content_id, chara_make_json } => {
// overwrite it in the database
database.set_chara_make(*content_id, chara_make_json);
// reset flag
database.set_remake_mode(*content_id, RemakeMode::None);
// send response
{
send_packet::<CustomIpcSegment>(
&mut connection.socket,
&mut connection.state,
ConnectionType::None,
CompressionType::Uncompressed,
&[PacketSegment {
segment_type: SegmentType::KawariIpc,
data: SegmentData::KawariIpc {
data: CustomIpcSegment {
op_code: CustomIpcType::CharacterRemade,
data: CustomIpcData::CharacterRemade {
content_id: *content_id,
},
..Default::default()
},
},
..Default::default()
}],
)
.await;
}
}
_ => {
panic!("The server is recieving a response or unknown custom IPC!")
}
}
}
_ => { _ => {
panic!("The server is recieving a response or unknown packet!") panic!("The server is recieving a response or unknown packet!")
} }

View file

@ -0,0 +1,237 @@
use crate::{
common::{
determine_initial_starting_zone,
workdefinitions::{CharaMake, RemakeMode},
},
config::get_config,
inventory::Inventory,
ipc::kawari::{CustomIpcData, CustomIpcSegment, CustomIpcType},
packet::{
CompressionType, ConnectionType, PacketSegment, SegmentData, SegmentType, send_packet,
},
};
use super::ZoneConnection;
pub async fn handle_custom_ipc(connection: &mut ZoneConnection, data: &CustomIpcSegment) {
match &data.data {
CustomIpcData::RequestCreateCharacter {
service_account_id,
name,
chara_make_json,
} => {
tracing::info!("creating character from: {name} {chara_make_json}");
let chara_make = CharaMake::from_json(chara_make_json);
let city_state;
{
let mut game_data = connection.gamedata.lock().unwrap();
city_state = game_data.get_citystate(chara_make.classjob_id as u16);
}
let mut inventory = Inventory::default();
{
let mut game_data = connection.gamedata.lock().unwrap();
// fill inventory
inventory.equip_racial_items(
chara_make.customize.race,
chara_make.customize.gender,
&mut game_data,
);
}
let (content_id, actor_id) = connection.database.create_player_data(
*service_account_id,
name,
chara_make_json,
city_state,
determine_initial_starting_zone(city_state),
inventory,
);
tracing::info!("Created new player: {content_id} {actor_id}");
// send them the new actor and content id
{
connection
.send_segment(PacketSegment {
segment_type: SegmentType::KawariIpc,
data: SegmentData::KawariIpc {
data: CustomIpcSegment {
op_code: CustomIpcType::CharacterCreated,
data: CustomIpcData::CharacterCreated {
actor_id,
content_id,
},
..Default::default()
},
},
..Default::default()
})
.await;
}
}
CustomIpcData::GetActorId { content_id } => {
let actor_id = connection.database.find_actor_id(*content_id);
tracing::info!("We found an actor id: {actor_id}");
// send them the actor id
{
connection
.send_segment(PacketSegment {
segment_type: SegmentType::KawariIpc,
data: SegmentData::KawariIpc {
data: CustomIpcSegment {
op_code: CustomIpcType::ActorIdFound,
data: CustomIpcData::ActorIdFound { actor_id },
..Default::default()
},
},
..Default::default()
})
.await;
}
}
CustomIpcData::CheckNameIsAvailable { name } => {
let is_name_free = connection.database.check_is_name_free(name);
// send response
{
connection
.send_segment(PacketSegment {
segment_type: SegmentType::KawariIpc,
data: SegmentData::KawariIpc {
data: CustomIpcSegment {
op_code: CustomIpcType::NameIsAvailableResponse,
data: CustomIpcData::NameIsAvailableResponse { free: is_name_free },
..Default::default()
},
},
..Default::default()
})
.await;
}
}
CustomIpcData::RequestCharacterList { service_account_id } => {
let config = get_config();
let world_name;
{
let mut game_data = connection.gamedata.lock().unwrap();
world_name = game_data.get_world_name(config.world.world_id);
}
let characters;
{
let mut game_data = connection.gamedata.lock().unwrap();
characters = connection.database.get_character_list(
*service_account_id,
config.world.world_id,
&world_name,
&mut game_data,
);
}
// send response
{
send_packet::<CustomIpcSegment>(
&mut connection.socket,
&mut connection.state,
ConnectionType::None,
CompressionType::Uncompressed,
&[PacketSegment {
segment_type: SegmentType::KawariIpc,
data: SegmentData::KawariIpc {
data: CustomIpcSegment {
op_code: CustomIpcType::RequestCharacterListRepsonse,
data: CustomIpcData::RequestCharacterListRepsonse { characters },
..Default::default()
},
},
..Default::default()
}],
)
.await;
}
}
CustomIpcData::DeleteCharacter { content_id } => {
connection.database.delete_character(*content_id);
// send response
{
send_packet::<CustomIpcSegment>(
&mut connection.socket,
&mut connection.state,
ConnectionType::None,
CompressionType::Uncompressed,
&[PacketSegment {
segment_type: SegmentType::KawariIpc,
data: SegmentData::KawariIpc {
data: CustomIpcSegment {
op_code: CustomIpcType::CharacterDeleted,
data: CustomIpcData::CharacterDeleted { deleted: 1 },
..Default::default()
},
},
..Default::default()
}],
)
.await;
}
}
CustomIpcData::ImportCharacter {
service_account_id,
path,
} => {
connection
.database
.import_character(*service_account_id, path);
}
CustomIpcData::RemakeCharacter {
content_id,
chara_make_json,
} => {
// overwrite it in the database
connection
.database
.set_chara_make(*content_id, chara_make_json);
// reset flag
connection
.database
.set_remake_mode(*content_id, RemakeMode::None);
// send response
{
send_packet::<CustomIpcSegment>(
&mut connection.socket,
&mut connection.state,
ConnectionType::None,
CompressionType::Uncompressed,
&[PacketSegment {
segment_type: SegmentType::KawariIpc,
data: SegmentData::KawariIpc {
data: CustomIpcSegment {
op_code: CustomIpcType::CharacterRemade,
data: CustomIpcData::CharacterRemade {
content_id: *content_id,
},
..Default::default()
},
},
..Default::default()
}],
)
.await;
}
}
_ => {
panic!("The server is recieving a response or unknown custom IPC!")
}
}
}

View file

@ -26,3 +26,6 @@ pub use status_effects::StatusEffects;
mod server; mod server;
pub use server::server_main_loop; pub use server::server_main_loop;
mod custom_ipc_handler;
pub use custom_ipc_handler::handle_custom_ipc;