From b5e16f0bef6258c48f2c1a24b6d2999f0752549dfd62164762fd5bec21ad47c8 Mon Sep 17 00:00:00 2001 From: RavenX8 <7156279+RavenX8@users.noreply.github.com> Date: Tue, 28 Jan 2025 22:48:11 -0500 Subject: [PATCH] - add: mouse cmd packet handling - add: change map handler - update: logout handler to send the reply packet - update: character id list change from u8 to u32 --- packet-service/Cargo.toml | 1 + packet-service/src/connection_state.rs | 2 +- packet-service/src/handlers/auth.rs | 27 +++++--- packet-service/src/handlers/character.rs | 12 ++-- packet-service/src/handlers/mod.rs | 1 + packet-service/src/handlers/world.rs | 88 ++++++++++++++++++++++++ packet-service/src/router.rs | 18 +++-- 7 files changed, 124 insertions(+), 25 deletions(-) create mode 100644 packet-service/src/handlers/world.rs diff --git a/packet-service/Cargo.toml b/packet-service/Cargo.toml index c343390..421c545 100644 --- a/packet-service/Cargo.toml +++ b/packet-service/Cargo.toml @@ -25,6 +25,7 @@ utils = { path = "../utils" } warp = "0.3.7" dashmap = "6.1.0" uuid = { version = "1.11.0", features = ["v4"] } +chrono = "0.4.39" [build-dependencies] tonic-build = "0.12.3" diff --git a/packet-service/src/connection_state.rs b/packet-service/src/connection_state.rs index aea281f..0a70494 100644 --- a/packet-service/src/connection_state.rs +++ b/packet-service/src/connection_state.rs @@ -5,7 +5,7 @@ pub struct ConnectionState { pub user_id: Option, pub session_id: Option, pub character_id: Option, - pub character_list: Option>, + pub character_list: Option>, pub additional_data: HashMap, // Flexible data storage } diff --git a/packet-service/src/handlers/auth.rs b/packet-service/src/handlers/auth.rs index 7656524..219f451 100644 --- a/packet-service/src/handlers/auth.rs +++ b/packet-service/src/handlers/auth.rs @@ -1,15 +1,18 @@ use crate::auth_client::AuthClient; -use utils::null_string::NullTerminatedString; +use crate::connection_service::ConnectionService; use crate::packet::{send_packet, Packet, PacketPayload}; use crate::packet_type::PacketType; use crate::packets::cli_accept_req::CliAcceptReq; use crate::packets::cli_channel_list_req::CliChannelListReq; use crate::packets::cli_join_server_token_req::CliJoinServerTokenReq; use crate::packets::cli_login_token_req::CliLoginTokenReq; +use crate::packets::cli_logout_req::CliLogoutReq; use crate::packets::cli_srv_select_req::CliSrvSelectReq; use crate::packets::srv_accept_reply::SrvAcceptReply; use crate::packets::srv_channel_list_reply::{ChannelInfo, SrvChannelListReply}; +use crate::packets::srv_join_server_reply::SrvJoinServerReply; use crate::packets::srv_login_reply::{ServerInfo, SrvLoginReply}; +use crate::packets::srv_logout_reply::SrvLogoutReply; use crate::packets::srv_srv_select_reply::SrvSrvSelectReply; use crate::packets::*; use std::collections::HashMap; @@ -17,15 +20,13 @@ use std::env; use std::error::Error; use std::net::SocketAddr; use std::sync::Arc; +use tokio::io::AsyncWriteExt; use tokio::net::TcpStream; use tokio::sync::Mutex; use tonic::{Code, Status}; use tracing::{debug, error, info, warn}; +use utils::null_string::NullTerminatedString; use utils::service_discovery; -use crate::connection_service::ConnectionService; -use crate::packets::cli_logout_req::CliLogoutReq; -use crate::packets::srv_join_server_reply::SrvJoinServerReply; - pub(crate) async fn handle_alive_req(stream: &mut TcpStream, packet: Packet, auth_client: Arc>, connection_service: Arc, connection_id: String) -> Result<(), Box> { if let Some(mut state) = connection_service.get_connection(&connection_id) { @@ -61,13 +62,13 @@ pub(crate) async fn handle_join_server_req(stream: &mut TcpStream, packet: Packe let session = auth_client.validate_session(&session_id).await?; if (!session.valid) { warn!("Invalid session ID: {}", session_id); - + let data = SrvJoinServerReply { result: srv_join_server_reply::Result::Failed, id: 0, pay_flag: 0 }; let response_packet = Packet::new(PacketType::PakscJoinServerReply, &data)?; send_packet(stream, &response_packet).await?; return Err("Session not valid".into()); } - + let data = SrvJoinServerReply { result: srv_join_server_reply::Result::Ok, id: 1, pay_flag: 0 }; let response_packet = Packet::new(PacketType::PakscJoinServerReply, &data)?; send_packet(stream, &response_packet).await?; @@ -78,11 +79,15 @@ pub(crate) async fn handle_join_server_req(stream: &mut TcpStream, packet: Packe } pub(crate) async fn handle_logout_req(stream: &mut TcpStream, packet: Packet, auth_client: Arc>, connection_service: Arc, connection_id: String) -> Result<(), Box> { - let request = CliLogoutReq::decode(packet.payload.as_slice()); if let Some(mut state) = connection_service.get_connection(&connection_id) { let session_id = state.session_id.clone().unwrap(); let mut auth_client = auth_client.lock().await; auth_client.logout(&session_id).await?; + + let data = SrvLogoutReply { wait_time: 1 }; + let response_packet = Packet::new(PacketType::PakwcLogoutReply, &data)?; + send_packet(stream, &response_packet).await?; + stream.shutdown().await?; Ok(()) } else { Err("Unable to find connection state".into()) @@ -134,7 +139,7 @@ pub(crate) async fn handle_login_req(stream: &mut TcpStream, packet: Packet, aut } else { name = format!(" {}", name); } - server_info.push(ServerInfo { test: u8::from(is_test), name: NullTerminatedString::new(&name), id}); + server_info.push(ServerInfo { test: u8::from(is_test), name: NullTerminatedString::new(&name), id }); id = id + 1; } debug!("Server info: {:?}", server_info); @@ -149,7 +154,7 @@ pub(crate) async fn handle_login_req(stream: &mut TcpStream, packet: Packet, aut match tonic_status.code() { Code::Unauthenticated => { info!("Login failed: Invalid credentials"); - + let data = SrvLoginReply { result: srv_login_reply::Result::UnknownAccount, right: 0, type_: 0, servers_info: Vec::new() }; let response_packet = Packet::new(PacketType::PaklcLoginReply, &data)?; send_packet(stream, &response_packet).await?; @@ -190,7 +195,7 @@ pub(crate) async fn handle_server_select_req(stream: &mut TcpStream, packet: Pac ip: NullTerminatedString::new(""), // If this is empty, the client should stay connected (requires client change) port: 0, // See comment about ip above }; - + let response_packet = Packet::new(PacketType::PaklcSrvSelectReply, &data)?; send_packet(stream, &response_packet).await?; Ok(()) diff --git a/packet-service/src/handlers/character.rs b/packet-service/src/handlers/character.rs index 7cff079..bb7f140 100644 --- a/packet-service/src/handlers/character.rs +++ b/packet-service/src/handlers/character.rs @@ -23,7 +23,7 @@ use tonic::{Code, Status}; use tracing::{debug, error, info, warn}; use utils::null_string::NullTerminatedString; -fn convert_slot(slot: i32) -> srv_char_list_reply::EquippedPosition { +pub(crate) fn convert_slot(slot: i32) -> srv_char_list_reply::EquippedPosition { match enums::EquippedPosition::from_i32(slot) { Some(enums::EquippedPosition::Goggles) => srv_char_list_reply::EquippedPosition::Googles, Some(enums::EquippedPosition::Helmet) => srv_char_list_reply::EquippedPosition::Helmet, @@ -53,12 +53,12 @@ pub(crate) async fn handle_char_list_req(stream: &mut TcpStream, packet: Packet, let mut character_client = character_client.lock().await; let character_list = character_client.get_character_list(&user_id.to_string()).await?; let mut characters = vec![]; - let mut character_id_list: Vec = Vec::new(); + let mut character_id_list: Vec = Vec::new(); for character in character_list.characters { let mut item_list: [EquippedItem; (MAX_VISIBLE_ITEMS as usize)] = core::array::from_fn(|i| EquippedItem::default()); for item in character.items { - if item.slot < 10 { + if item.slot < MAX_VISIBLE_ITEMS as i32 { let slot = convert_slot(item.slot) as usize; item_list[slot] = EquippedItem { id: item.item_id as u16, @@ -133,7 +133,7 @@ pub(crate) async fn handle_delete_char_req(stream: &mut TcpStream, packet: Packe let mut user_id = 0; let session_id; - let mut character_id_list: Vec = Vec::new(); + let mut character_id_list: Vec = Vec::new(); if let Some(mut state) = connection_service.get_connection(&connection_id) { user_id = state.user_id.expect("Missing user id in connection state"); @@ -165,7 +165,7 @@ pub(crate) async fn handle_select_char_req(stream: &mut TcpStream, packet: Packe debug!("{:?}", request); let mut user_id = 0; - let mut character_id_list: Vec = Vec::new(); + let mut character_id_list: Vec = Vec::new(); if let Some(mut state) = connection_service.get_connection_mut(&connection_id) { user_id = state.user_id.expect("Missing user id in connection state"); character_id_list = state.character_list.clone().expect("Missing character id list"); @@ -182,7 +182,7 @@ pub(crate) async fn handle_select_char_req(stream: &mut TcpStream, packet: Packe send_packet(stream, &response_packet).await?; let mut character_client = character_client.lock().await; - let character_data = character_client.get_character(&user_id.to_string(), character_id_list[request.char_id as usize]).await?; + let character_data = character_client.get_character(&user_id.to_string(), character_id_list[request.char_id as usize] as u8).await?; let character = character_data.character.unwrap_or_default(); diff --git a/packet-service/src/handlers/mod.rs b/packet-service/src/handlers/mod.rs index 01adb9b..fb98300 100644 --- a/packet-service/src/handlers/mod.rs +++ b/packet-service/src/handlers/mod.rs @@ -1,2 +1,3 @@ pub mod auth; pub mod character; +pub mod world; diff --git a/packet-service/src/handlers/world.rs b/packet-service/src/handlers/world.rs new file mode 100644 index 0000000..0227678 --- /dev/null +++ b/packet-service/src/handlers/world.rs @@ -0,0 +1,88 @@ +use crate::character_client::CharacterClient; +use crate::connection_service::ConnectionService; +use crate::packet::{send_packet, Packet, PacketPayload}; +use crate::packet_type::PacketType; +use chrono::{Local, Timelike}; +use std::error::Error; +use std::sync::Arc; +use tokio::net::TcpStream; +use tokio::sync::Mutex; +use tracing::debug; + +fn distance(x1: f64, y1: f64, x2: f64, y2: f64) -> u16 { + let dist = ((x2 - x1).powi(2) + (y2 - y1).powi(2)).sqrt(); + dist.round() as u16 +} + +pub(crate) async fn handle_change_map_req(stream: &mut TcpStream, packet: Packet, character_client: Arc>, connection_service: Arc, connection_id: String) -> Result<(), Box> { + use crate::packets::cli_change_map_req::*; + use crate::packets::srv_change_map_reply::*; + let request = CliChangeMapReq::decode(packet.payload.as_slice())?; + debug!("{:?}", request); + + let mut user_id = 0; + let mut char_id = 0; + let mut character_id_list: Vec = Vec::new(); + let session_id; + if let Some(mut state) = connection_service.get_connection(&connection_id) { + user_id = state.user_id.expect("Missing user id in connection state"); + session_id = state.session_id.expect("Missing session id in connection state"); + char_id = state.character_id.expect("Missing character id in connection state"); + character_id_list = state.character_list.clone().expect("Missing character id list"); + } + + let mut character_client = character_client.lock().await; + let character_data = character_client.get_character(&user_id.to_string(), character_id_list[char_id as usize] as u8).await?; + + let character = character_data.character.unwrap_or_default(); + let stats = character.stats.unwrap(); + + let now = Local::now(); + let time_as_u16 = (now.hour() * 100 + now.minute()) as u16; + + let data = SrvChangeMapReply { + object_index: character_id_list[char_id as usize] as u16, + hp: stats.hp as u16, + mp: stats.mp as u16, + xp: stats.xp as u16, + penalize_xp: stats.penalty_xp as u16, + craft_rate: 0, + update_time: 0, + world_rate: 1, + town_rate: 1, + item_rate: [0u8; 11], + flags: 1, + world_time: time_as_u16, + team_number: 10, + }; + let response_packet = Packet::new(PacketType::PakwcChangeMapReply, &data)?; + send_packet(stream, &response_packet).await?; + + Ok(()) +} + +pub(crate) async fn handle_mouse_cmd_req(stream: &mut TcpStream, packet: Packet, connection_service: Arc, connection_id: String) -> Result<(), Box> { + use crate::packets::cli_mouse_cmd::*; + use crate::packets::srv_mouse_cmd::*; + let request = CliMouseCmd::decode(packet.payload.as_slice())?; + debug!("{:?}", request); + + let mut char_id = 0; + let mut character_id_list: Vec = Vec::new(); + if let Some(mut state) = connection_service.get_connection(&connection_id) { + char_id = state.character_id.expect("Missing character id in connection state"); + character_id_list = state.character_list.clone().expect("Missing character id list"); + } + + let data = SrvMouseCmd { + id: character_id_list[char_id as usize] as u16, + target_id: request.target_id, + distance: distance(520000 as f64, 520000 as f64, request.x as f64, request.y as f64), + x: request.x, + y: request.y, + z: request.z, + }; + let response_packet = Packet::new(PacketType::PakwcMouseCmd, &data)?; + send_packet(stream, &response_packet).await?; + Ok(()) +} \ No newline at end of file diff --git a/packet-service/src/router.rs b/packet-service/src/router.rs index a12d704..cbedba2 100644 --- a/packet-service/src/router.rs +++ b/packet-service/src/router.rs @@ -1,5 +1,9 @@ use crate::auth_client::AuthClient; +use crate::bufferpool::BufferPool; +use crate::character_client::CharacterClient; +use crate::connection_service::ConnectionService; use crate::handlers::*; +use crate::metrics::{ACTIVE_CONNECTIONS, PACKETS_RECEIVED}; use crate::packet::Packet; use crate::packet_type::PacketType; use std::error::Error; @@ -8,10 +12,6 @@ use tokio::io::AsyncReadExt; use tokio::net::TcpStream; use tokio::sync::Mutex; use tracing::{debug, warn}; -use crate::bufferpool::BufferPool; -use crate::character_client::CharacterClient; -use crate::connection_service::ConnectionService; -use crate::metrics::{ACTIVE_CONNECTIONS, PACKETS_RECEIVED}; #[derive(Clone, Debug)] pub struct PacketRouter { @@ -32,7 +32,7 @@ impl PacketRouter { } let packet_size = u16::from_le_bytes(buffer[0..2].try_into()?) as usize; if packet_size > 6 { - let mut body_handle = stream.take((packet_size-6) as u64); + let mut body_handle = stream.take((packet_size - 6) as u64); let n = body_handle.read(&mut buffer[6..]).await?; if n == 0 { break; // Connection closed @@ -66,7 +66,7 @@ impl PacketRouter { ACTIVE_CONNECTIONS.dec(); Ok(()) } - + pub async fn route_packet(&self, stream: &mut TcpStream, packet: Packet, connection_id: String) -> Result<(), Box> { debug!("Routing packet: {:?}", packet); match packet.packet_type { @@ -86,12 +86,16 @@ impl PacketRouter { PacketType::PakcsDeleteCharReq => character::handle_delete_char_req(stream, packet, self.character_client.clone(), self.connection_service.clone(), connection_id).await, PacketType::PakcsSelectCharReq => character::handle_select_char_req(stream, packet, self.character_client.clone(), self.connection_service.clone(), connection_id).await, + // World Packets + PacketType::PakcsChangeMapReq => world::handle_change_map_req(stream, packet, self.character_client.clone(), self.connection_service.clone(), connection_id).await, + PacketType::PakcsMouseCmd => world::handle_mouse_cmd_req(stream, packet, self.connection_service.clone(), connection_id).await, + // 1 => chat::handle_chat(packet).await?, // 2 => movement::handle_movement(packet).await?, _ => { warn!("Unhandled packet type: {:?}", packet.packet_type); Ok(()) - }, + } } } }