1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-06-20 23:17: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();
if let Some(service_accounts) = service_accounts {
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
connection.send_error(*sequence, 1012, 13101).await;
@ -114,7 +116,9 @@ async fn main() {
connection.send_account_list().await;
}
} 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
connection.send_error(*sequence, 1012, 13101).await;

View file

@ -896,7 +896,7 @@ async fn client_loop(
msg = internal_recv.recv() => match msg {
Some(msg) => match msg {
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::ActorDespawn(actor_id) => connection.remove_actor(actor_id).await,
FromServer::ActorControl(actor_id, actor_control) => connection.actor_control(actor_id, actor_control).await,

View file

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

View file

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

View file

@ -214,20 +214,17 @@ impl ZoneConnection {
.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!'
assert!(actor.id.0 != self.player_data.actor_id);
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 {
op_code: ServerZoneIpcType::NpcSpawn,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::NpcSpawn(NpcSpawn {
common,
..Default::default()
}),
data: ServerZoneIpcData::NpcSpawn(spawn),
..Default::default()
};

View file

@ -2,7 +2,7 @@ use std::collections::HashMap;
use tokio::sync::mpsc::Receiver;
use crate::{
common::{ObjectId, Position},
common::ObjectId,
ipc::zone::{
ActorControl, ActorControlCategory, ActorControlSelf, ActorControlTarget, BattleNpcSubKind,
ClientTriggerCommand, CommonSpawn, NpcSpawn, ObjectKind,
@ -11,10 +11,26 @@ use crate::{
use super::{Actor, ClientHandle, ClientId, FromServer, ToServer};
#[derive(Debug, Clone)]
enum NetworkedActor {
Player(NpcSpawn),
NPC(NpcSpawn),
}
#[derive(Default, Debug, Clone)]
struct Instance {
// 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)]
@ -81,14 +97,20 @@ pub async fn server_main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::i
state.zone_id = zone_id;
// 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(
Actor {
id: *id,
hp: 100,
spawn_index: 0,
},
common.clone(),
npc_spawn.clone(),
);
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
{
let instance = data.find_instance_mut(zone_id);
instance
.actors
.insert(ObjectId(client.actor_id), client.common.clone());
instance.actors.insert(
ObjectId(client.actor_id),
NetworkedActor::Player(NpcSpawn {
common: client.common.clone(),
..Default::default()
}),
);
}
// 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,
spawn_index: 0,
},
client.common.clone(),
NpcSpawn {
common: client.common.clone(),
..Default::default()
},
);
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) => {
if let Some(instance) = data.find_actor_instance_mut(actor_id) {
if let Some((_, common)) = instance
if let Some((_, spawn)) = instance
.actors
.iter_mut()
.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.rotation = rotation;
}
@ -279,11 +312,22 @@ pub async fn server_main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::i
}
}
}
ToServer::DebugNewNpc(_from_id) => {
for (id, (handle, _)) in &mut data.clients {
let id = *id;
ToServer::DebugNewNpc(_from_id, from_actor_id) => {
let spawn;
{
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,
common: CommonSpawn {
hp_curr: 91,
@ -297,11 +341,19 @@ pub async fn server_main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::i
level: 1,
battalion: 4,
model_chara: 297,
pos: Position::default(),
pos: player.common.pos,
..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() {
to_remove.push(id);