diff --git a/BNetServer/Services/ServiceDispatcher.cs b/BNetServer/Services/ServiceDispatcher.cs
index 7c22f5225..6cb9aff37 100644
--- a/BNetServer/Services/ServiceDispatcher.cs
+++ b/BNetServer/Services/ServiceDispatcher.cs
@@ -43,7 +43,6 @@ namespace BNetServer.Services
public void Dispatch(Session session, uint serviceHash, uint token, uint methodId, CodedInputStream stream)
{
- Log.outInfo(LogFilter.Server, "ServiceHash = {0}, methodId = {1}", serviceHash, methodId);
var action = _dispatchers.LookupByKey(serviceHash);
if (action != null)
action(session, serviceHash, token, methodId, stream);
diff --git a/Game/Game.csproj b/Game/Game.csproj
index f955ca2ee..7ced8b5cf 100644
--- a/Game/Game.csproj
+++ b/Game/Game.csproj
@@ -50,7 +50,7 @@
pdbonly
x64
prompt
- true
+ true
@@ -191,7 +191,7 @@
-
+
diff --git a/Game/Globals/Global.cs b/Game/Globals/Global.cs
index 9e199185b..bc165d9e9 100644
--- a/Game/Globals/Global.cs
+++ b/Game/Globals/Global.cs
@@ -34,6 +34,7 @@ using Game.PvP;
using Game.Scenarios;
using Game.Scripting;
using Game.SupportSystem;
+using Game.Services;
public static class Global
{
@@ -42,6 +43,7 @@ public static class Global
public static ObjectManager ObjectMgr { get { return ObjectManager.Instance; } }
public static WorldManager WorldMgr { get { return WorldManager.Instance; } }
public static RealmManager RealmMgr { get { return RealmManager.Instance; } }
+ public static ServiceDispatcher ServiceMgr { get { return ServiceDispatcher.Instance; } }
//Guild
public static GuildManager GuildMgr { get { return GuildManager.Instance; } }
diff --git a/Game/Handlers/BattlenetHandler.cs b/Game/Handlers/BattlenetHandler.cs
index 4db37d46c..5b5caa78a 100644
--- a/Game/Handlers/BattlenetHandler.cs
+++ b/Game/Handlers/BattlenetHandler.cs
@@ -29,17 +29,7 @@ namespace Game
[WorldPacketHandler(ClientOpcodes.BattlenetRequest, Status = SessionStatus.Authed)]
void HandleBattlenetRequest(BattlenetRequest request)
{
- var handler = ServiceManager.GetHandler((NameHash)request.Method.GetServiceHash(), request.Method.GetMethodId());
- if (handler == null)
- {
- Log.outError(LogFilter.Server, "No defined handler ServiceHash {0} MethodId {1} Sent by {2}", (NameHash)request.Method.GetServiceHash(), request.Method.GetMethodId(), GetPlayerInfo());
- }
- else
- {
- var status = handler.Invoke(this, new CodedInputStream(request.Data));
- if (status != BattlenetRpcErrorCode.Ok)
- SendBattlenetResponse(request.Method.GetServiceHash(), request.Method.GetMethodId(), status);
- }
+ Global.ServiceMgr.Dispatch(this, request.Method.GetServiceHash(), request.Method.Token, request.Method.GetMethodId(), new CodedInputStream(request.Data));
}
[WorldPacketHandler(ClientOpcodes.BattlenetRequestRealmListTicket, Status = SessionStatus.Authed)]
@@ -56,13 +46,13 @@ namespace Game
SendPacket(realmListTicket);
}
- public void SendBattlenetResponse(uint serviceHash, uint methodId, IMessage response)
+ public void SendBattlenetResponse(uint serviceHash, uint methodId, uint token, IMessage response)
{
Response bnetResponse = new Response();
bnetResponse.BnetStatus = BattlenetRpcErrorCode.Ok;
bnetResponse.Method.Type = MathFunctions.MakePair64(methodId, serviceHash);
bnetResponse.Method.ObjectId = 1;
- bnetResponse.Method.Token = _battlenetRequestToken++;
+ bnetResponse.Method.Token = token;
if (response.CalculateSize() != 0)
bnetResponse.Data.WriteBytes(response.ToByteArray());
@@ -70,13 +60,13 @@ namespace Game
SendPacket(bnetResponse);
}
- public void SendBattlenetResponse(uint serviceHash, uint methodId, BattlenetRpcErrorCode status)
+ public void SendBattlenetResponse(uint serviceHash, uint methodId, uint token, BattlenetRpcErrorCode status)
{
Response bnetResponse = new Response();
bnetResponse.BnetStatus = status;
bnetResponse.Method.Type = MathFunctions.MakePair64(methodId, serviceHash);
bnetResponse.Method.ObjectId = 1;
- bnetResponse.Method.Token = _battlenetRequestToken++;
+ bnetResponse.Method.Token = token;
SendPacket(bnetResponse);
}
diff --git a/Game/Services/GameUtilitiesService.cs b/Game/Services/GameUtilitiesService.cs
index 64effecda..6f11151ff 100644
--- a/Game/Services/GameUtilitiesService.cs
+++ b/Game/Services/GameUtilitiesService.cs
@@ -25,10 +25,144 @@ using System.Collections.Generic;
namespace Game
{
- public partial class WorldSession
+ class GameUtilitiesService : ServiceBase
{
- [BnetService(NameHash.GameUtilitiesService, 1)]
- BattlenetRpcErrorCode HandleProcessClientRequest(ClientRequest request)
+ public GameUtilitiesService(WorldSession session, uint serviceHash) : base(session, serviceHash) { }
+
+ public override void CallServerMethod(uint token, uint methodId, CodedInputStream stream)
+ {
+ switch (methodId)
+ {
+ case 1:
+ {
+ ClientRequest request = new ClientRequest();
+ request.MergeFrom(stream);
+
+
+ ClientResponse response = new ClientResponse();
+ BattlenetRpcErrorCode status = HandleProcessClientRequest(request, response);
+ Log.outDebug(LogFilter.ServiceProtobuf, "{0} Client called server method GameUtilitiesService.ProcessClientRequest(bgs.protocol.game_utilities.v1.ClientRequest: {1}) returned bgs.protocol.game_utilities.v1.ClientResponse: {2} status: {3}.",
+ GetCallerInfo(), request.ToString(), response.ToString(), status);
+ if (status == 0)
+ SendResponse(1, token, response);
+ else
+ SendResponse(1, token, status);
+ break;
+ }
+ case 2:
+ {
+ PresenceChannelCreatedRequest request = new PresenceChannelCreatedRequest();
+ request.MergeFrom(stream);
+
+
+ Bgs.Protocol.NoData response = new Bgs.Protocol.NoData();
+ BattlenetRpcErrorCode status = HandlePresenceChannelCreated(request, response);
+ Log.outDebug(LogFilter.ServiceProtobuf, "{0} Client called server method GameUtilitiesService.PresenceChannelCreated(bgs.protocol.game_utilities.v1.PresenceChannelCreatedRequest: {1}) returned bgs.protocol.NoData: {2} status: {3}.",
+ GetCallerInfo(), request.ToString(), response.ToString(), status);
+ if (status == 0)
+ SendResponse(2, token, response);
+ else
+ SendResponse(2, token, status);
+ break;
+ }
+ case 3:
+ {
+ GetPlayerVariablesRequest request = new GetPlayerVariablesRequest();
+ request.MergeFrom(stream);
+
+
+ GetPlayerVariablesResponse response = new GetPlayerVariablesResponse();
+ BattlenetRpcErrorCode status = HandleGetPlayerVariables(request, response);
+ Log.outDebug(LogFilter.ServiceProtobuf, "{0} Client called server method GameUtilitiesService.GetPlayerVariables(bgs.protocol.game_utilities.v1.GetPlayerVariablesRequest: {1}) returned bgs.protocol.game_utilities.v1.GetPlayerVariablesResponse: {2} status: {3}.",
+ GetCallerInfo(), request.ToString(), response.ToString(), status);
+ if (status == 0)
+ SendResponse(3, token, response);
+ else
+ SendResponse(3, token, status);
+ break;
+ }
+ case 6:
+ {
+ ServerRequest request = new ServerRequest();
+ request.MergeFrom(stream);
+
+
+ ServerResponse response = new ServerResponse();
+ BattlenetRpcErrorCode status = HandleProcessServerRequest(request, response);
+ Log.outDebug(LogFilter.ServiceProtobuf, "{0} Client called server method GameUtilitiesService.ProcessServerRequest(bgs.protocol.game_utilities.v1.ServerRequest: {1}) returned bgs.protocol.game_utilities.v1.ServerResponse: {2} status: {3}.",
+ GetCallerInfo(), request.ToString(), response.ToString(), status);
+ if (status == 0)
+ SendResponse(6, token, response);
+ else
+ SendResponse(6, token, status);
+ break;
+ }
+ case 7:
+ {
+ GameAccountOnlineNotification request = new GameAccountOnlineNotification();
+ request.MergeFrom(stream);
+
+
+ BattlenetRpcErrorCode status = HandleOnGameAccountOnline(request);
+ Log.outDebug(LogFilter.ServiceProtobuf, "{0} Client called server method GameUtilitiesService.OnGameAccountOnline(bgs.protocol.game_utilities.v1.GameAccountOnlineNotification: {1}) status: {2}.",
+ GetCallerInfo(), request.ToString(), status);
+ if (status != 0)
+ SendResponse(7, token, status);
+ break;
+ }
+ case 8:
+ {
+ GameAccountOfflineNotification request = new GameAccountOfflineNotification();
+ request.MergeFrom(stream);
+
+
+ BattlenetRpcErrorCode status = HandleOnGameAccountOffline(request);
+ Log.outDebug(LogFilter.ServiceProtobuf, "{0} Client called server method GameUtilitiesService.OnGameAccountOffline(bgs.protocol.game_utilities.v1.GameAccountOfflineNotification: {1}) status: {2}.",
+ GetCallerInfo(), request.ToString(), status);
+ if (status != 0)
+ SendResponse(8, token, status);
+ break;
+ }
+ case 9:
+ {
+ GetAchievementsFileRequest request = new GetAchievementsFileRequest();
+ request.MergeFrom(stream);
+
+
+ GetAchievementsFileResponse response = new GetAchievementsFileResponse();
+ BattlenetRpcErrorCode status = HandleGetAchievementsFile(request, response);
+ Log.outDebug(LogFilter.ServiceProtobuf, "{0} Client called server method GameUtilitiesService.GetAchievementsFile(bgs.protocol.game_utilities.v1.GetAchievementsFileRequest: {1}) returned bgs.protocol.game_utilities.v1.GetAchievementsFileResponse: {2} status: {3}.",
+ GetCallerInfo(), request.ToString(), response.ToString(), status);
+ if (status == 0)
+ SendResponse(9, token, response);
+ else
+ SendResponse(9, token, status);
+ break;
+ }
+ case 10:
+ {
+ GetAllValuesForAttributeRequest request = new GetAllValuesForAttributeRequest();
+ request.MergeFrom(stream);
+
+
+ GetAllValuesForAttributeResponse response = new GetAllValuesForAttributeResponse();
+ BattlenetRpcErrorCode status = HandleGetAllValuesForAttribute(request, response);
+ Log.outDebug(LogFilter.ServiceProtobuf, "{0} Client called server method GameUtilitiesService.GetAllValuesForAttribute(bgs.protocol.game_utilities.v1.GetAllValuesForAttributeRequest: {1}) returned bgs.protocol.game_utilities.v1.GetAllValuesForAttributeResponse: {2} status: {3}.",
+ GetCallerInfo(), request.ToString(), response.ToString(), status);
+ if (status == 0)
+ SendResponse(10, token, response);
+ else
+ SendResponse(10, token, status);
+ break;
+ }
+ default:
+ Log.outError(LogFilter.ServiceProtobuf, "Bad method id {0}.", methodId);
+ SendResponse(methodId, token, BattlenetRpcErrorCode.RpcInvalidMethod);
+ break;
+ }
+ }
+
+ BattlenetRpcErrorCode HandleProcessClientRequest(ClientRequest request, ClientResponse response)
{
Bgs.Protocol.Attribute command = null;
Dictionary Params = new Dictionary();
@@ -43,73 +177,65 @@ namespace Game
if (command == null)
{
- Log.outError(LogFilter.SessionRpc, "{0} sent ClientRequest with no command.", GetPlayerInfo());
+ Log.outError(LogFilter.SessionRpc, "{0} sent ClientRequest with no command.", GetCallerInfo());
return BattlenetRpcErrorCode.RpcMalformedRequest;
}
- ClientResponse response = new ClientResponse();
- var status = BattlenetRpcErrorCode.RpcNotImplemented;
if (command.Name == "Command_RealmListRequest_v1_b9")
- status= HandleRealmListRequest(Params, response);
+ return HandleRealmListRequest(Params, response);
else if (command.Name == "Command_RealmJoinRequest_v1_b9")
- status= HandleRealmJoinRequest(Params, response);
+ return HandleRealmJoinRequest(Params, response);
- if (status == 0)
- SendBattlenetResponse((uint)NameHash.GameUtilitiesService, 1, response);
-
- return status;
- }
-
- [BnetService(NameHash.GameUtilitiesService, 2)]
- BattlenetRpcErrorCode HandlePresenceChannelCreated(PresenceChannelCreatedRequest request)
- {
- Log.outError(LogFilter.ServiceProtobuf, "{0} Client tried to call not implemented method GameUtilitiesService.PresenceChannelCreated: {1}", GetPlayerInfo(), request.ToString());
return BattlenetRpcErrorCode.RpcNotImplemented;
}
- [BnetService(NameHash.GameUtilitiesService, 3)]
- BattlenetRpcErrorCode HandleGetPlayerVariables(GetPlayerVariablesRequest request)
+ BattlenetRpcErrorCode HandlePresenceChannelCreated(PresenceChannelCreatedRequest request, Bgs.Protocol.NoData response)
{
- Log.outError(LogFilter.ServiceProtobuf, "{0} Client tried to call not implemented method GameUtilitiesService.GetPlayerVariables: {1}", GetPlayerInfo(), request.ToString());
+ Log.outError(LogFilter.ServiceProtobuf, "{0} Client tried to call not implemented method GameUtilitiesService.PresenceChannelCreated: {1}",
+ GetCallerInfo(), request.ToString());
return BattlenetRpcErrorCode.RpcNotImplemented;
}
- [BnetService(NameHash.GameUtilitiesService, 6)]
- BattlenetRpcErrorCode HandleProcessServerRequest(ServerRequest request)
+ BattlenetRpcErrorCode HandleGetPlayerVariables(GetPlayerVariablesRequest request, GetPlayerVariablesResponse response)
{
- Log.outError(LogFilter.ServiceProtobuf, "{0} Client tried to call not implemented method GameUtilitiesService.ProcessServerRequest: {1}", GetPlayerInfo(), request.ToString());
+ Log.outError(LogFilter.ServiceProtobuf, "{0} Client tried to call not implemented method GameUtilitiesService.GetPlayerVariables: {1}",
+ GetCallerInfo(), request.ToString());
+ return BattlenetRpcErrorCode.RpcNotImplemented;
+ }
+
+ BattlenetRpcErrorCode HandleProcessServerRequest(ServerRequest request, ServerResponse response)
+ {
+ Log.outError(LogFilter.ServiceProtobuf, "{0} Client tried to call not implemented method GameUtilitiesService.ProcessServerRequest: {1}",
+ GetCallerInfo(), request.ToString());
return BattlenetRpcErrorCode.RpcNotImplemented;
}
- [BnetService(NameHash.GameUtilitiesService, 7)]
BattlenetRpcErrorCode HandleOnGameAccountOnline(GameAccountOnlineNotification request)
{
- Log.outError(LogFilter.ServiceProtobuf, "{0} Client tried to call not implemented method GameUtilitiesService.OnGameAccountOnline: {1}", GetPlayerInfo(), request.ToString());
+ Log.outError(LogFilter.ServiceProtobuf, "{0} Client tried to call not implemented method GameUtilitiesService.OnGameAccountOnline: {1}",
+ GetCallerInfo(), request.ToString());
return BattlenetRpcErrorCode.RpcNotImplemented;
}
- [BnetService(NameHash.GameUtilitiesService, 8)]
BattlenetRpcErrorCode HandleOnGameAccountOffline(GameAccountOfflineNotification request)
{
- Log.outError(LogFilter.ServiceProtobuf, "{0} Client tried to call not implemented method GameUtilitiesService.OnGameAccountOffline: {1}", GetPlayerInfo(), request.ToString());
+ Log.outError(LogFilter.ServiceProtobuf, "{0} Client tried to call not implemented method GameUtilitiesService.OnGameAccountOffline: {1}",
+ GetCallerInfo(), request.ToString());
return BattlenetRpcErrorCode.RpcNotImplemented;
}
- [BnetService(NameHash.GameUtilitiesService, 9)]
- BattlenetRpcErrorCode HandleGetAchievementsFile(GetAchievementsFileRequest request)
+ BattlenetRpcErrorCode HandleGetAchievementsFile(GetAchievementsFileRequest request, GetAchievementsFileResponse response)
{
- Log.outError(LogFilter.ServiceProtobuf, "{0} Client tried to call not implemented method GameUtilitiesService.GetAchievementsFile: {1}", GetPlayerInfo(), request.ToString());
+ Log.outError(LogFilter.ServiceProtobuf, "{0} Client tried to call not implemented method GameUtilitiesService.GetAchievementsFile: {1}",
+ GetCallerInfo(), request.ToString());
return BattlenetRpcErrorCode.RpcNotImplemented;
}
- [BnetService(NameHash.GameUtilitiesService, 10)]
- BattlenetRpcErrorCode HandleGetAllValuesForAttribute(GetAllValuesForAttributeRequest request)
+ BattlenetRpcErrorCode HandleGetAllValuesForAttribute(GetAllValuesForAttributeRequest request, GetAllValuesForAttributeResponse response)
{
if (request.AttributeKey == "Command_RealmListRequest_v1_b9")
{
- GetAllValuesForAttributeResponse response = new GetAllValuesForAttributeResponse();
Global.RealmMgr.WriteSubRegions(response);
- SendBattlenetResponse((uint)NameHash.GameUtilitiesService, 10, response);
return BattlenetRpcErrorCode.Ok;
}
@@ -134,7 +260,7 @@ namespace Game
response.Attribute.Add(attribute);
var realmCharacterCounts = new RealmCharacterCountList();
- foreach (var characterCount in GetRealmCharacterCounts())
+ foreach (var characterCount in _session.GetRealmCharacterCounts())
{
RealmCharacterCountEntry countEntry = new RealmCharacterCountEntry();
countEntry.WowRealmAddress = (int)characterCount.Key;
@@ -155,8 +281,8 @@ namespace Game
{
var realmAddress = Params.LookupByKey("Param_RealmAddress");
if (realmAddress != null)
- return Global.RealmMgr.JoinRealm((uint)realmAddress.UintValue, Global.WorldMgr.GetRealm().Build, System.Net.IPAddress.Parse(GetRemoteAddress()), GetRealmListSecret(),
- GetSessionDbcLocale(), GetOS(), GetAccountName(), response);
+ return Global.RealmMgr.JoinRealm((uint)realmAddress.UintValue, Global.WorldMgr.GetRealm().Build, System.Net.IPAddress.Parse(_session.GetRemoteAddress()), _session.GetRealmListSecret(),
+ _session.GetSessionDbcLocale(), _session.GetOS(), _session.GetAccountName(), response);
return BattlenetRpcErrorCode.Ok;
}
diff --git a/Game/Services/ServiceDispatcher.cs b/Game/Services/ServiceDispatcher.cs
new file mode 100644
index 000000000..22cd2e68c
--- /dev/null
+++ b/Game/Services/ServiceDispatcher.cs
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2012-2016 CypherCore
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+using Framework.Constants;
+using Google.Protobuf;
+using System;
+using System.Collections.Generic;
+
+namespace Game.Services
+{
+ public class ServiceDispatcher : Singleton
+ {
+ ServiceDispatcher()
+ {
+ AddService(NameHash.GameUtilitiesService);
+ }
+
+ public void Dispatch(WorldSession session, uint serviceHash, uint token, uint methodId, CodedInputStream stream)
+ {
+ var action = _dispatchers.LookupByKey(serviceHash);
+ if (action != null)
+ action(session, serviceHash, token, methodId, stream);
+ else
+ Log.outDebug(LogFilter.SessionRpc, "{0} tried to call invalid service {1}", session.GetPlayerInfo(), serviceHash);
+ }
+
+ void AddService(NameHash OriginalHash) where Service : ServiceBase
+ {
+ _dispatchers[(uint)OriginalHash] = Dispatch;
+ }
+
+ void Dispatch(WorldSession session, uint serviceHash, uint token, uint methodId, CodedInputStream stream) where Service : ServiceBase
+ {
+ var obj = (Service)Activator.CreateInstance(typeof(Service), session, serviceHash);
+ obj.CallServerMethod(token, methodId, stream);
+ }
+
+ Dictionary _dispatchers = new Dictionary();
+
+ delegate void DispatcherHandler(WorldSession session, uint serviceHash, uint token, uint methodId, CodedInputStream stream);
+ }
+
+ abstract class ServiceBase
+ {
+ public ServiceBase(WorldSession session, uint serviceHash)
+ {
+ _session = session;
+ _serviceHash = serviceHash;
+ }
+
+ public abstract void CallServerMethod(uint token, uint methodId, CodedInputStream stream);
+
+ public void SendRequest(uint methodId, IMessage request, Action callback) { _session.SendBattlenetRequest(_serviceHash, methodId, request, callback); }
+ public void SendRequest(uint methodId, IMessage request) { _session.SendBattlenetRequest(_serviceHash, methodId, request); }
+ public void SendResponse(uint methodId, uint token, BattlenetRpcErrorCode status) { _session.SendBattlenetResponse(_serviceHash, methodId, token, status); }
+ public void SendResponse(uint methodId, uint token, IMessage response) { _session.SendBattlenetResponse(_serviceHash, methodId, token, response); }
+
+ public string GetCallerInfo()
+ {
+ return _session.GetPlayerInfo();
+ }
+
+ protected WorldSession _session;
+ protected uint _serviceHash;
+ }
+}
diff --git a/Game/Services/ServiceManager.cs b/Game/Services/ServiceManager.cs
deleted file mode 100644
index 8bfcc9813..000000000
--- a/Game/Services/ServiceManager.cs
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2012-2017 CypherCore
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-using Framework.Constants;
-using Google.Protobuf;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Reflection;
-
-namespace Game.Services
-{
- class ServiceManager
- {
- public static void Initialize()
- {
- Assembly currentAsm = Assembly.GetExecutingAssembly();
- foreach (var type in currentAsm.GetTypes())
- {
- foreach (var methodInfo in type.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic))
- {
- foreach (var msgAttr in methodInfo.GetCustomAttributes())
- {
- if (msgAttr == null)
- continue;
-
- if (_clientPacketTable.ContainsKey(msgAttr.Hash) && _clientPacketTable[msgAttr.Hash].ContainsKey(msgAttr.MethodId))
- {
- //Log.outError(LogFilter.Network, "Tried to override OpcodeHandler of {0} with {1} (Opcode {2})", _clientPacketTable[msgAttr.Opcode].ToString(), methodInfo.Name, msgAttr.Opcode);
- continue;
- }
-
- var parameters = methodInfo.GetParameters();
- if (parameters.Length == 0)
- {
- Log.outError(LogFilter.Network, "Method: {0} Has no paramters", methodInfo.Name);
- continue;
- }
-
- if (!_clientPacketTable.ContainsKey(msgAttr.Hash))
- _clientPacketTable[msgAttr.Hash] = new Dictionary();
-
- _clientPacketTable[msgAttr.Hash][msgAttr.MethodId] = new ServiceHandler(methodInfo, parameters[0].ParameterType);
- }
- }
- }
- }
-
- public static ServiceHandler GetHandler(NameHash hash, uint methodId)
- {
- if (!_clientPacketTable.ContainsKey(hash))
- return null;
-
- return _clientPacketTable[hash].LookupByKey(methodId);
- }
-
- static ConcurrentDictionary> _clientPacketTable = new ConcurrentDictionary>();
- }
-
- public class ServiceHandler
- {
- public ServiceHandler(MethodInfo info, Type type)
- {
- methodCaller = (Func)GetType().GetMethod("CreateDelegate", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(type).Invoke(null, new object[] { info });
- packetType = type;
- }
-
- public BattlenetRpcErrorCode Invoke(WorldSession session, CodedInputStream stream)
- {
- var request = (IMessage)Activator.CreateInstance(packetType);
- request.MergeFrom(stream);
-
- return methodCaller(session, request);
- }
-
- static Func CreateDelegate(MethodInfo method) where P1 : IMessage
- {
- // create first delegate. It is not fine because its
- // signature contains unknown types T and P1
- Func d = (Func)method.CreateDelegate(typeof(Func));
- // create another delegate having necessary signature.
- // It encapsulates first delegate with a closure
- return delegate (WorldSession target, IMessage p) { return d(target, (P1)p); };
- }
-
- Func methodCaller;
- Type packetType;
- }
-
- [AttributeUsage(AttributeTargets.Method)]
- public class BnetServiceAttribute : Attribute
- {
- public BnetServiceAttribute(NameHash hash, uint methodId)
- {
- Hash = hash;
- MethodId = methodId;
- }
-
- public NameHash Hash { get; }
- public uint MethodId { get; }
- }
-}