1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-06-21 07:27:45 +00:00

Make !spawnmonster put the NPC at your location again

Also included some refactoring that will help networking these better.
This commit is contained in:
Joshua Goins 2025-06-18 20:28:03 -04:00
parent 1b6fdab000
commit 3757f4e0db
6 changed files with 83 additions and 27 deletions

View file

@ -104,7 +104,9 @@ async fn main() {
serde_json::from_str(&body).ok(); serde_json::from_str(&body).ok();
if let Some(service_accounts) = service_accounts { if let Some(service_accounts) = service_accounts {
if service_accounts.is_empty() { if service_accounts.is_empty() {
tracing::warn!("This account has no service accounts attached, how did this happen?"); tracing::warn!(
"This account has no service accounts attached, how did this happen?"
);
// request an update, wrong error message lol // request an update, wrong error message lol
connection.send_error(*sequence, 1012, 13101).await; connection.send_error(*sequence, 1012, 13101).await;
@ -114,7 +116,9 @@ async fn main() {
connection.send_account_list().await; connection.send_account_list().await;
} }
} else { } else {
tracing::warn!("Failed to parse service accounts from the login server!"); tracing::warn!(
"Failed to parse service accounts from the login server!"
);
// request an update, wrong error message lol // request an update, wrong error message lol
connection.send_error(*sequence, 1012, 13101).await; connection.send_error(*sequence, 1012, 13101).await;

View file

@ -896,7 +896,7 @@ async fn client_loop(
msg = internal_recv.recv() => match msg { msg = internal_recv.recv() => match msg {
Some(msg) => match msg { Some(msg) => match msg {
FromServer::Message(msg) => connection.send_message(&msg).await, FromServer::Message(msg) => connection.send_message(&msg).await,
FromServer::ActorSpawn(actor, common) => connection.spawn_actor(actor, common).await, FromServer::ActorSpawn(actor, spawn) => connection.spawn_actor(actor, spawn).await,
FromServer::ActorMove(actor_id, position, rotation) => connection.set_actor_position(actor_id, position, rotation).await, FromServer::ActorMove(actor_id, position, rotation) => connection.set_actor_position(actor_id, position, rotation).await,
FromServer::ActorDespawn(actor_id) => connection.remove_actor(actor_id).await, FromServer::ActorDespawn(actor_id) => connection.remove_actor(actor_id).await,
FromServer::ActorControl(actor_id, actor_control) => connection.actor_control(actor_id, actor_control).await, FromServer::ActorControl(actor_id, actor_control) => connection.actor_control(actor_id, actor_control).await,

View file

@ -106,7 +106,10 @@ impl ChatHandler {
"!spawnmonster" => { "!spawnmonster" => {
connection connection
.handle .handle
.send(ToServer::DebugNewNpc(connection.id)) .send(ToServer::DebugNewNpc(
connection.id,
connection.player_data.actor_id,
))
.await; .await;
} }
"!playscene" => { "!playscene" => {

View file

@ -24,7 +24,7 @@ pub enum FromServer {
/// A chat message. /// A chat message.
Message(String), Message(String),
/// An actor has been spawned. /// An actor has been spawned.
ActorSpawn(Actor, CommonSpawn), ActorSpawn(Actor, NpcSpawn),
/// An actor moved to a new position. /// An actor moved to a new position.
ActorMove(u32, Position, f32), ActorMove(u32, Position, f32),
// An actor has despawned. // An actor has despawned.
@ -88,7 +88,7 @@ pub enum ToServer {
Disconnected(ClientId), Disconnected(ClientId),
/// A fatal error occured. /// A fatal error occured.
FatalError(std::io::Error), FatalError(std::io::Error),
DebugNewNpc(ClientId), DebugNewNpc(ClientId, u32),
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]

View file

@ -214,20 +214,17 @@ impl ZoneConnection {
.await; .await;
} }
pub async fn spawn_actor(&mut self, mut actor: Actor, mut common: CommonSpawn) { pub async fn spawn_actor(&mut self, mut actor: Actor, mut spawn: NpcSpawn) {
// There is no reason for us to spawn our own player again. It's probably a bug!' // There is no reason for us to spawn our own player again. It's probably a bug!'
assert!(actor.id.0 != self.player_data.actor_id); assert!(actor.id.0 != self.player_data.actor_id);
actor.spawn_index = self.get_free_spawn_index() as u32; actor.spawn_index = self.get_free_spawn_index() as u32;
common.spawn_index = actor.spawn_index as u8; spawn.common.spawn_index = actor.spawn_index as u8;
let ipc = ServerZoneIpcSegment { let ipc = ServerZoneIpcSegment {
op_code: ServerZoneIpcType::NpcSpawn, op_code: ServerZoneIpcType::NpcSpawn,
timestamp: timestamp_secs(), timestamp: timestamp_secs(),
data: ServerZoneIpcData::NpcSpawn(NpcSpawn { data: ServerZoneIpcData::NpcSpawn(spawn),
common,
..Default::default()
}),
..Default::default() ..Default::default()
}; };

View file

@ -2,7 +2,7 @@ use std::collections::HashMap;
use tokio::sync::mpsc::Receiver; use tokio::sync::mpsc::Receiver;
use crate::{ use crate::{
common::{ObjectId, Position}, common::ObjectId,
ipc::zone::{ ipc::zone::{
ActorControl, ActorControlCategory, ActorControlSelf, ActorControlTarget, BattleNpcSubKind, ActorControl, ActorControlCategory, ActorControlSelf, ActorControlTarget, BattleNpcSubKind,
ClientTriggerCommand, CommonSpawn, NpcSpawn, ObjectKind, ClientTriggerCommand, CommonSpawn, NpcSpawn, ObjectKind,
@ -11,10 +11,26 @@ use crate::{
use super::{Actor, ClientHandle, ClientId, FromServer, ToServer}; use super::{Actor, ClientHandle, ClientId, FromServer, ToServer};
#[derive(Debug, Clone)]
enum NetworkedActor {
Player(NpcSpawn),
NPC(NpcSpawn),
}
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
struct Instance { struct Instance {
// structure temporary, of course // structure temporary, of course
actors: HashMap<ObjectId, CommonSpawn>, actors: HashMap<ObjectId, NetworkedActor>,
}
impl Instance {
fn find_actor(&self, id: ObjectId) -> Option<&NetworkedActor> {
self.actors.get(&id)
}
fn insert_npc(&mut self, id: ObjectId, spawn: NpcSpawn) {
self.actors.insert(id, NetworkedActor::NPC(spawn));
}
} }
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
@ -81,14 +97,20 @@ pub async fn server_main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::i
state.zone_id = zone_id; state.zone_id = zone_id;
// send existing player data // send existing player data
for (id, common) in &instance.actors { for (id, spawn) in &instance.actors {
let npc_spawn = match spawn {
NetworkedActor::Player(npc_spawn) => npc_spawn,
NetworkedActor::NPC(npc_spawn) => npc_spawn,
};
// Note that we currently only support spawning via the NPC packet, hence why we don't need to differentiate here
let msg = FromServer::ActorSpawn( let msg = FromServer::ActorSpawn(
Actor { Actor {
id: *id, id: *id,
hp: 100, hp: 100,
spawn_index: 0, spawn_index: 0,
}, },
common.clone(), npc_spawn.clone(),
); );
handle.send(msg).unwrap(); handle.send(msg).unwrap();
@ -104,9 +126,13 @@ pub async fn server_main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::i
// add the connection's actor to the table // add the connection's actor to the table
{ {
let instance = data.find_instance_mut(zone_id); let instance = data.find_instance_mut(zone_id);
instance instance.actors.insert(
.actors ObjectId(client.actor_id),
.insert(ObjectId(client.actor_id), client.common.clone()); NetworkedActor::Player(NpcSpawn {
common: client.common.clone(),
..Default::default()
}),
);
} }
// Then tell any clients in the zone that we spawned // Then tell any clients in the zone that we spawned
@ -129,7 +155,10 @@ pub async fn server_main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::i
hp: 0, hp: 0,
spawn_index: 0, spawn_index: 0,
}, },
client.common.clone(), NpcSpawn {
common: client.common.clone(),
..Default::default()
},
); );
if handle.send(msg).is_err() { if handle.send(msg).is_err() {
@ -180,11 +209,15 @@ pub async fn server_main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::i
} }
ToServer::ActorMoved(from_id, actor_id, position, rotation) => { ToServer::ActorMoved(from_id, actor_id, position, rotation) => {
if let Some(instance) = data.find_actor_instance_mut(actor_id) { if let Some(instance) = data.find_actor_instance_mut(actor_id) {
if let Some((_, common)) = instance if let Some((_, spawn)) = instance
.actors .actors
.iter_mut() .iter_mut()
.find(|actor| *actor.0 == ObjectId(actor_id)) .find(|actor| *actor.0 == ObjectId(actor_id))
{ {
let common = match spawn {
NetworkedActor::Player(npc_spawn) => &mut npc_spawn.common,
NetworkedActor::NPC(npc_spawn) => &mut npc_spawn.common,
};
common.pos = position; common.pos = position;
common.rotation = rotation; common.rotation = rotation;
} }
@ -279,11 +312,22 @@ pub async fn server_main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::i
} }
} }
} }
ToServer::DebugNewNpc(_from_id) => { ToServer::DebugNewNpc(_from_id, from_actor_id) => {
for (id, (handle, _)) in &mut data.clients { let spawn;
let id = *id; {
let Some(instance) = data.find_actor_instance_mut(from_actor_id) else {
break;
};
let msg = FromServer::SpawnNPC(NpcSpawn { let Some(actor) = instance.find_actor(ObjectId(from_actor_id)) else {
break;
};
let NetworkedActor::Player(player) = actor else {
break;
};
spawn = NpcSpawn {
aggression_mode: 1, aggression_mode: 1,
common: CommonSpawn { common: CommonSpawn {
hp_curr: 91, hp_curr: 91,
@ -297,11 +341,19 @@ pub async fn server_main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::i
level: 1, level: 1,
battalion: 4, battalion: 4,
model_chara: 297, model_chara: 297,
pos: Position::default(), pos: player.common.pos,
..Default::default() ..Default::default()
}, },
..Default::default() ..Default::default()
}); };
instance.insert_npc(ObjectId(1), spawn.clone());
}
for (id, (handle, _)) in &mut data.clients {
let id = *id;
let msg = FromServer::SpawnNPC(spawn.clone());
if handle.send(msg).is_err() { if handle.send(msg).is_err() {
to_remove.push(id); to_remove.push(id);