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

When using the !spawnmonster command, send it to all players

You can't attack it and see it on other clients yet, that will take some
more plumbing.
This commit is contained in:
Joshua Goins 2025-05-09 20:09:22 -04:00
parent 2e50d1f7ad
commit 477380c8b9
5 changed files with 63 additions and 49 deletions

View file

@ -837,12 +837,13 @@ async fn client_loop(
}
msg = internal_recv.recv() => 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::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,
FromServer::ActorControlTarget(actor_id, actor_control) => connection.actor_control_target(actor_id, actor_control).await,
FromServer::SpawnNPC(npc) => connection.send_npc(npc).await,
},
None => break,
}

View file

@ -6,7 +6,7 @@ use crate::{
},
opcodes::ServerZoneIpcType,
packet::{PacketSegment, SegmentData, SegmentType},
world::{Actor, Event},
world::{Event, ToServer},
};
use super::{LuaPlayer, ZoneConnection};
@ -102,51 +102,11 @@ impl ChatHandler {
.await;
}
"!spawnmonster" => {
let spawn_index = connection.get_free_spawn_index();
// spawn a tiny mandragora
{
let ipc = ServerZoneIpcSegment {
op_code: ServerZoneIpcType::NpcSpawn,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::NpcSpawn(NpcSpawn {
aggression_mode: 1,
common: CommonSpawn {
hp_curr: 91,
hp_max: 91,
mp_curr: 100,
mp_max: 100,
spawn_index,
bnpc_base: 13498, // TODO: changing this prevents it from spawning...
bnpc_name: 405,
object_kind: ObjectKind::BattleNpc(BattleNpcSubKind::Enemy),
level: 1,
battalion: 4,
model_chara: 297,
pos: connection.player_data.position,
..Default::default()
},
..Default::default()
}),
..Default::default()
};
connection
.send_segment(PacketSegment {
source_actor: 0x106ad804,
target_actor: connection.player_data.actor_id,
segment_type: SegmentType::Ipc,
data: SegmentData::Ipc { data: ipc },
})
.handle
.send(ToServer::DebugNewNpc(connection.id))
.await;
}
connection.actors.push(Actor {
id: ObjectId(0x106ad804),
hp: 91,
spawn_index: spawn_index as u32,
});
}
"!playscene" => {
let parts: Vec<&str> = chat_message.message.split(' ').collect();
let event_id = parts[1].parse::<u32>().unwrap();

View file

@ -10,7 +10,7 @@ use tokio::sync::mpsc::Sender;
use crate::{
common::Position,
ipc::zone::{ActorControl, ActorControlTarget, ClientTrigger, CommonSpawn},
ipc::zone::{ActorControl, ActorControlTarget, ClientTrigger, CommonSpawn, NpcSpawn},
};
use super::Actor;
@ -31,6 +31,8 @@ pub enum FromServer {
ActorControl(u32, ActorControl),
/// We need to update an actor's target'
ActorControlTarget(u32, ActorControlTarget),
/// Spawn an NPC
SpawnNPC(NpcSpawn),
}
#[derive(Debug, Clone)]
@ -82,6 +84,7 @@ pub enum ToServer {
Disconnected(ClientId),
/// A fatal error occured.
FatalError(std::io::Error),
DebugNewNpc(ClientId),
}
#[derive(Clone, Debug)]

View file

@ -770,4 +770,24 @@ impl ZoneConnection {
})
.await;
}
pub async fn send_npc(&mut self, mut npc: NpcSpawn) {
// the one from the global state is useless, of course
npc.common.spawn_index = self.get_free_spawn_index();
let ipc = ServerZoneIpcSegment {
op_code: ServerZoneIpcType::NpcSpawn,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::NpcSpawn(npc),
..Default::default()
};
self.send_segment(PacketSegment {
source_actor: 0x106ad804,
target_actor: self.player_data.actor_id,
segment_type: SegmentType::Ipc,
data: SegmentData::Ipc { data: ipc },
})
.await;
}
}

View file

@ -2,9 +2,10 @@ use std::collections::HashMap;
use tokio::sync::mpsc::Receiver;
use crate::{
common::ObjectId,
common::{ObjectId, Position},
ipc::zone::{
ActorControl, ActorControlCategory, ActorControlTarget, ClientTriggerCommand, CommonSpawn,
ActorControl, ActorControlCategory, ActorControlTarget, BattleNpcSubKind,
ClientTriggerCommand, CommonSpawn, NpcSpawn, ObjectKind,
},
};
@ -263,6 +264,35 @@ 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;
let msg = FromServer::SpawnNPC(NpcSpawn {
aggression_mode: 1,
common: CommonSpawn {
hp_curr: 91,
hp_max: 91,
mp_curr: 100,
mp_max: 100,
spawn_index: 0, // not needed at this level
bnpc_base: 13498, // TODO: changing this prevents it from spawning...
bnpc_name: 405,
object_kind: ObjectKind::BattleNpc(BattleNpcSubKind::Enemy),
level: 1,
battalion: 4,
model_chara: 297,
pos: Position::default(),
..Default::default()
},
..Default::default()
});
if handle.send(msg).is_err() {
to_remove.push(id);
}
}
}
ToServer::Disconnected(from_id) => {
to_remove.push(from_id);
}