aboutsummaryrefslogtreecommitdiff
path: root/core/src/data/game
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/data/game')
-rw-r--r--core/src/data/game/cli/cli_command.rs169
-rw-r--r--core/src/data/game/runtime/implements.rs88
-rw-r--r--core/src/data/game/runtime/structs.rs2
3 files changed, 239 insertions, 20 deletions
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,