aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author1992414357@qq.com <1992414357@qq.com>2025-06-09 03:26:09 +0800
committer1992414357@qq.com <1992414357@qq.com>2025-06-09 03:26:09 +0800
commit8359c5391f1f87d1a29df94ae90d431d432bc344 (patch)
tree129101538b9cc45176e9a345583db22609134fe5
parent8db4f6af3421392fb75d4a2257d39a10bcefa493 (diff)
完成了控制台部分
-rw-r--r--console/src/bin/padc.rs22
-rw-r--r--core/src/data/controller/cli/cli_command.rs111
-rw-r--r--core/src/data/controller/runtime/implements.rs30
-rw-r--r--core/src/data/controller/runtime/structs.rs3
-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
-rw-r--r--core/src/service/tcp_network/pad_client/implements.rs5
-rw-r--r--export/dev/bin/padc.exebin2452992 -> 2831360 bytes
9 files changed, 399 insertions, 31 deletions
diff --git a/console/src/bin/padc.rs b/console/src/bin/padc.rs
index 742b6c2..3887dd2 100644
--- a/console/src/bin/padc.rs
+++ b/console/src/bin/padc.rs
@@ -14,6 +14,8 @@ use std::process::exit;
use std::str::FromStr;
use std::sync::Arc;
use log::LevelFilter;
+use tokio::signal::ctrl_c;
+use nogamepads::entry_mutex;
use nogamepads::logger_utils::logger_build;
use nogamepads_core::data::controller::cli::cli_command::{process_controller_cli, ControllerCli};
use nogamepads_core::data::controller::structs::ControllerData;
@@ -450,6 +452,16 @@ fn connect(data: &mut LocalData, args: ConnectArgs) {
logger_build(LevelFilter::Info);
}
+ // Ctrl + C
+ let shutdown_runtime = Arc::clone(&runtime);
+ let shutdown = async move {
+ let _ = ctrl_c().await;
+ entry_mutex!(shutdown_runtime, |guard| {
+ guard.close();
+ });
+ };
+ services.push(Box::pin(shutdown));
+
ServiceRunner::run(services);
}
}
@@ -510,6 +522,16 @@ fn listen(data: &mut LocalData, args: ListenArgs) {
logger_build(LevelFilter::Info);
}
+ // Ctrl + C
+ let shutdown_runtime = Arc::clone(&runtime);
+ let shutdown = async move {
+ let _ = ctrl_c().await;
+ entry_mutex!(shutdown_runtime, |guard| {
+ guard.close_game();
+ });
+ };
+ services.push(Box::pin(shutdown));
+
ServiceRunner::run(services);
}
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
diff --git a/export/dev/bin/padc.exe b/export/dev/bin/padc.exe
index 4630768..1f969da 100644
--- a/export/dev/bin/padc.exe
+++ b/export/dev/bin/padc.exe
Binary files differ