feat: Adds a memory mirrored ring buffer for networking. (#1533)

## Breaking Changes

Incoming packet registration signature has changed to:
```cs
delegate* void OnReceiveCallback(NetState state, SpanReader reader, int packetLength);

IncomingPackets.Register(int packetID, int length, bool ingame, OnReceiveCallback onReceive);
```

For example, an incoming packet handler signature would now look like this:
```cs
public static void SomeIncomingPacket(NetState state, SpanReader reader, int packetLength)
{
    // Parse the data
}
```

## Summary

Updates the network Pipe class to use a mirrored memory technique. This technique involves mapping the same physical memory to two contiguous virtual memory spaces so the byte buffer appears duplicated. This allows writing to a double-sized array to wrap around without the need for the `CircularBuffer` classes.

In practice this allows us to use `Span<byte>` as if the buffer was a regular array.


### Bug Fixes

- [X] Fixes bad fixed length string parsing
This commit is contained in:
Kamron Batman 2023-10-09 00:57:53 -07:00 • committed by GitHub
parent 629a5008c3
commit 10a69bf754
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
83 changed files with 958 additions and 2432 deletions

View file

@ -29,7 +29,7 @@ namespace Server.Items
IncomingPackets.Register(0x93, 99, true, &OldHeaderChange);
}
public static void OldHeaderChange(NetState state, CircularBufferReader reader, int packetLength)
public static void OldHeaderChange(NetState state, SpanReader reader, int packetLength)
{
var from = state.Mobile;
@ -48,7 +48,7 @@ namespace Server.Items
book.Author = Utility.FixHtml(author);
}
public static void HeaderChange(NetState state, CircularBufferReader reader, int packetLength)
public static void HeaderChange(NetState state, SpanReader reader, int packetLength)
{
var from = state.Mobile;
@ -84,7 +84,7 @@ namespace Server.Items
book.Author = Utility.FixHtml(author);
}
public static void ContentChange(NetState state, CircularBufferReader reader, int packetLength)
public static void ContentChange(NetState state, SpanReader reader, int packetLength)
{
var from = state.Mobile;

View file

@ -48,7 +48,7 @@ namespace Server.Network
return $"{seconds} second{(seconds == 1 ? "" : "s")}";
}
public static void BBClientRequest(NetState state, CircularBufferReader reader, int packetLength)
public static void BBClientRequest(NetState state, SpanReader reader, int packetLength)
{
var from = state.Mobile;
@ -76,7 +76,7 @@ namespace Server.Network
}
}
public static void BBRequestContent(Mobile from, BaseBulletinBoard board, CircularBufferReader reader)
public static void BBRequestContent(Mobile from, BaseBulletinBoard board, SpanReader reader)
{
if (World.FindItem((Serial)reader.ReadUInt32()) is not BulletinMessage msg || msg.Parent != board)
{
@ -86,7 +86,7 @@ namespace Server.Network
from.NetState.SendBBMessage(board, msg, true);
}
public static void BBRequestHeader(Mobile from, BaseBulletinBoard board, CircularBufferReader reader)
public static void BBRequestHeader(Mobile from, BaseBulletinBoard board, SpanReader reader)
{
if (World.FindItem((Serial)reader.ReadUInt32()) is not BulletinMessage msg || msg.Parent != board)
{
@ -96,7 +96,7 @@ namespace Server.Network
from.NetState.SendBBMessage(board, msg);
}
public static void BBPostMessage(Mobile from, BaseBulletinBoard board, CircularBufferReader reader)
public static void BBPostMessage(Mobile from, BaseBulletinBoard board, SpanReader reader)
{
var thread = World.FindItem((Serial)reader.ReadUInt32()) as BulletinMessage;
@ -151,7 +151,7 @@ namespace Server.Network
board.PostMessage(from, thread, subject, lines);
}
public static void BBRemoveMessage(Mobile from, BaseBulletinBoard board, CircularBufferReader reader)
public static void BBRemoveMessage(Mobile from, BaseBulletinBoard board, SpanReader reader)
{
if (World.FindItem((Serial)reader.ReadUInt32()) is not BulletinMessage msg || msg.Parent != board)
{

View file

@ -20,7 +20,7 @@ using Server.Network;
namespace Server.Engines.Mahjong
{
public delegate void OnMahjongPacketReceive(MahjongGame game, NetState state, CircularBufferReader reader);
public delegate void OnMahjongPacketReceive(MahjongGame game, NetState state, SpanReader reader);
public static class MahjongPackets
{
@ -61,7 +61,7 @@ namespace Server.Engines.Mahjong
RegisterSubCommand(0x18, MoveDealerIndicator);
}
public static void OnPacket(NetState state, CircularBufferReader reader, int packetLength)
public static void OnPacket(NetState state, SpanReader reader, int packetLength)
{
var game = World.FindItem((Serial)reader.ReadUInt32()) as MahjongGame;
@ -79,7 +79,7 @@ namespace Server.Engines.Mahjong
}
else
{
reader.Trace(state);
state.Trace(reader.Buffer);
}
}
@ -105,7 +105,7 @@ namespace Server.Engines.Mahjong
};
}
public static void ExitGame(MahjongGame game, NetState state, CircularBufferReader reader)
public static void ExitGame(MahjongGame game, NetState state, SpanReader reader)
{
if (game == null)
{
@ -117,7 +117,7 @@ namespace Server.Engines.Mahjong
game.Players.LeaveGame(from);
}
public static void GivePoints(MahjongGame game, NetState state, CircularBufferReader reader)
public static void GivePoints(MahjongGame game, NetState state, SpanReader reader)
{
if (game?.Players.IsInGamePlayer(state.Mobile) != true)
{
@ -130,7 +130,7 @@ namespace Server.Engines.Mahjong
game.Players.TransferScore(state.Mobile, to, amount);
}
public static void RollDice(MahjongGame game, NetState state, CircularBufferReader reader)
public static void RollDice(MahjongGame game, NetState state, SpanReader reader)
{
if (game?.Players.IsInGamePlayer(state.Mobile) != true)
{
@ -140,7 +140,7 @@ namespace Server.Engines.Mahjong
game.Dices.RollDices(state.Mobile);
}
public static void BuildWalls(MahjongGame game, NetState state, CircularBufferReader reader)
public static void BuildWalls(MahjongGame game, NetState state, SpanReader reader)
{
if (game?.Players.IsInGameDealer(state.Mobile) != true)
{
@ -150,7 +150,7 @@ namespace Server.Engines.Mahjong
game.ResetWalls(state.Mobile);
}
public static void ResetScores(MahjongGame game, NetState state, CircularBufferReader reader)
public static void ResetScores(MahjongGame game, NetState state, SpanReader reader)
{
if (game?.Players.IsInGameDealer(state.Mobile) != true)
{
@ -160,7 +160,7 @@ namespace Server.Engines.Mahjong
game.Players.ResetScores(MahjongGame.BaseScore);
}
public static void AssignDealer(MahjongGame game, NetState state, CircularBufferReader reader)
public static void AssignDealer(MahjongGame game, NetState state, SpanReader reader)
{
if (game?.Players.IsInGameDealer(state.Mobile) != true)
{
@ -172,7 +172,7 @@ namespace Server.Engines.Mahjong
game.Players.AssignDealer(position);
}
public static void OpenSeat(MahjongGame game, NetState state, CircularBufferReader reader)
public static void OpenSeat(MahjongGame game, NetState state, SpanReader reader)
{
if (game?.Players.IsInGameDealer(state.Mobile) != true)
{
@ -189,7 +189,7 @@ namespace Server.Engines.Mahjong
game.Players.OpenSeat(position);
}
public static void ChangeOption(MahjongGame game, NetState state, CircularBufferReader reader)
public static void ChangeOption(MahjongGame game, NetState state, SpanReader reader)
{
if (game?.Players.IsInGameDealer(state.Mobile) != true)
{
@ -205,7 +205,7 @@ namespace Server.Engines.Mahjong
game.SpectatorVision = (options & 0x2) != 0;
}
public static void MoveWallBreakIndicator(MahjongGame game, NetState state, CircularBufferReader reader)
public static void MoveWallBreakIndicator(MahjongGame game, NetState state, SpanReader reader)
{
if (game?.Players.IsInGameDealer(state.Mobile) != true)
{
@ -218,7 +218,7 @@ namespace Server.Engines.Mahjong
game.WallBreakIndicator.Move(new Point2D(x, y));
}
public static void TogglePublicHand(MahjongGame game, NetState state, CircularBufferReader reader)
public static void TogglePublicHand(MahjongGame game, NetState state, SpanReader reader)
{
if (game?.Players.IsInGamePlayer(state.Mobile) != true)
{
@ -233,7 +233,7 @@ namespace Server.Engines.Mahjong
game.Players.SetPublic(game.Players.GetPlayerIndex(state.Mobile), publicHand);
}
public static void MoveTile(MahjongGame game, NetState state, CircularBufferReader reader)
public static void MoveTile(MahjongGame game, NetState state, SpanReader reader)
{
if (game?.Players.IsInGamePlayer(state.Mobile) != true)
{
@ -268,7 +268,7 @@ namespace Server.Engines.Mahjong
game.Tiles[number].Move(new Point2D(x, y), direction, flip, game.Players.GetPlayerIndex(state.Mobile));
}
public static void MoveDealerIndicator(MahjongGame game, NetState state, CircularBufferReader reader)
public static void MoveDealerIndicator(MahjongGame game, NetState state, SpanReader reader)
{
if (game?.Players.IsInGameDealer(state.Mobile) != true)
{

View file

@ -25,7 +25,7 @@ namespace Server.Network
IncomingPackets.Register(0x56, 11, true, &OnMapCommand);
}
private static void OnMapCommand(NetState state, CircularBufferReader reader, int packetLength)
private static void OnMapCommand(NetState state, SpanReader reader, int packetLength)
{
var from = state.Mobile;