baseline: OpenMU upstream b5a0961 (fresh source)

This commit is contained in:
Acentech Dev
2026-07-14 19:00:35 +03:00
parent 450402e47d
commit 36fc125d5c
11968 changed files with 748705 additions and 0 deletions

View File

@@ -0,0 +1,52 @@
// <copyright file="ClientLanguage.cs" company="MUnique">
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
// </copyright>
namespace MUnique.OpenMU.Network.PlugIns;
/// <summary>
/// The language of the client.
/// Webzen released clients to different countries, with slightly different network protocol, mostly different header values.
/// </summary>
public enum ClientLanguage
{
/// <summary>
/// Invariant client language. A plugin marked with this value is compatible with any client.
/// </summary>
Invariant,
/// <summary>
/// The english client language. A plugin marked with this value is compatible only with the english (GMO) client.
/// </summary>
English,
/// <summary>
/// The japanese client language. A plugin marked with this value is compatible only with the japanese client.
/// </summary>
Japanese,
/// <summary>
/// The vietnamese client language. A plugin marked with this value is compatible only with the vietnamese client.
/// </summary>
Vietnamese,
/// <summary>
/// The filipino client language. A plugin marked with this value is compatible only with the filipino client.
/// </summary>
Filipino,
/// <summary>
/// The chinese client language. A plugin marked with this value is compatible only with the chinese client.
/// </summary>
Chinese,
/// <summary>
/// The korean client language. A plugin marked with this value is compatible only with the korean client.
/// </summary>
Korean,
/// <summary>
/// The thai client language. A plugin marked with this value is compatible only with the thai client.
/// </summary>
Thai,
}

View File

@@ -0,0 +1,98 @@
// <copyright file="ClientVersion.cs" company="MUnique">
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
// </copyright>
namespace MUnique.OpenMU.Network.PlugIns;
/// <summary>
/// A definition about a client version.
/// </summary>
/// <param name="Season">The season.</param>
/// <param name="Episode">The episode.</param>
/// <param name="Language">The language.</param>
public record struct ClientVersion(byte Season, byte Episode, ClientLanguage Language) : IComparable<ClientVersion>, IComparable
{
private int CombinedVersion => (this.Season << 8) + this.Episode;
/// <summary>
/// Implements the operator &gt;.
/// </summary>
/// <param name="left">The left.</param>
/// <param name="right">The right.</param>
/// <returns>
/// The result of the operator.
/// </returns>
public static bool operator >(ClientVersion left, ClientVersion right) => Compare(left, right) > 0;
/// <summary>
/// Implements the operator &gt;=.
/// </summary>
/// <param name="left">The left.</param>
/// <param name="right">The right.</param>
/// <returns>
/// The result of the operator.
/// </returns>
public static bool operator >=(ClientVersion left, ClientVersion right) => Compare(left, right) > 0;
/// <summary>
/// Implements the operator &lt;.
/// </summary>
/// <param name="left">The left.</param>
/// <param name="right">The right.</param>
/// <returns>
/// The result of the operator.
/// </returns>
public static bool operator <(ClientVersion left, ClientVersion right) => Compare(left, right) < 0;
/// <summary>
/// Implements the operator &lt;=.
/// </summary>
/// <param name="left">The left.</param>
/// <param name="right">The right.</param>
/// <returns>
/// The result of the operator.
/// </returns>
public static bool operator <=(ClientVersion left, ClientVersion right) => Compare(left, right) < 0;
/// <inheritdoc />
public int CompareTo(ClientVersion other)
{
if (other.Language != ClientLanguage.Invariant && this.Language != other.Language)
{
return int.MinValue;
}
var result = this.CombinedVersion - other.CombinedVersion;
result *= 10;
if (this.Language != ClientLanguage.Invariant && other.Language == ClientLanguage.Invariant)
{
result++;
}
return result;
}
/// <inheritdoc/>
public int CompareTo(object? obj)
{
if (obj is ClientVersion other)
{
return this.CompareTo(other);
}
return int.MinValue;
}
/// <inheritdoc />
public override string ToString()
{
if (this.Season > 0)
{
return $"Season {this.Season} Episode {this.Episode} {this.Language}";
}
return $"{this.Season}.{this.Episode} {this.Language}";
}
private static int Compare(ClientVersion left, ClientVersion right) => left.CompareTo(right);
}

View File

@@ -0,0 +1,21 @@
// <copyright file="DataDirection.cs" company="MUnique">
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
// </copyright>
namespace MUnique.OpenMU.Network.PlugIns;
/// <summary>
/// The direction of the data flow.
/// </summary>
public enum DataDirection
{
/// <summary>
/// The data is sent from the client to the server.
/// </summary>
ClientToServer,
/// <summary>
/// The data is sent from the server to the client.
/// </summary>
ServerToClient,
}

