Skip to content

Commit 12f629d

Browse files
authored
Add 474 Protocol (#25)
1 parent ee5b8f3 commit 12f629d

File tree

67 files changed

+2328
-151
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+2328
-151
lines changed

NetScape.Abstractions/Constants.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
using DotNetty.Common.Utilities;
2+
using NetScape.Abstractions.Model;
23
using NetScape.Abstractions.Model.Game;
34

45
namespace NetScape.Abstractions
56
{
67
public class Constants
78
{
8-
public static readonly int RegionSize = 8;
9-
public static readonly int ArchiveCount = 9;
10-
public static readonly AttributeKey<Player> PlayerAttributeKey = AttributeKey<Player>.ValueOf("Player");
9+
public static int RegionSize { get; } = 8;
10+
public static AttributeKey<Player> PlayerAttributeKey { get; } = AttributeKey<Player>.ValueOf("Player");
11+
public static Position HomePosition { get; } = new Position(3333, 3333, 0);
1112
}
1213
}

NetScape.Abstractions/Extensions/ByteBufferExtensions.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,15 @@ namespace NetScape.Abstractions.Extensions
88
public static class ByteBufferExtensions
99
{
1010
public static string ReadString(this IByteBuffer buffer)
11+
{
12+
return ReadString(buffer, 10);
13+
}
14+
15+
public static string ReadString(this IByteBuffer buffer, int terminator)
1116
{
1217
var strBldr = new StringBuilder();
1318
int charByte;
14-
while ((charByte = buffer.ReadByte()) != 10)
19+
while ((charByte = buffer.ReadByte()) != terminator)
1520
{
1621
strBldr.Append((char)charByte);
1722
}

NetScape.Abstractions/Model/Game/Walking/WalkingQueueHandler.cs renamed to NetScape.Abstractions/Game/WalkingQueueHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
using System.Collections.Generic;
55
using System.Linq;
66

7-
namespace NetScape.Abstractions.Model.Game.Walking
7+
namespace NetScape.Abstractions.Model.Game
88
{
99
public class WalkingQueueHandler
1010
{
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
using Autofac;
2+
using NetScape.Abstractions.FileSystem;
3+
using NetScape.Abstractions.Interfaces.Login;
4+
using NetScape.Abstractions.Model.Login;
5+
using Serilog;
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using System.Threading;
10+
using System.Threading.Tasks;
11+
12+
namespace NetScape.Abstractions.Login
13+
{
14+
public abstract class DefaultLoginProcessor<TRequest, TResponse> : ILoginProcessor<TRequest, TResponse>,
15+
IStartable,
16+
IDisposable
17+
where TRequest : LoginRequest<TResponse>
18+
{
19+
protected internal readonly ILogger _logger;
20+
private readonly IList<TRequest> _loginRequests = new List<TRequest>();
21+
22+
private readonly object _lockObject = new object();
23+
24+
private CancellationToken _cancellationToken;
25+
private CancellationTokenSource _cancellationTokenSource;
26+
27+
public DefaultLoginProcessor(ILogger logger)
28+
{
29+
_logger = logger;
30+
}
31+
32+
/// <summary>
33+
/// Enqueues the specified request.
34+
/// </summary>
35+
/// <param name="request">The request.</param>
36+
/// <exception cref="InvalidOperationException">Login already exists</exception>
37+
public void Enqueue(TRequest request)
38+
{
39+
lock (_lockObject)
40+
{
41+
var loginExists = _loginRequests.Any(t => t.Credentials.Username.Equals(request.Credentials.Username, StringComparison.InvariantCultureIgnoreCase)
42+
&& t.Credentials.Password.Equals(request.Credentials.Password, StringComparison.InvariantCultureIgnoreCase));
43+
44+
if (loginExists)
45+
{
46+
throw new InvalidOperationException("Login already exists");
47+
}
48+
49+
_loginRequests.Add(request);
50+
}
51+
}
52+
53+
/// <summary>
54+
/// Processes a single by retriving the player from <see cref="IPlayerSerializer"/>
55+
/// </summary>
56+
/// <param name="request">The login request.</param>
57+
/// <returns></returns>
58+
protected abstract Task<TResponse> ProcessAsync(TRequest request);
59+
60+
/// <summary>
61+
/// Handles the login queue
62+
/// </summary>
63+
private async Task ProcessLoginsAsync()
64+
{
65+
while (!_cancellationToken.IsCancellationRequested)
66+
{
67+
while (_loginRequests.Count > 0)
68+
{
69+
var requests = _loginRequests.ToList();
70+
var tasks = requests.Select(loginTask =>
71+
(request: loginTask, responseTask: ProcessAsync(loginTask)))
72+
.ToList();
73+
await Task.WhenAll(tasks.Select(t => t.responseTask));
74+
tasks.ForEach(t =>
75+
{
76+
var responseTask = t.responseTask;
77+
var request = t.request;
78+
if (responseTask.IsCompletedSuccessfully)
79+
{
80+
_loginRequests.Remove(t.request);
81+
t.request.Result = request.Result;
82+
_ = request.OnResult(responseTask.Result);
83+
_logger.Debug("Processed Login Request: {@LoginRequest}", request.Credentials);
84+
}
85+
});
86+
}
87+
await Task.Delay(600);
88+
}
89+
}
90+
91+
/// <summary>
92+
/// Perform once-off startup processing.
93+
/// </summary>
94+
public void Start()
95+
{
96+
_cancellationTokenSource = new CancellationTokenSource();
97+
_cancellationToken = _cancellationTokenSource.Token;
98+
Task.Factory.StartNew(ProcessLoginsAsync, _cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default);
99+
}
100+
101+
/// <summary>
102+
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
103+
/// </summary>
104+
public void Dispose()
105+
{
106+
_cancellationTokenSource?.Cancel();
107+
_cancellationTokenSource?.Dispose();
108+
}
109+
}
110+
}

NetScape.Abstractions/Model/Game/Player.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using NetScape.Abstractions.Model.World.Updating.Blocks;
66
using NetScape.Modules.Messages;
77
using NetScape.Modules.Messages.Builder;
8+
using Serilog;
89
using System.Collections.Generic;
910
using System.ComponentModel.DataAnnotations.Schema;
1011
using System.Threading;
@@ -17,6 +18,7 @@ public partial class Player : Mob
1718
private static readonly int DefaultViewingDistance = 15;
1819
private static int _appearanceTicketCounter = 0;
1920

21+
[NotMapped] public int PingCount { get; set; }
2022
[NotMapped] public Position LastKnownRegion { get; set; }
2123
[NotMapped] public bool RegionChanged { get; set; }
2224
[NotMapped] public int AppearanceTicket { get; } = NextAppearanceTicket();
@@ -66,6 +68,7 @@ public void ResetViewingDistance()
6668
/// <param name="message">The message.</param>
6769
public async Task SendAsync(IEncoderMessage<MessageFrame> message)
6870
{
71+
Log.Logger.Debug("Sending {0} to player {1}", message, Username);
6972
var msg = message.ToMessage(ChannelHandlerContext.Allocator);
7073

7174
if (ChannelHandlerContext.Channel.Active)
File renamed without changes.

NetScape.Abstractions/Model/Login/LoginRequest.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using DotNetty.Transport.Channels;
22
using NetScape.Abstractions.IO.Util;
3+
using System;
4+
using System.Threading.Tasks;
35

46
namespace NetScape.Abstractions.Model.Login
57
{
@@ -19,5 +21,10 @@ public record LoginRequest<TRes>
1921

2022
public int ReleaseNumber { get; set; }
2123
public TRes Result { get; set; }
24+
25+
/// <summary>
26+
/// Called on response of request <seealso cref="LoginProcessor.ProcessLoginsAsync"/>
27+
/// </summary>
28+
public Func<TRes, Task> OnResult { get; set; }
2229
}
2330
}

NetScape.Abstractions/Model/Position.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,24 @@ public int TopLeftRegionY
207207
}
208208
}
209209

210+
/// <summary>
211+
/// Gets the region x.
212+
/// </summary>
213+
/// <value>
214+
/// The region x.
215+
/// </value>
216+
[NotMapped]
217+
public int RegionX => (X >> 3) - 6;
218+
219+
/// <summary>
220+
/// Gets the region y.
221+
/// </summary>
222+
/// <value>
223+
/// The region y.
224+
/// </value>
225+
[NotMapped]
226+
public int RegionY => (Y >> 3) - 6;
227+
210228
/// <summary>
211229
/// Gets the x coordinate.
212230
/// </summary>

NetScape.Abstractions/NetScape.Abstractions.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="5.0.1" />
1616
<PackageReference Include="Nito.Collections.Deque" Version="1.1.0" />
1717
<PackageReference Include="Portable.BouncyCastle" Version="1.8.9" />
18+
<PackageReference Include="Serilog" Version="2.10.0" />
1819
<PackageReference Include="SevenZip" Version="19.0.0" />
1920
<PackageReference Include="SharpZipLib" Version="1.3.1" />
2021
<PackageReference Include="System.Linq" Version="4.3.0" />

NetScape.Modules.Cache/RuneTek5/Sector.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public static Sector Decode(int position, byte[] data, CacheIndex expectedIndex,
110110
var nextSectorPosition = dataReader.ReadUInt24BigEndian();
111111

112112
var actualIndex = (CacheIndex)dataReader.ReadByte();
113-
if (actualIndex - 1 != expectedIndex)
113+
if (actualIndex != expectedIndex)
114114
{
115115
throw new DecodeException($"Expected sector for index {(int)expectedIndex}, got {(int)actualIndex}.");
116116
}

0 commit comments

Comments
 (0)