1
Fork 0
mirror of https://github.com/redstrate/Kawari.git synced 2025-06-30 11:47:45 +00:00

When equipping items, network that to other players

See #50
This commit is contained in:
Joshua Goins 2025-06-28 11:11:42 -04:00
parent ad4edf801d
commit 9a3652fb42
4 changed files with 83 additions and 31 deletions

View file

@ -11,7 +11,7 @@ use kawari::ipc::zone::{
ActorControlCategory, ActorControlSelf, PlayerEntry, PlayerSpawn, PlayerStatus, SocialList,
};
use kawari::ipc::zone::{
ClientTriggerCommand, ClientZoneIpcData, CommonSpawn, EventStart, GameMasterRank, OnlineStatus,
ClientTriggerCommand, ClientZoneIpcData, EventStart, GameMasterRank, OnlineStatus,
ServerZoneIpcData, ServerZoneIpcSegment, SocialListRequestType,
};
use kawari::opcodes::{ServerChatIpcType, ServerZoneIpcType};
@ -79,7 +79,6 @@ pub fn spawn_client(connection: ZoneConnection) {
ip: *ip,
channel: send,
actor_id: 0,
common: CommonSpawn::default(),
};
let _ = my_send.send(handle);
}
@ -170,7 +169,6 @@ async fn client_loop(
let mut client_handle = client_handle.clone();
client_handle.actor_id = actor_id;
client_handle.common = connection.get_player_common_spawn(connection.exit_position, connection.exit_rotation);
// tell the server we exist, now that we confirmed we are a legitimate connection
connection.handle.send(ToServer::NewClient(client_handle)).await;
@ -326,11 +324,11 @@ async fn client_loop(
.unwrap();
}
ClientZoneIpcData::FinishLoading { .. } => {
// tell the server we loaded into the zone, so it can start sending us acors
connection.handle.send(ToServer::ZoneLoaded(connection.id, connection.zone.as_ref().unwrap().id)).await;
let common = connection.get_player_common_spawn(connection.exit_position, connection.exit_rotation);
// tell the server we loaded into the zone, so it can start sending us acors
connection.handle.send(ToServer::ZoneLoaded(connection.id, connection.zone.as_ref().unwrap().id, common.clone())).await;
let chara_details = database.find_chara_make(connection.player_data.content_id);
connection.send_inventory(false).await;
@ -941,6 +939,7 @@ async fn client_loop(
FromServer::ActionComplete(request) => connection.execute_action(request, &mut lua_player).await,
FromServer::ActionCancelled() => connection.cancel_action().await,
FromServer::UpdateConfig(actor_id, config) => connection.update_config(actor_id, config).await,
FromServer::ActorEquip(actor_id, main_weapon_id, model_ids) => connection.update_equip(actor_id, main_weapon_id, model_ids).await,
},
None => break,
}

View file

@ -42,6 +42,8 @@ pub enum FromServer {
ActionCancelled(),
/// Update an actor's equip display flags.
UpdateConfig(u32, Config),
/// Update an actor's model IDs.
ActorEquip(u32, u64, [u32; 10]),
}
#[derive(Debug, Clone)]
@ -50,7 +52,6 @@ pub struct ClientHandle {
pub ip: SocketAddr,
pub channel: Sender<FromServer>,
pub actor_id: u32,
pub common: CommonSpawn,
}
impl ClientHandle {
@ -86,7 +87,7 @@ pub enum ToServer {
ClientTrigger(ClientId, u32, ClientTrigger),
/// The connection loaded into a zone.
// TODO: the connection should not be in charge and telling the global server what zone they just loaded in! but this will work for now
ZoneLoaded(ClientId, u16),
ZoneLoaded(ClientId, u16, CommonSpawn),
/// The connection left a zone.
LeftZone(ClientId, u32, u16),
/// The connection disconnected.
@ -103,6 +104,8 @@ pub enum ToServer {
ActionRequest(ClientId, u32, ActionRequest),
/// We want to update our own equip display flags.
Config(ClientId, u32, Config),
/// Tell the server what models IDs we have equipped.
Equip(ClientId, u32, u64, [u32; 10]),
}
#[derive(Clone, Debug)]

View file

@ -585,34 +585,47 @@ impl ZoneConnection {
// send them an appearance update
if send_appearance_update {
let ipc;
let main_weapon_id;
let model_ids;
{
let mut game_data = self.gamedata.lock().unwrap();
let inventory = &self.player_data.inventory;
ipc = ServerZoneIpcSegment {
main_weapon_id = inventory.get_main_weapon_id(&mut game_data);
model_ids = inventory.get_model_ids(&mut game_data);
}
self.handle
.send(ToServer::Equip(
self.id,
self.player_data.actor_id,
main_weapon_id,
model_ids,
))
.await;
}
}
pub async fn update_equip(&mut self, actor_id: u32, main_weapon_id: u64, model_ids: [u32; 10]) {
let ipc = ServerZoneIpcSegment {
op_code: ServerZoneIpcType::Equip,
timestamp: timestamp_secs(),
data: ServerZoneIpcData::Equip(Equip {
main_weapon_id: inventory.get_main_weapon_id(&mut game_data),
sub_weapon_id: 0,
crest_enable: 0,
pattern_invalid: 0,
model_ids: inventory.get_model_ids(&mut game_data),
main_weapon_id,
model_ids,
..Default::default()
}),
..Default::default()
};
}
self.send_segment(PacketSegment {
source_actor: self.player_data.actor_id,
source_actor: actor_id,
target_actor: self.player_data.actor_id,
segment_type: SegmentType::Ipc,
data: SegmentData::Ipc { data: ipc },
})
.await;
}
}
pub async fn send_message(&mut self, message: &str) {
let ipc = ServerZoneIpcSegment {

View file

@ -62,6 +62,10 @@ impl Instance {
self.actors.get(&id)
}
fn find_actor_mut(&mut self, id: ObjectId) -> Option<&mut NetworkedActor> {
self.actors.get_mut(&id)
}
fn insert_npc(&mut self, id: ObjectId, spawn: NpcSpawn) {
self.actors.insert(id, NetworkedActor::Npc(spawn));
}
@ -132,7 +136,7 @@ pub async fn server_main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::i
data.clients
.insert(handle.id, (handle, ClientState::default()));
}
ToServer::ZoneLoaded(from_id, zone_id) => {
ToServer::ZoneLoaded(from_id, zone_id, common_spawn) => {
let mut data = data.lock().unwrap();
// create a new instance if necessary
@ -181,7 +185,7 @@ pub async fn server_main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::i
instance.actors.insert(
ObjectId(client.actor_id),
NetworkedActor::Player(NpcSpawn {
common: client.common.clone(),
common: common_spawn.clone(),
..Default::default()
}),
);
@ -208,7 +212,7 @@ pub async fn server_main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::i
spawn_index: 0,
},
NpcSpawn {
common: client.common.clone(),
common: common_spawn.clone(),
..Default::default()
},
);
@ -601,6 +605,39 @@ pub async fn server_main_loop(mut recv: Receiver<ToServer>) -> Result<(), std::i
}
}
}
ToServer::Equip(_from_id, from_actor_id, main_weapon_id, model_ids) => {
// update their stored state so it's correctly sent on new spawns
{
let mut data = data.lock().unwrap();
let Some(instance) = data.find_actor_instance_mut(from_actor_id) else {
break;
};
let Some(actor) = instance.find_actor_mut(ObjectId(from_actor_id)) else {
break;
};
let NetworkedActor::Player(player) = actor else {
break;
};
player.common.main_weapon_model = main_weapon_id;
player.common.models = model_ids.clone();
}
// Inform all clients about their new equipped model ids
let mut data = data.lock().unwrap();
for (id, (handle, _)) in &mut data.clients {
let id = *id;
let msg = FromServer::ActorEquip(from_actor_id, main_weapon_id, model_ids);
if handle.send(msg).is_err() {
to_remove.push(id);
}
}
}
ToServer::Disconnected(from_id) => {
let mut data = data.lock().unwrap();