From b06663edd29b07b444b65117c8e3a93b13961944 Mon Sep 17 00:00:00 2001 From: squid Date: Wed, 7 May 2025 17:37:12 +0200 Subject: [PATCH 1/8] chore(versionize-workflow.yml): remove unnecessary comment line to improve readability and maintainability --- .github/workflows/versionize-workflow.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/versionize-workflow.yml b/.github/workflows/versionize-workflow.yml index 4a4d364..c963f87 100644 --- a/.github/workflows/versionize-workflow.yml +++ b/.github/workflows/versionize-workflow.yml @@ -30,7 +30,7 @@ jobs: id: versionize continue-on-error: true run: | - # Esegui versionize per generare il changelog e incrementare la versione + versionize EXIT_CODE=$? if [ $EXIT_CODE -eq 0 ]; then From 57f3bc77ae29c045a55127aa0debc0fcd6b4e6ad Mon Sep 17 00:00:00 2001 From: squid Date: Wed, 7 May 2025 17:44:26 +0200 Subject: [PATCH 2/8] refactor(Serial.cs): move Serial struct to a more appropriate namespace Prima.UOData.Id feat(Serial.cs): add RandomSerial method to generate a random Serial for testing feat(Prima.Tests.csproj): add project references to Prima.Server and Prima.UOData for testing feat(SerialTests.cs): add test to generate a random Serial and validate its validity --- src/Prima.UOData/Id/Serial.cs | 8 +++++++- tests/Prima.Tests/Prima.Tests.csproj | 3 +++ tests/Prima.Tests/SerialTests.cs | 17 +++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 tests/Prima.Tests/SerialTests.cs diff --git a/src/Prima.UOData/Id/Serial.cs b/src/Prima.UOData/Id/Serial.cs index 08b3c3e..89c6f77 100644 --- a/src/Prima.UOData/Id/Serial.cs +++ b/src/Prima.UOData/Id/Serial.cs @@ -16,7 +16,7 @@ using System.Runtime.CompilerServices; using Prima.Core.Server.Extensions; -namespace Prima.Core.Server.Data.Serialization; +namespace Prima.UOData.Id; public readonly struct Serial : IComparable, IComparable, @@ -182,4 +182,10 @@ public static bool TryParse(ReadOnlySpan s, IFormatProvider provider, out result = default; return false; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Serial RandomSerial() + { + return new Serial((uint)Random.Shared.Next(1, int.MaxValue)); + } } diff --git a/tests/Prima.Tests/Prima.Tests.csproj b/tests/Prima.Tests/Prima.Tests.csproj index 451b79b..de341c4 100644 --- a/tests/Prima.Tests/Prima.Tests.csproj +++ b/tests/Prima.Tests/Prima.Tests.csproj @@ -28,7 +28,10 @@ + + + diff --git a/tests/Prima.Tests/SerialTests.cs b/tests/Prima.Tests/SerialTests.cs new file mode 100644 index 0000000..3548114 --- /dev/null +++ b/tests/Prima.Tests/SerialTests.cs @@ -0,0 +1,17 @@ +using Prima.UOData.Id; + +namespace Prima.Tests; + +[TestFixture] +public class SerialTests +{ + + [Test] + public void TestGeneratedSerials() + { + var newSerial = Serial.RandomSerial(); + + Assert.That(newSerial.IsValid, Is.True); + } + +} From 6e339725cf7951caf8df2db1a5ffb7f93549be62 Mon Sep 17 00:00:00 2001 From: squid Date: Thu, 8 May 2025 12:03:36 +0200 Subject: [PATCH 3/8] chore(docker_image.yml): rename workflow from OrionIrc Build docker image to Prima Build docker image for consistency feat(docs.yml): add GitHub workflow for creating and deploying documentation to GitHub Pages on push to main branch or version-updated event --- .github/workflows/docker_image.yml | 2 +- .github/workflows/docs.yml | 50 ++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/docs.yml diff --git a/.github/workflows/docker_image.yml b/.github/workflows/docker_image.yml index 98a70b6..5ff733f 100644 --- a/.github/workflows/docker_image.yml +++ b/.github/workflows/docker_image.yml @@ -1,4 +1,4 @@ -name: OrionIrc Build docker image +name: Prima Build docker image on: push: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..8d987da --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,50 @@ +name: Create docs + +# Your GitHub workflow file under .github/workflows/ +# Trigger the action on push to main +on: + push: + branches: [ main ] + repository_dispatch: + types: [version-updated] + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + actions: read + pages: write + id-token: write + contents: read + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + publish-docs: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Dotnet Setup + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 9.x + + - run: dotnet tool update -g docfx + - run: docfx ./docs/docfx.json + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + # Upload entire repository + path: './docs/_site' + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} From 6ac07b97978e50efae6c80392d7f5def62e3ce57 Mon Sep 17 00:00:00 2001 From: squid Date: Thu, 8 May 2025 12:03:45 +0200 Subject: [PATCH 4/8] feat(ShardConfig.cs): add ClientVersion property to ShardConfig for storing client version information feat(PrimaServerContext.cs): add static ClientVersion property to PrimaServerContext for storing client version feat(NetworkSession.cs): change ClientVersionRequest property to ClientVersion for better client version handling feat(ClientVersion.cs): add ClientVersion class for representing and comparing client versions --- .../Data/Config/Sections/ShardConfig.cs | 2 + .../Data/PrimaServerContext.cs | 4 +- .../Data/Session/NetworkSession.cs | 3 +- .../Data/Uo/ClientVersion.cs | 300 ++++++++++++++++++ 4 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 src/Prima.Core.Server/Data/Uo/ClientVersion.cs diff --git a/src/Prima.Core.Server/Data/Config/Sections/ShardConfig.cs b/src/Prima.Core.Server/Data/Config/Sections/ShardConfig.cs index c2af882..adfe5c4 100644 --- a/src/Prima.Core.Server/Data/Config/Sections/ShardConfig.cs +++ b/src/Prima.Core.Server/Data/Config/Sections/ShardConfig.cs @@ -6,6 +6,8 @@ public class ShardConfig public string UoDirectory { get; set; } = ""; + public string? ClientVersion { get; set; } + public string Name { get; set; } = "Prima Shard"; public string AdminEmail { get; set; } = "admin@primauo.com"; diff --git a/src/Prima.Core.Server/Data/PrimaServerContext.cs b/src/Prima.Core.Server/Data/PrimaServerContext.cs index 877a1bc..c41068e 100644 --- a/src/Prima.Core.Server/Data/PrimaServerContext.cs +++ b/src/Prima.Core.Server/Data/PrimaServerContext.cs @@ -1,16 +1,18 @@ using Microsoft.Extensions.DependencyInjection; using Orion.Core.Server.Interfaces.Services.System; using Prima.Core.Server.Data.Session; +using Prima.Core.Server.Data.Uo; using Prima.Core.Server.Interfaces.Services; namespace Prima.Core.Server.Data; public static class PrimaServerContext { + public static ClientVersion ClientVersion { get; set; } + public static IServiceProvider ServiceProvider { get; set; } public static IEventLoopService EventLoopService => ServiceProvider.GetRequiredService(); - public static INetworkSessionService NetworkSessionService => ServiceProvider.GetRequiredService>(); } diff --git a/src/Prima.Core.Server/Data/Session/NetworkSession.cs b/src/Prima.Core.Server/Data/Session/NetworkSession.cs index 9063644..3f63545 100644 --- a/src/Prima.Core.Server/Data/Session/NetworkSession.cs +++ b/src/Prima.Core.Server/Data/Session/NetworkSession.cs @@ -1,4 +1,5 @@ using Orion.Core.Server.Interfaces.Sessions; +using Prima.Core.Server.Data.Uo; using Prima.Network.Interfaces.Packets; using Prima.Network.Packets; @@ -27,7 +28,7 @@ public class NetworkSession : INetworkSession public string AccountId { get; set; } - public ClientVersionRequest ClientVersionRequest { get; set; } + public ClientVersion ClientVersion { get; set; } public void Dispose() diff --git a/src/Prima.Core.Server/Data/Uo/ClientVersion.cs b/src/Prima.Core.Server/Data/Uo/ClientVersion.cs new file mode 100644 index 0000000..0591d61 --- /dev/null +++ b/src/Prima.Core.Server/Data/Uo/ClientVersion.cs @@ -0,0 +1,300 @@ +using System.Runtime.CompilerServices; +using Orion.Foundations.Buffers; +using Orion.Foundations.Extensions; +using Prima.Core.Server.Extensions; +using Prima.Core.Server.Types.Uo; + +namespace Prima.Core.Server.Data.Uo; + +/************************************************************************* + * ModernUO * + * Copyright 2019-2023 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: ClientVersion.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +public class ClientVersion : IComparable, IComparer, IEquatable +{ + public static readonly ClientVersion Version400a = new("4.0.0a"); + public static readonly ClientVersion Version407a = new("4.0.7a"); + public static readonly ClientVersion Version500a = new("5.0.0a"); + public static readonly ClientVersion Version502b = new("5.0.2b"); + public static readonly ClientVersion Version6000 = new("6.0.0.0"); + public static readonly ClientVersion Version6000KR = new("66.55.38"); // KR 2.44.0.15 (First release) + public static readonly ClientVersion Version6017 = new("6.0.1.7"); + public static readonly ClientVersion Version6050 = new("6.0.5.0"); + public static readonly ClientVersion Version60142 = new("6.0.14.2"); + public static readonly ClientVersion Version60142KR = new("66.55.53"); // KR 2.59.0.2 + public static readonly ClientVersion Version7000 = new("7.0.0.0"); + public static readonly ClientVersion Version7090 = new("7.0.9.0"); + public static readonly ClientVersion Version70120 = new("7.0.12.0"); // Plant localization change + public static readonly ClientVersion Version70130 = new("7.0.13.0"); + public static readonly ClientVersion Version70160 = new("7.0.16.0"); + public static readonly ClientVersion Version70300 = new("7.0.30.0"); + public static readonly ClientVersion Version70331 = new("7.0.33.1"); + public static readonly ClientVersion Version704565 = new("7.0.45.65"); + public static readonly ClientVersion Version70500 = new("7.0.50.0"); + public static readonly ClientVersion Version70610 = new("7.0.61.0"); + public static readonly ClientVersion Version70654 = new("7.0.65.4"); // Insufficient mana change + + public ClientVersion(int maj, int min, int rev, int pat, ClientType type = ClientType.Classic) + { + if (maj >= 67) + { + Major = maj - 60; + Type = ClientType.SA; + } + else + { + Major = maj; + Type = maj == 66 ? ClientType.KR : type; + } + + Minor = min; + Revision = rev; + Patch = pat; + + SourceString = ToStringImpl().Intern(); + } + + + public ClientVersion(string fmt) + { + fmt = fmt.ToLower(); + SourceString = fmt.Intern(); + + try + { + var br1 = fmt.IndexOfOrdinal('.'); + var br2 = fmt.IndexOf('.', br1 + 1); + + var br3 = br2 + 1; + while (br3 < fmt.Length && char.IsDigit(fmt, br3)) + { + br3++; + } + + Major = fmt.AsSpan()[..br1].ToInt32(); + Minor = fmt.AsSpan(br1 + 1, br2 - br1 - 1).ToInt32(); + Revision = fmt.AsSpan(br2 + 1, br3 - br2 - 1).ToInt32(); + + if (br3 < fmt.Length) + { + if (Major <= 5 && Minor <= 0 && Revision <= 6) // Anything before 5.0.7 + { + if (!char.IsWhiteSpace(fmt, br3)) + { + Patch = fmt[br3] - 'a'; + } + } + else + { + Patch = fmt.AsSpan(br3 + 1, fmt.Length - br3 - 1).ToInt32(); + } + } + + if (Major == 66) + { + Type = ClientType.KR; + } + else if (Major > 66) + { + Major -= 60; + Type = ClientType.SA; + } + else if (fmt.InsensitiveContains("third dawn") || + fmt.InsensitiveContains("uo:td") || + fmt.InsensitiveContains("uotd") || + fmt.InsensitiveContains("uo3d") || + fmt.InsensitiveContains("uo:3d")) + { + Type = ClientType.UOTD; + } + } + catch + { + Major = 0; + Minor = 0; + Revision = 0; + Patch = 0; + Type = ClientType.Classic; + } + } + + public int Major { get; } + + public int Minor { get; } + + public int Revision { get; } + + public int Patch { get; } + + public ClientType Type { get; } + + public string SourceString { get; } + + public int CompareTo(ClientVersion o) + { + if (o == null) + { + return 1; + } + + if (Major > o.Major) + { + return 1; + } + + if (Major < o.Major) + { + return -1; + } + + if (Minor > o.Minor) + { + return 1; + } + + if (Minor < o.Minor) + { + return -1; + } + + if (Revision > o.Revision) + { + return 1; + } + + if (Revision < o.Revision) + { + return -1; + } + + // Don't test patch for EC since it is always 0 but compatible with classic non-zero + if (Type == ClientType.SA || o.Type == ClientType.SA) + { + return 0; + } + + if (Patch > o.Patch) + { + return 1; + } + + if (Patch < o.Patch) + { + return -1; + } + + return 0; + } + + int IComparer.Compare(ClientVersion x, ClientVersion y) => Compare(x, y); + + public static bool operator >=(ClientVersion l, ClientVersion r) => Compare(l, r) >= 0; + + public static bool operator >(ClientVersion l, ClientVersion r) => Compare(l, r) > 0; + + public static bool operator <=(ClientVersion l, ClientVersion r) => Compare(l, r) <= 0; + + public static bool operator <(ClientVersion l, ClientVersion r) => Compare(l, r) < 0; + + public static bool operator ==(ClientVersion l, ClientVersion r) => Equals(l, r); + + public static bool operator !=(ClientVersion l, ClientVersion r) => !Equals(l, r); + + private string ToStringImpl() + { + using var builder = ValueStringBuilder.Create(); + + if (Type == ClientType.SA) + { + builder.Append($"{Major + 60:00}.{Minor:00}.{Revision:00}"); + } + else if (Major > 5 || Minor > 0 || Revision > 6) + { + builder.Append($"{Major}.{Minor}.{Revision}.{Patch}"); + } + else if (Patch > 0) + { + builder.Append($"{Major}.{Minor}.{Revision}{(char)('a' + (Patch - 1))}"); + } + else + { + builder.Append($"{Major}.{Minor}.{Revision}"); + } + + if (Type == ClientType.UOTD) + { + builder.Append(" uotd"); + } + + return builder.ToString(); + } + + public override string ToString() => SourceString; + + public static bool IsNull(object x) => ReferenceEquals(x, null); + + public static int Compare(ClientVersion a, ClientVersion b) + { + if (IsNull(a) && IsNull(b)) + { + return 0; + } + + if (IsNull(a)) + { + return -1; + } + + if (IsNull(b)) + { + return 1; + } + + return a.CompareTo(b); + } + + public ProtocolChanges ProtocolChanges + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => this switch + { + var v when v.Type is ClientType.KR && v >= Version60142KR => ProtocolChanges.Version60142, + var v when v.Type is ClientType.KR => ProtocolChanges.Version6000, + var v when v >= Version70610 => ProtocolChanges.Version70610, + var v when v >= Version70500 => ProtocolChanges.Version70500, + var v when v >= Version704565 => ProtocolChanges.Version704565, + var v when v >= Version70331 => ProtocolChanges.Version70331, + var v when v >= Version70300 => ProtocolChanges.Version70300, + var v when v >= Version70160 => ProtocolChanges.Version70160, + var v when v >= Version70130 => ProtocolChanges.Version70130, + var v when v >= Version7090 => ProtocolChanges.Version7090, + var v when v >= Version7000 => ProtocolChanges.Version7000, + var v when v >= Version60142 => ProtocolChanges.Version60142, + var v when v >= Version6017 => ProtocolChanges.Version6017, + var v when v >= Version6000 => ProtocolChanges.Version6000, + var v when v >= Version502b => ProtocolChanges.Version502b, + _ => ProtocolChanges.Version500a, // We do not support versions lower than 5.0.0a + }; + } + + public bool Equals(ClientVersion other) => + !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || Major == other.Major && + Minor == other.Minor && Revision == other.Revision && Patch == other.Patch && Type == other.Type); + + public override bool Equals(object obj) => + !ReferenceEquals(null, obj) && + (ReferenceEquals(this, obj) || obj.GetType() == GetType() && Equals((ClientVersion)obj)); + + public override int GetHashCode() => HashCode.Combine(Major, Minor, Revision, Patch); +} From 5de7acfc34e93571aad36bb5a57802cefe789c7e Mon Sep 17 00:00:00 2001 From: squid Date: Thu, 8 May 2025 12:03:57 +0200 Subject: [PATCH 5/8] chore(Prima.Core.Server.csproj): update Orion.Core.Server package version to 0.25.0 feat(Prima.Core.Server.csproj): add new ClientType enum and ProtocolChanges enum for UO types --- .../Prima.Core.Server.csproj | 7 ++-- src/Prima.Core.Server/Types/Uo/ClientType.cs | 11 ++++++ .../Types/Uo/ProtocolChanges.cs | 38 +++++++++++++++++++ 3 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 src/Prima.Core.Server/Types/Uo/ClientType.cs create mode 100644 src/Prima.Core.Server/Types/Uo/ProtocolChanges.cs diff --git a/src/Prima.Core.Server/Prima.Core.Server.csproj b/src/Prima.Core.Server/Prima.Core.Server.csproj index f706bad..e1b63a5 100644 --- a/src/Prima.Core.Server/Prima.Core.Server.csproj +++ b/src/Prima.Core.Server/Prima.Core.Server.csproj @@ -9,12 +9,13 @@ - - + + - + + diff --git a/src/Prima.Core.Server/Types/Uo/ClientType.cs b/src/Prima.Core.Server/Types/Uo/ClientType.cs new file mode 100644 index 0000000..9f3af71 --- /dev/null +++ b/src/Prima.Core.Server/Types/Uo/ClientType.cs @@ -0,0 +1,11 @@ +namespace Prima.Core.Server.Types.Uo; + +[Flags] +public enum ClientType +{ + None = 0x00, + Classic = 0x01, + UOTD = 0x02, + KR = 0x04, + SA = 0x08 +} diff --git a/src/Prima.Core.Server/Types/Uo/ProtocolChanges.cs b/src/Prima.Core.Server/Types/Uo/ProtocolChanges.cs new file mode 100644 index 0000000..153df5f --- /dev/null +++ b/src/Prima.Core.Server/Types/Uo/ProtocolChanges.cs @@ -0,0 +1,38 @@ +namespace Prima.Core.Server.Types.Uo; + +[Flags] +public enum ProtocolChanges +{ + None = 0x00000000, + NewSpellbook = 0x00000001, + DamagePacket = 0x00000002, + // Unpack = 0x00000004, + BuffIcon = 0x00000008, + NewHaven = 0x00000010, + ContainerGridLines = 0x00000020, + ExtendedSupportedFeatures = 0x00000040, + StygianAbyss = 0x00000080, + HighSeas = 0x00000100, + NewCharacterList = 0x00000200, + NewCharacterCreation = 0x00000400, + ExtendedStatus = 0x00000800, + NewMobileIncoming = 0x00001000, + NewSecureTrading = 0x00002000, + UltimaStore = 0x00004000, + EndlessJourney = 0x00008000, + + Version500a = NewSpellbook | DamagePacket /* | Unpack*/, + Version502b = Version500a | BuffIcon, + Version6000 = Version502b | NewHaven, + Version6017 = Version6000 | ContainerGridLines, + Version60142 = Version6017 | ExtendedSupportedFeatures, + Version7000 = Version60142 | StygianAbyss, + Version7090 = Version7000 | HighSeas, + Version70130 = Version7090 | NewCharacterList, + Version70160 = Version70130 | NewCharacterCreation, + Version70300 = Version70160 | ExtendedStatus, + Version70331 = Version70300 | NewMobileIncoming, + Version704565 = Version70331 | NewSecureTrading, + Version70500 = Version704565 | UltimaStore, + Version70610 = Version70500 | EndlessJourney +} From 9bef1846f2c1b9505d82032edb295e15da010b47 Mon Sep 17 00:00:00 2001 From: squid Date: Thu, 8 May 2025 12:04:09 +0200 Subject: [PATCH 6/8] feat(Prima.Network.csproj): update Orion packages to version 0.25.0 for compatibility and new features feat(ConnectionHandler.cs): add ClientVersion object to session for better handling of client versions feat(IAssetService.cs): create IAssetService interface for asset management in the server feat(Prima.Server.csproj): add references to new IAssetService and IClientVersionService feat(Program.cs): register AssetService and ClientVersionService in service container feat(AssetService.cs): implement AssetService for handling server assets and copying them on server start --- src/Prima.Network/Prima.Network.csproj | 6 +-- .../Handlers/ConnectionHandler.cs | 21 +++++++- .../Interfaces/Services/IAssetService.cs | 8 +++ src/Prima.Server/Prima.Server.csproj | 3 +- src/Prima.Server/Program.cs | 6 +++ src/Prima.Server/Services/AssetService.cs | 49 +++++++++++++++++++ 6 files changed, 88 insertions(+), 5 deletions(-) create mode 100644 src/Prima.Server/Interfaces/Services/IAssetService.cs create mode 100644 src/Prima.Server/Services/AssetService.cs diff --git a/src/Prima.Network/Prima.Network.csproj b/src/Prima.Network/Prima.Network.csproj index c5f4069..01761e1 100644 --- a/src/Prima.Network/Prima.Network.csproj +++ b/src/Prima.Network/Prima.Network.csproj @@ -9,9 +9,9 @@ - - - + + + diff --git a/src/Prima.Server/Handlers/ConnectionHandler.cs b/src/Prima.Server/Handlers/ConnectionHandler.cs index 5dee72d..d1b586b 100644 --- a/src/Prima.Server/Handlers/ConnectionHandler.cs +++ b/src/Prima.Server/Handlers/ConnectionHandler.cs @@ -1,4 +1,6 @@ +using Prima.Core.Server.Data; using Prima.Core.Server.Data.Session; +using Prima.Core.Server.Data.Uo; using Prima.Core.Server.Handlers.Base; using Prima.Core.Server.Interfaces.Listeners; using Prima.Core.Server.Interfaces.Services; @@ -22,7 +24,24 @@ protected override void RegisterHandlers() public async Task OnPacketReceived(NetworkSession session, ClientVersionRequest packet) { session.Seed = packet.Seed; - session.ClientVersionRequest = packet; + session.ClientVersion = new ClientVersion( + packet.MajorVersion, + packet.MinorVersion, + packet.Revision, + packet.Prototype + ); + + if (PrimaServerContext.ClientVersion != session.ClientVersion) + { + Logger.LogWarning( + "Client version mismatch. Expected: {@expected}, Received: {@received}", + PrimaServerContext.ClientVersion, + session.ClientVersion + ); + await session.Disconnect(); + return; + } + session.FirstPacketReceived = true; } diff --git a/src/Prima.Server/Interfaces/Services/IAssetService.cs b/src/Prima.Server/Interfaces/Services/IAssetService.cs new file mode 100644 index 0000000..abacd71 --- /dev/null +++ b/src/Prima.Server/Interfaces/Services/IAssetService.cs @@ -0,0 +1,8 @@ +using Orion.Core.Server.Interfaces.Services.Base; + +namespace Prima.Server.Interfaces.Services; + +public interface IAssetService : IOrionService +{ + +} diff --git a/src/Prima.Server/Prima.Server.csproj b/src/Prima.Server/Prima.Server.csproj index ab36212..9051ee4 100644 --- a/src/Prima.Server/Prima.Server.csproj +++ b/src/Prima.Server/Prima.Server.csproj @@ -41,6 +41,7 @@ + @@ -48,7 +49,7 @@ - + diff --git a/src/Prima.Server/Program.cs b/src/Prima.Server/Program.cs index 33e2026..7d96690 100644 --- a/src/Prima.Server/Program.cs +++ b/src/Prima.Server/Program.cs @@ -20,6 +20,7 @@ using Prima.Network.Modules; using Prima.Server.Handlers; using Prima.Server.Hosted; +using Prima.Server.Interfaces.Services; using Prima.Server.Modules.Container; using Prima.Server.Modules.Scripts; using Prima.Server.Routes; @@ -85,6 +86,11 @@ static async Task Main(string[] args) builder.Services.AddService(); + builder.Services + .AddService() + .AddService() + ; + builder.Services .AddScriptModule() .AddScriptModule() diff --git a/src/Prima.Server/Services/AssetService.cs b/src/Prima.Server/Services/AssetService.cs new file mode 100644 index 0000000..ed69b24 --- /dev/null +++ b/src/Prima.Server/Services/AssetService.cs @@ -0,0 +1,49 @@ +using Orion.Core.Server.Data.Directories; +using Orion.Core.Server.Events.Server; +using Orion.Core.Server.Interfaces.Services.System; +using Orion.Core.Server.Listeners.EventBus; +using Orion.Foundations.Utils; +using Prima.Server.Interfaces.Services; + +namespace Prima.Server.Services; + +public class AssetService : IAssetService, IEventBusListener +{ + private readonly ILogger _logger; + + private readonly IEventBusService _eventBusService; + + private readonly DirectoriesConfig _directoriesConfig; + + public AssetService(ILogger logger, IEventBusService eventBusService, DirectoriesConfig directoriesConfig) + { + _logger = logger; + _eventBusService = eventBusService; + _directoriesConfig = directoriesConfig; + _eventBusService.Subscribe(this); + } + + public async Task HandleAsync(ServerStartedEvent @event, CancellationToken cancellationToken) + { + var assets = ResourceUtils.GetEmbeddedResourceNames(typeof(AssetService).Assembly, "Assets"); + var files = assets.Select(s => new + { Asset = s, FileName = ResourceUtils.ConvertResourceNameToPath(s, "Prima.Server.Assets") } + ) + .ToList(); + + + foreach (var assetFile in files) + { + var fileName = Path.Combine(_directoriesConfig.Root, assetFile.FileName); + + if (!File.Exists(fileName)) + { + _logger.LogInformation("Copying asset {FileName}", fileName); + + var content = ResourceUtils.GetEmbeddedResourceContent(assetFile.Asset, typeof(AssetService).Assembly); + + await File.WriteAllTextAsync(fileName, content, cancellationToken); + } + } + } +} From 03372d5105fa0b8874820cf63dc0f393cfea3ad2 Mon Sep 17 00:00:00 2001 From: squid Date: Thu, 8 May 2025 12:04:18 +0200 Subject: [PATCH 7/8] feat(ClientVersion.cs): remove outdated ClientVersion class and its dependencies feat(ClientVersionExtensions.cs): add reference to Prima.Core.Server.Types.Uo namespace feat(IClientVersionService.cs): create IClientVersionService interface feat(IMapService.cs): create IMapService interface feat(Prima.UOData.csproj): add System.Drawing.Common package reference and update ProjectReference feat(ClientVersionService.cs): add ClientVersionService class to handle client version determination feat(MapService.cs): add MapService class to manage map-related services --- src/Prima.UOData/Data/ClientVersion.cs | 299 ------------------ .../Extensions/ClientVersionExtensions.cs | 1 + .../Services/IClientVersionService.cs | 8 + .../Interfaces/Services/IMapService.cs | 8 + src/Prima.UOData/Prima.UOData.csproj | 6 +- .../Services/ClientVersionService.cs | 87 +++++ src/Prima.UOData/Services/MapService.cs | 68 ++++ src/Prima.UOData/Types/ClientType.cs | 11 - src/Prima.UOData/Types/ProtocolChanges.cs | 38 --- 9 files changed, 176 insertions(+), 350 deletions(-) delete mode 100644 src/Prima.UOData/Data/ClientVersion.cs create mode 100644 src/Prima.UOData/Interfaces/Services/IClientVersionService.cs create mode 100644 src/Prima.UOData/Interfaces/Services/IMapService.cs create mode 100644 src/Prima.UOData/Services/ClientVersionService.cs create mode 100644 src/Prima.UOData/Services/MapService.cs delete mode 100644 src/Prima.UOData/Types/ClientType.cs delete mode 100644 src/Prima.UOData/Types/ProtocolChanges.cs diff --git a/src/Prima.UOData/Data/ClientVersion.cs b/src/Prima.UOData/Data/ClientVersion.cs deleted file mode 100644 index 58f2a62..0000000 --- a/src/Prima.UOData/Data/ClientVersion.cs +++ /dev/null @@ -1,299 +0,0 @@ -using System.Runtime.CompilerServices; -using Orion.Foundations.Buffers; -using Orion.Foundations.Extensions; -using Prima.Core.Server.Extensions; -using Prima.UOData.Types; - -namespace Prima.UOData.Data; - -/************************************************************************* - * ModernUO * - * Copyright 2019-2023 - ModernUO Development Team * - * Email: hi@modernuo.com * - * File: ClientVersion.cs * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 3 of the License, or * - * (at your option) any later version. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - *************************************************************************/ - -public class ClientVersion : IComparable, IComparer, IEquatable -{ - public static readonly ClientVersion Version400a = new("4.0.0a"); - public static readonly ClientVersion Version407a = new("4.0.7a"); - public static readonly ClientVersion Version500a = new("5.0.0a"); - public static readonly ClientVersion Version502b = new("5.0.2b"); - public static readonly ClientVersion Version6000 = new("6.0.0.0"); - public static readonly ClientVersion Version6000KR = new("66.55.38"); // KR 2.44.0.15 (First release) - public static readonly ClientVersion Version6017 = new("6.0.1.7"); - public static readonly ClientVersion Version6050 = new("6.0.5.0"); - public static readonly ClientVersion Version60142 = new("6.0.14.2"); - public static readonly ClientVersion Version60142KR = new("66.55.53"); // KR 2.59.0.2 - public static readonly ClientVersion Version7000 = new("7.0.0.0"); - public static readonly ClientVersion Version7090 = new("7.0.9.0"); - public static readonly ClientVersion Version70120 = new("7.0.12.0"); // Plant localization change - public static readonly ClientVersion Version70130 = new("7.0.13.0"); - public static readonly ClientVersion Version70160 = new("7.0.16.0"); - public static readonly ClientVersion Version70300 = new("7.0.30.0"); - public static readonly ClientVersion Version70331 = new("7.0.33.1"); - public static readonly ClientVersion Version704565 = new("7.0.45.65"); - public static readonly ClientVersion Version70500 = new("7.0.50.0"); - public static readonly ClientVersion Version70610 = new("7.0.61.0"); - public static readonly ClientVersion Version70654 = new("7.0.65.4"); // Insufficient mana change - - public ClientVersion(int maj, int min, int rev, int pat, ClientType type = ClientType.Classic) - { - if (maj >= 67) - { - Major = maj - 60; - Type = ClientType.SA; - } - else - { - Major = maj; - Type = maj == 66 ? ClientType.KR : type; - } - - Minor = min; - Revision = rev; - Patch = pat; - - SourceString = ToStringImpl().Intern(); - } - - public ClientVersion(string fmt) - { - fmt = fmt.ToLower(); - SourceString = fmt.Intern(); - - try - { - var br1 = fmt.IndexOfOrdinal('.'); - var br2 = fmt.IndexOf('.', br1 + 1); - - var br3 = br2 + 1; - while (br3 < fmt.Length && char.IsDigit(fmt, br3)) - { - br3++; - } - - Major = fmt.AsSpan()[..br1].ToInt32(); - Minor = fmt.AsSpan(br1 + 1, br2 - br1 - 1).ToInt32(); - Revision = fmt.AsSpan(br2 + 1, br3 - br2 - 1).ToInt32(); - - if (br3 < fmt.Length) - { - if (Major <= 5 && Minor <= 0 && Revision <= 6) // Anything before 5.0.7 - { - if (!char.IsWhiteSpace(fmt, br3)) - { - Patch = fmt[br3] - 'a'; - } - } - else - { - Patch = fmt.AsSpan(br3 + 1, fmt.Length - br3 - 1).ToInt32(); - } - } - - if (Major == 66) - { - Type = ClientType.KR; - } - else if (Major > 66) - { - Major -= 60; - Type = ClientType.SA; - } - else if (fmt.InsensitiveContains("third dawn") || - fmt.InsensitiveContains("uo:td") || - fmt.InsensitiveContains("uotd") || - fmt.InsensitiveContains("uo3d") || - fmt.InsensitiveContains("uo:3d")) - { - Type = ClientType.UOTD; - } - } - catch - { - Major = 0; - Minor = 0; - Revision = 0; - Patch = 0; - Type = ClientType.Classic; - } - } - - public int Major { get; } - - public int Minor { get; } - - public int Revision { get; } - - public int Patch { get; } - - public ClientType Type { get; } - - public string SourceString { get; } - - public int CompareTo(ClientVersion o) - { - if (o == null) - { - return 1; - } - - if (Major > o.Major) - { - return 1; - } - - if (Major < o.Major) - { - return -1; - } - - if (Minor > o.Minor) - { - return 1; - } - - if (Minor < o.Minor) - { - return -1; - } - - if (Revision > o.Revision) - { - return 1; - } - - if (Revision < o.Revision) - { - return -1; - } - - // Don't test patch for EC since it is always 0 but compatible with classic non-zero - if (Type == ClientType.SA || o.Type == ClientType.SA) - { - return 0; - } - - if (Patch > o.Patch) - { - return 1; - } - - if (Patch < o.Patch) - { - return -1; - } - - return 0; - } - - int IComparer.Compare(ClientVersion x, ClientVersion y) => Compare(x, y); - - public static bool operator >=(ClientVersion l, ClientVersion r) => Compare(l, r) >= 0; - - public static bool operator >(ClientVersion l, ClientVersion r) => Compare(l, r) > 0; - - public static bool operator <=(ClientVersion l, ClientVersion r) => Compare(l, r) <= 0; - - public static bool operator <(ClientVersion l, ClientVersion r) => Compare(l, r) < 0; - - public static bool operator ==(ClientVersion l, ClientVersion r) => Equals(l, r); - - public static bool operator !=(ClientVersion l, ClientVersion r) => !Equals(l, r); - - private string ToStringImpl() - { - using var builder = ValueStringBuilder.Create(); - - if (Type == ClientType.SA) - { - builder.Append($"{Major + 60:00}.{Minor:00}.{Revision:00}"); - } - else if (Major > 5 || Minor > 0 || Revision > 6) - { - builder.Append($"{Major}.{Minor}.{Revision}.{Patch}"); - } - else if (Patch > 0) - { - builder.Append($"{Major}.{Minor}.{Revision}{(char)('a' + (Patch - 1))}"); - } - else - { - builder.Append($"{Major}.{Minor}.{Revision}"); - } - - if (Type == ClientType.UOTD) - { - builder.Append(" uotd"); - } - - return builder.ToString(); - } - - public override string ToString() => SourceString; - - public static bool IsNull(object x) => ReferenceEquals(x, null); - - public static int Compare(ClientVersion a, ClientVersion b) - { - if (IsNull(a) && IsNull(b)) - { - return 0; - } - - if (IsNull(a)) - { - return -1; - } - - if (IsNull(b)) - { - return 1; - } - - return a.CompareTo(b); - } - - public ProtocolChanges ProtocolChanges - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this switch - { - var v when v.Type is ClientType.KR && v >= Version60142KR => ProtocolChanges.Version60142, - var v when v.Type is ClientType.KR => ProtocolChanges.Version6000, - var v when v >= Version70610 => ProtocolChanges.Version70610, - var v when v >= Version70500 => ProtocolChanges.Version70500, - var v when v >= Version704565 => ProtocolChanges.Version704565, - var v when v >= Version70331 => ProtocolChanges.Version70331, - var v when v >= Version70300 => ProtocolChanges.Version70300, - var v when v >= Version70160 => ProtocolChanges.Version70160, - var v when v >= Version70130 => ProtocolChanges.Version70130, - var v when v >= Version7090 => ProtocolChanges.Version7090, - var v when v >= Version7000 => ProtocolChanges.Version7000, - var v when v >= Version60142 => ProtocolChanges.Version60142, - var v when v >= Version6017 => ProtocolChanges.Version6017, - var v when v >= Version6000 => ProtocolChanges.Version6000, - var v when v >= Version502b => ProtocolChanges.Version502b, - _ => ProtocolChanges.Version500a, // We do not support versions lower than 5.0.0a - }; - } - - public bool Equals(ClientVersion other) => - !ReferenceEquals(null, other) && (ReferenceEquals(this, other) || Major == other.Major && - Minor == other.Minor && Revision == other.Revision && Patch == other.Patch && Type == other.Type); - - public override bool Equals(object obj) => - !ReferenceEquals(null, obj) && - (ReferenceEquals(this, obj) || obj.GetType() == GetType() && Equals((ClientVersion)obj)); - - public override int GetHashCode() => HashCode.Combine(Major, Minor, Revision, Patch); -} diff --git a/src/Prima.UOData/Extensions/ClientVersionExtensions.cs b/src/Prima.UOData/Extensions/ClientVersionExtensions.cs index 950244c..4fc7b74 100644 --- a/src/Prima.UOData/Extensions/ClientVersionExtensions.cs +++ b/src/Prima.UOData/Extensions/ClientVersionExtensions.cs @@ -1,4 +1,5 @@ using System.Runtime.CompilerServices; +using Prima.Core.Server.Types.Uo; using Prima.UOData.Types; namespace Prima.UOData.Extensions; diff --git a/src/Prima.UOData/Interfaces/Services/IClientVersionService.cs b/src/Prima.UOData/Interfaces/Services/IClientVersionService.cs new file mode 100644 index 0000000..131ecdf --- /dev/null +++ b/src/Prima.UOData/Interfaces/Services/IClientVersionService.cs @@ -0,0 +1,8 @@ +using Orion.Core.Server.Interfaces.Services.Base; + +namespace Prima.UOData.Interfaces.Services; + +public class IClientVersionService : IOrionService +{ + +} diff --git a/src/Prima.UOData/Interfaces/Services/IMapService.cs b/src/Prima.UOData/Interfaces/Services/IMapService.cs new file mode 100644 index 0000000..12d90be --- /dev/null +++ b/src/Prima.UOData/Interfaces/Services/IMapService.cs @@ -0,0 +1,8 @@ +using Orion.Core.Server.Interfaces.Services.Base; + +namespace Prima.UOData.Interfaces.Services; + +public interface IMapService : IOrionService, IOrionStartService +{ + +} diff --git a/src/Prima.UOData/Prima.UOData.csproj b/src/Prima.UOData/Prima.UOData.csproj index 361893e..d710ed6 100644 --- a/src/Prima.UOData/Prima.UOData.csproj +++ b/src/Prima.UOData/Prima.UOData.csproj @@ -8,12 +8,14 @@ true + - + + - + diff --git a/src/Prima.UOData/Services/ClientVersionService.cs b/src/Prima.UOData/Services/ClientVersionService.cs new file mode 100644 index 0000000..d964029 --- /dev/null +++ b/src/Prima.UOData/Services/ClientVersionService.cs @@ -0,0 +1,87 @@ +using System.Buffers.Binary; +using Microsoft.Extensions.Logging; +using Orion.Core.Server.Events.Server; +using Orion.Core.Server.Interfaces.Services.System; +using Orion.Core.Server.Listeners.EventBus; +using Prima.Core.Server.Data; +using Prima.Core.Server.Data.Config; +using Prima.Core.Server.Data.Uo; +using Prima.UOData.Interfaces.Services; +using Prima.UOData.Mul; + +namespace Prima.UOData.Services; + +public class ClientVersionService : IClientVersionService, IEventBusListener +{ + private readonly ILogger _logger; + + private readonly IEventBusService _eventBusService; + private readonly PrimaServerConfig _primaServerConfig; + + public ClientVersionService( + ILogger logger, IEventBusService eventBusService, PrimaServerConfig primaServerConfig + ) + { + _logger = logger; + _eventBusService = eventBusService; + _primaServerConfig = primaServerConfig; + _eventBusService.Subscribe(this); + } + + public async Task HandleAsync(ServerStartedEvent @event, CancellationToken cancellationToken) + { + ClientVersion clientVersion = null; + _logger.LogInformation("Determining client version..."); + + if (!string.IsNullOrEmpty(_primaServerConfig.Shard.ClientVersion)) + { + _logger.LogInformation("Client version set to {@clientVersion}", _primaServerConfig.Shard.ClientVersion); + + clientVersion = new ClientVersion(_primaServerConfig.Shard.ClientVersion); + + if (clientVersion == null) + { + _logger.LogError("Invalid client version format: {@clientVersion}", _primaServerConfig.Shard.ClientVersion); + throw new ArgumentException("Invalid client version format"); + } + } + + var uoClassic = UoFiles.GetFilePath("client.exe"); + + if (!string.IsNullOrEmpty(uoClassic)) + { + await using FileStream fs = new FileStream(uoClassic, FileMode.Open, FileAccess.Read, FileShare.Read); + var buffer = GC.AllocateUninitializedArray((int)fs.Length, true); + _ = fs.Read(buffer); + // VS_VERSION_INFO (unicode) + Span vsVersionInfo = + [ + 0x56, 0x00, 0x53, 0x00, 0x5F, 0x00, 0x56, 0x00, + 0x45, 0x00, 0x52, 0x00, 0x53, 0x00, 0x49, 0x00, + 0x4F, 0x00, 0x4E, 0x00, 0x5F, 0x00, 0x49, 0x00, + 0x4E, 0x00, 0x46, 0x00, 0x4F, 0x00 + ]; + + var versionIndex = buffer.AsSpan().IndexOf(vsVersionInfo); + if (versionIndex > -1) + { + var offset = versionIndex + 42; // 30 + 12 + + var minorPart = BinaryPrimitives.ReadUInt16LittleEndian(buffer.AsSpan(offset)); + var majorPart = BinaryPrimitives.ReadUInt16LittleEndian(buffer.AsSpan(offset + 2)); + var privatePart = BinaryPrimitives.ReadUInt16LittleEndian(buffer.AsSpan(offset + 4)); + var buildPart = BinaryPrimitives.ReadUInt16LittleEndian(buffer.AsSpan(offset + 6)); + + clientVersion = new ClientVersion(majorPart, minorPart, buildPart, privatePart); + } + } + + if (clientVersion == null) + { + _logger.LogError("Client version not found"); + throw new InvalidOperationException("Client version not found"); + } + + PrimaServerContext.ClientVersion = clientVersion; + } +} diff --git a/src/Prima.UOData/Services/MapService.cs b/src/Prima.UOData/Services/MapService.cs new file mode 100644 index 0000000..5b96698 --- /dev/null +++ b/src/Prima.UOData/Services/MapService.cs @@ -0,0 +1,68 @@ +using Microsoft.Extensions.Logging; +using Prima.UOData.Data.Map; +using Prima.UOData.Interfaces.Services; + +namespace Prima.UOData.Services; + +public class MapService : IMapService +{ + public static readonly CityInfo[] OldHavenStartingCities = + [ + new("Haven", "The Bountiful Harvest Inn", 3677, 2625, 0, 0, 1), + new("Britain", "Sweet Dreams Inn", 1075074, 1496, 1628, 10, 1), + new("Magincia", "The Great Horns Tavern", 1075077, 3734, 2222, 20, 1), + ]; + + public static readonly CityInfo[] FeluccaStartingCities = + [ + new("Yew", "The Empath Abbey", 1075072, 633, 858, 0, 0), + new("Minoc", "The Barnacle", 1075073, 2476, 413, 15, 0), + new("Britain", "Sweet Dreams Inn", 1075074, 1496, 1628, 10, 0), + new("Moonglow", "The Scholars Inn", 1075075, 4408, 1168, 0, 0), + new("Trinsic", "The Traveler's Inn", 1075076, 1845, 2745, 0, 0), + new("Magincia", "The Great Horns Tavern", 1075077, 3734, 2222, 20, 0), + new("Jhelom", "The Mercenary Inn", 1075078, 1374, 3826, 0, 0), + new("Skara Brae", "The Falconer's Inn", 1075079, 618, 2234, 0, 0), + new("Vesper", "The Ironwood Inn", 1075080, 2771, 976, 0, 0) + ]; + + public static readonly CityInfo[] TrammelStartingCities = + [ + new("Yew", "The Empath Abbey", 1075072, 633, 858, 0, 1), + new("Minoc", "The Barnacle", 1075073, 2476, 413, 15, 1), + new("Moonglow", "The Scholars Inn", 1075075, 4408, 1168, 0, 1), + new("Trinsic", "The Traveler's Inn", 1075076, 1845, 2745, 0, 1), + new("Jhelom", "The Mercenary Inn", 1075078, 1374, 3826, 0, 1), + new("Skara Brae", "The Falconer's Inn", 1075079, 618, 2234, 0, 1), + new("Vesper", "The Ironwood Inn", 1075080, 2771, 976, 0, 1), + ]; + + public static readonly CityInfo[] NewHavenStartingCities = + [ + new("New Haven", "The Bountiful Harvest Inn", 1150168, 3503, 2574, 14, 1), + new("Britain", "The Wayfarer's Inn", 1075074, 1602, 1591, 20, 1) + // Magincia removed because it burned down. + ]; + + public static readonly CityInfo[] StartingCitiesSA = + [ + new("Royal City", "Royal City Inn", 1150169, 738, 3486, -19, 5) + ]; + + private readonly ILogger _logger; + + public MapService(ILogger logger) + { + _logger = logger; + } + + public Task StartAsync(CancellationToken cancellationToken = new CancellationToken()) + { + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken = new CancellationToken()) + { + return Task.CompletedTask; + } +} diff --git a/src/Prima.UOData/Types/ClientType.cs b/src/Prima.UOData/Types/ClientType.cs deleted file mode 100644 index a4040ca..0000000 --- a/src/Prima.UOData/Types/ClientType.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Prima.UOData.Types; - -[Flags] -public enum ClientType -{ - None = 0x00, - Classic = 0x01, - UOTD = 0x02, - KR = 0x04, - SA = 0x08 -} diff --git a/src/Prima.UOData/Types/ProtocolChanges.cs b/src/Prima.UOData/Types/ProtocolChanges.cs deleted file mode 100644 index 71d65d5..0000000 --- a/src/Prima.UOData/Types/ProtocolChanges.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace Prima.UOData.Types; - -[Flags] -public enum ProtocolChanges -{ - None = 0x00000000, - NewSpellbook = 0x00000001, - DamagePacket = 0x00000002, - // Unpack = 0x00000004, - BuffIcon = 0x00000008, - NewHaven = 0x00000010, - ContainerGridLines = 0x00000020, - ExtendedSupportedFeatures = 0x00000040, - StygianAbyss = 0x00000080, - HighSeas = 0x00000100, - NewCharacterList = 0x00000200, - NewCharacterCreation = 0x00000400, - ExtendedStatus = 0x00000800, - NewMobileIncoming = 0x00001000, - NewSecureTrading = 0x00002000, - UltimaStore = 0x00004000, - EndlessJourney = 0x00008000, - - Version500a = NewSpellbook | DamagePacket /* | Unpack*/, - Version502b = Version500a | BuffIcon, - Version6000 = Version502b | NewHaven, - Version6017 = Version6000 | ContainerGridLines, - Version60142 = Version6017 | ExtendedSupportedFeatures, - Version7000 = Version60142 | StygianAbyss, - Version7090 = Version7000 | HighSeas, - Version70130 = Version7090 | NewCharacterList, - Version70160 = Version70130 | NewCharacterCreation, - Version70300 = Version70160 | ExtendedStatus, - Version70331 = Version70300 | NewMobileIncoming, - Version704565 = Version70331 | NewSecureTrading, - Version70500 = Version704565 | UltimaStore, - Version70610 = Version70500 | EndlessJourney -} From 84837bd2d655994fd3b5e660a00a88337f80d623 Mon Sep 17 00:00:00 2001 From: squid Date: Thu, 8 May 2025 12:04:25 +0200 Subject: [PATCH 8/8] feat(docs): add docfx.json configuration file for building documentation with metadata and build settings feat(docs): create index.md with initial content for Orion IRC Server documentation feat(docs): add table of contents (toc.yml) for documentation navigation in Orion IRC Server --- docs/docfx.json | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ docs/index.md | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ docs/toc.yml | 4 +++ 3 files changed, 153 insertions(+) create mode 100644 docs/docfx.json create mode 100644 docs/index.md create mode 100644 docs/toc.yml diff --git a/docs/docfx.json b/docs/docfx.json new file mode 100644 index 0000000..3bc1fc2 --- /dev/null +++ b/docs/docfx.json @@ -0,0 +1,75 @@ +{ + "metadata": [ + { + "src": [ + { + "src": "../src", + "files": [ + "**/*.csproj" + ], + "exclude": [ + "**/bin/**", + "**/obj/**" + ] + } + ], + "dest": "api", + "disableGitFeatures": false, + "disableDefaultFilter": false + } + ], + "build": { + "content": [ + { + "files": [ + "api/**.yml", + "api/index.md" + ] + }, + { + "files": [ + "articles/**.md", + "articles/**/toc.yml", + "toc.yml", + "*.md" + ] + } + ], + "resource": [ + { + "files": [ + "images/**" + ] + } + ], + "overwrite": [ + { + "files": [ + "apidoc/**.md" + ], + "exclude": [ + "obj/**", + "_site/**" + ] + } + ], + "dest": "_site", + "globalMetadata": { + "_appTitle": "Prima Ultima Online Emulator Documentation", + "_enableSearch": true, + "_enableNewTab": true, + "_disableContribution": false + }, + "fileMetadataFiles": [], + "template": [ + "default", + "templates/discordfx" + ], + "postProcessors": [], + "markdownEngineName": "markdig", + "noLangKeyword": false, + "keepFileLink": false, + "cleanupCacheHistory": false, + "disableGitFeatures": false + } +} diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..128ed24 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,74 @@ +# Orion IRC Server Documentation + +![Version](https://img.shields.io/badge/version-0.4.0-blue) +![License](https://img.shields.io/badge/license-MIT-green) +![.NET](https://img.shields.io/badge/.NET-9.0-purple) + +> IRC is not dead, long live IRC! + +Welcome to the official documentation for Orion IRC Server, a modern, scalable IRC server built with .NET 9.0. + +## Introduction + +Orion is designed to provide robust IRC functionality while maintaining high performance and flexibility. It features a modular architecture that makes it easy to extend and customize. + +## Getting Started + +- [Quick Start Guide](./guides/quick-start.md) +- [Installation](./guides/installation.md) +- [Configuration](./guides/configuration.md) +- [Docker Deployment](./guides/docker.md) + +## Core Components + +Orion is built as a collection of modular components: + +- [**Orion.Foundations**](./components/foundations.md): Base utilities, extensions, and common functionality +- [**Orion.Core.Server**](./components/core-server.md): Server-side core functionality +- [**Orion.Core.Server.Web**](./components/core-server-web.md): Web API and HTTP interface +- [**Orion.Irc.Core**](./components/irc-core.md): IRC protocol implementation +- [**Orion.Network.Core**](./components/network-core.md): Networking abstractions +- [**Orion.Network.Tcp**](./components/network-tcp.md): TCP implementation for network transports + +## Advanced Topics + +- [Event System](./advanced/event-system.md) +- [Network Transport Architecture](./advanced/network-transport.md) +- [IRC Command Handling](./advanced/command-handling.md) +- [Scripting with JavaScript](./advanced/scripting.md) +- [Text Templating](./advanced/text-templating.md) +- [Security Features](./advanced/security.md) + +## Development + +- [Building from Source](./development/building.md) +- [Adding New Commands](./development/adding-commands.md) +- [Creating Plugins](./development/creating-plugins.md) +- [Contributing Guidelines](./development/contributing.md) +- [Coding Standards](./development/coding-standards.md) + +## API Reference + +- [HTTP API Documentation](./api/http-api.md) +- [JavaScript API](./api/javascript-api.md) + +## Troubleshooting + +- [Common Issues](./troubleshooting/common-issues.md) +- [Logs and Diagnostics](./troubleshooting/logs-diagnostics.md) +- [Performance Tuning](./troubleshooting/performance-tuning.md) + +## Community and Support + +- [Community Resources](./community/resources.md) +- [Support Channels](./community/support.md) +- [Contributing to Orion](./community/contributing.md) + +## Release Notes + +- [Version History](./releases/version-history.md) +- [Roadmap](./releases/roadmap.md) + +## License + +Orion IRC Server is licensed under the MIT License. See the [LICENSE](https://github.com/tgiachi/orion/blob/main/LICENSE) file for details. diff --git a/docs/toc.yml b/docs/toc.yml new file mode 100644 index 0000000..abd17b8 --- /dev/null +++ b/docs/toc.yml @@ -0,0 +1,4 @@ +- name: Docs + href: docs/ +- name: API + href: api/