Skip to content
Closed
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
4 changes: 2 additions & 2 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ name: .NET

on:
push:
branches: [ "*" ]
branches: [ "main" ]
pull_request:
branches: [ "*" ]
branches: [ "main" ]

jobs:
build:
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The project aims to provide a high-performance, efficient server engine. Instead
* **Sharpmine.Server**: Core logic and GUI.
* **Sharpmine.Gen**: The incremental source generator for the protocol.
* **Sharpmine.Tests**: Unit tests.
* **Sharpmine.AppHost** and **Sharpmine.ServiceDefaults**: Aspire orchestration. Not yet made proper use of, but maybe in the future.

## Contribute

Expand Down
17 changes: 11 additions & 6 deletions Sharpmine.Gen/PacketGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ private static void GenerateProtocolDirection(
string packetName = packet.Name.Substring("minecraft:".Length);
string packetClassName = ToPascalCase(packetName) + "Packet";
GeneratePacketPartial(context, packetClassName, interfaceName, stateName, directionName, packet.Id);
sb?.AppendLine($" (ProtocolState.{stateName}, 0x{packet.Id:X2}) => new {stateName}.{directionName}.{packetClassName}(),");
sb?.AppendLine($" (ProtocolState.{stateName}, 0x{packet.Id:X2}) => {stateName}.{directionName}.{packetClassName}.DeserializeAsync(stream, reader, cancellationToken),");
}
}

Expand All @@ -96,8 +96,8 @@ namespace {{BaseNamespace}}.{{stateName}}.{{directionName}};

public partial record {{className}} : {{interfaceName}}
{
public ProtocolState State => ProtocolState.{{stateName}};
public int Id => 0x{{id:X2}};
public new ProtocolState State => ProtocolState.{{stateName}};
public new int Id => 0x{{id:X2}};
}
""";

Expand All @@ -118,17 +118,22 @@ namespace {{BaseNamespace}};

public static class ServerboundPacketRegistry
{
public static bool TryCreatePacket(ProtocolState state, int id, [NotNullWhen(true)] out IServerboundPacket? packet)
public static Task<IServerboundPacket?> TryDeserializePacket(
ProtocolState state,
int id,
NetworkStream stream,
BinaryReader reader,
CancellationToken cancellationToken)
{
packet = (state, id) switch
return (state, id) switch
{
""");
}

