using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Security.Claims; using Amazon.DynamoDBv2.Model; using Amazon.DynamoDBv2; using Microsoft.AspNetCore.Authentication.OAuth.Claims; using Google.Protobuf; using ServerCore; using ServerBase; using ServerCommon; using GameServer.PacketHandler; using MetaAssets; using static ClientToGameReq.Types; using static ClientToGameRes.Types; using static ClientToGameMessage.Types; using SESSION_ID = System.Int32; using WORLD_META_ID = System.UInt32; using META_ID = System.UInt32; using ENTITY_GUID = System.String; using ACCOUNT_ID = System.String; using OWNER_GUID = System.String; using USER_GUID = System.String; using CHARACTER_GUID = System.String; using ITEM_GUID = System.String; namespace GameServer; public class ChatCommand : Attribute { Dictionary command_base_map = new Dictionary(); public ChatCommand() { loadChatCommand(); } private void loadChatCommand() { // ChatCommand 클래스의 모든 메서드를 가져옵니다. var assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly in assemblies) { foreach (Type type in assembly.GetTypes()) { ChatCommandAttribute[] attributes = (ChatCommandAttribute[])type.GetCustomAttributes(typeof(ChatCommandAttribute), false); foreach (var attrib in attributes) { var command_key = attrib.getCommand(); if (command_key == null) { Log.getLogger().error($"ChatCommand Key is null !!!, in ChatCommandAttributes : {attrib.getHandlerClass().FullName}"); continue; } var handler_class = Activator.CreateInstance(attrib.getHandlerClass()) as ChatCommandBase; if (handler_class == null) { Log.getLogger().error($"Failed to create ChatCommand !!! : commandKey:{command_key}"); continue; } handler_class.setAuthAdminLevelType(attrib.getAdminLevel()); handler_class.setClassName(attrib.getHandlerClass().Name); if (command_base_map.TryAdd(command_key, handler_class) == false) { Log.getLogger().error($"Failed to TryAdd() !!!, Already added CommandKey !!! : commandKey:{command_key}"); continue; } } } } } public bool isCheatCommand(string input) { return input.StartsWith("//"); } public async Task HandleCommand(Player player, string input) { var tokenArr = input.Split(" ", 2); try { var command = tokenArr[0].Remove(0, 2); if (command_base_map.TryGetValue(command.ToLower(), out var handler_class) == false) { Log.getLogger().error($"Command Not Exist Command : {command.ToLower()}"); return false; } if (await hasAuthority(handler_class, player) == false) { return false; } if (tokenArr.Length > 1) { var args = tokenArr[1].Split(" ", StringSplitOptions.RemoveEmptyEntries); await handler_class.invoke(player, tokenArr[1], args); } else { await handler_class.invoke(player, String.Empty, new string[] { }); } } catch (TaskCanceledException e) { Log.getLogger().error($"TaskCanceledException !!!, Failed to perform in HandleCommand() !!! : exception:{e}, inputString:{input} - {player.toBasicString()}"); } catch (Exception e) { Log.getLogger().error($"Exception !!!, Failed to perform in HandleCommand() !!! : exception:{e}, inputString:{input} - {player.toBasicString()}"); return false; } return true; } private async Task hasAuthority(ChatCommandBase handlerClass, Player player) { await Task.CompletedTask; var server_config = ServerConfigHelper.getServerConfig(); NullReferenceCheckHelper.throwIfNull(server_config, () => $"server_config is null !!!"); // ServiceType.Dev 타입일 경우 무조건 치트 사용이 가능 하다. !!! if (server_config.ServiceType.Equals(ServiceType.Dev.ToString())) { return true; } // CheatCommandAlwaysAllow == true 일 경우 무조건 치트 사용이 가능 하다. !!! if (true == server_config.CheatCommandAlwaysAllow) { return true; } var account_attribute = player.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(account_attribute, () => $"account_attribute is null !!!"); var admin_level_type = account_attribute.AuthAdminLevelType; //여기에 유저 레벨이랑, 클래스에 할당된 레벨이랑 비교 필요 var class_admin_level_type = handlerClass.getAuthAddminLevelType(); if (class_admin_level_type.Contains(admin_level_type) == false) { Log.getLogger().info($"Not Match Admin LevelType !!! : className = {handlerClass.getAuthAddminLevelType().ToString()}, className:{handlerClass.getClassName()} - {player.toBasicString()}"); return false; } return true; } } [AttributeUsage(AttributeTargets.Class)] internal class ChatCommandAttribute : Attribute { readonly string m_cheat_comment; private readonly Type m_handler_class; private readonly HashSet m_auth_admin_level_type; public ChatCommandAttribute(string cheatCommend, Type handlerClass, params AuthAdminLevelType[] authAdminLevelType) { m_cheat_comment = cheatCommend; m_handler_class = handlerClass; m_auth_admin_level_type = new HashSet(authAdminLevelType); } public string getCommand() { return m_cheat_comment; } public HashSet getAdminLevel() { return m_auth_admin_level_type; } public Type getHandlerClass() { return m_handler_class; } } public abstract class ChatCommandBase { private HashSet m_auth_admin_level_type = new(); private string m_class_name = string.Empty; public void setAuthAdminLevelType(HashSet typeSet) { m_auth_admin_level_type = typeSet; } public HashSet getAuthAddminLevelType() { return m_auth_admin_level_type; } public void setClassName(string className) { m_class_name = className; } public string getClassName() { return m_class_name; } public virtual async Task invoke(Player player, string token, string[] args) { await Task.CompletedTask; } } [ChatCommandAttribute("sessionkeepalivetime", typeof(ChatCommandSessionKeepAliveTime), AuthAdminLevelType.Developer, AuthAdminLevelType.GmNormal, AuthAdminLevelType.GmSuper)] internal class ChatCommandSessionKeepAliveTime : ChatCommandBase { public override async Task invoke(Player player, string token, string[] args) { await Task.CompletedTask; Log.getLogger().info($"Call sessionkeepalivetime !!! - {player.toBasicString()}"); var result = new Result(); var err_msg = string.Empty; if (args.Length < 1) { err_msg = $"Not enough argument !!! : argCount:{args.Length} == 3 - {player.toBasicString()}"; Log.getLogger().error(err_msg); return; } var keep_alive_minutes = int.Parse(args[0]); var server_logic = GameServerApp.getServerLogic(); NullReferenceCheckHelper.throwIfNull(server_logic, () => $"server_logic is null !!! - {player.toBasicString()}"); var session = player as IEntityWithSession; NullReferenceCheckHelper.throwIfNull(session, () => $"session is null !!! - {player.toBasicString()}"); var timeout_ms = keep_alive_minutes * ConstValue.default_1_min_to_sec * ConstValue.default_1_sec_to_milisec; var net_server = server_logic.getProudNetListener().getNetServer(); NullReferenceCheckHelper.throwIfNull(net_server, () => $"net_server is null !!!"); net_server.SetTimeoutTimeMs(session.getHostId(), timeout_ms); } }