diff --git a/nap_gameserver/src/commands/mod.rs b/nap_gameserver/src/commands/mod.rs index 8480297..d976fe3 100644 --- a/nap_gameserver/src/commands/mod.rs +++ b/nap_gameserver/src/commands/mod.rs @@ -87,5 +87,6 @@ impl CommandManager { player::procedure "[player_uid] [procedure_id]" "changes current beginner procedure id, parameter -1 can be used for skipping it"; avatar::add "[player_uid] [avatar_id]" "gives avatar with specified id to player"; item::add_weapon "[player_uid] [weapon_id]" "gives weapon with specified id to player"; + player::kick "[player_uid] [reason]" "kick the specified player (reason is optional)"; } } diff --git a/nap_gameserver/src/commands/player.rs b/nap_gameserver/src/commands/player.rs index 0aeaea2..e0e00fe 100644 --- a/nap_gameserver/src/commands/player.rs +++ b/nap_gameserver/src/commands/player.rs @@ -1,5 +1,5 @@ use data::tables::{AvatarBaseID, ProcedureConfigID}; -use proto::PlayerSyncScNotify; +use proto::{DisconnectReason, DisconnectScNotify, PlayerSyncScNotify}; use crate::ServerState; @@ -126,3 +126,44 @@ pub async fn procedure( "successfully changed procedure_id to {procedure_id:?}" )) } + +pub async fn kick( + args: ArgSlice<'_>, + state: &ServerState, +) -> Result> { + const USAGE: &str = "Usage: player kick [player_uid]"; + + if args.len() > 2 { + return Ok(USAGE.to_string()); + } + + let uid = args[0].parse::()?; + let reason = match args.get(1) { + Some(arg) => match arg.parse::() { + Ok(val) => val, + Err(_err) => 1, + }, + None => 1, + }; + let reason_str = match DisconnectReason::try_from(reason) { + Ok(converted_enum) => converted_enum.as_str_name().to_owned(), + Err(_err) => reason.to_string(), + }; + + let Some(player_lock) = state.player_mgr.get_player(uid).await else { + return Ok(String::from("player not found")); + }; + + let session_id = player_lock.lock().await.current_session_id(); + + if let Some(session) = session_id.map(|id| state.session_mgr.get(id)).flatten() { + session + .notify(DisconnectScNotify { reason: reason }) + .await?; + tokio::time::sleep(tokio::time::Duration::from_millis(50)).await; + session.shutdown().await?; + Ok(format!("kicked player, uid: {uid}, reason: {reason_str}")) + } else { + Ok(format!("player uid: {uid} is not online yet.")) + } +} diff --git a/nap_gameserver/src/net/session.rs b/nap_gameserver/src/net/session.rs index f3457f6..b749992 100644 --- a/nap_gameserver/src/net/session.rs +++ b/nap_gameserver/src/net/session.rs @@ -247,4 +247,8 @@ impl NetSession { pub fn set_state(&self, state: NetSessionState) { self.state.store(state, std::sync::atomic::Ordering::SeqCst); } + + pub async fn shutdown(&self) -> Result<(), std::io::Error> { + self.writer.lock().await.shutdown().await + } } diff --git a/nap_proto/out/_.rs b/nap_proto/out/_.rs index eb6ccfb..447fe85 100644 --- a/nap_proto/out/_.rs +++ b/nap_proto/out/_.rs @@ -28249,8 +28249,8 @@ pub struct Flpgnabkedc { #[derive(proto_gen::XorFields)] #[allow(clippy::derive_partial_eq_without_eq)] #[derive(Clone, PartialEq, ::prost::Message)] -pub struct Igapopdfcef { - #[prost(enumeration = "Obpfhejepck", tag = "15")] +pub struct DisconnectScNotify { + #[prost(enumeration = "DisconnectReason", tag = "15")] pub reason: i32, } #[derive(proto_gen::CmdID)] @@ -54259,9 +54259,9 @@ pub enum ItemStatic { FrontendGold = 10, GameDiamond = 100, RechargeDiamond = 101, - Lcdlfoheaim = 110, - Mndhfchkhcl = 111, - Fcffdnjnemf = 112, + GachaTicketStandard = 110, + GachaTicketEvent = 111, + GachaTicketBangboo = 112, Exp = 201, Energy = 501, Gdglcfmgoji = 3000001, @@ -54280,9 +54280,9 @@ impl ItemStatic { ItemStatic::FrontendGold => "ITEM_STATIC_FRONTEND_GOLD", ItemStatic::GameDiamond => "ITEM_STATIC_GAME_DIAMOND", ItemStatic::RechargeDiamond => "ITEM_STATIC_RECHARGE_DIAMOND", - ItemStatic::Lcdlfoheaim => "ItemStatic_LCDLFOHEAIM", - ItemStatic::Mndhfchkhcl => "ItemStatic_MNDHFCHKHCL", - ItemStatic::Fcffdnjnemf => "ItemStatic_FCFFDNJNEMF", + ItemStatic::GachaTicketStandard => "ItemStatic_GACHA_TICKET_STANDARD", + ItemStatic::GachaTicketEvent => "ItemStatic_GACHA_TICKET_EVENT", + ItemStatic::GachaTicketBangboo => "ItemStatic_GACHA_TICKET_BANGBOO", ItemStatic::Exp => "ITEM_STATIC_EXP", ItemStatic::Energy => "ITEM_STATIC_ENERGY", ItemStatic::Gdglcfmgoji => "ItemStatic_GDGLCFMGOJI", @@ -54298,9 +54298,9 @@ impl ItemStatic { "ITEM_STATIC_FRONTEND_GOLD" => Some(Self::FrontendGold), "ITEM_STATIC_GAME_DIAMOND" => Some(Self::GameDiamond), "ITEM_STATIC_RECHARGE_DIAMOND" => Some(Self::RechargeDiamond), - "ItemStatic_LCDLFOHEAIM" => Some(Self::Lcdlfoheaim), - "ItemStatic_MNDHFCHKHCL" => Some(Self::Mndhfchkhcl), - "ItemStatic_FCFFDNJNEMF" => Some(Self::Fcffdnjnemf), + "ItemStatic_GACHA_TICKET_STANDARD" => Some(Self::GachaTicketStandard), + "ItemStatic_GACHA_TICKET_EVENT" => Some(Self::GachaTicketEvent), + "ItemStatic_GACHA_TICKET_BANGBOO" => Some(Self::GachaTicketBangboo), "ITEM_STATIC_EXP" => Some(Self::Exp), "ITEM_STATIC_ENERGY" => Some(Self::Energy), "ItemStatic_GDGLCFMGOJI" => Some(Self::Gdglcfmgoji), @@ -55320,50 +55320,62 @@ impl Jiedoddkipa { #[derive(proto_gen::XorFields)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] -pub enum Obpfhejepck { +pub enum DisconnectReason { Domjllafeac = 0, - Gdbjccehcdb = 1, + /// 您的账号在其他地方登录,请检查是否存在账号泄露风险,是否要重新登录游戏? + ServerRelogin = 1, Clcbejonokn = 2, - Jlimlghggke = 3, - Omjjggajcbh = 4, - Kdpiceebneb = 5, + /// 游戏正在维护中,请等维护完成后再尝试登录。 + ServerShutdown = 3, + /// UID:"3" + /// 您已掉线,请返回登录界面重试 + ServerKick = 4, + /// 登录状态已失效,请重新登录 + AccountPasswordChange = 5, + /// 您已断开链接,请重新登录 Nmcpihldicf = 6, + /// 您的卡死问题已处理完成,请重新登录游戏 Ihcmpplkgkn = 7, + /// 您的PSN™的好友关系已解绑,现在可自由处理游戏内好友关系 Lgjemnlahcp = 8, Mfgomdhiejh = 9, } -impl Obpfhejepck { +impl DisconnectReason { /// String value of the enum field names used in the ProtoBuf definition. /// /// The values are not transformed in any way and thus are considered stable /// (if the ProtoBuf definition does not change) and safe for programmatic use. pub fn as_str_name(&self) -> &'static str { match self { - Obpfhejepck::Domjllafeac => "OBPFHEJEPCK_DOMJLLAFEAC", - Obpfhejepck::Gdbjccehcdb => "OBPFHEJEPCK_GDBJCCEHCDB", - Obpfhejepck::Clcbejonokn => "OBPFHEJEPCK_CLCBEJONOKN", - Obpfhejepck::Jlimlghggke => "OBPFHEJEPCK_JLIMLGHGGKE", - Obpfhejepck::Omjjggajcbh => "OBPFHEJEPCK_OMJJGGAJCBH", - Obpfhejepck::Kdpiceebneb => "OBPFHEJEPCK_KDPICEEBNEB", - Obpfhejepck::Nmcpihldicf => "OBPFHEJEPCK_NMCPIHLDICF", - Obpfhejepck::Ihcmpplkgkn => "OBPFHEJEPCK_IHCMPPLKGKN", - Obpfhejepck::Lgjemnlahcp => "OBPFHEJEPCK_LGJEMNLAHCP", - Obpfhejepck::Mfgomdhiejh => "OBPFHEJEPCK_MFGOMDHIEJH", + DisconnectReason::Domjllafeac => "DISCONNECT_REASON_DOMJLLAFEAC", + DisconnectReason::ServerRelogin => "DISCONNECT_REASON_SERVER_RELOGIN", + DisconnectReason::Clcbejonokn => "DISCONNECT_REASON_CLCBEJONOKN", + DisconnectReason::ServerShutdown => "DISCONNECT_REASON_SERVER_SHUTDOWN", + DisconnectReason::ServerKick => "DISCONNECT_REASON_SERVER_KICK", + DisconnectReason::AccountPasswordChange => { + "DISCONNECT_REASON_ACCOUNT_PASSWORD_CHANGE" + } + DisconnectReason::Nmcpihldicf => "DISCONNECT_REASON_NMCPIHLDICF", + DisconnectReason::Ihcmpplkgkn => "DISCONNECT_REASON_IHCMPPLKGKN", + DisconnectReason::Lgjemnlahcp => "DISCONNECT_REASON_LGJEMNLAHCP", + DisconnectReason::Mfgomdhiejh => "DISCONNECT_REASON_MFGOMDHIEJH", } } /// Creates an enum from field names used in the ProtoBuf definition. pub fn from_str_name(value: &str) -> ::core::option::Option { match value { - "OBPFHEJEPCK_DOMJLLAFEAC" => Some(Self::Domjllafeac), - "OBPFHEJEPCK_GDBJCCEHCDB" => Some(Self::Gdbjccehcdb), - "OBPFHEJEPCK_CLCBEJONOKN" => Some(Self::Clcbejonokn), - "OBPFHEJEPCK_JLIMLGHGGKE" => Some(Self::Jlimlghggke), - "OBPFHEJEPCK_OMJJGGAJCBH" => Some(Self::Omjjggajcbh), - "OBPFHEJEPCK_KDPICEEBNEB" => Some(Self::Kdpiceebneb), - "OBPFHEJEPCK_NMCPIHLDICF" => Some(Self::Nmcpihldicf), - "OBPFHEJEPCK_IHCMPPLKGKN" => Some(Self::Ihcmpplkgkn), - "OBPFHEJEPCK_LGJEMNLAHCP" => Some(Self::Lgjemnlahcp), - "OBPFHEJEPCK_MFGOMDHIEJH" => Some(Self::Mfgomdhiejh), + "DISCONNECT_REASON_DOMJLLAFEAC" => Some(Self::Domjllafeac), + "DISCONNECT_REASON_SERVER_RELOGIN" => Some(Self::ServerRelogin), + "DISCONNECT_REASON_CLCBEJONOKN" => Some(Self::Clcbejonokn), + "DISCONNECT_REASON_SERVER_SHUTDOWN" => Some(Self::ServerShutdown), + "DISCONNECT_REASON_SERVER_KICK" => Some(Self::ServerKick), + "DISCONNECT_REASON_ACCOUNT_PASSWORD_CHANGE" => { + Some(Self::AccountPasswordChange) + } + "DISCONNECT_REASON_NMCPIHLDICF" => Some(Self::Nmcpihldicf), + "DISCONNECT_REASON_IHCMPPLKGKN" => Some(Self::Ihcmpplkgkn), + "DISCONNECT_REASON_LGJEMNLAHCP" => Some(Self::Lgjemnlahcp), + "DISCONNECT_REASON_MFGOMDHIEJH" => Some(Self::Mfgomdhiejh), _ => None, } }