From 1402b1018040a491efd9906eeeacd26bac568e74 Mon Sep 17 00:00:00 2001 From: Sofia Date: Sat, 18 Jul 2026 02:55:41 +0300 Subject: [PATCH] Implement syncing --- rust/src/game_manager.rs | 100 +++++++++++++++++++++++++++++++- rust/src/net/network_manager.rs | 19 +++++- rust/src/player.rs | 14 +++++ 3 files changed, 130 insertions(+), 3 deletions(-) diff --git a/rust/src/game_manager.rs b/rust/src/game_manager.rs index c99da4e..8b2279c 100644 --- a/rust/src/game_manager.rs +++ b/rust/src/game_manager.rs @@ -1,4 +1,4 @@ -use std::net::SocketAddr; +use std::{collections::HashMap, net::SocketAddr}; use godot::{classes::CharacterBody3D, prelude::*, tools::get_autoload_by_name}; use serde::{Deserialize, Serialize}; @@ -6,7 +6,14 @@ use serde::{Deserialize, Serialize}; use crate::{ map::Map, map_resource::MapResource, - net::network_manager::{NetworkManager, Package, PeerKind}, + net::{ + network_manager::{ + NetworkManager, + Package::{self, SelfSync}, + PeerKind, + }, + util::NetVector3, + }, player::{IPlayer, NetPlayerTransform}, }; @@ -82,10 +89,52 @@ pub struct Game { game_started: bool, pub current_map: Option>, + since_last_sync: f64, base: Base, } +#[godot_api] +impl INode for Game { + fn process(&mut self, delta: f64) { + self.since_last_sync += delta; + if self.since_last_sync > (1. / 30.) { + self.since_last_sync = 0.; + if let Some(_) = self.current_map { + if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer { + match peer { + PeerKind::Client(peer, socket_addr) => { + if let Some(player) = self + .players + .iter() + .find(|p| p.id == self.self_id.unwrap_or(0)) + { + if let Some((dir, rot)) = &player.get_self_sync() { + peer.send_unreliable( + socket_addr, + SelfSync(dir.clone(), rot.clone()), + ); + } + } + } + PeerKind::Server(peer, _) => { + let mut sync_data = HashMap::new(); + for player in &self.players { + if let (Some(dir), Some(transform)) = + (player.get_move_dir(), player.get_transform()) + { + sync_data.insert(player.id, (dir, transform)); + } + } + peer.broadcast_unreliable(Package::Sync(sync_data)); + } + } + } + } + } + } +} + #[godot_api] impl Game { #[signal] @@ -166,6 +215,10 @@ impl Game { self.players.iter().find(|p| p.connection_addr == *addr) } + pub fn find_player_by_addr_mut(&mut self, addr: &SocketAddr) -> Option<&mut Player> { + self.players.iter_mut().find(|p| p.connection_addr == *addr) + } + pub fn find_player(&self, player_id: u16) -> Option<&Player> { self.players.iter().find(|p| p.id == player_id) } @@ -234,6 +287,17 @@ impl Game { } } } + + pub fn handle_sync(&mut self, sync_data: HashMap) { + for (player_id, (dir, transform)) in sync_data { + if let Some(player) = self.players.iter_mut().find(|p| p.id == player_id) { + if player.id != self.self_id.unwrap_or(0) { + player.set_transform(transform); + player.set_move_dir(dir); + } + } + } + } } #[derive(Clone, Debug)] @@ -260,6 +324,38 @@ impl Player { character.dyn_bind_mut().apply_transform(transform); } } + + pub fn get_move_dir(&self) -> Option { + if let Some(character) = &self.character { + Some(character.dyn_bind().get_movement_dir().into()) + } else { + None + } + } + + pub fn set_move_dir(&mut self, dir: NetVector3) { + if let Some(character) = &mut self.character { + character.dyn_bind_mut().set_movement_dir(dir.into()); + } + } + + pub fn get_self_sync(&self) -> Option<(NetVector3, NetVector3)> { + if let Some(character) = &self.character { + Some(( + character.dyn_bind().get_movement_dir().into(), + character.dyn_bind().get_transform().rotation, + )) + } else { + None + } + } + + pub fn apply_self_sync(&mut self, dir: NetVector3, rot: NetVector3) { + if let Some(character) = &mut self.character { + character.dyn_bind_mut().set_movement_dir(dir.into()); + character.dyn_bind_mut().apply_rotation(rot.into()); + } + } } #[derive(Debug, Serialize, Deserialize, Clone)] diff --git a/rust/src/net/network_manager.rs b/rust/src/net/network_manager.rs index cd0dd76..3c7cbdf 100644 --- a/rust/src/net/network_manager.rs +++ b/rust/src/net/network_manager.rs @@ -10,7 +10,7 @@ use teanet::{Peer, PeerConfig, PeerMessage, connections::Connection}; use crate::{ game_manager::{Game, GameManager, NetPlayer, Player}, - net::net_stats::Stats, + net::{net_stats::Stats, util::NetVector3}, player::NetPlayerTransform, ui::cli::{CliColor, CommandLinePanel}, }; @@ -217,6 +217,11 @@ impl INode for NetworkManager { game.bind_mut().spawn_player(id, transform); } } + Package::Sync(sync_data) => { + if let Some(game) = &mut Game::singleton() { + game.bind_mut().handle_sync(sync_data); + } + } _ => {} }, } @@ -346,6 +351,16 @@ impl INode for NetworkManager { } } } + Package::SelfSync(dir, rot) => { + if let Some(game) = &mut Game::singleton() { + if let Some(player) = &mut game + .bind_mut() + .find_player_by_addr_mut(&conn.address) + { + player.apply_self_sync(dir, rot); + } + } + } _ => {} }, } @@ -466,6 +481,8 @@ pub enum Package { SelectMap(u8), GameStarted, SpawnPlayer(u16, NetPlayerTransform), + Sync(HashMap), + SelfSync(NetVector3, NetVector3), MapLoaded, } diff --git a/rust/src/player.rs b/rust/src/player.rs index 8f8a48b..8ce2ed4 100644 --- a/rust/src/player.rs +++ b/rust/src/player.rs @@ -23,8 +23,10 @@ pub trait IPlayer { fn get_y_speed(&self) -> f32; fn set_y_speed(&mut self, speed: f32); fn get_movement_dir(&self) -> Vector3; + fn set_movement_dir(&mut self, dir: Vector3); fn get_move_speed(&self) -> f32; fn apply_transform(&mut self, transform: NetPlayerTransform); + fn apply_rotation(&mut self, rot: Vector3); fn get_transform(&self) -> NetPlayerTransform; } @@ -95,6 +97,8 @@ impl IPlayer for LocalPlayer { self.movement_dir } + fn set_movement_dir(&mut self, _dir: Vector3) {} + fn get_move_speed(&self) -> f32 { self.move_speed } @@ -106,6 +110,8 @@ impl IPlayer for LocalPlayer { .set_global_rotation(transform.rotation.into()); } + fn apply_rotation(&mut self, _rot: Vector3) {} + fn get_transform(&self) -> NetPlayerTransform { NetPlayerTransform { location: self.base().get_global_position().into(), @@ -212,6 +218,10 @@ impl IPlayer for RemotePlayer { self.movement_dir } + fn set_movement_dir(&mut self, dir: Vector3) { + self.movement_dir = dir.into(); + } + fn get_move_speed(&self) -> f32 { self.move_speed } @@ -227,6 +237,10 @@ impl IPlayer for RemotePlayer { .set_global_rotation(transform.rotation.into()); } + fn apply_rotation(&mut self, rot: Vector3) { + self.base_mut().set_global_rotation(rot); + } + fn get_transform(&self) -> NetPlayerTransform { NetPlayerTransform { location: self.base().get_global_position().into(),