mirror of
https://github.com/redstrate/Kawari.git
synced 2025-04-20 06:37:45 +00:00
Add initial stuffs for actor replication
This commit is contained in:
parent
4bacc35551
commit
9cb7cd9abd
3 changed files with 115 additions and 17 deletions
|
@ -18,6 +18,10 @@ use kawari::world::ipc::{
|
||||||
GameMasterCommandType, GameMasterRank, ObjectKind, OnlineStatus, PlayerSubKind,
|
GameMasterCommandType, GameMasterRank, ObjectKind, OnlineStatus, PlayerSubKind,
|
||||||
ServerZoneIpcData, ServerZoneIpcSegment, SocialListRequestType,
|
ServerZoneIpcData, ServerZoneIpcSegment, SocialListRequestType,
|
||||||
};
|
};
|
||||||
|
use kawari::world::{
|
||||||
|
Actor, ClientHandle, ClientId, EffectsBuilder, FromServer, LuaPlayer, PlayerData, ServerHandle,
|
||||||
|
StatusEffects, ToServer, WorldDatabase,
|
||||||
|
};
|
||||||
use kawari::world::{
|
use kawari::world::{
|
||||||
ChatHandler, Inventory, Zone, ZoneConnection,
|
ChatHandler, Inventory, Zone, ZoneConnection,
|
||||||
ipc::{
|
ipc::{
|
||||||
|
@ -25,10 +29,6 @@ use kawari::world::{
|
||||||
SocialList,
|
SocialList,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use kawari::world::{
|
|
||||||
ClientHandle, ClientId, EffectsBuilder, FromServer, LuaPlayer, PlayerData, ServerHandle,
|
|
||||||
StatusEffects, ToServer, WorldDatabase,
|
|
||||||
};
|
|
||||||
use mlua::{Function, Lua};
|
use mlua::{Function, Lua};
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use tokio::io::AsyncReadExt;
|
use tokio::io::AsyncReadExt;
|
||||||
|
@ -49,10 +49,12 @@ struct ExtraLuaState {
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
struct Data {
|
struct Data {
|
||||||
clients: HashMap<ClientId, ClientHandle>,
|
clients: HashMap<ClientId, ClientHandle>,
|
||||||
|
actors: Vec<Actor>,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::io::Error> {
|
async fn main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::io::Error> {
|
||||||
let mut data = Data::default();
|
let mut data = Data::default();
|
||||||
|
let mut to_remove = Vec::new();
|
||||||
|
|
||||||
while let Some(msg) = recv.recv().await {
|
while let Some(msg) = recv.recv().await {
|
||||||
match msg {
|
match msg {
|
||||||
|
@ -60,9 +62,7 @@ async fn main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::io::Error> {
|
||||||
data.clients.insert(handle.id, handle);
|
data.clients.insert(handle.id, handle);
|
||||||
}
|
}
|
||||||
ToServer::Message(from_id, msg) => {
|
ToServer::Message(from_id, msg) => {
|
||||||
let mut to_remove = Vec::new();
|
for (id, handle) in &mut data.clients {
|
||||||
|
|
||||||
for (id, handle) in data.clients.iter_mut() {
|
|
||||||
let id = *id;
|
let id = *id;
|
||||||
|
|
||||||
if id == from_id {
|
if id == from_id {
|
||||||
|
@ -75,16 +75,44 @@ async fn main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::io::Error> {
|
||||||
to_remove.push(id);
|
to_remove.push(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
ToServer::ActorSpawned(from_id, actor) => {
|
||||||
|
for (id, handle) in &mut data.clients {
|
||||||
|
let id = *id;
|
||||||
|
|
||||||
// Remove any clients that errored out
|
if id == from_id {
|
||||||
for id in to_remove {
|
continue;
|
||||||
data.clients.remove(&id);
|
}
|
||||||
|
|
||||||
|
let msg = FromServer::ActorSpawn(actor);
|
||||||
|
|
||||||
|
if handle.send(msg).is_err() {
|
||||||
|
to_remove.push(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ToServer::ActorMoved(from_id, actor_id, position) => {
|
||||||
|
for (id, handle) in &mut data.clients {
|
||||||
|
let id = *id;
|
||||||
|
|
||||||
|
if id == from_id {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let msg = FromServer::ActorMove(actor_id, position);
|
||||||
|
|
||||||
|
if handle.send(msg).is_err() {
|
||||||
|
to_remove.push(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ToServer::FatalError(err) => return Err(err),
|
ToServer::FatalError(err) => return Err(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Remove any clients that errored out
|
||||||
|
for id in to_remove {
|
||||||
|
data.clients.remove(&id);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1017,6 +1045,8 @@ 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) => connection.spawn_actor(actor).await,
|
||||||
|
FromServer::ActorMove(actor_id, position) => connection.set_actor_position(actor_id, position).await,
|
||||||
},
|
},
|
||||||
None => break,
|
None => break,
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,7 +136,7 @@ struct Packet<T: ReadWriteIpcSegment> {
|
||||||
|
|
||||||
fn dump(msg: &str, data: &[u8]) {
|
fn dump(msg: &str, data: &[u8]) {
|
||||||
write("packet.bin", data).unwrap();
|
write("packet.bin", data).unwrap();
|
||||||
panic!("{msg} Dumped to packet.bin.");
|
tracing::warn!("{msg} Dumped to packet.bin.");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_packet<T: ReadWriteIpcSegment>(
|
pub async fn send_packet<T: ReadWriteIpcSegment>(
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::{
|
||||||
use tokio::{net::TcpStream, sync::mpsc::Sender, task::JoinHandle};
|
use tokio::{net::TcpStream, sync::mpsc::Sender, task::JoinHandle};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
common::{GameData, ObjectId, Position, timestamp_secs},
|
common::{GameData, ObjectId, ObjectTypeId, Position, timestamp_secs},
|
||||||
opcodes::ServerZoneIpcType,
|
opcodes::ServerZoneIpcType,
|
||||||
packet::{
|
packet::{
|
||||||
CompressionType, ConnectionType, PacketSegment, PacketState, SegmentType, parse_packet,
|
CompressionType, ConnectionType, PacketSegment, PacketState, SegmentType, parse_packet,
|
||||||
|
@ -19,10 +19,11 @@ use crate::{
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
Actor, Event, Inventory, Item, LuaPlayer, StatusEffects, WorldDatabase, Zone,
|
Actor, Event, Inventory, Item, LuaPlayer, StatusEffects, WorldDatabase, Zone,
|
||||||
|
chat_handler::CUSTOMIZE_DATA,
|
||||||
ipc::{
|
ipc::{
|
||||||
ActorControlSelf, ActorSetPos, ClientZoneIpcSegment, ContainerInfo, ContainerType,
|
ActorControlSelf, ActorSetPos, BattleNpcSubKind, ClientZoneIpcSegment, CommonSpawn,
|
||||||
InitZone, ItemInfo, ServerZoneIpcData, ServerZoneIpcSegment, StatusEffect,
|
ContainerInfo, ContainerType, InitZone, ItemInfo, NpcSpawn, ObjectKind, ServerZoneIpcData,
|
||||||
StatusEffectList, UpdateClassInfo, WeatherChange,
|
ServerZoneIpcSegment, StatusEffect, StatusEffectList, UpdateClassInfo, WeatherChange,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,6 +54,10 @@ pub struct ClientId(usize);
|
||||||
pub enum FromServer {
|
pub enum FromServer {
|
||||||
/// A chat message.
|
/// A chat message.
|
||||||
Message(String),
|
Message(String),
|
||||||
|
/// An actor has been spawned.
|
||||||
|
ActorSpawn(Actor),
|
||||||
|
/// An actor moved to a new position.
|
||||||
|
ActorMove(u32, Position),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -88,6 +93,8 @@ impl ClientHandle {
|
||||||
pub enum ToServer {
|
pub enum ToServer {
|
||||||
NewClient(ClientHandle),
|
NewClient(ClientHandle),
|
||||||
Message(ClientId, String),
|
Message(ClientId, String),
|
||||||
|
ActorSpawned(ClientId, Actor),
|
||||||
|
ActorMoved(ClientId, u32, Position),
|
||||||
FatalError(std::io::Error),
|
FatalError(std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,6 +254,67 @@ impl ZoneConnection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn set_actor_position(&mut self, actor_id: u32, position: Position) {
|
||||||
|
let ipc = ServerZoneIpcSegment {
|
||||||
|
op_code: ServerZoneIpcType::ActorMove,
|
||||||
|
timestamp: timestamp_secs(),
|
||||||
|
data: ServerZoneIpcData::ActorMove { pos: position },
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
self.send_segment(PacketSegment {
|
||||||
|
source_actor: actor_id,
|
||||||
|
target_actor: actor_id,
|
||||||
|
segment_type: SegmentType::Ipc { data: ipc },
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn spawn_actor(&mut self, actor: Actor) {
|
||||||
|
let ipc = ServerZoneIpcSegment {
|
||||||
|
unk1: 20,
|
||||||
|
unk2: 0,
|
||||||
|
op_code: ServerZoneIpcType::NpcSpawn,
|
||||||
|
server_id: 0,
|
||||||
|
timestamp: timestamp_secs(),
|
||||||
|
data: ServerZoneIpcData::NpcSpawn(NpcSpawn {
|
||||||
|
common: CommonSpawn {
|
||||||
|
hp_curr: 100,
|
||||||
|
hp_max: 100,
|
||||||
|
mp_curr: 100,
|
||||||
|
mp_max: 100,
|
||||||
|
look: CUSTOMIZE_DATA,
|
||||||
|
spawn_index: self.get_free_spawn_index(),
|
||||||
|
bnpc_base: 13498,
|
||||||
|
bnpc_name: 10261,
|
||||||
|
object_kind: ObjectKind::BattleNpc(BattleNpcSubKind::Enemy),
|
||||||
|
level: 1,
|
||||||
|
models: [
|
||||||
|
0, // head
|
||||||
|
89, // body
|
||||||
|
89, // hands
|
||||||
|
89, // legs
|
||||||
|
89, // feet
|
||||||
|
0, // ears
|
||||||
|
0, // neck
|
||||||
|
0, // wrists
|
||||||
|
0, // left finger
|
||||||
|
0, // right finger
|
||||||
|
],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.send_segment(PacketSegment {
|
||||||
|
source_actor: actor.id.0,
|
||||||
|
target_actor: self.player_data.actor_id,
|
||||||
|
segment_type: SegmentType::Ipc { data: ipc },
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn change_zone(&mut self, new_zone_id: u16) {
|
pub async fn change_zone(&mut self, new_zone_id: u16) {
|
||||||
self.zone = Some(Zone::load(new_zone_id));
|
self.zone = Some(Zone::load(new_zone_id));
|
||||||
self.player_data.zone_id = new_zone_id;
|
self.player_data.zone_id = new_zone_id;
|
||||||
|
|
Loading…
Add table
Reference in a new issue