chore: formatting and slnx
Signed-off-by: Timothy Schenk <admin@rainote.dev>
This commit is contained in:
parent
09f8dda990
commit
3a24dabdf2
93 changed files with 437 additions and 770 deletions
|
@ -1,4 +1,4 @@
|
|||
; EditorConfig to support per-solution formatting.
|
||||
; EditorConfig to support per-solution formatting.
|
||||
; Use the EditorConfig VS add-in to make this work.
|
||||
; http://editorconfig.org/
|
||||
;
|
||||
|
@ -53,7 +53,7 @@ csharp_style_var_elsewhere = true:suggestion
|
|||
csharp_style_throw_expression = false:suggestion
|
||||
|
||||
# Newline settings
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_before_open_brace = none
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_finally = true
|
||||
|
@ -469,4 +469,4 @@ dotnet_diagnostic.IDE0161.severity = silent
|
|||
|
||||
[{**/Shared/**.cs,**/microsoft.extensions.hostfactoryresolver.sources/**.{cs,vb}}]
|
||||
# IDE0005: Remove unused usings. Ignore for shared src files since imports for those depend on the projects in which they are included.
|
||||
dotnet_diagnostic.IDE0005.severity = silent
|
||||
dotnet_diagnostic.IDE0005.severity = silent
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -5,7 +5,7 @@
|
|||
|
||||
licenses
|
||||
.run
|
||||
|
||||
BenchmarkDotNet.Artifacts
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
|
|
|
@ -5,15 +5,15 @@ repos:
|
|||
- id: dotnet-format
|
||||
name: dotnet-format
|
||||
language: system
|
||||
entry: dotnet format --include
|
||||
entry: dotnet format --include Continuity.slnx
|
||||
types_or: [c#, vb]
|
||||
- repo: https://github.com/Mateusz-Grzelinski/actionlint-py
|
||||
rev: v1.7.1.15
|
||||
rev: v1.7.6.22
|
||||
hooks:
|
||||
- id: actionlint
|
||||
additional_dependencies: [pyflakes>=3.0.1, shellcheck-py>=0.9.0.5]
|
||||
- repo: https://github.com/hadolint/hadolint
|
||||
rev: v2.13.0-beta
|
||||
rev: v2.13.1-beta
|
||||
hooks:
|
||||
- id: hadolint-docker
|
||||
args: [--ignore, SC2086]
|
||||
|
|
|
@ -11,8 +11,7 @@ namespace Benchmarks;
|
|||
|
||||
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
|
||||
[Config(typeof(GenericConfig))]
|
||||
public class Argon2Benchmarks
|
||||
{
|
||||
public class Argon2Benchmarks {
|
||||
private byte[] _additionalData = null!;
|
||||
[Params(2, 4)] public int _iterations;
|
||||
[Params(16)] public int _length;
|
||||
|
@ -23,18 +22,15 @@ public class Argon2Benchmarks
|
|||
private byte[] _salt = null!;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
public void Setup() {
|
||||
_salt = RandomNumberGenerator.GetBytes(16);
|
||||
_additionalData = RandomNumberGenerator.GetBytes(16);
|
||||
_password = RandomNumberGenerator.GetBytes(16);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public byte[] Argon2i()
|
||||
{
|
||||
return new Argon2i(_password)
|
||||
{
|
||||
public byte[] Argon2i() {
|
||||
return new Argon2i(_password) {
|
||||
Iterations = _iterations,
|
||||
MemorySize = 1024 * _memory,
|
||||
DegreeOfParallelism = _parallelism,
|
||||
|
@ -44,10 +40,8 @@ public class Argon2Benchmarks
|
|||
}
|
||||
|
||||
[Benchmark]
|
||||
public byte[] Argon2d()
|
||||
{
|
||||
return new Argon2d(_password)
|
||||
{
|
||||
public byte[] Argon2d() {
|
||||
return new Argon2d(_password) {
|
||||
Iterations = _iterations,
|
||||
MemorySize = 1024 * _memory,
|
||||
DegreeOfParallelism = _parallelism,
|
||||
|
@ -57,10 +51,8 @@ public class Argon2Benchmarks
|
|||
}
|
||||
|
||||
[Benchmark]
|
||||
public byte[] Argon2id()
|
||||
{
|
||||
return new Argon2id(_password)
|
||||
{
|
||||
public byte[] Argon2id() {
|
||||
return new Argon2id(_password) {
|
||||
Iterations = _iterations,
|
||||
MemorySize = 1024 * _memory,
|
||||
DegreeOfParallelism = _parallelism,
|
||||
|
@ -70,10 +62,8 @@ public class Argon2Benchmarks
|
|||
}
|
||||
|
||||
[Benchmark]
|
||||
public byte[] IsopohArgon2DD()
|
||||
{
|
||||
var config = new Argon2Config
|
||||
{
|
||||
public byte[] IsopohArgon2DD() {
|
||||
var config = new Argon2Config {
|
||||
Type = Argon2Type.DataDependentAddressing,
|
||||
Version = Argon2Version.Nineteen,
|
||||
MemoryCost = 1024 * _memory,
|
||||
|
@ -89,10 +79,8 @@ public class Argon2Benchmarks
|
|||
}
|
||||
|
||||
[Benchmark]
|
||||
public byte[] IsopohArgon2DI()
|
||||
{
|
||||
var config = new Argon2Config
|
||||
{
|
||||
public byte[] IsopohArgon2DI() {
|
||||
var config = new Argon2Config {
|
||||
Type = Argon2Type.DataIndependentAddressing,
|
||||
Version = Argon2Version.Nineteen,
|
||||
MemoryCost = 1024 * _memory,
|
||||
|
@ -108,10 +96,8 @@ public class Argon2Benchmarks
|
|||
}
|
||||
|
||||
[Benchmark]
|
||||
public byte[] IsopohArgon2Hybrid()
|
||||
{
|
||||
var config = new Argon2Config
|
||||
{
|
||||
public byte[] IsopohArgon2Hybrid() {
|
||||
var config = new Argon2Config {
|
||||
Type = Argon2Type.HybridAddressing,
|
||||
Version = Argon2Version.Nineteen,
|
||||
MemoryCost = 1024 * _memory,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>12</LangVersion>
|
||||
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
|
||||
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -9,29 +9,25 @@ namespace Benchmarks;
|
|||
|
||||
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
|
||||
[Config(typeof(GenericConfig))]
|
||||
public class BinaryConversionBenchmarks
|
||||
{
|
||||
public class BinaryConversionBenchmarks {
|
||||
private byte[] _data = null!;
|
||||
private int _offset;
|
||||
private int _writeBuffer;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
public void Setup() {
|
||||
_data = RandomNumberGenerator.GetBytes(4000);
|
||||
_offset = RandomNumberGenerator.GetInt32(0, 3500);
|
||||
_writeBuffer = RandomNumberGenerator.GetInt32(int.MinValue, int.MaxValue);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public short BitConverterParseTest()
|
||||
{
|
||||
public short BitConverterParseTest() {
|
||||
return BitConverter.ToInt16(_data, _offset);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public short BinaryReader()
|
||||
{
|
||||
public short BinaryReader() {
|
||||
using var ms = new MemoryStream(_data);
|
||||
using var reader = new BinaryReader(ms);
|
||||
reader.BaseStream.Position = _offset;
|
||||
|
@ -39,28 +35,24 @@ public class BinaryConversionBenchmarks
|
|||
}
|
||||
|
||||
[Benchmark]
|
||||
public short BinaryPrimitivesRead()
|
||||
{
|
||||
public short BinaryPrimitivesRead() {
|
||||
return BinaryPrimitives.ReadInt16LittleEndian(
|
||||
new ArraySegment<byte>(_data, _offset, sizeof(short)));
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void BinaryPrimitivesWrite()
|
||||
{
|
||||
public void BinaryPrimitivesWrite() {
|
||||
BinaryPrimitives.WriteInt32LittleEndian(_data.AsSpan(_offset, 4),
|
||||
_writeBuffer);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void BitConverterCopy()
|
||||
{
|
||||
public void BitConverterCopy() {
|
||||
BitConverter.GetBytes(_writeBuffer).CopyTo(_data, _offset);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void BitConverterAssignment()
|
||||
{
|
||||
public void BitConverterAssignment() {
|
||||
var bytes = BitConverter.GetBytes(_writeBuffer);
|
||||
_data[_offset] = bytes[0];
|
||||
_data[_offset + 1] = bytes[1];
|
||||
|
|
|
@ -9,8 +9,7 @@ namespace Benchmarks;
|
|||
|
||||
[Config(typeof(GenericConfig))]
|
||||
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
|
||||
public class DataCacheBenchmark
|
||||
{
|
||||
public class DataCacheBenchmark {
|
||||
private ConcurrentDictionary<int, int> _concurrentDictionary = null!;
|
||||
private Dictionary<int, int> _dictionary = null!;
|
||||
private HashSet<int> _hashSet = null!;
|
||||
|
@ -18,8 +17,7 @@ public class DataCacheBenchmark
|
|||
[Params(1000, 100000, 1000000)] public int N;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
public void Setup() {
|
||||
_hashSet = new HashSet<int>();
|
||||
_dictionary = new Dictionary<int, int>();
|
||||
_concurrentDictionary = new ConcurrentDictionary<int, int>();
|
||||
|
@ -32,8 +30,7 @@ public class DataCacheBenchmark
|
|||
_hashSet.EnsureCapacity(N);
|
||||
_dictionary.EnsureCapacity(N);
|
||||
|
||||
for (var i = 0; i < N; i++)
|
||||
{
|
||||
for (var i = 0; i < N; i++) {
|
||||
_immutableHashSet = _immutableHashSet.Add(i);
|
||||
_hashSet.Add(i);
|
||||
_dictionary.Add(i, i);
|
||||
|
@ -42,45 +39,38 @@ public class DataCacheBenchmark
|
|||
}
|
||||
|
||||
[Benchmark]
|
||||
public void HashSetAdd()
|
||||
{
|
||||
public void HashSetAdd() {
|
||||
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => _hashSet.Add(i));
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void DictionaryAdd()
|
||||
{
|
||||
public void DictionaryAdd() {
|
||||
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => _dictionary.Add(N + i, i));
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void ConcurrentDictionaryAddOrUpdate()
|
||||
{
|
||||
public void ConcurrentDictionaryAddOrUpdate() {
|
||||
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i =>
|
||||
_concurrentDictionary.AddOrUpdate(N + i, i, (_, oldValue) => oldValue + i));
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void ImmutableHashSetLookup()
|
||||
{
|
||||
public void ImmutableHashSetLookup() {
|
||||
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => { _ = _immutableHashSet.Contains(i); });
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void HashSetLookup()
|
||||
{
|
||||
public void HashSetLookup() {
|
||||
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => { _ = _hashSet.Contains(i); });
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void DictionaryLookup()
|
||||
{
|
||||
public void DictionaryLookup() {
|
||||
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => { _ = _dictionary.ContainsKey(i); });
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void ConcurrentDictionaryLookup()
|
||||
{
|
||||
public void ConcurrentDictionaryLookup() {
|
||||
ParallelEnumerable.Range(0, N).AsParallel().ForAll(i => { _ = _concurrentDictionary.ContainsKey(i); });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,10 +11,8 @@ using BenchmarkDotNet.Jobs;
|
|||
|
||||
namespace Benchmarks;
|
||||
|
||||
public class GenericConfig : ManualConfig
|
||||
{
|
||||
public GenericConfig()
|
||||
{
|
||||
public class GenericConfig : ManualConfig {
|
||||
public GenericConfig() {
|
||||
AddJob(Job.Default
|
||||
.WithRuntime(CoreRuntime.Core80))
|
||||
.AddDiagnoser(ThreadingDiagnoser.Default, MemoryDiagnoser.Default,
|
||||
|
|
|
@ -8,32 +8,26 @@ namespace Benchmarks;
|
|||
|
||||
[Config(typeof(GenericConfig))]
|
||||
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
|
||||
public class MemCasting
|
||||
{
|
||||
public class MemCasting {
|
||||
private byte[] _data = null!;
|
||||
private byte[] _arrayData = null!;
|
||||
|
||||
[Params(1000, 100000, 1000000)] public int N;
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
public void Setup() {
|
||||
_data = new byte[64];
|
||||
_arrayData = new byte[N * 64];
|
||||
Random.Shared.NextBytes(_data);
|
||||
Random.Shared.NextBytes(_arrayData);
|
||||
}
|
||||
private static ElementalStats ReadElementalStatsMemoryMarshal(ref Span<byte> data)
|
||||
{
|
||||
private static ElementalStats ReadElementalStatsMemoryMarshal(ref Span<byte> data) {
|
||||
return MemoryMarshal.Cast<byte, ElementalStats>(data.Slice(0, 64))[0];
|
||||
}
|
||||
private static ElementalStats ReadElementalStatsMemoryMarshal2(ref Span<byte> data)
|
||||
{
|
||||
private static ElementalStats ReadElementalStatsMemoryMarshal2(ref Span<byte> data) {
|
||||
return MemoryMarshal.Read<ElementalStats>(data.Slice(0, 64));
|
||||
}
|
||||
private static ElementalStats ReadElementalStatsNew(ref Span<byte> data)
|
||||
{
|
||||
return new ElementalStats
|
||||
{
|
||||
private static ElementalStats ReadElementalStatsNew(ref Span<byte> data) {
|
||||
return new ElementalStats {
|
||||
MinimumFireDamage = BitConverter.ToInt32(data.Slice(0, 4)), // 140 -> 144
|
||||
MinimumWaterDamage = BitConverter.ToInt32(data.Slice(4, 4)), // 144 -> 148
|
||||
MinimumDarkDamage = BitConverter.ToInt32(data.Slice(8, 4)), // 148 -> 152
|
||||
|
@ -54,8 +48,7 @@ public class MemCasting
|
|||
}
|
||||
|
||||
[Benchmark]
|
||||
public Span<ElementalStats> MemoryMarshalCastArray()
|
||||
{
|
||||
public Span<ElementalStats> MemoryMarshalCastArray() {
|
||||
var data = _arrayData.AsSpan();
|
||||
var elements = MemoryMarshal.Cast<byte, ElementalStats>(data);
|
||||
|
||||
|
@ -63,24 +56,20 @@ public class MemCasting
|
|||
}
|
||||
|
||||
[Benchmark]
|
||||
public Span<ElementalStats> MemoryMarshalReadArray()
|
||||
{
|
||||
public Span<ElementalStats> MemoryMarshalReadArray() {
|
||||
Span<ElementalStats> statsArr = stackalloc ElementalStats[N + 1];
|
||||
var data = _data.AsSpan();
|
||||
for (int i = 0; i <= N; i++)
|
||||
{
|
||||
for (int i = 0; i <= N; i++) {
|
||||
statsArr[i] = ReadElementalStatsMemoryMarshal2(ref data);
|
||||
}
|
||||
|
||||
return statsArr.ToArray();
|
||||
}
|
||||
[Benchmark]
|
||||
public Span<ElementalStats> ManualSpanSlicingArray()
|
||||
{
|
||||
public Span<ElementalStats> ManualSpanSlicingArray() {
|
||||
Span<ElementalStats> statsArr = stackalloc ElementalStats[N + 1];
|
||||
var data = _data.AsSpan();
|
||||
for (int i = 0; i <= N; i++)
|
||||
{
|
||||
for (int i = 0; i <= N; i++) {
|
||||
statsArr[i] = ReadElementalStatsNew(ref data);
|
||||
}
|
||||
|
||||
|
@ -88,28 +77,24 @@ public class MemCasting
|
|||
}
|
||||
|
||||
[Benchmark]
|
||||
public ElementalStats MemoryMarshalCastSingle()
|
||||
{
|
||||
public ElementalStats MemoryMarshalCastSingle() {
|
||||
var data = _data.AsSpan();
|
||||
return ReadElementalStatsMemoryMarshal(ref data);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public ElementalStats MemoryMarshalReadSingle()
|
||||
{
|
||||
public ElementalStats MemoryMarshalReadSingle() {
|
||||
var data = _data.AsSpan();
|
||||
return ReadElementalStatsMemoryMarshal2(ref data);
|
||||
}
|
||||
[Benchmark]
|
||||
public ElementalStats ManualSpanSlicingSingle()
|
||||
{
|
||||
public ElementalStats ManualSpanSlicingSingle() {
|
||||
var data = _data.AsSpan();
|
||||
return ReadElementalStatsNew(ref data);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 64)]
|
||||
public struct ElementalStats
|
||||
{
|
||||
public struct ElementalStats {
|
||||
[FieldOffset(0)]
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int MinimumFireDamage;
|
||||
|
|
|
@ -10,16 +10,14 @@ using Wonderking.Packets;
|
|||
|
||||
namespace Continuity.AuthServer;
|
||||
|
||||
public class AuthSession : TcpSession
|
||||
{
|
||||
public class AuthSession : TcpSession {
|
||||
private readonly PacketDistributorService<OperationCode, AuthSession> _distributorService;
|
||||
private readonly ILogger<AuthSession> _logger;
|
||||
private readonly IMediator _mediator;
|
||||
|
||||
public AuthSession(TcpServer
|
||||
server, IMediator mediator, ILogger<AuthSession> logger,
|
||||
PacketDistributorService<OperationCode, AuthSession> distributorService) : base(server)
|
||||
{
|
||||
PacketDistributorService<OperationCode, AuthSession> distributorService) : base(server) {
|
||||
_mediator = mediator;
|
||||
_logger = logger;
|
||||
_distributorService = distributorService;
|
||||
|
@ -27,14 +25,12 @@ public class AuthSession : TcpSession
|
|||
|
||||
public Guid AccountId { get; set; }
|
||||
|
||||
public override long Send(byte[] buffer)
|
||||
{
|
||||
public override long Send(byte[] buffer) {
|
||||
_logger.LogInformation("Data being sent is: {Data}", BitConverter.ToString(buffer));
|
||||
return base.Send(buffer);
|
||||
}
|
||||
|
||||
public Task SendAsync(IOutgoingPacket packet)
|
||||
{
|
||||
public Task SendAsync(IOutgoingPacket packet) {
|
||||
var opcode = _distributorService.GetOperationCodeByPacketType(packet);
|
||||
|
||||
Span<byte> packetData = packet.Serialize();
|
||||
|
@ -46,13 +42,11 @@ public class AuthSession : TcpSession
|
|||
|
||||
var bytesOfLength = BitConverter.GetBytes(length);
|
||||
var bytesOfOpcode = BitConverter.GetBytes((ushort)opcode);
|
||||
for (var i = 0; i < bytesOfLength.Length || i < 2; i++)
|
||||
{
|
||||
for (var i = 0; i < bytesOfLength.Length || i < 2; i++) {
|
||||
buffer[i] = bytesOfLength[i];
|
||||
}
|
||||
|
||||
for (var i = 0; i < bytesOfOpcode.Length || i < 2; i++)
|
||||
{
|
||||
for (var i = 0; i < bytesOfOpcode.Length || i < 2; i++) {
|
||||
buffer[2 + i] = bytesOfOpcode[i];
|
||||
}
|
||||
|
||||
|
@ -63,8 +57,7 @@ public class AuthSession : TcpSession
|
|||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
protected override void OnReceived(byte[] buffer, long offset, long size)
|
||||
{
|
||||
protected override void OnReceived(byte[] buffer, long offset, long size) {
|
||||
_logger.LogDebug("Length: {Size} & offset: {Offset}", size, offset);
|
||||
Span<byte> decryptedBuffer = stackalloc byte[(int)size];
|
||||
|
||||
|
@ -93,18 +86,15 @@ public class AuthSession : TcpSession
|
|||
base.OnReceived(decryptedBuffer.ToArray(), offset, decryptedBuffer.Length);
|
||||
}
|
||||
|
||||
private static Span<byte> Decrypt(Span<byte> buffer)
|
||||
{
|
||||
for (var i = 0; i < buffer.Length; ++i)
|
||||
{
|
||||
private static Span<byte> Decrypt(Span<byte> buffer) {
|
||||
for (var i = 0; i < buffer.Length; ++i) {
|
||||
buffer[i] = (byte)(buffer[i] ^ i ^ (3 * (0xFE - i)));
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
protected override void OnError(SocketError error)
|
||||
{
|
||||
protected override void OnError(SocketError error) {
|
||||
_logger.LogWarning("An error has occured: {Error}", error);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,7 @@ using NetCoreServer;
|
|||
|
||||
namespace Continuity.AuthServer;
|
||||
|
||||
public class ChannelSession : TcpSession
|
||||
{
|
||||
public class ChannelSession : TcpSession {
|
||||
private static readonly byte[] _key = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7 }
|
||||
.Reverse().ToArray();
|
||||
|
||||
|
@ -25,8 +24,7 @@ public class ChannelSession : TcpSession
|
|||
private readonly IMediator _mediator;
|
||||
private bool _disposed;
|
||||
|
||||
public ChannelSession(TcpServer server, IMediator mediator, ILogger<ChannelSession> logger) : base(server)
|
||||
{
|
||||
public ChannelSession(TcpServer server, IMediator mediator, ILogger<ChannelSession> logger) : base(server) {
|
||||
_mediator = mediator;
|
||||
_logger = logger;
|
||||
using var aes = Aes.Create();
|
||||
|
@ -41,39 +39,31 @@ public class ChannelSession : TcpSession
|
|||
_encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
|
||||
}
|
||||
|
||||
protected override void OnReceived(byte[] buffer, long offset, long size)
|
||||
{
|
||||
try
|
||||
{
|
||||
protected override void OnReceived(byte[] buffer, long offset, long size) {
|
||||
try {
|
||||
using (var ms = new MemoryStream(Decrypt(buffer)))
|
||||
using (var cs = new CryptoStream(ms, _decryptor, CryptoStreamMode.Read))
|
||||
{
|
||||
using (var cs = new CryptoStream(ms, _decryptor, CryptoStreamMode.Read)) {
|
||||
var amountOfReadBytes = cs.Read(buffer);
|
||||
if (amountOfReadBytes != buffer.Length)
|
||||
{
|
||||
if (amountOfReadBytes != buffer.Length) {
|
||||
_logger.LogError("Amount of read bytes is not equal to buffer length");
|
||||
}
|
||||
}
|
||||
|
||||
base.OnReceived(buffer, offset, size);
|
||||
}
|
||||
catch (CryptographicException ex)
|
||||
{
|
||||
catch (CryptographicException ex) {
|
||||
_logger.LogError("An error has occured while decrypting: {ErrorMessage}", ex.Message);
|
||||
_logger.LogError("Default buffer message: {Message}", Encoding.ASCII.GetString(buffer));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposingManagedResources)
|
||||
{
|
||||
if (_disposed)
|
||||
{
|
||||
protected override void Dispose(bool disposingManagedResources) {
|
||||
if (_disposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
if (disposingManagedResources)
|
||||
{
|
||||
if (disposingManagedResources) {
|
||||
_decryptor.Dispose();
|
||||
_encryptor.Dispose();
|
||||
}
|
||||
|
@ -81,15 +71,12 @@ public class ChannelSession : TcpSession
|
|||
base.Dispose(disposingManagedResources);
|
||||
}
|
||||
|
||||
protected virtual void ThrowIfDisposed()
|
||||
{
|
||||
protected virtual void ThrowIfDisposed() {
|
||||
ObjectDisposedException.ThrowIf(_disposed, GetType());
|
||||
}
|
||||
|
||||
private static byte[] Decrypt(byte[] buffer)
|
||||
{
|
||||
for (var i = 0; i < buffer.Length; ++i)
|
||||
{
|
||||
private static byte[] Decrypt(byte[] buffer) {
|
||||
for (var i = 0; i < buffer.Length; ++i) {
|
||||
buffer[i] = (byte)(buffer[i] ^ i ^ (3 * (0xFE - i)));
|
||||
}
|
||||
|
||||
|
|
|
@ -10,19 +10,16 @@ using Wonderking.Packets;
|
|||
namespace Continuity.AuthServer.Consumers;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class PacketConsumer : IConsumer<RawPacket>, IDisposable
|
||||
{
|
||||
public sealed class PacketConsumer : IConsumer<RawPacket>, IDisposable {
|
||||
private readonly ActivitySource _activitySource;
|
||||
private readonly PacketDistributorService<OperationCode, AuthSession> _distributorService;
|
||||
|
||||
public PacketConsumer(PacketDistributorService<OperationCode, AuthSession> distributorService)
|
||||
{
|
||||
public PacketConsumer(PacketDistributorService<OperationCode, AuthSession> distributorService) {
|
||||
_distributorService = distributorService;
|
||||
_activitySource = new ActivitySource(nameof(PacketConsumer));
|
||||
}
|
||||
|
||||
public async Task Consume(ConsumeContext<RawPacket> context)
|
||||
{
|
||||
public async Task Consume(ConsumeContext<RawPacket> context) {
|
||||
using var activity = _activitySource?.StartActivity("PacketConsumption");
|
||||
activity?.SetTag("PacketId", context.Message.OperationCode.ToString());
|
||||
activity?.SetTag("SessionId", context.Message.Session.Id.ToString());
|
||||
|
@ -32,8 +29,7 @@ public sealed class PacketConsumer : IConsumer<RawPacket>, IDisposable
|
|||
context.Message.Session);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
public void Dispose() {
|
||||
_activitySource.Dispose();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<ProduceReferenceAssembly>True</ProduceReferenceAssembly>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
<AnalysisLevel>latest-recommended</AnalysisLevel>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0|AnyCPU'">
|
||||
|
@ -40,63 +40,63 @@
|
|||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="DotNext" Version="5.13.0" />
|
||||
<PackageReference Include="DotNext.IO" Version="5.13.0" />
|
||||
<PackageReference Include="DotNext.Metaprogramming" Version="5.13.0" />
|
||||
<PackageReference Include="DotNext.Threading" Version="5.13.0" />
|
||||
<PackageReference Include="DotNext.Unsafe" Version="5.13.0" />
|
||||
<PackageReference Include="IDisposableAnalyzers" Version="4.0.7">
|
||||
<PackageReference Include="DotNext" Version="5.17.2" />
|
||||
<PackageReference Include="DotNext.IO" Version="5.17.2" />
|
||||
<PackageReference Include="DotNext.Metaprogramming" Version="5.17.2" />
|
||||
<PackageReference Include="DotNext.Threading" Version="5.17.2" />
|
||||
<PackageReference Include="DotNext.Unsafe" Version="5.17.2" />
|
||||
<PackageReference Include="IDisposableAnalyzers" Version="4.0.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2024.2.0" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0" />
|
||||
<PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.3.1" />
|
||||
<PackageReference Include="MassTransit" Version="8.2.5" />
|
||||
<PackageReference Include="MassTransit.Analyzers" Version="8.2.5">
|
||||
<PackageReference Include="MassTransit" Version="8.3.4" />
|
||||
<PackageReference Include="MassTransit.Analyzers" Version="8.3.4">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Meziantou.Analyzer" Version="2.0.163">
|
||||
<PackageReference Include="Meziantou.Analyzer" Version="2.0.186">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="9.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Analyzers" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.8">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Analyzers" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.11.20">
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.12.19">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="NetCoreServer" Version="8.0.7" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />
|
||||
<PackageReference Include="Npgsql.OpenTelemetry" Version="8.0.4" />
|
||||
<PackageReference Include="Nullable.Extended.Analyzer" Version="1.15.6169">
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.2" />
|
||||
<PackageReference Include="Npgsql.OpenTelemetry" Version="9.0.2" />
|
||||
<PackageReference Include="Nullable.Extended.Analyzer" Version="1.15.6495">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="OpenTelemetry" Version="1.9.0" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.9.0" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
|
||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.9.0" />
|
||||
<PackageReference Include="OpenTelemetry" Version="1.11.0" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.11.0" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.11.0" />
|
||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.11.0" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.EntityFrameworkCore" Version="1.0.0-beta.12" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Process" Version="1.0.0-alpha.6" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.9.0" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" Version="1.10.0" />
|
||||
<PackageReference Include="OpenTelemetry.PersistentStorage.FileSystem" Version="1.0.0" />
|
||||
<PackageReference Include="OpenTelemetry.ResourceDetectors.Container" Version="1.0.0-beta.7" />
|
||||
<PackageReference Include="RaiNote.PacketMediator" Version="0.0.7" />
|
||||
|
|
|
@ -8,10 +8,8 @@ namespace Continuity.AuthServer.DB.Documents;
|
|||
|
||||
[Index(nameof(Username), IsUnique = true)]
|
||||
[Index(nameof(Id), IsUnique = true)]
|
||||
public class Account
|
||||
{
|
||||
public Account(string username, byte[] password, string email, byte permissionLevel, byte[] salt)
|
||||
{
|
||||
public class Account {
|
||||
public Account(string username, byte[] password, string email, byte permissionLevel, byte[] salt) {
|
||||
Username = username;
|
||||
Password = password;
|
||||
Email = email;
|
||||
|
|
|
@ -10,8 +10,7 @@ namespace Continuity.AuthServer.DB.Documents;
|
|||
|
||||
[Index(nameof(Name), IsUnique = true)]
|
||||
[Index(nameof(Id), IsUnique = true)]
|
||||
public class Character
|
||||
{
|
||||
public class Character {
|
||||
[DeleteBehavior(DeleteBehavior.Cascade)]
|
||||
[Required]
|
||||
public virtual Account Account { get; set; }
|
||||
|
|
|
@ -8,8 +8,7 @@ namespace Continuity.AuthServer.DB.Documents;
|
|||
|
||||
[Index(nameof(Name), IsUnique = true)]
|
||||
[Index(nameof(Id), IsUnique = true)]
|
||||
public class Guild
|
||||
{
|
||||
public class Guild {
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid Id { get; set; }
|
||||
|
|
|
@ -7,8 +7,7 @@ using Microsoft.EntityFrameworkCore;
|
|||
namespace Continuity.AuthServer.DB.Documents;
|
||||
|
||||
[Index(nameof(Id), IsUnique = true)]
|
||||
public class GuildMember
|
||||
{
|
||||
public class GuildMember {
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid Id { get; set; }
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
namespace Continuity.AuthServer.DB.Documents;
|
||||
|
||||
public enum GuildRank : byte
|
||||
{
|
||||
public enum GuildRank : byte {
|
||||
Initiate = 0,
|
||||
Member = 1,
|
||||
Veteran = 2,
|
||||
|
|
|
@ -6,8 +6,7 @@ using Microsoft.EntityFrameworkCore;
|
|||
|
||||
namespace Continuity.AuthServer.DB.Documents;
|
||||
|
||||
public class InventoryItem
|
||||
{
|
||||
public class InventoryItem {
|
||||
[DeleteBehavior(DeleteBehavior.Restrict)]
|
||||
[Required]
|
||||
public virtual Character Character { get; set; }
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
namespace Continuity.AuthServer.DB.Documents;
|
||||
|
||||
public enum InventoryTab : byte
|
||||
{
|
||||
public enum InventoryTab : byte {
|
||||
WornEquipment = 0,
|
||||
WornCashEquipment = 1,
|
||||
Equipment = 2,
|
||||
|
|
|
@ -6,13 +6,11 @@ namespace Server.DB.Migrations;
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
/// <inheritdoc />
|
||||
public partial class Initial : Migration
|
||||
{
|
||||
public partial class Initial : Migration {
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder) => migrationBuilder.CreateTable(
|
||||
name: "Accounts",
|
||||
columns: table => new
|
||||
{
|
||||
columns: table => new {
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Username = table.Column<string>(type: "varchar(20)", nullable: false),
|
||||
Password = table.Column<byte[]>(type: "bytea", nullable: false),
|
||||
|
|
|
@ -6,11 +6,9 @@ namespace Server.DB.Migrations;
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
/// <inheritdoc />
|
||||
public partial class CharacterDataDraft : Migration
|
||||
{
|
||||
public partial class CharacterDataDraft : Migration {
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Username",
|
||||
table: "Accounts",
|
||||
|
@ -45,8 +43,7 @@ public partial class CharacterDataDraft : Migration
|
|||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Characters",
|
||||
columns: table => new
|
||||
{
|
||||
columns: table => new {
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
ServerId = table.Column<byte>(type: "smallint", nullable: false),
|
||||
AccountId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
|
@ -59,8 +56,7 @@ public partial class CharacterDataDraft : Migration
|
|||
Experience = table.Column<long>(type: "bigint", nullable: false),
|
||||
Level = table.Column<byte>(type: "smallint", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
constraints: table => {
|
||||
table.PrimaryKey("PK_Characters", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Characters_Accounts_AccountId",
|
||||
|
@ -77,8 +73,7 @@ public partial class CharacterDataDraft : Migration
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.DropTable(
|
||||
name: "Characters");
|
||||
|
||||
|
|
|
@ -7,15 +7,12 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
|||
namespace Server.DB.Migrations;
|
||||
|
||||
/// <inheritdoc />
|
||||
public partial class AddInventoryToCharacter : Migration
|
||||
{
|
||||
public partial class AddInventoryToCharacter : Migration {
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.CreateTable(
|
||||
name: "InventoryItem",
|
||||
columns: table => new
|
||||
{
|
||||
columns: table => new {
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
CharacterId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
ItemId = table.Column<short>(type: "smallint", nullable: false),
|
||||
|
@ -31,8 +28,7 @@ public partial class AddInventoryToCharacter : Migration
|
|||
Option2 = table.Column<short>(type: "smallint", nullable: false),
|
||||
Option3 = table.Column<short>(type: "smallint", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
constraints: table => {
|
||||
table.PrimaryKey("PK_InventoryItem", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_InventoryItem_Characters_CharacterId",
|
||||
|
@ -49,8 +45,7 @@ public partial class AddInventoryToCharacter : Migration
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.DropTable(
|
||||
name: "InventoryItem");
|
||||
}
|
||||
|
|
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
|||
namespace Server.DB.Migrations;
|
||||
|
||||
/// <inheritdoc />
|
||||
public partial class AdditionalCharacterData : Migration
|
||||
{
|
||||
public partial class AdditionalCharacterData : Migration {
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "ItemId",
|
||||
table: "InventoryItem",
|
||||
|
@ -96,8 +94,7 @@ public partial class AdditionalCharacterData : Migration
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.DropColumn(
|
||||
name: "BaseStats_Dexterity",
|
||||
table: "Characters");
|
||||
|
|
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
|||
namespace Server.DB.Migrations;
|
||||
|
||||
/// <inheritdoc />
|
||||
public partial class AddGuildData : Migration
|
||||
{
|
||||
public partial class AddGuildData : Migration {
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "GuildId",
|
||||
table: "Characters",
|
||||
|
@ -21,28 +19,24 @@ public partial class AddGuildData : Migration
|
|||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Guild",
|
||||
columns: table => new
|
||||
{
|
||||
columns: table => new {
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Name = table.Column<string>(type: "text", nullable: true),
|
||||
Notice = table.Column<string>(type: "text", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
constraints: table => {
|
||||
table.PrimaryKey("PK_Guild", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "GuildMember",
|
||||
columns: table => new
|
||||
{
|
||||
columns: table => new {
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
CharacterId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
GuildId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Rank = table.Column<byte>(type: "smallint", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
constraints: table => {
|
||||
table.PrimaryKey("PK_GuildMember", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_GuildMember_Characters_CharacterId",
|
||||
|
@ -95,8 +89,7 @@ public partial class AddGuildData : Migration
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Characters_Guild_GuildId",
|
||||
table: "Characters");
|
||||
|
|
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
|||
namespace Server.DB.Migrations;
|
||||
|
||||
/// <inheritdoc />
|
||||
public partial class GuildIsNotRequired : Migration
|
||||
{
|
||||
public partial class GuildIsNotRequired : Migration {
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "ItemType",
|
||||
table: "InventoryItem",
|
||||
|
@ -19,8 +17,7 @@ public partial class GuildIsNotRequired : Migration
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.RenameColumn(
|
||||
name: "InventoryTab",
|
||||
table: "InventoryItem",
|
||||
|
|
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
|||
namespace Server.DB.Migrations;
|
||||
|
||||
/// <inheritdoc />
|
||||
public partial class SwitchToDataAnnotations : Migration
|
||||
{
|
||||
public partial class SwitchToDataAnnotations : Migration {
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Characters_Accounts_AccountId",
|
||||
table: "Characters");
|
||||
|
@ -113,8 +111,7 @@ public partial class SwitchToDataAnnotations : Migration
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Characters_Accounts_AccountId",
|
||||
table: "Characters");
|
||||
|
|
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
|||
namespace Server.DB.Migrations;
|
||||
|
||||
/// <inheritdoc />
|
||||
public partial class DBPoolingAndLazyLoadingSupport : Migration
|
||||
{
|
||||
public partial class DBPoolingAndLazyLoadingSupport : Migration {
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Name",
|
||||
table: "Characters",
|
||||
|
@ -36,8 +34,7 @@ public partial class DBPoolingAndLazyLoadingSupport : Migration
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Characters_Id",
|
||||
table: "Characters");
|
||||
|
|
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
|||
namespace Server.DB.Migrations;
|
||||
|
||||
/// <inheritdoc />
|
||||
public partial class FixInventoryItemAsDbset : Migration
|
||||
{
|
||||
public partial class FixInventoryItemAsDbset : Migration {
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Characters_Guild_GuildId",
|
||||
table: "Characters");
|
||||
|
@ -86,8 +84,7 @@ public partial class FixInventoryItemAsDbset : Migration
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Characters_Guilds_GuildId",
|
||||
table: "Characters");
|
||||
|
|
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
|||
namespace Server.DB.Migrations;
|
||||
|
||||
/// <inheritdoc />
|
||||
public partial class MissingCascadeDeletionOnCharacter : Migration
|
||||
{
|
||||
public partial class MissingCascadeDeletionOnCharacter : Migration {
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_InventoryItems_Characters_CharacterId",
|
||||
table: "InventoryItems");
|
||||
|
@ -26,8 +24,7 @@ public partial class MissingCascadeDeletionOnCharacter : Migration
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_InventoryItems_Characters_CharacterId",
|
||||
table: "InventoryItems");
|
||||
|
|
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
|||
namespace Server.DB.Migrations;
|
||||
|
||||
/// <inheritdoc />
|
||||
public partial class IndexingAndVariousOtherAnnotations : Migration
|
||||
{
|
||||
public partial class IndexingAndVariousOtherAnnotations : Migration {
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Characters_Accounts_AccountId",
|
||||
table: "Characters");
|
||||
|
@ -112,8 +110,7 @@ public partial class IndexingAndVariousOtherAnnotations : Migration
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Characters_Accounts_AccountId",
|
||||
table: "Characters");
|
||||
|
|
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
|||
namespace Server.DB.Migrations;
|
||||
|
||||
/// <inheritdoc />
|
||||
public partial class VariousDeletionBehaviours : Migration
|
||||
{
|
||||
public partial class VariousDeletionBehaviours : Migration {
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Characters_Accounts_AccountId",
|
||||
table: "Characters");
|
||||
|
@ -45,8 +43,7 @@ public partial class VariousDeletionBehaviours : Migration
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Accounts_GuildMember_GuildMemberId",
|
||||
table: "Accounts");
|
||||
|
|
|
@ -7,11 +7,9 @@ using Microsoft.EntityFrameworkCore.Migrations;
|
|||
namespace Server.DB.Migrations;
|
||||
|
||||
/// <inheritdoc />
|
||||
public partial class FixEntityRelationships : Migration
|
||||
{
|
||||
public partial class FixEntityRelationships : Migration {
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Accounts_GuildMember_GuildMemberId",
|
||||
table: "Accounts");
|
||||
|
@ -88,8 +86,7 @@ public partial class FixEntityRelationships : Migration
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
protected override void Down(MigrationBuilder migrationBuilder) {
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_GuildMember_CharacterId",
|
||||
table: "GuildMember");
|
||||
|
|
|
@ -6,14 +6,21 @@ using Microsoft.EntityFrameworkCore;
|
|||
|
||||
namespace Continuity.AuthServer.DB;
|
||||
|
||||
public class WonderkingContext : DbContext
|
||||
{
|
||||
public WonderkingContext([NotNull] DbContextOptions options) : base(options)
|
||||
{
|
||||
public class WonderkingContext : DbContext {
|
||||
public WonderkingContext([NotNull] DbContextOptions options) : base(options) {
|
||||
}
|
||||
|
||||
public DbSet<Account> Accounts { get; set; }
|
||||
public DbSet<Character> Characters { get; set; }
|
||||
public DbSet<InventoryItem> InventoryItems { get; set; }
|
||||
public DbSet<Guild> Guilds { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder) {
|
||||
base.OnModelCreating(modelBuilder);
|
||||
modelBuilder.Entity<Account>(entity => {
|
||||
entity.HasIndex(e => e.Username).IsUnique();
|
||||
entity.HasIndex(e => e.Id).IsUnique();
|
||||
entity.Property(e => e.Id).HasColumnType("uuid");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,8 +5,7 @@ using Microsoft.Extensions.Logging;
|
|||
|
||||
namespace Continuity.AuthServer.LoggerMessages;
|
||||
|
||||
internal static partial class LoginHandlerLoggerMessages
|
||||
{
|
||||
internal static partial class LoginHandlerLoggerMessages {
|
||||
[LoggerMessage(EventId = 0, Level = LogLevel.Information,
|
||||
Message = "Login data: Username {Username} & Password {Password}")]
|
||||
public static partial void LoginData(this ILogger<LoginHandler> logger, string username, string password);
|
||||
|
|
|
@ -6,8 +6,7 @@ using Wonderking.Packets;
|
|||
|
||||
namespace Continuity.AuthServer.LoggerMessages;
|
||||
|
||||
internal static partial class PacketLoggerMessages
|
||||
{
|
||||
internal static partial class PacketLoggerMessages {
|
||||
[LoggerMessage(EventId = 0, Level = LogLevel.Information,
|
||||
Message = "Packet creation function created for {PacketID}")]
|
||||
public static partial void PacketCreationFunctionCreated(this ILogger logger, OperationCode packetId);
|
||||
|
|
|
@ -6,8 +6,7 @@ using Wonderking.Packets.Outgoing.Data;
|
|||
|
||||
namespace Continuity.AuthServer.PacketHandlers;
|
||||
|
||||
public partial class ChannelSelectionHandler
|
||||
{
|
||||
public partial class ChannelSelectionHandler {
|
||||
private sealed record InventoryItemProjection(ushort ItemId, byte Slot, InventoryTab InventoryTab);
|
||||
|
||||
private sealed record CharacterDataProjection(
|
||||
|
|
|
@ -11,18 +11,15 @@ using Wonderking.Packets.Outgoing.Data;
|
|||
|
||||
namespace Continuity.AuthServer.PacketHandlers;
|
||||
|
||||
public partial class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPacket, AuthSession>
|
||||
{
|
||||
public partial class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPacket, AuthSession> {
|
||||
private readonly WonderkingContext _wonderkingContext;
|
||||
|
||||
public ChannelSelectionHandler(WonderkingContext wonderkingContext)
|
||||
{
|
||||
public ChannelSelectionHandler(WonderkingContext wonderkingContext) {
|
||||
_wonderkingContext = wonderkingContext;
|
||||
}
|
||||
|
||||
public async Task HandleAsync(ChannelSelectionPacket packet, AuthSession session,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
CancellationToken cancellationToken) {
|
||||
ChannelSelectionResponsePacket responsePacket;
|
||||
var guildNameResponsePacket = new CharacterSelectionSetGuildNamePacket { GuildNames = Array.Empty<string>() };
|
||||
|
||||
|
@ -34,15 +31,12 @@ public partial class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPa
|
|||
.Where(c => c.Account.Id == session.AccountId).Take(3)
|
||||
.CountAsync(cancellationToken);
|
||||
|
||||
if (!accountExists)
|
||||
{
|
||||
if (!accountExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (amountOfCharacter > 0)
|
||||
{
|
||||
responsePacket = new ChannelSelectionResponsePacket
|
||||
{
|
||||
if (amountOfCharacter > 0) {
|
||||
responsePacket = new ChannelSelectionResponsePacket {
|
||||
ChannelIsFullFlag = 0,
|
||||
Endpoint = "127.0.0.1",
|
||||
Port = 2000,
|
||||
|
@ -55,10 +49,8 @@ public partial class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPa
|
|||
.Where(c => c.Account.Id == session.AccountId && c.GuildMember.Guild != null)
|
||||
.Select(c => c.GuildMember.Guild.Name).Take(3).ToArrayAsync(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
responsePacket = new ChannelSelectionResponsePacket
|
||||
{
|
||||
else {
|
||||
responsePacket = new ChannelSelectionResponsePacket {
|
||||
ChannelIsFullFlag = 0,
|
||||
Endpoint = "127.0.0.1",
|
||||
Port = 2000,
|
||||
|
@ -68,21 +60,17 @@ public partial class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPa
|
|||
|
||||
await session.SendAsync(responsePacket);
|
||||
if (guildNameResponsePacket.GuildNames.Length > 0 &&
|
||||
guildNameResponsePacket.GuildNames.Select(n => n != string.Empty).Any())
|
||||
{
|
||||
guildNameResponsePacket.GuildNames.Select(n => n != string.Empty).Any()) {
|
||||
await session.SendAsync(guildNameResponsePacket);
|
||||
}
|
||||
}
|
||||
|
||||
private static ushort[] GetItemIDsByInventoryTab(IEnumerable<InventoryItemProjection> items)
|
||||
{
|
||||
private static ushort[] GetItemIDsByInventoryTab(IEnumerable<InventoryItemProjection> items) {
|
||||
var ids = new ushort[20];
|
||||
ids.AsSpan().Clear();
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item.Slot > 20)
|
||||
{
|
||||
foreach (var item in items) {
|
||||
if (item.Slot > 20) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -92,8 +80,7 @@ public partial class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPa
|
|||
return ids;
|
||||
}
|
||||
|
||||
private async IAsyncEnumerable<CharacterData> GetCharacterDataAsync(Guid accountId)
|
||||
{
|
||||
private async IAsyncEnumerable<CharacterData> GetCharacterDataAsync(Guid accountId) {
|
||||
var characterDataProjections = _wonderkingContext.Characters.AsNoTracking().AsSplitQuery()
|
||||
.Include(c => c.InventoryItems).Include(c => c.Account)
|
||||
.Where(c => c.Account.Id == accountId)
|
||||
|
@ -110,10 +97,8 @@ public partial class ChannelSelectionHandler : IPacketHandler<ChannelSelectionPa
|
|||
new InventoryItemProjection(i.ItemId, i.Slot, i.InventoryTab))
|
||||
)).Take(3);
|
||||
|
||||
await foreach (var c in characterDataProjections)
|
||||
{
|
||||
yield return new CharacterData
|
||||
{
|
||||
await foreach (var c in characterDataProjections) {
|
||||
yield return new CharacterData {
|
||||
Name = c.Name,
|
||||
Job = c.JobData,
|
||||
Gender = c.Gender,
|
||||
|
|
|
@ -13,28 +13,24 @@ using Wonderking.Packets.Outgoing.Data;
|
|||
|
||||
namespace Continuity.AuthServer.PacketHandlers;
|
||||
|
||||
public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket, AuthSession>
|
||||
{
|
||||
public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket, AuthSession> {
|
||||
private readonly CharacterStatsMappingConfiguration _characterStatsMapping;
|
||||
private readonly ItemObjectPoolService _itemObjectPoolService;
|
||||
private readonly WonderkingContext _wonderkingContext;
|
||||
|
||||
public CharacterCreationHandler(WonderkingContext wonderkingContext, ItemObjectPoolService itemObjectPoolService,
|
||||
CharacterStatsMappingConfiguration characterStatsMappingConfiguration)
|
||||
{
|
||||
CharacterStatsMappingConfiguration characterStatsMappingConfiguration) {
|
||||
_wonderkingContext = wonderkingContext;
|
||||
_itemObjectPoolService = itemObjectPoolService;
|
||||
_characterStatsMapping = characterStatsMappingConfiguration;
|
||||
}
|
||||
|
||||
public async Task HandleAsync(CharacterCreationPacket packet, AuthSession session,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
CancellationToken cancellationToken) {
|
||||
var account =
|
||||
await _wonderkingContext.Accounts.Include(a => a.Characters).FirstOrDefaultAsync(a => a.Id == session.AccountId, cancellationToken);
|
||||
|
||||
if (account is null)
|
||||
{
|
||||
if (account is null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -46,8 +42,7 @@ public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket,
|
|||
await _wonderkingContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
var character =
|
||||
new CharacterData
|
||||
{
|
||||
new CharacterData {
|
||||
Name = toBeAddedCharacter.Name,
|
||||
Job = toBeAddedCharacter.JobData,
|
||||
Gender = toBeAddedCharacter.Gender,
|
||||
|
@ -65,16 +60,14 @@ public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket,
|
|||
.Select(item => new Tuple<ushort, byte>(item.ItemId, item.Slot)).AsEnumerable())
|
||||
};
|
||||
|
||||
await session.SendAsync(new CharacterCreationResponsePacket
|
||||
{
|
||||
await session.SendAsync(new CharacterCreationResponsePacket {
|
||||
Character = character,
|
||||
Slot = packet.Slot,
|
||||
isDuplicate = false
|
||||
});
|
||||
}
|
||||
|
||||
private InventoryItem[] CreateDefaultItems(CharacterCreationPacket packet, JobSpecificMapping firstJobConfig)
|
||||
{
|
||||
private InventoryItem[] CreateDefaultItems(CharacterCreationPacket packet, JobSpecificMapping firstJobConfig) {
|
||||
var mappedDefaultItems = _characterStatsMapping.DefaultCharacterMapping.Items
|
||||
.Select(i => _itemObjectPoolService.GetBaseInventoryItem(i.Id, i.Quantity)).ToArray();
|
||||
|
||||
|
@ -91,10 +84,8 @@ public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket,
|
|||
}
|
||||
|
||||
private static Character CreateDefaultCharacter(CharacterCreationPacket packet, Account account,
|
||||
InventoryItem[] items, JobSpecificMapping firstJobConfig)
|
||||
{
|
||||
return new Character
|
||||
{
|
||||
InventoryItem[] items, JobSpecificMapping firstJobConfig) {
|
||||
return new Character {
|
||||
Account = account,
|
||||
MapId = 300,
|
||||
Name = packet.Name,
|
||||
|
@ -112,10 +103,8 @@ public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket,
|
|||
};
|
||||
}
|
||||
|
||||
private JobSpecificMapping SelectFirstJobConfig(byte firstJob)
|
||||
{
|
||||
return firstJob switch
|
||||
{
|
||||
private JobSpecificMapping SelectFirstJobConfig(byte firstJob) {
|
||||
return firstJob switch {
|
||||
1 => _characterStatsMapping.Swordsman,
|
||||
2 => _characterStatsMapping.Mage,
|
||||
3 => _characterStatsMapping.Thief,
|
||||
|
@ -124,8 +113,7 @@ public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket,
|
|||
};
|
||||
}
|
||||
|
||||
private InventoryItem[] CreateChosenItems(CharacterCreationPacket packet)
|
||||
{
|
||||
private InventoryItem[] CreateChosenItems(CharacterCreationPacket packet) {
|
||||
return new[]
|
||||
{
|
||||
_itemObjectPoolService.GetBaseInventoryItem((ushort)((packet.FirstJob - 1) * 6 +
|
||||
|
@ -141,27 +129,22 @@ public class CharacterCreationHandler : IPacketHandler<CharacterCreationPacket,
|
|||
};
|
||||
}
|
||||
|
||||
private static int CalculateCurrentHealth(ushort level, JobSpecificMapping firstJobConfig)
|
||||
{
|
||||
private static int CalculateCurrentHealth(ushort level, JobSpecificMapping firstJobConfig) {
|
||||
return (int)((level - 1) * firstJobConfig.DynamicStats.HealthPerLevel +
|
||||
firstJobConfig.BaseStats.Vitality * firstJobConfig.DynamicStats.HealthPerVitality);
|
||||
}
|
||||
|
||||
private static int CalculateCurrentMana(ushort level, JobSpecificMapping firstJobConfig)
|
||||
{
|
||||
private static int CalculateCurrentMana(ushort level, JobSpecificMapping firstJobConfig) {
|
||||
return (int)((level - 1) * firstJobConfig.DynamicStats.ManaPerLevel +
|
||||
firstJobConfig.BaseStats.Wisdom * firstJobConfig.DynamicStats.ManaPerWisdom);
|
||||
}
|
||||
|
||||
private static ushort[] GetItemIDsByInventoryTab(IEnumerable<Tuple<ushort, byte>> items)
|
||||
{
|
||||
private static ushort[] GetItemIDsByInventoryTab(IEnumerable<Tuple<ushort, byte>> items) {
|
||||
Span<ushort> ids = stackalloc ushort[20];
|
||||
ids.Clear();
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item.Item2 > 20)
|
||||
{
|
||||
foreach (var item in items) {
|
||||
if (item.Item2 > 20) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,24 +8,20 @@ using Wonderking.Packets.Outgoing;
|
|||
|
||||
namespace Continuity.AuthServer.PacketHandlers;
|
||||
|
||||
public class CharacterDeletionHandler : IPacketHandler<CharacterDeletePacket, AuthSession>
|
||||
{
|
||||
public class CharacterDeletionHandler : IPacketHandler<CharacterDeletePacket, AuthSession> {
|
||||
private readonly WonderkingContext _wonderkingContext;
|
||||
|
||||
public CharacterDeletionHandler(WonderkingContext wonderkingContext)
|
||||
{
|
||||
public CharacterDeletionHandler(WonderkingContext wonderkingContext) {
|
||||
_wonderkingContext = wonderkingContext;
|
||||
}
|
||||
|
||||
public async Task HandleAsync(CharacterDeletePacket packet, AuthSession session,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
CancellationToken cancellationToken) {
|
||||
var character = await _wonderkingContext.Characters.FirstOrDefaultAsync(x => x.Name == packet.Name &&
|
||||
x.Account.Id == session.AccountId, cancellationToken);
|
||||
|
||||
var response = new CharacterDeleteResponsePacket { HasToBeZero = 0 };
|
||||
if (character == null)
|
||||
{
|
||||
if (character == null) {
|
||||
await session.SendAsync(response);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -5,8 +5,7 @@ using System.Runtime.InteropServices;
|
|||
namespace Continuity.AuthServer.PacketHandlers;
|
||||
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct CharacterMappingItemEntry
|
||||
{
|
||||
public struct CharacterMappingItemEntry {
|
||||
public required ushort Id { get; set; }
|
||||
public required ushort Quantity { get; set; }
|
||||
}
|
||||
|
|
|
@ -8,18 +8,15 @@ using Wonderking.Packets.Outgoing;
|
|||
|
||||
namespace Continuity.AuthServer.PacketHandlers;
|
||||
|
||||
public class CharacterNameCheckHandler : IPacketHandler<CharacterNameCheckPacket, AuthSession>
|
||||
{
|
||||
public class CharacterNameCheckHandler : IPacketHandler<CharacterNameCheckPacket, AuthSession> {
|
||||
private readonly WonderkingContext _wonderkingContext;
|
||||
|
||||
public CharacterNameCheckHandler(WonderkingContext wonderkingContext)
|
||||
{
|
||||
public CharacterNameCheckHandler(WonderkingContext wonderkingContext) {
|
||||
_wonderkingContext = wonderkingContext;
|
||||
}
|
||||
|
||||
public async Task HandleAsync(CharacterNameCheckPacket packet, AuthSession session,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
CancellationToken cancellationToken) {
|
||||
var isTaken =
|
||||
await _wonderkingContext.Characters.AnyAsync(c => c.Name == packet.Name,
|
||||
cancellationToken);
|
||||
|
|
|
@ -17,44 +17,37 @@ using Wonderking.Packets.Outgoing.Data;
|
|||
|
||||
namespace Continuity.AuthServer.PacketHandlers;
|
||||
|
||||
public class LoginHandler : IPacketHandler<LoginInfoPacket, AuthSession>
|
||||
{
|
||||
public class LoginHandler : IPacketHandler<LoginInfoPacket, AuthSession> {
|
||||
private static readonly ActivitySource _activitySource = new(nameof(Server));
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly ILogger<LoginHandler> _logger;
|
||||
private readonly WonderkingContext _wonderkingContext;
|
||||
|
||||
public LoginHandler(ILogger<LoginHandler> logger, WonderkingContext wonderkingContext, IConfiguration configuration)
|
||||
{
|
||||
public LoginHandler(ILogger<LoginHandler> logger, WonderkingContext wonderkingContext, IConfiguration configuration) {
|
||||
_logger = logger;
|
||||
_wonderkingContext = wonderkingContext;
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
public async Task HandleAsync(LoginInfoPacket packet, AuthSession session, CancellationToken cancellationToken)
|
||||
{
|
||||
public async Task HandleAsync(LoginInfoPacket packet, AuthSession session, CancellationToken cancellationToken) {
|
||||
LoginResponseReason loginResponseReason;
|
||||
_logger.LoginData(packet.Username, packet.Password);
|
||||
var account =
|
||||
await _wonderkingContext.Accounts.FirstOrDefaultAsync(a => a.Username == packet.Username,
|
||||
cancellationToken);
|
||||
|
||||
if (account == null)
|
||||
{
|
||||
if (_configuration.GetSection("Testing").GetValue<bool>("CreateAccountOnLogin"))
|
||||
{
|
||||
if (account == null) {
|
||||
if (_configuration.GetSection("Testing").GetValue<bool>("CreateAccountOnLogin")) {
|
||||
loginResponseReason = await CreateAccountOnLoginAsync(packet.Username, packet.Password);
|
||||
account = await _wonderkingContext.Accounts.FirstOrDefaultAsync(a => a.Username == packet.Username,
|
||||
cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
_logger.RequestedAccountDoesNotExist(packet.Username);
|
||||
loginResponseReason = LoginResponseReason.AccountDoesNotExit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
var salt = account.Salt;
|
||||
var tempPasswordBytes = await GetPasswordHashAsync(packet.Password, salt, account.Id);
|
||||
loginResponseReason = tempPasswordBytes.SequenceEqual(account.Password)
|
||||
|
@ -64,16 +57,14 @@ public class LoginHandler : IPacketHandler<LoginInfoPacket, AuthSession>
|
|||
|
||||
var channelData = new ServerChannelData[1];
|
||||
channelData[0] = new ServerChannelData { ChannelId = 0, LoadPercentage = 0, ServerId = 0 };
|
||||
var loginResponsePacket = new LoginResponsePacket
|
||||
{
|
||||
var loginResponsePacket = new LoginResponsePacket {
|
||||
ResponseReason = loginResponseReason,
|
||||
ChannelData = channelData.ToArray(),
|
||||
UnknownFlag = 1,
|
||||
IsGameMaster = true
|
||||
};
|
||||
|
||||
if (account != null)
|
||||
{
|
||||
if (account != null) {
|
||||
session.AccountId = account.Id;
|
||||
}
|
||||
|
||||
|
@ -81,8 +72,7 @@ public class LoginHandler : IPacketHandler<LoginInfoPacket, AuthSession>
|
|||
_ = session.SendAsync(loginResponsePacket);
|
||||
}
|
||||
|
||||
private static async Task<byte[]> GetPasswordHashAsync(string password, byte[] salt, Guid userId)
|
||||
{
|
||||
private static async Task<byte[]> GetPasswordHashAsync(string password, byte[] salt, Guid userId) {
|
||||
using var activity = _activitySource.StartActivity();
|
||||
// https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Chea1t_Sheet.html#argon2id
|
||||
// "Use Argon2id with a minimum configuration of 19 MiB of memory, an iteration count of 2, and 1 degree of parallelism."
|
||||
|
@ -95,16 +85,13 @@ public class LoginHandler : IPacketHandler<LoginInfoPacket, AuthSession>
|
|||
return await argon2Id.GetBytesAsync(16);
|
||||
}
|
||||
|
||||
private async Task<LoginResponseReason> CreateAccountOnLoginAsync(string username, string password)
|
||||
{
|
||||
private async Task<LoginResponseReason> CreateAccountOnLoginAsync(string username, string password) {
|
||||
using var activity = _activitySource.StartActivity();
|
||||
LoginResponseReason loginResponseReason;
|
||||
var transaction =
|
||||
await _wonderkingContext.Database.BeginTransactionAsync();
|
||||
await using (transaction)
|
||||
{
|
||||
try
|
||||
{
|
||||
await using (transaction) {
|
||||
try {
|
||||
var salt = RandomNumberGenerator.GetBytes(16);
|
||||
var finalAccount = await _wonderkingContext.Accounts.AddAsync(new Account(username,
|
||||
Array.Empty<byte>(), "", 0, salt));
|
||||
|
@ -117,8 +104,7 @@ public class LoginHandler : IPacketHandler<LoginInfoPacket, AuthSession>
|
|||
|
||||
await transaction.CommitAsync();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
catch (Exception) {
|
||||
await transaction.RollbackAsync(); // Rollback the transaction on error
|
||||
throw;
|
||||
}
|
||||
|
|
|
@ -6,11 +6,9 @@ using Wonderking.Packets;
|
|||
namespace Continuity.AuthServer.Packets;
|
||||
|
||||
[MessageUrn("packets")]
|
||||
public class RawPacket
|
||||
{
|
||||
public class RawPacket {
|
||||
public RawPacket(OperationCode operationCode, Span<byte> messageBody, uint aliveTime, byte unknownValue2,
|
||||
byte unknownValue, Guid sessionId, AuthSession session)
|
||||
{
|
||||
byte unknownValue, Guid sessionId, AuthSession session) {
|
||||
MessageBody = messageBody.ToArray();
|
||||
UnknownValue2 = unknownValue2;
|
||||
UnknownValue = unknownValue;
|
||||
|
|
|
@ -35,13 +35,11 @@ builder.Configuration.AddJsonFile("settings.json", true, true)
|
|||
.AddEnvironmentVariables().Build();
|
||||
|
||||
builder.Services.AddLogging();
|
||||
var loggerFactory = LoggerFactory.Create(loggingBuilder =>
|
||||
{
|
||||
var loggerFactory = LoggerFactory.Create(loggingBuilder => {
|
||||
loggingBuilder.AddFile("logs/Continuity.AuthServer-{Date}.log", LogLevel.Trace);
|
||||
loggingBuilder.AddFile("logs/Continuity.AuthServer-{Date}.json.log", LogLevel.Trace, isJson: true);
|
||||
loggingBuilder.AddConsole();
|
||||
loggingBuilder.AddOpenTelemetry(logging =>
|
||||
{
|
||||
loggingBuilder.AddOpenTelemetry(logging => {
|
||||
logging.AddOtlpExporter();
|
||||
logging.IncludeFormattedMessage = true;
|
||||
logging.IncludeScopes = true;
|
||||
|
@ -50,15 +48,12 @@ var loggerFactory = LoggerFactory.Create(loggingBuilder =>
|
|||
|
||||
var configuration = builder.Configuration;
|
||||
builder.Services.AddOpenTelemetry()
|
||||
.WithMetrics(metrics =>
|
||||
{
|
||||
.WithMetrics(metrics => {
|
||||
metrics.AddRuntimeInstrumentation().AddProcessInstrumentation().AddMeter("Microsoft.AspNetCore.Hosting", nameof(Continuity.AuthServer))
|
||||
.ConfigureResource(resourceBuilder => resourceBuilder.AddService("Continuity", serviceNamespace: "Wonderking", serviceVersion: "0.0.1"));
|
||||
})
|
||||
.WithTracing(tracing =>
|
||||
{
|
||||
if (builder.Environment.IsDevelopment())
|
||||
{
|
||||
.WithTracing(tracing => {
|
||||
if (builder.Environment.IsDevelopment()) {
|
||||
tracing.SetSampler<AlwaysOnSampler>();
|
||||
}
|
||||
tracing.AddEntityFrameworkCoreInstrumentation(options => options.SetDbStatementForText = true).AddNpgsql();
|
||||
|
@ -73,8 +68,7 @@ builder.Services.ConfigureOpenTelemetryTracerProvider(tracer => tracer.AddOtlpEx
|
|||
builder.Services.AddHealthChecks()
|
||||
.AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
|
||||
|
||||
builder.Services.AddDbContextPool<WonderkingContext>(o =>
|
||||
{
|
||||
builder.Services.AddDbContextPool<WonderkingContext>(o => {
|
||||
o.UseNpgsql(
|
||||
$"Host={configuration["DB:Host"]};Username={configuration["DB:Username"]};Password={configuration["DB:Password"]};Database={configuration["DB:Database"]};Port={configuration["DB:Port"]}")
|
||||
.EnableSensitiveDataLogging().UseLoggerFactory(loggerFactory);
|
||||
|
@ -104,16 +98,14 @@ builder.Services.AddHostedService(provider =>
|
|||
provider.GetService<PacketDistributorService<OperationCode, AuthSession>>() ??
|
||||
throw new InvalidOperationException());
|
||||
|
||||
builder.Services.AddMassTransit(x =>
|
||||
{
|
||||
builder.Services.AddMassTransit(x => {
|
||||
x.UsingInMemory((context, configurator) => configurator.ConfigureEndpoints(context));
|
||||
x.AddMediator(cfg => cfg.AddConsumers(Assembly.GetExecutingAssembly()));
|
||||
});
|
||||
|
||||
using var host = builder.Build();
|
||||
|
||||
await using (var scope = host.Services.CreateAsyncScope())
|
||||
{
|
||||
await using (var scope = host.Services.CreateAsyncScope()) {
|
||||
var db = scope.ServiceProvider.GetRequiredService<WonderkingContext>();
|
||||
await db.Database.MigrateAsync();
|
||||
}
|
||||
|
|
|
@ -10,14 +10,12 @@ using Wonderking.Game.Reader;
|
|||
|
||||
namespace Continuity.AuthServer.Services;
|
||||
|
||||
public class ItemObjectPoolService : IHostedService
|
||||
{
|
||||
public class ItemObjectPoolService : IHostedService {
|
||||
private readonly ConcurrentDictionary<uint, ItemObject> _itemObjectPool;
|
||||
private readonly ItemReader _itemReader;
|
||||
private readonly ILogger<ItemObjectPoolService> _logger;
|
||||
|
||||
public ItemObjectPoolService(IConfiguration configuration, ILogger<ItemObjectPoolService> logger)
|
||||
{
|
||||
public ItemObjectPoolService(IConfiguration configuration, ILogger<ItemObjectPoolService> logger) {
|
||||
_logger = logger;
|
||||
_itemReader = new ItemReader(configuration.GetSection("Game").GetSection("Data").GetValue<string>("Path") ??
|
||||
string.Empty);
|
||||
|
@ -25,15 +23,12 @@ public class ItemObjectPoolService : IHostedService
|
|||
_itemObjectPool = new ConcurrentDictionary<uint, ItemObject>();
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
public Task StartAsync(CancellationToken cancellationToken) {
|
||||
var amountOfEntries = _itemReader.GetAmountOfEntries();
|
||||
Parallel.For(0, (int)amountOfEntries, i =>
|
||||
{
|
||||
Parallel.For(0, (int)amountOfEntries, i => {
|
||||
var itemObject = _itemReader.GetEntry((uint)i);
|
||||
var result = _itemObjectPool.TryAdd(itemObject.ItemID, itemObject);
|
||||
if (!result)
|
||||
{
|
||||
if (!result) {
|
||||
throw new KeyNotFoundException($"Failed to add item {itemObject.ItemID} to the item object pool");
|
||||
}
|
||||
_logger.LogTrace("Item with id:{ID} and name: '{Name}' has been added", itemObject.ItemID, itemObject.Name);
|
||||
|
@ -45,38 +40,31 @@ public class ItemObjectPoolService : IHostedService
|
|||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
public Task StopAsync(CancellationToken cancellationToken) {
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public ItemObject GetItem(ushort itemId)
|
||||
{
|
||||
public ItemObject GetItem(ushort itemId) {
|
||||
_ = _itemObjectPool.TryGetValue(itemId, out var itemObject);
|
||||
return itemObject;
|
||||
}
|
||||
|
||||
public bool ContainsItem(ushort itemId)
|
||||
{
|
||||
public bool ContainsItem(ushort itemId) {
|
||||
return _itemObjectPool.ContainsKey(itemId);
|
||||
}
|
||||
|
||||
public IQueryable<ItemObject> QueryItems()
|
||||
{
|
||||
public IQueryable<ItemObject> QueryItems() {
|
||||
return _itemObjectPool.AsReadOnly().Values.AsQueryable();
|
||||
}
|
||||
|
||||
public InventoryItem GetBaseInventoryItem(ushort itemId, ushort count = 1, bool isWorn = false)
|
||||
{
|
||||
public InventoryItem GetBaseInventoryItem(ushort itemId, ushort count = 1, bool isWorn = false) {
|
||||
var item = GetItem(itemId);
|
||||
return new InventoryItem
|
||||
{
|
||||
return new InventoryItem {
|
||||
ItemId = itemId,
|
||||
Count = count,
|
||||
Slot = (byte)item.SlotNo1,
|
||||
InventoryTab =
|
||||
item.ItemType switch
|
||||
{
|
||||
item.ItemType switch {
|
||||
1 => InventoryTab.WornCashEquipment,
|
||||
2 => isWorn ? InventoryTab.WornEquipment : InventoryTab.Equipment,
|
||||
3 => InventoryTab.Etc,
|
||||
|
|
|
@ -9,74 +9,62 @@ using NetCoreServer;
|
|||
|
||||
namespace Continuity.AuthServer.Services;
|
||||
|
||||
public class WonderkingAuthServer : TcpServer, IHostedService
|
||||
{
|
||||
public class WonderkingAuthServer : TcpServer, IHostedService {
|
||||
private readonly ILogger<WonderkingAuthServer> _logger;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public WonderkingAuthServer(IPAddress address, int port, ILogger<WonderkingAuthServer> logger,
|
||||
IServiceProvider serviceProvider) : base(address, port)
|
||||
{
|
||||
IServiceProvider serviceProvider) : base(address, port) {
|
||||
_logger = logger;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
public Task StartAsync(CancellationToken cancellationToken) {
|
||||
Start();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
public Task StopAsync(CancellationToken cancellationToken) {
|
||||
DisconnectAll();
|
||||
Stop();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
protected override TcpSession CreateSession()
|
||||
{
|
||||
protected override TcpSession CreateSession() {
|
||||
return ActivatorUtilities.CreateInstance<AuthSession>(_serviceProvider, this);
|
||||
}
|
||||
|
||||
protected override void OnStarting()
|
||||
{
|
||||
protected override void OnStarting() {
|
||||
_logger.LogInformation("Starting");
|
||||
base.OnStarting();
|
||||
}
|
||||
|
||||
protected override void OnStarted()
|
||||
{
|
||||
protected override void OnStarted() {
|
||||
_logger.LogInformation("Started");
|
||||
base.OnStarted();
|
||||
}
|
||||
|
||||
protected override void OnStopping()
|
||||
{
|
||||
protected override void OnStopping() {
|
||||
_logger.LogInformation("Stopping");
|
||||
base.OnStopping();
|
||||
}
|
||||
|
||||
protected override void OnStopped()
|
||||
{
|
||||
protected override void OnStopped() {
|
||||
_logger.LogInformation("Stopped");
|
||||
base.OnStopped();
|
||||
}
|
||||
|
||||
protected override void OnConnected(TcpSession session)
|
||||
{
|
||||
protected override void OnConnected(TcpSession session) {
|
||||
_logger.LogInformation("Client connected {Session}", session.Id);
|
||||
base.OnConnected(session);
|
||||
}
|
||||
|
||||
protected override void OnDisconnected(TcpSession session)
|
||||
{
|
||||
protected override void OnDisconnected(TcpSession session) {
|
||||
_logger.LogInformation("Client disconnected {Session}", session.Id);
|
||||
base.OnDisconnected(session);
|
||||
}
|
||||
|
||||
protected override void OnError(SocketError error)
|
||||
{
|
||||
protected override void OnError(SocketError error) {
|
||||
_logger.LogError("An error has occured {Error}", error);
|
||||
}
|
||||
}
|
||||
|
|
21
Continuity.WorldServer/Continuity.WorldServer.csproj
Normal file
21
Continuity.WorldServer/Continuity.WorldServer.csproj
Normal file
|
@ -0,0 +1,21 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="IDisposableAnalyzers" Version="4.0.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Wonderking\Wonderking.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
21
Continuity.WorldServer/Program.cs
Normal file
21
Continuity.WorldServer/Program.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Licensed to Timothy Schenk under the GNU AGPL Version 3 License.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.Json;
|
||||
|
||||
Span<byte> buffer = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
|
||||
Console.WriteLine(buffer.Length == Marshal.SizeOf<TestStruct>());
|
||||
var tstruct = MemoryMarshal.Cast<byte, TestStruct>(buffer)[0];
|
||||
Console.WriteLine(JsonSerializer.Serialize(tstruct));
|
||||
Console.WriteLine(tstruct.b);
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 20)]
|
||||
public struct TestStruct {
|
||||
[FieldOffset(0)]
|
||||
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I4, SizeConst = 4)]
|
||||
public int[] arr;
|
||||
|
||||
[FieldOffset(16)]
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int b;
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Continuity.AuthServer", "Continuity.AuthServer\Continuity.AuthServer.csproj", "{7EDA8B31-3E03-4CA3-87D1-CFEB05C277D6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Benchmarks", "Benchmarks\Benchmarks.csproj", "{7D560FA1-A61C-4B67-8300-835CA5814621}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wonderking", "Wonderking\Wonderking.csproj", "{6B53A10B-C397-4347-BB00-A12272D0528E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Continuity.WorldServer", "Continuity.WorldServer\Continuity.WorldServer.csproj", "{740E4A11-D2DB-4A36-8811-5D599311220A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{7EDA8B31-3E03-4CA3-87D1-CFEB05C277D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7EDA8B31-3E03-4CA3-87D1-CFEB05C277D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7EDA8B31-3E03-4CA3-87D1-CFEB05C277D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7EDA8B31-3E03-4CA3-87D1-CFEB05C277D6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7D560FA1-A61C-4B67-8300-835CA5814621}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7D560FA1-A61C-4B67-8300-835CA5814621}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7D560FA1-A61C-4B67-8300-835CA5814621}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7D560FA1-A61C-4B67-8300-835CA5814621}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6B53A10B-C397-4347-BB00-A12272D0528E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6B53A10B-C397-4347-BB00-A12272D0528E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6B53A10B-C397-4347-BB00-A12272D0528E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6B53A10B-C397-4347-BB00-A12272D0528E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{740E4A11-D2DB-4A36-8811-5D599311220A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{740E4A11-D2DB-4A36-8811-5D599311220A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{740E4A11-D2DB-4A36-8811-5D599311220A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{740E4A11-D2DB-4A36-8811-5D599311220A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
6
Continuity.slnx
Normal file
6
Continuity.slnx
Normal file
|
@ -0,0 +1,6 @@
|
|||
<Solution>
|
||||
<Project Path="Benchmarks/Benchmarks.csproj" />
|
||||
<Project Path="Continuity.AuthServer/Continuity.AuthServer.csproj" />
|
||||
<Project Path="Continuity.WorldServer/Continuity.WorldServer.csproj" />
|
||||
<Project Path="Wonderking/Wonderking.csproj" />
|
||||
</Solution>
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
namespace Wonderking.Game.Data.Character;
|
||||
|
||||
public enum Gender : byte
|
||||
{
|
||||
public enum Gender : byte {
|
||||
None = 0,
|
||||
Male = 1,
|
||||
Female = 2
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
namespace Wonderking.Game.Data.Character;
|
||||
|
||||
public enum PvPLevel : byte
|
||||
{
|
||||
public enum PvPLevel : byte {
|
||||
None = 0,
|
||||
Dualer = 1,
|
||||
Challenger = 2,
|
||||
|
|
|
@ -5,8 +5,7 @@ using System.Runtime.InteropServices;
|
|||
namespace Wonderking.Game.Data.Item;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct ContainedItem
|
||||
{
|
||||
public struct ContainedItem {
|
||||
public short ID { get; internal set; }
|
||||
public float ObtainChance { get; internal set; }
|
||||
}
|
||||
|
|
|
@ -5,8 +5,7 @@ using System.Runtime.InteropServices;
|
|||
namespace Wonderking.Game.Data.Item;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct CraftMaterial
|
||||
{
|
||||
public struct CraftMaterial {
|
||||
public uint ID;
|
||||
public uint Amount;
|
||||
}
|
||||
|
|
|
@ -5,8 +5,7 @@ using System.Runtime.InteropServices;
|
|||
namespace Wonderking.Game.Data.Item;
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 64)]
|
||||
public struct ElementalStats
|
||||
{
|
||||
public struct ElementalStats {
|
||||
[FieldOffset(0)]
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int MinimumFireDamage;
|
||||
|
|
|
@ -5,8 +5,7 @@ using System.Runtime.InteropServices;
|
|||
namespace Wonderking.Game.Data.Item;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct ItemOptions
|
||||
{
|
||||
public struct ItemOptions {
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.U4)]
|
||||
public uint[] OptionIDs;
|
||||
|
||||
|
|
|
@ -5,8 +5,7 @@ using System.Runtime.InteropServices;
|
|||
namespace Wonderking.Game.Data.Item;
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = 24)]
|
||||
public struct Stats
|
||||
{
|
||||
public struct Stats {
|
||||
[FieldOffset(0)]
|
||||
[MarshalAs(UnmanagedType.I4)]
|
||||
public int Strength;
|
||||
|
|
|
@ -7,8 +7,7 @@ using Wonderking.Utils;
|
|||
namespace Wonderking.Game.Data;
|
||||
|
||||
[GameDataMetadata(932, "baseitemdata.dat", 197)]
|
||||
public struct ItemObject
|
||||
{
|
||||
public struct ItemObject {
|
||||
public uint ItemID { get; set; }
|
||||
public bool Disabled { get; set; }
|
||||
public uint ItemType { get; set; }
|
||||
|
|
|
@ -4,15 +4,13 @@ using System.Reflection;
|
|||
|
||||
namespace Wonderking.Game;
|
||||
|
||||
public abstract class DataReader<T>
|
||||
{
|
||||
public abstract class DataReader<T> {
|
||||
private readonly string _datFileName;
|
||||
|
||||
private readonly byte _xorKey;
|
||||
protected readonly ushort SizeOfEntry;
|
||||
|
||||
protected DataReader(string path)
|
||||
{
|
||||
protected DataReader(string path) {
|
||||
Path = path;
|
||||
_xorKey = GetXorKey();
|
||||
SizeOfEntry = GetSizeOfEntry();
|
||||
|
@ -27,31 +25,26 @@ public abstract class DataReader<T>
|
|||
public abstract uint GetAmountOfEntries();
|
||||
public abstract T GetEntry(uint entryId);
|
||||
|
||||
private static ushort GetSizeOfEntry()
|
||||
{
|
||||
private static ushort GetSizeOfEntry() {
|
||||
return typeof(T).GetCustomAttribute<GameDataMetadataAttribute>()?.DataEntrySize ??
|
||||
throw new NotSupportedException("DataEntrySize is null");
|
||||
}
|
||||
|
||||
private static string GetDatFileName()
|
||||
{
|
||||
private static string GetDatFileName() {
|
||||
return typeof(T).GetCustomAttribute<GameDataMetadataAttribute>()?.DatFileName ??
|
||||
throw new NotSupportedException("DatFileName is null");
|
||||
}
|
||||
|
||||
private static byte GetXorKey()
|
||||
{
|
||||
private static byte GetXorKey() {
|
||||
return typeof(T).GetCustomAttribute<GameDataMetadataAttribute>()?.XorKey ??
|
||||
throw new NotSupportedException("XorKey is null");
|
||||
}
|
||||
|
||||
private ReadOnlySpan<byte> GetDatFileContent(string path)
|
||||
{
|
||||
private ReadOnlySpan<byte> GetDatFileContent(string path) {
|
||||
var fileData = File.ReadAllBytes(path + _datFileName);
|
||||
var data = new byte[fileData.Length];
|
||||
|
||||
for (var i = 0; i < fileData.Length; i++)
|
||||
{
|
||||
for (var i = 0; i < fileData.Length; i++) {
|
||||
data[i] = (byte)(fileData[i] ^ _xorKey);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,8 +5,7 @@ using JetBrains.Annotations;
|
|||
namespace Wonderking.Game;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class)]
|
||||
public class GameDataMetadataAttribute(ushort dataEntrySize, string datFileName, byte xorKey) : Attribute
|
||||
{
|
||||
public class GameDataMetadataAttribute(ushort dataEntrySize, string datFileName, byte xorKey) : Attribute {
|
||||
[UsedImplicitly] public byte XorKey { get; init; } = xorKey;
|
||||
[UsedImplicitly] public ushort DataEntrySize { get; init; } = dataEntrySize;
|
||||
|
||||
|
|
|
@ -4,8 +4,7 @@ using System.Text.Json.Serialization;
|
|||
|
||||
namespace Wonderking.Game.Mapping;
|
||||
|
||||
public class CharacterStatsMappingConfiguration
|
||||
{
|
||||
public class CharacterStatsMappingConfiguration {
|
||||
[JsonPropertyName("default")] public required DefaultCharacterMapping DefaultCharacterMapping { get; set; }
|
||||
[JsonPropertyName("1")] public required JobSpecificMapping Swordsman { get; set; }
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ using System.Text.Json.Serialization;
|
|||
|
||||
namespace Wonderking.Game.Mapping;
|
||||
|
||||
public class DefaultCharacterMapping
|
||||
{
|
||||
public class DefaultCharacterMapping {
|
||||
[JsonPropertyName("items")] public required ICollection<Item> Items { get; set; }
|
||||
}
|
||||
|
|
|
@ -4,8 +4,7 @@ using System.Text.Json.Serialization;
|
|||
|
||||
namespace Wonderking.Game.Mapping;
|
||||
|
||||
public class DynamicStats
|
||||
{
|
||||
public class DynamicStats {
|
||||
[JsonPropertyName("healthPerLevel")] public int HealthPerLevel { get; set; }
|
||||
[JsonPropertyName("manaPerLevel")] public int ManaPerLevel { get; set; }
|
||||
|
||||
|
|
|
@ -4,8 +4,7 @@ using System.Text.Json.Serialization;
|
|||
|
||||
namespace Wonderking.Game.Mapping;
|
||||
|
||||
public class Item
|
||||
{
|
||||
public class Item {
|
||||
[JsonPropertyName("id")] public ushort Id { get; set; }
|
||||
|
||||
[JsonPropertyName("quantity")] public ushort Quantity { get; set; }
|
||||
|
|
|
@ -7,8 +7,7 @@ using Wonderking.Packets.Outgoing.Data;
|
|||
namespace Wonderking.Game.Mapping;
|
||||
|
||||
[UsedImplicitly]
|
||||
public class JobSpecificMapping
|
||||
{
|
||||
public class JobSpecificMapping {
|
||||
[JsonPropertyName("items")] public required ICollection<Item> Items { get; set; }
|
||||
|
||||
[JsonPropertyName("baseStats")] public required BaseStats BaseStats { get; set; }
|
||||
|
|
|
@ -4,8 +4,7 @@ using System.Runtime.InteropServices;
|
|||
|
||||
namespace Wonderking.Game.Reader;
|
||||
|
||||
public static class BinaryReader<T> where T : new()
|
||||
{
|
||||
public static class BinaryReader<T> where T : new() {
|
||||
public static readonly Func<BinaryReader, T> Read;
|
||||
|
||||
#pragma warning disable MA0051, CA1810
|
||||
|
@ -14,64 +13,49 @@ public static class BinaryReader<T> where T : new()
|
|||
{
|
||||
var type = typeof(T);
|
||||
|
||||
if (type == typeof(bool))
|
||||
{
|
||||
if (type == typeof(bool)) {
|
||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, bool>)(p => p.ReadBoolean());
|
||||
}
|
||||
else if (type == typeof(char))
|
||||
{
|
||||
else if (type == typeof(char)) {
|
||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, char>)(p => p.ReadChar());
|
||||
}
|
||||
else if (type == typeof(string))
|
||||
{
|
||||
else if (type == typeof(string)) {
|
||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, string>)(p => p.ReadString());
|
||||
}
|
||||
else if (type == typeof(sbyte))
|
||||
{
|
||||
else if (type == typeof(sbyte)) {
|
||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, sbyte>)(p => p.ReadSByte());
|
||||
}
|
||||
else if (type == typeof(short))
|
||||
{
|
||||
else if (type == typeof(short)) {
|
||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, short>)(p => p.ReadInt16());
|
||||
}
|
||||
else if (type == typeof(int))
|
||||
{
|
||||
else if (type == typeof(int)) {
|
||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, int>)(p => p.ReadInt32());
|
||||
}
|
||||
else if (type == typeof(long))
|
||||
{
|
||||
else if (type == typeof(long)) {
|
||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, long>)(p => p.ReadInt64());
|
||||
}
|
||||
else if (type == typeof(byte))
|
||||
{
|
||||
else if (type == typeof(byte)) {
|
||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, byte>)(p => p.ReadByte());
|
||||
}
|
||||
else if (type == typeof(ushort))
|
||||
{
|
||||
else if (type == typeof(ushort)) {
|
||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, ushort>)(p => p.ReadUInt16());
|
||||
}
|
||||
else if (type == typeof(uint))
|
||||
{
|
||||
else if (type == typeof(uint)) {
|
||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, uint>)(p => p.ReadUInt32());
|
||||
}
|
||||
else if (type == typeof(ulong))
|
||||
{
|
||||
else if (type == typeof(ulong)) {
|
||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, ulong>)(p => p.ReadUInt64());
|
||||
}
|
||||
else if (type == typeof(float))
|
||||
{
|
||||
else if (type == typeof(float)) {
|
||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, float>)(p => p.ReadSingle());
|
||||
}
|
||||
else if (type == typeof(double))
|
||||
{
|
||||
else if (type == typeof(double)) {
|
||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, double>)(p => p.ReadDouble());
|
||||
}
|
||||
else if (type == typeof(decimal))
|
||||
{
|
||||
else if (type == typeof(decimal)) {
|
||||
Read = (Func<BinaryReader, T>)(Delegate)(Func<BinaryReader, decimal>)(p => p.ReadDecimal());
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
Read = (Func<BinaryReader, T>)(p =>
|
||||
(T)(object)p.ReadBytes(Marshal.SizeOf(new T())));
|
||||
}
|
||||
|
|
|
@ -4,27 +4,22 @@ using System.Text;
|
|||
|
||||
namespace Wonderking.Game.Reader;
|
||||
|
||||
public static class GenericReaderExtensions
|
||||
{
|
||||
public static string ReadString(this BinaryReader reader, int length)
|
||||
{
|
||||
public static class GenericReaderExtensions {
|
||||
public static string ReadString(this BinaryReader reader, int length) {
|
||||
var ret = Encoding.ASCII.GetString(reader.ReadBytes(length)).Replace("\0", "", StringComparison.Ordinal);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static T[] ReadArray<T>(this BinaryReader pReader, int pLength) where T : new()
|
||||
{
|
||||
public static T[] ReadArray<T>(this BinaryReader pReader, int pLength) where T : new() {
|
||||
var array = new T[pLength];
|
||||
for (var index = 0; index < pLength; ++index)
|
||||
{
|
||||
for (var index = 0; index < pLength; ++index) {
|
||||
array[index] = pReader.Read<T>();
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
public static T Read<T>(this BinaryReader br) where T : new()
|
||||
{
|
||||
public static T Read<T>(this BinaryReader br) where T : new() {
|
||||
return BinaryReader<T>.Read(br);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,10 +9,8 @@ using Wonderking.Game.Data.Item;
|
|||
|
||||
namespace Wonderking.Game.Reader;
|
||||
|
||||
public class ItemReader(string path) : DataReader<ItemObject>(path)
|
||||
{
|
||||
public override uint GetAmountOfEntries()
|
||||
{
|
||||
public class ItemReader(string path) : DataReader<ItemObject>(path) {
|
||||
public override uint GetAmountOfEntries() {
|
||||
return (uint)((DatFileContent.Length - 9) / SizeOfEntry);
|
||||
}
|
||||
|
||||
|
@ -110,10 +108,8 @@ public class ItemReader(string path) : DataReader<ItemObject>(path)
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static Stats ReadStats(ref Span<byte> data)
|
||||
{
|
||||
return new Stats
|
||||
{
|
||||
private static Stats ReadStats(ref Span<byte> data) {
|
||||
return new Stats {
|
||||
Strength = BitConverter.ToInt32(data.Slice(116, 4)), // 116 -> 120
|
||||
Dexterity = BitConverter.ToInt32(data.Slice(120, 4)), // 120 -> 124
|
||||
Intelligence = BitConverter.ToInt32(data.Slice(124, 4)), // 124 -> 128
|
||||
|
@ -124,8 +120,7 @@ public class ItemReader(string path) : DataReader<ItemObject>(path)
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static uint[] ReadSetItems(ref Span<byte> data)
|
||||
{
|
||||
private static uint[] ReadSetItems(ref Span<byte> data) {
|
||||
return
|
||||
[
|
||||
BitConverter.ToUInt32(data.Slice(796, 4)), // 796 -> 800
|
||||
|
@ -137,10 +132,8 @@ public class ItemReader(string path) : DataReader<ItemObject>(path)
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ItemOptions ReadItemOptions(ref Span<byte> data)
|
||||
{
|
||||
return new ItemOptions
|
||||
{
|
||||
private static ItemOptions ReadItemOptions(ref Span<byte> data) {
|
||||
return new ItemOptions {
|
||||
OptionAvailable = BitConverter.ToBoolean(data.Slice(820, 4)), // 820 -> 824
|
||||
OptionIDs =
|
||||
[
|
||||
|
@ -153,8 +146,7 @@ public class ItemReader(string path) : DataReader<ItemObject>(path)
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ContainedItem[] ReadContainedItems(ref Span<byte> data)
|
||||
{
|
||||
private static ContainedItem[] ReadContainedItems(ref Span<byte> data) {
|
||||
return
|
||||
[
|
||||
new ContainedItem
|
||||
|
@ -186,8 +178,7 @@ public class ItemReader(string path) : DataReader<ItemObject>(path)
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static CraftMaterial[] ReadCraftMaterial(ref Span<byte> data)
|
||||
{
|
||||
private static CraftMaterial[] ReadCraftMaterial(ref Span<byte> data) {
|
||||
return
|
||||
[
|
||||
new CraftMaterial
|
||||
|
@ -214,8 +205,7 @@ public class ItemReader(string path) : DataReader<ItemObject>(path)
|
|||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ElementalStats ReadElementalStats(ref Span<byte> data)
|
||||
{
|
||||
private static ElementalStats ReadElementalStats(ref Span<byte> data) {
|
||||
return MemoryMarshal.Cast<byte, ElementalStats>(data.Slice(140, 64))[0];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,9 @@ using Wonderking.Game.Data.Item;
|
|||
|
||||
namespace Wonderking.Game.Reader;
|
||||
|
||||
public static class ItemReaderExtensions
|
||||
{
|
||||
public static Stats ReadStats(this BinaryReader reader)
|
||||
{
|
||||
return new Stats
|
||||
{
|
||||
public static class ItemReaderExtensions {
|
||||
public static Stats ReadStats(this BinaryReader reader) {
|
||||
return new Stats {
|
||||
Strength = reader.ReadInt32(), //125
|
||||
Dexterity = reader.ReadInt32(), //129
|
||||
Intelligence = reader.ReadInt32(), //133
|
||||
|
@ -19,10 +16,8 @@ public static class ItemReaderExtensions
|
|||
};
|
||||
}
|
||||
|
||||
public static ElementalStats ReadElementalStats(this BinaryReader reader)
|
||||
{
|
||||
return new ElementalStats
|
||||
{
|
||||
public static ElementalStats ReadElementalStats(this BinaryReader reader) {
|
||||
return new ElementalStats {
|
||||
MinimumFireDamage = reader.ReadInt32(), //149
|
||||
MinimumWaterDamage = reader.ReadInt32(), //153
|
||||
MinimumDarkDamage = reader.ReadInt32(), //157
|
||||
|
@ -42,52 +37,44 @@ public static class ItemReaderExtensions
|
|||
};
|
||||
}
|
||||
|
||||
public static ContainedItem[] ReadContainedItems(this BinaryReader reader)
|
||||
{
|
||||
public static ContainedItem[] ReadContainedItems(this BinaryReader reader) {
|
||||
var list = new ContainedItem[5];
|
||||
//893
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
for (var i = 0; i < 5; i++) {
|
||||
list[i].ID = reader.ReadInt16();
|
||||
}
|
||||
|
||||
//903
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
for (var i = 0; i < 5; i++) {
|
||||
list[i].ObtainChance = reader.ReadSingle();
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static CraftMaterial[] ReadCraftMaterial(this BinaryReader reader)
|
||||
{
|
||||
public static CraftMaterial[] ReadCraftMaterial(this BinaryReader reader) {
|
||||
var mats = new CraftMaterial[4];
|
||||
//329
|
||||
for (var i = 0; i < 4; ++i)
|
||||
{
|
||||
for (var i = 0; i < 4; ++i) {
|
||||
mats[i].ID = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
//345
|
||||
for (var i = 0; i < 4; ++i)
|
||||
{
|
||||
for (var i = 0; i < 4; ++i) {
|
||||
mats[i].ID = reader.ReadUInt32();
|
||||
}
|
||||
|
||||
return mats;
|
||||
}
|
||||
|
||||
public static ItemOptions ReadItemOptions(this BinaryReader reader)
|
||||
{
|
||||
public static ItemOptions ReadItemOptions(this BinaryReader reader) {
|
||||
var options = new ItemOptions();
|
||||
|
||||
options.OptionAvailable = reader.ReadInt32() == 1; //819
|
||||
|
||||
var optionIDs = new List<uint>(4);
|
||||
//823
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
for (var i = 0; i < 3; i++) {
|
||||
optionIDs.Add(reader.ReadUInt32());
|
||||
}
|
||||
|
||||
|
|
|
@ -5,13 +5,11 @@ using RaiNote.PacketMediator;
|
|||
namespace Wonderking.Packets.Incoming;
|
||||
|
||||
[WonderkingPacketId(OperationCode.ChannelSelection)]
|
||||
public class ChannelSelectionPacket : IIncomingPacket
|
||||
{
|
||||
public class ChannelSelectionPacket : IIncomingPacket {
|
||||
public required ushort ServerId { get; set; }
|
||||
public required ushort ChannelId { get; set; }
|
||||
|
||||
public void Deserialize(byte[] data)
|
||||
{
|
||||
public void Deserialize(byte[] data) {
|
||||
ServerId = BitConverter.ToUInt16(data, 0);
|
||||
ChannelId = BitConverter.ToUInt16(data, 2);
|
||||
}
|
||||
|
|
|
@ -7,8 +7,7 @@ using Wonderking.Game.Data.Character;
|
|||
namespace Wonderking.Packets.Incoming;
|
||||
|
||||
[WonderkingPacketId(OperationCode.CharacterCreation)]
|
||||
public class CharacterCreationPacket : IIncomingPacket
|
||||
{
|
||||
public class CharacterCreationPacket : IIncomingPacket {
|
||||
public required byte Slot { get; set; }
|
||||
public required byte Unknown { get; set; }
|
||||
public required ushort Id { get; set; }
|
||||
|
@ -21,8 +20,7 @@ public class CharacterCreationPacket : IIncomingPacket
|
|||
public required byte Shirt { get; set; }
|
||||
public required byte Pants { get; set; }
|
||||
|
||||
public void Deserialize(byte[] data)
|
||||
{
|
||||
public void Deserialize(byte[] data) {
|
||||
Slot = data[0];
|
||||
Unknown = data[1];
|
||||
Id = BitConverter.ToUInt16(data, 2);
|
||||
|
|
|
@ -6,14 +6,12 @@ using RaiNote.PacketMediator;
|
|||
namespace Wonderking.Packets.Incoming;
|
||||
|
||||
[WonderkingPacketId(OperationCode.CharacterDeletion)]
|
||||
public class CharacterDeletePacket : IIncomingPacket
|
||||
{
|
||||
public class CharacterDeletePacket : IIncomingPacket {
|
||||
public required byte Slot { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public required uint Unknown { get; set; }
|
||||
|
||||
public void Deserialize(byte[] data)
|
||||
{
|
||||
public void Deserialize(byte[] data) {
|
||||
Span<byte> span = data;
|
||||
Slot = span[0];
|
||||
Name = Encoding.ASCII.GetString(span.Slice(1, 20)).TrimEnd('\0').TrimEnd('\n').TrimEnd('\0');
|
||||
|
|
|
@ -6,12 +6,10 @@ using RaiNote.PacketMediator;
|
|||
namespace Wonderking.Packets.Incoming;
|
||||
|
||||
[WonderkingPacketId(OperationCode.CharacterNameCheck)]
|
||||
public class CharacterNameCheckPacket : IIncomingPacket
|
||||
{
|
||||
public class CharacterNameCheckPacket : IIncomingPacket {
|
||||
public required string Name { get; set; }
|
||||
|
||||
public void Deserialize(byte[] data)
|
||||
{
|
||||
public void Deserialize(byte[] data) {
|
||||
Name = Encoding.ASCII.GetString(data, 0, 20).TrimEnd('\0').TrimEnd('\n').TrimEnd('\0');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,14 +6,12 @@ using RaiNote.PacketMediator;
|
|||
namespace Wonderking.Packets.Incoming;
|
||||
|
||||
[WonderkingPacketId(OperationCode.LoginInfo)]
|
||||
public class LoginInfoPacket : IIncomingPacket
|
||||
{
|
||||
public class LoginInfoPacket : IIncomingPacket {
|
||||
public required string Username { get; set; }
|
||||
|
||||
public required string Password { get; set; }
|
||||
|
||||
public void Deserialize(byte[] data)
|
||||
{
|
||||
public void Deserialize(byte[] data) {
|
||||
Username = Encoding.ASCII.GetString(data, 0, 20).TrimEnd('\0').TrimEnd('\n').TrimEnd('\0');
|
||||
// Remove unnecessary Symbols
|
||||
Password = Encoding.ASCII.GetString(data, 20, 31).TrimEnd('\0').TrimEnd('\n').TrimEnd('\0');
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
namespace Wonderking.Packets;
|
||||
|
||||
public enum OperationCode : ushort
|
||||
{
|
||||
public enum OperationCode : ushort {
|
||||
LoginInfo = 11,
|
||||
LoginResponse = 12,
|
||||
ChannelSelection = 13,
|
||||
|
|
|
@ -8,15 +8,13 @@ using Wonderking.Packets.Outgoing.Data;
|
|||
namespace Wonderking.Packets.Outgoing;
|
||||
|
||||
[WonderkingPacketId(OperationCode.ChannelSelectionResponse)]
|
||||
public class ChannelSelectionResponsePacket : IOutgoingPacket
|
||||
{
|
||||
public class ChannelSelectionResponsePacket : IOutgoingPacket {
|
||||
public required byte ChannelIsFullFlag { get; set; }
|
||||
public required string Endpoint { get; set; }
|
||||
public required ushort Port { get; set; }
|
||||
public required CharacterData[] Characters { get; set; }
|
||||
|
||||
public byte[] Serialize()
|
||||
{
|
||||
public byte[] Serialize() {
|
||||
Span<byte> data = stackalloc byte[1 + 16 + 2 + 1 + 132 * Characters.Length];
|
||||
data.Clear();
|
||||
data[0] = ChannelIsFullFlag;
|
||||
|
@ -25,8 +23,7 @@ public class ChannelSelectionResponsePacket : IOutgoingPacket
|
|||
data[19] = (byte)Characters.Length;
|
||||
|
||||
// Character Data
|
||||
for (var i = 0; i < Characters.Length; i++)
|
||||
{
|
||||
for (var i = 0; i < Characters.Length; i++) {
|
||||
var offset = 20 + i * 132;
|
||||
var character = Characters[i];
|
||||
// Character Data
|
||||
|
@ -54,8 +51,7 @@ public class ChannelSelectionResponsePacket : IOutgoingPacket
|
|||
BinaryPrimitives.WriteInt32LittleEndian(data.Slice(offset + 44, 4), character.Health);
|
||||
BinaryPrimitives.WriteInt32LittleEndian(data.Slice(offset + 48, 4), character.Mana);
|
||||
|
||||
for (var j = 0; j < 20; j++)
|
||||
{
|
||||
for (var j = 0; j < 20; j++) {
|
||||
// Equipped Items
|
||||
BinaryPrimitives.WriteUInt16LittleEndian(data.Slice(offset + 52 + j * 2, 2),
|
||||
character.EquippedItems.Length > j ? character.EquippedItems[j] : (ushort)0);
|
||||
|
|
|
@ -8,14 +8,12 @@ using Wonderking.Packets.Outgoing.Data;
|
|||
namespace Wonderking.Packets.Outgoing;
|
||||
|
||||
[WonderkingPacketId(OperationCode.CharacterCreationResponse)]
|
||||
public class CharacterCreationResponsePacket : IOutgoingPacket
|
||||
{
|
||||
public class CharacterCreationResponsePacket : IOutgoingPacket {
|
||||
public required CharacterData Character { get; set; }
|
||||
public required int Slot { get; set; }
|
||||
public required bool isDuplicate { get; set; }
|
||||
|
||||
public byte[] Serialize()
|
||||
{
|
||||
public byte[] Serialize() {
|
||||
Span<byte> data = stackalloc byte[1 + 132];
|
||||
data[0] = isDuplicate ? (byte)1 : (byte)0;
|
||||
|
||||
|
@ -44,8 +42,7 @@ public class CharacterCreationResponsePacket : IOutgoingPacket
|
|||
BinaryPrimitives.WriteInt32LittleEndian(data.Slice(45, 4), Character.Health);
|
||||
BinaryPrimitives.WriteInt32LittleEndian(data.Slice(49, 4), Character.Mana);
|
||||
|
||||
for (var i = 0; i < 20; i++)
|
||||
{
|
||||
for (var i = 0; i < 20; i++) {
|
||||
// Equipped Items
|
||||
BinaryPrimitives.WriteUInt16LittleEndian(data.Slice(53 + i * 2, 2),
|
||||
Character.EquippedItems.Length > i ? Character.EquippedItems[i] : (ushort)0);
|
||||
|
|
|
@ -5,12 +5,10 @@ using RaiNote.PacketMediator;
|
|||
namespace Wonderking.Packets.Outgoing;
|
||||
|
||||
[WonderkingPacketId(OperationCode.CharacterDeletionResponse)]
|
||||
public class CharacterDeleteResponsePacket : IOutgoingPacket
|
||||
{
|
||||
public class CharacterDeleteResponsePacket : IOutgoingPacket {
|
||||
public required byte HasToBeZero { get; set; }
|
||||
|
||||
public byte[] Serialize()
|
||||
{
|
||||
public byte[] Serialize() {
|
||||
Span<byte> data = stackalloc byte[1];
|
||||
data[0] = HasToBeZero;
|
||||
return data.ToArray();
|
||||
|
|
|
@ -5,12 +5,10 @@ using RaiNote.PacketMediator;
|
|||
namespace Wonderking.Packets.Outgoing;
|
||||
|
||||
[WonderkingPacketId(OperationCode.CharacterNameCheckResponse)]
|
||||
public class CharacterNameCheckPacketResponse : IOutgoingPacket
|
||||
{
|
||||
public class CharacterNameCheckPacketResponse : IOutgoingPacket {
|
||||
public required bool IsTaken { get; set; }
|
||||
|
||||
public byte[] Serialize()
|
||||
{
|
||||
public byte[] Serialize() {
|
||||
Span<byte> data = stackalloc byte[1];
|
||||
data[0] = IsTaken ? (byte)1 : (byte)0;
|
||||
return data.ToArray();
|
||||
|
|
|
@ -6,17 +6,14 @@ using RaiNote.PacketMediator;
|
|||
namespace Wonderking.Packets.Outgoing;
|
||||
|
||||
[WonderkingPacketId(OperationCode.CharacterSelectionSetGuildName)]
|
||||
public class CharacterSelectionSetGuildNamePacket : IOutgoingPacket
|
||||
{
|
||||
public class CharacterSelectionSetGuildNamePacket : IOutgoingPacket {
|
||||
public required string[] GuildNames { get; set; }
|
||||
|
||||
public byte[] Serialize()
|
||||
{
|
||||
public byte[] Serialize() {
|
||||
Span<byte> data = stackalloc byte[1 + (1 + 16 + 1) * GuildNames.Length];
|
||||
data.Clear();
|
||||
data[0] = (byte)GuildNames.Length;
|
||||
for (var i = 0; i < GuildNames.Length; i++)
|
||||
{
|
||||
for (var i = 0; i < GuildNames.Length; i++) {
|
||||
data[1 + i * (1 + 16 + 1)] = (byte)i;
|
||||
Encoding.ASCII.GetBytes(GuildNames[i], data.Slice(2 + i * (1 + 16 + 1), 16));
|
||||
// Null terminator
|
||||
|
|
|
@ -8,8 +8,7 @@ namespace Wonderking.Packets.Outgoing.Data;
|
|||
|
||||
[UsedImplicitly]
|
||||
[Owned]
|
||||
public class BaseStats
|
||||
{
|
||||
public class BaseStats {
|
||||
[JsonPropertyName("strength")] public required short Strength { get; set; }
|
||||
[JsonPropertyName("dexterity")] public required short Dexterity { get; set; }
|
||||
[JsonPropertyName("intelligence")] public required short Intelligence { get; set; }
|
||||
|
|
|
@ -4,8 +4,7 @@ using Wonderking.Game.Data.Character;
|
|||
|
||||
namespace Wonderking.Packets.Outgoing.Data;
|
||||
|
||||
public struct CharacterData
|
||||
{
|
||||
public struct CharacterData {
|
||||
public required string Name { get; set; }
|
||||
public required JobData Job { get; set; }
|
||||
public required Gender Gender { get; set; }
|
||||
|
|
|
@ -7,8 +7,7 @@ namespace Wonderking.Packets.Outgoing.Data;
|
|||
|
||||
[UsedImplicitly]
|
||||
[Owned]
|
||||
public class JobData
|
||||
{
|
||||
public class JobData {
|
||||
public required byte FirstJob { get; set; }
|
||||
public required byte SecondJob { get; set; }
|
||||
public required byte ThirdJob { get; set; }
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
namespace Wonderking.Packets.Outgoing.Data;
|
||||
|
||||
public enum LoginResponseReason : byte
|
||||
{
|
||||
public enum LoginResponseReason : byte {
|
||||
Ok,
|
||||
AccountDoesNotExit,
|
||||
WrongPassword,
|
||||
|
|
|
@ -5,8 +5,7 @@ using System.Runtime.InteropServices;
|
|||
namespace Wonderking.Packets.Outgoing.Data;
|
||||
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct ServerChannelData
|
||||
{
|
||||
public struct ServerChannelData {
|
||||
public ushort ServerId { get; set; }
|
||||
public ushort ChannelId { get; set; }
|
||||
public byte LoadPercentage { get; set; }
|
||||
|
|
|
@ -7,16 +7,14 @@ using Wonderking.Packets.Outgoing.Data;
|
|||
namespace Wonderking.Packets.Outgoing;
|
||||
|
||||
[WonderkingPacketId(OperationCode.LoginResponse)]
|
||||
public class LoginResponsePacket : IOutgoingPacket
|
||||
{
|
||||
public class LoginResponsePacket : IOutgoingPacket {
|
||||
public required LoginResponseReason ResponseReason { get; set; }
|
||||
public required byte UnknownFlag { get; set; } = 1;
|
||||
public required bool IsGameMaster { get; set; }
|
||||
|
||||
public required ServerChannelData[] ChannelData { get; set; }
|
||||
|
||||
public byte[] Serialize()
|
||||
{
|
||||
public byte[] Serialize() {
|
||||
const int sizeOfServerChannelData = 5;
|
||||
Span<byte> dataSpan = stackalloc byte[5 + ChannelData.Length * sizeOfServerChannelData];
|
||||
dataSpan.Clear();
|
||||
|
@ -25,8 +23,7 @@ public class LoginResponsePacket : IOutgoingPacket
|
|||
dataSpan[2] = BitConverter.GetBytes(IsGameMaster)[0];
|
||||
BinaryPrimitives.WriteUInt16LittleEndian(dataSpan.Slice(3, 2), (ushort)ChannelData.Length);
|
||||
|
||||
for (var i = 0; i < ChannelData.Length; i++)
|
||||
{
|
||||
for (var i = 0; i < ChannelData.Length; i++) {
|
||||
var bytesOfServerId = BitConverter.GetBytes(ChannelData[i].ServerId);
|
||||
var bytesOfChannelId = BitConverter.GetBytes(ChannelData[i].ChannelId);
|
||||
dataSpan[5 + 0 + i * sizeOfServerChannelData] = bytesOfServerId[0];
|
||||
|
|
|
@ -5,9 +5,7 @@ using RaiNote.PacketMediator;
|
|||
namespace Wonderking.Packets;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
|
||||
public class WonderkingPacketIdAttribute : PacketIdAttribute<OperationCode>
|
||||
{
|
||||
public WonderkingPacketIdAttribute(OperationCode code) : base(code)
|
||||
{
|
||||
public class WonderkingPacketIdAttribute : PacketIdAttribute<OperationCode> {
|
||||
public WonderkingPacketIdAttribute(OperationCode code) : base(code) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,16 +5,13 @@ using System.Text.Json.Serialization;
|
|||
|
||||
namespace Wonderking.Utils;
|
||||
|
||||
public class ByteArrayConverter : JsonConverter<byte[]>
|
||||
{
|
||||
public class ByteArrayConverter : JsonConverter<byte[]> {
|
||||
public override byte[] Read(
|
||||
ref Utf8JsonReader reader,
|
||||
Type typeToConvert,
|
||||
JsonSerializerOptions options)
|
||||
{
|
||||
JsonSerializerOptions options) {
|
||||
var hexData = reader.GetString();
|
||||
if (hexData != null)
|
||||
{
|
||||
if (hexData != null) {
|
||||
return hexData.Split('-').Select(b => Convert.ToByte(b, 16)).ToArray();
|
||||
}
|
||||
|
||||
|
@ -24,14 +21,11 @@ public class ByteArrayConverter : JsonConverter<byte[]>
|
|||
public override void Write(
|
||||
Utf8JsonWriter writer,
|
||||
byte[]? value,
|
||||
JsonSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
JsonSerializerOptions options) {
|
||||
if (value == null) {
|
||||
writer.WriteNullValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
var hexData = BitConverter.ToString(value).Replace("-", string.Empty);
|
||||
writer.WriteStringValue(hexData);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<Nullable>enable</Nullable>
|
||||
<Features>strict</Features>
|
||||
<LangVersion>12</LangVersion>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -17,21 +17,21 @@
|
|||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2024.2.0" />
|
||||
<PackageReference Include="Meziantou.Analyzer" Version="2.0.163">
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2024.3.0" />
|
||||
<PackageReference Include="Meziantou.Analyzer" Version="2.0.186">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
|
||||
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="9.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.11.20">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="9.0.1" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.12.19">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Nullable.Extended.Analyzer" Version="1.15.6169">
|
||||
<PackageReference Include="Nullable.Extended.Analyzer" Version="1.15.6495">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
|
|
@ -44,6 +44,8 @@ services:
|
|||
- continuity
|
||||
volumes:
|
||||
- db-data:/var/lib/postgresql/data
|
||||
ports:
|
||||
- 5432:5432
|
||||
healthcheck:
|
||||
test: [CMD-SHELL, 'pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}']
|
||||
interval: 10s
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"sdk": {
|
||||
"version": "8.0.203",
|
||||
"version": "9.0.0",
|
||||
"rollForward": "latestMinor",
|
||||
"allowPrerelease": false
|
||||
"allowPrerelease": true
|
||||
}
|
||||
}
|
||||
|
|
29
qodana.yaml
29
qodana.yaml
|
@ -1,29 +0,0 @@
|
|||
#-------------------------------------------------------------------------------#
|
||||
# Qodana analysis is configured by qodana.yaml file #
|
||||
# https://www.jetbrains.com/help/qodana/qodana-yaml.html #
|
||||
#-------------------------------------------------------------------------------#
|
||||
version: "1.0"
|
||||
|
||||
#Specify inspection profile for code analysis
|
||||
profile:
|
||||
name: qodana.starter
|
||||
|
||||
#Enable inspections
|
||||
#include:
|
||||
# - name: <SomeEnabledInspectionId>
|
||||
|
||||
#Disable inspections
|
||||
#exclude:
|
||||
# - name: <SomeDisabledInspectionId>
|
||||
# paths:
|
||||
# - <path/where/not/run/inspection>
|
||||
|
||||
#Execute shell command before Qodana execution (Applied in CI/CD pipeline)
|
||||
#bootstrap: sh ./prepare-qodana.sh
|
||||
|
||||
#Install IDE plugins before Qodana execution (Applied in CI/CD pipeline)
|
||||
#plugins:
|
||||
# - id: <plugin.id> #(plugin id can be found at https://plugins.jetbrains.com)
|
||||
|
||||
#Specify Qodana linter for analysis (Applied in CI/CD pipeline)
|
||||
linter: jetbrains/qodana-dotnet:latest
|
Loading…
Reference in a new issue