diff options
| author | 1992414357@qq.com <1992414357@qq.com> | 2025-06-09 01:44:36 +0800 |
|---|---|---|
| committer | 1992414357@qq.com <1992414357@qq.com> | 2025-06-09 01:44:36 +0800 |
| commit | 49192dbb98e0ab1f2a66b4786fac86d63f69be64 (patch) | |
| tree | 7cdf27c7cab5fb6b1aabc2ac7c44b7b492558945 /core/src/data/game/runtime/implements.rs | |
| parent | c9dbba0d288becb7f05cebe526be25c76e5a850a (diff) | |
重构所有部分
Diffstat (limited to 'core/src/data/game/runtime/implements.rs')
| -rw-r--r-- | core/src/data/game/runtime/implements.rs | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/core/src/data/game/runtime/implements.rs b/core/src/data/game/runtime/implements.rs new file mode 100644 index 0000000..62038ba --- /dev/null +++ b/core/src/data/game/runtime/implements.rs @@ -0,0 +1,324 @@ +use std::collections::{HashMap, VecDeque}; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::Ordering::SeqCst; +use log::{info, trace, warn}; +use nogamepads::entry_mutex; +use crate::data::game::runtime::structs::{GameControlRuntime, GameRuntime, GameRuntimeData}; +use crate::data::game::types::Players; +use crate::data::message::enums::{JoinFailedMessage, ControlMessage, ExitReason, GameMessage}; +use crate::data::message::enums::JoinFailedMessage::{ContainIdenticalPlayer, GameLocked, PlayerBanned}; +use crate::data::message::enums::ControlMessage::{Axis, Dir, Msg, Pressed, Released}; +use crate::data::message::enums::GameMessage::LetExit; +use crate::data::message::traits::MessageManager; +use crate::data::player::structs::{Account, Player}; +use crate::service::service_types::ServiceType; +use crate::service::service_types::ServiceType::TCPConnection; + +impl GameRuntime { + + /// Attempt to have the specified player join the game + pub fn try_join_player(&mut self, player: Player) -> Result<(), JoinFailedMessage> { + let join = self.can_join_game(&player.account); + match join { + Ok(_) => { + self.data.sign_player_online_status(&player, TCPConnection, true); + trace!("[Game Runtime] Player \"{}\" joined", player.account); + Ok(()) + } + Err(why) => { + warn!("[Game Runtime] Player \"{}\" join failed: {:?}", player.account, why); + Err(why) + } + } + } + + fn can_join_game(&self, account: &Account) -> Result<bool, JoinFailedMessage> { + + if self.is_game_locked() { + Err(GameLocked) + } else if self.data.is_account_banned(account) { + Err(PlayerBanned) + } else if self.data.is_account_online(account) { + Err(ContainIdenticalPlayer) + } else { + Ok(true) + } + } + + /// Request an account to exit + pub fn let_account_exit(&mut self, account: &Account, reason: ExitReason, service_type: ServiceType) { + // Send a leave message to the pad_client and wait for it to actively disconnect + if self.data.is_account_online(account) { + self.send((account.clone(), LetExit(reason)), account.clone(), service_type); + } + } + + /// Check if the game is locked + pub fn is_game_locked(&self) -> bool { + self.data.locked.load(SeqCst) + } + + /// Lock the game + pub fn lock_game(&self) { + if !self.data.locked.load(SeqCst) { + self.data.locked.store(true, SeqCst); + info!("[Game Runtime] Game locked!"); + } + } + + /// Unlock the game + pub fn unlock_game(&self) { + if self.data.locked.load(SeqCst) { + self.data.locked.store(false, SeqCst); + info!("[Game Runtime] Game unlocked!"); + } + } + + /// Close the Game + pub fn close_game(&self) { + if !self.data.close.load(SeqCst) { + self.data.close.store(true, SeqCst); + info!("[Game Runtime] Game closed!"); + } + } +} + +/// Message manager for game pad_client runtime +/// After the service starts, it can be accessed or relevant messages can be stored. +impl MessageManager<(Account, ControlMessage), (Account, GameMessage), Account> for GameRuntime { + fn borrow_received_list_mut(&mut self) -> &mut HashMap<(ServiceType, Account), VecDeque<(Account, ControlMessage)>> { + &mut self.data.received + } + + fn borrow_send_list_mut(&mut self) -> &mut HashMap<(ServiceType, Account), VecDeque<(Account, GameMessage)>> { + &mut self.data.send + } + + fn pop_from_send_list(&mut self, key: Account, service: ServiceType) -> Option<(Account, GameMessage)> { + let key = (service, key); + self.borrow_send_list_mut() + .entry(key) + .or_insert_with(VecDeque::new) + .pop_front() + } + + fn put_into_receive_list(&mut self, message: (Account, ControlMessage), _key: Account, _service: ServiceType) { + let result = self.control.process_control_message(&message.0, message.1); + if result.is_err() { + let result = result.unwrap_err(); + warn!("[Game Runtime] Can't process message: {:?}", result); + drop(result); + } + } +} + +impl Default for GameRuntimeData { + fn default() -> Self { + Self { + received: Default::default(), + send: Default::default(), + players_online: Players::default(), + players_banned: Players::default(), + + locked: AtomicBool::new(false), + close: AtomicBool::new(false) + } + } +} + +impl GameRuntimeData { + + /// Mark a player as online + pub fn sign_player_online_status(&mut self, player: &Player, service_type: ServiceType, value: bool) { + let online = self.is_account_online(&player.account); + if online && !value { + + // Remove player + entry_mutex!(self.players_online, |guard| { + guard.remove_entry(&player.account); + }); + + info!("[Game Runtime] Signed player \"{}\" is [OFFLINE]!", player.account); + + // Reset runtime + let key = (service_type, player.account.clone()); + let get_received = self.received.get_mut(&key); + let get_send = self.send.get_mut(&key); + if let Some(mut list) = get_received { + list.clear(); + } + if let Some(mut list) = get_send { + list.clear(); + } + + } else if !online & value { + + // Insert player + entry_mutex!(self.players_online, |guard| { + guard.entry(player.account.clone()) + .or_insert_with(|| player.clone()); + }); + + info!("[Game Runtime] Signed player \"{}\" is [ONLINE]!", player.account); + } + } + + /// Returns all online accounts + pub fn online_accounts(&self) -> Vec<Account> { + let mut vec = Vec::new(); + entry_mutex!(self.players_online, |guard| { + for account in guard.keys().into_iter() { + vec.push(account.clone()); + } + }); + vec + } + + /// Check if specified account is online + pub fn is_account_online(&self, account: &Account) -> bool { + entry_mutex!(self.players_online, |guard| { + if guard.contains_key(account) { + return true; + } + }); + false + } + + /// Returns all banned accounts + pub fn banned_accounts(&self) -> Vec<Account> { + let mut vec = Vec::new(); + entry_mutex!(self.players_banned, |guard| { + for account in guard.keys().into_iter() { + vec.push(account.clone()); + } + }); + vec + } + + /// Check if account is banned + pub fn is_account_banned(&self, account: &Account) -> bool { + entry_mutex!(self.players_banned, |guard| { + if guard.contains_key(account) { + true; + } + }); + false + } +} + +impl GameControlRuntime { + + /// Process a control message + fn process_control_message(&mut self, who: &Account, msg: ControlMessage) -> Result<(), ControlMessage> { + match msg { + Msg(_) => { + self.send_event(who, msg); + Ok(()) + } + + Pressed(button_key) => { + let key_valid = self.check_key(&self.keys.button_keys, &button_key); + if key_valid { + Self::change_value(&mut self.button, button_key, who, true); + self.send_event(who, msg); + trace!("[Control Runtime] Player \"{}\" pressed btn_{}", &who.id, button_key); + } else { + warn!("[Control Runtime] Key btn_{} not registered!", button_key); + } + Ok(()) + } + + Released(button_key) => { + if self.check_key(&self.keys.button_keys, &button_key) { + Self::change_value(&mut self.button, button_key, who, false); + self.send_event(who, msg); + trace!("[Control Runtime] Player \"{}\" released btn_{}", &who.id, button_key); + } else { + warn!("[Control Runtime] Key btn_{} not registered!", button_key); + } + Ok(()) + } + + Axis(axis_key, axis) => { + if self.check_key(&self.keys.button_keys, &axis_key) { + Self::change_value(&mut self.axes, axis_key, who, axis); + trace!("[Control Runtime] Player \"{}\" changed ax_{} to ({})", &who.id, axis_key, axis); + } else { + warn!("[Control Runtime] Key ax_{} not registered!", axis_key); + } + Ok(()) + } + + Dir(dir_key, dir) => { + if self.check_key(&self.keys.button_keys, &dir_key) { + Self::change_value(&mut self.directions, dir_key, who, dir); + trace!("[Control Runtime] Player \"{}\" changed dir_{} to ({}, {})", &who.id, dir_key, dir.0, dir.1); + } else { + warn!("[Control Runtime] Key dir_{} not registered!", dir_key); + } + Ok(()) + } + + _ => { + Err(msg) + } + } + } + + /// Pop an event message + pub fn pop_event(&mut self, game_runtime: &GameRuntime) -> Option<(Account, ControlMessage)> { + let pop = self.events.pop_front(); + if pop.is_some() { + let (account, msg) = pop.unwrap(); + if game_runtime.data.is_account_online(&account) { + trace!("[Control Runtime] Message: {:?} from \"{}\" ", &msg, account); + Some((account, msg)) + } else { + warn!("[Control Runtime] Invalid message: Player \"{}\" is not online!", account); + None + } + } else { + None + } + } + + /// Get specified player's direction value + pub fn get_direction(&self, who: &Account, key: &u8) -> Option<(f64, f64)> { + Self::get(&self.directions, who, key) + } + + /// Get specified player's axis value + pub fn get_axis(&self, who: &Account, key: &u8) -> Option<f64> { + Self::get(&self.axes, who, key) + } + + /// Get specified player's button status + pub fn get_button_status(&self, who: &Account, key: &u8) -> Option<bool> { + Self::get(&self.button, who, key) + } + + fn check_key(&self, map: &HashMap<u8, String>, key: &u8) -> bool { + map.contains_key(key) + } + + fn get<V: Clone>(map: &HashMap<u8, HashMap<Account, V>>, who: &Account, key: &u8) -> Option<V> { + let key = map.get(key); + if key.is_some() { + let value = key.unwrap().get(who); + if value.is_some() { + let result = value.unwrap(); + Some(result.clone()) + } else { None } + } else { None } + } + + fn change_value<T>(map: &mut HashMap<u8, HashMap<Account, T>>, key: u8, who: &Account, msg: T) { + map.entry(key) + .or_insert_with(HashMap::new) + .insert(who.clone(), msg); + } + + fn send_event(&mut self, who: &Account, msg: ControlMessage) { + self.events.push_back((who.clone(), msg)); + } +}
\ No newline at end of file |