private static void EndRegistry(StringBuilder sb)
{
sb.Append("""
_ => null
_ => Task.FromResult(null)
};

return packet is not null;
Expand Down
6 changes: 6 additions & 0 deletions Sharpmine.Server/Protocol/ClientHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
using Serilog.Context;

using Sharpmine.Server.Protocol.Packets;
using Sharpmine.Server.Protocol.Packets.Abstract.Serverbound;

namespace Sharpmine.Server.Protocol;

public sealed partial class ClientHandler(
TcpClient client,
ServerService server,
ILogger<ClientHandler> logger) : IAsyncDisposable
{

Expand All @@ -23,8 +25,12 @@ public sealed partial class ClientHandler(

public TcpClient Client { get; } = client;

public ServerService Server { get; } = server;

public PacketTransceiver PacketTransceiver { get; internal set; } = null!;

public ClientInformationPacket? Information { get; set; }

public ProtocolState ProtocolState { get; private set; } = ProtocolState.Handshake;

public void SwitchProtocolState(ProtocolState newState)
Expand Down
4 changes: 2 additions & 2 deletions Sharpmine.Server/Protocol/ClientHandlerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ namespace Sharpmine.Server.Protocol;
public class ClientHandlerFactory(ILoggerFactory loggerFactory)
{

public ClientHandler Create(TcpClient client)
public ClientHandler Create(TcpClient client, ServerService server)
{
var clientHandlerLogger = loggerFactory.CreateLogger<ClientHandler>();
var packetLogger = loggerFactory.CreateLogger<PacketTransceiver>();
var packetTransceiver = new PacketTransceiver(packetLogger);
var handler = new ClientHandler(client, clientHandlerLogger);
var handler = new ClientHandler(client, server, clientHandlerLogger);
packetTransceiver.Handler = handler;
handler.PacketTransceiver = packetTransceiver;
return handler;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace Sharpmine.Server.Protocol.Packets.Abstract.Clientbound;

public abstract record KeepAlivePacket : IClientboundPacket
{

public abstract ProtocolState State { get; }

public abstract int Id { get; }

public long KeepAliveId { get; init; }

public Task SerializeContentAsync(
Stream stream,
BinaryWriter writer,
CancellationToken cancellationToken)
{
writer.Write(KeepAliveId);
return Task.CompletedTask;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace Sharpmine.Server.Protocol.Packets.Abstract.Clientbound;

public abstract record PongResponsePacket : IClientboundPacket
{

public abstract ProtocolState State { get; }

public abstract int Id { get; }

public long Timestamp { get; init; }

public Task SerializeContentAsync(
Stream stream,
BinaryWriter writer,
CancellationToken cancellationToken)
{
writer.Write(Timestamp);
return Task.CompletedTask;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
namespace Sharpmine.Server.Protocol.Packets.Abstract.Serverbound;

public abstract record ClientInformationPacket : IServerboundPacket
{

public abstract ProtocolState State { get; }

public abstract int Id { get; }

public string Locale { get; set; } = null!;

public sbyte ViewDistance { get; set; }

public ChatMode ChatMode { get; set; }

public bool ChatColors { get; set; }

public SkinParts DisplayedSkinParts { get; set; }

public Hand MainHand { get; set; }

public bool EnableTextFiltering { get; set; }

public bool AllowServerListings { get; set; }

public ParticleStatus ParticleStatus { get; set; }

public static Task DeserializeAsync(
NetworkStream stream,
BinaryReader reader,
CancellationToken cancellationToken)
{
Locale = reader.ReadString();
ViewDistance = reader.ReadSByte();
ChatMode = (ChatMode) reader.Read7BitEncodedInt();
ChatColors = reader.ReadBoolean();
DisplayedSkinParts = (SkinParts) reader.ReadByte();
MainHand = (Hand) reader.Read7BitEncodedInt();
EnableTextFiltering = reader.ReadBoolean();
AllowServerListings = reader.ReadBoolean();
ParticleStatus = (ParticleStatus) reader.Read7BitEncodedInt();
return Task.CompletedTask;
}

public Task ProcessAsync(
ClientHandler handler,
NetworkStream stream,
BinaryReader reader,
BinaryWriter writer,
CancellationToken cancellationToken)
{
handler.Information = this;
return Task.CompletedTask;
}

}

public enum ChatMode
{

Enabled = 0,

CommandsOnly = 1,

Hidden = 2,

}

[Flags]
public enum SkinParts : byte
{

Cape = 0x01,

Jacket = 0x02,

LeftSleeve = 0x04,

RightSleeve = 0x08,

LeftPantsLeg = 0x10,

RightPantsLeg = 0x20,

Hat = 0x40,

}

public enum Hand
{

Left = 0,

Right = 1,

}

public enum ParticleStatus
{

All = 0,

Decreased = 1,

Minimal = 2,

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
namespace Sharpmine.Server.Protocol.Packets.Abstract.Serverbound;

public abstract record CustomPayloadPacket : IServerboundPacket
{

public abstract ProtocolState State { get; }

public abstract int Id { get; }

public string Channel { get; set; } = null!;

// TODO: Data

public static Task DeserializeAsync(
NetworkStream stream,
BinaryReader reader,
CancellationToken cancellationToken)
{
Channel = reader.ReadString();
return Task.CompletedTask;
}

public Task ProcessAsync(
ClientHandler handler,
NetworkStream stream,
BinaryReader reader,
BinaryWriter writer,
CancellationToken cancellationToken) => Task.CompletedTask;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
namespace Sharpmine.Server.Protocol.Packets.Abstract.Serverbound;

public abstract record KeepAlivePacket : IServerboundPacket
{

public abstract ProtocolState State { get; }

public abstract int Id { get; }

public long KeepAliveId { get; set; }

public static Task DeserializeAsync(
NetworkStream stream,
BinaryReader reader,
CancellationToken cancellationToken)
{
KeepAliveId = reader.ReadInt64();
return Task.CompletedTask;
}

public Task ProcessAsync(ClientHandler handler,
NetworkStream stream,
BinaryReader reader,
BinaryWriter writer,
CancellationToken cancellationToken)
{
throw new NotImplementedException("Check whether the client responded with the same packet");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Sharpmine.Server.Protocol.Packets.Abstract.Clientbound;

namespace Sharpmine.Server.Protocol.Packets.Abstract.Serverbound;

public abstract record PingRequestPacket : IServerboundPacket
{

public abstract ProtocolState State { get; }

public abstract int Id { get; }

public long Timestamp { get; set; }

public static Task DeserializeAsync(
NetworkStream stream,
BinaryReader reader,
CancellationToken cancellationToken)
{
// TODO: Maybe catch exceptions and return Task.FromException
Timestamp = reader.Read7BitEncodedInt64();
return Task.CompletedTask;
}

public async Task ProcessAsync(
ClientHandler handler,
NetworkStream stream,
BinaryReader reader,
BinaryWriter writer,
CancellationToken cancellationToken)
{
await handler.PacketTransceiver.TransmitAsync(CreatePongResponsePacket(), stream, writer, cancellationToken);
await handler.DisposeAsync();
}

protected abstract PongResponsePacket CreatePongResponsePacket();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Sharpmine.Server.Protocol.Packets.Configuration.Clientbound;

public partial record KeepAlivePacket : Abstract.Clientbound.KeepAlivePacket;

Check failure on line 3 in Sharpmine.Server/Protocol/Packets/Configuration/Clientbound/KeepAlivePacket.cs

View workflow job for this annotation

GitHub Actions / build

'KeepAlivePacket' does not implement inherited abstract member 'KeepAlivePacket.State.get'

Check failure on line 3 in Sharpmine.Server/Protocol/Packets/Configuration/Clientbound/KeepAlivePacket.cs

View workflow job for this annotation

GitHub Actions / build

'KeepAlivePacket' does not implement inherited abstract member 'KeepAlivePacket.Id.get'
Loading
Loading