Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR, Palworld Support (Tested on Minecraft and PalWorld) #57

Merged
merged 7 commits into from Feb 17, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/CoreRCON/Constants.cs
Expand Up @@ -16,7 +16,12 @@ internal class Constants
/// <summary>
/// The size of the header of an RCON packet.
/// </summary>
internal const int PACKET_HEADER_SIZE = 12;
internal const int PACKET_HEADER_SIZE = 8;
xobust marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// The size of the header of an RCON packet.
xobust marked this conversation as resolved.
Show resolved Hide resolved
/// </summary>
internal const int PACKET_PADDING_SIZE = 2;

/// <summary>
/// Special response value when you send a Response.Response to the server.
Expand Down
17 changes: 9 additions & 8 deletions src/CoreRCON/PacketFormats/RCONPacket.cs
Expand Up @@ -68,14 +68,15 @@ internal static RCONPacket FromBytes(byte[] buffer)
/// <returns>Byte array with each field.</returns>
internal byte[] ToBytes()
{
int bodyLength = Encoding.UTF8.GetByteCount(Body) + 1;
int totalLength = Constants.PACKET_HEADER_SIZE + bodyLength;
byte[] packetBytes = new byte[totalLength];
int bodyLength = Encoding.UTF8.GetByteCount(Body);
int size = Constants.PACKET_HEADER_SIZE + Constants.PACKET_PADDING_SIZE + bodyLength;

byte[] packetBytes = new byte[size+4];
Span<byte> packetSpan = packetBytes;

// Write packet size
// Packet size parameter does not include the size of the size parameter itself
BinaryPrimitives.WriteInt32LittleEndian(packetSpan, totalLength - 4);
BinaryPrimitives.WriteInt32LittleEndian(packetSpan, size);
packetSpan = packetSpan.Slice(4);

// Write ID
Expand All @@ -84,12 +85,12 @@ internal byte[] ToBytes()

// Write type
BinaryPrimitives.WriteInt32LittleEndian(packetSpan, (int)Type);
packetSpan = packetSpan.Slice(4);

// Write body
Encoding.UTF8.GetBytes(Body, 0, Body.Length, packetBytes, Constants.PACKET_HEADER_SIZE);
packetSpan[bodyLength - 1] = 0; // Null terminator for the body
packetBytes[totalLength - 1] = 0; // Null terminator for the package
Encoding.UTF8.GetBytes(Body, 0, Body.Length, packetBytes, 12);
ExusAltimus marked this conversation as resolved.
Show resolved Hide resolved

packetBytes[packetBytes.Length - 2] = 0; // Null terminator for the body
packetBytes[packetBytes.Length - 1] = 0; // Null terminator for the package

return packetBytes;
}
Expand Down
57 changes: 34 additions & 23 deletions src/CoreRCON/RCON.cs
Expand Up @@ -28,6 +28,7 @@ public partial class RCON(
string password,
uint timeout = 10000,
bool sourceMultiPacketSupport = false,
bool strictCommandPacketIdMatching = true,
ILogger logger = null) : IDisposable
{
// Allows us to keep track of when authentication succeeds, so we can block Connect from returning until it does.
Expand Down Expand Up @@ -71,8 +72,8 @@ public partial class RCON(
/// <param name="host">Server address</param>
/// <param name="port">Server port</param>
public RCON(IPAddress host, ushort port, string password, uint timeout = 10000,
bool sourceMultiPacketSupport = false, ILogger logger = null)
: this(new IPEndPoint(host, port), password, timeout, sourceMultiPacketSupport, logger)
bool sourceMultiPacketSupport = false, bool strictCommandPacketIdMatching = true, ILogger logger = null)
: this(new IPEndPoint(host, port), password, timeout, sourceMultiPacketSupport,strictCommandPacketIdMatching, logger)
{ }

/// <summary>
Expand Down Expand Up @@ -316,6 +317,7 @@ public async Task<string> SendCommandAsync(string command, TimeSpan? overrideTim
throw new SocketException();
}


using var activity = Tracing.ActivitySource.StartActivity("SendCommand", ActivityKind.Client);
activity?.AddTag(Tracing.Tags.Address, _endpoint.Address.ToString());
activity?.AddTag(Tracing.Tags.Port, _endpoint.Port.ToString());
Expand Down Expand Up @@ -367,39 +369,48 @@ public async Task<string> SendCommandAsync(string command, TimeSpan? overrideTim
private void RCONPacketReceived(RCONPacket packet)
{
_logger?.LogTrace("RCON packet received: {}", packet.Id);

TaskCompletionSource<string> taskSource;
// Call pending result and remove from map
if (_pendingCommands.TryGetValue(packet.Id, out TaskCompletionSource<string> taskSource))
if (!_pendingCommands.TryGetValue(packet.Id, out taskSource))
{
if (_multiPacket)
_logger?.LogWarning("Received packet with no matching command id: {} body: {}", packet.Id, packet.Body);
ExusAltimus marked this conversation as resolved.
Show resolved Hide resolved
// The server did not respect our id
if (!strictCommandPacketIdMatching && packet.Id == 0)
{
//Read any previous messages
_incomingBuffer.TryGetValue(packet.Id, out string body);

if (packet.Body == Constants.MULTI_PACKET_END_RESPONSE)
{
//Avoid yielding
taskSource.SetResult(body ?? string.Empty);
_pendingCommands.TryRemove(packet.Id, out _);
_incomingBuffer.Remove(packet.Id);
}
else
{
//Append to previous messages
_incomingBuffer[packet.Id] = body + packet.Body;
}
// Get the most recently sent command
taskSource = _pendingCommands
xobust marked this conversation as resolved.
Show resolved Hide resolved
.OrderBy(cmd => cmd.Key)
.Select(cmd => cmd.Value)
.FirstOrDefault();
ExusAltimus marked this conversation as resolved.
Show resolved Hide resolved
}
else
}

if (_multiPacket)
{
//Read any previous messages
_incomingBuffer.TryGetValue(packet.Id, out string body);

if (packet.Body == Constants.MULTI_PACKET_END_RESPONSE)
{
//Avoid yielding
taskSource.SetResult(packet.Body);
taskSource.SetResult(body ?? string.Empty);
_pendingCommands.TryRemove(packet.Id, out _);
_incomingBuffer.Remove(packet.Id);
}
else
{
//Append to previous messages
_incomingBuffer[packet.Id] = body + packet.Body;
}
}
else
{
_logger?.LogWarning("Received packet with no matching command id: {} body: {}", packet.Id, packet.Body);
//Avoid yielding
taskSource.SetResult(packet.Body);
ExusAltimus marked this conversation as resolved.
Show resolved Hide resolved
_pendingCommands.TryRemove(packet.Id, out _);
}

OnPacketReceived?.Invoke(packet);
}

Expand Down
2 changes: 1 addition & 1 deletion src/RconShell/Program.cs
Expand Up @@ -76,7 +76,7 @@ static async Task Main(string[] args)
port
);

rcon = new RCON(endpoint, password, 0);
rcon = new RCON(endpoint, password, 0, strictCommandPacketIdMatching: false);
await rcon.ConnectAsync();
bool connected = true;
Console.WriteLine("Connected");
Expand Down
2 changes: 1 addition & 1 deletion src/RconTest/RconTest.cs
Expand Up @@ -54,7 +54,7 @@ public async Task testInitAsync()
});
ILogger<RCON> logger = loggerFactory.CreateLogger<RCON>();

rconClient = new RCON(_ip, _port, _password, 1000, false, logger);
rconClient = new RCON(_ip, _port, _password, 1000, false, true, logger);
await rconClient.ConnectAsync();
}

Expand Down