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

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;
}
}
}