From f10cac3794b5a60513cf88cdc7ab60b1bb581d1ae656f2332f4cc5b5003b88a9 Mon Sep 17 00:00:00 2001 From: raven <7156279+RavenX8@users.noreply.github.com> Date: Wed, 23 Jul 2025 13:52:50 -0400 Subject: [PATCH] Did some code clean-up Added TODOs for some changes that need to be made --- packet-service/src/handlers/auth.rs | 3 - packet-service/src/handlers/character.rs | 14 ++++- packet-service/src/handlers/world.rs | 29 +++++++++- world-service/src/world_service.rs | 73 +++++++++++++++++++----- 4 files changed, 99 insertions(+), 20 deletions(-) diff --git a/packet-service/src/handlers/auth.rs b/packet-service/src/handlers/auth.rs index 75776dd..2672ea6 100644 --- a/packet-service/src/handlers/auth.rs +++ b/packet-service/src/handlers/auth.rs @@ -193,9 +193,6 @@ pub(crate) async fn handle_login_req( if let Some(mut state) = connection_service.get_connection_mut(&connection_id) { let writer_clone = state.writer.clone().unwrap(); create_chat_client_handler(writer_clone, chat_handler.clone()).await?; - } - - if let Some(mut state) = connection_service.get_connection_mut(&connection_id) { state.chat_handler = Some(chat_handler); } diff --git a/packet-service/src/handlers/character.rs b/packet-service/src/handlers/character.rs index 9155dbc..e635404 100644 --- a/packet-service/src/handlers/character.rs +++ b/packet-service/src/handlers/character.rs @@ -264,6 +264,14 @@ pub(crate) async fn handle_select_char_req( state.character_id = Some(request.char_id as i8); } + //TODO: All of the following packet code needs to be moved to their own functions + // We instead want to make our world service connection then request a player connection event + // from the world service to the game logic service. Then we have the game logic service send + // the appropriate events back and should cause the packet service to send the appropriate packets. + + + //TODO: Switch server packet is used to accept the client into the server and should be sent after + // the world service connection is established and confirm the client is in the correct map. let data = SrvSwitchServer { port: 0, session_id: 0, @@ -277,6 +285,9 @@ pub(crate) async fn handle_select_char_req( send_packet(&mut locked_stream, &response_packet).await?; } + + //TODO: Get the character data from the character service should be moved to the game logic service + // as it needs to be sent to all the other nearby clients as well. 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] as u8) @@ -429,7 +440,8 @@ pub(crate) async fn handle_select_char_req( send_packet(&mut locked_stream, &response_packet).await?; } - // Send the billing message (we don't use this, so we just send the defaults to allow) + // Send the billing message (we don't actually use this, so we just send the defaults to allow) + // This tells the client to actually switch from character select to the game world let data = SrvBillingMessage { function_type: 0x1001, pay_flag: 2, diff --git a/packet-service/src/handlers/world.rs b/packet-service/src/handlers/world.rs index 3bdb12c..9eaacd5 100644 --- a/packet-service/src/handlers/world.rs +++ b/packet-service/src/handlers/world.rs @@ -282,11 +282,38 @@ async fn handle_world_events( Some(crate::world_client::world::world_event::Event::NpcSpawn(npc_spawn)) => { debug!("Processing NPC spawn event: {:?}", npc_spawn); // Convert to the appropriate game packet and send to client - // This would involve creating a spawn packet and sending it through the connection's writer + let npc = WorldObject { + id: npc_spawn.id, + object_type: 2, + x: npc_spawn.pos_x, + y: npc_spawn.pos_y, + z: 0.0, + map_id: 0, + name: "NPC".to_string(), + hp: npc_spawn.hp, + max_hp: npc_spawn.hp, + }; + // if let Err(e) = spawn_npc(&npc, connection_service.clone(), session_id.clone()).await { + // error!("Failed to spawn npc for session {}: {}", session_id, e); + // } } Some(crate::world_client::world::world_event::Event::MobSpawn(mob_spawn)) => { debug!("Processing mob spawn event: {:?}", mob_spawn); // Convert to the appropriate game packet and send to client + let mob = WorldObject { + id: mob_spawn.id, + object_type: 3, + x: mob_spawn.pos_x, + y: mob_spawn.pos_y, + z: 0.0, + map_id: 0, + name: "Mob".to_string(), + hp: mob_spawn.hp, + max_hp: mob_spawn.hp, + }; + if let Err(e) = spawn_mob(&mob, connection_service.clone(), session_id.clone()).await { + error!("Failed to spawn mob for session {}: {}", session_id, e); + } } Some(crate::world_client::world::world_event::Event::ObjectDespawn(despawn)) => { debug!("Processing object despawn event: {:?}", despawn); diff --git a/world-service/src/world_service.rs b/world-service/src/world_service.rs index b749dd8..af409eb 100644 --- a/world-service/src/world_service.rs +++ b/world-service/src/world_service.rs @@ -113,16 +113,6 @@ impl MyWorldService { } } - pub fn get_nearby_objects_for_client(&self, session_id: &str, x: f32, y: f32, z: f32, map_id: i32, radius: f32) -> Vec { - // This is a placeholder implementation - // In a real implementation, you would query the game logic service or maintain a spatial index - debug!("Getting nearby objects for client {} at ({}, {}, {}) in map {} with radius {}", - session_id, x, y, z, map_id, radius); - - // Return empty list for now - this will be populated by game logic service - vec![] - } - /// Send nearby objects to a connecting client pub async fn send_nearby_objects_to_client(&self, session_id: &str, client_id: &str, x: f32, y: f32, z: f32, map_id: i32) { debug!("Sending nearby objects to client {} at ({}, {}, {}) in map {}", client_id, x, y, z, map_id); @@ -170,7 +160,7 @@ impl MyWorldService { x: obj.x, y: obj.y, z: obj.z, - map_id: map_id, + map_id, name: format!("Object_{}", obj.id), // Default name hp: obj.hp, // Default HP max_hp: obj.max_hp, // Default max HP @@ -212,7 +202,8 @@ impl MyWorldService { /// Convert a game logic object to a WorldEvent based on its type fn convert_game_logic_object_to_world_event(&self, obj: &client_game_logic::Object, client_id: &str) -> Option { - // Object types: 1 = Player, 2 = NPC, 3 = Mob (based on common MMORPG conventions) + // Object types: 1 = Player, 2 = NPC, 3 = Mob + //TODO: switch these magic numbers with the actual type names defined like how we did it in the chat service match obj.r#type { 2 => { // NPC @@ -339,7 +330,56 @@ impl WorldService for MyWorldService { let req = request.into_inner(); debug!("GetNearbyObjects request: {:?}", req); - let objects = self.get_nearby_objects_for_client(&req.session_id, req.x, req.y, req.z, req.map_id, req.radius); + let mut objects = vec![]; + if let Some(game_logic_manager) = &self.game_logic_manager { + match game_logic_manager.get_nearby_objects(req.map_id as u32, &req.session_id, req.x, req.y, req.z).await { + Ok(response) => { + debug!("Received {} nearby objects from game logic service", response.objects.len()); + + if !response.objects.is_empty() { + // Convert game logic objects to WorldObjects for batch sending + let world_objects: Vec = response.objects + .into_iter() + .filter_map(|obj| { + // Filter out players for now, only include NPCs and Mobs + //TODO: switch these magic numbers with the actual type names defined like how we did it in the chat service + match obj.r#type { + 1 => { + // Player - skip for now + debug!("Skipping player object {} for nearby objects", obj.id); + None + } + 2 | 3 => { + // NPC or Mob - include in batch + Some(WorldObject { + id: obj.id as u32, + object_type: obj.r#type, + x: obj.x, + y: obj.y, + z: obj.z, + map_id: req.map_id, + name: format!("Object_{}", obj.id), // Default name + hp: obj.hp, // Default HP + max_hp: obj.max_hp, // Default max HP + }) + } + _ => { + debug!("Unknown object type {} for object {}", obj.r#type, obj.id); + None + } + } + }) + .collect(); + objects = world_objects; + } + } + Err(e) => { + warn!("Failed to get nearby objects from game logic service for client {}: {}", req.session_id, e); + } + } + } else { + debug!("No game logic manager available, skipping nearby objects"); + } let response = NearbyObjectsResponse { objects, @@ -556,8 +596,10 @@ impl WorldGameLogicService for MyWorldGameLogicService { event: Some(world_event::Event::NpcSpawn(npc_spawn)), }; // Broadcast to clients - for now broadcast to all clients in the map - // In a real implementation, you'd determine the map from the event // world_service.broadcast_to_clients_in_map(game_event.map_id, world_event); + //TODO: call the spawn npc function as this is a single spawn + // this might not ever get called as we spawn all NPCs at the start + // Could be useful if we allow quests or scripted NPC spawning in the future } Some(world::game_logic_event::Event::MobSpawn(mob_spawn)) => { let _world_event = WorldEvent { @@ -565,13 +607,14 @@ impl WorldGameLogicService for MyWorldGameLogicService { event: Some(world_event::Event::MobSpawn(mob_spawn)), }; // Broadcast to clients + //TODO: call the spawn mob function as this is a single spawn } Some(world::game_logic_event::Event::ObjectDespawn(despawn)) => { let _world_event = WorldEvent { client_ids: game_event.client_ids.clone(), event: Some(world_event::Event::ObjectDespawn(despawn)), }; - // Broadcast to clients + //TODO: Just tell everyone that the object is gone } _ => { debug!("Unhandled game logic event type");