Skip to content
This repository was archived by the owner on Jun 17, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Prima.Core.Server/Contexts/UserLoginContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Prima.Core.Server.Contexts;

public record UserLoginContext(string UserId, string Username);
2 changes: 1 addition & 1 deletion src/Prima.Core.Server/Prima.Core.Server.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

<ItemGroup>
<PackageReference Include="LiteDB" Version="5.0.21" />
<PackageReference Include="Orion.Core.Server" Version="0.27.1" />
<PackageReference Include="Orion.Core.Server" Version="0.28.2" />
</ItemGroup>

<ItemGroup>
Expand Down
34 changes: 34 additions & 0 deletions src/Prima.Network/Extensions/IpAddressExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.Buffers.Binary;
using System.Net;

namespace Prima.Network.Extensions;

public static class IpAddressExtensions
{
public static uint ToRawAddress(this IPEndPoint endPoint)
{
Span<byte> integer = stackalloc byte[4];
endPoint.Address.MapToIPv4().TryWriteBytes(integer, out var bytesWritten);
if (bytesWritten != 4)
{
throw new InvalidOperationException("IP Address could not be serialized to an integer");
}

return BinaryPrimitives.ReadUInt32LittleEndian(integer);
}

public static uint ToRawAddress(this IPAddress ipAddress)
{
Span<byte> integer = stackalloc byte[4];
ipAddress.MapToIPv4().TryWriteBytes(integer, out var bytesWritten);
if (bytesWritten != 4)
{
throw new InvalidOperationException("IP Address could not be serialized to an integer");
}

var ip = BinaryPrimitives.ReadUInt32LittleEndian(integer);

return ip;
}

}
7 changes: 4 additions & 3 deletions src/Prima.Network/Interfaces/Packets/IUoNetworkPacket.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Prima.Network.Serializers;
using Orion.Foundations.Spans;


namespace Prima.Network.Interfaces.Packets;

Expand All @@ -24,11 +25,11 @@ public interface IUoNetworkPacket
/// Reads the packet data from the provided packet reader.
/// </summary>
/// <param name="reader">The packet reader containing the packet data.</param>
void Read(PacketReader reader);
void Read(SpanReader reader);

/// <summary>
/// Writes the packet data to the provided packet writer.
/// </summary>
/// <param name="writer">The packet writer to write packet data to.</param>
void Write(PacketWriter writer);
Span<byte> Write();
}
8 changes: 4 additions & 4 deletions src/Prima.Network/Packets/Base/BaseUoNetworkPacket.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Orion.Foundations.Spans;
using Prima.Network.Interfaces.Packets;
using Prima.Network.Serializers;

namespace Prima.Network.Packets.Base;

Expand Down Expand Up @@ -36,7 +36,7 @@ protected BaseUoNetworkPacket(byte opCode, int length)
/// </summary>
/// <param name="reader">The packet reader containing the packet data.</param>
/// <exception cref="NotImplementedException">Thrown if this method is not overridden in derived classes.</exception>
public virtual void Read(PacketReader reader)
public virtual void Read(SpanReader reader)
{

}
Expand All @@ -47,9 +47,9 @@ public virtual void Read(PacketReader reader)
/// </summary>
/// <param name="writer">The packet writer to write packet data to.</param>
/// <exception cref="NotImplementedException">Thrown if this method is not overridden in derived classes.</exception>
public virtual void Write(PacketWriter writer)
public virtual Span<byte> Write()
{

throw new NotImplementedException("Write method not implemented for this packet type.");
}

/// <summary>
Expand Down
4 changes: 2 additions & 2 deletions src/Prima.Network/Packets/ClientVersionRequest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Net;
using Orion.Foundations.Spans;
using Prima.Network.Packets.Base;
using Prima.Network.Serializers;

namespace Prima.Network.Packets;

Expand Down Expand Up @@ -31,7 +31,7 @@ public ClientVersionRequest(int majorVersion, int minorVersion, int revision, in
Prototype = prototype;
}