View File

@@ -0,0 +1,34 @@
// <copyright file="INetworkEncryptionFactoryPlugIn.cs" company="MUnique">
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
// </copyright>
namespace MUnique.OpenMU.Network.PlugIns;
using System.IO.Pipelines;
using System.Runtime.InteropServices;
using MUnique.OpenMU.Network;
using MUnique.OpenMU.PlugIns;
/// <summary>
/// A strategy plugin interface for plugins which provide network packet encryptors and decryptors for a specific game client version.
/// </summary>
[PlugInPoint("Network Encryption Factories", "Plugins which will be executed when a client connects to a server. It provides network packet encryptors and decryptors for a specific game client version.")]
[Guid("97DF394A-513B-43AA-A833-40F322FC8E43")]
public interface INetworkEncryptionFactoryPlugIn : IStrategyPlugIn<ClientVersion>
{
/// <summary>
/// Creates a <see cref="IPipelinedDecryptor"/> for the specified source.
/// </summary>
/// <param name="source">The source.</param>
/// <param name="direction">The direction of the data flow.</param>
/// <returns>The created decryptor.</returns>
IPipelinedDecryptor? CreateDecryptor(PipeReader source, DataDirection direction);
/// <summary>
/// Creates a <see cref="IPipelinedEncryptor"/> for the specified target.
/// </summary>
/// <param name="target">The target.</param>
/// /// <param name="direction">The direction of the data flow.</param>
/// <returns>The created encryptor.</returns>
IPipelinedEncryptor? CreateEncryptor(PipeWriter target, DataDirection direction);
}

View File

