WutheringWaves/GameServer/Handlers/Factory/MessageHandlerFactory.cs
2024-02-08 00:41:39 +03:00

56 lines
2.4 KiB
C#

using System.Collections.Immutable;
using System.Linq.Expressions;
using System.Reflection;
using GameServer.Handlers.Attributes;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Protocol;
namespace GameServer.Handlers.Factory;
internal class MessageHandlerFactory
{
private readonly ImmutableDictionary<MessageId, MessageHandler> s_messageHandlers;
public MessageHandlerFactory(ILogger<MessageHandlerFactory> logger)
{
IEnumerable<Type> handlerTypes = Assembly.GetExecutingAssembly().GetTypes()
.Where(t => t.IsAssignableTo(typeof(MessageHandlerBase)) && !t.IsAbstract);
s_messageHandlers = GenerateHandlerMethods(handlerTypes);
logger.LogInformation("Registered {count} message handlers", s_messageHandlers.Count);
}
public MessageHandler? GetHandler(MessageId messageId)
{
s_messageHandlers.TryGetValue(messageId, out MessageHandler? handler);
return handler;
}
private static ImmutableDictionary<MessageId, MessageHandler> GenerateHandlerMethods(IEnumerable<Type> handlerTypes)
{
var builder = ImmutableDictionary.CreateBuilder<MessageId, MessageHandler>();
MethodInfo getServiceMethod = typeof(ServiceProviderServiceExtensions).GetMethod("GetRequiredService", [typeof(IServiceProvider)])!;
foreach (Type type in handlerTypes)
{
IEnumerable<MethodInfo> methods = type.GetMethods()
.Where(method => method.GetCustomAttribute<MessageHandlerAttribute>() != null);
foreach (MethodInfo method in methods)
{
MessageHandlerAttribute attribute = method.GetCustomAttribute<MessageHandlerAttribute>()!;
ParameterExpression serviceProviderParam = Expression.Parameter(typeof(IServiceProvider));
ParameterExpression dataParam = Expression.Parameter(typeof(ReadOnlyMemory<byte>));
MethodCallExpression getServiceCall = Expression.Call(getServiceMethod.MakeGenericMethod(type), serviceProviderParam);
MethodCallExpression handlerCall = Expression.Call(getServiceCall, method, dataParam);
Expression<MessageHandler> lambda = Expression.Lambda<MessageHandler>(handlerCall, serviceProviderParam, dataParam);
builder.Add(attribute.MessageId, lambda.Compile());
}
}
return builder.ToImmutable();
}
}