Skip to content

Commit

Permalink
#29 add support for 1.20.2
Browse files Browse the repository at this point in the history
  • Loading branch information
psu-de committed Jan 7, 2024
1 parent 3c11315 commit 2566d41
Show file tree
Hide file tree
Showing 24 changed files with 298 additions and 46 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ MineSharp 0.1.3:
- added Raycast() method to Physics plugin
- added UseItem(hand) method to Window plugin
- added Serverbound SetHeldItemPacket
- added EquipItem() methods
- added EquipItem() methods
- replaced MiNet.fNbt with MineSharp.fNbt
- Support Minecraft Java 1.20.2
18 changes: 16 additions & 2 deletions Components/MineSharp.Protocol/MinecraftClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using System.Diagnostics;
using System.Net.Sockets;
using System.Net;
using MineSharp.Protocol.Packets.Serverbound.Configuration;

namespace MineSharp.Protocol;

Expand Down Expand Up @@ -50,6 +51,7 @@ public sealed class MinecraftClient : IDisposable
private readonly IDictionary<PacketType, IList<AsyncPacketHandler>> _packetHandlers;
private readonly IDictionary<PacketType, TaskCompletionSource<object>> _packetWaiters;
private readonly TaskCompletionSource _gameJoinedTsc;
private readonly bool _useAnonymousNbt;