@@ -0,0 +1,47 @@
// <copyright file="OpenSourceClientNetworkEncryptionFactoryPlugIn.cs" company="MUnique">
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
// </copyright>
namespace MUnique.OpenMU.Network.PlugIns;
using System.ComponentModel.DataAnnotations;
using System.IO.Pipelines;
using System.Runtime.InteropServices;
using MUnique.OpenMU.Network;
using MUnique.OpenMU.Network.SimpleModulus;
using MUnique.OpenMU.Network.Xor;
using MUnique.OpenMU.PlugIns;
/// <summary>
/// A plugin which provides network encryptors and decryptors for the english open source game clients of season 6 episode 3, version 2.04d.
/// </summary>
[PlugIn]
[Display(Name = nameof(PlugInResources.OpenSourceClientNetworkEncryptionFactoryPlugIn_Name), Description = nameof(PlugInResources.OpenSourceClientNetworkEncryptionFactoryPlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("AB9EBD28-7A45-4FBA-A282-E2120E70FF17")]
public class OpenSourceClientNetworkEncryptionFactoryPlugIn : INetworkEncryptionFactoryPlugIn
{
/// <inheritdoc />
public ClientVersion Key { get; } = new(106, 3, ClientLanguage.English);
/// <inheritdoc />
public IPipelinedEncryptor CreateEncryptor(PipeWriter target, DataDirection direction)
{
if (direction == DataDirection.ServerToClient)
{
return new PipelinedEncryptor(target);
}
return new PipelinedXor32Encryptor(new PipelinedSimpleModulusEncryptor(target, PipelinedSimpleModulusEncryptor.DefaultClientKey).Writer);
}
/// <inheritdoc />
public IPipelinedDecryptor CreateDecryptor(PipeReader source, DataDirection direction)
{
if (direction == DataDirection.ClientToServer)
{
return new PipelinedDecryptor(source);
}
return new PipelinedSimpleModulusDecryptor(source, PipelinedSimpleModulusDecryptor.DefaultClientKey);
}
}

View File

@@ -0,0 +1,60 @@
// <copyright file="PreSeason6NetworkEncryptionFactoryPlugIn.cs" company="MUnique">
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
// </copyright>
namespace MUnique.OpenMU.Network.PlugIns;
using System.ComponentModel.DataAnnotations;
using System.IO.Pipelines;
using System.Runtime.InteropServices;
using MUnique.OpenMU.Network;
using MUnique.OpenMU.Network.SimpleModulus;
using MUnique.OpenMU.Network.Xor;
using MUnique.OpenMU.PlugIns;
/// <summary>
/// A plugin which provides network encryptors and decryptors for game clients before season 6.
/// </summary>
/// <remarks>
/// The simple modulus keys were never changed, so the default keys of season 6 work here without changes.
/// For the Xor32 key it's different. During season 6 on GMO, Webzen desperately changed them in a regular manner - sometimes
/// every weekly maintenance. Needless to say, calculating the new key was a matter of seconds and provided no protection from skilled hackers at all.
/// </remarks>
[PlugIn]
[Display(Name = nameof(PlugInResources.PreSeason6NetworkEncryptionFactoryPlugIn_Name), Description = nameof(PlugInResources.PreSeason6NetworkEncryptionFactoryPlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("E72839BF-5ADE-419D-91C5-278EC2A7CEBF")]
public class PreSeason6NetworkEncryptionFactoryPlugIn : INetworkEncryptionFactoryPlugIn
{
/// <summary>
/// The xor32 key for all clients before season 6.
/// </summary>
private static readonly byte[] Xor32Key =
{
0xE7, 0x6D, 0x3A, 0x89, 0xBC, 0xB2, 0x9F, 0x73, 0x23, 0xA8, 0xFE, 0xB6, 0x49, 0x5D, 0x39, 0x5D, 0x8A, 0xCB, 0x63, 0x8D, 0xEA, 0x7D, 0x2B, 0x5F, 0xC3, 0xB1, 0xE9, 0x83, 0x29, 0x51, 0xE8, 0x56,
};
/// <inheritdoc />
public ClientVersion Key { get; } = default;
/// <inheritdoc />
public IPipelinedEncryptor CreateEncryptor(PipeWriter target, DataDirection direction)
{
if (direction == DataDirection.ServerToClient)
{
return new PipelinedEncryptor(target);
}
return new PipelinedXor32Encryptor(new PipelinedSimpleModulusEncryptor(target, PipelinedSimpleModulusEncryptor.DefaultClientKey).Writer, Xor32Key);
}
/// <inheritdoc />
public IPipelinedDecryptor CreateDecryptor(PipeReader source, DataDirection direction)
{
if (direction == DataDirection.ClientToServer)
{
return new PipelinedDecryptor(source, PipelinedSimpleModulusDecryptor.DefaultServerKey, Xor32Key);
}
return new PipelinedSimpleModulusDecryptor(source, PipelinedSimpleModulusDecryptor.DefaultClientKey);
}
}

View File

@@ -0,0 +1,47 @@
// <copyright file="Season6Episode3NetworkEncryptionFactoryPlugIn.cs" company="MUnique">
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
// </copyright>
namespace MUnique.OpenMU.Network.PlugIns;
using System.ComponentModel.DataAnnotations;
using System.IO.Pipelines;
using System.Runtime.InteropServices;
using MUnique.OpenMU.Network;
using MUnique.OpenMU.Network.SimpleModulus;
using MUnique.OpenMU.Network.Xor;
using MUnique.OpenMU.PlugIns;
/// <summary>
/// A plugin which provides network encryptors and decryptors for english game clients of season 6 episode 3, version 1.04d.
/// </summary>
[PlugIn]
[Display(Name = nameof(PlugInResources.Season6Episode3NetworkEncryptionFactoryPlugIn_Name), Description = nameof(PlugInResources.Season6Episode3NetworkEncryptionFactoryPlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("AC79C81C-36A1-49A0-85AD-E4DAC7D5C5CE")]
public class Season6Episode3NetworkEncryptionFactoryPlugIn : INetworkEncryptionFactoryPlugIn
{
/// <inheritdoc />
public ClientVersion Key { get; } = new(6, 3, ClientLanguage.English);
/// <inheritdoc />
public IPipelinedEncryptor CreateEncryptor(PipeWriter target, DataDirection direction)
{
if (direction == DataDirection.ServerToClient)
{
return new PipelinedEncryptor(target);
}
return new PipelinedXor32Encryptor(new PipelinedSimpleModulusEncryptor(target, PipelinedSimpleModulusEncryptor.DefaultClientKey).Writer);
}
/// <inheritdoc />
public IPipelinedDecryptor CreateDecryptor(PipeReader source, DataDirection direction)
{
if (direction == DataDirection.ClientToServer)
{
return new PipelinedDecryptor(source);
}
return new PipelinedSimpleModulusDecryptor(source, PipelinedSimpleModulusDecryptor.DefaultClientKey);
}
}

View File

@@ -0,0 +1,66 @@
// <copyright file="Version075NetworkEncryptionFactoryPlugIn.cs" company="MUnique">
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
// </copyright>
namespace MUnique.OpenMU.Network.PlugIns;
using System.ComponentModel.DataAnnotations;
using System.IO.Pipelines;
using System.Runtime.InteropServices;
using MUnique.OpenMU.Network;
using MUnique.OpenMU.Network.SimpleModulus;
using MUnique.OpenMU.PlugIns;
/// <summary>
/// A plugin which provides network encryptors and decryptors for game clients of version 0.75 (server version 0.65).
/// </summary>
/// <remarks>
/// This early and very old version doesn't seem to have xor 32 encryption yet.
/// However, it uses simple modulus with some other keys.
/// </remarks>
[PlugIn]
[Display(Name = nameof(PlugInResources.Version075NetworkEncryptionFactoryPlugIn_Name), Description = nameof(PlugInResources.Version075NetworkEncryptionFactoryPlugIn_Description), ResourceType = typeof(PlugInResources))]
[Guid("E83F05AC-18D4-4714-AEFB-2F4F3B37951C")]
public class Version075NetworkEncryptionFactoryPlugIn : INetworkEncryptionFactoryPlugIn
{
/// <summary>
/// The simple modulus keys which are used to transfer data from client to server.
/// </summary>
/// <remarks>
/// Enc1.dat (client file):
/// Modulus: 102510, 92475, 128027, 81329, 70183, 106846, 85665, 114515, 212247, 82188, 154403, 71042, 122076, 157628, 74267, 110930
/// Crypt: 24347, 21878, 31058, 35010, 15375, 24555, 15976, 18344, 26249, 24973, 10565, 12143, 6481, 21283, 21147, 30327
/// XOR: 2573, 25253, 28177, 14604, 17198, 36180, 26560, 26251, 31434, 5415, 30023, 60392, 23094, 3763, 24151, 8640
/// Calculated Crypt Key: 33683, 33092, 21827, 3905, 1269, 2019, 27706, 35839, 10730, 34033, 22258, 32587, 29629, 25211, 2353, 6873.
/// </remarks>
private static readonly SimpleModulusKeys ClientToServerKeys = new(
new uint[] { 102510, 92475, 128027, 81329, 70183, 106846, 85665, 114515, 212247, 82188, 154403, 71042, 122076, 157628, 74267, 110930 },
new uint[] { 2573, 25253, 28177, 14604, 17198, 36180, 26560, 26251, 31434, 5415, 30023, 60392, 23094, 3763, 24151, 8640 },
new uint[] { 24347, 21878, 31058, 35010, 15375, 24555, 15976, 18344, 26249, 24973, 10565, 12143, 6481, 21283, 21147, 30327 },
new uint[] { 33683, 33092, 21827, 3905, 1269, 2019, 27706, 35839, 10730, 34033, 22258, 32587, 29629, 25211, 2353, 6873 });
/// <summary>
/// The simple modulus keys which are used to transfer data from server to client.
/// </summary>
/// <remarks>
/// Dec2.dat (client file):
/// Modulus: 85408, 122071, 147588, 136442, 78598, 187476, 81823, 118486, 71788, 107340, 115009, 103863, 82682, 71536, 97053, 170379
/// Crypt: 32265, 27110, 8593, 9807, 46581, 19561, 30064, 13133, 20169, 24647, 7162, 28304, 40819, 44985, 19577, 1178
/// XOR: 31800, 64655, 7620, 59986, 36846, 57613, 50524, 22089, 23951, 62961, 18047, 1584, 53418, 60300, 54445, 2206
/// Calculated Crypt Key: 23289, 24896, 28597, 12911, 11889, 6661, 27698, 28699, 35789, 4403, 11032, 24164, 17661, 30793, 21347, 5930.
/// </remarks>
private static readonly SimpleModulusKeys ServerToClientKeys = new(
new uint[] { 85408, 122071, 147588, 136442, 78598, 187476, 81823, 118486, 71788, 107340, 115009, 103863, 82682, 71536, 97053, 170379 },
new uint[] { 31800, 64655, 7620, 59986, 36846, 57613, 50524, 22089, 23951, 62961, 18047, 1584, 53418, 60300, 54445, 2206 },
new uint[] { 23289, 24896, 28597, 12911, 11889, 6661, 27698, 28699, 35789, 4403, 11032, 24164, 17661, 30793, 21347, 5930 },
new uint[] { 32265, 27110, 8593, 9807, 46581, 19561, 30064, 13133, 20169, 24647, 7162, 28304, 40819, 44985, 19577, 1178 });
/// <inheritdoc />
public ClientVersion Key { get; } = new(0, 75, ClientLanguage.Invariant);
/// <inheritdoc />
public IPipelinedEncryptor CreateEncryptor(PipeWriter target, DataDirection direction) => new PipelinedSimpleModulusEncryptor(target, direction == DataDirection.ClientToServer ? ClientToServerKeys : ServerToClientKeys);
/// <inheritdoc />
public IPipelinedDecryptor CreateDecryptor(PipeReader source, DataDirection direction) => new PipelinedSimpleModulusDecryptor(source, direction == DataDirection.ClientToServer ? ClientToServerKeys : ServerToClientKeys);
}