public override void Read(PacketReader reader)
public override void Read(SpanReader reader)
{
Seed = reader.ReadInt32();
ClientIP = new IPAddress(Seed);
Expand Down
17 changes: 11 additions & 6 deletions src/Prima.Network/Packets/ConnectToGameServer.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Net;
using Orion.Foundations.Spans;
using Prima.Network.Extensions;
using Prima.Network.Packets.Base;
using Prima.Network.Serializers;

namespace Prima.Network.Packets;

Expand Down Expand Up @@ -34,9 +35,11 @@ public class ConnectToGameServer() : BaseUoNetworkPacket(0x8c, 11)
/// Reads the packet data from the provided packet reader.
/// </summary>
/// <param name="reader">The packet reader to read data from.</param>
public override void Read(PacketReader reader)
public override void Read(SpanReader reader)
{
byte[] ipBytes = reader.ReadBytes(4);
byte[] ipBytes = new byte[4];
reader.Read(ipBytes);

GameServerIP = new IPAddress(ipBytes);
GameServerPort = reader.ReadUInt16();
SessionKey = reader.ReadInt32();
Expand All @@ -46,11 +49,13 @@ public override void Read(PacketReader reader)
/// Writes the packet data to the provided packet writer.
/// </summary>
/// <param name="writer">The packet writer to write data to.</param>
public override void Write(PacketWriter writer)
public override Span<byte> Write()
{
byte[] ipBytes = GameServerIP.GetAddressBytes();
writer.Write(ipBytes);
using var writer = new SpanWriter(stackalloc byte[4], true);
writer.WriteLE(GameServerIP.ToRawAddress());
writer.Write((short)GameServerPort);
writer.Write(SessionKey);

return writer.ToSpan().Span;
}
}
10 changes: 7 additions & 3 deletions src/Prima.Network/Packets/FeatureFlagsResponse.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Orion.Foundations.Spans;
using Prima.Network.Packets.Base;
using Prima.Network.Serializers;

using Prima.Network.Types;

namespace Prima.Network.Packets;
Expand Down Expand Up @@ -60,7 +61,7 @@ public FeatureFlagsResponse(FeatureFlags flags) : this()
/// Reads the packet data from the provided packet reader.
/// </summary>
/// <param name="reader">The packet reader to read data from.</param>
public override void Read(PacketReader reader)
public override void Read(SpanReader reader)
{
Flags = (FeatureFlags)reader.ReadUInt32();
}
Expand All @@ -69,9 +70,12 @@ public override void Read(PacketReader reader)
/// Writes the packet data to the provided packet writer.
/// </summary>
/// <param name="writer">The packet writer to write data to.</param>
public override void Write(PacketWriter writer)
public override Span<byte> Write()
{
using var writer = new SpanWriter(stackalloc byte[5]);
writer.Write((uint)Flags);

return writer.ToSpan().Span;
}

/// <summary>
Expand Down
62 changes: 41 additions & 21 deletions src/Prima.Network/Packets/GameServerList.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using System.Net;
using Orion.Foundations.Spans;
using Prima.Network.Extensions;
using Prima.Network.Packets.Base;
using Prima.Network.Packets.Entries;
using Prima.Network.Serializers;

namespace Prima.Network.Packets;

Expand Down Expand Up @@ -55,24 +56,38 @@ public void AddServer(GameServerEntry server)
/// BYTE[4] Server IP address (reversed for network order)
/// </summary>
/// <param name="writer">The packet writer to write the data to.</param>
public override void Write(PacketWriter writer)
public override Span<byte> Write()
{
var servers = GetServers();

writer.Write((ushort)(servers.Length + 6));

// Write the system info flag
writer.Write(SystemInfoFlag);

// Write the number of servers
writer.Write((ushort)Servers.Count);
var info = Servers.ToArray();
var length = 6 + 40 * info.Length;
var writer = new SpanWriter(stackalloc byte[length]);
writer.Write((ushort)length);
writer.Write((byte)0x5D);
writer.Write((ushort)info.Length);

for (var i = 0; i < info.Length; ++i)
{
var si = info[i];

writer.Write((ushort)i);
writer.WriteAscii(si.Name, 32);
writer.Write((byte)si.LoadPercent);
writer.Write((sbyte)si.TimeZone);
// UO only supports IPv4
writer.Write(si.IP.ToRawAddress());
}

return writer.Span.ToArray();


writer.Write(servers);
}

private byte[] GetServers()
{
using var stream = new PacketWriter();
using var stream = new SpanWriter(stackalloc byte[Servers.Count * 40 + 6], true);
for (var i = 0; i < Servers.Count; i++)
{
var server = Servers[i];
Expand All @@ -81,29 +96,33 @@ private byte[] GetServers()
stream.Write((ushort)i);

// Write server name (fixed 32 bytes)
stream.WriteAsciiFixed(server.Name, 32);
stream.WriteAscii(server.Name, 32);

// Write load percentage
stream.Write(server.LoadPercent);

// Write timezone
stream.Write(server.TimeZone);
var ipBytes = server.IP.GetAddressBytes();
// Reverse the IP address bytes for network order
Array.Reverse(ipBytes);
// Write the reversed IP address

var ipInt = BitConverter.ToUInt32(ipBytes, 0);
var rawAddress = server.IP.ToRawAddress();


// Write IP address in reverse order (as specified in the protocol)
// For example, 192.168.0.1 is sent as 0100A8C0
//var ipBytes = server.IP.GetAddressBytes();
//Array.Reverse(ipBytes);
stream.WriteIpAddress(server.IP);
stream.Write(ipInt);
}

return stream.ToArray();
return stream.Span.ToArray();
}

/// <summary>
/// Reads packet data from the provided packet reader.
/// </summary>
/// <param name="reader">The packet reader to read the data from.</param>
public override void Read(PacketReader reader)
public override void Read(SpanReader reader)
{
reader.ReadByte();
reader.ReadByte();
Expand All @@ -119,15 +138,16 @@ public override void Read(PacketReader reader)
{
var entry = new GameServerEntry
{
Index = reader.ReadUInt16BE(),
Name = reader.ReadFixedString(32),
Index = reader.ReadUInt16(),
Name = reader.ReadAscii(32),
LoadPercent = reader.ReadByte(),
TimeZone = reader.ReadByte()
};

// IP address bytes are reversed in the packet
// For example, 0100A8C0 needs to be converted to 192.168.0.1
byte[] ipBytes = reader.ReadBytes(4);
byte[] ipBytes = new byte[4];
reader.Read(ipBytes);
Array.Reverse(ipBytes);
entry.IP = new IPAddress(ipBytes);

Expand Down
9 changes: 5 additions & 4 deletions src/Prima.Network/Packets/GameServerLogin.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Orion.Foundations.Spans;
using Prima.Network.Packets.Base;
using Prima.Network.Serializers;


namespace Prima.Network.Packets;

Expand All @@ -15,10 +16,10 @@ public GameServerLogin() : base(0x91, 65)
{
}

public override void Read(PacketReader reader)
public override void Read(SpanReader reader)
{
SessionKey = reader.ReadInt32();
AccountId = reader.ReadFixedString(30);
Password = reader.ReadFixedString(30);
AccountId = reader.ReadAscii(30);
Password = reader.ReadAscii(30);
}
}
13 changes: 8 additions & 5 deletions src/Prima.Network/Packets/LoginDenied.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Orion.Foundations.Spans;
using Prima.Network.Packets.Base;
using Prima.Network.Serializers;

using Prima.Network.Types;

namespace Prima.Network.Packets;
Expand Down Expand Up @@ -30,17 +31,19 @@ public LoginDenied(LoginDeniedReasonType reason) : this()
/// Writes the packet data to the provided packet writer.
/// </summary>
/// <param name="writer">The packet writer to write data to.</param>
public override void Write(PacketWriter writer)
public override Span<byte> Write()
{
writer.WriteEnum(Reason);
using var writer = new SpanWriter(stackalloc byte[1]);
writer.Write((byte)Reason);
return writer.ToSpan().Span;
}

/// <summary>
/// Reads the packet data from the provided packet reader.
/// </summary>
/// <param name="reader">The packet reader to read data from.</param>
public override void Read(PacketReader reader)
public override void Read(SpanReader reader)
{
Reason = reader.ReadEnum<LoginDeniedReasonType>();
Reason = (LoginDeniedReasonType)reader.ReadByte();
}
}
17 changes: 10 additions & 7 deletions src/Prima.Network/Packets/LoginRequest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Orion.Foundations.Spans;
using Prima.Network.Packets.Base;
using Prima.Network.Serializers;


namespace Prima.Network.Packets;

Expand Down Expand Up @@ -33,21 +34,23 @@ public class LoginRequest() : BaseUoNetworkPacket(0x80, 62)
/// Writes the packet data to the provided packet writer.
/// </summary>
/// <param name="writer">The packet writer to write data to.</param>
public override void Write(PacketWriter writer)
public Span<byte> Write()
{
writer.WriteAsciiFixed(Username, 30);
writer.WriteAsciiFixed(Password, 30);
using var writer = new SpanWriter(stackalloc byte[62]);
writer.WriteAscii(Username, 30);
writer.WriteAscii(Password, 30);
writer.Write(NextLoginKey);
return writer.ToSpan().Span;
}

/// <summary>
/// Reads the packet data from the provided packet reader.
/// </summary>
/// <param name="reader">The packet reader to read data from.</param>
public override void Read(PacketReader reader)
public override void Read(SpanReader reader)
{
Username = reader.ReadFixedString(30);
Password = reader.ReadFixedString(30);
Username = reader.ReadAscii(30);
Password = reader.ReadAscii(30);
NextLoginKey = reader.ReadByte();
}

Expand Down
Loading