private bool _bundlePackets;
private IPacketHandler _internalPacketHandler;
Expand Down Expand Up @@ -107,6 +109,7 @@ public MinecraftClient(MinecraftData data, Session session, string hostnameOrIp,
this._packetWaiters = new Dictionary<PacketType, TaskCompletionSource<object>>();
this._gameJoinedTsc = new TaskCompletionSource();
this._bundledPackets = new Queue<(PacketType, PacketBuffer)>();
this._useAnonymousNbt = this._data.Version.Protocol >= ProtocolVersion.V_1_20_2;

this.Session = session;
this.IP = IPHelper.ResolveHostname(hostnameOrIp);
Expand All @@ -126,7 +129,7 @@ public async Task<bool> Connect(GameState nextState)
try
{
await this._client.ConnectAsync(this.IP, this.Port, this._cancellation.Token);
this._stream = new MinecraftStream(this._client.GetStream());
this._stream = new MinecraftStream(this._client.GetStream(), this._useAnonymousNbt);

this.StreamLoop();
Logger.Info("Connected, starting handshake...");
Expand Down Expand Up @@ -233,6 +236,17 @@ internal void UpdateGameState(GameState next)

if (next == GameState.Play)
this._gameJoinedTsc.TrySetResult();

if (next == GameState.Configuration)
this.SendPacket(new ClientInformationPacket(
"en_pt",
24,
0,
true,
0x7F,
1,
false,
true)); // TODO: Add a settings object #31
}

internal void EnableEncryption(byte[] key)
Expand Down Expand Up @@ -324,7 +338,7 @@ private void DispatchPacket(IPacket packet)
{
var packetId = this._data.Protocol.GetPacketId(packet.Type);

var buffer = new PacketBuffer();
var buffer = new PacketBuffer(this._useAnonymousNbt);
buffer.WriteVarInt(packetId);
packet.Write(buffer, this._data);

Expand Down
14 changes: 8 additions & 6 deletions Components/MineSharp.Protocol/MinecraftStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,18 @@ internal class MinecraftStream

private readonly Inflater Inflater = new Inflater();
private readonly Deflater Deflater = new Deflater();


private readonly bool _useAnonymousNbt;
private readonly object _streamLock;
private readonly NetworkStream _networkStream;
private AesStream? _encryptionStream;

private Stream _stream;
private int _compressionThreshold;

public MinecraftStream(NetworkStream networkStream)
public MinecraftStream(NetworkStream networkStream, bool useAnonymousNbt)
{
this._useAnonymousNbt = useAnonymousNbt;
this._networkStream = networkStream;
this._stream = this._networkStream;

Expand Down Expand Up @@ -71,7 +73,7 @@ public PacketBuffer ReadPacket()

PacketBuffer packetBuffer = uncompressedLength switch {
> 0 => this.DecompressBuffer(data, uncompressedLength),
_ => new PacketBuffer(data)
_ => new PacketBuffer(data, this._useAnonymousNbt)
};

return packetBuffer;
Expand All @@ -96,20 +98,20 @@ private PacketBuffer DecompressBuffer(byte[] buffer, int length)
{
if (length == 0)
{
return new PacketBuffer(buffer);
return new PacketBuffer(buffer, this._useAnonymousNbt);
}

var buffer2 = new byte[length];
Inflater.SetInput(buffer);
Inflater.Inflate(buffer2);
Inflater.Reset();

return new PacketBuffer(buffer2);
return new PacketBuffer(buffer2, this._useAnonymousNbt);
}

private PacketBuffer CompressBuffer(PacketBuffer input)
{
var output = new PacketBuffer();
var output = new PacketBuffer(this._useAnonymousNbt);
if (input.Size < this._compressionThreshold)
{
output.WriteVarInt(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public void Write(PacketBuffer buffer, MinecraftData version)
public static IPacket Read(PacketBuffer buffer, MinecraftData version)
{
var channelName = buffer.ReadString();
var clone = new PacketBuffer(buffer.ReadBytes((int)buffer.ReadableBytes));
var clone = new PacketBuffer(buffer.ReadBytes((int)buffer.ReadableBytes), version.Version.Protocol >= ProtocolVersion.V_1_20_2);
return new PluginMessagePacket(channelName, clone);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using MineSharp.Core.Common;
using MineSharp.Data;
using MineSharp.Data.Protocol;

namespace MineSharp.Protocol.Packets.Clientbound.Play;

/// <summary>
/// The ChunkBatchFinished packet, used since 1.20.2.
/// https://wiki.vg/Protocol#Chunk_Batch_Finished
/// </summary>
public class ChunkBatchFinishedPacket : IPacket
{
/// <inheritdoc />
public PacketType Type => PacketType.CB_Play_ChunkBatchFinished;

/// <summary>
/// The batch size
/// </summary>
public int BatchSize { get; set; }

/// <summary>
/// Create a new ChunkBatchFinishedPacket instance
/// </summary>
/// <param name="batchSize"></param>
public ChunkBatchFinishedPacket(int batchSize)
{
this.BatchSize = batchSize;
}

/// <inheritdoc />
public void Write(PacketBuffer buffer, MinecraftData version)
{
buffer.WriteVarInt(this.BatchSize);
}

/// <inheritdoc />
public static IPacket Read(PacketBuffer buffer, MinecraftData version)
{
return new ChunkBatchFinishedPacket(
buffer.ReadVarInt());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using MineSharp.Core.Common;
using MineSharp.Data;
using MineSharp.Data.Protocol;

namespace MineSharp.Protocol.Packets.Clientbound.Play;

/// <summary>
/// The ChunkBatchStart Packet, used since 1.20.2
/// https://wiki.vg/Protocol#Chunk_Batch_Start
/// </summary>
public class ChunkBatchStartPacket : IPacket
{
/// <inheritdoc />
public PacketType Type => PacketType.CB_Play_ChunkBatchStart;

/// <inheritdoc />
public void Write(PacketBuffer buffer, MinecraftData version)
{ }

/// <inheritdoc />
public static IPacket Read(PacketBuffer buffer, MinecraftData version)
=> new ChunkBatchStartPacket();
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public void Write(PacketBuffer buffer, MinecraftData version)
/// <inheritdoc />
public static IPacket Read(PacketBuffer buffer, MinecraftData version)
{
var clone = new PacketBuffer(buffer.ReadBytes((int)buffer.ReadableBytes));
var clone = new PacketBuffer(buffer.ReadBytes((int)buffer.ReadableBytes), version.Version.Protocol >= ProtocolVersion.V_1_20_2);
return new DeclareCommandsPacket(clone);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class LoginPacket : IPacket
public byte GameMode { get; set; }
public sbyte PreviousGameMode { get; set; }
public string[] DimensionNames { get; set; }
public NbtCompound RegistryCodec { get; set; }
public NbtCompound? RegistryCodec { get; set; }
public string DimensionType { get; set; }
public string DimensionName { get; set; }
public long HashedSeed { get; set; }
Expand All @@ -30,13 +30,14 @@ public class LoginPacket : IPacket
public string? DeathDimensionName { get; set; }
public Position? DeathLocation { get; set; }
public int? PortalCooldown { get; set; }
public bool? DoLimitedCrafting { get; set; } // since 1.20.2

public LoginPacket(int entityId,
bool isHardcore,
byte gameMode,
sbyte previousGameMode,
string[] dimensionNames,
NbtCompound registryCodec,
NbtCompound? registryCodec,
string dimensionType,
string dimensionName,
long hashedSeed,
Expand All @@ -50,7 +51,8 @@ public LoginPacket(int entityId,
bool hasDeathLocation,
string? deathDimensionName,
Position? deathLocation,
int? portalCooldown)
int? portalCooldown,
bool? doLimitedCrafting)
{
this.EntityId = entityId;
this.IsHardcore = isHardcore;
Expand All @@ -65,13 +67,14 @@ public LoginPacket(int entityId,
this.ViewDistance = viewDistance;
this.SimulationDistance = simulationDistance;
this.ReducedDebugInfo = reducedDebugInfo;
this.EnableRespawnScreen = enableRespawnScreen;
this.EnableRespawnScreen = enableRespawnScreen;
this.IsDebug = isDebug;
this.IsFlat = isFlat;
this.HasDeathLocation = hasDeathLocation;
this.DeathDimensionName = deathDimensionName;
this.DeathLocation = deathLocation;
this.PortalCooldown = portalCooldown;
this.DoLimitedCrafting = doLimitedCrafting;
}

public void Write(PacketBuffer buffer, MinecraftData version)
Expand All @@ -83,18 +86,33 @@ public void Write(PacketBuffer buffer, MinecraftData version)

buffer.WriteInt(this.EntityId);
buffer.WriteBool(this.IsHardcore);
buffer.WriteByte(this.GameMode);
buffer.WriteSByte(this.PreviousGameMode);
if (version.Version.Protocol < ProtocolVersion.V_1_20_2)
{
buffer.WriteByte(this.GameMode);
buffer.WriteSByte(this.PreviousGameMode);
}
buffer.WriteVarIntArray(this.DimensionNames, (buf, val) => buf.WriteString(val));
buffer.WriteNbt(this.RegistryCodec);
buffer.WriteString(this.DimensionType);
buffer.WriteString(this.DimensionName);
buffer.WriteLong(this.HashedSeed);
if (version.Version.Protocol < ProtocolVersion.V_1_20_2)
{
buffer.WriteNbt(this.RegistryCodec);
buffer.WriteString(this.DimensionType);
buffer.WriteString(this.DimensionName);
buffer.WriteLong(this.HashedSeed);
}
buffer.WriteVarInt(this.MaxPlayers);
buffer.WriteVarInt(this.ViewDistance);
buffer.WriteVarInt(this.SimulationDistance);
buffer.WriteBool(this.ReducedDebugInfo);
buffer.WriteBool(this.EnableRespawnScreen);
if (version.Version.Protocol >= ProtocolVersion.V_1_20_2)
{
buffer.WriteBool(this.DoLimitedCrafting!.Value);
buffer.WriteString(this.DimensionType);
buffer.WriteString(this.DimensionName);
buffer.WriteLong(this.HashedSeed);
buffer.WriteByte(this.GameMode);
buffer.WriteSByte(this.PreviousGameMode);
}
buffer.WriteBool(this.IsDebug);
buffer.WriteBool(this.IsFlat);

Expand All @@ -115,6 +133,9 @@ public void Write(PacketBuffer buffer, MinecraftData version)

public static IPacket Read(PacketBuffer buffer, MinecraftData version)
{
if (version.Version.Protocol >= ProtocolVersion.V_1_20_2)
return ReadV1_20_2(buffer, version);

var entityId = buffer.ReadInt();
var isHardcore = buffer.ReadBool();
var gameMode = buffer.ReadByte();
Expand Down Expand Up @@ -182,7 +203,60 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version)
hasDeathLocation ?? false,
deathDimensionName,
deathLocation,
portalCooldown);
portalCooldown,
false);
}

private static LoginPacket ReadV1_20_2(PacketBuffer buffer, MinecraftData data)
{
var entityId = buffer.ReadInt();
var isHardcode = buffer.ReadBool();
var dimensionNames = buffer.ReadVarIntArray<string>(buf => buf.ReadString());
var maxPlayer = buffer.ReadVarInt();
var viewDistance = buffer.ReadVarInt();
var simulationDistance = buffer.ReadVarInt();
var reducedDebugInfo = buffer.ReadBool();
var enableRespawnScreen = buffer.ReadBool();
var doLimitedCrafting = buffer.ReadBool();
var dimensionType = buffer.ReadString();
var dimensionName = buffer.ReadString();
var hashedSeed = buffer.ReadLong();
var gameMode = buffer.ReadByte();
var previousGameMode = buffer.ReadSByte();
var isDebug = buffer.ReadBool();
var isFlat = buffer.ReadBool();
var hasDeathLocation = buffer.ReadBool();
string? deathDimensionName = null;
Position? deathLocation = null;
if (hasDeathLocation)
{
deathDimensionName = buffer.ReadString();
deathLocation = new Position(buffer.ReadULong());
}
var portalCooldown = buffer.ReadVarInt();

return new LoginPacket(
entityId,
isHardcode,
gameMode,
previousGameMode,
dimensionNames,
null,
dimensionType,
dimensionName,
hashedSeed,
maxPlayer,
viewDistance,
simulationDistance,
reducedDebugInfo,
enableRespawnScreen,
isDebug,
isFlat,
hasDeathLocation,
deathDimensionName,
deathLocation,
portalCooldown,
doLimitedCrafting);
}
}
#pragma warning restore CS1591
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ private async Task HandleEncryptionRequest(EncryptionRequestPacket packet)
{
var salt = (long)RandomNumberGenerator.GetInt32(int.MaxValue) << 32 | (uint)RandomNumberGenerator.GetInt32(int.MaxValue);

var signData = new PacketBuffer();
var signData = new PacketBuffer(this._data.Version.Protocol >= ProtocolVersion.V_1_20_2);
signData.WriteBytes(packet.VerifyToken);
signData.WriteLong(salt);

Expand Down
Loading

0 comments on commit 2566d41

Please sign in to comment.