From 1504809de2c01d55d68cdbf2477fd69b64ec06a0 Mon Sep 17 00:00:00 2001 From: Kaioru Date: Mon, 15 Apr 2024 20:39:18 +0800 Subject: [PATCH] Add bootstrap for login service --- Edelstein.sln | 7 + src/Directory.Packages.props | 2 + .../Bindings/StageConfigLogin.cs | 12 + .../Edelstein.Application.Server.csproj | 9 +- .../Edelstein.Application.Server/Program.cs | 31 +- .../ProgramHandler.cs | 67 +++ .../ServiceHostStage.cs | 55 ++ .../packages.lock.json | 165 ++++-- .../Edelstein.Common.Gameplay.Login.csproj | 7 +- .../LoginStageSystem.cs | 15 + .../LoginStageUser.cs | 13 + .../packages.lock.json | 131 ++++- .../AbstractStageSystem.cs | 21 + .../Edelstein.Common.Gameplay.csproj | 10 + .../Handling/IPacketHandler.cs | 15 + .../Handling/IPacketHandlerManager.cs | 15 + .../Handling/IPacketSerializer.cs | 11 + .../Handling/PacketHandlerManager.cs | 77 +++ .../Handling/PacketRecvOperations.cs | 320 +++++++++++ .../Handling/PacketSendOperations.cs | 513 ++++++++++++++++++ .../packages.lock.json | 138 +++++ .../Handlers/NettyTransportAcceptorHandler.cs | 35 +- .../NettyTransportConnectorHandler.cs | 36 +- .../NettyAttributes.cs | 1 - .../NettySocket.cs | 6 +- .../Transports/NettyTransportAcceptor.cs | 13 +- .../Transports/NettyTransportConnector.cs | 11 +- .../packages.lock.json | 11 +- .../packages.lock.json | 17 +- .../Templates/TemplateCollection.cs | 21 + .../Templates/TemplateCollectionLazy.cs | 21 + .../TemplateCollectionProviderEager.cs | 16 + .../TemplateCollectionProviderLazy.cs | 19 + .../TemplateCollectionProviderLazyHolder.cs | 7 + .../Templates/TemplateManager.cs | 26 + src/protocol/Directory.Build.props | 2 +- .../ILoginStage.cs | 3 - .../ILoginStageSystem.cs | 7 +- .../ILoginStageSystemOptions.cs | 2 +- .../ILoginStageUser.cs | 4 +- .../Edelstein.Protocol.Gameplay.csproj | 3 + .../Edelstein.Protocol.Gameplay/IStage.cs | 15 +- .../IStageSystem.cs | 14 +- .../Edelstein.Protocol.Gameplay/IStageUser.cs | 10 +- .../Edelstein.Protocol.Network/IAdapter.cs | 17 - .../IAdapterInitializer.cs | 6 - .../Edelstein.Protocol.Network/ISocket.cs | 6 +- .../ISocketAdapter.cs | 13 + .../Edelstein.Protocol.Network/ISocketUser.cs | 12 + .../ISocketUserCreator.cs | 7 + .../Templates/ITemplate.cs | 5 + .../Templates/ITemplateCollection.cs | 11 + .../Templates/ITemplateCollectionProvider.cs | 11 + .../Templates/ITemplateManager.cs | 8 + 54 files changed, 1846 insertions(+), 184 deletions(-) create mode 100644 src/app/Edelstein.Application.Server/Bindings/StageConfigLogin.cs create mode 100644 src/app/Edelstein.Application.Server/ProgramHandler.cs create mode 100644 src/app/Edelstein.Application.Server/ServiceHostStage.cs create mode 100644 src/common/Edelstein.Common.Gameplay.Login/LoginStageSystem.cs create mode 100644 src/common/Edelstein.Common.Gameplay.Login/LoginStageUser.cs create mode 100644 src/common/Edelstein.Common.Gameplay/AbstractStageSystem.cs create mode 100644 src/common/Edelstein.Common.Gameplay/Edelstein.Common.Gameplay.csproj create mode 100644 src/common/Edelstein.Common.Gameplay/Handling/IPacketHandler.cs create mode 100644 src/common/Edelstein.Common.Gameplay/Handling/IPacketHandlerManager.cs create mode 100644 src/common/Edelstein.Common.Gameplay/Handling/IPacketSerializer.cs create mode 100644 src/common/Edelstein.Common.Gameplay/Handling/PacketHandlerManager.cs create mode 100644 src/common/Edelstein.Common.Gameplay/Handling/PacketRecvOperations.cs create mode 100644 src/common/Edelstein.Common.Gameplay/Handling/PacketSendOperations.cs create mode 100644 src/common/Edelstein.Common.Gameplay/packages.lock.json create mode 100644 src/common/Edelstein.Common.Utilities/Templates/TemplateCollection.cs create mode 100644 src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionLazy.cs create mode 100644 src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionProviderEager.cs create mode 100644 src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionProviderLazy.cs create mode 100644 src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionProviderLazyHolder.cs create mode 100644 src/common/Edelstein.Common.Utilities/Templates/TemplateManager.cs delete mode 100644 src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStage.cs delete mode 100644 src/protocol/Edelstein.Protocol.Network/IAdapter.cs delete mode 100644 src/protocol/Edelstein.Protocol.Network/IAdapterInitializer.cs create mode 100644 src/protocol/Edelstein.Protocol.Network/ISocketAdapter.cs create mode 100644 src/protocol/Edelstein.Protocol.Network/ISocketUser.cs create mode 100644 src/protocol/Edelstein.Protocol.Network/ISocketUserCreator.cs create mode 100644 src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplate.cs create mode 100644 src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateCollection.cs create mode 100644 src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateCollectionProvider.cs create mode 100644 src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateManager.cs diff --git a/Edelstein.sln b/Edelstein.sln index 622c0397c..9ace93224 100644 --- a/Edelstein.sln +++ b/Edelstein.sln @@ -51,6 +51,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Edelstein.Common.Network.Do EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Edelstein.Common.Crypto", "src\common\Edelstein.Common.Crypto\Edelstein.Common.Crypto.csproj", "{2B8D2564-3DF1-42B2-9A50-0AAD2E8A8AE8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Edelstein.Common.Gameplay", "src\common\Edelstein.Common.Gameplay\Edelstein.Common.Gameplay.csproj", "{F66379E6-CAB8-4E63-BB0C-94B98F021A29}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -76,6 +78,7 @@ Global {406AF08D-7BF4-4C00-A959-60D5D4601295} = {82D7864B-19AD-484C-BD2E-897F05B5852C} {F94D12DC-FDC8-48F2-9EF0-7F229AF1A9CC} = {E50DFCDF-39D5-4D0D-A46E-94D11D795087} {2B8D2564-3DF1-42B2-9A50-0AAD2E8A8AE8} = {E50DFCDF-39D5-4D0D-A46E-94D11D795087} + {F66379E6-CAB8-4E63-BB0C-94B98F021A29} = {E50DFCDF-39D5-4D0D-A46E-94D11D795087} EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {5AA56CCA-0711-4F1E-956D-6A9ECB62AA6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU @@ -130,5 +133,9 @@ Global {2B8D2564-3DF1-42B2-9A50-0AAD2E8A8AE8}.Debug|Any CPU.Build.0 = Debug|Any CPU {2B8D2564-3DF1-42B2-9A50-0AAD2E8A8AE8}.Release|Any CPU.ActiveCfg = Release|Any CPU {2B8D2564-3DF1-42B2-9A50-0AAD2E8A8AE8}.Release|Any CPU.Build.0 = Release|Any CPU + {F66379E6-CAB8-4E63-BB0C-94B98F021A29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F66379E6-CAB8-4E63-BB0C-94B98F021A29}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F66379E6-CAB8-4E63-BB0C-94B98F021A29}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F66379E6-CAB8-4E63-BB0C-94B98F021A29}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 1758331b5..7bd172c66 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -12,6 +12,7 @@ + @@ -21,5 +22,6 @@ + \ No newline at end of file diff --git a/src/app/Edelstein.Application.Server/Bindings/StageConfigLogin.cs b/src/app/Edelstein.Application.Server/Bindings/StageConfigLogin.cs new file mode 100644 index 000000000..d80329b3e --- /dev/null +++ b/src/app/Edelstein.Application.Server/Bindings/StageConfigLogin.cs @@ -0,0 +1,12 @@ +using Edelstein.Protocol.Gameplay.Login; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Edelstein.Application.Server.Bindings; + +public record StageConfigLogin : ILoginStageSystemOptions +{ + public string ID { get; init; } + + public string Host { get; init; } + public int Port { get; init; } +} diff --git a/src/app/Edelstein.Application.Server/Edelstein.Application.Server.csproj b/src/app/Edelstein.Application.Server/Edelstein.Application.Server.csproj index 5f0796a79..57af7bb18 100644 --- a/src/app/Edelstein.Application.Server/Edelstein.Application.Server.csproj +++ b/src/app/Edelstein.Application.Server/Edelstein.Application.Server.csproj @@ -7,11 +7,7 @@ - - - - - + @@ -23,6 +19,7 @@ - + + diff --git a/src/app/Edelstein.Application.Server/Program.cs b/src/app/Edelstein.Application.Server/Program.cs index ca0429c19..073edd805 100644 --- a/src/app/Edelstein.Application.Server/Program.cs +++ b/src/app/Edelstein.Application.Server/Program.cs @@ -1,19 +1,18 @@ -using Edelstein.Common.Services.Server; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Serilog; +using System; +using System.CommandLine; +using System.IO; +using Edelstein.Application.Server; -var builder = Host.CreateApplicationBuilder(); +var commandRoot = new RootCommand( + "A mushroom game server emulator" +); +var argumentFile = new Argument( + "file or directory path", + () => new FileInfo(AppDomain.CurrentDomain.BaseDirectory), + "The file or directory path to stage json file(s)" +); -builder.Services.AddSerilog((_, logger) - => logger.ReadFrom.Configuration(builder.Configuration)); +commandRoot.AddArgument(argumentFile); +commandRoot.SetHandler(ProgramHandler.ExecuteRoot, argumentFile); -builder.Services.AddDbContextFactory(options - => options.UseNpgsql(builder.Configuration.GetConnectionString(ServerDbContext.ConnectionStringKey))); -builder.Services.AddAutoMapper(typeof(ServerDbContext)); - -var host = builder.Build(); - -await host.RunAsync(); +await commandRoot.InvokeAsync(args); diff --git a/src/app/Edelstein.Application.Server/ProgramHandler.cs b/src/app/Edelstein.Application.Server/ProgramHandler.cs new file mode 100644 index 000000000..230efe1a5 --- /dev/null +++ b/src/app/Edelstein.Application.Server/ProgramHandler.cs @@ -0,0 +1,67 @@ +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Edelstein.Application.Server.Bindings; +using Edelstein.Common.Gameplay.Login; +using Edelstein.Protocol.Gameplay.Login; +using Edelstein.Protocol.Network.Transports; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Serilog; + +namespace Edelstein.Application.Server; + +internal static class ProgramHandler +{ + public async static Task ExecuteRoot(FileInfo file) + { + var builder = Host.CreateApplicationBuilder(); + + builder.Services.AddSerilog((_, configuration) => configuration.ReadFrom.Configuration(builder.Configuration)); + + builder.Services.AddEdelsteinCommonUtilities(); + builder.Services.AddEdelsteinCommonGameplay(); + builder.Services.AddEdelsteinCommonGameplayLogin(); + + var configFileInfos = (file.Attributes & FileAttributes.Directory) != 0 + ? file.Directory?.GetFiles() ?? Array.Empty() + : new[]{ file }; + + foreach (var configFile in configFileInfos.Where(f => f.Extension == ".json")) + { + var version = new TransportVersion(95, "1", 8); + var config = new ConfigurationBuilder() + .AddJsonFile(configFile.FullName, false, false) + .Build(); + + switch (config["Type"]) + { + case "Login": + builder.Services.AddHostedService(p => + { + var loginConfig = new StageConfigLogin(); + var loginSystem = new LoginStageSystem(loginConfig); + + config.Bind(loginConfig); + + return new ServiceHostStage( + p.GetRequiredService>>(), + version, + loginConfig, + loginSystem + ); + }); + break; + default: + continue; + } + } + + var host = builder.Build(); + + await host.RunAsync(); + } +} diff --git a/src/app/Edelstein.Application.Server/ServiceHostStage.cs b/src/app/Edelstein.Application.Server/ServiceHostStage.cs new file mode 100644 index 000000000..2d40f1744 --- /dev/null +++ b/src/app/Edelstein.Application.Server/ServiceHostStage.cs @@ -0,0 +1,55 @@ +using System.Threading; +using System.Threading.Tasks; +using Edelstein.Common.Network.DotNetty.Transports; +using Edelstein.Protocol.Gameplay; +using Edelstein.Protocol.Network.Transports; +using Edelstein.Protocol.Services.Server; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace Edelstein.Application.Server; + +public class ServiceHostStage( + ILogger> logger, + TransportVersion version, + IServerEntry settings, + IStageSystem system +) : IHostedService + where TStageUser : class, IStageUser + where TStageSystem : IStageSystem +{ + private ITransportContext? Context { get; set; } + + public async Task StartAsync(CancellationToken cancellationToken) + { + var acceptor = new NettyTransportAcceptor( + version, + system, + system + ); + + Context = await acceptor.Accept(settings.Host, settings.Port); + logger.LogInformation( + "{ID} socket acceptor for v{Version}.{Patch} (Locale {Locale}) bound at {Host}:{Port}", + settings.ID, + version.Major, version.Patch, version.Locale, + settings.Host, settings.Port + ); + } + + public async Task StopAsync(CancellationToken cancellationToken) + { + logger.LogInformation( + "{ID} socket acceptor shutting down, this may take awhile..", + settings.ID + ); + + if (Context != null) + await Context.Close(); + + logger.LogInformation( + "{ID} socket acceptor finished shutting down", + settings.ID + ); + } +} diff --git a/src/app/Edelstein.Application.Server/packages.lock.json b/src/app/Edelstein.Application.Server/packages.lock.json index 2f1c91a5e..61577fcc3 100644 --- a/src/app/Edelstein.Application.Server/packages.lock.json +++ b/src/app/Edelstein.Application.Server/packages.lock.json @@ -96,6 +96,12 @@ "Serilog": "2.10.0" } }, + "System.CommandLine": { + "type": "Direct", + "requested": "[2.0.0-beta4.22272.1, )", + "resolved": "2.0.0-beta4.22272.1", + "contentHash": "1uqED/q2H0kKoLJ4+hI2iPSBSEdTuhfCYADeJrAqERmiGQ2NNacYKRNEQ+gFbU4glgVyK8rxI+ZOe1onEtr/Pg==" + }, "Grpc.Core.Api": { "type": "Transitive", "resolved": "2.51.0", @@ -287,14 +293,6 @@ "Microsoft.Extensions.Options": "9.0.0-preview.3.24172.9" } }, - "Microsoft.Extensions.Logging.Abstractions": { - "type": "Transitive", - "resolved": "9.0.0-preview.3.24172.9", - "contentHash": "b9wNSdoc20aarUp1ktpS2ERzO9MDqLflH2TmW/CXmjEnCli8CQ5gI+BeTyHa3j4RXwuhJiV4ssvthXYQj5rpWQ==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0-preview.3.24172.9" - } - }, "Microsoft.Extensions.Logging.Configuration": { "type": "Transitive", "resolved": "8.0.0", @@ -389,14 +387,6 @@ "resolved": "2.1.0", "contentHash": "ok+RPAtESz/9MUXeIEz6Lv5XAGQsaNmEYXMsgVALj4D7kqC8gveKWXWXbufLySR2fWrwZf8smyN5RmHu0e4BHA==" }, - "Npgsql": { - "type": "Transitive", - "resolved": "8.0.2", - "contentHash": "MuJzLoWCaQhQAR3oh66YR0Ir6mxuezncGX3f8wxvAc21g0+9HICktJQlqMoODhxztZKXE5k9GxRxqUAN+vPb4g==", - "dependencies": { - "Microsoft.Extensions.Logging.Abstractions": "8.0.0" - } - }, "protobuf-net": { "type": "Transitive", "resolved": "2.4.8", @@ -414,6 +404,11 @@ "Serilog": "3.1.1" } }, + "System.Collections.Immutable": { + "type": "Transitive", + "resolved": "1.5.0", + "contentHash": "EXKiDFsChZW0RjrZ4FYHu9aW6+P4MCgEDCklsVseRfhoO0F+dXeMSsMRAlVXIo06kGJ/zv+2w1a2uc2+kxxSaQ==" + }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", @@ -444,6 +439,11 @@ "resolved": "4.5.0", "contentHash": "+UW1hq11TNSeb+16rIk8hRQ02o339NFyzMc4ma/FqmxBzM30l1c2IherBB4ld1MNcenS48fz8tbt50OW4rVULA==" }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==" + }, "System.Security.Principal.Windows": { "type": "Transitive", "resolved": "4.5.0", @@ -473,31 +473,66 @@ "System.Text.Encodings.Web": "8.0.0" } }, - "edelstein.common.services.server": { + "edelstein.common.crypto": { + "type": "Project" + }, + "edelstein.common.gameplay": { "type": "Project", "dependencies": { - "AutoMapper": "[13.0.1, )", - "Edelstein.Protocol.Services.Migration": "[1.0.0, )", + "Edelstein.Common.Utilities": "[1.0.0, )", + "Edelstein.Protocol.Gameplay": "[1.0.0, )", "Edelstein.Protocol.Services.Server": "[1.0.0, )", - "Edelstein.Protocol.Services.Session": "[1.0.0, )", - "Microsoft.EntityFrameworkCore": "[9.0.0-preview.3.24172.4, )", - "Microsoft.Extensions.Configuration.Json": "[8.0.0, )", - "Npgsql.EntityFrameworkCore.PostgreSQL": "[8.0.2, )" + "Microsoft.Extensions.Logging.Abstractions": "[9.0.0-preview.3.24172.9, )" } }, - "edelstein.protocol.services.migration": { + "edelstein.common.gameplay.login": { "type": "Project", "dependencies": { - "protobuf-net.Grpc": "[1.1.1, )" + "Edelstein.Common.Gameplay": "[1.0.0, )", + "Edelstein.Protocol.Gameplay.Login": "[1.0.0, )" } }, - "edelstein.protocol.services.server": { + "edelstein.common.network.dotnetty": { "type": "Project", "dependencies": { - "protobuf-net.Grpc": "[1.1.1, )" + "DotNetty.Buffers": "[0.7.6, )", + "DotNetty.Codecs": "[0.7.6, )", + "DotNetty.Common": "[0.7.6, )", + "DotNetty.Handlers": "[0.7.6, )", + "DotNetty.Transport": "[0.7.6, )", + "Edelstein.Common.Crypto": "[1.0.0, )", + "Edelstein.Common.Utilities": "[1.0.0, )", + "Edelstein.Protocol.Network": "[1.0.0, )" + } + }, + "edelstein.common.utilities": { + "type": "Project", + "dependencies": { + "Edelstein.Protocol.Utilities": "[1.0.0, )", + "Microsoft.IO.RecyclableMemoryStream": "[3.0.0, )" + } + }, + "edelstein.protocol.gameplay": { + "type": "Project", + "dependencies": { + "Edelstein.Protocol.Network": "[1.0.0, )", + "Edelstein.Protocol.Services.Server": "[1.0.0, )" + } + }, + "edelstein.protocol.gameplay.login": { + "type": "Project", + "dependencies": { + "Edelstein.Protocol.Gameplay": "[1.0.0, )", + "Edelstein.Protocol.Services.Server": "[1.0.0, )" + } + }, + "edelstein.protocol.network": { + "type": "Project", + "dependencies": { + "Edelstein.Protocol.Utilities": "[1.0.0, )" } }, - "edelstein.protocol.services.session": { + "edelstein.protocol.services.server": { "type": "Project", "dependencies": { "protobuf-net.Grpc": "[1.1.1, )" @@ -506,13 +541,58 @@ "edelstein.protocol.utilities": { "type": "Project" }, - "AutoMapper": { + "DotNetty.Buffers": { + "type": "CentralTransitive", + "requested": "[0.7.6, )", + "resolved": "0.7.6", + "contentHash": "JVYypDugRG4m3hbS0drCC79vX93zqjn5w+U4ti/KXjTIzcQ/UVHrCgs7ZgJfWRUQLfgfQB0daYQtE18lKD8pHg==", + "dependencies": { + "DotNetty.Common": "0.7.6", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + } + }, + "DotNetty.Codecs": { + "type": "CentralTransitive", + "requested": "[0.7.6, )", + "resolved": "0.7.6", + "contentHash": "XBZy/m3+V8PBUHHHbFKaRBE0+knTCitcE8oKCQn4jZybH25mCZ1vTwj3BRuPYdNpzh74Op32Hj4ZXF+DMx/oAg==", + "dependencies": { + "DotNetty.Buffers": "0.7.6", + "DotNetty.Common": "0.7.6", + "DotNetty.Transport": "0.7.6", + "System.Collections.Immutable": "1.5.0" + } + }, + "DotNetty.Common": { + "type": "CentralTransitive", + "requested": "[0.7.6, )", + "resolved": "0.7.6", + "contentHash": "dmK8Njfh2Y4qnz99lLK0evoc46FPL5WOnHMLlavNZ6zqC5/bKgqGsJFoXbhVPkSYDp58g2euI64dhY0cvOUOZQ==", + "dependencies": { + "Microsoft.Extensions.Logging": "5.0.0", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + } + }, + "DotNetty.Handlers": { + "type": "CentralTransitive", + "requested": "[0.7.6, )", + "resolved": "0.7.6", + "contentHash": "6sSMp0Md8DbpyOAV9IjiR30uzaLrxAbJTcwFFpMJM1+EJhvPz6Ywt0RqoV6+lseq6zqBjMq2jbPTKcqPoqNYIA==", + "dependencies": { + "DotNetty.Buffers": "0.7.6", + "DotNetty.Codecs": "0.7.6", + "DotNetty.Common": "0.7.6", + "DotNetty.Transport": "0.7.6" + } + }, + "DotNetty.Transport": { "type": "CentralTransitive", - "requested": "[13.0.1, )", - "resolved": "13.0.1", - "contentHash": "/Fx1SbJ16qS7dU4i604Sle+U9VLX+WSNVJggk6MupKVkYvvBm4XqYaeFuf67diHefHKHs50uQIS2YEDFhPCakQ==", + "requested": "[0.7.6, )", + "resolved": "0.7.6", + "contentHash": "EVQ5FihFPdWmw7v6l/4iyMepj49vZT11kWQNJ0ApC4KzkdJJ6LM/7NDUgghyxbO0e25nfQRtkGLP5EZAEo7QDA==", "dependencies": { - "Microsoft.Extensions.Options": "6.0.0" + "DotNetty.Buffers": "0.7.6", + "DotNetty.Common": "0.7.6" } }, "Microsoft.EntityFrameworkCore": { @@ -540,18 +620,21 @@ "System.Text.Json": "8.0.0" } }, - "Npgsql.EntityFrameworkCore.PostgreSQL": { + "Microsoft.Extensions.Logging.Abstractions": { "type": "CentralTransitive", - "requested": "[8.0.2, )", - "resolved": "8.0.2", - "contentHash": "eoZPynwkZTWFTgnocvXORuCL2yFZtscrUdqVhjxiRULpC7BMg9zhLM5oDZAU5PoX1PgN77hmkKE4a3PQiHqh7Q==", + "requested": "[9.0.0-preview.3.24172.9, )", + "resolved": "9.0.0-preview.3.24172.9", + "contentHash": "b9wNSdoc20aarUp1ktpS2ERzO9MDqLflH2TmW/CXmjEnCli8CQ5gI+BeTyHa3j4RXwuhJiV4ssvthXYQj5rpWQ==", "dependencies": { - "Microsoft.EntityFrameworkCore": "8.0.2", - "Microsoft.EntityFrameworkCore.Abstractions": "8.0.2", - "Microsoft.EntityFrameworkCore.Relational": "8.0.2", - "Npgsql": "8.0.2" + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0-preview.3.24172.9" } }, + "Microsoft.IO.RecyclableMemoryStream": { + "type": "CentralTransitive", + "requested": "[3.0.0, )", + "resolved": "3.0.0", + "contentHash": "irv0HuqoH8Ig5i2fO+8dmDNdFdsrO+DoQcedwIlb810qpZHBNQHZLW7C/AHBQDgLLpw2T96vmMAy/aE4Yj55Sg==" + }, "protobuf-net.Grpc": { "type": "CentralTransitive", "requested": "[1.1.1, )", diff --git a/src/common/Edelstein.Common.Gameplay.Login/Edelstein.Common.Gameplay.Login.csproj b/src/common/Edelstein.Common.Gameplay.Login/Edelstein.Common.Gameplay.Login.csproj index e855ff5d9..5e2a01e8e 100644 --- a/src/common/Edelstein.Common.Gameplay.Login/Edelstein.Common.Gameplay.Login.csproj +++ b/src/common/Edelstein.Common.Gameplay.Login/Edelstein.Common.Gameplay.Login.csproj @@ -1,5 +1,6 @@  - - - + + + + diff --git a/src/common/Edelstein.Common.Gameplay.Login/LoginStageSystem.cs b/src/common/Edelstein.Common.Gameplay.Login/LoginStageSystem.cs new file mode 100644 index 000000000..513813e2f --- /dev/null +++ b/src/common/Edelstein.Common.Gameplay.Login/LoginStageSystem.cs @@ -0,0 +1,15 @@ +using Edelstein.Protocol.Gameplay.Login; +using Edelstein.Protocol.Network; + +namespace Edelstein.Common.Gameplay.Login; + +public class LoginStageSystem( + ILoginStageSystemOptions options +) : AbstractStageSystem, ILoginStageSystem +{ + public override string ID => options.ID; + public ILoginStageSystemOptions Options => options; + + public override ILoginStageUser CreateUser(ISocket socket) + => new LoginStageUser(this, socket); +} diff --git a/src/common/Edelstein.Common.Gameplay.Login/LoginStageUser.cs b/src/common/Edelstein.Common.Gameplay.Login/LoginStageUser.cs new file mode 100644 index 000000000..169d4b2a5 --- /dev/null +++ b/src/common/Edelstein.Common.Gameplay.Login/LoginStageUser.cs @@ -0,0 +1,13 @@ +using Edelstein.Protocol.Gameplay.Login; +using Edelstein.Protocol.Network; + +namespace Edelstein.Common.Gameplay.Login; + +public class LoginStageUser( + ILoginStageSystem system, + ISocket socket +) : ILoginStageUser +{ + public ILoginStageSystem System { get; } = system; + public ISocket Socket { get; } = socket; +} diff --git a/src/common/Edelstein.Common.Gameplay.Login/packages.lock.json b/src/common/Edelstein.Common.Gameplay.Login/packages.lock.json index a51481db6..19011b5d7 100644 --- a/src/common/Edelstein.Common.Gameplay.Login/packages.lock.json +++ b/src/common/Edelstein.Common.Gameplay.Login/packages.lock.json @@ -17,10 +17,137 @@ "resolved": "5.0.0", "contentHash": "ybkgpQMtt0Fo91l5rYtE3TZtD+Nmy5Ko091xvfXXOosQdMi30XO2EZ2+ShZt89gdu7RMmJqZaJ+e1q6d+6+KNw==" }, + "Grpc.Core.Api": { + "type": "Transitive", + "resolved": "2.51.0", + "contentHash": "WUYCnxZKfdBWCKNs08lWFRoTjESt3iyFDthsZu5KcWguZ4OnnXrTu/K5mIdO+R9dUhuw5Xm1ygUrI1e2q8d1YA==", + "dependencies": { + "System.Memory": "4.5.3" + } + }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" + "resolved": "9.0.0-preview.3.24172.9", + "contentHash": "3176Psy4JxVCJI9L57MyLXt+0HmCylzFmblmmG4GNbxCArrt8slJGWootNRj7rJBh1CPNXOI3nwk9VvDLj/8oQ==" + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "2.1.0", + "contentHash": "ok+RPAtESz/9MUXeIEz6Lv5XAGQsaNmEYXMsgVALj4D7kqC8gveKWXWXbufLySR2fWrwZf8smyN5RmHu0e4BHA==" + }, + "protobuf-net": { + "type": "Transitive", + "resolved": "2.4.8", + "contentHash": "O+vbVVDxTWlFRBe5OsAmMKqqD7WQ7TPIH97Nr/Pk8gDxtNW77seiDmXfxnODuWIkm0fYW7kE5ILq8jHsgH79yg==", + "dependencies": { + "System.ServiceModel.Primitives": "4.5.3" + } + }, + "System.Memory": { + "type": "Transitive", + "resolved": "4.5.3", + "contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA==" + }, + "System.Private.ServiceModel": { + "type": "Transitive", + "resolved": "4.5.3", + "contentHash": "ancrQgJagx+yC4SZbuE+eShiEAUIF0E1d21TRSoy1C/rTwafAVcBr/fKibkq5TQzyy9uNil2tx2/iaUxsy0S9g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "2.1.0", + "System.Reflection.DispatchProxy": "4.5.0", + "System.Security.Principal.Windows": "4.5.0" + } + }, + "System.Reflection.DispatchProxy": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "+UW1hq11TNSeb+16rIk8hRQ02o339NFyzMc4ma/FqmxBzM30l1c2IherBB4ld1MNcenS48fz8tbt50OW4rVULA==" + }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "U77HfRXlZlOeIXd//Yoj6Jnk8AXlbeisf1oq1os+hxOGVnuG+lGSfGqTwTZBoORFF6j/0q7HXIl8cqwQ9aUGqQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "2.0.0" + } + }, + "System.ServiceModel.Primitives": { + "type": "Transitive", + "resolved": "4.5.3", + "contentHash": "Wc9Hgg4Cmqi416zvEgq2sW1YYCGuhwWzspDclJWlFZqY6EGhFUPZU+kVpl5z9kAgrSOQP7/Uiik+PtSQtmq+5A==", + "dependencies": { + "System.Private.ServiceModel": "4.5.3" + } + }, + "edelstein.common.gameplay": { + "type": "Project", + "dependencies": { + "Edelstein.Common.Utilities": "[1.0.0, )", + "Edelstein.Protocol.Gameplay": "[1.0.0, )", + "Edelstein.Protocol.Services.Server": "[1.0.0, )", + "Microsoft.Extensions.Logging.Abstractions": "[9.0.0-preview.3.24172.9, )" + } + }, + "edelstein.common.utilities": { + "type": "Project", + "dependencies": { + "Edelstein.Protocol.Utilities": "[1.0.0, )", + "Microsoft.IO.RecyclableMemoryStream": "[3.0.0, )" + } + }, + "edelstein.protocol.gameplay": { + "type": "Project", + "dependencies": { + "Edelstein.Protocol.Network": "[1.0.0, )", + "Edelstein.Protocol.Services.Server": "[1.0.0, )" + } + }, + "edelstein.protocol.gameplay.login": { + "type": "Project", + "dependencies": { + "Edelstein.Protocol.Gameplay": "[1.0.0, )", + "Edelstein.Protocol.Services.Server": "[1.0.0, )" + } + }, + "edelstein.protocol.network": { + "type": "Project", + "dependencies": { + "Edelstein.Protocol.Utilities": "[1.0.0, )" + } + }, + "edelstein.protocol.services.server": { + "type": "Project", + "dependencies": { + "protobuf-net.Grpc": "[1.1.1, )" + } + }, + "edelstein.protocol.utilities": { + "type": "Project" + }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "CentralTransitive", + "requested": "[9.0.0-preview.3.24172.9, )", + "resolved": "9.0.0-preview.3.24172.9", + "contentHash": "b9wNSdoc20aarUp1ktpS2ERzO9MDqLflH2TmW/CXmjEnCli8CQ5gI+BeTyHa3j4RXwuhJiV4ssvthXYQj5rpWQ==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0-preview.3.24172.9" + } + }, + "Microsoft.IO.RecyclableMemoryStream": { + "type": "CentralTransitive", + "requested": "[3.0.0, )", + "resolved": "3.0.0", + "contentHash": "irv0HuqoH8Ig5i2fO+8dmDNdFdsrO+DoQcedwIlb810qpZHBNQHZLW7C/AHBQDgLLpw2T96vmMAy/aE4Yj55Sg==" + }, + "protobuf-net.Grpc": { + "type": "CentralTransitive", + "requested": "[1.1.1, )", + "resolved": "1.1.1", + "contentHash": "uThFb/iUplzuXEa/cztJaNGpKLRQRb515STtQX99IS1MKh8Qsunw6MjjU+9rjo8s9UymR6lN9Ab6xT3adBlyDg==", + "dependencies": { + "Grpc.Core.Api": "2.51.0", + "protobuf-net": "2.4.8" + } } } } diff --git a/src/common/Edelstein.Common.Gameplay/AbstractStageSystem.cs b/src/common/Edelstein.Common.Gameplay/AbstractStageSystem.cs new file mode 100644 index 000000000..9f1dc0bd4 --- /dev/null +++ b/src/common/Edelstein.Common.Gameplay/AbstractStageSystem.cs @@ -0,0 +1,21 @@ +using System; +using System.Threading.Tasks; +using Edelstein.Protocol.Gameplay; +using Edelstein.Protocol.Network; +using Edelstein.Protocol.Utilities.Buffers; + +namespace Edelstein.Common.Gameplay; + +public abstract class AbstractStageSystem : + IStageSystem + where TStageUser : IStageUser + where TStageSystem : IStageSystem +{ + public abstract string ID { get; } + + public abstract TStageUser CreateUser(ISocket socket); + + public Task OnPacket(TStageUser user, IPacket packet) => Task.CompletedTask; + public Task OnException(TStageUser user, Exception exception) => Task.CompletedTask; + public Task OnDisconnect(TStageUser user) => Task.CompletedTask; +} diff --git a/src/common/Edelstein.Common.Gameplay/Edelstein.Common.Gameplay.csproj b/src/common/Edelstein.Common.Gameplay/Edelstein.Common.Gameplay.csproj new file mode 100644 index 000000000..44a6c695e --- /dev/null +++ b/src/common/Edelstein.Common.Gameplay/Edelstein.Common.Gameplay.csproj @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/common/Edelstein.Common.Gameplay/Handling/IPacketHandler.cs b/src/common/Edelstein.Common.Gameplay/Handling/IPacketHandler.cs new file mode 100644 index 000000000..4549f24e9 --- /dev/null +++ b/src/common/Edelstein.Common.Gameplay/Handling/IPacketHandler.cs @@ -0,0 +1,15 @@ +using System.Threading.Tasks; +using Edelstein.Protocol.Gameplay; +using Edelstein.Protocol.Utilities.Buffers; + +namespace Edelstein.Common.Gameplay.Handling; + +public interface IPacketHandler + where TStageUser : IStageUser + where TStageSystem : IStageSystem +{ + short Operation { get; } + + bool Check(TStageUser user); + Task Handle(TStageUser user, IPacketReader reader); +} diff --git a/src/common/Edelstein.Common.Gameplay/Handling/IPacketHandlerManager.cs b/src/common/Edelstein.Common.Gameplay/Handling/IPacketHandlerManager.cs new file mode 100644 index 000000000..a967ae793 --- /dev/null +++ b/src/common/Edelstein.Common.Gameplay/Handling/IPacketHandlerManager.cs @@ -0,0 +1,15 @@ +using System.Threading.Tasks; +using Edelstein.Protocol.Gameplay; +using Edelstein.Protocol.Utilities.Buffers; + +namespace Edelstein.Common.Gameplay.Handling; + +public interface IPacketHandlerManager + where TStageUser : IStageUser + where TStageSystem : IStageSystem +{ + void Add(IPacketHandler handler); + void Remove(IPacketHandler handler); + + Task Process(TStageUser user, IPacket packet); +} diff --git a/src/common/Edelstein.Common.Gameplay/Handling/IPacketSerializer.cs b/src/common/Edelstein.Common.Gameplay/Handling/IPacketSerializer.cs new file mode 100644 index 000000000..1060ff7f1 --- /dev/null +++ b/src/common/Edelstein.Common.Gameplay/Handling/IPacketSerializer.cs @@ -0,0 +1,11 @@ +using Edelstein.Protocol.Gameplay; +using Edelstein.Protocol.Utilities.Buffers; + +namespace Edelstein.Common.Gameplay.Handling; + +public interface IPacketSerializer + where TStageUser : IStageUser + where TStageSystem : IStageSystem +{ + TObject? Serialize(TStageUser user, IPacketReader reader); +} diff --git a/src/common/Edelstein.Common.Gameplay/Handling/PacketHandlerManager.cs b/src/common/Edelstein.Common.Gameplay/Handling/PacketHandlerManager.cs new file mode 100644 index 000000000..b95c2d03e --- /dev/null +++ b/src/common/Edelstein.Common.Gameplay/Handling/PacketHandlerManager.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Edelstein.Common.Utilities.Buffers; +using Edelstein.Protocol.Gameplay; +using Edelstein.Protocol.Utilities.Buffers; +using Injectio.Attributes; +using Microsoft.Extensions.Logging; + +namespace Edelstein.Common.Gameplay.Handling; + +[RegisterScoped(ImplementationType = typeof(PacketHandlerManager<,>), ServiceType = typeof(IPacketHandlerManager<,>))] +public class PacketHandlerManager( + ILogger> logger +) : IPacketHandlerManager + where TStageUser : IStageUser + where TStageSystem : IStageSystem +{ + private readonly Dictionary> _handlers = new(); + private readonly ILogger _logger = logger; + + public PacketHandlerManager( + ILogger> logger, + IEnumerable> handlers + ) : this(logger) + { + foreach (var handler in handlers) Add(handler); + } + + public void Add(IPacketHandler handler) + { + if (_handlers.ContainsKey(handler.Operation)) + _logger.LogWarning( + "Overriding packet handler for operation 0x{Operation:X} ({OperationName}) to {Handler}", + handler.Operation, Enum.GetName((PacketRecvOperations)handler.Operation), handler.GetType().Name + ); + else + _logger.LogDebug( + "Set packet handler for operation 0x{Operation:X} ({OperationName}) to {Handler}", + handler.Operation, Enum.GetName((PacketRecvOperations)handler.Operation), handler.GetType().Name + ); + _handlers[handler.Operation] = handler; + } + + public void Remove(IPacketHandler handler) + { + _logger.LogWarning( + "Removing packet handler for operation 0x{Operation:X} ({OperationName})", + handler.Operation, Enum.GetName((PacketRecvOperations)handler.Operation) + ); + _handlers.Remove(handler.Operation); + } + + public async Task Process(TStageUser user, IPacket packet) + { + using var reader = new PacketReader(packet.Buffer); + var operation = reader.ReadShort(); + var handler = _handlers.GetValueOrDefault(operation); + + if (handler == null) + { + _logger.LogWarning( + "Unhandled packet operation 0x{Operation:X} ({OperationName})", + operation, Enum.GetName((PacketRecvOperations)operation) + ); + return; + } + + if (handler.Check(user)) + await handler.Handle(user, reader); + + _logger.LogDebug( + "Handled packet operation 0x{Operation:X} ({OperationName}) with {Available} available bytes left", + operation, Enum.GetName((PacketRecvOperations)operation), reader.Available + ); + } +} diff --git a/src/common/Edelstein.Common.Gameplay/Handling/PacketRecvOperations.cs b/src/common/Edelstein.Common.Gameplay/Handling/PacketRecvOperations.cs new file mode 100644 index 000000000..de45936a7 --- /dev/null +++ b/src/common/Edelstein.Common.Gameplay/Handling/PacketRecvOperations.cs @@ -0,0 +1,320 @@ +namespace Edelstein.Common.Gameplay.Handling; + +public enum PacketRecvOperations : short +{ + BEGIN_SOCKET = 0x0, + CheckPassword = 0x1, + GuestIDLogin = 0x2, + AccountInfoRequest = 0x3, + WorldInfoRequest = 0x4, + SelectWorld = 0x5, + CheckUserLimit = 0x6, + ConfirmEULA = 0x7, + SetGender = 0x8, + CheckPinCode = 0x9, + UpdatePinCode = 0xA, + WorldRequest = 0xB, + LogoutWorld = 0xC, + ViewAllChar = 0xD, + SelectCharacterByVAC = 0xE, + VACFlagSet = 0xF, + CheckNameChangePossible = 0x10, + RegisterNewCharacter = 0x11, + CheckTransferWorldPossible = 0x12, + SelectCharacter = 0x13, + MigrateIn = 0x14, + CheckDuplicatedID = 0x15, + CreateNewCharacter = 0x16, + CreateNewCharacterInCS = 0x17, + DeleteCharacter = 0x18, + AliveAck = 0x19, + ExceptionLog = 0x1A, + SecurityPacket = 0x1B, + EnableSPWRequest = 0x1C, + CheckSPWRequest = 0x1D, + EnableSPWRequestByACV = 0x1E, + CheckSPWRequestByACV = 0x1F, + CheckOTPRequest = 0x20, + CheckDeleteCharacterOTP = 0x21, + CreateSecurityHandle = 0x22, + SSOErrorLog = 0x23, + ClientDumpLog = 0x24, + CheckExtraCharInfo = 0x25, + CreateNewCharacter_Ex = 0x26, + END_SOCKET = 0x27, + BEGIN_USER = 0x28, + UserTransferFieldRequest = 0x29, + UserTransferChannelRequest = 0x2A, + UserMigrateToCashShopRequest = 0x2B, + UserMove = 0x2C, + UserSitRequest = 0x2D, + UserPortableChairSitRequest = 0x2E, + UserMeleeAttack = 0x2F, + UserShootAttack = 0x30, + UserMagicAttack = 0x31, + UserBodyAttack = 0x32, + UserMovingShootAttackPrepare = 0x33, + UserHit = 0x34, + UserAttackUser = 0x35, + UserChat = 0x36, + UserADBoardClose = 0x37, + UserEmotion = 0x38, + UserActivateEffectItem = 0x39, + UserUpgradeTombEffect = 0x3A, + UserHP = 0x3B, + Premium = 0x3C, + UserBanMapByMob = 0x3D, + UserMonsterBookSetCover = 0x3E, + UserSelectNpc = 0x3F, + UserRemoteShopOpenRequest = 0x40, + UserScriptMessageAnswer = 0x41, + UserShopRequest = 0x42, + UserTrunkRequest = 0x43, + UserEntrustedShopRequest = 0x44, + UserStoreBankRequest = 0x45, + UserParcelRequest = 0x46, + UserEffectLocal = 0x47, + ShopScannerRequest = 0x48, + ShopLinkRequest = 0x49, + AdminShopRequest = 0x4A, + UserGatherItemRequest = 0x4B, + UserSortItemRequest = 0x4C, + UserChangeSlotPositionRequest = 0x4D, + UserStatChangeItemUseRequest = 0x4E, + UserStatChangeItemCancelRequest = 0x4F, + UserStatChangeByPortableChairRequest = 0x50, + UserMobSummonItemUseRequest = 0x51, + UserPetFoodItemUseRequest = 0x52, + UserTamingMobFoodItemUseRequest = 0x53, + UserScriptItemUseRequest = 0x54, + UserConsumeCashItemUseRequest = 0x55, + UserDestroyPetItemRequest = 0x56, + UserBridleItemUseRequest = 0x57, + UserSkillLearnItemUseRequest = 0x58, + UserSkillResetItemUseRequest = 0x59, + UserShopScannerItemUseRequest = 0x5A, + UserMapTransferItemUseRequest = 0x5B, + UserPortalScrollUseRequest = 0x5C, + UserUpgradeItemUseRequest = 0x5D, + UserHyperUpgradeItemUseRequest = 0x5E, + UserItemOptionUpgradeItemUseRequest = 0x5F, + UserUIOpenItemUseRequest = 0x60, + UserItemReleaseRequest = 0x61, + UserAbilityUpRequest = 0x62, + UserAbilityMassUpRequest = 0x63, + UserChangeStatRequest = 0x64, + UserChangeStatRequestByItemOption = 0x65, + UserSkillUpRequest = 0x66, + UserSkillUseRequest = 0x67, + UserSkillCancelRequest = 0x68, + UserSkillPrepareRequest = 0x69, + UserDropMoneyRequest = 0x6A, + UserGivePopularityRequest = 0x6B, + UserPartyRequest = 0x6C, + UserCharacterInfoRequest = 0x6D, + UserActivatePetRequest = 0x6E, + UserTemporaryStatUpdateRequest = 0x6F, + UserPortalScriptRequest = 0x70, + UserPortalTeleportRequest = 0x71, + UserMapTransferRequest = 0x72, + UserAntiMacroItemUseRequest = 0x73, + UserAntiMacroSkillUseRequest = 0x74, + UserAntiMacroQuestionResult = 0x75, + UserClaimRequest = 0x76, + UserQuestRequest = 0x77, + UserCalcDamageStatSetRequest = 0x78, + UserThrowGrenade = 0x79, + UserMacroSysDataModified = 0x7A, + UserSelectNpcItemUseRequest = 0x7B, + UserLotteryItemUseRequest = 0x7C, + UserItemMakeRequest = 0x7D, + UserSueCharacterRequest = 0x7E, + UserUseGachaponBoxRequest = 0x7F, + UserUseGachaponRemoteRequest = 0x80, + UserUseWaterOfLife = 0x81, + UserRepairDurabilityAll = 0x82, + UserRepairDurability = 0x83, + UserQuestRecordSetState = 0x84, + UserClientTimerEndRequest = 0x85, + UserFollowCharacterRequest = 0x86, + UserFollowCharacterWithdraw = 0x87, + UserSelectPQReward = 0x88, + UserRequestPQReward = 0x89, + SetPassenserResult = 0x8A, + BroadcastMsg = 0x8B, + GroupMessage = 0x8C, + Whisper = 0x8D, + CoupleMessage = 0x8E, + Messenger = 0x8F, + MiniRoom = 0x90, + PartyRequest = 0x91, + PartyResult = 0x92, + ExpeditionRequest = 0x93, + PartyAdverRequest = 0x94, + GuildRequest = 0x95, + GuildResult = 0x96, + Admin = 0x97, + Log = 0x98, + FriendRequest = 0x99, + MemoRequest = 0x9A, + MemoFlagRequest = 0x9B, + EnterTownPortalRequest = 0x9C, + EnterOpenGateRequest = 0x9D, + SlideRequest = 0x9E, + FuncKeyMappedModified = 0x9F, + RPSGame = 0xA0, + MarriageRequest = 0xA1, + WeddingWishListRequest = 0xA2, + WeddingProgress = 0xA3, + GuestBless = 0xA4, + BoobyTrapAlert = 0xA5, + StalkBegin = 0xA6, + AllianceRequest = 0xA7, + AllianceResult = 0xA8, + FamilyChartRequest = 0xA9, + FamilyInfoRequest = 0xAA, + FamilyRegisterJunior = 0xAB, + FamilyUnregisterJunior = 0xAC, + FamilyUnregisterParent = 0xAD, + FamilyJoinResult = 0xAE, + FamilyUsePrivilege = 0xAF, + FamilySetPrecept = 0xB0, + FamilySummonResult = 0xB1, + ChatBlockUserReq = 0xB2, + GuildBBS = 0xB3, + UserMigrateToITCRequest = 0xB4, + UserExpUpItemUseRequest = 0xB5, + UserTempExpUseRequest = 0xB6, + NewYearCardRequest = 0xB7, + RandomMorphRequest = 0xB8, + CashItemGachaponRequest = 0xB9, + CashGachaponOpenRequest = 0xBA, + ChangeMaplePointRequest = 0xBB, + TalkToTutor = 0xBC, + RequestIncCombo = 0xBD, + MobCrcKeyChangedReply = 0xBE, + RequestSessionValue = 0xBF, + UpdateGMBoard = 0xC0, + AccountMoreInfo = 0xC1, + FindFriend = 0xC2, + AcceptAPSPEvent = 0xC3, + UserDragonBallBoxRequest = 0xC4, + UserDragonBallSummonRequest = 0xC5, + BEGIN_PET = 0xC6, + PetMove = 0xC7, + PetAction = 0xC8, + PetInteractionRequest = 0xC9, + PetDropPickUpRequest = 0xCA, + PetStatChangeItemUseRequest = 0xCB, + PetUpdateExceptionListRequest = 0xCC, + END_PET = 0xCD, + BEGIN_SUMMONED = 0xCE, + SummonedMove = 0xCF, + SummonedAttack = 0xD0, + SummonedHit = 0xD1, + SummonedSkill = 0xD2, + Remove = 0xD3, + END_SUMMONED = 0xD4, + BEGIN_DRAGON = 0xD5, + DragonMove = 0xD6, + END_DRAGON = 0xD7, + QuickslotKeyMappedModified = 0xD8, + PassiveskillInfoUpdate = 0xD9, + UpdateScreenSetting = 0xDA, + UserAttackUser_Specific = 0xDB, + UserPamsSongUseRequest = 0xDC, + QuestGuideRequest = 0xDD, + UserRepeatEffectRemove = 0xDE, + END_USER = 0xDF, + BEGIN_FIELD = 0xE0, + BEGIN_LIFEPOOL = 0xE1, + BEGIN_MOB = 0xE2, + MobMove = 0xE3, + MobApplyCtrl = 0xE4, + MobDropPickUpRequest = 0xE5, + MobHitByObstacle = 0xE6, + MobHitByMob = 0xE7, + MobSelfDestruct = 0xE8, + MobAttackMob = 0xE9, + MobSkillDelayEnd = 0xEA, + MobTimeBombEnd = 0xEB, + MobEscortCollision = 0xEC, + MobRequestEscortInfo = 0xED, + MobEscortStopEndRequest = 0xEE, + END_MOB = 0xEF, + BEGIN_NPC = 0xF0, + NpcMove = 0xF1, + NpcSpecialAction = 0xF2, + END_NPC = 0xF3, + END_LIFEPOOL = 0xF4, + BEGIN_DROPPOOL = 0xF5, + DropPickUpRequest = 0xF6, + END_DROPPOOL = 0xF7, + BEGIN_REACTORPOOL = 0xF8, + ReactorHit = 0xF9, + ReactorTouch = 0xFA, + RequireFieldObstacleStatus = 0xFB, + END_REACTORPOOL = 0xFC, + BEGIN_EVENT_FIELD = 0xFD, + EventStart = 0xFE, + SnowBallHit = 0xFF, + SnowBallTouch = 0x100, + CoconutHit = 0x101, + TournamentMatchTable = 0x102, + PulleyHit = 0x103, + END_EVENT_FIELD = 0x104, + BEGIN_MONSTER_CARNIVAL_FIELD = 0x105, + MCarnivalRequest = 0x106, + END_MONSTER_CARNIVAL_FIELD = 0x107, + CONTISTATE = 0x108, + BEGIN_PARTY_MATCH = 0x109, + INVITE_PARTY_MATCH = 0x10A, + CANCEL_INVITE_PARTY_MATCH = 0x10B, + END_PARTY_MATCH = 0x10C, + RequestFootHoldInfo = 0x10D, + FootHoldInfo = 0x10E, + END_FIELD = 0x10F, + BEGIN_CASHSHOP = 0x110, + CashShopChargeParamRequest = 0x111, + CashShopQueryCashRequest = 0x112, + CashShopCashItemRequest = 0x113, + CashShopCheckCouponRequest = 0x114, + CashShopGiftMateInfoRequest = 0x115, + END_CASHSHOP = 0x116, + CheckSSN2OnCreateNewCharacter = 0x117, + CheckSPWOnCreateNewCharacter = 0x118, + FirstSSNOnCreateNewCharacter = 0x119, + BEGIN_RAISE = 0x11A, + RaiseRefesh = 0x11B, + RaiseUIState = 0x11C, + RaiseIncExp = 0x11D, + RaiseAddPiece = 0x11E, + END_RAISE = 0x11F, + SendMateMail = 0x120, + RequestGuildBoardAuthKey = 0x121, + RequestConsultAuthKey = 0x122, + RequestClassCompetitionAuthKey = 0x123, + RequestWebBoardAuthKey = 0x124, + BEGIN_ITEMUPGRADE = 0x125, + GoldHammerRequest = 0x126, + GoldHammerComplete = 0x127, + ItemUpgradeComplete = 0x128, + END_ITEMUPGRADE = 0x129, + BEGIN_BATTLERECORD = 0x12A, + BATTLERECORD_ONOFF_REQUEST = 0x12B, + END_BATTLERECORD = 0x12C, + BEGIN_MAPLETV = 0x12D, + MapleTVSendMessageRequest = 0x12E, + MapleTVUpdateViewCount = 0x12F, + END_MAPLETV = 0x130, + BEGIN_ITC = 0x131, + ITCChargeParamRequest = 0x132, + ITCQueryCashRequest = 0x133, + ITCItemRequest = 0x134, + END_ITC = 0x135, + BEGIN_CHARACTERSALE = 0x136, + CheckDuplicatedIDInCS = 0x137, + END_CHARACTERSALE = 0x138, + LogoutGiftSelect = 0x139, + NO = 0x13A +} diff --git a/src/common/Edelstein.Common.Gameplay/Handling/PacketSendOperations.cs b/src/common/Edelstein.Common.Gameplay/Handling/PacketSendOperations.cs new file mode 100644 index 000000000..aae658886 --- /dev/null +++ b/src/common/Edelstein.Common.Gameplay/Handling/PacketSendOperations.cs @@ -0,0 +1,513 @@ +namespace Edelstein.Common.Gameplay.Handling; + +public enum PacketSendOperations : short +{ + BEGIN_SOCKET = 0x0, + CheckPasswordResult = 0x0, + GuestIDLoginResult = 0x1, + AccountInfoResult = 0x2, + CheckUserLimitResult = 0x3, + SetAccountResult = 0x4, + ConfirmEULAResult = 0x5, + CheckPinCodeResult = 0x6, + UpdatePinCodeResult = 0x7, + ViewAllCharResult = 0x8, + SelectCharacterByVACResult = 0x9, + WorldInformation = 0xA, + SelectWorldResult = 0xB, + SelectCharacterResult = 0xC, + CheckDuplicatedIDResult = 0xD, + CreateNewCharacterResult = 0xE, + DeleteCharacterResult = 0xF, + MigrateCommand = 0x10, + AliveReq = 0x11, + AuthenCodeChanged = 0x12, + AuthenMessage = 0x13, + SecurityPacket = 0x14, + EnableSPWResult = 0x15, + DeleteCharacterOTPRequest = 0x16, + CheckCrcResult = 0x17, + LatestConnectedWorld = 0x18, + RecommendWorldMessage = 0x19, + CheckExtraCharInfoResult = 0x1A, + CheckSPWResult = 0x1B, + END_SOCKET = 0x1B, + BEGIN_CHARACTERDATA = 0x1C, + InventoryOperation = 0x1C, + InventoryGrow = 0x1D, + StatChanged = 0x1E, + TemporaryStatSet = 0x1F, + TemporaryStatReset = 0x20, + ForcedStatSet = 0x21, + ForcedStatReset = 0x22, + ChangeSkillRecordResult = 0x23, + SkillUseResult = 0x24, + GivePopularityResult = 0x25, + Message = 0x26, + SendOpenFullClientLink = 0x27, + MemoResult = 0x28, + MapTransferResult = 0x29, + AntiMacroResult = 0x2A, + InitialQuizStart = 0x2B, + ClaimResult = 0x2C, + SetClaimSvrAvailableTime = 0x2D, + ClaimSvrStatusChanged = 0x2E, + SetTamingMobInfo = 0x2F, + QuestClear = 0x30, + EntrustedShopCheckResult = 0x31, + SkillLearnItemResult = 0x32, + SkillResetItemResult = 0x33, + GatherItemResult = 0x34, + SortItemResult = 0x35, + RemoteShopOpenResult = 0x36, + SueCharacterResult = 0x37, + MigrateToCashShopResult = 0x38, + TradeMoneyLimit = 0x39, + SetGender = 0x3A, + GuildBBS = 0x3B, + PetDeadMessage = 0x3C, + CharacterInfo = 0x3D, + PartyResult = 0x3E, + ExpeditionRequest = 0x3F, + ExpeditionNoti = 0x40, + FriendResult = 0x41, + GuildRequest = 0x42, + GuildResult = 0x43, + AllianceResult = 0x44, + TownPortal = 0x45, + OpenGate = 0x46, + BroadcastMsg = 0x47, + IncubatorResult = 0x48, + ShopScannerResult = 0x49, + ShopLinkResult = 0x4A, + MarriageRequest = 0x4B, + MarriageResult = 0x4C, + WeddingGiftResult = 0x4D, + MarriedPartnerMapTransfer = 0x4E, + CashPetFoodResult = 0x4F, + SetWeekEventMessage = 0x50, + SetPotionDiscountRate = 0x51, + BridleMobCatchFail = 0x52, + ImitatedNPCResult = 0x53, + ImitatedNPCData = 0x54, + LimitedNPCDisableInfo = 0x55, + MonsterBookSetCard = 0x56, + MonsterBookSetCover = 0x57, + HourChanged = 0x58, + MiniMapOnOff = 0x59, + ConsultAuthkeyUpdate = 0x5A, + ClassCompetitionAuthkeyUpdate = 0x5B, + WebBoardAuthkeyUpdate = 0x5C, + SessionValue = 0x5D, + PartyValue = 0x5E, + FieldSetVariable = 0x5F, + BonusExpRateChanged = 0x60, + PotionDiscountRateChanged = 0x61, + FamilyChartResult = 0x62, + FamilyInfoResult = 0x63, + FamilyResult = 0x64, + FamilyJoinRequest = 0x65, + FamilyJoinRequestResult = 0x66, + FamilyJoinAccepted = 0x67, + FamilyPrivilegeList = 0x68, + FamilyFamousPointIncResult = 0x69, + FamilyNotifyLoginOrLogout = 0x6A, + FamilySetPrivilege = 0x6B, + FamilySummonRequest = 0x6C, + NotifyLevelUp = 0x6D, + NotifyWedding = 0x6E, + NotifyJobChange = 0x6F, + IncRateChanged = 0x70, + MapleTVUseRes = 0x71, + AvatarMegaphoneRes = 0x72, + AvatarMegaphoneUpdateMessage = 0x73, + AvatarMegaphoneClearMessage = 0x74, + CancelNameChangeResult = 0x75, + CancelTransferWorldResult = 0x76, + DestroyShopResult = 0x77, + FAKEGMNOTICE = 0x78, + SuccessInUseGachaponBox = 0x79, + NewYearCardRes = 0x7A, + RandomMorphRes = 0x7B, + CancelNameChangeByOther = 0x7C, + SetBuyEquipExt = 0x7D, + SetPassenserRequest = 0x7E, + ScriptProgressMessage = 0x7F, + DataCRCCheckFailed = 0x80, + CakePieEventResult = 0x81, + UpdateGMBoard = 0x82, + ShowSlotMessage = 0x83, + WildHunterInfo = 0x84, + AccountMoreInfo = 0x85, + FindFirend = 0x86, + StageChange = 0x87, + DragonBallBox = 0x88, + AskUserWhetherUsePamsSong = 0x89, + TransferChannel = 0x8A, + DisallowedDeliveryQuestList = 0x8B, + MacroSysDataInit = 0x8C, + END_CHARACTERDATA = 0x8C, + BEGIN_STAGE = 0x8D, + SetField = 0x8D, + SetITC = 0x8E, + SetCashShop = 0x8F, + END_STAGE = 0x8F, + BEGIN_MAP = 0x90, + SetBackgroundEffect = 0x90, + SetMapObjectVisible = 0x91, + ClearBackgroundEffect = 0x92, + END_MAP = 0x92, + BEGIN_FIELD = 0x93, + TransferFieldReqIgnored = 0x93, + TransferChannelReqIgnored = 0x94, + FieldSpecificData = 0x95, + GroupMessage = 0x96, + Whisper = 0x97, + CoupleMessage = 0x98, + MobSummonItemUseResult = 0x99, + FieldEffect = 0x9A, + FieldObstacleOnOff = 0x9B, + FieldObstacleOnOffStatus = 0x9C, + FieldObstacleAllReset = 0x9D, + BlowWeather = 0x9E, + PlayJukeBox = 0x9F, + AdminResult = 0xA0, + Quiz = 0xA1, + Desc = 0xA2, + Clock = 0xA3, + CONTIMOVE = 0xA4, + CONTISTATE = 0xA5, + SetQuestClear = 0xA6, + SetQuestTime = 0xA7, + Warn = 0xA8, + SetObjectState = 0xA9, + DestroyClock = 0xAA, + ShowArenaResult = 0xAB, + StalkResult = 0xAC, + MassacreIncGauge = 0xAD, + MassacreResult = 0xAE, + QuickslotMappedInit = 0xAF, + FootHoldInfo = 0xB0, + RequestFootHoldInfo = 0xB1, + FieldKillCount = 0xB2, + BEGIN_USERPOOL = 0xB3, + UserEnterField = 0xB3, + UserLeaveField = 0xB4, + BEGIN_USERCOMMON = 0xB5, + UserChat = 0xB5, + UserChatNLCPQ = 0xB6, + UserADBoard = 0xB7, + UserMiniRoomBalloon = 0xB8, + UserConsumeItemEffect = 0xB9, + UserItemUpgradeEffect = 0xBA, + UserItemHyperUpgradeEffect = 0xBB, + UserItemOptionUpgradeEffect = 0xBC, + UserItemReleaseEffect = 0xBD, + UserItemUnreleaseEffect = 0xBE, + UserHitByUser = 0xBF, + UserTeslaTriangle = 0xC0, + UserFollowCharacter = 0xC1, + UserShowPQReward = 0xC2, + UserSetPhase = 0xC3, + SetPortalUsable = 0xC4, + ShowPamsSongResult = 0xC5, + BEGIN_PET = 0xC6, + PetActivated = 0xC6, + PetEvol = 0xC7, + PetTransferField = 0xC8, + PetMove = 0xC9, + PetAction = 0xCA, + PetNameChanged = 0xCB, + PetLoadExceptionList = 0xCC, + PetActionCommand = 0xCD, + END_PET = 0xCD, + BEGIN_DRAGON = 0xCE, + DragonEnterField = 0xCE, + DragonMove = 0xCF, + DragonLeaveField = 0xD0, + END_DRAGON = 0xD0, + END_USERCOMMON = 0xD1, + BEGIN_USERREMOTE = 0xD2, + UserMove = 0xD2, + UserMeleeAttack = 0xD3, + UserShootAttack = 0xD4, + UserMagicAttack = 0xD5, + UserBodyAttack = 0xD6, + UserSkillPrepare = 0xD7, + UserMovingShootAttackPrepare = 0xD8, + UserSkillCancel = 0xD9, + UserHit = 0xDA, + UserEmotion = 0xDB, + UserSetActiveEffectItem = 0xDC, + UserShowUpgradeTombEffect = 0xDD, + UserSetActivePortableChair = 0xDE, + UserAvatarModified = 0xDF, + UserEffectRemote = 0xE0, + UserTemporaryStatSet = 0xE1, + UserTemporaryStatReset = 0xE2, + UserHP = 0xE3, + UserGuildNameChanged = 0xE4, + UserGuildMarkChanged = 0xE5, + UserThrowGrenade = 0xE6, + END_USERREMOTE = 0xE6, + BEGIN_USERLOCAL = 0xE7, + UserSitResult = 0xE7, + UserEmotionLocal = 0xE8, + UserEffectLocal = 0xE9, + UserTeleport = 0xEA, + Premium = 0xEB, + MesoGive_Succeeded = 0xEC, + MesoGive_Failed = 0xED, + Random_Mesobag_Succeed = 0xEE, + Random_Mesobag_Failed = 0xEF, + FieldFadeInOut = 0xF0, + FieldFadeOutForce = 0xF1, + UserQuestResult = 0xF2, + NotifyHPDecByField = 0xF3, + UserPetSkillChanged = 0xF4, + UserBalloonMsg = 0xF5, + PlayEventSound = 0xF6, + PlayMinigameSound = 0xF7, + UserMakerResult = 0xF8, + UserOpenConsultBoard = 0xF9, + UserOpenClassCompetitionPage = 0xFA, + UserOpenUI = 0xFB, + UserOpenUIWithOption = 0xFC, + SetDirectionMode = 0xFD, + SetStandAloneMode = 0xFE, + UserHireTutor = 0xFF, + UserTutorMsg = 0x100, + IncCombo = 0x101, + UserRandomEmotion = 0x102, + ResignQuestReturn = 0x103, + PassMateName = 0x104, + SetRadioSchedule = 0x105, + UserOpenSkillGuide = 0x106, + UserNoticeMsg = 0x107, + UserChatMsg = 0x108, + UserBuffzoneEffect = 0x109, + UserGoToCommoditySN = 0x10A, + UserDamageMeter = 0x10B, + UserTimeBombAttack = 0x10C, + UserPassiveMove = 0x10D, + UserFollowCharacterFailed = 0x10E, + UserRequestVengeance = 0x10F, + UserRequestExJablin = 0x110, + UserAskAPSPEvent = 0x111, + QuestGuideResult = 0x112, + UserDeliveryQuest = 0x113, + SkillCooltimeSet = 0x114, + END_USERLOCAL = 0x114, + END_USERPOOL = 0x115, + BEGIN_SUMMONED = 0x116, + SummonedEnterField = 0x116, + SummonedLeaveField = 0x117, + SummonedMove = 0x118, + SummonedAttack = 0x119, + SummonedSkill = 0x11A, + SummonedHit = 0x11B, + END_SUMMONED = 0x11B, + BEGIN_MOBPOOL = 0x11C, + MobEnterField = 0x11C, + MobLeaveField = 0x11D, + MobChangeController = 0x11E, + BEGIN_MOB = 0x11F, + MobMove = 0x11F, + MobCtrlAck = 0x120, + MobCtrlHint = 0x121, + MobStatSet = 0x122, + MobStatReset = 0x123, + MobSuspendReset = 0x124, + MobAffected = 0x125, + MobDamaged = 0x126, + MobSpecialEffectBySkill = 0x127, + MobHPChange = 0x128, + MobCrcKeyChanged = 0x129, + MobHPIndicator = 0x12A, + MobCatchEffect = 0x12B, + MobEffectByItem = 0x12C, + MobSpeaking = 0x12D, + MobChargeCount = 0x12E, + MobSkillDelay = 0x12F, + MobRequestResultEscortInfo = 0x130, + MobEscortStopEndPermmision = 0x131, + MobEscortStopSay = 0x132, + MobEscortReturnBefore = 0x133, + MobNextAttack = 0x134, + MobAttackedByMob = 0x135, + END_MOB = 0x135, + END_MOBPOOL = 0x136, + BEGIN_NPCPOOL = 0x137, + NpcEnterField = 0x137, + NpcLeaveField = 0x138, + NpcChangeController = 0x139, + BEGIN_NPC = 0x13A, + NpcMove = 0x13A, + NpcUpdateLimitedInfo = 0x13B, + NpcSpecialAction = 0x13C, + END_NPC = 0x13C, + BEGIN_NPCTEMPLATE = 0x13D, + NpcSetScript = 0x13D, + END_NPCTEMPLATE = 0x13D, + END_NPCPOOL = 0x13E, + BEGIN_EMPLOYEEPOOL = 0x13F, + EmployeeEnterField = 0x13F, + EmployeeLeaveField = 0x140, + EmployeeMiniRoomBalloon = 0x141, + END_EMPLOYEEPOOL = 0x141, + BEGIN_DROPPOOL = 0x142, + DropEnterField = 0x142, + DropReleaseAllFreeze = 0x143, + DropLeaveField = 0x144, + END_DROPPOOL = 0x144, + BEGIN_MESSAGEBOXPOOL = 0x145, + CreateMessageBoxFailed = 0x145, + MessageBoxEnterField = 0x146, + MessageBoxLeaveField = 0x147, + END_MESSAGEBOXPOOL = 0x147, + BEGIN_AFFECTEDAREAPOOL = 0x148, + AffectedAreaCreated = 0x148, + AffectedAreaRemoved = 0x149, + END_AFFECTEDAREAPOOL = 0x149, + BEGIN_TOWNPORTALPOOL = 0x14A, + TownPortalCreated = 0x14A, + TownPortalRemoved = 0x14B, + END_TOWNPORTALPOOL = 0x14B, + BEGIN_OPENGATEPOOL = 0x14C, + OpenGateCreated = 0x14C, + OpenGateRemoved = 0x14D, + END_OPENGATEPOOL = 0x14D, + BEGIN_REACTORPOOL = 0x14E, + ReactorChangeState = 0x14E, + ReactorMove = 0x14F, + ReactorEnterField = 0x150, + ReactorLeaveField = 0x151, + END_REACTORPOOL = 0x151, + BEGIN_ETCFIELDOBJ = 0x152, + SnowBallState = 0x152, + SnowBallHit = 0x153, + SnowBallMsg = 0x154, + SnowBallTouch = 0x155, + CoconutHit = 0x156, + CoconutScore = 0x157, + HealerMove = 0x158, + PulleyStateChange = 0x159, + MCarnivalEnter = 0x15A, + MCarnivalPersonalCP = 0x15B, + MCarnivalTeamCP = 0x15C, + MCarnivalResultSuccess = 0x15D, + MCarnivalResultFail = 0x15E, + MCarnivalDeath = 0x15F, + MCarnivalMemberOut = 0x160, + MCarnivalGameResult = 0x161, + ArenaScore = 0x162, + BattlefieldEnter = 0x163, + BattlefieldScore = 0x164, + BattlefieldTeamChanged = 0x165, + WitchtowerScore = 0x166, + HontaleTimer = 0x167, + ChaosZakumTimer = 0x168, + HontailTimer = 0x169, + ZakumTimer = 0x16A, + END_ETCFIELDOBJ = 0x16A, + BEGIN_SCRIPT = 0x16B, + ScriptMessage = 0x16B, + END_SCRIPT = 0x16B, + BEGIN_SHOP = 0x16C, + OpenShopDlg = 0x16C, + ShopResult = 0x16D, + END_SHOP = 0x16D, + BEGIN_ADMINSHOP = 0x16E, + AdminShopResult = 0x16E, + AdminShopCommodity = 0x16F, + END_ADMINSHOP = 0x16F, + TrunkResult = 0x170, + BEGIN_STOREBANK = 0x171, + StoreBankGetAllResult = 0x171, + StoreBankResult = 0x172, + END_STOREBANK = 0x172, + RPSGame = 0x173, + Messenger = 0x174, + MiniRoom = 0x175, + BEGIN_TOURNAMENT = 0x176, + Tournament = 0x176, + TournamentMatchTable = 0x177, + TournamentSetPrize = 0x178, + TournamentNoticeUEW = 0x179, + TournamentAvatarInfo = 0x17A, + END_TOURNAMENT = 0x17A, + BEGIN_WEDDING = 0x17B, + WeddingProgress = 0x17B, + WeddingCremonyEnd = 0x17C, + END_WEDDING = 0x17C, + Parcel = 0x17D, + END_FIELD = 0x17D, + BEGIN_CASHSHOP = 0x17E, + CashShopChargeParamResult = 0x17E, + CashShopQueryCashResult = 0x17F, + CashShopCashItemResult = 0x180, + CashShopPurchaseExpChanged = 0x181, + CashShopGiftMateInfoResult = 0x182, + CashShopCheckDuplicatedIDResult = 0x183, + CashShopCheckNameChangePossibleResult = 0x184, + CashShopRegisterNewCharacterResult = 0x185, + CashShopCheckTransferWorldPossibleResult = 0x186, + CashShopGachaponStampItemResult = 0x187, + CashShopCashItemGachaponResult = 0x188, + CashShopCashGachaponOpenResult = 0x189, + ChangeMaplePointResult = 0x18A, + CashShopOneADay = 0x18B, + CashShopNoticeFreeCashItem = 0x18C, + CashShopMemberShopResult = 0x18D, + END_CASHSHOP = 0x18D, + BEGIN_FUNCKEYMAPPED = 0x18E, + FuncKeyMappedInit = 0x18E, + PetConsumeItemInit = 0x18F, + PetConsumeMPItemInit = 0x190, + END_FUNCKEYMAPPED = 0x190, + CheckSSN2OnCreateNewCharacterResult = 0x191, + CheckSPWOnCreateNewCharacterResult = 0x192, + FirstSSNOnCreateNewCharacterResult = 0x193, + BEGIN_MAPLETV = 0x194, + MapleTVUpdateMessage = 0x195, + MapleTVClearMessage = 0x196, + MapleTVSendMessageResult = 0x197, + BroadSetFlashChangeEvent = 0x198, + END_MAPLETV = 0x199, + BEGIN_ITC = 0x19A, + ITCChargeParamResult = 0x19A, + ITCQueryCashResult = 0x19B, + ITCNormalItemResult = 0x19C, + END_ITC = 0x19C, + BEGIN_CHARACTERSALE = 0x19D, + CheckDuplicatedIDResultInCS = 0x19D, + CreateNewCharacterResultInCS = 0x19E, + CreateNewCharacterFailInCS = 0x19F, + CharacterSale = 0x1A0, + END_CHARACTERSALE = 0x1A0, + BEGIN_GOLDHAMMER = 0x1A1, + GoldHammere_s = 0x1A1, + GoldHammerResult = 0x1A2, + GoldHammere_e = 0x1A3, + END_GOLDHAMMER = 0x1A3, + BEGIN_BATTLERECORD = 0x1A4, + BattleRecord_s = 0x1A4, + BattleRecordDotDamageInfo = 0x1A5, + BattleRecordRequestResult = 0x1A6, + BattleRecord_e = 0x1A7, + END_BATTLERECORD = 0x1A7, + BEGIN_ITEMUPGRADE = 0x1A8, + ItemUpgrade_s = 0x1A8, + ItemUpgradeResult = 0x1A9, + ItemUpgradeFail = 0x1AA, + ItemUpgrade_e = 0x1AB, + END_ITEMUPGRADE = 0x1AB, + BEGIN_VEGA = 0x1AC, + Vega_s = 0x1AC, + VegaResult = 0x1AD, + VegaFail = 0x1AE, + Vega_e = 0x1AF, + END_VEGA = 0x1AF, + LogoutGift = 0x1B0, + NO = 0x1B1 +} diff --git a/src/common/Edelstein.Common.Gameplay/packages.lock.json b/src/common/Edelstein.Common.Gameplay/packages.lock.json new file mode 100644 index 000000000..1e857adc4 --- /dev/null +++ b/src/common/Edelstein.Common.Gameplay/packages.lock.json @@ -0,0 +1,138 @@ +{ + "version": 2, + "dependencies": { + "net9.0": { + "Injectio": { + "type": "Direct", + "requested": "[3.1.0, )", + "resolved": "3.1.0", + "contentHash": "7b7IdkoJA1ecyHYjstI0TraeilfaRdwmoBpR09oOYxuOTHYvKjPm5Odvjcdp6WMjcQF2WUs7xm169w9uXEgA1g==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" + } + }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "Direct", + "requested": "[9.0.0-preview.3.24172.9, )", + "resolved": "9.0.0-preview.3.24172.9", + "contentHash": "b9wNSdoc20aarUp1ktpS2ERzO9MDqLflH2TmW/CXmjEnCli8CQ5gI+BeTyHa3j4RXwuhJiV4ssvthXYQj5rpWQ==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0-preview.3.24172.9" + } + }, + "MinVer": { + "type": "Direct", + "requested": "[5.0.0, )", + "resolved": "5.0.0", + "contentHash": "ybkgpQMtt0Fo91l5rYtE3TZtD+Nmy5Ko091xvfXXOosQdMi30XO2EZ2+ShZt89gdu7RMmJqZaJ+e1q6d+6+KNw==" + }, + "Grpc.Core.Api": { + "type": "Transitive", + "resolved": "2.51.0", + "contentHash": "WUYCnxZKfdBWCKNs08lWFRoTjESt3iyFDthsZu5KcWguZ4OnnXrTu/K5mIdO+R9dUhuw5Xm1ygUrI1e2q8d1YA==", + "dependencies": { + "System.Memory": "4.5.3" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions": { + "type": "Transitive", + "resolved": "9.0.0-preview.3.24172.9", + "contentHash": "3176Psy4JxVCJI9L57MyLXt+0HmCylzFmblmmG4GNbxCArrt8slJGWootNRj7rJBh1CPNXOI3nwk9VvDLj/8oQ==" + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "2.1.0", + "contentHash": "ok+RPAtESz/9MUXeIEz6Lv5XAGQsaNmEYXMsgVALj4D7kqC8gveKWXWXbufLySR2fWrwZf8smyN5RmHu0e4BHA==" + }, + "protobuf-net": { + "type": "Transitive", + "resolved": "2.4.8", + "contentHash": "O+vbVVDxTWlFRBe5OsAmMKqqD7WQ7TPIH97Nr/Pk8gDxtNW77seiDmXfxnODuWIkm0fYW7kE5ILq8jHsgH79yg==", + "dependencies": { + "System.ServiceModel.Primitives": "4.5.3" + } + }, + "System.Memory": { + "type": "Transitive", + "resolved": "4.5.3", + "contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA==" + }, + "System.Private.ServiceModel": { + "type": "Transitive", + "resolved": "4.5.3", + "contentHash": "ancrQgJagx+yC4SZbuE+eShiEAUIF0E1d21TRSoy1C/rTwafAVcBr/fKibkq5TQzyy9uNil2tx2/iaUxsy0S9g==", + "dependencies": { + "Microsoft.NETCore.Platforms": "2.1.0", + "System.Reflection.DispatchProxy": "4.5.0", + "System.Security.Principal.Windows": "4.5.0" + } + }, + "System.Reflection.DispatchProxy": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "+UW1hq11TNSeb+16rIk8hRQ02o339NFyzMc4ma/FqmxBzM30l1c2IherBB4ld1MNcenS48fz8tbt50OW4rVULA==" + }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "U77HfRXlZlOeIXd//Yoj6Jnk8AXlbeisf1oq1os+hxOGVnuG+lGSfGqTwTZBoORFF6j/0q7HXIl8cqwQ9aUGqQ==", + "dependencies": { + "Microsoft.NETCore.Platforms": "2.0.0" + } + }, + "System.ServiceModel.Primitives": { + "type": "Transitive", + "resolved": "4.5.3", + "contentHash": "Wc9Hgg4Cmqi416zvEgq2sW1YYCGuhwWzspDclJWlFZqY6EGhFUPZU+kVpl5z9kAgrSOQP7/Uiik+PtSQtmq+5A==", + "dependencies": { + "System.Private.ServiceModel": "4.5.3" + } + }, + "edelstein.common.utilities": { + "type": "Project", + "dependencies": { + "Edelstein.Protocol.Utilities": "[1.0.0, )", + "Microsoft.IO.RecyclableMemoryStream": "[3.0.0, )" + } + }, + "edelstein.protocol.gameplay": { + "type": "Project", + "dependencies": { + "Edelstein.Protocol.Network": "[1.0.0, )", + "Edelstein.Protocol.Services.Server": "[1.0.0, )" + } + }, + "edelstein.protocol.network": { + "type": "Project", + "dependencies": { + "Edelstein.Protocol.Utilities": "[1.0.0, )" + } + }, + "edelstein.protocol.services.server": { + "type": "Project", + "dependencies": { + "protobuf-net.Grpc": "[1.1.1, )" + } + }, + "edelstein.protocol.utilities": { + "type": "Project" + }, + "Microsoft.IO.RecyclableMemoryStream": { + "type": "CentralTransitive", + "requested": "[3.0.0, )", + "resolved": "3.0.0", + "contentHash": "irv0HuqoH8Ig5i2fO+8dmDNdFdsrO+DoQcedwIlb810qpZHBNQHZLW7C/AHBQDgLLpw2T96vmMAy/aE4Yj55Sg==" + }, + "protobuf-net.Grpc": { + "type": "CentralTransitive", + "requested": "[1.1.1, )", + "resolved": "1.1.1", + "contentHash": "uThFb/iUplzuXEa/cztJaNGpKLRQRb515STtQX99IS1MKh8Qsunw6MjjU+9rjo8s9UymR6lN9Ab6xT3adBlyDg==", + "dependencies": { + "Grpc.Core.Api": "2.51.0", + "protobuf-net": "2.4.8" + } + } + } + } +} \ No newline at end of file diff --git a/src/common/Edelstein.Common.Network.DotNetty/Handlers/NettyTransportAcceptorHandler.cs b/src/common/Edelstein.Common.Network.DotNetty/Handlers/NettyTransportAcceptorHandler.cs index 3f3c9987a..fb629296d 100644 --- a/src/common/Edelstein.Common.Network.DotNetty/Handlers/NettyTransportAcceptorHandler.cs +++ b/src/common/Edelstein.Common.Network.DotNetty/Handlers/NettyTransportAcceptorHandler.cs @@ -1,4 +1,5 @@ using System; +using DotNetty.Common.Utilities; using DotNetty.Transport.Channels; using Edelstein.Common.Utilities.Buffers; using Edelstein.Protocol.Network; @@ -8,12 +9,15 @@ namespace Edelstein.Common.Network.DotNetty.Handlers; -public class NettyTransportAcceptorHandler( +public class NettyTransportAcceptorHandler( TransportVersion version, - IAdapterInitializer initializer, + ISocketUserCreator creator, + ISocketAdapter socketAdapter, IRepository sockets ) : ChannelHandlerAdapter + where TSocketUser : class, ISocketUser { + private readonly AttributeKey _userKey = AttributeKey.ValueOf("User"); public override void ChannelActive(IChannelHandlerContext context) { @@ -23,7 +27,7 @@ public override void ChannelActive(IChannelHandlerContext context) (uint)random.Next(), (uint)random.Next() ); - var newAdapter = initializer.Initialize(newSocket); + var newUser = creator.CreateUser(newSocket); using var handshake = new PacketWriter(); handshake.WriteShort(version.Major); @@ -40,36 +44,41 @@ public override void ChannelActive(IChannelHandlerContext context) .WriteByte(version.Locale); _ = newSocket.Dispatch(packet.Build()); - + context.Channel.GetAttribute(NettyAttributes.SocketKey).Set(newSocket); - context.Channel.GetAttribute(NettyAttributes.AdapterKey).Set(newAdapter); + context.Channel.GetAttribute(_userKey).Set(newUser); _ = sockets.Insert(newSocket); } public override void ChannelInactive(IChannelHandlerContext context) { - var adapter = context.Channel.GetAttribute(NettyAttributes.AdapterKey).Get(); + var user = context.Channel.GetAttribute(_userKey).Get(); - adapter?.OnDisconnect(); + socketAdapter.OnDisconnect(user); base.ChannelInactive(context); - if (adapter == null) return; + if (user == null) return; - _ = sockets.Delete(adapter.Socket); + _ = sockets.Delete(user.Socket); } public override void ChannelRead(IChannelHandlerContext context, object message) { - var adapter = context.Channel.GetAttribute(NettyAttributes.AdapterKey).Get(); + var user = context.Channel.GetAttribute(_userKey).Get(); using var packet = (IPacket)message; - adapter?.OnPacket(packet); + if (user == null) return; + + socketAdapter.OnPacket(user, packet); } public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) { - var adapter = context.Channel.GetAttribute(NettyAttributes.AdapterKey).Get(); - adapter?.OnException(exception); + var user = context.Channel.GetAttribute(_userKey).Get(); + + if (user == null) return; + + socketAdapter.OnException(user, exception); } } diff --git a/src/common/Edelstein.Common.Network.DotNetty/Handlers/NettyTransportConnectorHandler.cs b/src/common/Edelstein.Common.Network.DotNetty/Handlers/NettyTransportConnectorHandler.cs index 32de3408e..482b89afd 100644 --- a/src/common/Edelstein.Common.Network.DotNetty/Handlers/NettyTransportConnectorHandler.cs +++ b/src/common/Edelstein.Common.Network.DotNetty/Handlers/NettyTransportConnectorHandler.cs @@ -1,4 +1,5 @@ using System; +using DotNetty.Common.Utilities; using DotNetty.Transport.Channels; using Edelstein.Common.Utilities.Buffers; using Edelstein.Protocol.Network; @@ -8,21 +9,24 @@ namespace Edelstein.Common.Network.DotNetty.Handlers; -public class NettyTransportConnectorHandler( +public class NettyTransportConnectorHandler( TransportVersion transportVersion, - IAdapterInitializer initializer, + ISocketUserCreator creator, + ISocketAdapter socketAdapter, IRepository sockets ) : ChannelHandlerAdapter + where TSocketUser : class, ISocketUser { - + private readonly AttributeKey _userKey = AttributeKey.ValueOf("User"); + public override void ChannelRead(IChannelHandlerContext context, object message) { - var adapter = context.Channel.GetAttribute(NettyAttributes.AdapterKey).Get(); + var user = context.Channel.GetAttribute(_userKey).Get(); using var packet = (IPacket)message; - if (adapter != null) + if (user != null) { - adapter.OnPacket(packet); + socketAdapter.OnPacket(user, packet); } else { @@ -42,10 +46,10 @@ public override void ChannelRead(IChannelHandlerContext context, object message) seqSend, seqRecv ); - var newAdapter = initializer.Initialize(newSocket); + var newAdapter = creator.CreateUser(newSocket); context.Channel.GetAttribute(NettyAttributes.SocketKey).Set(newSocket); - context.Channel.GetAttribute(NettyAttributes.AdapterKey).Set(newAdapter); + context.Channel.GetAttribute(_userKey).Set(newAdapter); _ = sockets.Insert(newSocket); } @@ -53,21 +57,23 @@ public override void ChannelRead(IChannelHandlerContext context, object message) public override void ChannelInactive(IChannelHandlerContext context) { - var adapter = context.Channel.GetAttribute(NettyAttributes.AdapterKey).Get(); + var user = context.Channel.GetAttribute(_userKey).Get(); - adapter?.OnDisconnect(); + socketAdapter.OnDisconnect(user); base.ChannelInactive(context); - if (adapter == null) return; + if (user == null) return; - _ = sockets.Delete(adapter.Socket); + _ = sockets.Delete(user.Socket); } public override void ExceptionCaught(IChannelHandlerContext context, Exception exception) { - var adapter = context.Channel.GetAttribute(NettyAttributes.AdapterKey).Get(); - - adapter?.OnException(exception); + var user = context.Channel.GetAttribute(_userKey).Get(); + + if (user == null) return; + + socketAdapter.OnException(user, exception); } } diff --git a/src/common/Edelstein.Common.Network.DotNetty/NettyAttributes.cs b/src/common/Edelstein.Common.Network.DotNetty/NettyAttributes.cs index 80e244e20..6b6aff2ec 100644 --- a/src/common/Edelstein.Common.Network.DotNetty/NettyAttributes.cs +++ b/src/common/Edelstein.Common.Network.DotNetty/NettyAttributes.cs @@ -6,5 +6,4 @@ namespace Edelstein.Common.Network.DotNetty; public static class NettyAttributes { public static readonly AttributeKey SocketKey = AttributeKey.ValueOf("Socket"); - public static readonly AttributeKey AdapterKey = AttributeKey.ValueOf("Adapter"); } diff --git a/src/common/Edelstein.Common.Network.DotNetty/NettySocket.cs b/src/common/Edelstein.Common.Network.DotNetty/NettySocket.cs index 57ff80b41..f5665b6aa 100644 --- a/src/common/Edelstein.Common.Network.DotNetty/NettySocket.cs +++ b/src/common/Edelstein.Common.Network.DotNetty/NettySocket.cs @@ -1,5 +1,4 @@ -using System; -using System.Net; +using System.Net; using System.Threading.Tasks; using DotNetty.Transport.Channels; using Edelstein.Protocol.Network; @@ -26,9 +25,6 @@ public class NettySocket( public bool IsDataEncrypted { get; } = isDataEncrypted; - public DateTime LastAliveSent { get; set; } - public DateTime LastAliveRecv { get; set; } - public async Task Dispatch(IPacket packet) { if (channel.IsWritable) diff --git a/src/common/Edelstein.Common.Network.DotNetty/Transports/NettyTransportAcceptor.cs b/src/common/Edelstein.Common.Network.DotNetty/Transports/NettyTransportAcceptor.cs index 0241ff213..62d340802 100644 --- a/src/common/Edelstein.Common.Network.DotNetty/Transports/NettyTransportAcceptor.cs +++ b/src/common/Edelstein.Common.Network.DotNetty/Transports/NettyTransportAcceptor.cs @@ -11,14 +11,15 @@ using Edelstein.Protocol.Network; using Edelstein.Protocol.Network.Transports; using Edelstein.Protocol.Utilities.Repositories; -using Injectio.Attributes; namespace Edelstein.Common.Network.DotNetty.Transports; -public class NettyTransportAcceptor( - IAdapterInitializer initializer, - TransportVersion version -) : ITransportAcceptor +public class NettyTransportAcceptor( + TransportVersion version, + ISocketUserCreator creator, + ISocketAdapter socketAdapter +) : ITransportAcceptor + where TSocketUser : class, ISocketUser { private readonly IRepository _sockets = new Repository(); @@ -38,7 +39,7 @@ public async Task Accept(string host, int port) ch.Pipeline.AddLast( new ReadTimeoutHandler(TimeSpan.FromMinutes(5)), new NettyPacketDecoder(version, aesCipher, igCipher), - new NettyTransportAcceptorHandler(version, initializer, _sockets), + new NettyTransportAcceptorHandler(version, creator, socketAdapter, _sockets), new NettyPacketEncoder(version, aesCipher, igCipher) ); })) diff --git a/src/common/Edelstein.Common.Network.DotNetty/Transports/NettyTransportConnector.cs b/src/common/Edelstein.Common.Network.DotNetty/Transports/NettyTransportConnector.cs index 97e092ee7..f3d1d7176 100644 --- a/src/common/Edelstein.Common.Network.DotNetty/Transports/NettyTransportConnector.cs +++ b/src/common/Edelstein.Common.Network.DotNetty/Transports/NettyTransportConnector.cs @@ -9,14 +9,15 @@ using Edelstein.Protocol.Network; using Edelstein.Protocol.Network.Transports; using Edelstein.Protocol.Utilities.Repositories; -using Injectio.Attributes; namespace Edelstein.Common.Network.DotNetty.Transports; -public class NettyTransportConnector( - IAdapterInitializer initializer, - TransportVersion version +public class NettyTransportConnector( + TransportVersion version, + ISocketUserCreator creator, + ISocketAdapter socketAdapter ) : ITransportConnector + where TSocketUser : class, ISocketUser { private readonly IRepository _sockets = new Repository(); @@ -34,7 +35,7 @@ public async Task Connect(string host, int port) { ch.Pipeline.AddLast( new NettyPacketDecoder(version, aesCipher, igCipher), - new NettyTransportConnectorHandler(version, initializer, _sockets), + new NettyTransportConnectorHandler(version, creator, socketAdapter, _sockets), new NettyPacketEncoder(version, aesCipher, igCipher) ); })) diff --git a/src/common/Edelstein.Common.Network.DotNetty/packages.lock.json b/src/common/Edelstein.Common.Network.DotNetty/packages.lock.json index 7e23aae9e..6660eb86d 100644 --- a/src/common/Edelstein.Common.Network.DotNetty/packages.lock.json +++ b/src/common/Edelstein.Common.Network.DotNetty/packages.lock.json @@ -95,11 +95,6 @@ "Microsoft.Extensions.Options": "5.0.0" } }, - "Microsoft.Extensions.Logging.Abstractions": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "NxP6ahFcBnnSfwNBi2KH2Oz8Xl5Sm2krjId/jRR3I7teFphwiUoUeZPwTNA21EX+5PtjqmyAvKaOeBXcJjcH/w==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "5.0.0", @@ -143,6 +138,12 @@ "edelstein.protocol.utilities": { "type": "Project" }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "CentralTransitive", + "requested": "[9.0.0-preview.3.24172.9, )", + "resolved": "5.0.0", + "contentHash": "NxP6ahFcBnnSfwNBi2KH2Oz8Xl5Sm2krjId/jRR3I7teFphwiUoUeZPwTNA21EX+5PtjqmyAvKaOeBXcJjcH/w==" + }, "Microsoft.IO.RecyclableMemoryStream": { "type": "CentralTransitive", "requested": "[3.0.0, )", diff --git a/src/common/Edelstein.Common.Services.Server/packages.lock.json b/src/common/Edelstein.Common.Services.Server/packages.lock.json index 4ea18bc98..708a6634c 100644 --- a/src/common/Edelstein.Common.Services.Server/packages.lock.json +++ b/src/common/Edelstein.Common.Services.Server/packages.lock.json @@ -256,14 +256,6 @@ "Microsoft.Extensions.Options": "9.0.0-preview.3.24172.9" } }, - "Microsoft.Extensions.Logging.Abstractions": { - "type": "Transitive", - "resolved": "9.0.0-preview.3.24172.9", - "contentHash": "b9wNSdoc20aarUp1ktpS2ERzO9MDqLflH2TmW/CXmjEnCli8CQ5gI+BeTyHa3j4RXwuhJiV4ssvthXYQj5rpWQ==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0-preview.3.24172.9" - } - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "9.0.0-preview.3.24172.9", @@ -465,6 +457,15 @@ "Microsoft.Extensions.Configuration.Abstractions": "9.0.0-preview.3.24172.9" } }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "CentralTransitive", + "requested": "[9.0.0-preview.3.24172.9, )", + "resolved": "9.0.0-preview.3.24172.9", + "contentHash": "b9wNSdoc20aarUp1ktpS2ERzO9MDqLflH2TmW/CXmjEnCli8CQ5gI+BeTyHa3j4RXwuhJiV4ssvthXYQj5rpWQ==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.0-preview.3.24172.9" + } + }, "protobuf-net.Grpc": { "type": "CentralTransitive", "requested": "[1.1.1, )", diff --git a/src/common/Edelstein.Common.Utilities/Templates/TemplateCollection.cs b/src/common/Edelstein.Common.Utilities/Templates/TemplateCollection.cs new file mode 100644 index 000000000..54eae9d93 --- /dev/null +++ b/src/common/Edelstein.Common.Utilities/Templates/TemplateCollection.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Edelstein.Protocol.Utilities.Templates; + +namespace Edelstein.Common.Utilities.Templates; + +public class TemplateCollection( + IReadOnlyDictionary templates +) : + ITemplateCollection + where TTemplate : ITemplate +{ + public int Count => templates.Count; + + public Task Retrieve(int key) + => Task.FromResult(templates.TryGetValue(key, out var result) ? result : default); + + public Task> RetrieveAll() + => Task.FromResult>(templates.Values.ToImmutableArray()); +} diff --git a/src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionLazy.cs b/src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionLazy.cs new file mode 100644 index 000000000..c0f8ea229 --- /dev/null +++ b/src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionLazy.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Edelstein.Protocol.Utilities.Templates; + +namespace Edelstein.Common.Utilities.Templates; + +public class TemplateCollectionLazy( + IReadOnlyDictionary> providers +) : + ITemplateCollection + where TTemplate : ITemplate +{ + public int Count => providers.Count; + + public async Task Retrieve(int key) + => providers.TryGetValue(key, out var provider) ? await provider.Provide() : default; + + public async Task> RetrieveAll() + => await Task.WhenAll(providers.Values.Select(p => p.Provide())); +} diff --git a/src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionProviderEager.cs b/src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionProviderEager.cs new file mode 100644 index 000000000..bd01609f1 --- /dev/null +++ b/src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionProviderEager.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Edelstein.Protocol.Utilities.Templates; + +namespace Edelstein.Common.Utilities.Templates; + +public class TemplateCollectionProviderEager( + int id, + TTemplate template +) : ITemplateCollectionProvider + where TTemplate : ITemplate +{ + + public int ID { get; } = id; + + public Task Provide() => Task.FromResult(template); +} diff --git a/src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionProviderLazy.cs b/src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionProviderLazy.cs new file mode 100644 index 000000000..3791d0d80 --- /dev/null +++ b/src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionProviderLazy.cs @@ -0,0 +1,19 @@ +using System; +using System.Threading.Tasks; +using Edelstein.Protocol.Utilities.Templates; + +namespace Edelstein.Common.Utilities.Templates; + +public class TemplateCollectionProviderLazy( + int id, + Func func +) : ITemplateCollectionProvider + where TTemplate : ITemplate +{ + private TTemplate? _template = default; + + public int ID { get; } = id; + + public Task Provide() + => Task.FromResult(_template ??= func.Invoke()); +} diff --git a/src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionProviderLazyHolder.cs b/src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionProviderLazyHolder.cs new file mode 100644 index 000000000..bd47ef303 --- /dev/null +++ b/src/common/Edelstein.Common.Utilities/Templates/TemplateCollectionProviderLazyHolder.cs @@ -0,0 +1,7 @@ +using Edelstein.Protocol.Utilities.Templates; + +namespace Edelstein.Common.Utilities.Templates; + +public record TemplateCollectionProviderLazyHolder( + TTemplate Template +) where TTemplate : ITemplate; diff --git a/src/common/Edelstein.Common.Utilities/Templates/TemplateManager.cs b/src/common/Edelstein.Common.Utilities/Templates/TemplateManager.cs new file mode 100644 index 000000000..f9995502b --- /dev/null +++ b/src/common/Edelstein.Common.Utilities/Templates/TemplateManager.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Edelstein.Protocol.Utilities.Templates; +using Injectio.Attributes; + +namespace Edelstein.Common.Utilities.Templates; + +[RegisterScoped(ImplementationType = typeof(TemplateManager<>), ServiceType = typeof(ITemplateManager<>))] +public class TemplateManager : + ITemplateManager + where TTemplate : ITemplate +{ + private readonly IDictionary> _providers = new Dictionary>(); + + public int Count => _providers.Count; + + public async Task Retrieve(int key) => + _providers.TryGetValue(key, out var provider) ? await provider.Provide() : default; + + public async Task> RetrieveAll() => + await Task.WhenAll(_providers.Values.Select(p => p.Provide())); + + public Task> Insert(ITemplateCollectionProvider entry) => + Task.FromResult(_providers[entry.ID] = entry); +} diff --git a/src/protocol/Directory.Build.props b/src/protocol/Directory.Build.props index 3eaad973a..ca40099d7 100644 --- a/src/protocol/Directory.Build.props +++ b/src/protocol/Directory.Build.props @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStage.cs b/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStage.cs deleted file mode 100644 index 45807be81..000000000 --- a/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStage.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Edelstein.Protocol.Gameplay.Login; - -public interface ILoginStage : IStage; diff --git a/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStageSystem.cs b/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStageSystem.cs index 5a83b289b..d0f2cca0c 100644 --- a/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStageSystem.cs +++ b/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStageSystem.cs @@ -1,3 +1,6 @@ -namespace Edelstein.Protocol.Gameplay.Login; +namespace Edelstein.Protocol.Gameplay.Login; -public interface ILoginStageSystem : IStageSystem; +public interface ILoginStageSystem : IStageSystem +{ + ILoginStageSystemOptions Options { get; } +} diff --git a/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStageSystemOptions.cs b/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStageSystemOptions.cs index 66c804450..e34eaca16 100644 --- a/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStageSystemOptions.cs +++ b/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStageSystemOptions.cs @@ -1,4 +1,4 @@ -using Edelstein.Protocol.Services.Server; +using Edelstein.Protocol.Services.Server; namespace Edelstein.Protocol.Gameplay.Login; diff --git a/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStageUser.cs b/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStageUser.cs index 567c3b860..4d98ca436 100644 --- a/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStageUser.cs +++ b/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStageUser.cs @@ -1,3 +1,3 @@ -namespace Edelstein.Protocol.Gameplay.Login; +namespace Edelstein.Protocol.Gameplay.Login; -public interface ILoginStageUser : IStageUser; +public interface ILoginStageUser : IStageUser; diff --git a/src/protocol/Edelstein.Protocol.Gameplay/Edelstein.Protocol.Gameplay.csproj b/src/protocol/Edelstein.Protocol.Gameplay/Edelstein.Protocol.Gameplay.csproj index b4fa637a3..6d8b4eb8d 100644 --- a/src/protocol/Edelstein.Protocol.Gameplay/Edelstein.Protocol.Gameplay.csproj +++ b/src/protocol/Edelstein.Protocol.Gameplay/Edelstein.Protocol.Gameplay.csproj @@ -3,4 +3,7 @@ + + + diff --git a/src/protocol/Edelstein.Protocol.Gameplay/IStage.cs b/src/protocol/Edelstein.Protocol.Gameplay/IStage.cs index 2f78a2e8b..2c3e222a4 100644 --- a/src/protocol/Edelstein.Protocol.Gameplay/IStage.cs +++ b/src/protocol/Edelstein.Protocol.Gameplay/IStage.cs @@ -1,14 +1,11 @@ -using System.Threading.Tasks; -using Edelstein.Protocol.Services.Server; +using System.Threading.Tasks; namespace Edelstein.Protocol.Gameplay; -public interface IStage - where TStageSystem : IStageSystem - where TStageOptions : IServerEntry +public interface IStage + where TStageSystem : IStageSystem + where TStageUser : IStageUser { - TStageSystem System { get; } - - Task Enter(IStageUser user); - Task Leave(IStageUser user); + Task Enter(TStageUser user); + Task Leave(TStageUser user); } diff --git a/src/protocol/Edelstein.Protocol.Gameplay/IStageSystem.cs b/src/protocol/Edelstein.Protocol.Gameplay/IStageSystem.cs index 857ec8466..cf0a2cf2a 100644 --- a/src/protocol/Edelstein.Protocol.Gameplay/IStageSystem.cs +++ b/src/protocol/Edelstein.Protocol.Gameplay/IStageSystem.cs @@ -1,9 +1,11 @@ -using Edelstein.Protocol.Services.Server; +using Edelstein.Protocol.Network; +using Edelstein.Protocol.Utilities.Repositories; namespace Edelstein.Protocol.Gameplay; -public interface IStageSystem - where TStageOptions : IServerEntry -{ - TStageOptions Options { get; } -} +public interface IStageSystem : + IRepositoryEntry, + ISocketUserCreator, + ISocketAdapter + where TStageUser : IStageUser + where TStageSystem : IStageSystem; diff --git a/src/protocol/Edelstein.Protocol.Gameplay/IStageUser.cs b/src/protocol/Edelstein.Protocol.Gameplay/IStageUser.cs index a79ebcfd1..de19d0cc0 100644 --- a/src/protocol/Edelstein.Protocol.Gameplay/IStageUser.cs +++ b/src/protocol/Edelstein.Protocol.Gameplay/IStageUser.cs @@ -1,12 +1,10 @@ -using Edelstein.Protocol.Network; -using Edelstein.Protocol.Services.Server; +using Edelstein.Protocol.Network; namespace Edelstein.Protocol.Gameplay; -public interface IStageUser : IAdapter - where TStageSystem : IStageSystem - where TStageOptions : IServerEntry +public interface IStageUser : ISocketUser + where TStageSystem : IStageSystem + where TStageUser : IStageUser { TStageSystem System { get; } - IStage? Stage { get; set; } } diff --git a/src/protocol/Edelstein.Protocol.Network/IAdapter.cs b/src/protocol/Edelstein.Protocol.Network/IAdapter.cs deleted file mode 100644 index a6d8e2207..000000000 --- a/src/protocol/Edelstein.Protocol.Network/IAdapter.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Threading.Tasks; -using Edelstein.Protocol.Utilities.Buffers; - -namespace Edelstein.Protocol.Network; - -public interface IAdapter -{ - ISocket Socket { get; } - - Task OnPacket(IPacket packet); - Task OnException(Exception exception); - Task OnDisconnect(); - - Task Dispatch(IPacket packet); - Task Disconnect(); -} diff --git a/src/protocol/Edelstein.Protocol.Network/IAdapterInitializer.cs b/src/protocol/Edelstein.Protocol.Network/IAdapterInitializer.cs deleted file mode 100644 index d865f5b42..000000000 --- a/src/protocol/Edelstein.Protocol.Network/IAdapterInitializer.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Edelstein.Protocol.Network; - -public interface IAdapterInitializer -{ - IAdapter Initialize(ISocket socket); -} diff --git a/src/protocol/Edelstein.Protocol.Network/ISocket.cs b/src/protocol/Edelstein.Protocol.Network/ISocket.cs index 37f0e8259..75a80abde 100644 --- a/src/protocol/Edelstein.Protocol.Network/ISocket.cs +++ b/src/protocol/Edelstein.Protocol.Network/ISocket.cs @@ -1,5 +1,4 @@ -using System; -using System.Net; +using System.Net; using System.Threading.Tasks; using Edelstein.Protocol.Utilities.Buffers; using Edelstein.Protocol.Utilities.Repositories; @@ -16,9 +15,6 @@ public interface ISocket : IRepositoryEntry bool IsDataEncrypted { get; } - DateTime LastAliveSent { get; set; } - DateTime LastAliveRecv { get; set; } - Task Dispatch(IPacket packet); Task Close(); } diff --git a/src/protocol/Edelstein.Protocol.Network/ISocketAdapter.cs b/src/protocol/Edelstein.Protocol.Network/ISocketAdapter.cs new file mode 100644 index 000000000..f9330d906 --- /dev/null +++ b/src/protocol/Edelstein.Protocol.Network/ISocketAdapter.cs @@ -0,0 +1,13 @@ +using System; +using System.Threading.Tasks; +using Edelstein.Protocol.Utilities.Buffers; + +namespace Edelstein.Protocol.Network; + +public interface ISocketAdapter + where TSocketUser : ISocketUser +{ + Task OnPacket(TSocketUser user, IPacket packet); + Task OnException(TSocketUser user, Exception exception); + Task OnDisconnect(TSocketUser user); +} diff --git a/src/protocol/Edelstein.Protocol.Network/ISocketUser.cs b/src/protocol/Edelstein.Protocol.Network/ISocketUser.cs new file mode 100644 index 000000000..a70ca6c87 --- /dev/null +++ b/src/protocol/Edelstein.Protocol.Network/ISocketUser.cs @@ -0,0 +1,12 @@ +using System.Threading.Tasks; +using Edelstein.Protocol.Utilities.Buffers; + +namespace Edelstein.Protocol.Network; + +public interface ISocketUser +{ + ISocket Socket { get; } + + Task Dispatch(IPacket packet) => Socket.Dispatch(packet); + Task Disconnect() => Socket.Close(); +} diff --git a/src/protocol/Edelstein.Protocol.Network/ISocketUserCreator.cs b/src/protocol/Edelstein.Protocol.Network/ISocketUserCreator.cs new file mode 100644 index 000000000..65546746e --- /dev/null +++ b/src/protocol/Edelstein.Protocol.Network/ISocketUserCreator.cs @@ -0,0 +1,7 @@ +namespace Edelstein.Protocol.Network; + +public interface ISocketUserCreator + where TSocketUser : ISocketUser +{ + TSocketUser CreateUser(ISocket socket); +} diff --git a/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplate.cs b/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplate.cs new file mode 100644 index 000000000..c2bda69a2 --- /dev/null +++ b/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplate.cs @@ -0,0 +1,5 @@ +using Edelstein.Protocol.Utilities.Repositories; + +namespace Edelstein.Protocol.Utilities.Templates; + +public interface ITemplate : IRepositoryEntry; diff --git a/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateCollection.cs b/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateCollection.cs new file mode 100644 index 000000000..df9674448 --- /dev/null +++ b/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateCollection.cs @@ -0,0 +1,11 @@ +using Edelstein.Protocol.Utilities.Repositories.Methods; + +namespace Edelstein.Protocol.Utilities.Templates; + +public interface ITemplateCollection : + IRepositoryMethodRetrieve, + IRepositoryMethodRetrieveAll + where TTemplate : ITemplate +{ + int Count { get; } +} diff --git a/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateCollectionProvider.cs b/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateCollectionProvider.cs new file mode 100644 index 000000000..32b094d41 --- /dev/null +++ b/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateCollectionProvider.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; +using Edelstein.Protocol.Utilities.Repositories; + +namespace Edelstein.Protocol.Utilities.Templates; + +public interface ITemplateCollectionProvider : + IRepositoryEntry + where TTemplate : ITemplate +{ + Task Provide(); +} diff --git a/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateManager.cs b/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateManager.cs new file mode 100644 index 000000000..37876e036 --- /dev/null +++ b/src/protocol/Edelstein.Protocol.Utilities/Templates/ITemplateManager.cs @@ -0,0 +1,8 @@ +using Edelstein.Protocol.Utilities.Repositories.Methods; + +namespace Edelstein.Protocol.Utilities.Templates; + +public interface ITemplateManager : + ITemplateCollection, + IRepositoryMethodInsert> + where TTemplate : ITemplate;