aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
author1992414357@qq.com <1992414357@qq.com>2025-05-29 14:20:04 +0800
committer1992414357@qq.com <1992414357@qq.com>2025-05-29 14:20:04 +0800
commit3d23632d7c6330e0ec98dad53656dfed5f5767b0 (patch)
treed8d59726ca5b046b55ba502f1b8d5ba3a561a569 /core
parent9d3d6d4195e58c51166811d8357a331d53c4cdd4 (diff)
1. 优化了服务器的消息处理方式
2. 将c和c#的绑定移动到了./bindings/文件夹
Diffstat (limited to 'core')
-rw-r--r--core/Cargo.toml2
-rw-r--r--core/examples/start_client_console.rs8
-rw-r--r--core/examples/start_server_console.rs17
-rw-r--r--core/src/pad_data/game_layout.rs9
-rw-r--r--core/src/pad_data/layout.rs137
-rw-r--r--core/src/pad_data/mod.rs2
-rw-r--r--core/src/pad_service/client.rs25
-rw-r--r--core/src/pad_service/server.rs287
-rw-r--r--core/src/pad_service/server_debug_cli.rs64
9 files changed, 449 insertions, 102 deletions
diff --git a/core/Cargo.toml b/core/Cargo.toml
index e41697e..b4bfdb1 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -5,6 +5,7 @@ homepage = "https://github.com/CatilGrass/NoGamepads"
repository = "https://github.com/CatilGrass/NoGamepads"
readme = "../README.md"
+workspace = "../../NoGamepads"
edition = "2024"
[dependencies]
@@ -17,6 +18,7 @@ serde = { version = "1.0.219", features = ["derive"] }
clap = { version = "4.5.38", features = ["derive"] }
sha1 = "0.10.6"
log = "0.4.27"
+prettytable-rs = "0.10.0"
[lib]
name = "nogamepads_lib_rs"
diff --git a/core/examples/start_client_console.rs b/core/examples/start_client_console.rs
index 8116299..c4e0126 100644
--- a/core/examples/start_client_console.rs
+++ b/core/examples/start_client_console.rs
@@ -2,14 +2,14 @@ use std::net::{IpAddr, Ipv4Addr};
use nogamepads_lib_rs::pad_data::pad_player_info::nogamepads_player_info::PlayerInfo;
use nogamepads_lib_rs::pad_service::client::nogamepads_client::PadClient;
-const PASSWORD : &str = "password";
-
fn main() {
// 构建玩家信息
let mut player_info = PlayerInfo::new();
- player_info.setup_account_info("juliet", PASSWORD);
- player_info.set_nickname("Juliet_Smile");
+ player_info.setup_account_info(
+ env!("TEST_PLAYER_ACCOUNT"),
+ env!("TEST_PLAYER_PASSWORD"));
+ player_info.set_nickname(env!("TEST_PLAYER_NICKNAME"));
player_info.set_customize_color_hsv(320, 0.5, 1.0); // PINK
// 构建客户端
diff --git a/core/examples/start_server_console.rs b/core/examples/start_server_console.rs
index 560a378..cbe081f 100644
--- a/core/examples/start_server_console.rs
+++ b/core/examples/start_server_console.rs
@@ -11,10 +11,11 @@ fn main() {
// 构建服务端
let server = PadServer::default()
- .addr(
- IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
- DEFAULT_PORT
- )
+
+ // 地址
+ .addr(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), DEFAULT_PORT)
+
+ // 配置信息
.put_profile(
GameProfile::default()
.game_name("My Multiplayer Game")
@@ -22,6 +23,14 @@ fn main() {
.version("0.1 alpha")
.to_owned()
)
+
+ // 键位注册
+ .register_button(0, "Shoot")
+ .register_button(1, "Jump")
+ .register_direction(0, "Walk")
+ .register_axis(0, "View Yaw")
+
+ // 控制台
.enable_console()
// .quiet()
.build();
diff --git a/core/src/pad_data/game_layout.rs b/core/src/pad_data/game_layout.rs
deleted file mode 100644
index 62afbcc..0000000
--- a/core/src/pad_data/game_layout.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-pub mod game_layout {
- use bincode::{Decode, Encode};
- use serde::{Deserialize, Serialize};
-
- #[derive(Encode, Decode, Serialize, Deserialize, PartialEq, Debug)]
- pub struct GameLayout {
-
- }
-} \ No newline at end of file
diff --git a/core/src/pad_data/layout.rs b/core/src/pad_data/layout.rs
new file mode 100644
index 0000000..4c5f53f
--- /dev/null
+++ b/core/src/pad_data/layout.rs
@@ -0,0 +1,137 @@
+pub mod layout_data {
+ use std::collections::{HashMap, VecDeque};
+ use bincode::{Decode, Encode};
+ use serde::{Deserialize, Serialize};
+ use crate::pad_data::pad_messages::nogamepads_messages::ControlMessage;
+ use crate::pad_data::pad_player_info::nogamepads_player_info::PlayerInfo;
+ use crate::pad_service::server::nogamepads_server::PadServer;
+
+
+ #[derive(Encode, Decode, Serialize, Deserialize, PartialEq, Debug, Clone)]
+ pub struct LayoutKeyRegisters {
+ pub direction_keys : HashMap<u8, String>, // 注册方向键
+ pub axis_keys : HashMap<u8, String>, // 注册轴向键
+ pub button_keys : HashMap<u8, String>, // 注册按钮
+ }
+
+ impl Default for LayoutKeyRegisters {
+ fn default() -> LayoutKeyRegisters {
+ LayoutKeyRegisters {
+ direction_keys: Default::default(),
+ axis_keys: Default::default(),
+ button_keys: Default::default(),
+ }
+ }
+ }
+
+ pub struct LayoutKeyRuntimeData {
+ directions : HashMap<u8, HashMap<String, (f64, f64)>>, // <键, <玩家Hash, (x, y)>>
+ axes : HashMap<u8, HashMap<String, f64>>, // <键, <玩家Hash, 轴向>>
+ button : HashMap<u8, HashMap<String, bool>>, // <键, <玩家Hash, 是否按下>>
+
+ events : VecDeque<(String, ControlMessage)>, // (玩家Hash, 信息)
+ }
+
+ impl Default for LayoutKeyRuntimeData {
+ fn default() -> Self {
+ LayoutKeyRuntimeData {
+ directions: Default::default(),
+ axes: Default::default(),
+ button: Default::default(),
+ events: Default::default(),
+ }
+ }
+ }
+
+ impl LayoutKeyRuntimeData {
+
+ // 输入控制信息到数据
+ pub fn insert_control(&mut self, who: PlayerInfo, msg: ControlMessage) {
+ match msg {
+ // 消息放入信息队列待读取
+ ControlMessage::Msg(_) => {
+ self.events.push_back((who.account.player_hash, msg))
+ }
+
+ // 按钮更新对应玩家的状态,并且放入信息队列待读取
+ ControlMessage::Pressed(button_key) => {
+ self.button.entry(button_key)
+ .or_insert_with(HashMap::new)
+ .insert(who.account.player_hash.clone(), true);
+ self.events.push_back((who.account.player_hash, msg))
+ }
+ ControlMessage::Released(button_key) => {
+ self.button.entry(button_key)
+ .or_insert_with(HashMap::new)
+ .insert(who.account.player_hash.clone(), false);
+ self.events.push_back((who.account.player_hash, msg))
+ }
+
+ // 轴向更新直接传入玩家状态
+ ControlMessage::Axis(axis_key, axis) => {
+ self.axes.entry(axis_key)
+ .or_insert_with(HashMap::new)
+ .insert(who.account.player_hash.clone(), axis);
+ }
+ ControlMessage::Dir(dir_key, (x, y)) => {
+ self.directions.entry(dir_key)
+ .or_insert_with(HashMap::new)
+ .insert(who.account.player_hash.clone(), (x, y));
+ }
+ _ => { }
+ }
+ }
+
+ pub fn pop_control_event(&mut self, server: &PadServer) -> Option<(PlayerInfo, ControlMessage)> {
+ let pop = self.events.pop_front();
+ if pop.is_some() {
+ let (hash, msg) = pop.unwrap();
+ let info = server.find_online_player(hash);
+ if info.is_some() {
+ Some((info.unwrap(), msg))
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ }
+
+ pub fn get_direction(&self, who: &PlayerInfo, key: &u8) -> Option<(f64, f64)> {
+ Self::get(&self.directions, who, key)
+ }
+
+ pub fn get_axis(&self, who: &PlayerInfo, key: &u8) -> Option<f64> {
+ Self::get(&self.axes, who, key)
+ }
+
+ pub fn get_button_status(&self, who: &PlayerInfo, key: &u8) -> Option<bool> {
+ Self::get(&self.button, who, key)
+ }
+
+ fn get<V: Clone>(map: &HashMap<u8, HashMap<String, V>>, who: &PlayerInfo, key: &u8) -> Option<V> {
+ let key = map.get(key);
+ if key.is_some() {
+ let value = key.unwrap().get(&who.account.player_hash);
+ if value.is_some() {
+ let result = value.unwrap();
+ Some(result.clone())
+ } else { None }
+ } else { None }
+ }
+ }
+}
+
+pub mod layout_gamepad {
+ use bincode::{Decode, Encode};
+ use serde::{Deserialize, Serialize};
+
+ #[derive(Encode, Decode, Serialize, Deserialize, PartialEq, Debug)]
+ pub struct PadLayout {
+
+ }
+
+ pub trait ButtonArea {
+
+ }
+} \ No newline at end of file
diff --git a/core/src/pad_data/mod.rs b/core/src/pad_data/mod.rs
index 8ff024a..e041524 100644
--- a/core/src/pad_data/mod.rs
+++ b/core/src/pad_data/mod.rs
@@ -1,4 +1,4 @@
pub mod pad_messages;
pub mod pad_player_info;
pub mod game_profile;
-mod game_layout; \ No newline at end of file
+pub mod layout; \ No newline at end of file
diff --git a/core/src/pad_service/client.rs b/core/src/pad_service/client.rs
index c0b8282..ea0f4ba 100644
--- a/core/src/pad_service/client.rs
+++ b/core/src/pad_service/client.rs
@@ -21,6 +21,7 @@ pub mod nogamepads_client {
use crate::DEFAULT_PORT;
use crate::pad_data::game_profile::game_profile::GameProfile;
use crate::pad_data::pad_messages::nogamepads_message_encoder::NgpdMessageEncoder;
+ use crate::pad_data::pad_messages::nogamepads_messages::ControlMessage::{Axis, Dir, Msg, Pressed, Released};
type WriteList = Arc<Mutex<VecDeque<ControlMessage>>>;
type ReadList = Arc<Mutex<VecDeque<GameMessage>>>;
@@ -129,6 +130,30 @@ pub mod nogamepads_client {
// 客户端消息管理
impl PadClient {
+ pub fn key_press(&self, key_id: u8) {
+ self.put_msg(Pressed(key_id));
+ }
+
+ pub fn key_release(&self, key_id: u8) {
+ self.put_msg(Released(key_id));
+ }
+
+ pub fn change_axis(&self, axis_id: u8, axis: f64) {
+ self.put_msg(Axis(axis_id, axis));
+ }
+
+ pub fn change_direction(&self, direction_id: u8, x: f64, y: f64) {
+ self.put_msg(Dir(direction_id, (x.clamp(0.0, 1.0), y.clamp(0.0, 1.0))));
+ }
+
+ pub fn say_str(&self, msg: &str) {
+ self.put_msg(Msg(msg.to_owned()));
+ }
+
+ pub fn say(&self, msg: String) {
+ self.put_msg(Msg(msg));
+ }
+
pub fn put_msg(&self, msg: ControlMessage) {
let mut guard = self.write_list.lock().unwrap();
guard.push_back(msg);
diff --git a/core/src/pad_service/server.rs b/core/src/pad_service/server.rs
index 66ab56d..eeadb01 100644
--- a/core/src/pad_service/server.rs
+++ b/core/src/pad_service/server.rs
@@ -5,21 +5,24 @@ pub mod nogamepads_server {
use crate::pad_data::pad_messages::nogamepads_messages::{ConnectionCallbackMessage, ConnectionMessage, ControlMessage, GameMessage, LeaveReason};
use log::{error, info, warn};
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
+ use std::ops::Deref;
use std::process::exit;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::SeqCst;
use std::sync::{Arc, Mutex, MutexGuard, PoisonError};
use std::time::Duration;
use clap::CommandFactory;
+ use clearscreen::clear;
+ use prettytable::{Row, Table};
use tokio::io::{AsyncReadExt, AsyncWriteExt, ReadHalf, WriteHalf};
use tokio::net::{TcpListener, TcpStream};
- use tokio::{io, spawn};
+ use tokio::{io, signal, spawn};
use tokio::runtime::Runtime;
use nogamepads::console_utils::debug_console::read_cli;
- use nogamepads::convert_utils::convert_deque_to_vec;
use nogamepads::logger_utils::logger_build;
use crate::DEFAULT_PORT;
use crate::pad_data::game_profile::game_profile::GameProfile;
+ use crate::pad_data::layout::layout_data::{LayoutKeyRegisters, LayoutKeyRuntimeData};
use crate::pad_data::pad_messages::nogamepads_messages::ConnectionErrorType::{ContainSamePlayer, GameLocked, PlayerBanned, WhatTheHell};
use crate::pad_data::pad_messages::nogamepads_messages::GameMessage::Leave;
use crate::pad_data::pad_messages::nogamepads_messages::LeaveReason::ServerClosed;
@@ -28,7 +31,6 @@ pub mod nogamepads_server {
type PlayerMap = Arc<Mutex<HashMap<String, PlayerInfo>>>;
type WriteList = Arc<Mutex<HashMap<String, VecDeque<GameMessage>>>>;
- type ReadList = Arc<Mutex<HashMap<String, VecDeque<ControlMessage>>>>;
#[repr(C)]
pub struct PadServer {
@@ -50,13 +52,17 @@ pub mod nogamepads_server {
// 保持安静,不初始化 env_logger
quiet: bool,
+ // 键位表
+ keys: LayoutKeyRegisters,
+
// --- 运行时参数 ---
+
// 发送信息列表
write_list: WriteList,
- // 读取信息列表
- read_list: ReadList,
+ // 运行环境信息
+ control_data: Arc<Mutex<LayoutKeyRuntimeData>>,
// 在线玩家
online_players: PlayerMap,
@@ -69,6 +75,9 @@ pub mod nogamepads_server {
// 是否停止服务器
stop: AtomicBool,
+
+ // 调试模式 - 实时信息显示模式
+ monitor_view: AtomicBool,
}
impl Clone for PadServer {
@@ -79,13 +88,15 @@ pub mod nogamepads_server {
port: self.port.clone(),
enable_console: self.enable_console,
quiet: self.quiet,
+ keys: self.keys.clone(),
write_list: self.write_list.clone(),
- read_list: self.read_list.clone(),
+ control_data: self.control_data.clone(),
online_players: self.online_players.clone(),
banned_players: self.banned_players.clone(),
game_locked: AtomicBool::new((&self.game_locked.load(SeqCst)).clone()),
stop: AtomicBool::new((&self.stop.load(SeqCst)).clone()),
+ monitor_view: AtomicBool::new((&self.monitor_view.load(SeqCst)).clone())
}
}
}
@@ -98,13 +109,15 @@ pub mod nogamepads_server {
port: DEFAULT_PORT,
enable_console: false,
quiet: false,
+ keys: LayoutKeyRegisters::default(),
write_list: WriteList::default(),
- read_list: ReadList::default(),
+ control_data: Arc::new(Mutex::new(LayoutKeyRuntimeData::default())),
online_players: PlayerMap::default(),
banned_players: PlayerMap::default(),
game_locked: AtomicBool::new(false),
stop: AtomicBool::new(false),
+ monitor_view: AtomicBool::new(false),
}
}
}
@@ -151,10 +164,29 @@ pub mod nogamepads_server {
self
}
+ pub fn register_keys(&mut self, keys: LayoutKeyRegisters) -> &mut PadServer {
+ self.keys = keys;
+ self
+ }
+
+ pub fn register_button(&mut self, key: u8, name: &str) -> &mut PadServer {
+ self.keys.button_keys.insert(key, name.to_string());
+ self
+ }
+
+ pub fn register_axis(&mut self, key: u8, name: &str) -> &mut PadServer {
+ self.keys.axis_keys.insert(key, name.to_string());
+ self
+ }
+
+ pub fn register_direction(&mut self, key: u8, name: &str) -> &mut PadServer {
+ self.keys.direction_keys.insert(key, name.to_string());
+ self
+ }
+
pub fn build(&self) -> Arc<PadServer> {
Arc::new(self.clone())
}
-
}
// 服务端消息管理
@@ -189,43 +221,50 @@ pub mod nogamepads_server {
}
}
- pub fn pop_a_msg(&self, player: &PlayerInfo) -> Option<ControlMessage> {
- match self.read_list.lock() {
+ pub fn pop_a_msg(&self) -> Option<(PlayerInfo, ControlMessage)> {
+ match self.control_data.lock() {
Ok(mut guard) => {
- match guard.get_mut(&player.account.player_hash) {
- None => { None }
- Some(queue) => {
- if ! queue.is_empty() {
- queue.pop_front()
- } else {
- guard.remove(&player.account.player_hash);
- None
- }
- }
- }
+ guard.pop_control_event(self)
+ }
+ Err(_) => {
+ None
+ }
+ }
+ }
+ }
+
+ // 操控信息管理
+ impl PadServer {
+ pub fn get_player_direction(&self, player: &PlayerInfo, key: &u8) -> Option<(f64, f64)> {
+ match self.control_data.lock() {
+ Ok(guard) => {
+ guard.get_direction(player, &key)
}
Err(_) => {
- error!("Cannot lock \"{:?}\" in read_list", player.account.player_hash);
None
}
}
}
- pub fn pop_msg_or(&self, player: &PlayerInfo, or: ControlMessage) -> ControlMessage {
- self.pop_a_msg(player).unwrap_or(or)
+ pub fn get_player_axis(&self, player: &PlayerInfo, key: &u8) -> Option<f64> {
+ match self.control_data.lock() {
+ Ok(guard) => {
+ guard.get_axis(player, &key)
+ }
+ Err(_) => {
+ None
+ }
+ }
}
- pub fn list_received(&self, player: &PlayerInfo) -> Vec<ControlMessage> {
- match self.read_list.lock() {
+ pub fn get_player_button_status(&self, player: &PlayerInfo, key: &u8) -> Option<bool> {
+ match self.control_data.lock() {
Ok(guard) => {
- match guard.get_key_value(player.account.player_hash.as_str()) {
- None => { Vec::new() }
- Some(result) => {
- convert_deque_to_vec(result.1)
- }
- }
+ guard.get_button_status(player, &key)
+ }
+ Err(_) => {
+ None
}
- Err(_) => { Vec::new() }
}
}
}
@@ -303,6 +342,15 @@ pub mod nogamepads_server {
Err(err) => Err(err)
}
}
+
+ pub fn find_online_player(&self, hash: String) -> Option<PlayerInfo> {
+ match self.online_players.lock() {
+ Ok(guard) => {
+ guard.get(&hash).cloned()
+ }
+ Err(_) => None
+ }
+ }
}
// 服务端状态控制
@@ -360,6 +408,13 @@ pub mod nogamepads_server {
}
});
+ let ctrl_c_thread = spawn({
+ let client = Arc::clone(&self);
+ async move {
+ Self::process_ctrl_c(client).await
+ }
+ });
+
if debug {
let debug_cli = spawn({
let client = Arc::clone(&self);
@@ -368,9 +423,9 @@ pub mod nogamepads_server {
}
});
- let _ = tokio::join!(debug_cli, main_thread, background_thread);
+ let _ = tokio::join!(ctrl_c_thread, debug_cli, main_thread, background_thread);
} else {
- let _ = tokio::join!(main_thread, background_thread);
+ let _ = tokio::join!(ctrl_c_thread, main_thread, background_thread);
}
}
}
@@ -387,6 +442,14 @@ pub mod nogamepads_server {
self.game_locked.load(SeqCst)
}
+ pub fn enter_monitor(&self) {
+ self.monitor_view.store(true, SeqCst);
+ }
+
+ pub fn exit_monitor(&self) {
+ self.monitor_view.store(false, SeqCst);
+ }
+
async fn main_request_thread(self: Arc<Self>) {
let addr_str = format!("{}:{}", self.address.to_string(), self.port);
@@ -527,19 +590,19 @@ pub mod nogamepads_server {
Ok(0) => break,
Ok(n) => {
let msg = ControlMessage::de(buf[0..n].to_vec());
- {
- match self.read_list.lock() {
- Ok(mut guard) => {
- info!("{:?} from {}({})", &msg, player_info.customize.nickname, player_info.account.id);
- guard
- .entry(player_hash.clone())
- .or_insert_with(VecDeque::new)
- .push_back(msg);
-
- }
- Err(_) => {
+ match self.control_data.lock() {
+ Ok(mut guard) => {
+ info!("{:?} from {}({})", &msg, player_info.customize.nickname, player_info.account.id);
+ let player_info = self.find_online_player(player_hash.clone());
+ if player_info.is_some() {
+ let player_info = player_info.unwrap();
+ guard.insert_control(player_info, msg);
+ } else {
+ warn!("Player \"{}\" not found!", player_hash);
}
}
+ Err(_) => {
+ }
}
}
Err(e) => {
@@ -620,24 +683,136 @@ pub mod nogamepads_server {
}
}
+ async fn process_ctrl_c(self: Arc<Self>) {
+ loop {
+ signal::ctrl_c().await.unwrap();
+ if self.monitor_view.load(SeqCst) {
+ self.exit_monitor();
+ } else {
+ self.stop_server();
+ info!("Stopping server...");
+ break;
+ }
+ }
+ }
+
async fn process_debug_cli(self: Arc<Self>) {
loop {
if self.stop.load(SeqCst) {
info!("Debug console exited");
return;
}
- tokio::time::sleep(Duration::from_secs_f64(0.2)).await;
- let option: Option<Psc> = read_cli(
- format!("SERVER {}> ", self.address.to_string()).as_str(),
- "psc".to_string(),
- Psc::command()
- ).await;
- match option {
- None => {}
- Some(cmd) => {
- process_debug_cmd(cmd, Arc::clone(&self));
+
+ if ! self.monitor_view.load(SeqCst) {
+ tokio::time::sleep(Duration::from_secs_f64(0.2)).await;
+
+ // 控制台模式
+ let option: Option<Psc> = read_cli(
+ format!("SERVER {}> ", self.address.to_string()).as_str(),
+ "psc".to_string(),
+ Psc::command()
+ ).await;
+ match option {
+ None => {}
+ Some(cmd) => {
+ process_debug_cmd(cmd, Arc::clone(&self));
+ }
}
+ } else {
+ tokio::time::sleep(Duration::from_secs_f64(0.2)).await;
+
+ // 实时信息模式
+
+ // 表头文本
+ let mut header : Vec<String> = Vec::new();
+ header.push("PLAYER \\ KEYS".to_string());
+ self.all_keys(|key, name, i|{
+ if i == 0 {
+ header.push(format!("{}(btn:{})", name, key));
+ } else if i == 1 {
+ header.push(format!("{}(dir:{})", name, key));
+ } else if i == 2 {
+ header.push(format!("{}(ax:{})", name, key));
+ }
+ });
+
+ let mut info_table = Table::new();
+
+ // 添加表头
+ info_table.add_row(Row::from_iter(header));
+
+ // 玩家
+ let players = &self.deref().online_players;
+ match players.lock() {
+ Ok(guard) => {
+ for (_player_hash, player) in guard.iter() {
+
+ // 行
+ let mut line = Vec::new();
+ line.push(player.account.id.to_string());
+ self.all_keys(|key, _, i|{
+ if i == 0 {
+ // 按钮
+ let r = self.get_player_button_status(player, key);
+ if r.is_some() {
+ let r = r.unwrap();
+ if r {
+ line.push("TRUE".to_string());
+ } else {
+ line.push("FALSE".to_string());
+ }
+ } else {
+ line.push("UNKNOWN".to_string());
+ }
+
+ } else if i == 1 {
+ // 方向
+ let r = self.get_player_direction(player, key);
+ if r.is_some() {
+ let r = r.unwrap();
+ line.push(format!("{}, {}", r.0, r.1));
+ } else {
+ line.push("UNKNOWN".to_string());
+ }
+
+ } else if i == 2 {
+ // 轴向
+ let r = self.get_player_axis(player, key);
+ if r.is_some() {
+ let r = r.unwrap();
+ line.push(format!("{}", r));
+ } else {
+ line.push("UNKNOWN".to_string());
+ }
+ }
+ });
+
+ // 添加行文本
+ info_table.add_row(Row::from_iter(line));
+ }
+ }
+ Err(_) => {}
+ }
+
+ let result = info_table.to_string();
+ let _ = clear();
+ println!("[HELP] Ctrl + C to exit monitor.\n{}", result);
+ }
+ }
+ }
+
+ fn all_keys<F>(self: &Arc<Self>, mut f: F)
+ where F: FnMut(&u8, &String, i32){
+ let mut i = 0;
+ for iter in [
+ self.keys.button_keys.iter(),
+ self.keys.direction_keys.iter(),
+ self.keys.axis_keys.iter(),
+ ] {
+ for (key, name) in iter {
+ f(key, name, i);
}
+ i += 1;
}
}
}
diff --git a/core/src/pad_service/server_debug_cli.rs b/core/src/pad_service/server_debug_cli.rs
index ab9e5a5..ac52253 100644
--- a/core/src/pad_service/server_debug_cli.rs
+++ b/core/src/pad_service/server_debug_cli.rs
@@ -1,8 +1,7 @@
use std::collections::HashMap;
-use crate::pad_data::pad_messages::nogamepads_messages::{ControlMessage, GameMessage};
+use crate::pad_data::pad_messages::nogamepads_messages::{GameMessage};
use crate::pad_service::server::nogamepads_server::PadServer;
use clap::{Args, Parser, Subcommand};
-use std::ops::{Index};
use std::sync::{Arc, MutexGuard, PoisonError};
use log::{error, info};
use crate::pad_data::pad_player_info::nogamepads_player_info::PlayerInfo;
@@ -22,6 +21,9 @@ enum Commands {
#[command(about = "Clean the screen")]
Clear,
+ #[command(about = "Enter monitor")]
+ Monitor,
+
// 关闭服务器
#[command(about = "Close the server")]
Stop,
@@ -34,13 +36,9 @@ enum Commands {
#[command(about = "List all banned players")]
Banned,
- // 检查收到的消息
- #[command(about = "Check received")]
- Received(ReceivedArgs),
-
// 取出一条消息
#[command(about = "Pop a message")]
- Pop(PlayerArgs),
+ Pop,
// 踢出玩家
#[command(about = "Kick a player")]
@@ -54,6 +52,14 @@ enum Commands {
#[command(about = "Pardon a player")]
Pardon(PlayerArgs),
+ // 锁定游戏
+ #[command(about = "Lock this game")]
+ Lock,
+
+ // 解锁游戏
+ #[command(about = "Unlock this game")]
+ Unlock,
+
// 激活事件触发器
#[command(about = "Send SkinEventTrigger")]
Event(EventArgs)
@@ -98,6 +104,10 @@ pub fn process_debug_cmd (cmd: Psc, server: Arc<PadServer>) {
clearscreen::clear().expect("Failed to clear screen");
}
+ Commands::Monitor => {
+ server.enter_monitor();
+ }
+
Commands::Stop => {
server.stop_server();
}
@@ -110,27 +120,11 @@ pub fn process_debug_cmd (cmd: Psc, server: Arc<PadServer>) {
print_player_list(server.list_players_banned());
}
- Commands::Received(args) => {
- let players = server.list_players().unwrap_or(Vec::new());
- let player = players.index(args.player.clamp(0, players.iter().count() -1));
- if args.list {
- for msg in server.list_received(player) {
- info!("{:?}", msg);
- }
- } else {
- info!("Total {} messsage(s)!", server.list_received(player).iter().count());
- }
- }
-
- Commands::Pop(args) => {
- match get_player_by_index(&server, args.index) {
- None => {
- error!("Pup message failed : Player index \"{}\" not found!", args.index);
- }
- Some(player) => {
- let message = server.pop_msg_or(&player, ControlMessage::Err);
- info!("{:?}", message);
- }
+ Commands::Pop => {
+ let message = server.pop_a_msg();
+ if message.is_some() {
+ let (player, msg) = message.unwrap();
+ info!("{:?} from \"{}\"({})", msg, player.customize.nickname, player.account.id);
}
}
@@ -158,6 +152,20 @@ pub fn process_debug_cmd (cmd: Psc, server: Arc<PadServer>) {
}
}
+ Commands::Lock => {
+ if ! server.is_game_locked() {
+ server.lock_game();
+ info!("Game locked");
+ }
+ }
+
+ Commands::Unlock => {
+ if server.is_game_locked() {
+ server.unlock_game();
+ info!("Game unlocked");
+ }
+ }
+
Commands::Event(args) => {
put_to_list(server, args.index, GameMessage::SkinEventTrigger(args.message));
}