From c89fbd8ae5eba906384fe64fdfa51da15d609be0 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Thu, 29 Jun 2017 17:40:20 -0400 Subject: [PATCH] Fixed changing realms. Temp fix till i can come up with a better way. --- BNetServer/Services/ServiceDispatcher.cs | 1 - Game/Game.csproj | 4 +- Game/Globals/Global.cs | 2 + Game/Handlers/BattlenetHandler.cs | 20 +-- Game/Services/GameUtilitiesService.cs | 202 ++++++++++++++++++----- Game/Services/ServiceDispatcher.cs | 80 +++++++++ Game/Services/ServiceManager.cs | 116 ------------- 7 files changed, 253 insertions(+), 172 deletions(-) create mode 100644 Game/Services/ServiceDispatcher.cs delete mode 100644 Game/Services/ServiceManager.cs 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; } - } -}