diff options
Diffstat (limited to 'core')
| -rw-r--r-- | core/src/data/controller/cli/cli_command.rs | 111 | ||||
| -rw-r--r-- | core/src/data/controller/runtime/implements.rs | 30 | ||||
| -rw-r--r-- | core/src/data/controller/runtime/structs.rs | 3 | ||||
| -rw-r--r-- | core/src/data/game/cli/cli_command.rs | 169 | ||||
| -rw-r--r-- | core/src/data/game/runtime/implements.rs | 88 | ||||
| -rw-r--r-- | core/src/data/game/runtime/structs.rs | 2 | ||||
| -rw-r--r-- | core/src/service/tcp_network/pad_client/implements.rs | 5 |
7 files changed, 377 insertions, 31 deletions
diff --git a/core/src/data/controller/cli/cli_command.rs b/core/src/data/controller/cli/cli_command.rs index b5c0414..d5cda07 100644 --- a/core/src/data/controller/cli/cli_command.rs +++ b/core/src/data/controller/cli/cli_command.rs @@ -1,5 +1,8 @@ +use std::process::exit; use std::sync::{Arc, Mutex}; -use clap::{Parser, Subcommand}; +use clap::{Args, Parser, Subcommand}; +use clearscreen::clear; +use log::info; use nogamepads::entry_mutex; use crate::data::controller::runtime::structs::ControllerRuntime; use crate::data::message::enums::ControlMessage; @@ -19,30 +22,118 @@ enum Commands { #[command(about = "Clean the screen")] Clear, + #[command(about = "Close the controller")] + Close, + + #[command(about = "Exit the console")] + Exit, + #[command(about = "Send a message")] - Message, + Message(MessageArgs), - #[command(about = "Close the controller")] - Close + #[command(about = "Press a button")] + Press(ButtonArgs), + + #[command(about = "Release a button")] + Release(ButtonArgs), + + #[command(about = "Change a axis value")] + Axis(AxisArgs), + + #[command(about = "Change a direction value")] + Direction(DirectionArgs), + + Pop, + + PopAll +} + +#[derive(Args, Debug)] +struct MessageArgs { + message: String, +} + +#[derive(Args, Debug)] +struct ButtonArgs { + button_key: u8 +} + +#[derive(Args, Debug)] +struct AxisArgs { + axis_key: u8, + axis_value: f64 +} + +#[derive(Args, Debug)] +struct DirectionArgs { + dir_key: u8, + x: f64, + y: f64 } pub fn process_controller_cli(runtime: Arc<Mutex<ControllerRuntime>>, cmd: ControllerCli) { match cmd.command { Commands::Clear => { - + clear().expect("Failed to clear screen"); } - Commands::Message => { + Commands::Close => { entry_mutex!(runtime, |guard| { - guard.send(ControlMessage::Msg("fuck".to_string()), 0, TCPConnection); + guard.close(); }); } - Commands::Close => { + Commands::Exit => { + exit(1); + } + + Commands::Message(args) => { entry_mutex!(runtime, |guard| { - guard.close(); - }); + guard.message(args.message); + }) + } + + Commands::Press(args) => { + entry_mutex!(runtime, |guard| { + guard.press_button(args.button_key); + }) + } + + Commands::Release(args) => { + entry_mutex!(runtime, |guard| { + guard.release_button(args.button_key); + }) + } + + Commands::Axis(args) => { + entry_mutex!(runtime, |guard| { + guard.change_axis(args.axis_key, args.axis_value); + }) + } + + Commands::Direction(args) => { + entry_mutex!(runtime, |guard| { + guard.change_direction(args.dir_key, args.x, args.y); + }) + } + + Commands::Pop => { + entry_mutex!(runtime, |guard| { + if let Some(msg) = guard.pop() { + info!("Pop: {:?}", msg); + } else { + info!("None!"); + } + }) + } + + Commands::PopAll => { + entry_mutex!(runtime, |guard| { + while let Some(msg) = guard.pop() { + info!("Pop: {:?}", msg); + } + }) } } }
\ No newline at end of file diff --git a/core/src/data/controller/runtime/implements.rs b/core/src/data/controller/runtime/implements.rs index b79890e..840ea2c 100644 --- a/core/src/data/controller/runtime/implements.rs +++ b/core/src/data/controller/runtime/implements.rs @@ -4,6 +4,7 @@ use log::trace; use crate::data::controller::runtime::structs::ControllerRuntime; use crate::data::message::enums::{ControlMessage, GameMessage}; use crate::data::message::traits::MessageManager; +use crate::data::player::structs::Account; use crate::service::service_types::ServiceType; /// Message manager for controller-side runtime @@ -26,4 +27,33 @@ impl ControllerRuntime { trace!("[Controller Runtime] Closed."); } } + + pub fn message(&mut self, message: String) { + self.send_message(ControlMessage::Msg(message)); + } + + pub fn press_button(&mut self, key: u8) { + self.send_message(ControlMessage::Pressed(key)); + } + + pub fn release_button(&mut self, key: u8) { + self.send_message(ControlMessage::Released(key)); + } + + pub fn change_axis(&mut self, key: u8, ax_val: f64) { + self.send_message(ControlMessage::Axis(key, ax_val)); + } + + pub fn change_direction(&mut self, key: u8, x: f64, y: f64) { + self.send_message(ControlMessage::Dir(key, (x, y))); + } + + pub fn pop(&mut self) -> Option<GameMessage> { + self.receive(0, self.service_type.clone()) + } + + fn send_message (&mut self, msg: ControlMessage) { + let service = self.service_type.clone(); + self.send(msg, 0, service); + } }
\ No newline at end of file diff --git a/core/src/data/controller/runtime/structs.rs b/core/src/data/controller/runtime/structs.rs index 7be2cd6..bfd39c5 100644 --- a/core/src/data/controller/runtime/structs.rs +++ b/core/src/data/controller/runtime/structs.rs @@ -10,11 +10,12 @@ use crate::service::service_types::ServiceType; #[derive(Default)] pub struct ControllerRuntime { + pub(crate) service_type: ServiceType, pub(crate) received: HashMap<(ServiceType, u8), VecDeque<GameMessage>>, pub(crate) send: HashMap<(ServiceType, u8), VecDeque<ControlMessage>>, pub(crate) player: Player, pub game_info: GameInfo, - pub close: AtomicBool + pub close: AtomicBool, }
\ No newline at end of file diff --git a/core/src/data/game/cli/cli_command.rs b/core/src/data/game/cli/cli_command.rs index 1d79515..9b74831 100644 --- a/core/src/data/game/cli/cli_command.rs +++ b/core/src/data/game/cli/cli_command.rs @@ -1,7 +1,12 @@ +use std::process::exit; use std::sync::{Arc, Mutex}; -use clap::{Parser, Subcommand}; +use clap::{Args, Parser, Subcommand}; +use clearscreen::clear; +use log::{info, warn}; use nogamepads::entry_mutex; use crate::data::game::runtime::structs::GameRuntime; +use crate::data::message::traits::MessageManager; +use crate::data::player::structs::Player; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] @@ -16,14 +21,69 @@ enum Commands { #[command(about = "Clean the screen")] Clear, + LockGame, + + UnlockGame, + #[command(about = "Close the game")] - Close + Close, + + #[command(about = "Exit the console")] + Exit, + + OnlineList, + + BannedList, + + Ban(PlayerIndex), + + Pardon(PlayerIndex), + + Kick(PlayerIndex), + + Event(SendEventArgs), + + Message(SendMessageArgs), + + Pop, + + PopAll, +} + +#[derive(Args, Debug)] +struct PlayerIndex { + index: usize, +} + +#[derive(Args, Debug)] +struct SendEventArgs { + index: usize, + event: u8 +} + +#[derive(Args, Debug)] +struct SendMessageArgs { + index: usize, + msg: String } pub fn process_game_cli(runtime: Arc<Mutex<GameRuntime>>, cmd: GameCli) { match cmd.command { Commands::Clear => { + clear().expect("Failed to clear screen"); + + } + + Commands::LockGame => { + entry_mutex!(runtime, |guard| { + guard.lock_game(); + }) + } + Commands::UnlockGame => { + entry_mutex!(runtime, |guard| { + guard.unlock_game(); + }) } Commands::Close => { @@ -31,5 +91,110 @@ pub fn process_game_cli(runtime: Arc<Mutex<GameRuntime>>, cmd: GameCli) { guard.close_game(); }) } + + Commands::Exit => { + exit(1); + } + + Commands::OnlineList => { + entry_mutex!(runtime, |guard| { + let mut i = 0; + for account in guard.data.online_accounts() { + info!("{}.{}", i, account.id); + i += 1; + } + }) + } + + Commands::BannedList => { + entry_mutex!(runtime, |guard| { + let mut i = 0; + for account in guard.data.banned_accounts() { + info!("{}.{}", i, account.id); + i += 1; + } + }) + } + + Commands::Ban(args) => { + entry_mutex!(runtime, |guard| { + if let Some(account) = guard.data.online_accounts().get(args.index) { + if let Some(service_type) = guard.data.get_service_type(account) { + guard.ban_player(&Player::from(account.clone()), service_type); + info!("Account {} banned.", account.id); + } + } else { + warn!("Account number {} not found", args.index); + } + }) + } + + Commands::Pardon(args) => { + entry_mutex!(runtime, |guard| { + if let Some(account) = guard.data.banned_accounts().get(args.index) { + guard.pardon_player(&Player::from(account.clone())); + info!("Account {} pardoned.", account.id); + } else { + warn!("Account number {} not found", args.index); + } + }) + } + + Commands::Kick(args) => { + entry_mutex!(runtime, |guard| { + if let Some(account) = guard.data.online_accounts().get(args.index) { + if let Some(service_type) = guard.data.get_service_type(account) { + guard.kick_player(&Player::from(account.clone()), service_type); + info!("Account {} kicked.", account.id); + } + } else { + warn!("Account number {} not found", args.index); + } + }) + } + + Commands::Event(args) => { + entry_mutex!(runtime, |guard| { + if let Some(account) = guard.data.online_accounts().get(args.index) { + if let Some(service_type) = guard.data.get_service_type(account) { + guard.send_event(account, args.event, service_type); + info!("Sent event {} to {}.", args.event, account.id); + } + } else { + warn!("Account number {} not found", args.index); + } + }) + } + + Commands::Message(args) => { + entry_mutex!(runtime, |guard| { + if let Some(account) = guard.data.online_accounts().get(args.index) { + if let Some(service_type) = guard.data.get_service_type(account) { + guard.send_message(account, args.msg.clone(), service_type); + info!("Sent message \"{}\" to {}.", args.msg, account.id); + } + } else { + warn!("Account number {} not found", args.index); + } + }) + } + + Commands::Pop => { + entry_mutex!(runtime, |guard| { + if let Some((account, message)) = guard.pop_event() { + info!("{}: {:?}", account.id, message); + } else { + info!("None") + } + }) + } + + Commands::PopAll => { + entry_mutex!(runtime, |guard| { + while let Some((account, message)) = guard.pop_event() { + info!("{}: {:?}", account.id, message); + } + }) + } } }
\ No newline at end of file diff --git a/core/src/data/game/runtime/implements.rs b/core/src/data/game/runtime/implements.rs index 62038ba..43a7dee 100644 --- a/core/src/data/game/runtime/implements.rs +++ b/core/src/data/game/runtime/implements.rs @@ -8,7 +8,8 @@ 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::enums::ExitReason::{YouAreBanned, YouAreKicked}; +use crate::data::message::enums::GameMessage::{EventTrigger, LetExit}; use crate::data::message::traits::MessageManager; use crate::data::player::structs::{Account, Player}; use crate::service::service_types::ServiceType; @@ -53,6 +54,28 @@ impl GameRuntime { } } + pub fn kick_player(&mut self, player: &Player, service_type: ServiceType) { + // Send a leave message to the pad_client and wait for it to actively disconnect + if self.data.is_account_online(&player.account) { + self.send((player.account.clone(), LetExit(YouAreKicked)), player.account.clone(), service_type); + } + } + + pub fn ban_player(&mut self, player: &Player, service_type: ServiceType) { + if self.data.is_account_online(&player.account) { + self.send((player.account.clone(), LetExit(YouAreBanned)), player.account.clone(), service_type); + entry_mutex!(self.data.players_banned, |guard| { + guard.insert(player.account.clone(), player.clone()); + }); + } + } + + pub fn pardon_player(&mut self, player: &Player) { + entry_mutex!(self.data.players_banned, |guard| { + guard.remove(&player.account); + }); + } + /// Check if the game is locked pub fn is_game_locked(&self) -> bool { self.data.locked.load(SeqCst) @@ -81,6 +104,36 @@ impl GameRuntime { info!("[Game Runtime] Game closed!"); } } + + /// Send a GameMessage to account + pub fn send_game_message(&mut self, account: &Account, message: GameMessage, service_type: ServiceType) { + self.send((account.clone(), message), account.clone(), service_type); + } + + pub fn send_event(&mut self, account: &Account, event_trigger: u8, service_type: ServiceType) { + self.send_game_message(account, EventTrigger(event_trigger), service_type); + } + + pub fn send_message(&mut self, account: &Account, message: String, service_type: ServiceType) { + self.send_game_message(account, GameMessage::Msg(message), service_type); + } + + /// Pop an event message + pub fn pop_event(&mut self) -> Option<(Account, ControlMessage)> { + let pop = self.control.events.pop_front(); + if pop.is_some() { + let (account, msg) = pop.unwrap(); + if self.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 + } + } } /// Message manager for game pad_client runtime @@ -119,6 +172,7 @@ impl Default for GameRuntimeData { send: Default::default(), players_online: Players::default(), players_banned: Players::default(), + account_service_type: Default::default(), locked: AtomicBool::new(false), close: AtomicBool::new(false) @@ -160,6 +214,12 @@ impl GameRuntimeData { }); info!("[Game Runtime] Signed player \"{}\" is [ONLINE]!", player.account); + + // Record service type + entry_mutex!(self.account_service_type, |guard| { + guard.entry(player.account.clone()) + .or_insert_with(|| TCPConnection); + }) } } @@ -204,6 +264,15 @@ impl GameRuntimeData { }); false } + + /// Get service type of account + pub fn get_service_type(&self, account: &Account) -> Option<ServiceType> { + let mut result = None; + entry_mutex!(self.account_service_type, |guard| { + result = guard.get(account).cloned(); + }); + result + } } impl GameControlRuntime { @@ -265,23 +334,6 @@ impl GameControlRuntime { } } - /// 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) diff --git a/core/src/data/game/runtime/structs.rs b/core/src/data/game/runtime/structs.rs index bf68424..c6e005f 100644 --- a/core/src/data/game/runtime/structs.rs +++ b/core/src/data/game/runtime/structs.rs @@ -1,5 +1,6 @@ use std::collections::{HashMap, VecDeque}; use std::sync::atomic::AtomicBool; +use std::sync::Mutex; use crate::data::game::structs::GameControlData; use crate::data::game::types::{GameInfo, Players}; use crate::data::message::enums::{ControlMessage, GameMessage}; @@ -25,6 +26,7 @@ pub struct GameRuntimeData { pub(crate) players_online: Players, pub(crate) players_banned: Players, + pub(crate) account_service_type: Mutex<HashMap<Account, ServiceType>>, pub locked: AtomicBool, pub close: AtomicBool, diff --git a/core/src/service/tcp_network/pad_client/implements.rs b/core/src/service/tcp_network/pad_client/implements.rs index 584bc83..021b325 100644 --- a/core/src/service/tcp_network/pad_client/implements.rs +++ b/core/src/service/tcp_network/pad_client/implements.rs @@ -10,6 +10,7 @@ use crate::data::controller::runtime::structs::ControllerRuntime; use crate::data::message::enums::ConnectionMessage::{Join, RequestGameInfos}; use crate::data::message::enums::ConnectionResponseMessage; use crate::service::service_runner::NoGamepadsService; +use crate::service::service_types::ServiceType; use crate::service::tcp_network::pad_client::structs::PadClientNetwork; use crate::service::tcp_network::DEFAULT_PORT; use crate::service::tcp_network::utils::stream_utils::{read_msg, send_msg}; @@ -34,6 +35,10 @@ macro_rules! connect_once { impl PadClientNetwork { pub fn build(runtime: Arc<Mutex<ControllerRuntime>>) -> PadClientNetwork { + entry_mutex!(runtime, |guard| { + guard.service_type = ServiceType::TCPConnection; + }); + PadClientNetwork { addr: SocketAddr::from(([127, 0, 0, 1], DEFAULT_PORT)), runtime |
