You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
468 lines
15 KiB
468 lines
15 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
|
|
namespace Sog.IO
|
|
{
|
|
//GM指令
|
|
public enum GMBroadCastType
|
|
{
|
|
GMBroadCastType_None = 0, //随便,可以广播,也可以不广播
|
|
GMBroadCastType_CanNotBroad = 1, //禁止广播
|
|
GMBroadCastType_MustBroad = 2, //一定要广播
|
|
}
|
|
|
|
|
|
/**
|
|
* <summary>
|
|
* GM 指令标记,通过这个标记能够识别此方法的参数信息,类型和参数数量。方便客户端使用这些接口
|
|
* </summary>
|
|
*/
|
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
|
public class GmApiMapping : Attribute
|
|
{
|
|
public string Cmd;
|
|
public List<KeyValuePair<string, string>> Args;
|
|
public string Desc;
|
|
public string Help;
|
|
public GmGroup Group;
|
|
public bool Broadcast;
|
|
public bool Ignore; //客户端看不见得指令
|
|
|
|
public GmApiMapping(string cmd, string desc = "", bool broadcast = false)
|
|
{
|
|
this.Cmd = cmd; //若不定义,则默认用方法名作为cmd
|
|
this.Desc = desc;
|
|
this.Args = new List<KeyValuePair<string, string>>();
|
|
this.Broadcast = broadcast;
|
|
}
|
|
|
|
public GmApiMapping(string desc,bool broadcast = false,bool ignore =false)
|
|
{
|
|
this.Desc = desc; //若不定义,则默认用方法名作为cmd
|
|
this.Args = new List<KeyValuePair<string, string>>();
|
|
this.Broadcast = broadcast;
|
|
}
|
|
public GmApiMapping()
|
|
{
|
|
this.Args = new List<KeyValuePair<string, string>>();
|
|
}
|
|
|
|
public GmApiMapping(string desc, GmGroup group = GmGroup.SERVER, string help = "",bool ignore =false)
|
|
{
|
|
this.Desc = desc;
|
|
this.Args = new List<KeyValuePair<string, string>>();
|
|
this.Group = group;
|
|
this.Help = help;
|
|
this.Ignore = ignore;
|
|
}
|
|
public GmApiMapping(string desc,bool ignore =false)
|
|
{
|
|
this.Desc = desc;
|
|
this.Args = new List<KeyValuePair<string, string>>();
|
|
this.Ignore = ignore;
|
|
}
|
|
public GmApiMapping(string desc)
|
|
{
|
|
this.Desc = desc;
|
|
this.Args = new List<KeyValuePair<string, string>>();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 指令说明
|
|
/// -txxxx 指令目标,一般是uid
|
|
/// </summary>
|
|
public class GmCommandInfo
|
|
{
|
|
/// <summary>
|
|
/// 指令,比如AddExp
|
|
/// </summary>
|
|
public string Cmd;
|
|
|
|
/// <summary>
|
|
/// 帮助信息,比如AddExp expvalue -t10001; can level up
|
|
/// </summary>
|
|
public string HelpDesc;
|
|
|
|
/// <summary>
|
|
/// 调用函数,参数是uint userid, string[] params,返回值是int,0表示成功,非0失败
|
|
/// </summary>
|
|
public Func<long, string[], int> Function;
|
|
|
|
public GMBroadCastType broadCastType;
|
|
}
|
|
|
|
/// <summary>
|
|
/// GM指令注册和管理
|
|
/// </summary>
|
|
public class GmCommandMgr : Singleton<GmCommandMgr>
|
|
{
|
|
/// <summary>
|
|
/// gm指令做key,比如AddExp
|
|
/// </summary>
|
|
private Dictionary<string, GmCommandInfo> m_allGmCommand;
|
|
|
|
private Dictionary<string, MethodInfo> m_allGmMethods;
|
|
private List<GmApiMapping> _apiMappings;
|
|
|
|
public delegate void OnNotifyWorldBroadCastGMCmdToServer(long userId, string gmCmd, string cmdParams);
|
|
|
|
public OnNotifyWorldBroadCastGMCmdToServer NotifyWorldBroadCastGMCmdToServer;
|
|
|
|
public object agent;
|
|
|
|
public GmCommandMgr()
|
|
{
|
|
m_allGmCommand = new Dictionary<string, GmCommandInfo>();
|
|
m_allGmMethods = new Dictionary<string, MethodInfo>();
|
|
_apiMappings = new List<GmApiMapping>();
|
|
}
|
|
|
|
public void Init(object obj)
|
|
{
|
|
if (obj != null)
|
|
{
|
|
this.agent = obj;
|
|
}
|
|
}
|
|
|
|
public void Register(GmApiMapping mapping, MethodInfo method)
|
|
{
|
|
if (string.IsNullOrEmpty(mapping.Cmd))
|
|
{
|
|
mapping.Cmd = method.Name;
|
|
}
|
|
|
|
var cmd = mapping.Cmd;
|
|
|
|
var ps = method.GetParameters();
|
|
for (var i = 1; i < ps.Length; i++)
|
|
{
|
|
var parameter = ps[i];
|
|
var name = parameter.Name;
|
|
var type = parameter.ParameterType.Name;
|
|
mapping.Args.Add(new KeyValuePair<string, string>(name, type));
|
|
}
|
|
|
|
_apiMappings.Add(mapping);
|
|
m_allGmMethods[cmd.ToLower()] = method;
|
|
}
|
|
|
|
//但是 如果是需要广播 或者 不能广播的 但是请求的指令中-allserver不一致,就拒接执行
|
|
[Obsolete("不建议使用")]
|
|
public void Register(string gmcmd, string helpDesc, Func<long, string[], int> gmFun,
|
|
GMBroadCastType type = GMBroadCastType.GMBroadCastType_None)
|
|
{
|
|
if (gmFun == null)
|
|
{
|
|
TraceLog.Error("GmCommandMgr.Register cmd {0} invalid gmFun!", gmcmd);
|
|
return;
|
|
}
|
|
|
|
string lowcaseCmd = gmcmd.ToLower();
|
|
|
|
if (m_allGmCommand.ContainsKey(lowcaseCmd))
|
|
{
|
|
TraceLog.Error("GmCommandMgr.Register cmd {0} already registed!", gmcmd);
|
|
return;
|
|
}
|
|
|
|
TraceLog.Debug("GmCommandMgr.Register gmcmd {0} helpdesc [{1}] success", gmcmd, helpDesc);
|
|
|
|
GmCommandInfo info = new GmCommandInfo();
|
|
info.Cmd = gmcmd;
|
|
info.HelpDesc = helpDesc;
|
|
info.Function = gmFun;
|
|
info.broadCastType = type;
|
|
|
|
m_allGmCommand.Add(lowcaseCmd, info);
|
|
}
|
|
|
|
public void ClearAll()
|
|
{
|
|
TraceLog.Debug("GmCommandMgr.ClearAll clear all registed gmcmd");
|
|
m_allGmCommand.Clear();
|
|
}
|
|
|
|
|
|
public int HandlerGmCommand(string gmcmd, long userid, string[] gmCmdParams, bool needBroadCast, bool handleWorld = false)
|
|
{
|
|
string lowcaseCmd = gmcmd.ToLower();
|
|
|
|
if (! m_allGmCommand.ContainsKey(lowcaseCmd))
|
|
{
|
|
return HandlerGmCommandV2(gmcmd,userid,gmCmdParams,needBroadCast,handleWorld);
|
|
}
|
|
|
|
GmCommandInfo info = m_allGmCommand[lowcaseCmd];
|
|
|
|
//要不要这么严格控制?
|
|
if (needBroadCast)
|
|
{
|
|
if (info.broadCastType == GMBroadCastType.GMBroadCastType_CanNotBroad)
|
|
{
|
|
TraceLog.Error("GmCommandMgr.HandlerGmCommand cmd {0} cannot broadcast,but param require broadcast", gmcmd);
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (info.broadCastType == GMBroadCastType.GMBroadCastType_MustBroad)
|
|
{
|
|
TraceLog.Error("GmCommandMgr.HandlerGmCommand cmd {0} must broadcast, but param require not broadcast", gmcmd);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int ret = 0;
|
|
if (!handleWorld && needBroadCast && NotifyWorldBroadCastGMCmdToServer != null)
|
|
{
|
|
string cmdParams = string.Empty;
|
|
foreach (var gmparam in gmCmdParams)
|
|
{
|
|
cmdParams += gmparam + " ";
|
|
}
|
|
|
|
NotifyWorldBroadCastGMCmdToServer(userid, lowcaseCmd, cmdParams);
|
|
}
|
|
else
|
|
{
|
|
ret = info.Function(userid, gmCmdParams);
|
|
}
|
|
|
|
TraceLog.Debug("GmCommandMgr.HandlerGmCommand gmcmd {0} ret {1}", gmcmd, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**
|
|
* 支持注解模式的GM指令
|
|
*/
|
|
public int HandlerGmCommandV2(string gmcmd, long userid, string[] gmCmdParams, bool needBroadCast,
|
|
bool handleWorld = false)
|
|
{
|
|
string lowcaseCmd = gmcmd.ToLower();
|
|
if (!m_allGmMethods.ContainsKey(lowcaseCmd))
|
|
{
|
|
TraceLog.Error("GmCommandMgr.HandlerGmCommand cmd {0} not be registed,please check", gmcmd);
|
|
return -1;
|
|
}
|
|
|
|
int ret = 0;
|
|
if (!handleWorld && needBroadCast && NotifyWorldBroadCastGMCmdToServer != null)
|
|
{
|
|
string cmdParams = string.Empty;
|
|
foreach (var gmparam in gmCmdParams)
|
|
{
|
|
cmdParams += gmparam + " ";
|
|
}
|
|
|
|
NotifyWorldBroadCastGMCmdToServer(userid, lowcaseCmd, cmdParams);
|
|
}
|
|
else
|
|
{
|
|
var parameters = new List<object> { userid };
|
|
var method = m_allGmMethods[lowcaseCmd];
|
|
var ps = method.GetParameters();
|
|
for (var i = 1; i < ps.Length; i++)
|
|
{
|
|
var defaultVal = ps[i].DefaultValue;
|
|
var defaultType = ps[i].ParameterType;
|
|
|
|
if ((i - 1) < gmCmdParams.Length)
|
|
{
|
|
defaultVal = gmCmdParams[i - 1];
|
|
}
|
|
|
|
defaultVal ??= "";
|
|
try
|
|
{
|
|
var v = GetParamsValByType(defaultType, defaultVal.ToString());
|
|
parameters.Add(v);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
TraceLog.Error("GmCommandMgr.HandlerGmCommand gmcmd input params error", gmcmd, ret);
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
|
|
if (gmCmdParams.Length != parameters.Count-1)
|
|
{
|
|
TraceLog.Error("GmCommandMgr.HandlerGmCommand gm params error,cmd {0} params {1}", gmcmd,
|
|
gmCmdParams.Length);
|
|
return -1;
|
|
}
|
|
|
|
try
|
|
{
|
|
var rt = method.Invoke(agent, parameters.ToArray());
|
|
ret = int.Parse(rt?.ToString() ?? "0");
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
TraceLog.Error(
|
|
"GmCommandMgr.HandlerGmCommand invoke method error cmd={0},params count={1},message={2} stackTrace={3}", gmcmd,
|
|
parameters.Count, e.Message,e.StackTrace);
|
|
return -1;
|
|
}
|
|
|
|
|
|
TraceLog.Debug("GmCommandMgr.HandlerGmCommand gmcmd {0} ret {1}", gmcmd, ret);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
private static object GetParamsValByType(MemberInfo type, string value)
|
|
{
|
|
//可扩展别的类型
|
|
switch (type.Name)
|
|
{
|
|
case "Int32":
|
|
return int.Parse(value);
|
|
break;
|
|
case "Int64":
|
|
return long.Parse(value);
|
|
break;
|
|
case "Double":
|
|
return double.Parse(value);
|
|
break;
|
|
case "UInt32":
|
|
return uint.Parse(value);
|
|
break;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
public int HandlerGmCommandBySplit(string[] splitStr)
|
|
{
|
|
List<string> initgmCmdParams = new List<string>();
|
|
|
|
string gmcmd = splitStr[1];
|
|
|
|
string lowcaseCmd = gmcmd.ToLower();
|
|
|
|
long userid = 0;
|
|
|
|
|
|
List<string> paramList = new List<string>();
|
|
paramList.AddRange(splitStr);
|
|
|
|
bool needBroadCast = false;
|
|
|
|
for (int i = 2; i < paramList.Count; i++)
|
|
{
|
|
string param = paramList[i];
|
|
// -txxxxx
|
|
if (param.Length >= 7 && param[0] == '-' && param[1] == 't')
|
|
{
|
|
string target = param.Substring(2);
|
|
long.TryParse(target, out userid);
|
|
|
|
continue;
|
|
}
|
|
|
|
// -t xxxxx
|
|
if (param == "-t")
|
|
{
|
|
if (i <= paramList.Count - 2)
|
|
{
|
|
i++;
|
|
|
|
string target = paramList[i];
|
|
|
|
long.TryParse(target, out userid);
|
|
|
|
continue;
|
|
}
|
|
|
|
//出错了,格式不对
|
|
TraceLog.Error("HandlerGmCommandBySplit cmd {0} -t param invalid,exp -t 10001", gmcmd);
|
|
return -2;
|
|
}
|
|
|
|
//代表需要所有的服务器知道,使用广播
|
|
//如果有 -allserver 同时又有 -t 的则需要广播给-t后的玩家指定的server
|
|
//如果有-t 没有-allserver 的则不广播,使用指令的时候自己控制好使用具体的哪台server执行指令
|
|
//如果有 -allserver 同时 玩家ID = 0,就要通知所用的server
|
|
//如果没有 -allserver 则不管,只在当台server执行指令
|
|
if (param.ToLower() == "-allserver")
|
|
{
|
|
needBroadCast = true;
|
|
continue;
|
|
}
|
|
|
|
//gm指令本身支持base64转码
|
|
//gmcmd AddChip 500000000 -t 1000001
|
|
//用base64编码替换AddChip后面的参数
|
|
//gmcmd AddChip -bNTAwMDAwMDAwIC10IDEwMDAwMDE=
|
|
//gmcmd AddChip -b NTAwMDAwMDAwIC10IDEwMDAwMDE=
|
|
//以上两种都可以
|
|
//处理一下base64编码参数
|
|
string base64 = null;
|
|
// -bxxxxx
|
|
if (param.Length >= 6 && param[0] == '-' && param[1] == 'b')
|
|
{
|
|
base64 = param.Substring(2);
|
|
}
|
|
|
|
if (param == "-b")
|
|
{
|
|
if (i <= paramList.Count - 2)
|
|
{
|
|
i++;
|
|
base64 = paramList[i];
|
|
}
|
|
}
|
|
|
|
if (base64 != null)
|
|
{
|
|
byte[] byte64 = Convert.FromBase64String(base64);
|
|
string decodeText = Encoding.UTF8.GetString(byte64);
|
|
string[] decodesplitStr = decodeText.Split(' ');
|
|
paramList.AddRange(decodesplitStr);
|
|
}
|
|
else
|
|
{
|
|
initgmCmdParams.Add(paramList[i]);
|
|
}
|
|
}
|
|
|
|
string[] gmCmdParams = initgmCmdParams.ToArray();
|
|
|
|
string allparamString = string.Empty;
|
|
for (int i = 0; i < gmCmdParams.Length; i++)
|
|
{
|
|
allparamString += gmCmdParams[i];
|
|
if (i != gmCmdParams.Length - 1)
|
|
{
|
|
allparamString += ' ';
|
|
}
|
|
}
|
|
|
|
TraceLog.Debug("ProcessShmCommand_GmCommand cmd:{0} userid {1} params {2}"
|
|
, gmcmd, userid, allparamString);
|
|
|
|
return GmCommandMgr.Instance.HandlerGmCommand(gmcmd, userid, gmCmdParams, needBroadCast);
|
|
}
|
|
|
|
|
|
public Dictionary<string, GmApiMapping> GetAllGmCmd()
|
|
{
|
|
var dictionary = new Dictionary<string, GmApiMapping>();
|
|
foreach (var info in _apiMappings)
|
|
{
|
|
dictionary[info.Cmd] = info;
|
|
}
|
|
|
|
return dictionary;
|
|
}
|
|
}
|
|
}
|