From f94cb25b2e3dd82d726e323e8b8896452c5d251d Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Tue, 6 Aug 2024 13:56:19 +0200 Subject: [PATCH 01/73] removed net7.0 because it is no longer supported --- Components/MineSharp.Auth/MineSharp.Auth.csproj | 2 +- .../MineSharp.ChatComponent/MineSharp.ChatComponent.csproj | 4 ++-- Components/MineSharp.Commands/MineSharp.Commands.csproj | 2 +- Components/MineSharp.Physics/MineSharp.Physics.csproj | 2 +- Components/MineSharp.Protocol/MineSharp.Protocol.csproj | 2 +- Components/MineSharp.Windows/MineSharp.Windows.csproj | 2 +- Components/MineSharp.World/MineSharp.World.csproj | 2 +- Data/MineSharp.Data/MineSharp.Data.csproj | 2 +- MineSharp.Bot/MineSharp.Bot.csproj | 2 +- MineSharp.Core/MineSharp.Core.csproj | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Components/MineSharp.Auth/MineSharp.Auth.csproj b/Components/MineSharp.Auth/MineSharp.Auth.csproj index cb28959b..49b5e93d 100644 --- a/Components/MineSharp.Auth/MineSharp.Auth.csproj +++ b/Components/MineSharp.Auth/MineSharp.Auth.csproj @@ -3,7 +3,7 @@ enable enable - net7.0;net8.0 + net8.0 12 true README.md diff --git a/Components/MineSharp.ChatComponent/MineSharp.ChatComponent.csproj b/Components/MineSharp.ChatComponent/MineSharp.ChatComponent.csproj index c2f6cf9b..3f0ce003 100644 --- a/Components/MineSharp.ChatComponent/MineSharp.ChatComponent.csproj +++ b/Components/MineSharp.ChatComponent/MineSharp.ChatComponent.csproj @@ -1,9 +1,9 @@ - + enable enable - net8.0;net7.0 + net8.0 true README.md diff --git a/Components/MineSharp.Commands/MineSharp.Commands.csproj b/Components/MineSharp.Commands/MineSharp.Commands.csproj index 3c0a4fb7..cdbb1daf 100644 --- a/Components/MineSharp.Commands/MineSharp.Commands.csproj +++ b/Components/MineSharp.Commands/MineSharp.Commands.csproj @@ -5,7 +5,7 @@ enable MineSharp.Commands MineSharp.Commands - net7.0;net8.0 + net8.0 12 true README.md diff --git a/Components/MineSharp.Physics/MineSharp.Physics.csproj b/Components/MineSharp.Physics/MineSharp.Physics.csproj index e1047677..900caf14 100644 --- a/Components/MineSharp.Physics/MineSharp.Physics.csproj +++ b/Components/MineSharp.Physics/MineSharp.Physics.csproj @@ -3,7 +3,7 @@ enable enable - net7.0;net8.0 + net8.0 12 true README.md diff --git a/Components/MineSharp.Protocol/MineSharp.Protocol.csproj b/Components/MineSharp.Protocol/MineSharp.Protocol.csproj index 7114deb9..1e46f5a6 100644 --- a/Components/MineSharp.Protocol/MineSharp.Protocol.csproj +++ b/Components/MineSharp.Protocol/MineSharp.Protocol.csproj @@ -3,7 +3,7 @@ enable enable - net7.0;net8.0 + net8.0 12 true README.md diff --git a/Components/MineSharp.Windows/MineSharp.Windows.csproj b/Components/MineSharp.Windows/MineSharp.Windows.csproj index 9a835226..22451765 100644 --- a/Components/MineSharp.Windows/MineSharp.Windows.csproj +++ b/Components/MineSharp.Windows/MineSharp.Windows.csproj @@ -3,7 +3,7 @@ enable enable - net7.0;net8.0 + net8.0 12 true diff --git a/Components/MineSharp.World/MineSharp.World.csproj b/Components/MineSharp.World/MineSharp.World.csproj index a182f96b..7ee29477 100644 --- a/Components/MineSharp.World/MineSharp.World.csproj +++ b/Components/MineSharp.World/MineSharp.World.csproj @@ -3,7 +3,7 @@ enable enable - net7.0;net8.0 + net8.0 12 true README.md diff --git a/Data/MineSharp.Data/MineSharp.Data.csproj b/Data/MineSharp.Data/MineSharp.Data.csproj index b9296c17..b99f6b7f 100644 --- a/Data/MineSharp.Data/MineSharp.Data.csproj +++ b/Data/MineSharp.Data/MineSharp.Data.csproj @@ -3,7 +3,7 @@ enable enable - net7.0;net8.0 + net8.0 12 true README.md diff --git a/MineSharp.Bot/MineSharp.Bot.csproj b/MineSharp.Bot/MineSharp.Bot.csproj index 9031b47d..f0b0c5a4 100644 --- a/MineSharp.Bot/MineSharp.Bot.csproj +++ b/MineSharp.Bot/MineSharp.Bot.csproj @@ -3,7 +3,7 @@ enable enable - net7.0;net8.0 + net8.0 12 true README.md diff --git a/MineSharp.Core/MineSharp.Core.csproj b/MineSharp.Core/MineSharp.Core.csproj index b42679d4..b1381c27 100644 --- a/MineSharp.Core/MineSharp.Core.csproj +++ b/MineSharp.Core/MineSharp.Core.csproj @@ -3,7 +3,7 @@ enable enable - net7.0;net8.0 + net8.0 12 true README.md From 0fbead2d376d56450ec93109499439324af7324d Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Tue, 6 Aug 2024 13:57:46 +0200 Subject: [PATCH 02/73] moved NLog.config to MineSharp.Bot project --- MineSharp.Bot/MineSharp.Bot.csproj | 6 ++++++ {MineSharp.Core => MineSharp.Bot}/NLog.config | 0 MineSharp.Core/MineSharp.Core.csproj | 6 ------ 3 files changed, 6 insertions(+), 6 deletions(-) rename {MineSharp.Core => MineSharp.Bot}/NLog.config (100%) diff --git a/MineSharp.Bot/MineSharp.Bot.csproj b/MineSharp.Bot/MineSharp.Bot.csproj index f0b0c5a4..0ec3ab60 100644 --- a/MineSharp.Bot/MineSharp.Bot.csproj +++ b/MineSharp.Bot/MineSharp.Bot.csproj @@ -43,4 +43,10 @@ + + + Always + + + diff --git a/MineSharp.Core/NLog.config b/MineSharp.Bot/NLog.config similarity index 100% rename from MineSharp.Core/NLog.config rename to MineSharp.Bot/NLog.config diff --git a/MineSharp.Core/MineSharp.Core.csproj b/MineSharp.Core/MineSharp.Core.csproj index b1381c27..fcfa8c0c 100644 --- a/MineSharp.Core/MineSharp.Core.csproj +++ b/MineSharp.Core/MineSharp.Core.csproj @@ -35,10 +35,4 @@ - - - Always - - - From 74e467b080669ba920b76979ffc70ba3dcecc6d0 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Tue, 6 Aug 2024 13:59:49 +0200 Subject: [PATCH 03/73] added GameEvent enum to GameEventPacket --- .../Clientbound/Play/GameEventPacket.cs | 26 ++++++++++++++++--- MineSharp.Bot/Plugins/PlayerPlugin.cs | 10 +++---- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/GameEventPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/GameEventPacket.cs index c1941e0b..0516b01c 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/GameEventPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/GameEventPacket.cs @@ -6,19 +6,37 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 public class GameEventPacket : IPacket { - public GameEventPacket(byte @event, float value) + public enum GameEvent : byte + { + NoRespawnBlockAvailable, + EndRaining, + BeginRaining, + ChangeGameMode, + WinGame, + DemoEvent, + ArrowHitPlayer, + RainLevelChange, + ThunderLevelChange, + PlayPufferfishStingSound, + PlayElderGuardianMobAppearance, + EnableRespawnScreen, + LimitedCrafting, + StartWaitingForLevelChunks + } + + public GameEventPacket(GameEvent @event, float value) { Event = @event; Value = value; } - public byte Event { get; set; } + public GameEvent Event { get; set; } public float Value { get; set; } public PacketType Type => PacketType.CB_Play_GameStateChange; public void Write(PacketBuffer buffer, MinecraftData version) { - buffer.WriteByte(Event); + buffer.WriteByte((byte)Event); buffer.WriteFloat(Value); } @@ -26,7 +44,7 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var @event = buffer.ReadByte(); var value = buffer.ReadFloat(); - return new GameEventPacket(@event, value); + return new GameEventPacket((GameEvent)@event, value); } } #pragma warning restore CS1591 diff --git a/MineSharp.Bot/Plugins/PlayerPlugin.cs b/MineSharp.Bot/Plugins/PlayerPlugin.cs index ed3bd307..78e458bc 100644 --- a/MineSharp.Bot/Plugins/PlayerPlugin.cs +++ b/MineSharp.Bot/Plugins/PlayerPlugin.cs @@ -428,27 +428,27 @@ private Task HandleGameEvent(GameEventPacket packet) { switch (packet.Event) { - case 1: // End Raining + case GameEventPacket.GameEvent.EndRaining: IsRaining = false; OnWeatherChanged.Dispatch(Bot); break; - case 2: // Begin Raining + case GameEventPacket.GameEvent.BeginRaining: IsRaining = true; OnWeatherChanged.Dispatch(Bot); break; - case 7: // Rain Level Changed + case GameEventPacket.GameEvent.RainLevelChange: RainLevel = packet.Value; OnWeatherChanged.Dispatch(Bot); break; - case 8: // Thunder Level Changed + case GameEventPacket.GameEvent.ThunderLevelChange: ThunderLevel = packet.Value; OnWeatherChanged.Dispatch(Bot); break; - case 3: // GameMode Change + case GameEventPacket.GameEvent.ChangeGameMode: var gameMode = (GameMode)packet.Value; Self!.GameMode = gameMode; break; From afe79ce004e4719d575f43a79d1a2032d4f62023 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Tue, 6 Aug 2024 14:01:05 +0200 Subject: [PATCH 04/73] fix wrong health value upon joining server --- MineSharp.Bot/Plugins/PlayerPlugin.cs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/MineSharp.Bot/Plugins/PlayerPlugin.cs b/MineSharp.Bot/Plugins/PlayerPlugin.cs index 78e458bc..1bc72032 100644 --- a/MineSharp.Bot/Plugins/PlayerPlugin.cs +++ b/MineSharp.Bot/Plugins/PlayerPlugin.cs @@ -181,7 +181,7 @@ protected override async Task Init() PlayerMap.TryAdd(entity.ServerId, Self); - Health = 20.0f; + Health = loginPacket.HasDeathLocation ? 0f : 20.0f; Food = 20.0f; Saturation = 20.0f; Dimension = loginPacket.DimensionName; @@ -189,14 +189,17 @@ protected override async Task Init() Logger.Info( $"Initialized Bot Entity: Position=({Entity!.Position}), GameMode={Self.GameMode}, Dimension={Dimension}."); - await Bot.Client.SendPacket( - new SetPlayerPositionAndRotationPacket( - positionPacket.X, - positionPacket.Y, - positionPacket.Z, - positionPacket.Yaw, - positionPacket.Pitch, - Entity.IsOnGround)); + if (!loginPacket.HasDeathLocation) + { + await Bot.Client.SendPacket( + new SetPlayerPositionAndRotationPacket( + positionPacket.X, + positionPacket.Y, + positionPacket.Z, + positionPacket.Yaw, + positionPacket.Pitch, + Entity.IsOnGround)); + } try { From 440c5f4cf703f9782b66511205efd7c5919c733b Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Tue, 6 Aug 2024 14:02:42 +0200 Subject: [PATCH 05/73] added ReadLongArray and WriteLongArray to PacketBuffer --- .../Play/ChunkDataAndUpdateLightPacket.cs | 38 ++++--------------- .../Containers/PaletteContainer.cs | 6 +-- MineSharp.Core/Common/PacketBuffer.cs | 26 ++++++++++++- 3 files changed, 33 insertions(+), 37 deletions(-) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkDataAndUpdateLightPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkDataAndUpdateLightPacket.cs index 315a7b75..59cd23eb 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkDataAndUpdateLightPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkDataAndUpdateLightPacket.cs @@ -138,10 +138,10 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteBool(TrustEdges!.Value); } - WriteLongArray(SkyLightMask, buffer); - WriteLongArray(BlockLightMask, buffer); - WriteLongArray(EmptySkyLightMask, buffer); - WriteLongArray(EmptyBlockLightMask, buffer); + buffer.WriteLongArray(SkyLightMask); + buffer.WriteLongArray(BlockLightMask); + buffer.WriteLongArray(EmptySkyLightMask); + buffer.WriteLongArray(EmptyBlockLightMask); buffer.WriteVarInt(SkyLight.Length); foreach (var array in SkyLight) @@ -180,10 +180,10 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) trustEdges = buffer.ReadBool(); } - var skyLightMask = ReadLongArray(buffer); - var blockLightMask = ReadLongArray(buffer); - var emptySkyLightMask = ReadLongArray(buffer); - var emptyBlockLightMask = ReadLongArray(buffer); + var skyLightMask = buffer.ReadLongArray(); + var blockLightMask = buffer.ReadLongArray(); + var emptySkyLightMask = buffer.ReadLongArray(); + var emptyBlockLightMask = buffer.ReadLongArray(); var skyLight = new byte[buffer.ReadVarInt()][]; for (var i = 0; i < skyLight.Length; i++) { @@ -212,27 +212,5 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) skyLight, blockLight); } - - private static void WriteLongArray(long[] array, PacketBuffer buffer) - { - buffer.WriteVarInt(array.Length); - foreach (var l in array) - { - buffer.WriteLong(l); - } - } - - private static long[] ReadLongArray(PacketBuffer buffer) - { - var length = buffer.ReadVarInt(); - var array = new long[length]; - - for (var i = 0; i < array.Length; i++) - { - array[i] = buffer.ReadLong(); - } - - return array; - } } #pragma warning restore CS1591 diff --git a/Components/MineSharp.World/Containers/PaletteContainer.cs b/Components/MineSharp.World/Containers/PaletteContainer.cs index ebc8af44..92210d18 100644 --- a/Components/MineSharp.World/Containers/PaletteContainer.cs +++ b/Components/MineSharp.World/Containers/PaletteContainer.cs @@ -71,11 +71,7 @@ protected static (IPalette palette, IntBitArray data) FromStream(PacketBuffer bu palette = DirectPalette.FromStream(buffer); } - var data = new long[buffer.ReadVarInt()]; - for (var i = 0; i < data.Length; i++) - { - data[i] = buffer.ReadLong(); - } + var data = buffer.ReadLongArray(); return (palette, new(data, bitsPerEntry)); } diff --git a/MineSharp.Core/Common/PacketBuffer.cs b/MineSharp.Core/Common/PacketBuffer.cs index d4c8e7b1..bfb722e7 100644 --- a/MineSharp.Core/Common/PacketBuffer.cs +++ b/MineSharp.Core/Common/PacketBuffer.cs @@ -331,6 +331,19 @@ public T[] ReadVarIntArray(Func reader) return array; } + public long[] ReadLongArray() + { + var length = ReadVarInt(); + var array = new long[length]; + + for (var i = 0; i < array.Length; i++) + { + array[i] = ReadLong(); + } + + return array; + } + public byte[] RestBuffer() { var bytes = new byte[ReadableBytes]; @@ -589,6 +602,15 @@ public void WriteVarIntArray(ICollection collection, Action Date: Tue, 6 Aug 2024 14:04:11 +0200 Subject: [PATCH 06/73] add new packet types for sound effects and particles added `EntitySoundEffectPacket`, `ParticlePacket`, and `SoundEffectPacket` --- .../Play/EntitySoundEffectPacket.cs | 78 +++++++++++++++++ .../Clientbound/Play/ParticlePacket.cs | 76 ++++++++++++++++ .../Clientbound/Play/SoundEffectPacket.cs | 86 +++++++++++++++++++ .../Packets/PacketPalette.cs | 7 +- 4 files changed, 245 insertions(+), 2 deletions(-) create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/ParticlePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs new file mode 100644 index 00000000..d57ae752 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs @@ -0,0 +1,78 @@ +using MineSharp.Core.Common; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; +#pragma warning disable CS1591 +public class EntitySoundEffectPacket : IPacket +{ + public EntitySoundEffectPacket(int soundId, string? soundName, bool? hasFixedRange, float? range, int soundCategory, int entityId, float volume, float pitch, long seed) + { + SoundId = soundId; + SoundName = soundName; + HasFixedRange = hasFixedRange; + Range = range; + SoundCategory = soundCategory; + EntityId = entityId; + Volume = volume; + Pitch = pitch; + Seed = seed; + } + + public int SoundId { get; set; } + public string? SoundName { get; set; } + public bool? HasFixedRange { get; set; } + public float? Range { get; set; } + public int SoundCategory { get; set; } + public int EntityId { get; set; } + public float Volume { get; set; } + public float Pitch { get; set; } + public long Seed { get; set; } + public PacketType Type => PacketType.CB_Play_EntitySoundEffect; + + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(SoundId); + if (SoundId == 0) + { + buffer.WriteString(SoundName!); + buffer.WriteBool(HasFixedRange!.Value); + if (HasFixedRange.Value) + { + buffer.WriteFloat(Range!.Value); + } + } + buffer.WriteVarInt(SoundCategory); + buffer.WriteVarInt(EntityId); + buffer.WriteFloat(Volume); + buffer.WriteFloat(Pitch); + buffer.WriteLong(Seed); + } + + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var soundId = buffer.ReadVarInt(); + string? soundName = null; + bool? hasFixedRange = null; + float? range = null; + + if (soundId == 0) + { + soundName = buffer.ReadString(); + hasFixedRange = buffer.ReadBool(); + if (hasFixedRange.Value) + { + range = buffer.ReadFloat(); + } + } + + var soundCategory = buffer.ReadVarInt(); + var entityId = buffer.ReadVarInt(); + var volume = buffer.ReadFloat(); + var pitch = buffer.ReadFloat(); + var seed = buffer.ReadLong(); + + return new EntitySoundEffectPacket(soundId, soundName, hasFixedRange, range, soundCategory, entityId, volume, pitch, seed); + } +} +#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ParticlePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ParticlePacket.cs new file mode 100644 index 00000000..382b093c --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ParticlePacket.cs @@ -0,0 +1,76 @@ +using MineSharp.Core.Common; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; +#pragma warning disable CS1591 +public class ParticlePacket : IPacket +{ + public ParticlePacket(int particleId, bool longDistance, double x, double y, double z, float offsetX, float offsetY, float offsetZ, float maxSpeed, int particleCount, PacketBuffer data) + { + ParticleId = particleId; + LongDistance = longDistance; + X = x; + Y = y; + Z = z; + OffsetX = offsetX; + OffsetY = offsetY; + OffsetZ = offsetZ; + MaxSpeed = maxSpeed; + ParticleCount = particleCount; + Data = data; + } + + public int ParticleId { get; set; } + public bool LongDistance { get; set; } + public double X { get; set; } + public double Y { get; set; } + public double Z { get; set; } + public float OffsetX { get; set; } + public float OffsetY { get; set; } + public float OffsetZ { get; set; } + public float MaxSpeed { get; set; } + public int ParticleCount { get; set; } + /// + /// Data depends on the particle id. + /// Will be an empty buffer for most particles. + /// + public PacketBuffer Data { get; set; } + public PacketType Type => PacketType.CB_Play_WorldParticles; + + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(ParticleId); + buffer.WriteBool(LongDistance); + buffer.WriteDouble(X); + buffer.WriteDouble(Y); + buffer.WriteDouble(Z); + buffer.WriteFloat(OffsetX); + buffer.WriteFloat(OffsetY); + buffer.WriteFloat(OffsetZ); + buffer.WriteFloat(MaxSpeed); + buffer.WriteVarInt(ParticleCount); + buffer.WriteBytes(Data.GetBuffer()); + } + + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var particleId = buffer.ReadVarInt(); + var longDistance = buffer.ReadBool(); + var x = buffer.ReadDouble(); + var y = buffer.ReadDouble(); + var z = buffer.ReadDouble(); + var offsetX = buffer.ReadFloat(); + var offsetY = buffer.ReadFloat(); + var offsetZ = buffer.ReadFloat(); + var maxSpeed = buffer.ReadFloat(); + var particleCount = buffer.ReadVarInt(); + var byteBuffer = new byte[buffer.ReadableBytes]; + buffer.ReadBytes(byteBuffer); + var data = new PacketBuffer(byteBuffer, buffer.ProtocolVersion); + + return new ParticlePacket(particleId, longDistance, x, y, z, offsetX, offsetY, offsetZ, maxSpeed, particleCount, data); + } + +} +#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs new file mode 100644 index 00000000..d7ab883e --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs @@ -0,0 +1,86 @@ +using MineSharp.Core.Common; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; +#pragma warning disable CS1591 +public class SoundEffectPacket : IPacket +{ + public SoundEffectPacket(int soundId, string? soundName, bool? hasFixedRange, float? range, int soundCategory, int effectPositionX, int effectPositionY, int effectPositionZ, float volume, float pitch, long seed) + { + SoundId = soundId; + SoundName = soundName; + HasFixedRange = hasFixedRange; + Range = range; + SoundCategory = soundCategory; + EffectPositionX = effectPositionX; + EffectPositionY = effectPositionY; + EffectPositionZ = effectPositionZ; + Volume = volume; + Pitch = pitch; + Seed = seed; + } + + public int SoundId { get; set; } + public string? SoundName { get; set; } + public bool? HasFixedRange { get; set; } + public float? Range { get; set; } + public int SoundCategory { get; set; } + public int EffectPositionX { get; set; } + public int EffectPositionY { get; set; } + public int EffectPositionZ { get; set; } + public float Volume { get; set; } + public float Pitch { get; set; } + public long Seed { get; set; } + public PacketType Type => PacketType.CB_Play_SoundEffect; + + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(SoundId); + if (SoundId == 0) + { + buffer.WriteString(SoundName!); + buffer.WriteBool(HasFixedRange!.Value); + if (HasFixedRange.Value) + { + buffer.WriteFloat(Range!.Value); + } + } + buffer.WriteVarInt(SoundCategory); + buffer.WriteInt(EffectPositionX); + buffer.WriteInt(EffectPositionY); + buffer.WriteInt(EffectPositionZ); + buffer.WriteFloat(Volume); + buffer.WriteFloat(Pitch); + buffer.WriteLong(Seed); + } + + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var soundId = buffer.ReadVarInt(); + string? soundName = null; + bool? hasFixedRange = null; + float? range = null; + + if (soundId == 0) + { + soundName = buffer.ReadString(); + hasFixedRange = buffer.ReadBool(); + if (hasFixedRange.Value) + { + range = buffer.ReadFloat(); + } + } + + var soundCategory = buffer.ReadVarInt(); + var effectPositionX = buffer.ReadInt(); + var effectPositionY = buffer.ReadInt(); + var effectPositionZ = buffer.ReadInt(); + var volume = buffer.ReadFloat(); + var pitch = buffer.ReadFloat(); + var seed = buffer.ReadLong(); + + return new SoundEffectPacket(soundId, soundName, hasFixedRange, range, soundCategory, effectPositionX, effectPositionY, effectPositionZ, volume, pitch, seed); + } +} +#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/PacketPalette.cs b/Components/MineSharp.Protocol/Packets/PacketPalette.cs index ee89af3e..ab5f3f95 100644 --- a/Components/MineSharp.Protocol/Packets/PacketPalette.cs +++ b/Components/MineSharp.Protocol/Packets/PacketPalette.cs @@ -18,10 +18,12 @@ using CBKeepAlivePacket = MineSharp.Protocol.Packets.Clientbound.Play.KeepAlivePacket; using CBPluginMessagePacket = MineSharp.Protocol.Packets.Clientbound.Configuration.PluginMessagePacket; using CBSetHeldItemPacket = MineSharp.Protocol.Packets.Clientbound.Play.SetHeldItemPacket; +using ConfClientInformation = MineSharp.Protocol.Packets.Serverbound.Configuration.ClientInformationPacket; using ConfigurationDisconnectPacket = MineSharp.Protocol.Packets.Clientbound.Configuration.DisconnectPacket; using ConfPingPacket = MineSharp.Protocol.Packets.Clientbound.Configuration.PingPacket; using ConfPongPacket = MineSharp.Protocol.Packets.Serverbound.Configuration.PongPacket; using LoginDisconnectPacket = MineSharp.Protocol.Packets.Clientbound.Login.DisconnectPacket; +using PlayClientInformation = MineSharp.Protocol.Packets.Serverbound.Play.ClientInformationPacket; using PlayDisconnectPacket = MineSharp.Protocol.Packets.Clientbound.Play.DisconnectPacket; using PlayPingPacket = MineSharp.Protocol.Packets.Clientbound.Play.PingPacket; using PlayPongPacket = MineSharp.Protocol.Packets.Serverbound.Play.PongPacket; @@ -33,8 +35,6 @@ using SBKeepAlivePacket = MineSharp.Protocol.Packets.Serverbound.Play.KeepAlivePacket; using SBPluginMessagePacket = MineSharp.Protocol.Packets.Serverbound.Configuration.PluginMessagePacket; using SBSetHeldItemPacket = MineSharp.Protocol.Packets.Serverbound.Play.SetHeldItemPacket; -using ConfClientInformation = MineSharp.Protocol.Packets.Serverbound.Configuration.ClientInformationPacket; -using PlayClientInformation = MineSharp.Protocol.Packets.Serverbound.Play.ClientInformationPacket; namespace MineSharp.Protocol.Packets; @@ -117,6 +117,7 @@ private static void InitializePackets() RegisterPacket(PacketType.CB_Play_SpawnEntity); RegisterPacket(PacketType.CB_Play_KeepAlive); RegisterPacket(PacketType.CB_Play_MapChunk); + RegisterPacket(PacketType.CB_Play_WorldParticles); RegisterPacket(PacketType.CB_Play_UnloadChunk); RegisterPacket(PacketType.CB_Play_BlockChange); RegisterPacket(PacketType.CB_Play_MultiBlockChange); @@ -145,6 +146,8 @@ private static void InitializePackets() RegisterPacket(PacketType.CB_Play_OpenWindow); RegisterPacket(PacketType.CB_Play_CloseWindow); RegisterPacket(PacketType.CB_Play_HeldItemSlot); + RegisterPacket(PacketType.CB_Play_EntitySoundEffect); + RegisterPacket(PacketType.CB_Play_SoundEffect); RegisterPacket(PacketType.CB_Play_SystemChat); RegisterPacket(PacketType.CB_Play_ProfilelessChat); RegisterPacket(PacketType.CB_Play_EntityStatus); From a93f3699077d1069c44014948859632e21aaa83a Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Tue, 6 Aug 2024 14:06:01 +0200 Subject: [PATCH 07/73] moved EnableDebugLogs to helper class --- MineSharp.Bot/MineSharpBot.cs | 23 ++--------------------- MineSharp.Bot/Utils/LoggingHelper.cs | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 21 deletions(-) create mode 100644 MineSharp.Bot/Utils/LoggingHelper.cs diff --git a/MineSharp.Bot/MineSharpBot.cs b/MineSharp.Bot/MineSharpBot.cs index 7b82acdb..90ae048f 100644 --- a/MineSharp.Bot/MineSharpBot.cs +++ b/MineSharp.Bot/MineSharpBot.cs @@ -38,7 +38,7 @@ public class MineSharpBot /// The object used by this bot /// public readonly Session Session; - + /// /// NBT Registry sent by the server /// @@ -135,7 +135,7 @@ await Task.WhenAll( public async Task Disconnect(ChatComponent.Chat? reason = null) { reason ??= new TranslatableComponent("disconnect.quitting"); - + if (tickLoop is { Status: TaskStatus.Running }) { cancellation.Cancel(); @@ -180,23 +180,4 @@ private Task OnClientDisconnected(MinecraftClient sender, ChatComponent.Chat rea { return OnBotDisconnected.Dispatch(this, reason); } - - /// - /// Enable debug logs of minesharp to be written to the console and a log file. - /// Trace logs are only written to the logfile. - /// - /// if true, also log trace messages. - public static void EnableDebugLogs(bool trace = false) - { - var configuration = new NLog.Config.LoggingConfiguration(); - - var logfile = new NLog.Targets.FileTarget("customfile") { FileName = $"{DateTime.Now:dd.MM.yyyy hh:mm:ss}.log" }; - var logconsole = new NLog.Targets.ConsoleTarget("logconsole"); - - var level = trace ? LogLevel.Trace : LogLevel.Debug; - configuration.AddRule(level, LogLevel.Fatal, logfile); - configuration.AddRule(LogLevel.Debug, LogLevel.Fatal, logconsole); - - LogManager.Configuration = configuration; - } } diff --git a/MineSharp.Bot/Utils/LoggingHelper.cs b/MineSharp.Bot/Utils/LoggingHelper.cs new file mode 100644 index 00000000..56eebb48 --- /dev/null +++ b/MineSharp.Bot/Utils/LoggingHelper.cs @@ -0,0 +1,25 @@ +using NLog; + +namespace MineSharp.Bot.Utils; + +public static class LoggingHelper +{ + /// + /// Enable debug logs of minesharp to be written to the console and a log file. + /// Trace logs are only written to the logfile. + /// + /// if true, also log trace messages. + public static void EnableDebugLogs(bool trace = false) + { + var configuration = new NLog.Config.LoggingConfiguration(); + + var logfile = new NLog.Targets.FileTarget("customfile") { FileName = $"{DateTime.Now:dd.MM.yyyy hh:mm:ss}.log" }; + var logconsole = new NLog.Targets.ConsoleTarget("logconsole"); + + var level = trace ? LogLevel.Trace : LogLevel.Debug; + configuration.AddRule(level, LogLevel.Fatal, logfile); + configuration.AddRule(LogLevel.Debug, LogLevel.Fatal, logconsole); + + LogManager.Configuration = configuration; + } +} From 7fe2be3057d630f605c94e7890b8f90b5a9596fc Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Tue, 6 Aug 2024 14:12:25 +0200 Subject: [PATCH 08/73] fixed chunk data parsing by using DimensionInfo --- Components/MineSharp.World/AbstractWorld.cs | 12 +++-- Components/MineSharp.World/DimensionInfo.cs | 49 +++++++++++++++++++ .../MineSharp.World/V1_18/Chunk_1_18.cs | 24 +++++---- .../MineSharp.World/V1_18/World_1_18.cs | 14 ++---- Components/MineSharp.World/WorldVersion.cs | 12 ++--- 5 files changed, 81 insertions(+), 30 deletions(-) create mode 100644 Components/MineSharp.World/DimensionInfo.cs diff --git a/Components/MineSharp.World/AbstractWorld.cs b/Components/MineSharp.World/AbstractWorld.cs index ef15af0b..ccf06774 100644 --- a/Components/MineSharp.World/AbstractWorld.cs +++ b/Components/MineSharp.World/AbstractWorld.cs @@ -17,7 +17,8 @@ namespace MineSharp.World; /// Base class for other implementations of the IWorld interface /// /// -public abstract class AbstractWorld(MinecraftData data) : IWorld +/// +public abstract class AbstractWorld(MinecraftData data, DimensionInfo dimensionInfo) : IWorld { private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); @@ -26,6 +27,11 @@ public abstract class AbstractWorld(MinecraftData data) : IWorld /// public readonly MinecraftData Data = data; + /// + /// The Dimension that this world represents + /// + public readonly DimensionInfo DimensionInfo = dimensionInfo; + private readonly BlockInfo outOfMapBlock = data.Blocks.ByType(BlockType.Air)!; /// @@ -34,10 +40,10 @@ public abstract class AbstractWorld(MinecraftData data) : IWorld protected ConcurrentDictionary Chunks = new(); /// - public abstract int MaxY { get; } + public int MaxY => DimensionInfo.WorldMaxY; /// - public abstract int MinY { get; } + public int MinY => DimensionInfo.WorldMinY; /// diff --git a/Components/MineSharp.World/DimensionInfo.cs b/Components/MineSharp.World/DimensionInfo.cs new file mode 100644 index 00000000..948c062f --- /dev/null +++ b/Components/MineSharp.World/DimensionInfo.cs @@ -0,0 +1,49 @@ +using MineSharp.Core.Common; +using MineSharp.Data; + +namespace MineSharp.World; + +/// +/// Specifies the Dimension. +/// +public record DimensionInfo(Dimension Dimension, int WorldMinY, int WorldMaxY) +{ + public static readonly MinecraftVersion MinecraftVersionMajor118 = new("1.18", -1); + + // TODO: Select Version Specific Dimension Info + // since we currently only support 1.18 and above this is fine + + public static readonly DimensionInfo Overworld = new DimensionInfo(Dimension.Overworld, -64, 320); + public static readonly DimensionInfo Nether = new DimensionInfo(Dimension.Nether, 0, 256); + public static readonly DimensionInfo End = new DimensionInfo(Dimension.End, 0, 256); + + /// + /// Gets the height of the world. + /// + /// + /// The height of the world, calculated as the difference between WorldMaxY and WorldMinY. + /// + public int GetWorldHeight() + { + return WorldMaxY - WorldMinY; + } + + /// + /// Gets the DimensionInfo for the specified Dimension. + /// + /// The dimension to get the DimensionInfo for. + /// The DimensionInfo for the specified dimension. + /// + /// Thrown when the specified dimension is not recognized. + /// + public static DimensionInfo FromDimension(Dimension dimension) + { + return dimension switch + { + Dimension.Overworld => Overworld, + Dimension.Nether => Nether, + Dimension.End => End, + _ => throw new ArgumentOutOfRangeException(nameof(dimension), dimension, null) + }; + } +} diff --git a/Components/MineSharp.World/V1_18/Chunk_1_18.cs b/Components/MineSharp.World/V1_18/Chunk_1_18.cs index af1c3deb..f737c1f0 100644 --- a/Components/MineSharp.World/V1_18/Chunk_1_18.cs +++ b/Components/MineSharp.World/V1_18/Chunk_1_18.cs @@ -14,24 +14,28 @@ namespace MineSharp.World.V1_18; /// public sealed class Chunk118 : IChunk { - private const int SectionCount = World118.WorldHeight / ChunkSection118.SectionSize; private readonly Dictionary blockEntities; private readonly MinecraftData data; + private readonly DimensionInfo dimensionInfo; private readonly IChunkSection[] sections; + private int CalculateSectionCount() => dimensionInfo.GetWorldHeight() / ChunkSection118.SectionSize; + /// /// Create a new instance /// /// + /// /// /// - public Chunk118(MinecraftData data, ChunkCoordinates coordinates, BlockEntity[] blockEntities) + public Chunk118(MinecraftData data, DimensionInfo dimensionInfo, ChunkCoordinates coordinates, BlockEntity[] blockEntities) { Coordinates = coordinates; this.data = data; + this.dimensionInfo = dimensionInfo; this.blockEntities = new(); - sections = new IChunkSection[SectionCount]; + sections = new IChunkSection[CalculateSectionCount()]; foreach (var entity in blockEntities) { @@ -49,7 +53,7 @@ public Chunk118(MinecraftData data, ChunkCoordinates coordinates, BlockEntity[] public void LoadData(byte[] buf) { var buffer = new PacketBuffer(buf, data.Version.Protocol); - for (var i = 0; i < SectionCount; i++) + for (var i = 0; i < sections.Length; i++) { sections[i] = ChunkSection118.FromStream(data, buffer); } @@ -107,7 +111,7 @@ public IEnumerable FindBlocks(BlockType type, int? maxCount = null) { block.Position = new( block.Position.X, - FromChunkSectionY(block.Position.Y, i), + FromChunkSectionY(block.Position.Y, i, dimensionInfo.WorldMinY), block.Position.Z); yield return block; @@ -121,7 +125,7 @@ public IEnumerable FindBlocks(BlockType type, int? maxCount = null) private (int y, IChunkSection section) GetChunkSectionAndNewYFromPosition(Position position) { - var sectionIndex = GetSectionIndex(position.Y); + var sectionIndex = GetSectionIndex(position.Y, dimensionInfo.WorldMinY); if (sectionIndex >= sections.Length) { throw new OutOfWorldException($"The Y coordinate {position.Y} is out of the world."); @@ -143,14 +147,14 @@ private int ToChunkSectionY(int y) return v; } - private static int FromChunkSectionY(int y, int sectionIndex) + private static int FromChunkSectionY(int y, int sectionIndex, int worldMinY) { - const int negative_section_count = -World118.MIN_Y / ChunkSection118.SectionSize; + int negative_section_count = -worldMinY / ChunkSection118.SectionSize; return ((sectionIndex - negative_section_count) * ChunkSection118.SectionSize) + y; } - private static int GetSectionIndex(int y) + private static int GetSectionIndex(int y, int worldMinY) { - return (y - World118.MIN_Y) / ChunkSection118.SectionSize; + return (y - worldMinY) / ChunkSection118.SectionSize; } } diff --git a/Components/MineSharp.World/V1_18/World_1_18.cs b/Components/MineSharp.World/V1_18/World_1_18.cs index 19b79cb4..bf869211 100644 --- a/Components/MineSharp.World/V1_18/World_1_18.cs +++ b/Components/MineSharp.World/V1_18/World_1_18.cs @@ -11,22 +11,14 @@ namespace MineSharp.World.V1_18; /// public class World118 : AbstractWorld { - internal const int WorldHeight = MAX_Y - MIN_Y; - internal const int MAX_Y = 320; - internal const int MIN_Y = -64; private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(typeof(IWorld)); /// - public World118(MinecraftData data) : base(data) + public World118(MinecraftData data, DimensionInfo dimensionInfo) + : base(data, dimensionInfo) { } - /// - public override int MaxY => MAX_Y; - - /// - public override int MinY => MIN_Y; - /// public override bool IsOutOfMap(Position position) { @@ -51,6 +43,6 @@ public override bool IsOutOfMap(Position position) /// public override IChunk CreateChunk(ChunkCoordinates coordinates, BlockEntity[] entities) { - return new Chunk118(Data, coordinates, entities); + return new Chunk118(Data, DimensionInfo, coordinates, entities); } } diff --git a/Components/MineSharp.World/WorldVersion.cs b/Components/MineSharp.World/WorldVersion.cs index 5f30e0f4..f5635d65 100644 --- a/Components/MineSharp.World/WorldVersion.cs +++ b/Components/MineSharp.World/WorldVersion.cs @@ -1,4 +1,5 @@ -using MineSharp.Data; +using MineSharp.Core.Common; +using MineSharp.Data; using MineSharp.World.V1_18; namespace MineSharp.World; @@ -8,19 +9,18 @@ namespace MineSharp.World; /// public static class WorldVersion { - private static readonly MinecraftVersion Major118 = new("1.18", -1); - /// /// Create a new IWorld for the given version /// /// + /// /// /// - public static IWorld CreateWorld(MinecraftData version) + public static IWorld CreateWorld(MinecraftData version, Dimension dimension) { - if (version.Version >= Major118) + if (version.Version >= DimensionInfo.MinecraftVersionMajor118) { - return new World118(version); + return new World118(version, DimensionInfo.FromDimension(dimension)); } throw new NotSupportedException( From e5c466e33468b55e5a2a37b6be433362c70904d1 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Tue, 6 Aug 2024 14:16:29 +0200 Subject: [PATCH 09/73] fixed entity velocity handling --- MineSharp.Bot/Plugins/EntityPlugin.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MineSharp.Bot/Plugins/EntityPlugin.cs b/MineSharp.Bot/Plugins/EntityPlugin.cs index dbe376d9..6220c573 100644 --- a/MineSharp.Bot/Plugins/EntityPlugin.cs +++ b/MineSharp.Bot/Plugins/EntityPlugin.cs @@ -183,7 +183,7 @@ private Task HandleSetEntityVelocityPacket(SetEntityVelocityPacket packet) return Task.CompletedTask; } - (entity.Position as MutableVector3)!.Add( + (entity.Velocity as MutableVector3)!.Set( NetUtils.ConvertToVelocity(packet.VelocityX), NetUtils.ConvertToVelocity(packet.VelocityY), NetUtils.ConvertToVelocity(packet.VelocityZ) @@ -204,7 +204,7 @@ private Task HandleUpdateEntityPositionPacket(EntityPositionPacket packet) return Task.CompletedTask; } - (entity.Position as MutableVector3)!.Set( + (entity.Position as MutableVector3)!.Add( NetUtils.ConvertDeltaPosition(packet.DeltaX), NetUtils.ConvertDeltaPosition(packet.DeltaY), NetUtils.ConvertDeltaPosition(packet.DeltaZ) @@ -275,7 +275,7 @@ private Task HandleTeleportEntityPacket(TeleportEntityPacket packet) entity.Yaw = NetUtils.FromAngleByte(packet.Yaw); entity.Pitch = NetUtils.FromAngleByte(packet.Pitch); - + return OnEntityMoved.Dispatch(Bot, entity); } From 475deec17c7c4f1436b33c8caca0dc813768b6fd Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Tue, 6 Aug 2024 14:17:16 +0200 Subject: [PATCH 10/73] fix NRE when receiving chat message --- MineSharp.Bot/Plugins/ChatPlugin.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MineSharp.Bot/Plugins/ChatPlugin.cs b/MineSharp.Bot/Plugins/ChatPlugin.cs index adf32d58..b0466250 100644 --- a/MineSharp.Bot/Plugins/ChatPlugin.cs +++ b/MineSharp.Bot/Plugins/ChatPlugin.cs @@ -531,14 +531,14 @@ private Task HandleSystemChatMessage(SystemChatMessagePacket packet) { return packet switch { - SystemChatMessagePacket.Before192 before192 + SystemChatMessagePacket.Before192 before192 => HandleChatInternal(null, before192.Message, (ChatMessageType)before192.ChatType), - SystemChatMessagePacket.Since192 since192 + SystemChatMessagePacket.Since192 since192 => HandleChatInternal(null, since192.Message, since192.IsOverlay ? ChatMessageType.GameInfo : ChatMessageType.SystemMessage), - + _ => throw new UnreachableException() }; } @@ -581,7 +581,7 @@ private Task HandleChatInternal(Uuid? sender, ChatComponent.Chat message, ChatMe ChatComponent.Chat? content, ChatComponent.Chat? target) { - var entry = Bot.Registry["minecraft:chat_type"]["value"][index]; + var entry = Bot.Registry["chat_type"]["value"][index]; var name = entry["name"]!.StringValue!; var element = entry["element"]; var styleCompound = element["chat"]["style"]; From 5c360166d2fc9d95e185d80f39f904c5353d9bd9 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Tue, 6 Aug 2024 14:18:58 +0200 Subject: [PATCH 11/73] improved Raycast method --- MineSharp.Bot/Plugins/PhysicsPlugin.cs | 8 +++++--- MineSharp.Core/Common/Entities/MinecraftPlayer.cs | 7 ++++++- MineSharp.Core/Geometry/AABB.cs | 8 ++++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/MineSharp.Bot/Plugins/PhysicsPlugin.cs b/MineSharp.Bot/Plugins/PhysicsPlugin.cs index 761493a3..1cfb29bf 100644 --- a/MineSharp.Bot/Plugins/PhysicsPlugin.cs +++ b/MineSharp.Bot/Plugins/PhysicsPlugin.cs @@ -68,6 +68,7 @@ protected override async Task Init() worldPlugin = Bot.GetPlugin(); await playerPlugin.WaitForInitialization(); + await worldPlugin.WaitForInitialization(); self = playerPlugin.Self; await UpdateServerPos(); @@ -191,7 +192,7 @@ public Task LookAt(Block block, float smoothness = RotationSmoothness) /// Casts a ray from the players eyes, and returns the first block that is hit. /// /// - public (Block Block, BlockFace Face)? Raycast(double distance = 64) + public (Block Block, BlockFace Face, Aabb BlockCollisionShape, double Distance)? Raycast(double distance = 64) { if (distance < 0) { @@ -219,9 +220,10 @@ public Task LookAt(Block block, float smoothness = RotationSmoothness) { var blockBb = bb.Clone().Offset(block.Position.X, block.Position.Y, block.Position.Z); - if (blockBb.IntersectsLine(position, lookVector)) + var intersectionDistance = blockBb.IntersectsLine(position, lookVector); + if (intersectionDistance is not null) { - return (block, iterator.CurrentFace); + return (block, iterator.CurrentFace, bb, intersectionDistance.Value); } } } diff --git a/MineSharp.Core/Common/Entities/MinecraftPlayer.cs b/MineSharp.Core/Common/Entities/MinecraftPlayer.cs index f257af2c..18a44886 100644 --- a/MineSharp.Core/Common/Entities/MinecraftPlayer.cs +++ b/MineSharp.Core/Common/Entities/MinecraftPlayer.cs @@ -61,12 +61,17 @@ public class MinecraftPlayer( /// public EntityPose Pose { get; set; } = EntityPose.Standing; + /// + /// The offset for the player's eye height. + /// + public static readonly Vector3 PlayerEyeHeightOffset = new(0, 1.62, 0); + /// /// The position of this player's head. /// /// public Vector3 GetHeadPosition() { - return Entity!.Position.Plus(Vector3.Up); + return Entity!.Position.Plus(PlayerEyeHeightOffset); } } diff --git a/MineSharp.Core/Geometry/AABB.cs b/MineSharp.Core/Geometry/AABB.cs index da296bf9..8955a5b3 100644 --- a/MineSharp.Core/Geometry/AABB.cs +++ b/MineSharp.Core/Geometry/AABB.cs @@ -111,7 +111,7 @@ public bool Contains(Vector3 point) /// /// /// - public bool IntersectsLine(Vector3 origin, Vector3 direction) + public double? IntersectsLine(Vector3 origin, Vector3 direction) { direction = direction.Normalized(); @@ -125,7 +125,11 @@ public bool IntersectsLine(Vector3 origin, Vector3 direction) var tMin = Math.Max(Math.Max(Math.Min(tMinX, tMaxX), Math.Min(tMinY, tMaxY)), Math.Min(tMinZ, tMaxZ)); var tMax = Math.Min(Math.Min(Math.Max(tMinX, tMaxX), Math.Max(tMinY, tMaxY)), Math.Max(tMinZ, tMaxZ)); - return !(tMax < 0 || tMin > tMax); + if (!(tMax < 0 || tMin > tMax)) + { + return null; + } + return tMin; } /// From ae65fa5cff0785a5ecfc1281a93cfe92df11fba7 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Tue, 6 Aug 2024 17:14:59 +0200 Subject: [PATCH 12/73] fix world loading bugs --- MineSharp.Bot/Plugins/Plugin.cs | 21 ++++++++++++- MineSharp.Bot/Plugins/WorldPlugin.cs | 44 ++++++++++------------------ 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/MineSharp.Bot/Plugins/Plugin.cs b/MineSharp.Bot/Plugins/Plugin.cs index ddaf0a54..2127f9b1 100644 --- a/MineSharp.Bot/Plugins/Plugin.cs +++ b/MineSharp.Bot/Plugins/Plugin.cs @@ -1,4 +1,6 @@ -using NLog; +using MineSharp.Protocol.Packets; +using NLog; +using static MineSharp.Protocol.MinecraftClient; namespace MineSharp.Bot.Plugins; @@ -48,6 +50,7 @@ protected virtual Task Init() /// /// This method is called each minecraft tick. (About 20 times a second.) + /// It should stop (cancel) when the is cancelled. /// /// public virtual Task OnTick() @@ -105,6 +108,22 @@ public Task WaitForInitialization() return initializationTask.Task; } + private AsyncPacketHandler CreateAfterInitializationPacketHandlerWrapper(AsyncPacketHandler packetHandler) + where TPacket : IPacket + { + return async param => + { + await WaitForInitialization(); + await packetHandler(param); + }; + } + + public void OnPacketAfterInitialization(AsyncPacketHandler packetHandler) + where TPacket : IPacket + { + Bot.Client.On(CreateAfterInitializationPacketHandlerWrapper(packetHandler)); + } + internal async Task Initialize() { if (IsLoaded) diff --git a/MineSharp.Bot/Plugins/WorldPlugin.cs b/MineSharp.Bot/Plugins/WorldPlugin.cs index b1c3ea06..20ed1bf7 100644 --- a/MineSharp.Bot/Plugins/WorldPlugin.cs +++ b/MineSharp.Bot/Plugins/WorldPlugin.cs @@ -30,27 +30,28 @@ public class WorldPlugin : Plugin /// public WorldPlugin(MineSharpBot bot) : base(bot) { - World = WorldVersion.CreateWorld(Bot.Data); - - Bot.Client.On(HandleChunkDataAndLightUpdatePacket); - Bot.Client.On(HandleUnloadChunkPacket); - Bot.Client.On(HandleBlockUpdatePacket); - Bot.Client.On(HandleMultiBlockUpdatePacket); - Bot.Client.On(HandleChunkBatchStartPacket); - Bot.Client.On(HandleChunkBatchFinishedPacket); + OnPacketAfterInitialization(HandleChunkDataAndLightUpdatePacket); + OnPacketAfterInitialization(HandleUnloadChunkPacket); + OnPacketAfterInitialization(HandleBlockUpdatePacket); + OnPacketAfterInitialization(HandleMultiBlockUpdatePacket); + OnPacketAfterInitialization(HandleChunkBatchStartPacket); + OnPacketAfterInitialization(HandleChunkBatchFinishedPacket); } /// /// The world of the Minecraft server /// - public IWorld World { get; } + public IWorld World { get; private set; } /// - protected override Task Init() + protected override async Task Init() { playerPlugin = Bot.GetPlugin(); windowPlugin = Bot.GetPlugin(); - return Task.CompletedTask; + + await playerPlugin.WaitForInitialization(); + var dimension = playerPlugin.Self!.Dimension; + World = WorldVersion.CreateWorld(Bot.Data, dimension); } /// @@ -330,24 +331,9 @@ private Task HandleMultiBlockUpdatePacket(MultiBlockUpdatePacket packet) return Task.CompletedTask; } - var sectionX = packet.ChunkSection >> 42; - var sectionY = (packet.ChunkSection << 44) >> 44; - var sectionZ = (packet.ChunkSection << 22) >> 42; - - if (sectionX > Math.Pow(2, 21)) - { - sectionX -= (int)Math.Pow(2, 22); - } - - if (sectionY > Math.Pow(2, 19)) - { - sectionY -= (int)Math.Pow(2, 20); - } - - if (sectionZ > Math.Pow(2, 21)) - { - sectionZ -= (int)Math.Pow(2, 22); - } + var sectionX = packet.ChunkSection >> (64 - 22); // first 22 bits + var sectionZ = (packet.ChunkSection << 22) >> (64 - 22); // next 22 bits + var sectionY = (packet.ChunkSection << (22 + 22)) >> (64 - 20); // last 20 bits var coords = new ChunkCoordinates((int)sectionX, (int)sectionZ); var chunk = World!.GetChunkAt(coords); From 17b6fb247797f7ae4f5a79e3d393ba6c21614721 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Tue, 6 Aug 2024 17:17:36 +0200 Subject: [PATCH 13/73] reworked packet send/receive and gamestate logic; improved bot cancellation --- .../MineSharp.Protocol/MinecraftClient.cs | 304 ++++++++++++------ .../MineSharp.Protocol/MinecraftStream.cs | 160 ++++----- .../Handlers/ConfigurationPacketHandler.cs | 9 +- .../Handlers/GameStatePacketHandler.cs | 18 ++ .../Handlers/HandshakePacketHandler.cs | 12 +- .../Packets/Handlers/LoginPacketHandler.cs | 9 +- .../Packets/Handlers/PlayPacketHandler.cs | 16 +- .../Packets/Handlers/StatusPacketHandler.cs | 14 +- MineSharp.Bot/MineSharpBot.cs | 45 ++- MineSharp.Core/Common/PacketBuffer.cs | 39 ++- .../Concurrency/ConcurrencyHelper.cs | 78 +++++ 11 files changed, 458 insertions(+), 246 deletions(-) create mode 100644 Components/MineSharp.Protocol/Packets/Handlers/GameStatePacketHandler.cs create mode 100644 MineSharp.Core/Concurrency/ConcurrencyHelper.cs diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index 8c826dd6..f0d0c1e0 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -2,12 +2,14 @@ using System.Diagnostics; using System.Net; using System.Net.Sockets; +using System.Threading.Tasks.Dataflow; using MineSharp.Auth; using MineSharp.ChatComponent; using MineSharp.ChatComponent.Components; using MineSharp.Core; using MineSharp.Core.Common; using MineSharp.Core.Common.Protocol; +using MineSharp.Core.Concurrency; using MineSharp.Core.Events; using MineSharp.Data; using MineSharp.Data.Protocol; @@ -25,9 +27,9 @@ namespace MineSharp.Protocol; /// /// A Minecraft client. -/// Connect to a minecraft server. +/// Connect to a Minecraft server. /// -public sealed class MinecraftClient : IDisposable +public sealed class MinecraftClient : IAsyncDisposable, IDisposable { /// /// Delegate for handling packets async @@ -57,16 +59,22 @@ public sealed class MinecraftClient : IDisposable private readonly TaskCompletionSource gameJoinedTsc; /// - /// The Hostname of the minecraft server provided in the constructor + /// The Hostname of the Minecraft server provided in the constructor /// public readonly string Hostname; - private readonly IPAddress ip; - private readonly IDictionary> packetHandlers; - private readonly ConcurrentQueue packetQueue; - private readonly ConcurrentQueue<(PacketType, PacketBuffer)> bundledPackets; + private readonly IPAddress ip; + private readonly IDictionary> packetHandlers; + private readonly BufferBlock packetQueue; + private readonly ConcurrentQueue<(PacketType, PacketBuffer)> bundledPackets; private readonly IDictionary> packetWaiters; - private readonly CancellationTokenSource cancellationTokenSource; + private readonly CancellationTokenSource cancellationTokenSource; + + /// + /// Is cancelled once the client needs to stop. Usually because the connection was lost. + /// + // This variable exists (and is not a property) to prevent the possible problem when getting the token from the source when it's already disposed. + public readonly CancellationToken CancellationToken; /// /// The Port of the minecraft server @@ -82,21 +90,29 @@ public sealed class MinecraftClient : IDisposable /// The clients settings /// public readonly ClientSettings Settings; - + /// /// Fires when the client disconnected from the server /// public AsyncEvent OnDisconnected = new(); + /// + /// Fired when the TCP connection to the server is lost. + /// This is called after but also in cases where is not called before. + /// + /// If you want to be notified when the client is no longer functional, register to instead. + /// is also cancelled when the connection is lost. + /// + public AsyncEvent OnConnectionLost = new(); + private readonly IConnectionFactory tcpTcpFactory; - private TcpClient? client; + private TcpClient? client; private MinecraftStream? stream; - private Task? streamLoop; - private GameState gameState; - private IPacketHandler internalPacketHandler; - private object streamLock = new(); - private bool bundlePackets; + private int onConnectionLostFired; + private Task? streamLoop; + private GameStatePacketHandler gameStatePacketHandler; + private bool bundlePackets; /// /// Create a new MinecraftClient @@ -111,9 +127,13 @@ public MinecraftClient( ClientSettings settings) { Data = data; - packetQueue = new(); cancellationTokenSource = new(); - internalPacketHandler = new HandshakePacketHandler(this); + CancellationToken = cancellationTokenSource.Token; + packetQueue = new(new DataflowBlockOptions() + { + CancellationToken = CancellationToken + }); + gameStatePacketHandler = new HandshakePacketHandler(this); packetHandlers = new Dictionary>(); packetWaiters = new Dictionary>(); gameJoinedTsc = new(); @@ -125,18 +145,58 @@ public MinecraftClient( Session = session; Port = port; Hostname = hostnameOrIp; - gameState = GameState.Handshaking; Settings = settings; } - /// - public void Dispose() + /// + /// Must only be called after the was completed (this happens when was cancelled). + /// Otherwise race conditions can occur where there are still uncancelled tasks in the queue. + /// + private void CancelAllSendPendingPacketTasks() + { + // we need to cancel all tasks in the queue otherwise we might get a deadlock + // when some task is waiting for the packet task + if (packetQueue.TryReceiveAll(out var queuedPackets)) + { + foreach (var task in queuedPackets) + { + task.Task.TrySetCanceled(CancellationToken); + } + } + } + + private async Task DisposeInternal(bool calledFromStreamLoop) { cancellationTokenSource.Cancel(); - streamLoop?.Wait(); + // wait for the packetQueue to complete + await packetQueue.Completion; + CancelAllSendPendingPacketTasks(); + + // prevent waiting on ourselves (when called from the streamLoop task) + if (!calledFromStreamLoop) + { + await (streamLoop ?? Task.CompletedTask); + } client?.Dispose(); stream?.Close(); + + if (Interlocked.Exchange(ref onConnectionLostFired, 1) == 0) + { + await OnConnectionLost.Dispatch(this); + } + } + + public async ValueTask DisposeAsync() + { + await DisposeInternal(false); + } + + + /// + public void Dispose() + { + DisposeAsync().AsTask().Wait(); } /// @@ -178,40 +238,60 @@ public async Task Connect(GameState nextState) /// The packet to send. /// Optional cancellation token. /// A task that resolves once the packet was actually sent. - public Task SendPacket(IPacket packet, CancellationToken cancellation = default) + public async Task SendPacket(IPacket packet, CancellationToken cancellation = default) { var sendingTask = new PacketSendTask(packet, cancellation, new()); - packetQueue.Enqueue(sendingTask); + try + { + if (!await packetQueue.SendAsync(sendingTask, cancellation)) + { + // if the packetQueue is completed we can not send any more packets + // so we need to cancel the task here + // this must have happened because the CancellationToken was cancelled + sendingTask.Task.TrySetCanceled(CancellationToken); + } + } + catch (OperationCanceledException e) + { + sendingTask.Task.TrySetCanceled(e.CancellationToken); + throw; + } - return sendingTask.Task.Task; + await sendingTask.Task.Task; } + private Task? disconnectTask; + /// /// Disconnects the client from the server. /// /// The reason the client disconnected. Only used for the event. /// - public async Task Disconnect(Chat? reason = null) + public EnsureOnlyRunOnceAsyncResult Disconnect(Chat? reason = null) + { + return ConcurrencyHelper.EnsureOnlyRunOnceAsync(() => DisconnectInternal(reason), ref disconnectTask); + } + + private async Task DisconnectInternal(Chat? reason = null) { reason ??= new TranslatableComponent("disconnect.quitting"); - - Logger.Info($"Disconnecting: {reason.GetMessage(this.Data)}"); - if (!gameJoinedTsc.Task.IsCompleted) - { - gameJoinedTsc.SetException(new DisconnectedException("Client has been disconnected", reason.GetMessage(this.Data))); - } + var message = reason.GetMessage(Data); + Logger.Info($"Disconnecting: {message}"); + + gameJoinedTsc.TrySetException(new DisconnectedException("Client has been disconnected", message)); if (client is null || !client.Connected) { Logger.Warn("Disconnect() was called but client is not connected"); } - cancellationTokenSource.Cancel(); + await cancellationTokenSource.CancelAsync(); await (streamLoop ?? Task.CompletedTask); client?.Close(); await OnDisconnected.Dispatch(this, reason); + await OnConnectionLost.Dispatch(this); } /// @@ -241,19 +321,17 @@ public void On(AsyncPacketHandler handler) where T : IPacket public Task WaitForPacket() where T : IPacket { var packetType = PacketPalette.GetPacketType(); - if (!packetWaiters.TryGetValue(packetType, out var task)) + if (!packetWaiters.TryGetValue(packetType, out var tsc)) { - var tsc = new TaskCompletionSource(); + tsc = new TaskCompletionSource(); packetWaiters.Add(packetType, tsc); - - return tsc.Task.ContinueWith(prev => (T)prev.Result); } - return task.Task.ContinueWith(prev => (T)prev.Result); + return tsc.Task.ContinueWith(prev => (T)prev.Result); } /// - /// Waits until the client jumps into the Play + /// Waits until the client jumps into the state. /// /// public Task WaitForGame() @@ -263,20 +341,15 @@ public Task WaitForGame() internal void UpdateGameState(GameState next) { - lock (streamLock) + gameStatePacketHandler = next switch { - gameState = next; - - internalPacketHandler = next switch - { - GameState.Handshaking => new HandshakePacketHandler(this), - GameState.Login => new LoginPacketHandler(this, Data), - GameState.Status => new StatusPacketHandler(this), - GameState.Configuration => new ConfigurationPacketHandler(this, Data), - GameState.Play => new PlayPacketHandler(this, Data), - _ => throw new UnreachableException() - }; - } + GameState.Handshaking => new HandshakePacketHandler(this), + GameState.Login => new LoginPacketHandler(this, Data), + GameState.Status => new StatusPacketHandler(this), + GameState.Configuration => new ConfigurationPacketHandler(this, Data), + GameState.Play => new PlayPacketHandler(this, Data), + _ => throw new UnreachableException() + }; if (next == GameState.Play && !gameJoinedTsc.Task.IsCompleted) { @@ -299,7 +372,7 @@ internal void UpdateGameState(GameState next) if (next == GameState.Configuration) { - SendPacket(new ClientInformationPacket( + _ = SendPacket(new ClientInformationPacket( Settings.Locale, Settings.ViewDistance, (int)Settings.ChatMode, @@ -313,18 +386,12 @@ internal void UpdateGameState(GameState next) internal void EnableEncryption(byte[] key) { - lock (streamLock) - { - stream!.EnableEncryption(key); - } + stream!.EnableEncryption(key); } internal void SetCompression(int threshold) { - lock (streamLock) - { - stream!.SetCompression(threshold); - } + stream!.SetCompression(threshold); } internal void HandleBundleDelimiter() @@ -352,36 +419,51 @@ internal void HandleBundleDelimiter() Logger.Debug("Bundling packets!"); } } - + private async Task StreamLoop() { - while (!cancellationTokenSource.Token.IsCancellationRequested) + try { - try + while (!CancellationToken.IsCancellationRequested) { - await ReceivePackets(); - await SendPackets(); + try + { + // run both tasks in parallel + var receiveTask = Task.Run(ReceivePackets); + var sendTask = Task.Run(SendPackets); - await Task.Delay(1); - } - catch (Exception ex) - { - Logger.Error(ex, "Encountered error in stream loop"); + // extract the exception from the task that finished first + await await Task.WhenAny(receiveTask, sendTask); + // DisposeInternal in the catch block will then stop the other task + } + catch (Exception ex) + { + if (ex is SocketException or IOException) + { + // we probably can not continue after this + throw; + } + Logger.Error(ex, "Encountered error in stream loop"); + } } } + catch (Exception e) + { + Logger.Error(e, "Encountered exception in outer stream loop. Connection will be terminated."); + await DisposeInternal(true); + } } private async Task ReceivePackets() { - while (client!.Available > 0 && !cancellationTokenSource.IsCancellationRequested) + while (true) { - PacketBuffer buffer; - lock (streamLock) - { - buffer = stream!.ReadPacket(); - } - + CancellationToken.ThrowIfCancellationRequested(); + + var buffer = stream!.ReadPacket(); + var packetId = buffer.ReadVarInt(); + var gameState = gameStatePacketHandler.GameState; var packetType = Data.Protocol.GetPacketType(PacketFlow.Clientbound, gameState, packetId); if (gameState == GameState.Login) @@ -399,36 +481,41 @@ private async Task ReceivePackets() _ = Task.Run(() => HandleIncomingPacket(packetType, buffer)); } } - - if (gameState != GameState.Play) - { - await Task.Delay(1); - } } } - private Task SendPackets() + private async Task SendPackets() { - if (!packetQueue.TryDequeue(out var task)) - { - return Task.CompletedTask; - } - - if (task.Token is { IsCancellationRequested: true }) + await foreach (var task in packetQueue.ReceiveAllAsync()) { - return Task.CompletedTask; - } + if (task.Token.IsCancellationRequested) + { + task.Task.TrySetCanceled(); + continue; + } - DispatchPacket(task.Packet); - - - _ = Task.Run(async () => - { - task.Task.TrySetResult(); - await HandleOutgoingPacket(task.Packet); - }); + try + { + DispatchPacket(task.Packet); + task.Task.TrySetResult(); - return Task.CompletedTask; + // TODO: this feels wrong + // we probably should ask outgoing packet listeners before sending the packet + await HandleOutgoingPacket(task.Packet); + } + catch (SocketException e) + { + Logger.Error(e, "Encountered exception while dispatching packet {packetType}", task.Packet.Type); + task.Task.TrySetException(e); + // break the loop to prevent further packets from being sent + // because the connection is probably dead + throw; + } + catch (Exception e) + { + task.Task.TrySetException(e); + } + } } private void DispatchPacket(IPacket packet) @@ -439,11 +526,16 @@ private void DispatchPacket(IPacket packet) buffer.WriteVarInt(packetId); packet.Write(buffer, Data); - lock (streamLock) + try { Logger.Trace("Sending packet {packetType}", packet.Type); stream!.WritePacket(buffer); } + catch (SocketException e) + { + Logger.Error(e, "Encountered exception while dispatching packet {packetType}", packet.Type); + throw; + } } private async Task HandleIncomingPacket(PacketType packetType, PacketBuffer buffer) @@ -454,7 +546,7 @@ private async Task HandleIncomingPacket(PacketType packetType, PacketBuffer buff // - MinecraftClient.WaitForPacket() // - MinecraftClient.OnPacketReceived <-- Forces all packets to be parsed // - The internal IPacketHandler - + Logger.Trace("Received packet {packetType}", packetType); var factory = PacketPalette.GetFactory(packetType); if (factory == null) @@ -466,9 +558,9 @@ private async Task HandleIncomingPacket(PacketType packetType, PacketBuffer buff var handlers = new List(); // Internal packet handler - if (internalPacketHandler.HandlesIncoming(packetType)) + if (gameStatePacketHandler.HandlesIncoming(packetType)) { - handlers.Add(internalPacketHandler.HandleIncoming); + handlers.Add(gameStatePacketHandler.HandleIncoming); } // Custom packet handlers @@ -518,7 +610,7 @@ private async Task HandleOutgoingPacket(IPacket packet) { try { - await internalPacketHandler.HandleOutgoing(packet); + await gameStatePacketHandler.HandleOutgoing(packet); } catch (Exception e) { @@ -592,5 +684,5 @@ public static async Task AutodetectServerVersion(string hostname, return await MinecraftData.FromVersion(status.Version); } - private record PacketSendTask(IPacket Packet, CancellationToken? Token, TaskCompletionSource Task); + private record PacketSendTask(IPacket Packet, CancellationToken Token, TaskCompletionSource Task); } diff --git a/Components/MineSharp.Protocol/MinecraftStream.cs b/Components/MineSharp.Protocol/MinecraftStream.cs index 26e1910f..7ec877aa 100644 --- a/Components/MineSharp.Protocol/MinecraftStream.cs +++ b/Components/MineSharp.Protocol/MinecraftStream.cs @@ -9,19 +9,25 @@ namespace MineSharp.Protocol; /// /// Handles reading and writing packets. /// Also handles encryption and compression. -/// This class is not thread-safe. +/// This class is thread-safe. /// internal class MinecraftStream { private const int CompressionDisabled = -1; private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); - private readonly Deflater deflater = new(); - private readonly Inflater inflater = new(); private readonly NetworkStream networkStream; private readonly int protocolVersion; + + // Always acquire the readLock before the writeLock if both are needed + private readonly object readLock = new(); + private readonly object writeLock = new(); + + private readonly ThreadLocal inflater = new(() => new()); + private readonly ThreadLocal deflater = new(() => new()); + private int compressionThreshold; private AesStream? encryptionStream; @@ -32,7 +38,7 @@ public MinecraftStream(NetworkStream networkStream, int protocolVersion) this.protocolVersion = protocolVersion; this.networkStream = networkStream; stream = this.networkStream; - + compressionThreshold = CompressionDisabled; } @@ -40,7 +46,7 @@ public void EnableEncryption(byte[] sharedSecret) { Logger.Debug("Enabling encryption."); encryptionStream = new(networkStream, sharedSecret); - stream = encryptionStream; + stream = encryptionStream; } public void SetCompression(int threshold) @@ -50,41 +56,50 @@ public void SetCompression(int threshold) public PacketBuffer ReadPacket() { - var uncompressedLength = 0; - var length = ReadVarInt(out _); + var localCompressionThreshold = compressionThreshold; - if (compressionThreshold != CompressionDisabled) + lock (readLock) { - uncompressedLength = ReadVarInt(out var r); - length -= r; - } + var uncompressedLength = 0; + var length = PacketBuffer.ReadVarInt(stream, out _); - var data = new byte[length]; - - var read = 0; - while (read < length) - { - read += stream.Read(data, read, length - read); - } - - var packetBuffer = uncompressedLength switch - { - > 0 => DecompressBuffer(data, uncompressedLength), - _ => new(data, protocolVersion) - }; + if (localCompressionThreshold != CompressionDisabled) + { + uncompressedLength = PacketBuffer.ReadVarInt(stream, out var r); + length -= r; + } - return packetBuffer; + var data = new byte[length]; + + var read = 0; + while (read < length) + { + read += stream.Read(data, read, length - read); + } + + var packetBuffer = uncompressedLength switch + { + > 0 => DecompressBuffer(data, uncompressedLength), + _ => new(data, protocolVersion) + }; + + return packetBuffer; + } } public void WritePacket(PacketBuffer buffer) { - if (compressionThreshold > 0) + var localCompressionThreshold = compressionThreshold; + if (localCompressionThreshold > 0) + { + buffer = CompressBuffer(buffer, localCompressionThreshold); + } + + lock (writeLock) { - buffer = CompressBuffer(buffer); + PacketBuffer.WriteVarInt(stream, (int)buffer.Size); + stream.Write(buffer.GetBuffer()); } - - WriteVarInt((int)buffer.Size); - stream.Write(buffer.GetBuffer().AsSpan()); } private PacketBuffer DecompressBuffer(byte[] buffer, int length) @@ -95,86 +110,73 @@ private PacketBuffer DecompressBuffer(byte[] buffer, int length) } var buffer2 = new byte[length]; - inflater.SetInput(buffer); - inflater.Inflate(buffer2); - inflater.Reset(); + var localInflater = inflater.Value!; + localInflater.SetInput(buffer); + localInflater.Inflate(buffer2); + localInflater.Reset(); return new(buffer2, protocolVersion); } - private PacketBuffer CompressBuffer(PacketBuffer input) + // compressionThreshold is given as a parameter to make it thread-safe + private PacketBuffer CompressBuffer(PacketBuffer input, int compressionThreshold) { var output = new PacketBuffer(protocolVersion); + var buffer = input.GetBuffer(); + if (input.Size < compressionThreshold) { output.WriteVarInt(0); - output.WriteBytes(input.GetBuffer().AsSpan()); + output.WriteBytes(buffer); return output; } - var buffer = input.GetBuffer(); output.WriteVarInt(buffer.Length); - deflater.SetInput(buffer); - deflater.Finish(); + var localDeflater = deflater.Value!; + localDeflater.SetInput(buffer); + localDeflater.Finish(); var deflateBuf = new byte[8192]; - while (!deflater.IsFinished) + while (!localDeflater.IsFinished) { - var j = deflater.Deflate(deflateBuf); + var j = localDeflater.Deflate(deflateBuf); output.WriteBytes(deflateBuf.AsSpan(0, j)); } - deflater.Reset(); + localDeflater.Reset(); return output; } - private int ReadVarInt(out int read) + /// + /// This method checks if the stream is still connected. + /// This is method can be useful when you want to determine whether the stream is dead without reading or writing to it. + /// This is because the stream does not throw an exception when it is dead until you read or write to it. + /// + public bool CheckStreamUseable() { - var value = 0; - var length = 0; - byte currentByte; + var r = networkStream.Socket.Poll(0, SelectMode.SelectRead); - while (true) + if (r && !networkStream.DataAvailable) { - currentByte = (byte)stream.ReadByte(); - value |= (currentByte & 0x7F) << (length * 7); - - length++; - if (length > 5) - { - throw new("VarInt too big"); - } - - if ((currentByte & 0x80) != 0x80) - { - break; - } + // the socket got closed + // we would only get the exception next time we read or write to it + // so we do that now to get the exception + // we can not do this always because doing so would change the stream or block + var buffer = Array.Empty(); + networkStream.Socket.Receive(buffer, SocketFlags.Peek); // this will throw an exception + return false; } - - read = length; - return value; + return networkStream.Socket.Connected; } - private void WriteVarInt(int value) + public void Close() { - while (true) - { - if ((value & ~0x7F) == 0) + lock (readLock) + lock (writeLock) { - stream.WriteByte((byte)value); - return; + networkStream.Close(); + encryptionStream?.Close(); } - - stream.WriteByte((byte)((value & 0x7F) | 0x80)); - value >>= 7; - } - } - - - public void Close() - { - networkStream.Close(); - encryptionStream?.Close(); } } diff --git a/Components/MineSharp.Protocol/Packets/Handlers/ConfigurationPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/ConfigurationPacketHandler.cs index 26bed969..4594b53a 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/ConfigurationPacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/ConfigurationPacketHandler.cs @@ -9,7 +9,7 @@ namespace MineSharp.Protocol.Packets.Handlers; -internal class ConfigurationPacketHandler : IPacketHandler +internal class ConfigurationPacketHandler : GameStatePacketHandler { private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); @@ -17,12 +17,13 @@ internal class ConfigurationPacketHandler : IPacketHandler private readonly MinecraftData data; public ConfigurationPacketHandler(MinecraftClient client, MinecraftData data) + : base(GameState.Configuration) { this.client = client; this.data = data; } - public Task HandleIncoming(IPacket packet) + public override Task HandleIncoming(IPacket packet) { return packet switch { @@ -35,7 +36,7 @@ public Task HandleIncoming(IPacket packet) }; } - public Task HandleOutgoing(IPacket packet) + public override Task HandleOutgoing(IPacket packet) { if (packet is Serverbound.Configuration.FinishConfigurationPacket) { @@ -45,7 +46,7 @@ public Task HandleOutgoing(IPacket packet) return Task.CompletedTask; } - public bool HandlesIncoming(PacketType type) + public override bool HandlesIncoming(PacketType type) { return type is PacketType.CB_Configuration_Disconnect or PacketType.CB_Configuration_FinishConfiguration diff --git a/Components/MineSharp.Protocol/Packets/Handlers/GameStatePacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/GameStatePacketHandler.cs new file mode 100644 index 00000000..3dff6289 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Handlers/GameStatePacketHandler.cs @@ -0,0 +1,18 @@ +using MineSharp.Core.Common.Protocol; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Handlers; + +internal abstract class GameStatePacketHandler : IPacketHandler +{ + public readonly GameState GameState; + + protected GameStatePacketHandler(GameState gameState) + { + GameState = gameState; + } + + public abstract Task HandleIncoming(IPacket packet); + public abstract Task HandleOutgoing(IPacket packet); + public abstract bool HandlesIncoming(PacketType type); +} diff --git a/Components/MineSharp.Protocol/Packets/Handlers/HandshakePacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/HandshakePacketHandler.cs index fe076364..7cae3007 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/HandshakePacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/HandshakePacketHandler.cs @@ -1,24 +1,26 @@ -using MineSharp.Data.Protocol; +using MineSharp.Core.Common.Protocol; +using MineSharp.Data.Protocol; using MineSharp.Protocol.Exceptions; using MineSharp.Protocol.Packets.Serverbound.Handshaking; namespace MineSharp.Protocol.Packets.Handlers; -internal class HandshakePacketHandler : IPacketHandler +internal class HandshakePacketHandler : GameStatePacketHandler { private readonly MinecraftClient client; public HandshakePacketHandler(MinecraftClient client) + : base(GameState.Handshaking) { this.client = client; } - public Task HandleIncoming(IPacket packet) + public override Task HandleIncoming(IPacket packet) { return Task.CompletedTask; } - public Task HandleOutgoing(IPacket packet) + public override Task HandleOutgoing(IPacket packet) { return packet switch { @@ -28,7 +30,7 @@ public Task HandleOutgoing(IPacket packet) }; } - public bool HandlesIncoming(PacketType type) + public override bool HandlesIncoming(PacketType type) { return false; } diff --git a/Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs index 7fbfa5c7..963ebe5c 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs @@ -13,7 +13,7 @@ namespace MineSharp.Protocol.Packets.Handlers; -internal class LoginPacketHandler : IPacketHandler +internal class LoginPacketHandler : GameStatePacketHandler { private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); @@ -21,12 +21,13 @@ internal class LoginPacketHandler : IPacketHandler private readonly MinecraftData data; public LoginPacketHandler(MinecraftClient client, MinecraftData data) + : base(GameState.Login) { this.client = client; this.data = data; } - public Task HandleIncoming(IPacket packet) + public override Task HandleIncoming(IPacket packet) { return packet switch { @@ -38,12 +39,12 @@ public Task HandleIncoming(IPacket packet) }; } - public Task HandleOutgoing(IPacket packet) + public override Task HandleOutgoing(IPacket packet) { return Task.CompletedTask; } - public bool HandlesIncoming(PacketType type) + public override bool HandlesIncoming(PacketType type) { return type is PacketType.CB_Login_Disconnect or PacketType.CB_Login_EncryptionBegin diff --git a/Components/MineSharp.Protocol/Packets/Handlers/PlayPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/PlayPacketHandler.cs index f09187e6..96834e04 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/PlayPacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/PlayPacketHandler.cs @@ -1,4 +1,5 @@ -using MineSharp.Data; +using MineSharp.Core.Common.Protocol; +using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Packets.Clientbound.Play; using MineSharp.Protocol.Packets.Serverbound.Play; @@ -6,18 +7,19 @@ namespace MineSharp.Protocol.Packets.Handlers; -internal class PlayPacketHandler : IPacketHandler +internal class PlayPacketHandler : GameStatePacketHandler { private readonly MinecraftClient client; private readonly MinecraftData data; public PlayPacketHandler(MinecraftClient client, MinecraftData data) + : base(GameState.Play) { this.client = client; this.data = data; } - public Task HandleIncoming(IPacket packet) + public override Task HandleIncoming(IPacket packet) { return packet switch { @@ -29,12 +31,12 @@ public Task HandleIncoming(IPacket packet) }; } - public Task HandleOutgoing(IPacket packet) + public override Task HandleOutgoing(IPacket packet) { return Task.CompletedTask; } - public bool HandlesIncoming(PacketType type) + public override bool HandlesIncoming(PacketType type) { return type is PacketType.CB_Play_KeepAlive or PacketType.CB_Play_BundleDelimiter or PacketType.CB_Play_Ping or PacketType.CB_Play_KickDisconnect; @@ -42,7 +44,7 @@ public bool HandlesIncoming(PacketType type) private Task HandleKeepAlive(KeepAlivePacket packet) { - client.SendPacket(new Serverbound.Play.KeepAlivePacket(packet.KeepAliveId)); + _ = client.SendPacket(new Serverbound.Play.KeepAlivePacket(packet.KeepAliveId)); return Task.CompletedTask; } @@ -54,7 +56,7 @@ private Task HandleBundleDelimiter(BundleDelimiterPacket bundleDelimiter) private Task HandlePing(PingPacket ping) { - client.SendPacket(new PongPacket(ping.Id)); + _ = client.SendPacket(new PongPacket(ping.Id)); return Task.CompletedTask; } diff --git a/Components/MineSharp.Protocol/Packets/Handlers/StatusPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/StatusPacketHandler.cs index 4956f985..bb949540 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/StatusPacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/StatusPacketHandler.cs @@ -1,27 +1,29 @@ -using MineSharp.Data.Protocol; +using MineSharp.Core.Common.Protocol; +using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Handlers; -internal class StatusPacketHandler : IPacketHandler +internal class StatusPacketHandler : GameStatePacketHandler { - private MinecraftClient client; + private readonly MinecraftClient client; public StatusPacketHandler(MinecraftClient client) + : base(GameState.Status) { this.client = client; } - public Task HandleIncoming(IPacket packet) + public override Task HandleIncoming(IPacket packet) { return Task.CompletedTask; } - public Task HandleOutgoing(IPacket packet) + public override Task HandleOutgoing(IPacket packet) { return Task.CompletedTask; } - public bool HandlesIncoming(PacketType type) + public override bool HandlesIncoming(PacketType type) { return false; } diff --git a/MineSharp.Bot/MineSharpBot.cs b/MineSharp.Bot/MineSharpBot.cs index 90ae048f..4fb05140 100644 --- a/MineSharp.Bot/MineSharpBot.cs +++ b/MineSharp.Bot/MineSharpBot.cs @@ -2,9 +2,8 @@ using MineSharp.Auth; using MineSharp.Bot.Exceptions; using MineSharp.Bot.Plugins; -using MineSharp.ChatComponent.Components; using MineSharp.Core.Common.Protocol; -using MineSharp.Core.Events; +using MineSharp.Core.Concurrency; using MineSharp.Data; using MineSharp.Protocol; using MineSharp.Protocol.Packets.Clientbound.Configuration; @@ -17,16 +16,20 @@ namespace MineSharp.Bot; /// A Minecraft Bot. /// The Minecraft Bot uses Plugins that contain helper methods to handle and send minecraft packets. /// -public class MineSharpBot +public sealed class MineSharpBot : IAsyncDisposable, IDisposable { private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); - private readonly CancellationTokenSource cancellation; /// /// The underlying used by this bot /// public readonly MinecraftClient Client; + /// + /// Is cancelled once the client needs to stop. Usually because the connection was lost. + /// + public CancellationToken CancellationToken => Client!.CancellationToken; + /// /// The instance used by this bot /// @@ -44,11 +47,6 @@ public class MineSharpBot /// public NbtCompound Registry { get; private set; } = []; - /// - /// Fired when the bot disconnects - /// - public AsyncEvent OnBotDisconnected = new(); - // This field is used for syncing block updates since 1.19. internal int SequenceId = 0; @@ -64,10 +62,8 @@ public MineSharpBot(MinecraftClient client) Data = Client.Data; Session = Client.Session; - cancellation = new(); plugins = new Dictionary(); - Client.OnDisconnected += OnClientDisconnected; Client.On(packet => Task.FromResult(Registry = packet.RegistryData)); Client.On( packet => Task.FromResult(packet.RegistryCodec != null ? Registry = packet.RegistryCodec : null)); @@ -123,7 +119,7 @@ await Task.WhenAll( plugins.Values .Select(pl => pl.Initialize())); - tickLoop = TickLoop(); + tickLoop = Task.Run(TickLoop); return true; } @@ -132,22 +128,17 @@ await Task.WhenAll( /// Disconnect from the Minecraft server /// /// The reason for disconnecting - public async Task Disconnect(ChatComponent.Chat? reason = null) + public EnsureOnlyRunOnceAsyncResult Disconnect(ChatComponent.Chat? reason = null) { - reason ??= new TranslatableComponent("disconnect.quitting"); + // there is no point in waiting for the tickLoop + // it wil be cancelled when the bot disconnects - if (tickLoop is { Status: TaskStatus.Running }) - { - cancellation.Cancel(); - await tickLoop!; - } - - await Client.Disconnect(reason); + return Client.Disconnect(reason); } private async Task TickLoop() { - while (!cancellation.Token.IsCancellationRequested) + while (!CancellationToken.IsCancellationRequested) { var start = DateTime.Now; @@ -176,8 +167,14 @@ private async Task TickLoop() } } - private Task OnClientDisconnected(MinecraftClient sender, ChatComponent.Chat reason) + public void Dispose() + { + // TODO: improve packet callback registrations to be able to remove them here + } + + public ValueTask DisposeAsync() { - return OnBotDisconnected.Dispatch(this, reason); + Dispose(); + return ValueTask.CompletedTask; } } diff --git a/MineSharp.Core/Common/PacketBuffer.cs b/MineSharp.Core/Common/PacketBuffer.cs index bfb722e7..cae9e66c 100644 --- a/MineSharp.Core/Common/PacketBuffer.cs +++ b/MineSharp.Core/Common/PacketBuffer.cs @@ -253,16 +253,22 @@ public double ReadDouble() return BitConverter.ToDouble(bytes); } - public int ReadVarInt() + private const int VarIntSegmentBits = 0x7F; + private const int VarIntContinueBit = 0x80; + + // This method is also used by MinecraftStream + public static int ReadVarInt(Stream stream, out int byteCount) { var value = 0; var shift = 0; + byteCount = 0; while (true) { - var b = ReadByte(); - value |= (b & 0x7f) << shift; - if ((b & 0x80) == 0x00) + var b = stream.ReadByte(); + byteCount++; + value |= (b & VarIntSegmentBits) << shift; + if ((b & VarIntContinueBit) == 0x00) { break; } @@ -270,13 +276,18 @@ public int ReadVarInt() shift += 7; if (shift >= 32) { - throw new("varint is too big"); + throw new("VarInt is too big"); } } return value; } + public int ReadVarInt() + { + return ReadVarInt(buffer, out _); + } + public long ReadVarLong() { long value = 0; @@ -285,8 +296,8 @@ public long ReadVarLong() while (true) { var b = ReadByte(); - value |= (b & (long)0x7f) << shift; - if ((b & 0x80) == 0x00) + value |= (long)(b & VarIntSegmentBits) << shift; + if ((b & VarIntContinueBit) == 0x00) { break; } @@ -294,7 +305,7 @@ public long ReadVarLong() shift += 7; if (shift >= 64) { - throw new("varlong is too big"); + throw new("VarLong is too big"); } } @@ -549,21 +560,27 @@ public void WriteDouble(double value) WriteULong(val); } - public void WriteVarInt(int value) + // Is also used by MinecraftStream + public static void WriteVarInt(Stream stream, int value) { while (true) { if ((value & ~0x7F) == 0) { - buffer.WriteByte((byte)value); + stream.WriteByte((byte)value); return; } - buffer.WriteByte((byte)((value & 0x7F) | 0x80)); + stream.WriteByte((byte)((value & 0x7F) | 0x80)); value >>>= 7; } } + public void WriteVarInt(int value) + { + WriteVarInt(buffer, value); + } + public void WriteVarLong(int value) { while ((value & ~0x7F) != 0x00) diff --git a/MineSharp.Core/Concurrency/ConcurrencyHelper.cs b/MineSharp.Core/Concurrency/ConcurrencyHelper.cs new file mode 100644 index 00000000..d2991cc6 --- /dev/null +++ b/MineSharp.Core/Concurrency/ConcurrencyHelper.cs @@ -0,0 +1,78 @@ +using System.Runtime.CompilerServices; + +namespace MineSharp.Core.Concurrency; + +public record struct EnsureOnlyRunOnceAsyncResult(Task Task, bool FirstInvocation) +{ + public TaskAwaiter GetAwaiter() => Task.GetAwaiter(); +} +public record struct EnsureOnlyRunOnceAsyncResult(Task Task, bool FirstInvocation) +{ + public TaskAwaiter GetAwaiter() => Task.GetAwaiter(); +} + +public static class ConcurrencyHelper +{ + #region EnsureOnlyRunOnce + + /// + public static EnsureOnlyRunOnceAsyncResult EnsureOnlyRunOnceAsync(Func action, ref Task? taskStore) + { + var ret = EnsureOnlyRunOnceAsync(() => + { + var actualTask = action(); + // return value does mean nothing. Is just used to call the other method. + return actualTask.ContinueWith(_ => true, TaskContinuationOptions.ExecuteSynchronously); + }, + // this ref type conversion is safe because all Tasks with return type are also normal Tasks + ref Unsafe.As?>(ref taskStore)); + + return new(ret.Task, ret.FirstInvocation); + } + + /// + /// Ensures that the given async action is only run once while still returning the task of that first invocation for further calls. + /// + /// + /// The async action to execute once. + /// A reference to a variable holding the task of the first and only execution. + /// + public static EnsureOnlyRunOnceAsyncResult EnsureOnlyRunOnceAsync(Func> action, ref Task? taskStore) + { + var storedTask = taskStore; + if (storedTask is not null) + { + return new(storedTask, false); + } + + // we can use using here because this method is the only place where the cts is used + using var cts = new CancellationTokenSource(); + var newTaskWrapped = new Task>(action, cancellationToken: cts.Token); + // TODO: Check if Unwrap does forward OCE. If not use UnwrapSlow + var newTask = newTaskWrapped.Unwrap(); + //var newTask = UnwrapSlow(newTaskWrapped); + + var actualStoredTask = Interlocked.CompareExchange(ref taskStore, newTask, null); + if (ReferenceEquals(actualStoredTask, null)) + { + // we set the stored task to the new task + // and start the new task + + // important: start newTaskWrapped not newTask + newTaskWrapped.Start(); + return new(newTask, true); + } + + // some other task was faster and set the task + // cancel the new task + cts.Cancel(); + // and return the already started task + return new(actualStoredTask, false); + } + + private static async Task UnwrapSlow(Task> task) + { + return await await task; + } + #endregion +} From 60fb49bd55c4c51abf7a65d3d626b2383550c07a Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Tue, 6 Aug 2024 17:43:36 +0200 Subject: [PATCH 14/73] removed net7.0 for test projects --- .../MineSharp.Windows.Tests/MineSharp.Windows.Tests.csproj | 2 +- .../Tests/MineSharp.World.Tests/MineSharp.World.Tests.csproj | 2 +- Data/MineSharp.Data.Tests/MineSharp.Data.Tests.csproj | 2 +- .../MineSharp.Bot.IntegrationTests.csproj | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Components/Tests/MineSharp.Windows.Tests/MineSharp.Windows.Tests.csproj b/Components/Tests/MineSharp.Windows.Tests/MineSharp.Windows.Tests.csproj index 3046408b..eb124473 100644 --- a/Components/Tests/MineSharp.Windows.Tests/MineSharp.Windows.Tests.csproj +++ b/Components/Tests/MineSharp.Windows.Tests/MineSharp.Windows.Tests.csproj @@ -6,7 +6,7 @@ false - net7.0;net8.0 + net8.0 12 diff --git a/Components/Tests/MineSharp.World.Tests/MineSharp.World.Tests.csproj b/Components/Tests/MineSharp.World.Tests/MineSharp.World.Tests.csproj index 38d4f5fe..e7da4cb5 100644 --- a/Components/Tests/MineSharp.World.Tests/MineSharp.World.Tests.csproj +++ b/Components/Tests/MineSharp.World.Tests/MineSharp.World.Tests.csproj @@ -6,7 +6,7 @@ false - net7.0;net8.0 + net8.0 12 diff --git a/Data/MineSharp.Data.Tests/MineSharp.Data.Tests.csproj b/Data/MineSharp.Data.Tests/MineSharp.Data.Tests.csproj index 56b183fd..29ef82e5 100644 --- a/Data/MineSharp.Data.Tests/MineSharp.Data.Tests.csproj +++ b/Data/MineSharp.Data.Tests/MineSharp.Data.Tests.csproj @@ -6,7 +6,7 @@ false true - net8.0;net7.0 + net8.0 diff --git a/MineSharp.Bot.IntegrationTests/MineSharp.Bot.IntegrationTests.csproj b/MineSharp.Bot.IntegrationTests/MineSharp.Bot.IntegrationTests.csproj index 46f67fd7..2fef0621 100644 --- a/MineSharp.Bot.IntegrationTests/MineSharp.Bot.IntegrationTests.csproj +++ b/MineSharp.Bot.IntegrationTests/MineSharp.Bot.IntegrationTests.csproj @@ -4,7 +4,7 @@ Exe enable enable - net7.0;net8.0 + net8.0 12 false From 7b2ebc444699ef08949eb92ecb6f8454cfc98457 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Tue, 6 Aug 2024 18:13:37 +0200 Subject: [PATCH 15/73] improved PacketBuffer by using MemoryMarshal --- MineSharp.Core/Common/PacketBuffer.cs | 229 ++++++++++---------------- 1 file changed, 89 insertions(+), 140 deletions(-) diff --git a/MineSharp.Core/Common/PacketBuffer.cs b/MineSharp.Core/Common/PacketBuffer.cs index cae9e66c..bfe0df7c 100644 --- a/MineSharp.Core/Common/PacketBuffer.cs +++ b/MineSharp.Core/Common/PacketBuffer.cs @@ -1,4 +1,6 @@ -using System.Text; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; using System.Text.RegularExpressions; using fNbt; using MineSharp.Core.Common.Blocks; @@ -107,6 +109,23 @@ private void EnsureEnoughReadableBytes(int count) #region Reading + public T Read() + where T : unmanaged + { + Unsafe.SkipInit(out T value); + var typedSpan = MemoryMarshal.CreateSpan(ref value, 1); + var byteSpan = MemoryMarshal.AsBytes(typedSpan); + + ReadBytes(byteSpan); + + if (BitConverter.IsLittleEndian) + { + byteSpan.Reverse(); + } + + return value; + } + public int ReadBytes(Span bytes) { EnsureEnoughReadableBytes(bytes.Length); @@ -144,113 +163,66 @@ public byte ReadByte() return (byte)buffer.ReadByte(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public sbyte ReadSByte() { return (sbyte)ReadByte(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool ReadBool() { return ReadByte() == 1; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public ushort ReadUShort() { - EnsureEnoughReadableBytes(2); - - var b0 = buffer.ReadByte(); - var b1 = buffer.ReadByte(); - - if (BitConverter.IsLittleEndian) - { - return (ushort)((b0 << 8) | b1); - } - - return (ushort)(b0 | (b1 << 8)); + return Read(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public short ReadShort() { - return (short)ReadUShort(); + return Read(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public uint ReadUInt() { - EnsureEnoughReadableBytes(4); - - var b0 = buffer.ReadByte(); - var b1 = buffer.ReadByte(); - var b2 = buffer.ReadByte(); - var b3 = buffer.ReadByte(); - - if (BitConverter.IsLittleEndian) - { - return (uint)((b0 << 24) | (b1 << 16) | (b2 << 8) | b3); - } - - return (uint)(b0 | (b1 << 8) | (b2 << 16) | (b3 << 24)); + return Read(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public int ReadInt() { - return (int)ReadUInt(); + return Read(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public ulong ReadULong() { - EnsureEnoughReadableBytes(8); - - long b0 = buffer.ReadByte(); - long b1 = buffer.ReadByte(); - long b2 = buffer.ReadByte(); - long b3 = buffer.ReadByte(); - long b4 = buffer.ReadByte(); - long b5 = buffer.ReadByte(); - long b6 = buffer.ReadByte(); - long b7 = buffer.ReadByte(); - - if (BitConverter.IsLittleEndian) - { - return (ulong)((b0 << 56) | (b1 << 48) | (b2 << 40) | (b3 << 32) | (b4 << 24) | (b5 << 16) | (b6 << 8) | - b7); - } - - return (ulong)(b0 | (b1 << 8) | (b2 << 16) | (b3 << 24) | (b4 << 32) | (b5 << 40) | (b6 << 48) | (b7 << 56)); + return Read(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public long ReadLong() { - return (long)ReadULong(); + return Read(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public float ReadFloat() { - EnsureEnoughReadableBytes(4); - - Span bytes = stackalloc byte[sizeof(float)]; - ReadBytes(bytes); - - if (BitConverter.IsLittleEndian) - { - bytes.Reverse(); - } - - return BitConverter.ToSingle(bytes); + var bits = Read(); + return BitConverter.UInt32BitsToSingle(bits); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public double ReadDouble() { - EnsureEnoughReadableBytes(8); - - Span bytes = stackalloc byte[sizeof(double)]; - ReadBytes(bytes); - - if (BitConverter.IsLittleEndian) - { - bytes.Reverse(); - } - - return BitConverter.ToDouble(bytes); + var bits = Read(); + return BitConverter.UInt64BitsToDouble(bits); } private const int VarIntSegmentBits = 0x7F; @@ -283,6 +255,7 @@ public static int ReadVarInt(Stream stream, out int byteCount) return value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public int ReadVarInt() { return ReadVarInt(buffer, out _); @@ -323,10 +296,11 @@ public string ReadString(Encoding? encoding = null) return encoding.GetString(bytes); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Uuid ReadUuid() { - var l1 = ReadLong(); - var l2 = ReadLong(); + var l1 = Read(); + var l2 = Read(); return new(l1, l2); } @@ -349,7 +323,7 @@ public long[] ReadLongArray() for (var i = 0; i < array.Length; i++) { - array[i] = ReadLong(); + array[i] = Read(); } return array; @@ -405,7 +379,8 @@ public BlockEntity ReadBlockEntity() return new(x, y, z, type, nbt); } - public T? ReadOptional() where T : class + public T? ReadOptional() + where T : class { var available = ReadBool(); if (!available) @@ -413,10 +388,11 @@ public BlockEntity ReadBlockEntity() return null; } - return Read(); + return ReadObject(); } - public T? ReadOptional(bool _ = false) where T : struct + public T? ReadOptional(bool _ = false) + where T : unmanaged { var available = ReadBool(); if (!available) @@ -427,27 +403,14 @@ public BlockEntity ReadBlockEntity() return Read(); } - - public T Read() + public T ReadObject() + where T : class { var type = Type.GetTypeCode(typeof(T)); object value = type switch { - TypeCode.Boolean => ReadBool(), - TypeCode.SByte => ReadSByte(), - TypeCode.Byte => ReadByte(), - TypeCode.Int16 => ReadShort(), - TypeCode.Int32 => ReadInt(), - TypeCode.Int64 => ReadLong(), - - TypeCode.UInt16 => ReadUShort(), - TypeCode.UInt32 => ReadUInt(), - TypeCode.UInt64 => ReadULong(), - TypeCode.String => ReadString(), - TypeCode.Single => ReadFloat(), - TypeCode.Double => ReadBool(), _ => throw new NotSupportedException() }; return (T)value; @@ -458,106 +421,92 @@ public T Read() #region Writing - public void WriteBytes(Span bytes) + public void Write(T value) + where T : unmanaged + { + var typedSpan = MemoryMarshal.CreateSpan(ref value, 1); + var byteSpan = MemoryMarshal.AsBytes(typedSpan); + + if (BitConverter.IsLittleEndian) + { + byteSpan.Reverse(); + } + + WriteBytes(byteSpan); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteBytes(ReadOnlySpan bytes) { buffer.Write(bytes); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteBool(bool value) { WriteByte((byte)(value ? 1 : 0)); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteByte(byte b) { buffer.WriteByte(b); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteSByte(sbyte b) { WriteByte((byte)b); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteUShort(ushort value) { - if (BitConverter.IsLittleEndian) - { - WriteByte((byte)((value >> 8) & 0xFF)); - WriteByte((byte)(value & 0xFF)); - return; - } - - WriteByte((byte)(value & 0xFF)); - WriteByte((byte)((value >> 8) & 0xFF)); + Write(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteShort(short value) { - WriteUShort((ushort)value); + Write(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteUInt(uint value) { - if (BitConverter.IsLittleEndian) - { - WriteByte((byte)((value >> 24) & 0xFF)); - WriteByte((byte)((value >> 16) & 0xFF)); - WriteByte((byte)((value >> 8) & 0xFF)); - WriteByte((byte)(value & 0xFF)); - return; - } - - WriteByte((byte)(value & 0xFF)); - WriteByte((byte)((value >> 8) & 0xFF)); - WriteByte((byte)((value >> 16) & 0xFF)); - WriteByte((byte)((value >> 24) & 0xFF)); + Write(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteInt(int value) { - WriteUInt((uint)value); + Write(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteULong(ulong value) { - if (BitConverter.IsLittleEndian) - { - WriteByte((byte)((value >> 56) & 0xFF)); - WriteByte((byte)((value >> 48) & 0xFF)); - WriteByte((byte)((value >> 40) & 0xFF)); - WriteByte((byte)((value >> 32) & 0xFF)); - WriteByte((byte)((value >> 24) & 0xFF)); - WriteByte((byte)((value >> 16) & 0xFF)); - WriteByte((byte)((value >> 8) & 0xFF)); - WriteByte((byte)(value & 0xFF)); - return; - } - - WriteByte((byte)(value & 0xFF)); - WriteByte((byte)((value >> 8) & 0xFF)); - WriteByte((byte)((value >> 16) & 0xFF)); - WriteByte((byte)((value >> 24) & 0xFF)); - WriteByte((byte)((value >> 32) & 0xFF)); - WriteByte((byte)((value >> 40) & 0xFF)); - WriteByte((byte)((value >> 48) & 0xFF)); - WriteByte((byte)((value >> 56) & 0xFF)); + Write(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteLong(long value) { - WriteULong((ulong)value); + Write(value); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteFloat(float value) { var val = BitConverter.SingleToUInt32Bits(value); - WriteUInt(val); + Write(val); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void WriteDouble(double value) { var val = BitConverter.DoubleToUInt64Bits(value); - WriteULong(val); + Write(val); } // Is also used by MinecraftStream @@ -605,8 +554,8 @@ public void WriteString(string value, Encoding? encoding = null) public void WriteUuid(Uuid value) { - WriteLong(value.MostSignificantBits); - WriteLong(value.LeastSignificantBits); + Write(value.MostSignificantBits); + Write(value.LeastSignificantBits); } public void WriteVarIntArray(ICollection collection, Action writer) From 66374f6436e7d909384cbed77deabe321f844e11 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 7 Aug 2024 00:47:46 +0200 Subject: [PATCH 16/73] fixed negated condition bug in AABB.IntersectsLine --- MineSharp.Core/Geometry/AABB.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MineSharp.Core/Geometry/AABB.cs b/MineSharp.Core/Geometry/AABB.cs index 8955a5b3..abdd3bf6 100644 --- a/MineSharp.Core/Geometry/AABB.cs +++ b/MineSharp.Core/Geometry/AABB.cs @@ -125,7 +125,7 @@ public bool Contains(Vector3 point) var tMin = Math.Max(Math.Max(Math.Min(tMinX, tMaxX), Math.Min(tMinY, tMaxY)), Math.Min(tMinZ, tMaxZ)); var tMax = Math.Min(Math.Min(Math.Max(tMinX, tMaxX), Math.Max(tMinY, tMaxY)), Math.Max(tMinZ, tMaxZ)); - if (!(tMax < 0 || tMin > tMax)) + if (tMax < 0 || tMin > tMax) { return null; } From 51b07204dad40c1c24717ad2a72f10800f375c01 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 7 Aug 2024 00:58:08 +0200 Subject: [PATCH 17/73] created RaycastBlockResult record --- MineSharp.Bot/Plugins/PhysicsPlugin.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/MineSharp.Bot/Plugins/PhysicsPlugin.cs b/MineSharp.Bot/Plugins/PhysicsPlugin.cs index 1cfb29bf..2501fc06 100644 --- a/MineSharp.Bot/Plugins/PhysicsPlugin.cs +++ b/MineSharp.Bot/Plugins/PhysicsPlugin.cs @@ -188,11 +188,20 @@ public Task LookAt(Block block, float smoothness = RotationSmoothness) return LookAt(new Vector3(0.5, 0.5, 0.5).Plus(block.Position), smoothness); } + /// + /// Represents the result of a ray casting operation. + /// + /// The block that was hit by the ray. + /// The face of the block that was hit. + /// The index for the collision shape of the block that was hit. You can get the with: MineSharp.Bot.Data.BlockCollisionShapes.GetForBlock(block). + /// The distance from the ray origin to the hit point. + public record RaycastBlockResult(Block Block, BlockFace Face, int BlockCollisionShapeIndex, double Distance); + /// /// Casts a ray from the players eyes, and returns the first block that is hit. /// /// - public (Block Block, BlockFace Face, Aabb BlockCollisionShape, double Distance)? Raycast(double distance = 64) + public RaycastBlockResult? Raycast(double distance = 64) { if (distance < 0) { @@ -216,14 +225,15 @@ public Task LookAt(Block block, float smoothness = RotationSmoothness) var bbs = Bot.Data.BlockCollisionShapes.GetForBlock(block); - foreach (var bb in bbs) + for (int bbIndex = 0; bbIndex < bbs.Length; bbIndex++) { + var bb = bbs[bbIndex]; var blockBb = bb.Clone().Offset(block.Position.X, block.Position.Y, block.Position.Z); var intersectionDistance = blockBb.IntersectsLine(position, lookVector); if (intersectionDistance is not null) { - return (block, iterator.CurrentFace, bb, intersectionDistance.Value); + return new(block, iterator.CurrentFace, bbIndex, intersectionDistance.Value); } } } From c9674dcc763d86890597129e0b8d6b375972cd17 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 7 Aug 2024 01:22:40 +0200 Subject: [PATCH 18/73] improved exception handling in HandleIncomingPacket + small cleanup --- .../MineSharp.Protocol/MinecraftClient.cs | 67 +++++++++++++------ MineSharp.Bot/Plugins/PhysicsPlugin.cs | 4 +- 2 files changed, 50 insertions(+), 21 deletions(-) diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index f0d0c1e0..91fb28ff 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -77,7 +77,7 @@ public sealed class MinecraftClient : IAsyncDisposable, IDisposable public readonly CancellationToken CancellationToken; /// - /// The Port of the minecraft server + /// The Port of the Minecraft server /// public readonly ushort Port; @@ -114,6 +114,13 @@ public sealed class MinecraftClient : IAsyncDisposable, IDisposable private GameStatePacketHandler gameStatePacketHandler; private bool bundlePackets; + /// + /// The current of the client. + /// + /// Internal note: This property should not be used to determine the next because that is not thread safe. + /// + public GameState GameState => gameStatePacketHandler.GameState; + /// /// Create a new MinecraftClient /// @@ -505,7 +512,7 @@ private async Task SendPackets() } catch (SocketException e) { - Logger.Error(e, "Encountered exception while dispatching packet {packetType}", task.Packet.Type); + Logger.Error(e, "Encountered exception while dispatching packet {PacketType}", task.Packet.Type); task.Task.TrySetException(e); // break the loop to prevent further packets from being sent // because the connection is probably dead @@ -528,12 +535,12 @@ private void DispatchPacket(IPacket packet) try { - Logger.Trace("Sending packet {packetType}", packet.Type); + Logger.Trace("Sending packet {PacketType}", packet.Type); stream!.WritePacket(buffer); } catch (SocketException e) { - Logger.Error(e, "Encountered exception while dispatching packet {packetType}", packet.Type); + Logger.Error(e, "Encountered exception while dispatching packet {PacketType}", packet.Type); throw; } } @@ -557,7 +564,7 @@ private async Task HandleIncomingPacket(PacketType packetType, PacketBuffer buff var handlers = new List(); - // Internal packet handler + // GameState packet handler if (gameStatePacketHandler.HandlesIncoming(packetType)) { handlers.Add(gameStatePacketHandler.HandleIncoming); @@ -584,19 +591,32 @@ private async Task HandleIncomingPacket(PacketType packetType, PacketBuffer buff await buffer.DisposeAsync(); tsc?.TrySetResult(packet); - var tasks = handlers - .Select(task => task(packet)) - .ToArray(); + var packetHandlersTasks = new List(); try { - await Task.WhenAll(tasks); + // Run all handlers in parallel: + foreach (var handler in handlers) + { + // The synchronous part of the handlers might throw an exception + // So we also do this in a try-catch block + try + { + packetHandlersTasks.Add(handler(packet)); + } + catch (Exception e) + { + Logger.Warn(e, "An packet handler for packet of type {PacketType} threw an exception.", packetType); + } + } + + await Task.WhenAll(packetHandlersTasks); } catch (Exception) { - foreach (var exception in tasks.Where(x => x.Exception != null)) + foreach (var faultedTask in packetHandlersTasks.Where(task => task.Status == TaskStatus.Faulted)) { - Logger.Warn($"Error in custom packet handling: {exception.Exception}"); + Logger.Warn(faultedTask.Exception, "An packet handler for packet of type {PacketType} threw an exception.", packetType); } } } @@ -620,13 +640,17 @@ private async Task HandleOutgoingPacket(IPacket packet) /// /// Requests the server status and closes the connection. - /// Works only when is . + /// Works only when is . /// + /// The hostname or IP of the server. + /// The port of the server. + /// The time in milliseconds to wait for a response. + /// The factory to create the TCP connection. /// public static async Task RequestServerStatus( string hostnameOrIp, ushort port = 25565, - int timeout = 10000, + int responseTimeout = 10000, IConnectionFactory? tcpFactory = null) { var latest = await MinecraftData.FromVersion(LATEST_SUPPORTED_VERSION); @@ -644,7 +668,8 @@ public static async Task RequestServerStatus( throw new MineSharpHostException("failed to connect to server"); } - var timeoutCancellation = new CancellationTokenSource(); + var responseTimeoutCts = new CancellationTokenSource(); + var responseTimeoutCancellationToken = responseTimeoutCts.Token; var taskCompletionSource = new TaskCompletionSource(); client.On(async packet => @@ -659,13 +684,17 @@ public static async Task RequestServerStatus( client.Dispose(); }); - await client.SendPacket(new StatusRequestPacket(), timeoutCancellation.Token); - await client.SendPacket(new PingRequestPacket(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()), timeoutCancellation.Token); + await client.SendPacket(new StatusRequestPacket(), responseTimeoutCancellationToken); + await client.SendPacket(new PingRequestPacket(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()), responseTimeoutCancellationToken); - timeoutCancellation.Token.Register( - () => taskCompletionSource.TrySetCanceled(timeoutCancellation.Token)); + responseTimeoutCancellationToken.Register( + () => + { + taskCompletionSource.TrySetCanceled(responseTimeoutCancellationToken); + responseTimeoutCts.Dispose(); + }); - timeoutCancellation.CancelAfter(timeout); + responseTimeoutCts.CancelAfter(responseTimeout); return await taskCompletionSource.Task; } diff --git a/MineSharp.Bot/Plugins/PhysicsPlugin.cs b/MineSharp.Bot/Plugins/PhysicsPlugin.cs index 2501fc06..6b16dc2d 100644 --- a/MineSharp.Bot/Plugins/PhysicsPlugin.cs +++ b/MineSharp.Bot/Plugins/PhysicsPlugin.cs @@ -331,7 +331,7 @@ private void OnSneakingChanged(PlayerPhysics sender, bool isSneaking) : EntityActionPacket.EntityAction.StopSneaking, 0); - Bot.Client.SendPacket(packet); + _ = Bot.Client.SendPacket(packet); } private void OnSprintingChanged(PlayerPhysics sender, bool isSprinting) @@ -343,7 +343,7 @@ private void OnSprintingChanged(PlayerPhysics sender, bool isSprinting) : EntityActionPacket.EntityAction.StopSprinting, 0); - Bot.Client.SendPacket(packet); + _ = Bot.Client.SendPacket(packet); } private record PlayerState From 24cba927e40fe0c12ff19b48d4000b9b8c169649 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 7 Aug 2024 01:39:56 +0200 Subject: [PATCH 19/73] made packet handler dictionaries thread-safe --- .../MineSharp.Protocol/MinecraftClient.cs | 60 +++++++++---------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index 91fb28ff..14f00442 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -56,19 +56,12 @@ public sealed class MinecraftClient : IAsyncDisposable, IDisposable /// public readonly MinecraftData Data; - private readonly TaskCompletionSource gameJoinedTsc; - /// /// The Hostname of the Minecraft server provided in the constructor /// public readonly string Hostname; private readonly IPAddress ip; - private readonly IDictionary> packetHandlers; - private readonly BufferBlock packetQueue; - private readonly ConcurrentQueue<(PacketType, PacketBuffer)> bundledPackets; - private readonly IDictionary> packetWaiters; - private readonly CancellationTokenSource cancellationTokenSource; /// /// Is cancelled once the client needs to stop. Usually because the connection was lost. @@ -109,10 +102,20 @@ public sealed class MinecraftClient : IAsyncDisposable, IDisposable private TcpClient? client; private MinecraftStream? stream; - private int onConnectionLostFired; private Task? streamLoop; + private int onConnectionLostFired; + + private readonly ConcurrentDictionary> packetHandlers; + private readonly ConcurrentDictionary> packetWaiters; private GameStatePacketHandler gameStatePacketHandler; + private readonly BufferBlock packetQueue; private bool bundlePackets; + private readonly ConcurrentQueue<(PacketType, PacketBuffer)> bundledPackets; + + private readonly CancellationTokenSource cancellationTokenSource; + + private readonly TaskCompletionSource gameJoinedTcs; + /// /// The current of the client. @@ -141,9 +144,9 @@ public MinecraftClient( CancellationToken = CancellationToken }); gameStatePacketHandler = new HandshakePacketHandler(this); - packetHandlers = new Dictionary>(); - packetWaiters = new Dictionary>(); - gameJoinedTsc = new(); + packetHandlers = new(); + packetWaiters = new(); + gameJoinedTcs = new(); bundledPackets = new(); tcpTcpFactory = tcpFactory; ip = IpHelper.ResolveHostname(hostnameOrIp, ref port); @@ -194,6 +197,7 @@ private async Task DisposeInternal(bool calledFromStreamLoop) } } + /// public async ValueTask DisposeAsync() { await DisposeInternal(false); @@ -286,7 +290,7 @@ private async Task DisconnectInternal(Chat? reason = null) var message = reason.GetMessage(Data); Logger.Info($"Disconnecting: {message}"); - gameJoinedTsc.TrySetException(new DisconnectedException("Client has been disconnected", message)); + gameJoinedTcs.TrySetException(new DisconnectedException("Client has been disconnected", message)); if (client is null || !client.Connected) { @@ -311,13 +315,8 @@ public void On(AsyncPacketHandler handler) where T : IPacket { var key = PacketPalette.GetPacketType(); - if (!packetHandlers.TryGetValue(key, out var handlers)) - { - handlers = new List(); - packetHandlers.Add(key, handlers); - } - - handlers.Add(p => handler((T)p)); + packetHandlers.GetOrAdd(key, _ => new ConcurrentBag()) + .Add(p => handler((T)p)); } /// @@ -328,13 +327,8 @@ public void On(AsyncPacketHandler handler) where T : IPacket public Task WaitForPacket() where T : IPacket { var packetType = PacketPalette.GetPacketType(); - if (!packetWaiters.TryGetValue(packetType, out var tsc)) - { - tsc = new TaskCompletionSource(); - packetWaiters.Add(packetType, tsc); - } - - return tsc.Task.ContinueWith(prev => (T)prev.Result); + var tcs = packetWaiters.GetOrAdd(packetType, _ => new TaskCompletionSource()); + return tcs.Task.ContinueWith(prev => (T)prev.Result); } /// @@ -343,7 +337,7 @@ public Task WaitForPacket() where T : IPacket /// public Task WaitForGame() { - return gameJoinedTsc.Task; + return gameJoinedTcs.Task; } internal void UpdateGameState(GameState next) @@ -358,7 +352,7 @@ internal void UpdateGameState(GameState next) _ => throw new UnreachableException() }; - if (next == GameState.Play && !gameJoinedTsc.Task.IsCompleted) + if (next == GameState.Play && !gameJoinedTcs.Task.IsCompleted) { if (Data.Version.Protocol <= ProtocolVersion.V_1_20) { @@ -374,7 +368,7 @@ internal void UpdateGameState(GameState next) Settings.EnableTextFiltering, Settings.AllowServerListings))); } - gameJoinedTsc.TrySetResult(); + gameJoinedTcs.TrySetResult(); } if (next == GameState.Configuration) @@ -554,7 +548,7 @@ private async Task HandleIncomingPacket(PacketType packetType, PacketBuffer buff // - MinecraftClient.OnPacketReceived <-- Forces all packets to be parsed // - The internal IPacketHandler - Logger.Trace("Received packet {packetType}", packetType); + Logger.Trace("Received packet {PacketType}", packetType); var factory = PacketPalette.GetFactory(packetType); if (factory == null) { @@ -576,9 +570,9 @@ private async Task HandleIncomingPacket(PacketType packetType, PacketBuffer buff handlers.AddRange(customHandlers); } - packetWaiters.TryGetValue(packetType, out var tsc); + packetWaiters.TryGetValue(packetType, out var tcs); - if (handlers.Count == 0 && tsc == null) + if (handlers.Count == 0 && tcs == null) { await buffer.DisposeAsync(); return; @@ -590,7 +584,7 @@ private async Task HandleIncomingPacket(PacketType packetType, PacketBuffer buff var packet = factory(buffer, Data); await buffer.DisposeAsync(); - tsc?.TrySetResult(packet); + tcs?.TrySetResult(packet); var packetHandlersTasks = new List(); try From ece2a50122c73606afc47f412935710fe97c3a0a Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 7 Aug 2024 02:16:44 +0200 Subject: [PATCH 20/73] improvements to Plugin and OnPacketAfterInitialization --- MineSharp.Bot/Plugins/PhysicsPlugin.cs | 6 ++-- MineSharp.Bot/Plugins/Plugin.cs | 41 ++++++++++++++++++-------- MineSharp.Bot/Plugins/WorldPlugin.cs | 21 ++++++------- 3 files changed, 43 insertions(+), 25 deletions(-) diff --git a/MineSharp.Bot/Plugins/PhysicsPlugin.cs b/MineSharp.Bot/Plugins/PhysicsPlugin.cs index 6b16dc2d..5e57c11c 100644 --- a/MineSharp.Bot/Plugins/PhysicsPlugin.cs +++ b/MineSharp.Bot/Plugins/PhysicsPlugin.cs @@ -73,7 +73,7 @@ protected override async Task Init() self = playerPlugin.Self; await UpdateServerPos(); - Engine = new(Bot.Data, self!, worldPlugin.World, InputControls); + Engine = new(Bot.Data, self!, worldPlugin.World!, InputControls); Engine.OnCrouchingChanged += OnSneakingChanged; Engine.OnSprintingChanged += OnSprintingChanged; } @@ -217,7 +217,7 @@ public record RaycastBlockResult(Block Block, BlockFace Face, int BlockCollision foreach (var pos in iterator.Iterate()) { - var block = worldPlugin!.World.GetBlockAt(pos); + var block = worldPlugin!.World!.GetBlockAt(pos); if (!block.IsSolid()) { continue; @@ -242,7 +242,7 @@ public record RaycastBlockResult(Block Block, BlockFace Face, int BlockCollision } /// - public override Task OnTick() + protected internal override Task OnTick() { if (!IsLoaded) { diff --git a/MineSharp.Bot/Plugins/Plugin.cs b/MineSharp.Bot/Plugins/Plugin.cs index 2127f9b1..17455236 100644 --- a/MineSharp.Bot/Plugins/Plugin.cs +++ b/MineSharp.Bot/Plugins/Plugin.cs @@ -13,6 +13,11 @@ public abstract class Plugin private readonly TaskCompletionSource initializationTask; + /// + /// The bot + /// + protected readonly MineSharpBot Bot; + /// /// Create a new Plugin instance /// @@ -24,11 +29,6 @@ protected Plugin(MineSharpBot bot) initializationTask = new(); } - /// - /// The bot - /// - protected MineSharpBot Bot { get; } - /// /// Whether this plugin is currently enabled /// @@ -36,8 +36,10 @@ protected Plugin(MineSharpBot bot) /// /// Whether this plugin is loaded and functional + /// + /// /// - public bool IsLoaded { get; private set; } + public bool IsLoaded => initializationTask.Task.IsCompleted; /// /// This method is called once when the plugin starts. @@ -53,7 +55,7 @@ protected virtual Task Init() /// It should stop (cancel) when the is cancelled. /// /// - public virtual Task OnTick() + protected internal virtual Task OnTick() { return Task.CompletedTask; } @@ -108,20 +110,36 @@ public Task WaitForInitialization() return initializationTask.Task; } - private AsyncPacketHandler CreateAfterInitializationPacketHandlerWrapper(AsyncPacketHandler packetHandler) + private AsyncPacketHandler CreateAfterInitializationPacketHandlerWrapper(AsyncPacketHandler packetHandler, bool queuePacketsSentBeforeInitializationCompleted = false) where TPacket : IPacket { return async param => { - await WaitForInitialization(); + if (queuePacketsSentBeforeInitializationCompleted) + { + await WaitForInitialization(); + } + else + { + if (!IsLoaded) + { + return; + } + } await packetHandler(param); }; } - public void OnPacketAfterInitialization(AsyncPacketHandler packetHandler) + /// + /// Registers a packet handler that is only invoked after the plugin has been initialized. + /// + /// The type of the packet. + /// The packet handler to be called. + /// Whether packets sent before the plugin has been initialized should be queued and processed after initialization. + public void OnPacketAfterInitialization(AsyncPacketHandler packetHandler, bool queuePacketsSentBeforeInitializationCompleted = false) where TPacket : IPacket { - Bot.Client.On(CreateAfterInitializationPacketHandlerWrapper(packetHandler)); + Bot.Client.On(CreateAfterInitializationPacketHandlerWrapper(packetHandler, queuePacketsSentBeforeInitializationCompleted)); } internal async Task Initialize() @@ -137,7 +155,6 @@ internal async Task Initialize() initializationTask.TrySetResult(); - IsLoaded = true; Logger.Info("Plugin loaded: {PluginName}", GetType().Name); } catch (Exception e) diff --git a/MineSharp.Bot/Plugins/WorldPlugin.cs b/MineSharp.Bot/Plugins/WorldPlugin.cs index 20ed1bf7..7108888d 100644 --- a/MineSharp.Bot/Plugins/WorldPlugin.cs +++ b/MineSharp.Bot/Plugins/WorldPlugin.cs @@ -12,7 +12,7 @@ namespace MineSharp.Bot.Plugins; /// -/// World plugin handles all kind of packets regarding the minecraft world, +/// World plugin handles all kind of packets regarding the Minecraft world, /// and provides methods to interact with it, like mining and digging. /// public class WorldPlugin : Plugin @@ -30,18 +30,19 @@ public class WorldPlugin : Plugin /// public WorldPlugin(MineSharpBot bot) : base(bot) { - OnPacketAfterInitialization(HandleChunkDataAndLightUpdatePacket); - OnPacketAfterInitialization(HandleUnloadChunkPacket); - OnPacketAfterInitialization(HandleBlockUpdatePacket); - OnPacketAfterInitialization(HandleMultiBlockUpdatePacket); - OnPacketAfterInitialization(HandleChunkBatchStartPacket); - OnPacketAfterInitialization(HandleChunkBatchFinishedPacket); + // we want all the packets. Even those that are sent before the plugin is initialized. + OnPacketAfterInitialization(HandleChunkDataAndLightUpdatePacket, true); + OnPacketAfterInitialization(HandleUnloadChunkPacket, true); + OnPacketAfterInitialization(HandleBlockUpdatePacket, true); + OnPacketAfterInitialization(HandleMultiBlockUpdatePacket, true); + OnPacketAfterInitialization(HandleChunkBatchStartPacket, true); + OnPacketAfterInitialization(HandleChunkBatchFinishedPacket, true); } /// /// The world of the Minecraft server /// - public IWorld World { get; private set; } + public IWorld? World { get; private set; } /// protected override async Task Init() @@ -74,7 +75,7 @@ public async Task WaitForChunks(int radius = 5) for (var z = chunkCoords.Z - radius; z <= chunkCoords.Z + radius; z++) { var coords = new ChunkCoordinates(x, z); - while (!World.IsChunkLoaded(coords)) + while (!World!.IsChunkLoaded(coords)) { await Task.Delay(10); } @@ -289,7 +290,7 @@ private Task HandleChunkDataAndLightUpdatePacket(ChunkDataAndUpdateLightPacket p } var coords = new ChunkCoordinates(packet.X, packet.Z); - var chunk = World.CreateChunk(coords, packet.BlockEntities); + var chunk = World!.CreateChunk(coords, packet.BlockEntities); chunk.LoadData(packet.ChunkData); World!.LoadChunk(chunk); From af2bd44e97e6ddfb3d4dae12222d4b79c133dfed Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 7 Aug 2024 02:33:47 +0200 Subject: [PATCH 21/73] refactoring in EncryptionHelper --- .../Connection/IConnectionFactory.cs | 4 ++ .../Cryptography/AesStream.cs | 5 +- .../Cryptography/EncryptionHelper.cs | 51 ++++++------------- 3 files changed, 22 insertions(+), 38 deletions(-) diff --git a/Components/MineSharp.Protocol/Connection/IConnectionFactory.cs b/Components/MineSharp.Protocol/Connection/IConnectionFactory.cs index 8396f8f0..46c8e28e 100644 --- a/Components/MineSharp.Protocol/Connection/IConnectionFactory.cs +++ b/Components/MineSharp.Protocol/Connection/IConnectionFactory.cs @@ -16,5 +16,9 @@ public interface IConnectionFactory /// public Task CreateOpenConnection(IPAddress address, ushort port); + /// + /// Create an HTTP client + /// + /// public HttpClient CreateHttpClient(); } diff --git a/Components/MineSharp.Protocol/Cryptography/AesStream.cs b/Components/MineSharp.Protocol/Cryptography/AesStream.cs index ad64c514..f601f066 100644 --- a/Components/MineSharp.Protocol/Cryptography/AesStream.cs +++ b/Components/MineSharp.Protocol/Cryptography/AesStream.cs @@ -22,11 +22,12 @@ public class AesStream : Stream /// public AesStream(Stream stream, byte[] key) { + var cipherParameters = new ParametersWithIV(new KeyParameter(key), key, 0, 16); encryptCipher = new(new CfbBlockCipher(new AesEngine(), 8)); - encryptCipher.Init(true, new ParametersWithIV(new KeyParameter(key), key, 0, 16)); + encryptCipher.Init(true, cipherParameters); decryptCipher = new(new CfbBlockCipher(new AesEngine(), 8)); - decryptCipher.Init(false, new ParametersWithIV(new KeyParameter(key), key, 0, 16)); + decryptCipher.Init(false, cipherParameters); baseStream = new CipherStream(stream, decryptCipher, encryptCipher); } diff --git a/Components/MineSharp.Protocol/Cryptography/EncryptionHelper.cs b/Components/MineSharp.Protocol/Cryptography/EncryptionHelper.cs index ff31c87f..732dc691 100644 --- a/Components/MineSharp.Protocol/Cryptography/EncryptionHelper.cs +++ b/Components/MineSharp.Protocol/Cryptography/EncryptionHelper.cs @@ -7,15 +7,16 @@ namespace MineSharp.Protocol.Cryptography; -internal class EncryptionHelper +internal partial class EncryptionHelper { private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); + private static readonly ReadOnlyMemory SeqOid = new([0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00]); + public static RSA? DecodePublicKey(byte[] publicKeyBytes) { var ms = new MemoryStream(publicKeyBytes); var rd = new BinaryReader(ms); - byte[] seqOid = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 }; var seq = new byte[15]; try @@ -45,7 +46,7 @@ internal class EncryptionHelper seq = rd.ReadBytes(15); - if (!CompareBytearrays(seq, seqOid)) + if (!seq.AsSpan().SequenceEqual(SeqOid.Span)) { return null; } @@ -96,16 +97,16 @@ internal class EncryptionHelper var rsa = RSA.Create(); //RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(parms); - var rsAparams = new RSAParameters(); + var rsaParams = new RSAParameters(); - rsAparams.Modulus = rd.ReadBytes(DecodeIntegerSize(rd)); + rsaParams.Modulus = rd.ReadBytes(DecodeIntegerSize(rd)); - GetTraits(rsAparams.Modulus.Length * 8, out var sizeMod, out var sizeExp); + GetTraits(rsaParams.Modulus.Length * 8, out var sizeMod, out var sizeExp); - rsAparams.Modulus = AlignBytes(rsAparams.Modulus, sizeMod); - rsAparams.Exponent = AlignBytes(rd.ReadBytes(DecodeIntegerSize(rd)), sizeExp); + rsaParams.Modulus = AlignBytes(rsaParams.Modulus, sizeMod); + rsaParams.Exponent = AlignBytes(rd.ReadBytes(DecodeIntegerSize(rd)), sizeExp); - rsa.ImportParameters(rsAparams); + rsa.ImportParameters(rsaParams); return rsa; } @@ -121,28 +122,6 @@ internal class EncryptionHelper } } - private static bool CompareBytearrays(byte[] a, byte[] b) - { - if (a.Length != b.Length) - { - return false; - } - - var i = 0; - - foreach (var c in a) - { - if (c != b[i]) - { - return false; - } - - i++; - } - - return true; - } - private static byte[] AlignBytes(byte[] inputBytes, int alignSize) { var inputBytesSize = inputBytes.Length; @@ -151,10 +130,7 @@ private static byte[] AlignBytes(byte[] inputBytes, int alignSize) { var buf = new byte[alignSize]; - for (var i = 0; i < inputBytesSize; ++i) - { - buf[i + (alignSize - inputBytesSize)] = inputBytes[i]; - } + inputBytes.CopyTo(buf.AsSpan().Slice(alignSize - inputBytesSize)); return buf; } @@ -254,7 +230,7 @@ private static void GetTraits(int modulusLengthInBits, out int sizeMod, out int public static string PemKeyToDer(string pem) { - var rx = new Regex("-+[^-]+-+"); + var rx = PemKeyHeaderFooterRegex(); var der = rx.Replace(pem, "") .Replace("\r", "") .Replace("\n", ""); @@ -279,4 +255,7 @@ public static string ComputeHash(string serverId, byte[] key, byte[] publicKey) return hex.TrimStart('0'); } + + [GeneratedRegex("-+[^-]+-+")] + private static partial Regex PemKeyHeaderFooterRegex(); } From c52d76849998783b9856545b28798068225992b1 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 7 Aug 2024 02:47:49 +0200 Subject: [PATCH 22/73] overhauled PacketPalette and added IPacket.StaticType --- .../MineSharp.Protocol/MinecraftClient.cs | 4 +- .../Configuration/DisconnectPacket.cs | 3 +- .../Configuration/FeatureFlagsPacket.cs | 3 +- .../FinishConfigurationPacket.cs | 3 +- .../Configuration/KeepAlivePacket.cs | 3 +- .../Clientbound/Configuration/PingPacket.cs | 5 +- .../Configuration/PluginMessagePacket.cs | 3 +- .../Configuration/RegistryDataPacket.cs | 3 +- .../Clientbound/Login/DisconnectPacket.cs | 3 +- .../Login/EncryptionRequestPacket.cs | 3 +- .../Login/LoginPluginRequestPacket.cs | 3 +- .../Clientbound/Login/LoginSuccessPacket.cs | 3 +- .../Clientbound/Login/SetCompressionPacket.cs | 3 +- .../Play/AcknowledgeBlockChangePacket.cs | 3 +- .../Clientbound/Play/BlockUpdatePacket.cs | 3 +- .../Clientbound/Play/BundleDelimiterPacket.cs | 3 +- .../Packets/Clientbound/Play/ChatPacket.cs | 3 +- .../Play/ChunkBatchFinishedPacket.cs | 3 +- .../Clientbound/Play/ChunkBatchStartPacket.cs | 3 +- .../Play/ChunkDataAndUpdateLightPacket.cs | 3 +- .../Clientbound/Play/CloseWindowPacket.cs | 3 +- .../Clientbound/Play/CombatDeathPacket.cs | 3 +- .../Clientbound/Play/DeclareCommandsPacket.cs | 3 +- .../Clientbound/Play/DisconnectPacket.cs | 3 +- .../Play/DisguisedChatMessagePacket.cs | 3 +- .../Play/EntityPositionAndRotationPacket.cs | 3 +- .../Clientbound/Play/EntityPositionPacket.cs | 3 +- .../Clientbound/Play/EntityRotationPacket.cs | 3 +- .../Play/EntitySoundEffectPacket.cs | 3 +- .../Clientbound/Play/EntityStatusPacket.cs | 3 +- .../Clientbound/Play/GameEventPacket.cs | 3 +- .../Clientbound/Play/KeepAlivePacket.cs | 3 +- .../Packets/Clientbound/Play/LoginPacket.cs | 3 +- .../Play/MultiBlockUpdatePacket.cs | 3 +- .../Clientbound/Play/OpenWindowPacket.cs | 3 +- .../Clientbound/Play/ParticlePacket.cs | 3 +- .../Packets/Clientbound/Play/PingPacket.cs | 3 +- .../Clientbound/Play/PlayerChatPacket.cs | 3 +- .../Play/PlayerInfoRemovePacket.cs | 3 +- .../Play/PlayerInfoUpdatePacket.cs | 3 +- .../Clientbound/Play/PlayerPositionPacket.cs | 3 +- .../Clientbound/Play/RemoveEntitiesPacket.cs | 3 +- .../Packets/Clientbound/Play/RespawnPacket.cs | 3 +- .../Play/SetEntityVelocityPacket.cs | 3 +- .../Clientbound/Play/SetHealthPacket.cs | 3 +- .../Clientbound/Play/SetHeldItemPacket.cs | 3 +- .../Clientbound/Play/SetPassengersPacket.cs | 3 +- .../Clientbound/Play/SoundEffectPacket.cs | 3 +- .../Clientbound/Play/SpawnEntityPacket.cs | 3 +- .../Play/SpawnLivingEntityPacket.cs | 3 +- .../Clientbound/Play/SpawnPaintingPacket.cs | 3 +- .../Clientbound/Play/SpawnPlayerPacket.cs | 3 +- .../Play/SystemChatMessagePacket.cs | 3 +- .../Clientbound/Play/TeleportEntityPacket.cs | 3 +- .../Clientbound/Play/UnloadChunkPacket.cs | 3 +- .../Play/UpdateAttributesPacket.cs | 3 +- .../Clientbound/Play/WindowItemsPacket.cs | 3 +- .../Clientbound/Play/WindowSetSlotPacket.cs | 3 +- .../Clientbound/Status/PongResponsePacket.cs | 3 +- .../Status/StatusResponsePacket.cs | 3 +- .../MineSharp.Protocol/Packets/IPacket.cs | 10 +- .../Packets/PacketPalette.cs | 226 +++++++++--------- .../Configuration/ClientInformationPacket.cs | 3 +- .../FinishConfigurationPacket.cs | 3 +- .../Configuration/KeepAlivePacket.cs | 3 +- .../Configuration/PluginMessagePacket.cs | 3 +- .../Serverbound/Configuration/PongPacket.cs | 3 +- .../ResourcePackResponsePacket.cs | 3 +- .../Handshaking/HandshakePacket.cs | 3 +- .../Login/AcknowledgeLoginPacket.cs | 3 +- .../Login/EncryptionResponsePacket.cs | 3 +- .../Login/LoginPluginResponsePacket.cs | 3 +- .../Serverbound/Login/LoginStartPacket.cs | 3 +- .../Serverbound/Play/ChatCommandPacket.cs | 3 +- .../Serverbound/Play/ChatMessagePacket.cs | 3 +- .../Packets/Serverbound/Play/ChatPacket.cs | 3 +- .../Play/ChunkBatchReceivedPacket.cs | 3 +- .../Serverbound/Play/ClientCommandPacket.cs | 3 +- .../Play/ClientInformationPacket.cs | 3 +- .../Serverbound/Play/CloseWindowPacket.cs | 3 +- .../Serverbound/Play/ConfirmTeleportPacket.cs | 3 +- .../Serverbound/Play/EntityActionPacket.cs | 3 +- .../Serverbound/Play/InteractPacket.cs | 3 +- .../Serverbound/Play/KeepAlivePacket.cs | 3 +- .../Play/MessageAcknowledgementPacket.cs | 3 +- .../Serverbound/Play/PlaceBlockPacket.cs | 3 +- .../Serverbound/Play/PlayerActionPacket.cs | 3 +- .../Serverbound/Play/PlayerSessionPacket.cs | 3 +- .../Packets/Serverbound/Play/PongPacket.cs | 3 +- .../Serverbound/Play/SetCreativeSlotPacket.cs | 3 +- .../Serverbound/Play/SetHeldItemPacket.cs | 3 +- .../SetPlayerPositionAndRotationPacket.cs | 3 +- .../Play/SetPlayerPositionPacket.cs | 3 +- .../Serverbound/Play/SwingArmPacket.cs | 3 +- .../Serverbound/Play/UpdateCommandBlock.cs | 3 +- .../Packets/Serverbound/Play/UseItemPacket.cs | 3 +- .../Serverbound/Play/WindowClickPacket.cs | 3 +- .../Serverbound/Status/PingRequestPacket.cs | 3 +- .../Serverbound/Status/StatusRequestPacket.cs | 3 +- 99 files changed, 315 insertions(+), 215 deletions(-) diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index 14f00442..27cb8f67 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -313,7 +313,7 @@ private async Task DisconnectInternal(Chat? reason = null) /// The type of the packet public void On(AsyncPacketHandler handler) where T : IPacket { - var key = PacketPalette.GetPacketType(); + var key = T.StaticType; packetHandlers.GetOrAdd(key, _ => new ConcurrentBag()) .Add(p => handler((T)p)); @@ -326,7 +326,7 @@ public void On(AsyncPacketHandler handler) where T : IPacket /// A task that completes once the packet is received public Task WaitForPacket() where T : IPacket { - var packetType = PacketPalette.GetPacketType(); + var packetType = T.StaticType; var tcs = packetWaiters.GetOrAdd(packetType, _ => new TaskCompletionSource()); return tcs.Task.ContinueWith(prev => (T)prev.Result); } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/DisconnectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/DisconnectPacket.cs index b4208fe8..e1d3a4fa 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/DisconnectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/DisconnectPacket.cs @@ -12,7 +12,8 @@ namespace MineSharp.Protocol.Packets.Clientbound.Configuration; public class DisconnectPacket : IPacket { /// - public PacketType Type => PacketType.CB_Configuration_Disconnect; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Configuration_Disconnect; /// /// Reason for disconnect diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FeatureFlagsPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FeatureFlagsPacket.cs index aa3e8914..05e879e5 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FeatureFlagsPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FeatureFlagsPacket.cs @@ -11,7 +11,8 @@ namespace MineSharp.Protocol.Packets.Clientbound.Configuration; public class FeatureFlagsPacket : IPacket { /// - public PacketType Type => PacketType.CB_Configuration_FeatureFlags; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Configuration_FeatureFlags; /// /// The enabled feature flags diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FinishConfigurationPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FinishConfigurationPacket.cs index fb2fe8df..f974146d 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FinishConfigurationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FinishConfigurationPacket.cs @@ -11,7 +11,8 @@ namespace MineSharp.Protocol.Packets.Clientbound.Configuration; public class FinishConfigurationPacket : IPacket { /// - public PacketType Type => PacketType.CB_Configuration_FinishConfiguration; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Configuration_FinishConfiguration; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/KeepAlivePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/KeepAlivePacket.cs index 6acf9b59..9482d4fe 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/KeepAlivePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/KeepAlivePacket.cs @@ -11,7 +11,8 @@ namespace MineSharp.Protocol.Packets.Clientbound.Configuration; public class KeepAlivePacket : IPacket { /// - public PacketType Type => PacketType.CB_Configuration_KeepAlive; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Configuration_KeepAlive; /// /// The keep alive id diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PingPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PingPacket.cs index 20afca38..f89f0b0f 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PingPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PingPacket.cs @@ -11,8 +11,9 @@ namespace MineSharp.Protocol.Packets.Clientbound.Configuration; public class PingPacket : IPacket { /// - public PacketType Type => PacketType.CB_Configuration_Ping; - + public PacketType Type => StaticType; + public static PacketType StaticType => PacketType.CB_Configuration_Ping; + /// /// The id of the ping /// diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PluginMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PluginMessagePacket.cs index 1eaf402a..169784a3 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PluginMessagePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PluginMessagePacket.cs @@ -31,7 +31,8 @@ public PluginMessagePacket(string channelName, PacketBuffer data) public PacketBuffer Data { get; set; } /// - public PacketType Type => PacketType.CB_Configuration_CustomPayload; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Configuration_CustomPayload; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RegistryDataPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RegistryDataPacket.cs index 920c84ea..b8385491 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RegistryDataPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RegistryDataPacket.cs @@ -12,7 +12,8 @@ namespace MineSharp.Protocol.Packets.Clientbound.Configuration; public class RegistryDataPacket : IPacket { /// - public PacketType Type => PacketType.CB_Configuration_RegistryData; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Configuration_RegistryData; /// /// The registry data diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs index 183f7b8b..467394c5 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs @@ -12,7 +12,8 @@ namespace MineSharp.Protocol.Packets.Clientbound.Login; public class DisconnectPacket : IPacket { /// - public PacketType Type => PacketType.CB_Login_Disconnect; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Login_Disconnect; /// /// The reason for being disconnected diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/EncryptionRequestPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/EncryptionRequestPacket.cs index 9da13d7b..ef124ab2 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/EncryptionRequestPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/EncryptionRequestPacket.cs @@ -11,7 +11,8 @@ namespace MineSharp.Protocol.Packets.Clientbound.Login; public class EncryptionRequestPacket : IPacket { /// - public PacketType Type => PacketType.CB_Login_EncryptionBegin; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Login_EncryptionBegin; /// /// The hashed server id diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginPluginRequestPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginPluginRequestPacket.cs index 5ff2ab1a..9e00044e 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginPluginRequestPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginPluginRequestPacket.cs @@ -38,7 +38,8 @@ public LoginPluginRequestPacket(int messageId, string channel, byte[] data) public byte[] Data { get; set; } /// - public PacketType Type => PacketType.CB_Login_LoginPluginRequest; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Login_LoginPluginRequest; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginSuccessPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginSuccessPacket.cs index 02a64ca2..e96c5bc8 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginSuccessPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginSuccessPacket.cs @@ -12,7 +12,8 @@ namespace MineSharp.Protocol.Packets.Clientbound.Login; public class LoginSuccessPacket : IPacket { /// - public PacketType Type => PacketType.CB_Login_Success; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Login_Success; /// /// Uuid diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/SetCompressionPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/SetCompressionPacket.cs index b1eef2db..40f8cdc7 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/SetCompressionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/SetCompressionPacket.cs @@ -10,7 +10,8 @@ namespace MineSharp.Protocol.Packets.Clientbound.Login; public class SetCompressionPacket : IPacket { /// - public PacketType Type => PacketType.CB_Login_Compress; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Login_Compress; /// /// Threshold for when to use compression diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/AcknowledgeBlockChangePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/AcknowledgeBlockChangePacket.cs index 85104bd5..b77ff1c6 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/AcknowledgeBlockChangePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/AcknowledgeBlockChangePacket.cs @@ -44,7 +44,8 @@ internal AcknowledgeBlockChangePacket(IPacketBody body) public IPacketBody Body { get; set; } /// - public PacketType Type => PacketType.CB_Play_AcknowledgePlayerDigging; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_AcknowledgePlayerDigging; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockUpdatePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockUpdatePacket.cs index 865fea27..02a8f4ef 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockUpdatePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockUpdatePacket.cs @@ -32,7 +32,8 @@ public BlockUpdatePacket(Position location, int stateId) public int StateId { get; set; } /// - public PacketType Type => PacketType.CB_Play_BlockChange; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_BlockChange; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/BundleDelimiterPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BundleDelimiterPacket.cs index 6a8294ec..2b778b38 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/BundleDelimiterPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BundleDelimiterPacket.cs @@ -10,7 +10,8 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; public class BundleDelimiterPacket : IPacket { /// - public PacketType Type => PacketType.CB_Play_BundleDelimiter; + public PacketType Type => StaticType; + public static PacketType StaticType => PacketType.CB_Play_BundleDelimiter; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChatPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChatPacket.cs index 9c99b714..70cda1c5 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChatPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChatPacket.cs @@ -39,7 +39,8 @@ public ChatPacket(string message, byte position, Uuid sender) public Uuid Sender { get; set; } /// - public PacketType Type => PacketType.CB_Play_Chat; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_Chat; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchFinishedPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchFinishedPacket.cs index 98fae0ce..4b01dd80 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchFinishedPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchFinishedPacket.cs @@ -25,7 +25,8 @@ public ChunkBatchFinishedPacket(int batchSize) public int BatchSize { get; set; } /// - public PacketType Type => PacketType.CB_Play_ChunkBatchFinished; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_ChunkBatchFinished; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchStartPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchStartPacket.cs index 020ae573..a95465e3 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchStartPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchStartPacket.cs @@ -11,7 +11,8 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; public class ChunkBatchStartPacket : IPacket { /// - public PacketType Type => PacketType.CB_Play_ChunkBatchStart; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_ChunkBatchStart; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkDataAndUpdateLightPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkDataAndUpdateLightPacket.cs index 59cd23eb..89cbaa3f 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkDataAndUpdateLightPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkDataAndUpdateLightPacket.cs @@ -111,7 +111,8 @@ public ChunkDataAndUpdateLightPacket( public byte[][] BlockLight { get; set; } /// - public PacketType Type => PacketType.CB_Play_MapChunk; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_MapChunk; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/CloseWindowPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/CloseWindowPacket.cs index 038c1ac5..b6684186 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/CloseWindowPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/CloseWindowPacket.cs @@ -24,7 +24,8 @@ public CloseWindowPacket(byte windowId) public byte WindowId { get; set; } /// - public PacketType Type => PacketType.CB_Play_CloseWindow; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_CloseWindow; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/CombatDeathPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/CombatDeathPacket.cs index 312b1bbe..23626dbe 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/CombatDeathPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/CombatDeathPacket.cs @@ -57,7 +57,8 @@ private CombatDeathPacket(int playerId, int? entityId, string message) public string Message { get; set; } /// - public PacketType Type => PacketType.CB_Play_DeathCombatEvent; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_DeathCombatEvent; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DeclareCommandsPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DeclareCommandsPacket.cs index 1ce50bab..beb3e123 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DeclareCommandsPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DeclareCommandsPacket.cs @@ -24,7 +24,8 @@ public DeclareCommandsPacket(PacketBuffer buffer) public PacketBuffer RawBuffer { get; set; } /// - public PacketType Type => PacketType.CB_Play_DeclareCommands; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_DeclareCommands; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisconnectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisconnectPacket.cs index 6aafb95e..72240187 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisconnectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisconnectPacket.cs @@ -25,7 +25,8 @@ public DisconnectPacket(Chat reason) public Chat Reason { get; set; } /// - public PacketType Type => PacketType.CB_Play_KickDisconnect; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_KickDisconnect; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisguisedChatMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisguisedChatMessagePacket.cs index 5c63cc98..cbbfc48a 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisguisedChatMessagePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisguisedChatMessagePacket.cs @@ -19,7 +19,8 @@ public DisguisedChatMessagePacket(Chat message, int chatType, Chat name, Chat? t public int ChatType { get; set; } public Chat Name { get; set; } public Chat? Target { get; set; } - public PacketType Type => PacketType.CB_Play_ProfilelessChat; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_ProfilelessChat; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionAndRotationPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionAndRotationPacket.cs index 6cdd9dc4..5de4e0bb 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionAndRotationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionAndRotationPacket.cs @@ -25,7 +25,8 @@ public EntityPositionAndRotationPacket(int entityId, short deltaX, short deltaY, public sbyte Yaw { get; set; } public sbyte Pitch { get; set; } public bool OnGround { get; set; } - public PacketType Type => PacketType.CB_Play_EntityMoveLook; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_EntityMoveLook; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionPacket.cs index ee03130c..4eb6e10e 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionPacket.cs @@ -20,7 +20,8 @@ public EntityPositionPacket(int entityId, short deltaX, short deltaY, short delt public short DeltaY { get; set; } public short DeltaZ { get; set; } public bool OnGround { get; set; } - public PacketType Type => PacketType.CB_Play_RelEntityMove; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_RelEntityMove; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityRotationPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityRotationPacket.cs index f691dd37..ff7df713 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityRotationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityRotationPacket.cs @@ -18,7 +18,8 @@ public EntityRotationPacket(int entityId, sbyte yaw, sbyte pitch, bool onGround) public sbyte Yaw { get; set; } public sbyte Pitch { get; set; } public bool OnGround { get; set; } - public PacketType Type => PacketType.CB_Play_EntityLook; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_EntityLook; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs index d57ae752..aa34b740 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs @@ -28,7 +28,8 @@ public EntitySoundEffectPacket(int soundId, string? soundName, bool? hasFixedRan public float Volume { get; set; } public float Pitch { get; set; } public long Seed { get; set; } - public PacketType Type => PacketType.CB_Play_EntitySoundEffect; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_EntitySoundEffect; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityStatusPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityStatusPacket.cs index 9612c849..17f2433e 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityStatusPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityStatusPacket.cs @@ -14,7 +14,8 @@ public EntityStatusPacket(int entityId, byte status) public int EntityId { get; set; } public byte Status { get; set; } - public PacketType Type => PacketType.CB_Play_EntityStatus; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_EntityStatus; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/GameEventPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/GameEventPacket.cs index 0516b01c..74db2e62 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/GameEventPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/GameEventPacket.cs @@ -32,7 +32,8 @@ public GameEventPacket(GameEvent @event, float value) public GameEvent Event { get; set; } public float Value { get; set; } - public PacketType Type => PacketType.CB_Play_GameStateChange; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_GameStateChange; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/KeepAlivePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/KeepAlivePacket.cs index bf396b26..932f034e 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/KeepAlivePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/KeepAlivePacket.cs @@ -12,7 +12,8 @@ public KeepAlivePacket(long id) } public long KeepAliveId { get; set; } - public PacketType Type => PacketType.CB_Play_KeepAlive; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_KeepAlive; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs index 92fa1f9d..2e3a0522 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs @@ -76,7 +76,8 @@ public LoginPacket(int entityId, public Position? DeathLocation { get; set; } public int? PortalCooldown { get; set; } public bool? DoLimitedCrafting { get; set; } // since 1.20.2 - public PacketType Type => PacketType.CB_Play_Login; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_Login; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/MultiBlockUpdatePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/MultiBlockUpdatePacket.cs index 95da38fb..5079788a 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/MultiBlockUpdatePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/MultiBlockUpdatePacket.cs @@ -36,7 +36,8 @@ public MultiBlockUpdatePacket(long chunkSection, long[] blocks) public long ChunkSection { get; set; } public bool? SuppressLightUpdates { get; set; } public long[] Blocks { get; set; } - public PacketType Type => PacketType.CB_Play_MultiBlockChange; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_MultiBlockChange; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenWindowPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenWindowPacket.cs index 0c36bd7f..8a1553b7 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenWindowPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenWindowPacket.cs @@ -28,7 +28,8 @@ public OpenWindowPacket(int windowId, int inventoryType, Chat windowTitle) public string WindowTitle { get; set; } public Chat? WindowTitleChat { get; set; } - public PacketType Type => PacketType.CB_Play_OpenWindow; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_OpenWindow; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ParticlePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ParticlePacket.cs index 382b093c..04189395 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ParticlePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ParticlePacket.cs @@ -36,7 +36,8 @@ public ParticlePacket(int particleId, bool longDistance, double x, double y, dou /// Will be an empty buffer for most particles. /// public PacketBuffer Data { get; set; } - public PacketType Type => PacketType.CB_Play_WorldParticles; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_WorldParticles; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PingPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PingPacket.cs index 77d6bc6a..28cfce12 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PingPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PingPacket.cs @@ -24,7 +24,8 @@ public PingPacket(int id) public int Id { get; set; } /// - public PacketType Type => PacketType.CB_Play_Ping; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_Ping; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerChatPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerChatPacket.cs index 2cb50ad8..90749246 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerChatPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerChatPacket.cs @@ -15,7 +15,8 @@ public PlayerChatPacket(IChatMessageBody body) } public IChatMessageBody Body { get; set; } - public PacketType Type => PacketType.CB_Play_PlayerChat; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_PlayerChat; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoRemovePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoRemovePacket.cs index 33b973e0..3b7c7302 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoRemovePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoRemovePacket.cs @@ -12,7 +12,8 @@ public PlayerInfoRemovePacket(Uuid[] players) } public Uuid[] Players { get; set; } - public PacketType Type => PacketType.CB_Play_PlayerRemove; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_PlayerRemove; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoUpdatePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoUpdatePacket.cs index f360725e..5c325b50 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoUpdatePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoUpdatePacket.cs @@ -17,7 +17,8 @@ public PlayerInfoUpdatePacket(int action, ActionEntry[] data) public int Action { get; set; } public ActionEntry[] Data { get; set; } - public PacketType Type => PacketType.CB_Play_PlayerInfo; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_PlayerInfo; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerPositionPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerPositionPacket.cs index 3aaaff76..90867d8e 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerPositionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerPositionPacket.cs @@ -62,7 +62,8 @@ public PlayerPositionPacket(double x, double y, double z, float yaw, float pitch public sbyte Flags { get; set; } public int TeleportId { get; set; } public bool? DismountVehicle { get; set; } - public PacketType Type => PacketType.CB_Play_Position; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_Position; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveEntitiesPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveEntitiesPacket.cs index 051d129d..488d8c79 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveEntitiesPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveEntitiesPacket.cs @@ -12,7 +12,8 @@ public RemoveEntitiesPacket(int[] entityIds) } public int[] EntityIds { get; set; } - public PacketType Type => PacketType.CB_Play_EntityDestroy; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_EntityDestroy; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs index b228be93..efa294f6 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs @@ -41,7 +41,8 @@ public RespawnPacket(string dimension, string dimensionName, long hashedSeed, sb public string? DeathDimensionName { get; set; } public Position? DeathLocation { get; set; } public int? PortalCooldown { get; set; } - public PacketType Type => PacketType.CB_Play_Respawn; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_Respawn; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEntityVelocityPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEntityVelocityPacket.cs index 45a0cf98..e8bcd141 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEntityVelocityPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEntityVelocityPacket.cs @@ -18,7 +18,8 @@ public SetEntityVelocityPacket(int entityId, short velocityX, short velocityY, s public short VelocityX { get; set; } public short VelocityY { get; set; } public short VelocityZ { get; set; } - public PacketType Type => PacketType.CB_Play_EntityVelocity; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_EntityVelocity; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHealthPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHealthPacket.cs index 0b2b9cd1..75c60858 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHealthPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHealthPacket.cs @@ -16,7 +16,8 @@ public SetHealthPacket(float health, int food, float saturation) public float Health { get; set; } public int Food { get; set; } public float Saturation { get; set; } - public PacketType Type => PacketType.CB_Play_UpdateHealth; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_UpdateHealth; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHeldItemPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHeldItemPacket.cs index 1b08e458..cd7bc02d 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHeldItemPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHeldItemPacket.cs @@ -12,7 +12,8 @@ public SetHeldItemPacket(sbyte slot) } public sbyte Slot { get; set; } - public PacketType Type => PacketType.CB_Play_HeldItemSlot; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_HeldItemSlot; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetPassengersPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetPassengersPacket.cs index 6be834cc..045407dd 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetPassengersPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetPassengersPacket.cs @@ -16,7 +16,8 @@ public SetPassengersPacket(int entityId, int[] passengersId) public int EntityId { get; set; } public int[] PassengersId { get; set; } - public PacketType Type => PacketType.CB_Play_SetPassengers; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_SetPassengers; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs index d7ab883e..96743d37 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs @@ -32,7 +32,8 @@ public SoundEffectPacket(int soundId, string? soundName, bool? hasFixedRange, fl public float Volume { get; set; } public float Pitch { get; set; } public long Seed { get; set; } - public PacketType Type => PacketType.CB_Play_SoundEffect; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_SoundEffect; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnEntityPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnEntityPacket.cs index e0a1e05c..25671c25 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnEntityPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnEntityPacket.cs @@ -39,7 +39,8 @@ public SpawnEntityPacket(int entityId, Uuid objectUuid, int entityType, double x public short VelocityX { get; set; } public short VelocityY { get; set; } public short VelocityZ { get; set; } - public PacketType Type => PacketType.CB_Play_SpawnEntity; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_SpawnEntity; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnLivingEntityPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnLivingEntityPacket.cs index 9b830084..fa0c566a 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnLivingEntityPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnLivingEntityPacket.cs @@ -40,7 +40,8 @@ public SpawnLivingEntityPacket(int entityId, Uuid entityUuid, int entityType, do public short VelocityX { get; set; } public short VelocityY { get; set; } public short VelocityZ { get; set; } - public PacketType Type => PacketType.CB_Play_SpawnEntityLiving; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_SpawnEntityLiving; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPaintingPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPaintingPacket.cs index b6562ac7..be600e31 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPaintingPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPaintingPacket.cs @@ -25,7 +25,8 @@ public SpawnPaintingPacket(int entityId, Uuid entityUuid, int title, Position lo public int Title { get; set; } public Position Location { get; set; } public sbyte Direction { get; set; } - public PacketType Type => PacketType.CB_Play_SpawnEntityPainting; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_SpawnEntityPainting; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPlayerPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPlayerPacket.cs index 2b4aafea..4fc05f8b 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPlayerPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPlayerPacket.cs @@ -28,7 +28,8 @@ public SpawnPlayerPacket(int entityId, Uuid playerUuid, double x, double y, doub public double Z { get; set; } public byte Yaw { get; set; } public byte Pitch { get; set; } - public PacketType Type => PacketType.CB_Play_NamedEntitySpawn; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_NamedEntitySpawn; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SystemChatMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SystemChatMessagePacket.cs index 63d5e6d6..5f40878b 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SystemChatMessagePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SystemChatMessagePacket.cs @@ -14,7 +14,8 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; public abstract class SystemChatMessagePacket : IPacket { /// - public PacketType Type => PacketType.CB_Play_SystemChat; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_SystemChat; /// /// The message diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/TeleportEntityPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/TeleportEntityPacket.cs index 53c98c68..6c266011 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/TeleportEntityPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/TeleportEntityPacket.cs @@ -24,7 +24,8 @@ public TeleportEntityPacket(int entityId, double x, double y, double z, sbyte ya public sbyte Yaw { get; set; } public sbyte Pitch { get; set; } public bool OnGround { get; set; } - public PacketType Type => PacketType.CB_Play_EntityTeleport; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_EntityTeleport; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/UnloadChunkPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UnloadChunkPacket.cs index 49bc1048..6c2b0ff8 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/UnloadChunkPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UnloadChunkPacket.cs @@ -14,7 +14,8 @@ public UnloadChunkPacket(int x, int z) public int X { get; set; } public int Z { get; set; } - public PacketType Type => PacketType.CB_Play_UnloadChunk; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_UnloadChunk; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateAttributesPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateAttributesPacket.cs index 6180a12b..622893d3 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateAttributesPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateAttributesPacket.cs @@ -16,7 +16,8 @@ public UpdateAttributesPacket(int entityId, Attribute[] attributes) public int EntityId { get; set; } public Attribute[] Attributes { get; set; } - public PacketType Type => PacketType.CB_Play_EntityUpdateAttributes; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_EntityUpdateAttributes; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowItemsPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowItemsPacket.cs index da20b99c..4a746e6e 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowItemsPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowItemsPacket.cs @@ -20,7 +20,8 @@ public WindowItemsPacket(byte windowId, int stateId, Item?[] items, Item? select public int StateId { get; set; } public Item?[] Items { get; set; } public Item? SelectedItem { get; set; } - public PacketType Type => PacketType.CB_Play_WindowItems; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_WindowItems; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowSetSlotPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowSetSlotPacket.cs index 78358b3f..306149ed 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowSetSlotPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowSetSlotPacket.cs @@ -17,7 +17,8 @@ public WindowSetSlotPacket(sbyte windowId, int stateId, Slot slot) public sbyte WindowId { get; set; } public int StateId { get; set; } public Slot Slot { get; set; } - public PacketType Type => PacketType.CB_Play_SetSlot; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Play_SetSlot; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Status/PongResponsePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Status/PongResponsePacket.cs index 97eb6e7b..470d7415 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Status/PongResponsePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Status/PongResponsePacket.cs @@ -12,7 +12,8 @@ public PongResponsePacket(long payload) } public long Payload { get; set; } - public PacketType Type => PacketType.CB_Status_Ping; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Status_Ping; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Status/StatusResponsePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Status/StatusResponsePacket.cs index a3073850..a42877d1 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Status/StatusResponsePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Status/StatusResponsePacket.cs @@ -12,7 +12,8 @@ public StatusResponsePacket(string response) } public string Response { get; set; } - public PacketType Type => PacketType.CB_Status_ServerInfo; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.CB_Status_ServerInfo; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/IPacket.cs b/Components/MineSharp.Protocol/Packets/IPacket.cs index 8a0b9797..f205d553 100644 --- a/Components/MineSharp.Protocol/Packets/IPacket.cs +++ b/Components/MineSharp.Protocol/Packets/IPacket.cs @@ -5,15 +5,23 @@ namespace MineSharp.Protocol.Packets; /// -/// Represents a minecraft packet +/// Represents a Minecraft packet /// public interface IPacket { /// /// The corresponding + /// + /// /// public PacketType Type { get; } + /// + /// The corresponding . + /// The same as but static. + /// + public static abstract PacketType StaticType { get; } + /// /// Serialize the packet data into the buffer. /// diff --git a/Components/MineSharp.Protocol/Packets/PacketPalette.cs b/Components/MineSharp.Protocol/Packets/PacketPalette.cs index ab5f3f95..73ae8561 100644 --- a/Components/MineSharp.Protocol/Packets/PacketPalette.cs +++ b/Components/MineSharp.Protocol/Packets/PacketPalette.cs @@ -1,4 +1,5 @@ -using MineSharp.Core.Common; +using System.Collections.Frozen; +using MineSharp.Core.Common; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Packets.Clientbound.Configuration; @@ -43,15 +44,11 @@ internal static class PacketPalette public delegate IPacket PacketFactory(PacketBuffer buffer, MinecraftData version); private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); - private static readonly IDictionary PacketFactories; - private static readonly IDictionary ClassToTypeMap; + private static readonly FrozenDictionary PacketFactories; static PacketPalette() { - PacketFactories = new Dictionary(); - ClassToTypeMap = new Dictionary(); - - InitializePackets(); + PacketFactories = InitializePackets(); } public static PacketFactory? GetFactory(PacketType packetType) @@ -65,127 +62,126 @@ static PacketPalette() return packet; } - public static PacketType GetPacketType() where T : IPacket + private static FrozenDictionary InitializePackets() { - var guid = typeof(T).GUID; - return ClassToTypeMap[guid]; - } + Dictionary packetFactories = new(); + + void RegisterPacket() + where TPacket : IPacket + { + packetFactories.Add(TPacket.StaticType, TPacket.Read); + } - private static void InitializePackets() - { // Handshaking - RegisterPacket(PacketType.SB_Handshake_SetProtocol); + RegisterPacket(); // Login - RegisterPacket(PacketType.CB_Login_Disconnect); - RegisterPacket(PacketType.CB_Login_EncryptionBegin); - RegisterPacket(PacketType.CB_Login_Success); - RegisterPacket(PacketType.CB_Login_Compress); - RegisterPacket(PacketType.CB_Login_LoginPluginRequest); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); - RegisterPacket(PacketType.SB_Login_LoginStart); - RegisterPacket(PacketType.SB_Login_EncryptionBegin); - RegisterPacket(PacketType.SB_Login_LoginPluginResponse); - RegisterPacket(PacketType.SB_Login_LoginAcknowledged); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); // Status - RegisterPacket(PacketType.CB_Status_ServerInfo); - RegisterPacket(PacketType.CB_Status_Ping); + RegisterPacket(); + RegisterPacket(); - RegisterPacket(PacketType.SB_Status_PingStart); - RegisterPacket(PacketType.SB_Status_Ping); + RegisterPacket(); + RegisterPacket(); // Configuration - RegisterPacket(PacketType.CB_Configuration_CustomPayload); - RegisterPacket(PacketType.CB_Configuration_Disconnect); - RegisterPacket(PacketType.CB_Configuration_FinishConfiguration); - RegisterPacket(PacketType.CB_Configuration_KeepAlive); - RegisterPacket(PacketType.CB_Configuration_Ping); - RegisterPacket(PacketType.CB_Configuration_RegistryData); - RegisterPacket(PacketType.CB_Configuration_FeatureFlags); - - RegisterPacket(PacketType.SB_Configuration_Settings); - RegisterPacket(PacketType.SB_Configuration_CustomPayload); - RegisterPacket(PacketType.SB_Configuration_FinishConfiguration); - RegisterPacket(PacketType.SB_Configuration_KeepAlive); - RegisterPacket(PacketType.SB_Configuration_Pong); - RegisterPacket(PacketType.SB_Configuration_ResourcePackReceive); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); // Play - RegisterPacket(PacketType.CB_Play_SpawnEntityPainting); - RegisterPacket(PacketType.CB_Play_SpawnEntityLiving); - RegisterPacket(PacketType.CB_Play_SpawnEntity); - RegisterPacket(PacketType.CB_Play_KeepAlive); - RegisterPacket(PacketType.CB_Play_MapChunk); - RegisterPacket(PacketType.CB_Play_WorldParticles); - RegisterPacket(PacketType.CB_Play_UnloadChunk); - RegisterPacket(PacketType.CB_Play_BlockChange); - RegisterPacket(PacketType.CB_Play_MultiBlockChange); - RegisterPacket(PacketType.CB_Play_Login); - RegisterPacket(PacketType.CB_Play_Position); - RegisterPacket(PacketType.CB_Play_UpdateHealth); - RegisterPacket(PacketType.CB_Play_DeathCombatEvent); - RegisterPacket(PacketType.CB_Play_Respawn); - RegisterPacket(PacketType.CB_Play_EntityDestroy); - RegisterPacket(PacketType.CB_Play_EntityVelocity); - RegisterPacket(PacketType.CB_Play_RelEntityMove); - RegisterPacket(PacketType.CB_Play_EntityMoveLook); - RegisterPacket(PacketType.CB_Play_EntityLook); - RegisterPacket(PacketType.CB_Play_EntityTeleport); - RegisterPacket(PacketType.CB_Play_EntityUpdateAttributes); - RegisterPacket(PacketType.CB_Play_DeclareCommands); - RegisterPacket(PacketType.CB_Play_Chat); - RegisterPacket(PacketType.CB_Play_PlayerChat); - RegisterPacket(PacketType.CB_Play_NamedEntitySpawn); - RegisterPacket(PacketType.CB_Play_PlayerInfo); - RegisterPacket(PacketType.CB_Play_PlayerRemove); - RegisterPacket(PacketType.CB_Play_GameStateChange); - RegisterPacket(PacketType.CB_Play_AcknowledgePlayerDigging); - RegisterPacket(PacketType.CB_Play_WindowItems); - RegisterPacket(PacketType.CB_Play_SetSlot); - RegisterPacket(PacketType.CB_Play_OpenWindow); - RegisterPacket(PacketType.CB_Play_CloseWindow); - RegisterPacket(PacketType.CB_Play_HeldItemSlot); - RegisterPacket(PacketType.CB_Play_EntitySoundEffect); - RegisterPacket(PacketType.CB_Play_SoundEffect); - RegisterPacket(PacketType.CB_Play_SystemChat); - RegisterPacket(PacketType.CB_Play_ProfilelessChat); - RegisterPacket(PacketType.CB_Play_EntityStatus); - RegisterPacket(PacketType.CB_Play_ChunkBatchStart); - RegisterPacket(PacketType.CB_Play_ChunkBatchFinished); - RegisterPacket(PacketType.CB_Play_Ping); - RegisterPacket(PacketType.CB_Play_KickDisconnect); - RegisterPacket(PacketType.CB_Play_SetPassengers); - - RegisterPacket(PacketType.SB_Play_KeepAlive); - RegisterPacket(PacketType.SB_Play_Position); - RegisterPacket(PacketType.SB_Play_PositionLook); - RegisterPacket(PacketType.SB_Play_ClientCommand); - RegisterPacket(PacketType.SB_Play_Chat); - RegisterPacket(PacketType.SB_Play_ChatMessage); - RegisterPacket(PacketType.SB_Play_ChatCommand); - RegisterPacket(PacketType.SB_Play_MessageAcknowledgement); - RegisterPacket(PacketType.SB_Play_ChatSessionUpdate); - RegisterPacket(PacketType.SB_Play_TeleportConfirm); - RegisterPacket(PacketType.SB_Play_UpdateCommandBlock); - RegisterPacket(PacketType.SB_Play_WindowClick); - RegisterPacket(PacketType.SB_Play_BlockPlace); - RegisterPacket(PacketType.SB_Play_BlockDig); - RegisterPacket(PacketType.SB_Play_ArmAnimation); - RegisterPacket(PacketType.SB_Play_UseEntity); - RegisterPacket(PacketType.SB_Play_CloseWindow); - RegisterPacket(PacketType.SB_Play_EntityAction); - RegisterPacket(PacketType.SB_Play_UseItem); - RegisterPacket(PacketType.SB_Play_HeldItemSlot); - RegisterPacket(PacketType.SB_Play_ChunkBatchReceived); - RegisterPacket(PacketType.SB_Play_SetCreativeSlot); - RegisterPacket(PacketType.SB_Play_Pong); - RegisterPacket(PacketType.SB_Play_Settings); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + + return packetFactories.ToFrozenDictionary(); } - private static void RegisterPacket(PacketType type) where TPacket : IPacket - { - PacketFactories.Add(type, TPacket.Read); - ClassToTypeMap.Add(typeof(TPacket).GUID, type); - } } diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ClientInformationPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ClientInformationPacket.cs index 496262ed..c2dcc42a 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ClientInformationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ClientInformationPacket.cs @@ -28,7 +28,8 @@ public ClientInformationPacket(string locale, byte viewDistance, int chatMode, b public int MainHand { get; set; } public bool EnableTextFiltering { get; set; } public bool AllowServerListings { get; set; } - public PacketType Type => PacketType.SB_Configuration_Settings; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Configuration_Settings; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/FinishConfigurationPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/FinishConfigurationPacket.cs index 9c742462..47a5e4ab 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/FinishConfigurationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/FinishConfigurationPacket.cs @@ -6,7 +6,8 @@ namespace MineSharp.Protocol.Packets.Serverbound.Configuration; #pragma warning disable CS1591 public class FinishConfigurationPacket : IPacket { - public PacketType Type => PacketType.SB_Configuration_FinishConfiguration; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Configuration_FinishConfiguration; public void Write(PacketBuffer buffer, MinecraftData version) { } diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/KeepAlivePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/KeepAlivePacket.cs index dda74fd0..f4d11d47 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/KeepAlivePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/KeepAlivePacket.cs @@ -12,7 +12,8 @@ public KeepAlivePacket(long keepAliveId) } public long KeepAliveId { get; set; } - public PacketType Type => PacketType.SB_Configuration_KeepAlive; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Configuration_KeepAlive; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PluginMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PluginMessagePacket.cs index 9140de57..c489385a 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PluginMessagePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PluginMessagePacket.cs @@ -14,7 +14,8 @@ public PluginMessagePacket(string channelName, PacketBuffer data) public string ChannelName { get; set; } public PacketBuffer Data { get; set; } - public PacketType Type => PacketType.SB_Configuration_CustomPayload; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Configuration_CustomPayload; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PongPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PongPacket.cs index ce2f55f4..cd666b63 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PongPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PongPacket.cs @@ -12,7 +12,8 @@ public PongPacket(int id) } public int Id { get; set; } - public PacketType Type => PacketType.SB_Configuration_Pong; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Configuration_Pong; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ResourcePackResponsePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ResourcePackResponsePacket.cs index da6ab1b4..a2765b4c 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ResourcePackResponsePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ResourcePackResponsePacket.cs @@ -12,7 +12,8 @@ public ResourcePackResponsePacket(int result) } public int Result { get; set; } - public PacketType Type => PacketType.SB_Configuration_ResourcePackReceive; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Configuration_ResourcePackReceive; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Handshaking/HandshakePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Handshaking/HandshakePacket.cs index de167c7a..d160115b 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Handshaking/HandshakePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Handshaking/HandshakePacket.cs @@ -21,7 +21,8 @@ public HandshakePacket(int protocolVersion, string host, ushort port, GameState public string Host { get; set; } public ushort Port { get; set; } public GameState NextState { get; set; } - public PacketType Type => PacketType.SB_Handshake_SetProtocol; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Handshake_SetProtocol; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Login/AcknowledgeLoginPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Login/AcknowledgeLoginPacket.cs index ebd9c86b..1b026628 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Login/AcknowledgeLoginPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Login/AcknowledgeLoginPacket.cs @@ -6,7 +6,8 @@ namespace MineSharp.Protocol.Packets.Serverbound.Login; #pragma warning disable CS1591 public class AcknowledgeLoginPacket : IPacket { - public PacketType Type => PacketType.SB_Login_LoginAcknowledged; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Login_LoginAcknowledged; public void Write(PacketBuffer buffer, MinecraftData version) { } diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Login/EncryptionResponsePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Login/EncryptionResponsePacket.cs index 7e064241..75bee87e 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Login/EncryptionResponsePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Login/EncryptionResponsePacket.cs @@ -18,7 +18,8 @@ public EncryptionResponsePacket(byte[] sharedSecret, byte[]? verifyToken, Crypto public byte[] SharedSecret { get; set; } public byte[]? VerifyToken { get; set; } public CryptoContainer? Crypto { get; set; } - public PacketType Type => PacketType.SB_Login_EncryptionBegin; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Login_EncryptionBegin; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginPluginResponsePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginPluginResponsePacket.cs index 4cb13f97..dfdd7a7b 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginPluginResponsePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginPluginResponsePacket.cs @@ -14,7 +14,8 @@ public LoginPluginResponsePacket(int messageId, byte[]? data) public int MessageId { get; set; } public byte[]? Data { get; set; } - public PacketType Type => PacketType.SB_Login_LoginPluginResponse; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Login_LoginPluginResponse; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginStartPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginStartPacket.cs index 9938b601..0ab69fbe 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginStartPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginStartPacket.cs @@ -45,7 +45,8 @@ public LoginStartPacket(string username, SignatureContainer? signature, Uuid? pl public string Username { get; set; } public SignatureContainer? Signature { get; set; } public Uuid? PlayerUuid { get; set; } - public PacketType Type => PacketType.SB_Login_LoginStart; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Login_LoginStart; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatCommandPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatCommandPacket.cs index 8bc8f85d..de9d843f 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatCommandPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatCommandPacket.cs @@ -80,7 +80,8 @@ public ChatCommandPacket(string command, long timestamp, long salt, ArgumentSign public ChatMessageItem? LastRejectedMessage { get; set; } public int? MessageCount { get; set; } public byte[]? Acknowledged { get; set; } - public PacketType Type => PacketType.SB_Play_ChatCommand; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_ChatCommand; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatMessagePacket.cs index 57b88c1b..05255921 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatMessagePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatMessagePacket.cs @@ -59,7 +59,8 @@ public ChatMessagePacket(string message, long timestamp, long salt, byte[]? sign public ChatMessageItem? LastRejectedMessage { get; set; } public int? MessageCount { get; set; } public byte[]? Acknowledged { get; set; } - public PacketType Type => PacketType.SB_Play_ChatMessage; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_ChatMessage; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatPacket.cs index c690dec9..42a1ed9c 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatPacket.cs @@ -15,7 +15,8 @@ public ChatPacket(string message) } public string Message { get; set; } - public PacketType Type => PacketType.SB_Play_Chat; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_Chat; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChunkBatchReceivedPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChunkBatchReceivedPacket.cs index 08faa345..a90ba476 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChunkBatchReceivedPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChunkBatchReceivedPacket.cs @@ -25,7 +25,8 @@ public ChunkBatchReceivedPacket(float chunksPerTick) public float ChunksPerTick { get; set; } /// - public PacketType Type => PacketType.SB_Play_ChunkBatchReceived; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_ChunkBatchReceived; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientCommandPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientCommandPacket.cs index 5f9f9f5b..7c49a14f 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientCommandPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientCommandPacket.cs @@ -12,7 +12,8 @@ public ClientCommandPacket(int actionId) } public int ActionId { get; set; } - public PacketType Type => PacketType.SB_Play_ClientCommand; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_ClientCommand; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientInformationPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientInformationPacket.cs index 1d2cf871..5410c2ba 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientInformationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientInformationPacket.cs @@ -28,7 +28,8 @@ public ClientInformationPacket(string locale, byte viewDistance, int chatMode, b public int MainHand { get; set; } public bool EnableTextFiltering { get; set; } public bool AllowServerListings { get; set; } - public PacketType Type => PacketType.SB_Play_Settings; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_Settings; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/CloseWindowPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/CloseWindowPacket.cs index a70c0448..a0391f65 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/CloseWindowPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/CloseWindowPacket.cs @@ -12,7 +12,8 @@ public CloseWindowPacket(byte windowId) } public byte WindowId { get; set; } - public PacketType Type => PacketType.SB_Play_CloseWindow; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_CloseWindow; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ConfirmTeleportPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ConfirmTeleportPacket.cs index 9de1e18f..5f3a2711 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ConfirmTeleportPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ConfirmTeleportPacket.cs @@ -12,7 +12,8 @@ public ConfirmTeleportPacket(int teleportId) } public int TeleportId { get; set; } - public PacketType Type => PacketType.SB_Play_TeleportConfirm; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_TeleportConfirm; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/EntityActionPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/EntityActionPacket.cs index f914fdfd..a7a93447 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/EntityActionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/EntityActionPacket.cs @@ -29,7 +29,8 @@ public EntityActionPacket(int entityId, EntityAction action, int jumpBoost) public int EntityId { get; set; } public EntityAction Action { get; set; } public int JumpBoost { get; set; } - public PacketType Type => PacketType.SB_Play_EntityAction; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_EntityAction; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/InteractPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/InteractPacket.cs index 48d6b41e..0e51b672 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/InteractPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/InteractPacket.cs @@ -53,7 +53,8 @@ public InteractPacket(int entityId, float targetX, float targetY, float targetZ, public float? TargetZ { get; set; } public PlayerHand? Hand { get; set; } public bool Sneaking { get; set; } - public PacketType Type => PacketType.SB_Play_UseEntity; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_UseEntity; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/KeepAlivePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/KeepAlivePacket.cs index c3ae77fd..aba3eb0f 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/KeepAlivePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/KeepAlivePacket.cs @@ -12,7 +12,8 @@ public KeepAlivePacket(long id) } public long KeepAliveId { get; set; } - public PacketType Type => PacketType.SB_Play_KeepAlive; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_KeepAlive; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/MessageAcknowledgementPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/MessageAcknowledgementPacket.cs index 97c5ff33..34461011 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/MessageAcknowledgementPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/MessageAcknowledgementPacket.cs @@ -29,7 +29,8 @@ public MessageAcknowledgementPacket(ChatMessageItem[]? previousMessages, ChatMes public int? Count { get; set; } public ChatMessageItem[]? PreviousMessages { get; set; } public ChatMessageItem? LastRejectedMessage { get; set; } - public PacketType Type => PacketType.SB_Play_MessageAcknowledgement; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_MessageAcknowledgement; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlaceBlockPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlaceBlockPacket.cs index 7a1ed711..340476c0 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlaceBlockPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlaceBlockPacket.cs @@ -63,7 +63,8 @@ public PlaceBlockPacket(int hand, Position location, BlockFace direction, float public float CursorZ { get; set; } public bool InsideBlock { get; set; } public int? SequenceId { get; set; } - public PacketType Type => PacketType.SB_Play_BlockPlace; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_BlockPlace; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerActionPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerActionPacket.cs index c9a1acea..83fe6769 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerActionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerActionPacket.cs @@ -41,7 +41,8 @@ public PlayerActionPacket(int status, Position location, BlockFace face, int? se public Position Location { get; set; } public BlockFace Face { get; set; } public int? SequenceId { get; set; } - public PacketType Type => PacketType.SB_Play_BlockDig; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_BlockDig; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerSessionPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerSessionPacket.cs index 4368f3ee..b5e7b047 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerSessionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerSessionPacket.cs @@ -18,7 +18,8 @@ public PlayerSessionPacket(Uuid sessionId, long expiresAt, byte[] publicKey, byt public long ExpiresAt { get; set; } public byte[] PublicKey { get; set; } public byte[] KeySignature { get; set; } - public PacketType Type => PacketType.SB_Play_ChatSessionUpdate; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_ChatSessionUpdate; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PongPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PongPacket.cs index 5cba6626..0a04c80b 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PongPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PongPacket.cs @@ -16,7 +16,8 @@ public class PongPacket(int id) : IPacket public int Id { get; set; } = id; /// - public PacketType Type => PacketType.SB_Play_Pong; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_Pong; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetCreativeSlotPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetCreativeSlotPacket.cs index 8fb8649c..4152f47a 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetCreativeSlotPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetCreativeSlotPacket.cs @@ -31,7 +31,8 @@ public SetCreativeSlotPacket(short slotIndex, Item? item) public Item? Item { get; set; } /// - public PacketType Type => PacketType.SB_Play_SetCreativeSlot; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_SetCreativeSlot; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetHeldItemPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetHeldItemPacket.cs index 27d87f2a..a6a9755e 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetHeldItemPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetHeldItemPacket.cs @@ -24,7 +24,8 @@ public SetHeldItemPacket(short slot) public short Slot { get; set; } /// - public PacketType Type => PacketType.SB_Play_HeldItemSlot; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_HeldItemSlot; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionAndRotationPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionAndRotationPacket.cs index 3e9fbede..c1c8b891 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionAndRotationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionAndRotationPacket.cs @@ -22,7 +22,8 @@ public SetPlayerPositionAndRotationPacket(double x, double y, double z, float ya public float Yaw { get; set; } public float Pitch { get; set; } public bool IsOnGround { get; set; } - public PacketType Type => PacketType.SB_Play_PositionLook; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_PositionLook; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionPacket.cs index 680d071c..3f06e246 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionPacket.cs @@ -18,7 +18,8 @@ public SetPlayerPositionPacket(double x, double y, double z, bool isOnGround) public double Y { get; set; } public double Z { get; set; } public bool IsOnGround { get; set; } - public PacketType Type => PacketType.SB_Play_Position; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_Position; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SwingArmPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SwingArmPacket.cs index 70f2b462..82b65621 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SwingArmPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SwingArmPacket.cs @@ -12,7 +12,8 @@ public SwingArmPacket(PlayerHand hand) } public PlayerHand Hand { get; set; } - public PacketType Type => PacketType.SB_Play_ArmAnimation; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_ArmAnimation; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/UpdateCommandBlock.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/UpdateCommandBlock.cs index 2b7ec4a6..fc00a52c 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/UpdateCommandBlock.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/UpdateCommandBlock.cs @@ -19,7 +19,8 @@ public UpdateCommandBlock(Position location, string command, int mode, byte flag public string Command { get; set; } public int Mode { get; set; } public byte Flags { get; set; } - public PacketType Type => PacketType.SB_Play_UpdateCommandBlock; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_UpdateCommandBlock; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/UseItemPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/UseItemPacket.cs index be6b593b..e891bb2a 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/UseItemPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/UseItemPacket.cs @@ -41,7 +41,8 @@ public UseItemPacket(PlayerHand hand, int sequenceId) : this(hand) public int? SequenceId { get; set; } /// - public PacketType Type => PacketType.SB_Play_UseItem; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_UseItem; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/WindowClickPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/WindowClickPacket.cs index 173fbf72..cf4b044c 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/WindowClickPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/WindowClickPacket.cs @@ -27,7 +27,8 @@ public WindowClickPacket(byte windowId, int stateId, short slot, sbyte mouseButt public int Mode { get; set; } public Slot[] ChangedSlots { get; set; } public Item? SelectedItem { get; set; } - public PacketType Type => PacketType.SB_Play_WindowClick; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Play_WindowClick; public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Status/PingRequestPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Status/PingRequestPacket.cs index f532dd09..0f1627ef 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Status/PingRequestPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Status/PingRequestPacket.cs @@ -12,7 +12,8 @@ public PingRequestPacket(long payload) } public long Payload { get; set; } - public PacketType Type => PacketType.SB_Status_Ping; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Status_Ping; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Status/StatusRequestPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Status/StatusRequestPacket.cs index a7a4cae6..e19f8cb1 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Status/StatusRequestPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Status/StatusRequestPacket.cs @@ -6,7 +6,8 @@ namespace MineSharp.Protocol.Packets.Serverbound.Status; #pragma warning disable CS1591 public class StatusRequestPacket : IPacket { - public PacketType Type => PacketType.SB_Status_PingStart; + public PacketType Type => StaticType; +public static PacketType StaticType => PacketType.SB_Status_PingStart; public void Write(PacketBuffer buffer, MinecraftData version) { } From 6bff9f5a4475f0245e1166dd685a440f145c8691 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 7 Aug 2024 03:06:30 +0200 Subject: [PATCH 23/73] removed unused and nonsensical block parameter on AsyncEvent Since the returned Task of AsyncEvent.Dispatch now always completes after all subscribers finished I inspected the places where await was used on such tasks. Removed the await in the most cases since that how it was before. --- .../MineSharp.Protocol/MinecraftClient.cs | 1 + MineSharp.Bot/Plugins/EntityPlugin.cs | 12 +- MineSharp.Bot/Plugins/PhysicsPlugin.cs | 2 +- MineSharp.Bot/Plugins/WindowPlugin.cs | 4 +- MineSharp.Core/Events/AsyncEvent.cs | 115 ++++++++---------- 5 files changed, 66 insertions(+), 68 deletions(-) diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index 27cb8f67..03048ecb 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -479,6 +479,7 @@ private async Task ReceivePackets() } else { + // handle the packet in a new task to prevent blocking the stream loop _ = Task.Run(() => HandleIncomingPacket(packetType, buffer)); } } diff --git a/MineSharp.Bot/Plugins/EntityPlugin.cs b/MineSharp.Bot/Plugins/EntityPlugin.cs index 6220c573..de855eea 100644 --- a/MineSharp.Bot/Plugins/EntityPlugin.cs +++ b/MineSharp.Bot/Plugins/EntityPlugin.cs @@ -212,7 +212,8 @@ private Task HandleUpdateEntityPositionPacket(EntityPositionPacket packet) entity.IsOnGround = packet.OnGround; - return OnEntityMoved.Dispatch(Bot, entity); + _ = OnEntityMoved.Dispatch(Bot, entity); + return Task.CompletedTask; } private Task HandleUpdateEntityPositionAndRotationPacket(EntityPositionAndRotationPacket packet) @@ -236,7 +237,8 @@ private Task HandleUpdateEntityPositionAndRotationPacket(EntityPositionAndRotati entity.Pitch = NetUtils.FromAngleByte(packet.Pitch); entity.IsOnGround = packet.OnGround; - return OnEntityMoved.Dispatch(Bot, entity); + _ = OnEntityMoved.Dispatch(Bot, entity); + return Task.CompletedTask; } private Task HandleUpdateEntityRotationPacket(EntityRotationPacket packet) @@ -255,7 +257,8 @@ private Task HandleUpdateEntityRotationPacket(EntityRotationPacket packet) entity.Pitch = NetUtils.FromAngleByte(packet.Pitch); entity.IsOnGround = packet.OnGround; - return OnEntityMoved.Dispatch(Bot, entity); + _ = OnEntityMoved.Dispatch(Bot, entity); + return Task.CompletedTask; } private Task HandleTeleportEntityPacket(TeleportEntityPacket packet) @@ -276,7 +279,8 @@ private Task HandleTeleportEntityPacket(TeleportEntityPacket packet) entity.Yaw = NetUtils.FromAngleByte(packet.Yaw); entity.Pitch = NetUtils.FromAngleByte(packet.Pitch); - return OnEntityMoved.Dispatch(Bot, entity); + _ = OnEntityMoved.Dispatch(Bot, entity); + return Task.CompletedTask; } private Task HandleUpdateAttributesPacket(UpdateAttributesPacket packet) diff --git a/MineSharp.Bot/Plugins/PhysicsPlugin.cs b/MineSharp.Bot/Plugins/PhysicsPlugin.cs index 5e57c11c..b4f23997 100644 --- a/MineSharp.Bot/Plugins/PhysicsPlugin.cs +++ b/MineSharp.Bot/Plugins/PhysicsPlugin.cs @@ -319,7 +319,7 @@ private async Task UpdateServerPos() await Bot.Client.SendPacket(packet); - await BotMoved.Dispatch(Bot); + _ = BotMoved.Dispatch(Bot); } private void OnSneakingChanged(PlayerPhysics sender, bool isSneaking) diff --git a/MineSharp.Bot/Plugins/WindowPlugin.cs b/MineSharp.Bot/Plugins/WindowPlugin.cs index d441c71e..27acea21 100644 --- a/MineSharp.Bot/Plugins/WindowPlugin.cs +++ b/MineSharp.Bot/Plugins/WindowPlugin.cs @@ -207,8 +207,8 @@ public async Task SelectHotbarIndex(byte hotbarIndex) await Bot.Client.SendPacket(packet); SelectedHotbarIndex = hotbarIndex; - - await OnHeldItemChanged.Dispatch(Bot, HeldItem); + + _ = OnHeldItemChanged.Dispatch(Bot, HeldItem); } /// diff --git a/MineSharp.Core/Events/AsyncEvent.cs b/MineSharp.Core/Events/AsyncEvent.cs index e81f8a2b..17ec8f71 100644 --- a/MineSharp.Core/Events/AsyncEvent.cs +++ b/MineSharp.Core/Events/AsyncEvent.cs @@ -13,7 +13,7 @@ public abstract class AsyncEventBase where TSync : Delegate where /// List of synchronous handlers subscribed to this event /// protected readonly HashSet Handlers = []; - + /// /// List of asynchronous handlers subscribed to this event /// @@ -25,8 +25,8 @@ public abstract class AsyncEventBase where TSync : Delegate where public void Subscribe(TSync handler) { Handlers.Add(handler); - } - + } + /// /// Unsubscribe from this event /// @@ -34,7 +34,7 @@ public void Unsubscribe(TSync handler) { Handlers.Remove(handler); } - + /// /// Subscribe to this event /// @@ -50,14 +50,13 @@ public void Unsubscribe(TAsync handler) { AsyncHandlers.Remove(handler); } - + /// /// Makes sure all handlers run to completion and catch exceptions in the handlers /// /// - /// /// - protected Task WaitForHandlers(Task[] tasks, bool block = false) + protected Task WaitForHandlers(Task[] tasks) { var task = Task.Run(async () => { @@ -74,9 +73,7 @@ protected Task WaitForHandlers(Task[] tasks, bool block = false) } }); - return block - ? task - : Task.CompletedTask; + return task; } /// @@ -99,27 +96,26 @@ public class AsyncEvent : AsyncEventBase public delegate void Handler(); - + /// /// An asynchronous event handler /// public delegate Task AsyncHandler(); - + /// /// Dispatch this event /// - /// Whether to block until all handlers are completed - /// - public Task Dispatch(bool block = false) + /// A task that completes once all handlers have completed. + public Task Dispatch() { var tasks = AsyncHandlers .Select(handler => Task.Run(async () => await handler())) .Concat(Handlers.Select(handler => Task.Run(() => handler()))) .ToArray(); - return WaitForHandlers(tasks, block); + return WaitForHandlers(tasks); } - + /// /// Subscribe to this event /// @@ -131,7 +127,7 @@ public Task Dispatch(bool block = false) eventBase.Subscribe(handler); return eventBase; } - + /// /// Subscribe to this event /// @@ -143,7 +139,7 @@ public Task Dispatch(bool block = false) eventBase.Subscribe(handler); return eventBase; } - + /// /// Unsubscribe from this event /// @@ -155,7 +151,7 @@ public Task Dispatch(bool block = false) eventBase.Unsubscribe(handler); return eventBase; } - + /// /// Unsubscribe from this event /// @@ -178,28 +174,27 @@ public class AsyncEvent : AsyncEventBase.Handler, AsyncEvent /// A synchronous event handler /// public delegate void Handler(T arg1); - + /// /// An asynchronous event handler /// public delegate Task AsyncHandler(T arg1); - + /// /// Dispatch this event /// - /// Whether to block until all handlers are completed /// First argument for the handlers - /// - public Task Dispatch(T arg1, bool block = false) + /// A task that completes once all handlers have completed. + public Task Dispatch(T arg1) { var tasks = AsyncHandlers .Select(handler => Task.Run(async () => await handler(arg1))) .Concat(Handlers.Select(handler => Task.Run(() => handler(arg1)))) .ToArray(); - return WaitForHandlers(tasks, block); + return WaitForHandlers(tasks); } - + /// /// Subscribe to this event /// @@ -211,7 +206,7 @@ public Task Dispatch(T arg1, bool block = false) eventBase.Subscribe(handler); return eventBase; } - + /// /// Subscribe to this event /// @@ -223,7 +218,7 @@ public Task Dispatch(T arg1, bool block = false) eventBase.Subscribe(handler); return eventBase; } - + /// /// Unsubscribe from this event /// @@ -235,7 +230,7 @@ public Task Dispatch(T arg1, bool block = false) eventBase.Unsubscribe(handler); return eventBase; } - + /// /// Unsubscribe from this event /// @@ -258,29 +253,28 @@ public class AsyncEvent : AsyncEventBase.Handler, Asy /// A synchronous event handler /// public delegate void Handler(T1 arg1, T2 arg2); - + /// /// An asynchronous event handler /// public delegate Task AsyncHandler(T1 arg1, T2 arg2); - + /// /// Dispatch this event /// - /// Whether to block until all handlers are completed /// First argument for the handlers /// Second argument for the handlers - /// - public Task Dispatch(T1 arg1, T2 arg2, bool block = false) + /// A task that completes once all handlers have completed. + public Task Dispatch(T1 arg1, T2 arg2) { var tasks = AsyncHandlers .Select(handler => Task.Run(async () => await handler(arg1, arg2))) .Concat(Handlers.Select(handler => Task.Run(() => handler(arg1, arg2)))) .ToArray(); - return WaitForHandlers(tasks, block); + return WaitForHandlers(tasks); } - + /// /// Subscribe to this event /// @@ -292,7 +286,7 @@ public Task Dispatch(T1 arg1, T2 arg2, bool block = false) eventBase.Subscribe(handler); return eventBase; } - + /// /// Subscribe to this event /// @@ -304,7 +298,7 @@ public Task Dispatch(T1 arg1, T2 arg2, bool block = false) eventBase.Subscribe(handler); return eventBase; } - + /// /// Unsubscribe from this event /// @@ -316,7 +310,7 @@ public Task Dispatch(T1 arg1, T2 arg2, bool block = false) eventBase.Unsubscribe(handler); return eventBase; } - + /// /// Unsubscribe from this event /// @@ -339,30 +333,29 @@ public class AsyncEvent : AsyncEventBase.Hand /// A synchronous event handler /// public delegate void Handler(T1 arg1, T2 arg2, T3 arg3); - + /// /// An asynchronous event handler /// public delegate Task AsyncHandler(T1 arg1, T2 arg2, T3 arg3); - + /// /// Dispatch this event /// - /// Whether to block until all handlers are completed /// First argument for the handlers /// Second argument for the handlers /// Third argument for the handlers - /// - public Task Dispatch(T1 arg1, T2 arg2, T3 arg3, bool block = false) + /// A task that completes once all handlers have completed. + public Task Dispatch(T1 arg1, T2 arg2, T3 arg3) { var tasks = AsyncHandlers .Select(handler => Task.Run(async () => await handler(arg1, arg2, arg3))) .Concat(Handlers.Select(handler => Task.Run(() => handler(arg1, arg2, arg3)))) .ToArray(); - - return WaitForHandlers(tasks, block); + + return WaitForHandlers(tasks); } - + /// /// Subscribe to this event /// @@ -374,7 +367,7 @@ public Task Dispatch(T1 arg1, T2 arg2, T3 arg3, bool block = false) eventBase.Subscribe(handler); return eventBase; } - + /// /// Subscribe to this event /// @@ -386,7 +379,7 @@ public Task Dispatch(T1 arg1, T2 arg2, T3 arg3, bool block = false) eventBase.Subscribe(handler); return eventBase; } - + /// /// Unsubscribe from this event /// @@ -398,7 +391,7 @@ public Task Dispatch(T1 arg1, T2 arg2, T3 arg3, bool block = false) eventBase.Unsubscribe(handler); return eventBase; } - + /// /// Unsubscribe from this event /// @@ -421,12 +414,12 @@ public class AsyncEvent : AsyncEventBase public delegate void Handler(T1 arg1, T2 arg2, T3 arg3, T4 arg4); - + /// /// An asynchronous event handler /// public delegate Task AsyncHandler(T1 arg1, T2 arg2, T3 arg3, T4 arg4); - + /// /// Dispatch this event /// @@ -435,17 +428,17 @@ public class AsyncEvent : AsyncEventBaseSecond argument for the handlers /// Third argument for the handlers /// Fourth argument for the handlers - /// - public Task Dispatch(T1 arg1, T2 arg2, T3 arg3, T4 arg4, bool block = false) + /// A task that completes once all handlers have completed. + public Task Dispatch(T1 arg1, T2 arg2, T3 arg3, T4 arg4) { var tasks = AsyncHandlers .Select(handler => Task.Run(async () => await handler(arg1, arg2, arg3, arg4))) .Concat(Handlers.Select(handler => Task.Run(() => handler(arg1, arg2, arg3, arg4)))) .ToArray(); - - return WaitForHandlers(tasks, block); + + return WaitForHandlers(tasks); } - + /// /// Subscribe to this event /// @@ -457,7 +450,7 @@ public Task Dispatch(T1 arg1, T2 arg2, T3 arg3, T4 arg4, bool block = false) eventBase.Subscribe(handler); return eventBase; } - + /// /// Subscribe to this event /// @@ -469,7 +462,7 @@ public Task Dispatch(T1 arg1, T2 arg2, T3 arg3, T4 arg4, bool block = false) eventBase.Subscribe(handler); return eventBase; } - + /// /// Unsubscribe from this event /// @@ -481,7 +474,7 @@ public Task Dispatch(T1 arg1, T2 arg2, T3 arg3, T4 arg4, bool block = false) eventBase.Unsubscribe(handler); return eventBase; } - + /// /// Unsubscribe from this event /// From ca42d38115df0b281d4cb1ddced1cbb5771d8069 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 7 Aug 2024 03:09:45 +0200 Subject: [PATCH 24/73] added ConcurrentHashSet nuget to make AsyncEventBase thread-safe --- MineSharp.Core/Events/AsyncEvent.cs | 23 ++++++++++++----------- MineSharp.Core/MineSharp.Core.csproj | 2 ++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/MineSharp.Core/Events/AsyncEvent.cs b/MineSharp.Core/Events/AsyncEvent.cs index 17ec8f71..2bf7ceb1 100644 --- a/MineSharp.Core/Events/AsyncEvent.cs +++ b/MineSharp.Core/Events/AsyncEvent.cs @@ -1,4 +1,5 @@ -using NLog; +using ConcurrentCollections; +using NLog; namespace MineSharp.Core.Events; @@ -12,43 +13,43 @@ public abstract class AsyncEventBase where TSync : Delegate where /// /// List of synchronous handlers subscribed to this event /// - protected readonly HashSet Handlers = []; + protected readonly ConcurrentHashSet Handlers = []; /// /// List of asynchronous handlers subscribed to this event /// - protected readonly HashSet AsyncHandlers = []; + protected readonly ConcurrentHashSet AsyncHandlers = []; /// /// Subscribe to this event /// - public void Subscribe(TSync handler) + public bool Subscribe(TSync handler) { - Handlers.Add(handler); + return Handlers.Add(handler); } /// /// Unsubscribe from this event /// - public void Unsubscribe(TSync handler) + public bool Unsubscribe(TSync handler) { - Handlers.Remove(handler); + return Handlers.TryRemove(handler); } /// /// Subscribe to this event /// - public void Subscribe(TAsync handler) + public bool Subscribe(TAsync handler) { - AsyncHandlers.Add(handler); + return AsyncHandlers.Add(handler); } /// /// Unsubscribe from this event /// - public void Unsubscribe(TAsync handler) + public bool Unsubscribe(TAsync handler) { - AsyncHandlers.Remove(handler); + return AsyncHandlers.TryRemove(handler); } /// diff --git a/MineSharp.Core/MineSharp.Core.csproj b/MineSharp.Core/MineSharp.Core.csproj index fcfa8c0c..7cab6d0e 100644 --- a/MineSharp.Core/MineSharp.Core.csproj +++ b/MineSharp.Core/MineSharp.Core.csproj @@ -27,6 +27,8 @@ + + From 4a335683c2a750a6a439d021f73d3c0bc7b85084 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 7 Aug 2024 19:20:55 +0200 Subject: [PATCH 25/73] refactored all Packet classes to be sealed records + serialization improvements - added IVersionAwareSerializable to extend ISerializable with version specific logic like in the packets - moved some core element serialization methods in their classes fixes #68 --- .../MineSharp.Protocol/ClientSettings.cs | 27 +- .../MineSharp.Protocol/MinecraftClient.cs | 8 +- .../Configuration/DisconnectPacket.cs | 13 +- .../Configuration/FeatureFlagsPacket.cs | 14 +- .../FinishConfigurationPacket.cs | 5 +- .../Configuration/KeepAlivePacket.cs | 13 +- .../Clientbound/Configuration/PingPacket.cs | 11 +- .../Configuration/PluginMessagePacket.cs | 38 +-- .../Configuration/RegistryDataPacket.cs | 18 +- .../Clientbound/Login/DisconnectPacket.cs | 17 +- .../Login/EncryptionRequestPacket.cs | 30 +- .../Login/LoginPluginRequestPacket.cs | 39 +-- .../Clientbound/Login/LoginSuccessPacket.cs | 50 +-- .../Clientbound/Login/SetCompressionPacket.cs | 15 +- .../Play/AcknowledgeBlockChangePacket.cs | 80 ++--- .../Clientbound/Play/BlockUpdatePacket.cs | 31 +- .../Clientbound/Play/BundleDelimiterPacket.cs | 6 +- .../Packets/Clientbound/Play/ChatPacket.cs | 40 +-- .../Play/ChunkBatchFinishedPacket.cs | 21 +- .../Clientbound/Play/ChunkBatchStartPacket.cs | 5 +- .../Play/ChunkDataAndUpdateLightPacket.cs | 130 ++------ .../Clientbound/Play/CloseWindowPacket.cs | 26 +- .../Clientbound/Play/CombatDeathPacket.cs | 25 +- .../Clientbound/Play/DeclareCommandsPacket.cs | 25 +- .../Clientbound/Play/DisconnectPacket.cs | 26 +- .../Play/DisguisedChatMessagePacket.cs | 30 +- .../Play/EntityPositionAndRotationPacket.cs | 40 ++- .../Clientbound/Play/EntityPositionPacket.cs | 34 +-- .../Clientbound/Play/EntityRotationPacket.cs | 31 +- .../Play/EntitySoundEffectPacket.cs | 38 +-- .../Clientbound/Play/EntityStatusPacket.cs | 25 +- .../Clientbound/Play/GameEventPacket.cs | 56 ++-- .../Clientbound/Play/KeepAlivePacket.cs | 20 +- .../Packets/Clientbound/Play/LoginPacket.cs | 122 ++++---- .../Play/MultiBlockUpdatePacket.cs | 23 +- .../Clientbound/Play/OpenWindowPacket.cs | 37 +-- .../Clientbound/Play/ParticlePacket.cs | 74 ++--- .../Packets/Clientbound/Play/PingPacket.cs | 23 +- .../Clientbound/Play/PlayerChatPacket.cs | 112 +++---- .../Play/PlayerInfoRemovePacket.cs | 12 +- .../Play/PlayerInfoUpdatePacket.cs | 286 +++++++++--------- .../Clientbound/Play/PlayerPositionPacket.cs | 80 +++-- .../Clientbound/Play/RemoveEntitiesPacket.cs | 12 +- .../Packets/Clientbound/Play/RespawnPacket.cs | 51 ++-- .../Play/SetEntityVelocityPacket.cs | 18 +- .../Clientbound/Play/SetHealthPacket.cs | 16 +- .../Clientbound/Play/SetHeldItemPacket.cs | 12 +- .../Clientbound/Play/SetPassengersPacket.cs | 15 +- .../Clientbound/Play/SoundEffectPacket.cs | 44 +-- .../Clientbound/Play/SpawnEntityPacket.cs | 90 +++--- .../Play/SpawnLivingEntityPacket.cs | 70 +++-- .../Clientbound/Play/SpawnPaintingPacket.cs | 37 ++- .../Clientbound/Play/SpawnPlayerPacket.cs | 44 +-- .../Play/SystemChatMessagePacket.cs | 33 +- .../Clientbound/Play/TeleportEntityPacket.cs | 32 +- .../Clientbound/Play/UnloadChunkPacket.cs | 25 +- .../Play/UpdateAttributesPacket.cs | 54 +--- .../Clientbound/Play/WindowItemsPacket.cs | 31 +- .../Clientbound/Play/WindowSetSlotPacket.cs | 28 +- ...esponsePacket.cs => PingResponsePacket.cs} | 20 +- .../Status/StatusResponsePacket.cs | 18 +- .../Packets/Handlers/LoginPacketHandler.cs | 2 +- .../Packets/ISerializable.cs | 16 +- .../Packets/IVersionAwareSerializable.cs | 27 ++ .../Packets/NetworkTypes/ChatMessageItem.cs | 2 +- .../Packets/PacketPalette.cs | 4 +- .../Configuration/ClientInformationPacket.cs | 69 +++-- .../FinishConfigurationPacket.cs | 8 +- .../Configuration/KeepAlivePacket.cs | 22 +- .../Configuration/PluginMessagePacket.cs | 30 +- .../Serverbound/Configuration/PongPacket.cs | 25 +- .../ResourcePackResponsePacket.cs | 40 ++- .../Handshaking/HandshakePacket.cs | 29 +- .../Login/EncryptionResponsePacket.cs | 49 ++- ...inPacket.cs => LoginAcknowledgedPacket.cs} | 17 +- .../Login/LoginPluginResponsePacket.cs | 28 +- .../Serverbound/Login/LoginStartPacket.cs | 43 ++- .../Serverbound/Play/ChatCommandPacket.cs | 105 +++++-- .../Serverbound/Play/ChatMessagePacket.cs | 27 +- .../Packets/Serverbound/Play/ChatPacket.cs | 12 +- .../Play/ChunkBatchReceivedPacket.cs | 19 +- .../Serverbound/Play/ClientCommandPacket.cs | 21 +- .../Play/ClientInformationPacket.cs | 52 ++-- .../Serverbound/Play/CloseWindowPacket.cs | 15 +- .../Serverbound/Play/ConfirmTeleportPacket.cs | 12 +- .../Serverbound/Play/EntityActionPacket.cs | 43 ++- .../Serverbound/Play/InteractPacket.cs | 73 ++--- .../Serverbound/Play/KeepAlivePacket.cs | 12 +- .../Play/MessageAcknowledgementPacket.cs | 21 +- .../Serverbound/Play/PlaceBlockPacket.cs | 33 +- .../Serverbound/Play/PlayerActionPacket.cs | 25 +- .../Serverbound/Play/PlayerSessionPacket.cs | 21 +- .../Packets/Serverbound/Play/PongPacket.cs | 10 +- .../Serverbound/Play/SetCreativeSlotPacket.cs | 26 +- .../Serverbound/Play/SetHeldItemPacket.cs | 19 +- .../SetPlayerPositionAndRotationPacket.cs | 22 +- .../Play/SetPlayerPositionPacket.cs | 18 +- .../Serverbound/Play/SwingArmPacket.cs | 14 +- .../Serverbound/Play/UpdateCommandBlock.cs | 21 +- .../Packets/Serverbound/Play/UseItemPacket.cs | 40 +-- .../Serverbound/Play/WindowClickPacket.cs | 37 +-- .../Serverbound/Status/PingRequestPacket.cs | 18 +- .../Serverbound/Status/StatusRequestPacket.cs | 6 +- MineSharp.Bot/Plugins/EntityPlugin.cs | 10 +- .../Common/Entities/Attributes/Attribute.cs | 30 +- .../Common/Entities/Attributes/Modifier.cs | 21 +- 106 files changed, 1612 insertions(+), 1988 deletions(-) rename Components/MineSharp.Protocol/Packets/Clientbound/Status/{PongResponsePacket.cs => PingResponsePacket.cs} (52%) create mode 100644 Components/MineSharp.Protocol/Packets/IVersionAwareSerializable.cs rename Components/MineSharp.Protocol/Packets/Serverbound/Login/{AcknowledgeLoginPacket.cs => LoginAcknowledgedPacket.cs} (50%) diff --git a/Components/MineSharp.Protocol/ClientSettings.cs b/Components/MineSharp.Protocol/ClientSettings.cs index 25f4a041..1f6ef572 100644 --- a/Components/MineSharp.Protocol/ClientSettings.cs +++ b/Components/MineSharp.Protocol/ClientSettings.cs @@ -1,5 +1,4 @@ using MineSharp.Core.Common; -using NLog; namespace MineSharp.Protocol; @@ -16,7 +15,7 @@ public record ClientSettings 24, ChatMode.Enabled, true, - 0x7F, + SkinPart.All, PlayerHand.MainHand, false, true); @@ -25,7 +24,7 @@ public record ClientSettings /// Constructor /// public ClientSettings(string locale, byte viewDistance, ChatMode chatMode, bool coloredChat, - byte displayedSkinParts, + SkinPart displayedSkinParts, PlayerHand mainHand, bool enableTextFiltering, bool allowServerListings) { Locale = locale; @@ -61,7 +60,7 @@ public ClientSettings(string locale, byte viewDistance, ChatMode chatMode, bool /// /// Bitmask of skin parts displayed by the client (not used) /// - public byte DisplayedSkinParts { get; } + public SkinPart DisplayedSkinParts { get; } /// /// The clients main hand @@ -79,6 +78,26 @@ public ClientSettings(string locale, byte viewDistance, ChatMode chatMode, bool public bool AllowServerListings { get; } } +/// +/// Specifies the parts of the skin that are enabled +/// +[Flags] +public enum SkinPart : byte +{ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + None = 0x00, + Cape = 0x01, + Jacket = 0x02, + LeftSleeve = 0x04, + RightSleeve = 0x08, + LeftPants = 0x10, + RightPants = 0x20, + Hat = 0x40, + // 0x80 is unused + All = Cape | Jacket | LeftSleeve | RightSleeve | LeftPants | RightPants | Hat +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member +} + /// /// Specifies the chat mode /// diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index 03048ecb..74eb690a 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -361,10 +361,10 @@ internal void UpdateGameState(GameState next) SendPacket(new Packets.Serverbound.Play.ClientInformationPacket( Settings.Locale, Settings.ViewDistance, - (int)Settings.ChatMode, + Settings.ChatMode, Settings.ColoredChat, Settings.DisplayedSkinParts, - (int)Settings.MainHand, + Settings.MainHand, Settings.EnableTextFiltering, Settings.AllowServerListings))); } @@ -376,10 +376,10 @@ internal void UpdateGameState(GameState next) _ = SendPacket(new ClientInformationPacket( Settings.Locale, Settings.ViewDistance, - (int)Settings.ChatMode, + Settings.ChatMode, Settings.ColoredChat, Settings.DisplayedSkinParts, - (int)Settings.MainHand, + Settings.MainHand, Settings.EnableTextFiltering, Settings.AllowServerListings)); } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/DisconnectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/DisconnectPacket.cs index e1d3a4fa..413bdedb 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/DisconnectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/DisconnectPacket.cs @@ -9,16 +9,13 @@ namespace MineSharp.Protocol.Packets.Clientbound.Configuration; /// Configuration Disconnect packet /// See https://wiki.vg/Protocol#Disconnect_.28configuration.29 /// -public class DisconnectPacket : IPacket +/// Reason for disconnect +public sealed record DisconnectPacket(Chat Reason) : IPacket { /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Configuration_Disconnect; - - /// - /// Reason for disconnect - /// - public required Chat Reason { get; init; } + /// + public static PacketType StaticType => PacketType.CB_Configuration_Disconnect; /// public void Write(PacketBuffer buffer, MinecraftData version) @@ -29,6 +26,6 @@ public void Write(PacketBuffer buffer, MinecraftData version) /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - return new DisconnectPacket { Reason = buffer.ReadChatComponent() }; + return new DisconnectPacket(buffer.ReadChatComponent()); } } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FeatureFlagsPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FeatureFlagsPacket.cs index 05e879e5..81ff79b8 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FeatureFlagsPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FeatureFlagsPacket.cs @@ -8,16 +8,13 @@ namespace MineSharp.Protocol.Packets.Clientbound.Configuration; /// Feature flags packet /// See https://wiki.vg/Protocol#Feature_Flags /// -public class FeatureFlagsPacket : IPacket +/// The enabled feature flags +public sealed record FeatureFlagsPacket(string[] FeatureFlags) : IPacket { /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Configuration_FeatureFlags; - - /// - /// The enabled feature flags - /// - public required string[] FeatureFlags { get; init; } + /// + public static PacketType StaticType => PacketType.CB_Configuration_FeatureFlags; /// public void Write(PacketBuffer buffer, MinecraftData version) @@ -28,7 +25,6 @@ public void Write(PacketBuffer buffer, MinecraftData version) /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - return new FeatureFlagsPacket { FeatureFlags = buffer.ReadVarIntArray(buff => buff.ReadString()) }; + return new FeatureFlagsPacket(buffer.ReadVarIntArray(buff => buff.ReadString())); } } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FinishConfigurationPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FinishConfigurationPacket.cs index f974146d..f9c54885 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FinishConfigurationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FinishConfigurationPacket.cs @@ -8,11 +8,12 @@ namespace MineSharp.Protocol.Packets.Clientbound.Configuration; /// Finish configuration packet /// See https://wiki.vg/Protocol#Finish_Configuration /// -public class FinishConfigurationPacket : IPacket +public sealed record FinishConfigurationPacket : IPacket { /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Configuration_FinishConfiguration; + /// + public static PacketType StaticType => PacketType.CB_Configuration_FinishConfiguration; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/KeepAlivePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/KeepAlivePacket.cs index 9482d4fe..ef0e6e2c 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/KeepAlivePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/KeepAlivePacket.cs @@ -8,16 +8,13 @@ namespace MineSharp.Protocol.Packets.Clientbound.Configuration; /// Keep alive packet in Configuration /// See https://wiki.vg/Protocol#Clientbound_Keep_Alive_.28configuration.29 /// -public class KeepAlivePacket : IPacket +/// The keep alive id +public sealed record KeepAlivePacket(long KeepAliveId) : IPacket { /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Configuration_KeepAlive; - - /// - /// The keep alive id - /// - public required long KeepAliveId { get; init; } + /// + public static PacketType StaticType => PacketType.CB_Configuration_KeepAlive; /// public void Write(PacketBuffer buffer, MinecraftData version) @@ -28,6 +25,6 @@ public void Write(PacketBuffer buffer, MinecraftData version) /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - return new KeepAlivePacket() { KeepAliveId = buffer.ReadLong() }; + return new KeepAlivePacket(buffer.ReadLong()); } } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PingPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PingPacket.cs index f89f0b0f..1ddea7b3 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PingPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PingPacket.cs @@ -8,17 +8,14 @@ namespace MineSharp.Protocol.Packets.Clientbound.Configuration; /// Ping packet /// See https://wiki.vg/Protocol#Ping_.28configuration.29 /// -public class PingPacket : IPacket +/// The id of the ping +public sealed record PingPacket(int Id) : IPacket { /// public PacketType Type => StaticType; + /// public static PacketType StaticType => PacketType.CB_Configuration_Ping; - /// - /// The id of the ping - /// - public required int Id { get; init; } - /// public void Write(PacketBuffer buffer, MinecraftData version) { @@ -28,6 +25,6 @@ public void Write(PacketBuffer buffer, MinecraftData version) /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - return new PingPacket() { Id = buffer.ReadInt() }; + return new PingPacket(buffer.ReadInt()); } } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PluginMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PluginMessagePacket.cs index 169784a3..545d84ef 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PluginMessagePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PluginMessagePacket.cs @@ -3,50 +3,32 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Configuration; -#pragma warning disable CS1591 + /// /// Plugin message packet /// -public class PluginMessagePacket : IPacket +/// The name of the channel the data was sent +/// The message data +public sealed record PluginMessagePacket(string ChannelName, byte[] Data) : IPacket { - /// - /// Create a new instance - /// - /// - /// - public PluginMessagePacket(string channelName, PacketBuffer data) - { - ChannelName = channelName; - Data = data; - } - - /// - /// The name of the channel the data was sent - /// - public string ChannelName { get; set; } - - /// - /// The message data - /// - public PacketBuffer Data { get; set; } - /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Configuration_CustomPayload; + /// + public static PacketType StaticType => PacketType.CB_Configuration_CustomPayload; /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteString(ChannelName); - buffer.WriteBytes(Data.GetBuffer()); + buffer.WriteBytes(Data); } /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var channelName = buffer.ReadString(); - var clone = new PacketBuffer(buffer.ReadBytes((int)buffer.ReadableBytes), version.Version.Protocol); - return new PluginMessagePacket(channelName, clone); + var data = buffer.RestBuffer(); + return new PluginMessagePacket(channelName, data); } } -#pragma warning restore CS1591 + diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RegistryDataPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RegistryDataPacket.cs index b8385491..9acbe40a 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RegistryDataPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RegistryDataPacket.cs @@ -9,26 +9,24 @@ namespace MineSharp.Protocol.Packets.Clientbound.Configuration; /// Registry data packet /// See https://wiki.vg/Protocol#Registry_Data /// -public class RegistryDataPacket : IPacket +/// The registry data +public sealed record RegistryDataPacket(NbtCompound RegistryData) : IPacket { /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Configuration_RegistryData; - - /// - /// The registry data - /// - public required NbtCompound RegistryData { get; init; } - + /// + public static PacketType StaticType => PacketType.CB_Configuration_RegistryData; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteNbt(RegistryData); } - + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - return new RegistryDataPacket() { RegistryData = buffer.ReadNbtCompound() }; + return new RegistryDataPacket(buffer.ReadNbtCompound()); } } + diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs index 467394c5..8263660e 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs @@ -9,28 +9,25 @@ namespace MineSharp.Protocol.Packets.Clientbound.Login; /// Disconnect packet for login /// See https://wiki.vg/Protocol#Disconnect_.28login.29 /// -public class DisconnectPacket : IPacket +/// The reason for being disconnected +public sealed record DisconnectPacket(Chat Reason) : IPacket { /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Login_Disconnect; - - /// - /// The reason for being disconnected - /// - public required Chat Reason { get; init; } - + /// + public static PacketType StaticType => PacketType.CB_Login_Disconnect; + /// public void Write(PacketBuffer buffer, MinecraftData version) { // Disconnect (login) packet is always sent as JSON text component according to wiki.vg buffer.WriteString(Reason.ToJson().ToString()); } - + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var reason = buffer.ReadString(); - return new DisconnectPacket() { Reason = Chat.Parse(reason) }; + return new DisconnectPacket(Chat.Parse(reason)); } } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/EncryptionRequestPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/EncryptionRequestPacket.cs index ef124ab2..6577bd36 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/EncryptionRequestPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/EncryptionRequestPacket.cs @@ -8,26 +8,15 @@ namespace MineSharp.Protocol.Packets.Clientbound.Login; /// Encryption request packet /// See https://wiki.vg/Protocol#Encryption_Request /// -public class EncryptionRequestPacket : IPacket +/// The hashed server id +/// The public key of the server +/// Verify token +public sealed record EncryptionRequestPacket(string ServerId, byte[] PublicKey, byte[] VerifyToken) : IPacket { /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Login_EncryptionBegin; - - /// - /// The hashed server id - /// - public required string ServerId { get; init; } - - /// - /// The public key of the server - /// - public required byte[] PublicKey { get; init; } - - /// - /// Verify token - /// - public required byte[] VerifyToken { get; init; } + /// + public static PacketType StaticType => PacketType.CB_Login_EncryptionBegin; /// public void Write(PacketBuffer buffer, MinecraftData version) @@ -48,11 +37,6 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) var verifyToken = new byte[buffer.ReadVarInt()]; buffer.ReadBytes(verifyToken); - return new EncryptionRequestPacket() - { - ServerId = serverId, - PublicKey = publicKey, - VerifyToken = verifyToken - }; + return new EncryptionRequestPacket(serverId, publicKey, verifyToken); } } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginPluginRequestPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginPluginRequestPacket.cs index 9e00044e..11b74422 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginPluginRequestPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginPluginRequestPacket.cs @@ -3,43 +3,19 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Login; -#pragma warning disable CS1591 + /// /// Login plugin request packet /// -public class LoginPluginRequestPacket : IPacket +/// The message id +/// The channel identifier +/// The raw message data +public sealed record LoginPluginRequestPacket(int MessageId, string Channel, byte[] Data) : IPacket { - /// - /// Create a new instance - /// - /// - /// - /// - public LoginPluginRequestPacket(int messageId, string channel, byte[] data) - { - MessageId = messageId; - Channel = channel; - Data = data; - } - - /// - /// The message id - /// - public int MessageId { get; set; } - - /// - /// The channel identifier - /// - public string Channel { get; set; } // TODO: Identifier - - /// - /// The raw message data - /// - public byte[] Data { get; set; } - /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Login_LoginPluginRequest; + /// + public static PacketType StaticType => PacketType.CB_Login_LoginPluginRequest; /// public void Write(PacketBuffer buffer, MinecraftData version) @@ -59,4 +35,3 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) return new LoginPluginRequestPacket(messageId, channel, data); } } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginSuccessPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginSuccessPacket.cs index e96c5bc8..a4cb5a28 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginSuccessPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginSuccessPacket.cs @@ -3,32 +3,22 @@ using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Exceptions; +using static MineSharp.Protocol.Packets.Clientbound.Login.LoginSuccessPacket; namespace MineSharp.Protocol.Packets.Clientbound.Login; /// /// Login success packet /// -public class LoginSuccessPacket : IPacket +/// Uuid +/// Username of the client +/// A list of properties sent for versions >= 1.19 +public sealed record LoginSuccessPacket(Uuid Uuid, string Username, Property[]? Properties = null) : IPacket { /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Login_Success; - - /// - /// Uuid - /// - public required Uuid Uuid { get; init; } - - /// - /// Username of the client - /// - public required string Username { get; init; } - - /// - /// A list of properties sent for versions >= 1.19 - /// - public Property[]? Properties { get; init; } = null; + /// + public static PacketType StaticType => PacketType.CB_Login_Success; /// public void Write(PacketBuffer buffer, MinecraftData version) @@ -61,34 +51,14 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) properties = buffer.ReadVarIntArray(Property.Read); } - return new LoginSuccessPacket() - { - Uuid = uuid, - Username = username, - Properties = properties - }; + return new LoginSuccessPacket(uuid, username, properties); } /// /// A player property /// - public class Property : ISerializable + public sealed record Property(string Name, string Value, string? Signature) : ISerializable { - /// - /// Name of this property - /// - public required string Name { get; init; } - - /// - /// Value of this property - /// - public required string Value { get; init; } - - /// - /// Signature - /// - public required string? Signature { get; init; } - /// public void Write(PacketBuffer buffer) { @@ -114,7 +84,7 @@ public static Property Read(PacketBuffer buffer) signature = buffer.ReadString(); } - return new() { Name = name, Value = value, Signature = signature }; + return new Property(name, value, signature); } } } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/SetCompressionPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/SetCompressionPacket.cs index 40f8cdc7..8c966085 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/SetCompressionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/SetCompressionPacket.cs @@ -7,17 +7,14 @@ namespace MineSharp.Protocol.Packets.Clientbound.Login; /// /// Set Compression packet /// -public class SetCompressionPacket : IPacket +/// Threshold for when to use compression +public sealed record SetCompressionPacket(int Threshold) : IPacket { /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Login_Compress; - - /// - /// Threshold for when to use compression - /// - public required int Threshold { get; init; } - + /// + public static PacketType StaticType => PacketType.CB_Login_Compress; + /// public void Write(PacketBuffer buffer, MinecraftData version) { @@ -28,6 +25,6 @@ public void Write(PacketBuffer buffer, MinecraftData version) public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var threshold = buffer.ReadVarInt(); - return new SetCompressionPacket() { Threshold = threshold }; + return new SetCompressionPacket(threshold); } } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/AcknowledgeBlockChangePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/AcknowledgeBlockChangePacket.cs index b77ff1c6..1bf5d25a 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/AcknowledgeBlockChangePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/AcknowledgeBlockChangePacket.cs @@ -9,8 +9,21 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; /// /// Acknowledge block change packet /// -public class AcknowledgeBlockChangePacket : IPacket +public sealed record AcknowledgeBlockChangePacket : IPacket { + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_AcknowledgePlayerDigging; + + // Here is no non-argument constructor allowed + // Do not use +#pragma warning disable CS8618 + private AcknowledgeBlockChangePacket() +#pragma warning restore CS8618 + { + } + /// /// Constructor for version >= 1.19 /// @@ -39,14 +52,10 @@ internal AcknowledgeBlockChangePacket(IPacketBody body) /// /// The body of this packet. - /// Different minecraft versions use different packet bodies. + /// Different Minecraft versions use different packet bodies. /// public IPacketBody Body { get; set; } - /// - public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_AcknowledgePlayerDigging; - /// public void Write(PacketBuffer buffer, MinecraftData version) { @@ -64,7 +73,6 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) return new AcknowledgeBlockChangePacket(PacketBody119.Read(buffer)); } - /// /// Packet body of /// @@ -87,43 +95,12 @@ public interface IPacketBody /// /// Acknowledge block change packet for < 1.19 /// - public class PacketBody118 : IPacketBody + /// The Position of the block + /// Block state + /// Status of the block change + /// Whether the block change was successful + public sealed record PacketBody118(Position Location, int Block, int Status, bool Successful) : IPacketBody { - /// - /// Create a new instance - /// - /// - /// - /// - /// - public PacketBody118(Position location, int block, int status, bool successful) - { - Location = location; - Block = block; - Status = status; - Successful = successful; - } - - /// - /// The Position of the block - /// - public Position Location { get; set; } - - /// - /// Block state - /// - public int Block { get; set; } - - /// - /// Status of the block change - /// - public int Status { get; set; } - - /// - /// Whether the block change was successful - /// - public bool Successful { get; set; } - /// public void Write(PacketBuffer buffer) { @@ -147,22 +124,9 @@ public static IPacketBody Read(PacketBuffer buffer) /// /// Acknowledge block change packet body for versions >= 1.19 /// - public class PacketBody119 : IPacketBody + /// Sequence id used for synchronization + public sealed record PacketBody119(int SequenceId) : IPacketBody { - /// - /// Create a new instance - /// - /// - public PacketBody119(int sequenceId) - { - SequenceId = sequenceId; - } - - /// - /// Sequence id used for synchronization - /// - public int SequenceId { get; set; } - /// public void Write(PacketBuffer buffer) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockUpdatePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockUpdatePacket.cs index 02a8f4ef..28b873f9 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockUpdatePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockUpdatePacket.cs @@ -4,36 +4,18 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 + /// /// Block update packet /// -public class BlockUpdatePacket : IPacket +/// The location of the block update +/// The new state id +public sealed record BlockUpdatePacket(Position Location, int StateId) : IPacket { - /// - /// Create a new instance - /// - /// - /// - public BlockUpdatePacket(Position location, int stateId) - { - Location = location; - StateId = stateId; - } - - /// - /// The location of the block update - /// - public Position Location { get; set; } - - /// - /// The new state id - /// - public int StateId { get; set; } - /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_BlockChange; + /// + public static PacketType StaticType => PacketType.CB_Play_BlockChange; /// public void Write(PacketBuffer buffer, MinecraftData version) @@ -50,4 +32,3 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) return new BlockUpdatePacket(location, stateId); } } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/BundleDelimiterPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BundleDelimiterPacket.cs index 2b778b38..2be2a837 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/BundleDelimiterPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BundleDelimiterPacket.cs @@ -3,14 +3,15 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 + /// /// Bundle delimiter packet /// -public class BundleDelimiterPacket : IPacket +public sealed record BundleDelimiterPacket : IPacket { /// public PacketType Type => StaticType; + /// public static PacketType StaticType => PacketType.CB_Play_BundleDelimiter; /// @@ -23,4 +24,3 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) return new BundleDelimiterPacket(); } } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChatPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChatPacket.cs index 70cda1c5..e036fdd6 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChatPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChatPacket.cs @@ -3,44 +3,20 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 + /// /// ChatPacket only used for versions <= 1.18.2. /// It was replaced by multiple packets in 1.19 /// -public class ChatPacket : IPacket +/// The chat message +/// The position of the chat message +/// The UUID of the message sender +public sealed record ChatPacket(string Message, byte Position, Uuid Sender) : IPacket { - /// - /// Create a new instance - /// - /// - /// - /// - public ChatPacket(string message, byte position, Uuid sender) - { - Message = message; - Position = position; - Sender = sender; - } - - /// - /// The chat message - /// - public string Message { get; set; } - - /// - /// The position of the chat message - /// - public byte Position { get; set; } - - /// - /// The UUID of the message sender - /// - public Uuid Sender { get; set; } - /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_Chat; + /// + public static PacketType StaticType => PacketType.CB_Play_Chat; /// public void Write(PacketBuffer buffer, MinecraftData version) @@ -59,4 +35,4 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) buffer.ReadUuid()); } } -#pragma warning restore CS1591 + diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchFinishedPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchFinishedPacket.cs index 4b01dd80..f76c6a74 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchFinishedPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchFinishedPacket.cs @@ -8,25 +8,13 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; /// The ChunkBatchFinished packet, used since 1.20.2. /// https://wiki.vg/Protocol#Chunk_Batch_Finished /// -public class ChunkBatchFinishedPacket : IPacket +/// The batch size +public sealed record ChunkBatchFinishedPacket(int BatchSize) : IPacket { - /// - /// Create a new ChunkBatchFinishedPacket instance - /// - /// - public ChunkBatchFinishedPacket(int batchSize) - { - BatchSize = batchSize; - } - - /// - /// The batch size - /// - public int BatchSize { get; set; } - /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_ChunkBatchFinished; + /// + public static PacketType StaticType => PacketType.CB_Play_ChunkBatchFinished; /// public void Write(PacketBuffer buffer, MinecraftData version) @@ -41,3 +29,4 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) buffer.ReadVarInt()); } } + diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchStartPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchStartPacket.cs index a95465e3..526abc7c 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchStartPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchStartPacket.cs @@ -8,11 +8,12 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; /// The ChunkBatchStart Packet, used since 1.20.2 /// https://wiki.vg/Protocol#Chunk_Batch_Start /// -public class ChunkBatchStartPacket : IPacket +public sealed record ChunkBatchStartPacket : IPacket { /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_ChunkBatchStart; + /// + public static PacketType StaticType => PacketType.CB_Play_ChunkBatchStart; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkDataAndUpdateLightPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkDataAndUpdateLightPacket.cs index 89cbaa3f..2364cb93 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkDataAndUpdateLightPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkDataAndUpdateLightPacket.cs @@ -7,112 +7,40 @@ using MineSharp.Protocol.Exceptions; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 + /// /// Chunk data and update light packet /// -public class ChunkDataAndUpdateLightPacket : IPacket +/// X coordinate of the chunk +/// Y coordinate of the chunk +/// Heightmaps +/// Raw chunk data +/// Array of BlockEntities +/// Whether to trust edges (only sent before 1.20) +/// +/// +/// +/// +/// +/// +public sealed record ChunkDataAndUpdateLightPacket( + int X, + int Z, + NbtCompound Heightmaps, + byte[] ChunkData, + BlockEntity[] BlockEntities, + bool? TrustEdges, + long[] SkyLightMask, + long[] BlockLightMask, + long[] EmptySkyLightMask, + long[] EmptyBlockLightMask, + byte[][] SkyLight, + byte[][] BlockLight) : IPacket { - /// - /// Create a new instance - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public ChunkDataAndUpdateLightPacket( - int x, - int z, - NbtCompound heightmaps, - byte[] chunkData, - BlockEntity[] blockEntities, - bool? trustEdges, - long[] skyLightMask, - long[] blockLightMask, - long[] emptyBlockLightMask, - long[] emptySkyLightMask, - byte[][] skyLight, - byte[][] blockLight) - { - X = x; - Z = z; - Heightmaps = heightmaps; - ChunkData = chunkData; - BlockEntities = blockEntities; - TrustEdges = trustEdges; - SkyLightMask = skyLightMask; - BlockLightMask = blockLightMask; - EmptyBlockLightMask = emptyBlockLightMask; - EmptySkyLightMask = emptySkyLightMask; - SkyLight = skyLight; - BlockLight = blockLight; - } - - /// - /// X coordinate of the chunk - /// - public int X { get; set; } - - /// - /// Y coordinate of the chunk - /// - public int Z { get; set; } - - /// - /// Heightmaps - /// - public NbtCompound Heightmaps { get; set; } - - /// - /// Raw chunk data - /// - public byte[] ChunkData { get; set; } - - /// - /// Array of BlockEntities - /// - public BlockEntity[] BlockEntities { get; set; } - - /// - /// Whether to trust edges (only sent before 1.20) - /// - public bool? TrustEdges { get; set; } - - /// - /// - public long[] SkyLightMask { get; set; } - - /// - /// - public long[] BlockLightMask { get; set; } - - /// - /// - public long[] EmptySkyLightMask { get; set; } - - /// - /// - public long[] EmptyBlockLightMask { get; set; } - - /// - /// - public byte[][] SkyLight { get; set; } - - /// - /// - public byte[][] BlockLight { get; set; } - /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_MapChunk; + /// + public static PacketType StaticType => PacketType.CB_Play_MapChunk; /// public void Write(PacketBuffer buffer, MinecraftData version) @@ -151,7 +79,6 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteBytes(array); } - buffer.WriteVarInt(BlockLight.Length); foreach (var array in BlockLight) { @@ -214,4 +141,3 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) blockLight); } } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/CloseWindowPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/CloseWindowPacket.cs index b6684186..709b1ccd 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/CloseWindowPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/CloseWindowPacket.cs @@ -3,29 +3,17 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 + /// /// Close window packet +/// The id of the window to close /// -public class CloseWindowPacket : IPacket +public sealed record CloseWindowPacket(byte WindowId) : IPacket { - /// - /// Create a new instance - /// - /// - public CloseWindowPacket(byte windowId) - { - WindowId = windowId; - } - - /// - /// The id of the window to close - /// - public byte WindowId { get; set; } - /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_CloseWindow; + /// + public static PacketType StaticType => PacketType.CB_Play_CloseWindow; /// public void Write(PacketBuffer buffer, MinecraftData version) @@ -36,8 +24,6 @@ public void Write(PacketBuffer buffer, MinecraftData version) /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - return new CloseWindowPacket( - buffer.ReadByte()); + return new CloseWindowPacket(buffer.ReadByte()); } } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/CombatDeathPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/CombatDeathPacket.cs index 23626dbe..58fa802a 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/CombatDeathPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/CombatDeathPacket.cs @@ -8,8 +8,21 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; /// /// Combat death packet /// -public class CombatDeathPacket : IPacket +public sealed record CombatDeathPacket : IPacket { + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_DeathCombatEvent; + + // Here is no non-argument constructor allowed + // Do not use +#pragma warning disable CS8618 + private CombatDeathPacket() +#pragma warning restore CS8618 + { + } + /// /// Constructor before 1.20 /// @@ -44,21 +57,17 @@ private CombatDeathPacket(int playerId, int? entityId, string message) /// /// Id of the player /// - public int PlayerId { get; set; } + public int PlayerId { get; init; } /// /// Id of the entity /// - public int? EntityId { get; set; } + public int? EntityId { get; init; } /// /// Death message /// - public string Message { get; set; } - - /// - public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_DeathCombatEvent; + public string Message { get; init; } /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DeclareCommandsPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DeclareCommandsPacket.cs index beb3e123..198df3fe 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DeclareCommandsPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DeclareCommandsPacket.cs @@ -3,29 +3,19 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 + /// /// Declare commands packet /// -public class DeclareCommandsPacket : IPacket +/// +/// Raw buffer. The Command tree is not parsed here +/// +public sealed record DeclareCommandsPacket(PacketBuffer RawBuffer) : IPacket { - /// - /// Create a new instance - /// - /// - public DeclareCommandsPacket(PacketBuffer buffer) - { - RawBuffer = buffer; - } - - /// - /// Raw buffer. The Command tree is not parsed here - /// - public PacketBuffer RawBuffer { get; set; } - /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_DeclareCommands; + /// + public static PacketType StaticType => PacketType.CB_Play_DeclareCommands; /// public void Write(PacketBuffer buffer, MinecraftData version) @@ -40,4 +30,3 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) return new DeclareCommandsPacket(clone); } } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisconnectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisconnectPacket.cs index 72240187..82463e0c 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisconnectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisconnectPacket.cs @@ -4,29 +4,19 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 + /// /// Disconnect packet for play /// -public class DisconnectPacket : IPacket +/// +/// The reason for being disconnected +/// +public sealed record DisconnectPacket(Chat Reason) : IPacket { - /// - /// Create a new instance - /// - /// - public DisconnectPacket(Chat reason) - { - Reason = reason; - } - - /// - /// The reason for being disconnected - /// - public Chat Reason { get; set; } - /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_KickDisconnect; + /// + public static PacketType StaticType => PacketType.CB_Play_KickDisconnect; /// public void Write(PacketBuffer buffer, MinecraftData version) @@ -40,4 +30,4 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) return new DisconnectPacket(buffer.ReadChatComponent()); } } -#pragma warning restore CS1591 + diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisguisedChatMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisguisedChatMessagePacket.cs index cbbfc48a..e84ffb1d 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisguisedChatMessagePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisguisedChatMessagePacket.cs @@ -4,24 +4,22 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 -public class DisguisedChatMessagePacket : IPacket -{ - public DisguisedChatMessagePacket(Chat message, int chatType, Chat name, Chat? target) - { - Message = message; - ChatType = chatType; - Name = name; - Target = target; - } - public Chat Message { get; set; } - public int ChatType { get; set; } - public Chat Name { get; set; } - public Chat? Target { get; set; } +/// +/// Disguised chat message packet +/// +/// The chat message +/// The type of chat +/// The name associated with the chat +/// The target of the chat message (optional) +public sealed record DisguisedChatMessagePacket(Chat Message, int ChatType, Chat Name, Chat? Target) : IPacket +{ + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_ProfilelessChat; + /// + public static PacketType StaticType => PacketType.CB_Play_ProfilelessChat; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteChatComponent(Message); @@ -34,6 +32,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) } } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { return new DisguisedChatMessagePacket( @@ -43,4 +42,3 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) buffer.ReadBool() ? buffer.ReadChatComponent() : null); } } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionAndRotationPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionAndRotationPacket.cs index 5de4e0bb..299c87da 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionAndRotationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionAndRotationPacket.cs @@ -3,31 +3,25 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 -public class EntityPositionAndRotationPacket : IPacket -{ - public EntityPositionAndRotationPacket(int entityId, short deltaX, short deltaY, short deltaZ, sbyte yaw, - sbyte pitch, bool onGround) - { - EntityId = entityId; - DeltaX = deltaX; - DeltaY = deltaY; - DeltaZ = deltaZ; - Yaw = yaw; - Pitch = pitch; - OnGround = onGround; - } - public int EntityId { get; set; } - public short DeltaX { get; set; } - public short DeltaY { get; set; } - public short DeltaZ { get; set; } - public sbyte Yaw { get; set; } - public sbyte Pitch { get; set; } - public bool OnGround { get; set; } +/// +/// Entity position and rotation packet +/// +/// The entity ID +/// The change in X position +/// The change in Y position +/// The change in Z position +/// The yaw rotation +/// The pitch rotation +/// Whether the entity is on the ground +public sealed record EntityPositionAndRotationPacket(int EntityId, short DeltaX, short DeltaY, short DeltaZ, sbyte Yaw, sbyte Pitch, bool OnGround) : IPacket +{ + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_EntityMoveLook; + /// + public static PacketType StaticType => PacketType.CB_Play_EntityMoveLook; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteVarInt(EntityId); @@ -39,6 +33,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteBool(OnGround); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var entityId = buffer.ReadVarInt(); @@ -56,4 +51,3 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) onGround); } } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionPacket.cs index 4eb6e10e..3c5c1204 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionPacket.cs @@ -3,26 +3,23 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 -public class EntityPositionPacket : IPacket -{ - public EntityPositionPacket(int entityId, short deltaX, short deltaY, short deltaZ, bool onGround) - { - EntityId = entityId; - DeltaX = deltaX; - DeltaY = deltaY; - DeltaZ = deltaZ; - OnGround = onGround; - } - public int EntityId { get; set; } - public short DeltaX { get; set; } - public short DeltaY { get; set; } - public short DeltaZ { get; set; } - public bool OnGround { get; set; } +/// +/// Entity position packet +/// +/// The entity ID +/// The change in X position +/// The change in Y position +/// The change in Z position +/// Whether the entity is on the ground +public sealed record EntityPositionPacket(int EntityId, short DeltaX, short DeltaY, short DeltaZ, bool OnGround) : IPacket +{ + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_RelEntityMove; + /// + public static PacketType StaticType => PacketType.CB_Play_RelEntityMove; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteVarInt(EntityId); @@ -32,6 +29,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteBool(OnGround); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var entityId = buffer.ReadVarInt(); @@ -46,4 +44,4 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) onGround); } } -#pragma warning restore CS1591 + diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityRotationPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityRotationPacket.cs index ff7df713..473512ed 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityRotationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityRotationPacket.cs @@ -3,24 +3,22 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 -public class EntityRotationPacket : IPacket -{ - public EntityRotationPacket(int entityId, sbyte yaw, sbyte pitch, bool onGround) - { - EntityId = entityId; - Yaw = yaw; - Pitch = pitch; - OnGround = onGround; - } - public int EntityId { get; set; } - public sbyte Yaw { get; set; } - public sbyte Pitch { get; set; } - public bool OnGround { get; set; } +/// +/// Entity rotation packet +/// +/// The entity ID +/// The yaw rotation +/// The pitch rotation +/// Whether the entity is on the ground +public sealed record EntityRotationPacket(int EntityId, sbyte Yaw, sbyte Pitch, bool OnGround) : IPacket +{ + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_EntityLook; + /// + public static PacketType StaticType => PacketType.CB_Play_EntityLook; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteVarInt(EntityId); @@ -29,6 +27,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteBool(OnGround); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var entityId = buffer.ReadVarInt(); @@ -39,4 +38,4 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) return new EntityRotationPacket(entityId, yaw, pitch, onGround); } } -#pragma warning restore CS1591 + diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs index aa34b740..030f6eef 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs @@ -4,32 +4,22 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 -public class EntitySoundEffectPacket : IPacket +public sealed record EntitySoundEffectPacket( + int SoundId, + string? SoundName, + bool? HasFixedRange, + float? Range, + int SoundCategory, + int EntityId, + float Volume, + float Pitch, + long Seed +) : IPacket { - public EntitySoundEffectPacket(int soundId, string? soundName, bool? hasFixedRange, float? range, int soundCategory, int entityId, float volume, float pitch, long seed) - { - SoundId = soundId; - SoundName = soundName; - HasFixedRange = hasFixedRange; - Range = range; - SoundCategory = soundCategory; - EntityId = entityId; - Volume = volume; - Pitch = pitch; - Seed = seed; - } - - public int SoundId { get; set; } - public string? SoundName { get; set; } - public bool? HasFixedRange { get; set; } - public float? Range { get; set; } - public int SoundCategory { get; set; } - public int EntityId { get; set; } - public float Volume { get; set; } - public float Pitch { get; set; } - public long Seed { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_EntitySoundEffect; + /// + public static PacketType StaticType => PacketType.CB_Play_EntitySoundEffect; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityStatusPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityStatusPacket.cs index 17f2433e..d8071df8 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityStatusPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityStatusPacket.cs @@ -3,26 +3,27 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 -public class EntityStatusPacket : IPacket -{ - public EntityStatusPacket(int entityId, byte status) - { - EntityId = entityId; - Status = status; - } - public int EntityId { get; set; } - public byte Status { get; set; } +/// +/// Entity status packet +/// +/// The entity ID +/// The status byte +public sealed record EntityStatusPacket(int EntityId, byte Status) : IPacket +{ + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_EntityStatus; + /// + public static PacketType StaticType => PacketType.CB_Play_EntityStatus; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteVarInt(EntityId); buffer.WriteByte(Status); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { return new EntityStatusPacket( @@ -30,4 +31,4 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) buffer.ReadByte()); } } -#pragma warning restore CS1591 + diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/GameEventPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/GameEventPacket.cs index 74db2e62..f6c6b42c 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/GameEventPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/GameEventPacket.cs @@ -1,11 +1,40 @@ using MineSharp.Core.Common; using MineSharp.Data; using MineSharp.Data.Protocol; +using static MineSharp.Protocol.Packets.Clientbound.Play.GameEventPacket; namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 -public class GameEventPacket : IPacket +/// +/// Game event packet +/// +/// The game event +/// The value associated with the event +public sealed record GameEventPacket(GameEvent Event, float Value) : IPacket { + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_GameStateChange; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteByte((byte)Event); + buffer.WriteFloat(Value); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var @event = buffer.ReadByte(); + var value = buffer.ReadFloat(); + return new GameEventPacket((GameEvent)@event, value); + } + + /// + /// All the possible game events + /// public enum GameEvent : byte { NoRespawnBlockAvailable, @@ -23,29 +52,6 @@ public enum GameEvent : byte LimitedCrafting, StartWaitingForLevelChunks } - - public GameEventPacket(GameEvent @event, float value) - { - Event = @event; - Value = value; - } - - public GameEvent Event { get; set; } - public float Value { get; set; } - public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_GameStateChange; - - public void Write(PacketBuffer buffer, MinecraftData version) - { - buffer.WriteByte((byte)Event); - buffer.WriteFloat(Value); - } - - public static IPacket Read(PacketBuffer buffer, MinecraftData version) - { - var @event = buffer.ReadByte(); - var value = buffer.ReadFloat(); - return new GameEventPacket((GameEvent)@event, value); - } } + #pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/KeepAlivePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/KeepAlivePacket.cs index 932f034e..37f41eba 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/KeepAlivePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/KeepAlivePacket.cs @@ -3,27 +3,27 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 -public class KeepAlivePacket : IPacket +/// +/// Keep alive packet +/// +/// The keep-alive ID +public sealed record KeepAlivePacket(long KeepAliveId) : IPacket { - public KeepAlivePacket(long id) - { - KeepAliveId = id; - } - - public long KeepAliveId { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_KeepAlive; + /// + public static PacketType StaticType => PacketType.CB_Play_KeepAlive; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteLong(KeepAliveId); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var id = buffer.ReadLong(); return new KeepAlivePacket(id); } } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs index 2e3a0522..e413ac81 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs @@ -7,78 +7,60 @@ using MineSharp.Protocol.Exceptions; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 -public class LoginPacket : IPacket -{ - public LoginPacket(int entityId, - bool isHardcore, - byte gameMode, - sbyte previousGameMode, - string[] dimensionNames, - NbtCompound? registryCodec, - string dimensionType, - string dimensionName, - long hashedSeed, - int maxPlayers, - int viewDistance, - int simulationDistance, - bool reducedDebugInfo, - bool enableRespawnScreen, - bool isDebug, - bool isFlat, - bool hasDeathLocation, - string? deathDimensionName, - Position? deathLocation, - int? portalCooldown, - bool? doLimitedCrafting) - { - EntityId = entityId; - IsHardcore = isHardcore; - GameMode = gameMode; - PreviousGameMode = previousGameMode; - DimensionNames = dimensionNames; - RegistryCodec = registryCodec; - DimensionType = dimensionType; - DimensionName = dimensionName; - HashedSeed = hashedSeed; - MaxPlayers = maxPlayers; - ViewDistance = viewDistance; - SimulationDistance = simulationDistance; - ReducedDebugInfo = reducedDebugInfo; - EnableRespawnScreen = enableRespawnScreen; - IsDebug = isDebug; - IsFlat = isFlat; - HasDeathLocation = hasDeathLocation; - DeathDimensionName = deathDimensionName; - DeathLocation = deathLocation; - PortalCooldown = portalCooldown; - DoLimitedCrafting = doLimitedCrafting; - } - public int EntityId { get; set; } - public bool IsHardcore { get; set; } - public byte GameMode { get; set; } - public sbyte PreviousGameMode { get; set; } - public string[] DimensionNames { get; set; } - public NbtCompound? RegistryCodec { get; set; } - public string DimensionType { get; set; } - public string DimensionName { get; set; } - public long HashedSeed { get; set; } - public int MaxPlayers { get; set; } - public int ViewDistance { get; set; } - public int SimulationDistance { get; set; } - public bool ReducedDebugInfo { get; set; } - public bool EnableRespawnScreen { get; set; } - public bool IsDebug { get; set; } - public bool IsFlat { get; set; } - public bool HasDeathLocation { get; set; } - public string? DeathDimensionName { get; set; } - public Position? DeathLocation { get; set; } - public int? PortalCooldown { get; set; } - public bool? DoLimitedCrafting { get; set; } // since 1.20.2 +/// +/// Represents a login packet. +/// +/// The entity ID. +/// Indicates if the game is in hardcore mode. +/// The current game mode. +/// The previous game mode. +/// The names of the dimensions. +/// The registry codec. +/// The type of the dimension. +/// The name of the dimension. +/// The hashed seed. +/// The maximum number of players. +/// The view distance. +/// The simulation distance. +/// Indicates if reduced debug info is enabled. +/// Indicates if the respawn screen is enabled. +/// Indicates if the game is in debug mode. +/// Indicates if the world is flat. +/// Indicates if there is a death location. +/// The name of the death dimension. +/// The death location. +/// The portal cooldown. +/// Indicates if limited crafting is enabled. +public sealed record LoginPacket( + int EntityId, + bool IsHardcore, + byte GameMode, + sbyte PreviousGameMode, + string[] DimensionNames, + NbtCompound? RegistryCodec, + string DimensionType, + string DimensionName, + long HashedSeed, + int MaxPlayers, + int ViewDistance, + int SimulationDistance, + bool ReducedDebugInfo, + bool EnableRespawnScreen, + bool IsDebug, + bool IsFlat, + bool HasDeathLocation, + string? DeathDimensionName, + Position? DeathLocation, + int? PortalCooldown, + bool? DoLimitedCrafting) : IPacket +{ + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_Login; + /// + public static PacketType StaticType => PacketType.CB_Play_Login; + /// public void Write(PacketBuffer buffer, MinecraftData version) { if (version.Version.Protocol < ProtocolVersion.V_1_19) @@ -140,6 +122,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) } } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { if (version.Version.Protocol >= ProtocolVersion.V_1_20_2) @@ -271,4 +254,3 @@ private static LoginPacket ReadV1_20_2(PacketBuffer buffer, MinecraftData data) doLimitedCrafting); } } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/MultiBlockUpdatePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/MultiBlockUpdatePacket.cs index 5079788a..d7c08788 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/MultiBlockUpdatePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/MultiBlockUpdatePacket.cs @@ -6,8 +6,21 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 -public class MultiBlockUpdatePacket : IPacket +public sealed record MultiBlockUpdatePacket : IPacket { + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_MultiBlockChange; + + // Here is no non-argument constructor allowed + // Do not use +#pragma warning disable CS8618 + private MultiBlockUpdatePacket() +#pragma warning restore CS8618 + { + } + /// /// Constructor for before 1.20 /// @@ -33,11 +46,9 @@ public MultiBlockUpdatePacket(long chunkSection, long[] blocks) Blocks = blocks; } - public long ChunkSection { get; set; } - public bool? SuppressLightUpdates { get; set; } - public long[] Blocks { get; set; } - public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_MultiBlockChange; + public long ChunkSection { get; init; } + public bool? SuppressLightUpdates { get; init; } + public long[] Blocks { get; init; } public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenWindowPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenWindowPacket.cs index 8a1553b7..e02dbeae 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenWindowPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenWindowPacket.cs @@ -5,32 +5,27 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 -public class OpenWindowPacket : IPacket + +/// +/// Represents a packet to open a window in the client. +/// +/// The ID of the window. +/// The type of the inventory. +/// The title of the window. +/// The chat component of the window title. +public sealed record OpenWindowPacket(int WindowId, int InventoryType, string WindowTitle, Chat? WindowTitleChat = null) : IPacket { - public OpenWindowPacket(int windowId, int inventoryType, string windowTitle) - { - WindowId = windowId; - InventoryType = inventoryType; - WindowTitle = windowTitle; - } + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_OpenWindow; public OpenWindowPacket(int windowId, int inventoryType, Chat windowTitle) + : this(windowId, inventoryType, windowTitle.GetMessage(null), windowTitle) { - WindowId = windowId; - InventoryType = inventoryType; - WindowTitleChat = windowTitle; - WindowTitle = windowTitle.GetMessage(null); } - public int WindowId { get; set; } - public int InventoryType { get; set; } - public string WindowTitle { get; set; } - - public Chat? WindowTitleChat { get; set; } - public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_OpenWindow; - + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteVarInt(WindowId); @@ -38,6 +33,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteString(WindowTitle); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { if (version.Version.Protocol == ProtocolVersion.V_1_20_3) @@ -55,4 +51,3 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) buffer.ReadString()); } } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ParticlePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ParticlePacket.cs index 04189395..06f2f130 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ParticlePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ParticlePacket.cs @@ -3,42 +3,44 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 -public class ParticlePacket : IPacket -{ - public ParticlePacket(int particleId, bool longDistance, double x, double y, double z, float offsetX, float offsetY, float offsetZ, float maxSpeed, int particleCount, PacketBuffer data) - { - ParticleId = particleId; - LongDistance = longDistance; - X = x; - Y = y; - Z = z; - OffsetX = offsetX; - OffsetY = offsetY; - OffsetZ = offsetZ; - MaxSpeed = maxSpeed; - ParticleCount = particleCount; - Data = data; - } - public int ParticleId { get; set; } - public bool LongDistance { get; set; } - public double X { get; set; } - public double Y { get; set; } - public double Z { get; set; } - public float OffsetX { get; set; } - public float OffsetY { get; set; } - public float OffsetZ { get; set; } - public float MaxSpeed { get; set; } - public int ParticleCount { get; set; } - /// - /// Data depends on the particle id. - /// Will be an empty buffer for most particles. - /// - public PacketBuffer Data { get; set; } +/// +/// Represents a packet for particle effects in the game. +/// +/// The ID of the particle. +/// Indicates if the particle is long distance. +/// The X coordinate of the particle. +/// The Y coordinate of the particle. +/// The Z coordinate of the particle. +/// The X offset of the particle. +/// The Y offset of the particle. +/// The Z offset of the particle. +/// The maximum speed of the particle. +/// The number of particles. +/// +/// Data depends on the particle id. +/// Will be an empty buffer for most particles. +/// +public sealed record ParticlePacket( + int ParticleId, + bool LongDistance, + double X, + double Y, + double Z, + float OffsetX, + float OffsetY, + float OffsetZ, + float MaxSpeed, + int ParticleCount, + PacketBuffer Data +) : IPacket +{ + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_WorldParticles; + /// + public static PacketType StaticType => PacketType.CB_Play_WorldParticles; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteVarInt(ParticleId); @@ -54,6 +56,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteBytes(Data.GetBuffer()); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var particleId = buffer.ReadVarInt(); @@ -66,12 +69,9 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) var offsetZ = buffer.ReadFloat(); var maxSpeed = buffer.ReadFloat(); var particleCount = buffer.ReadVarInt(); - var byteBuffer = new byte[buffer.ReadableBytes]; - buffer.ReadBytes(byteBuffer); + var byteBuffer = buffer.RestBuffer(); var data = new PacketBuffer(byteBuffer, buffer.ProtocolVersion); return new ParticlePacket(particleId, longDistance, x, y, z, offsetX, offsetY, offsetZ, maxSpeed, particleCount, data); } - } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PingPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PingPacket.cs index 28cfce12..ebdda23c 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PingPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PingPacket.cs @@ -7,25 +7,13 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; /// /// Ping Packet https://wiki.vg/Protocol#Ping_.28play.29 /// -public class PingPacket : IPacket +/// The id of the ping +public sealed record PingPacket(int Id) : IPacket { - /// - /// Create a new instance - /// - /// - public PingPacket(int id) - { - Id = id; - } - - /// - /// The id of the ping - /// - public int Id { get; set; } - /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_Ping; + /// + public static PacketType StaticType => PacketType.CB_Play_Ping; /// public void Write(PacketBuffer buffer, MinecraftData version) @@ -36,7 +24,6 @@ public void Write(PacketBuffer buffer, MinecraftData version) /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - return new PingPacket( - buffer.ReadInt()); + return new PingPacket(buffer.ReadInt()); } } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerChatPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerChatPacket.cs index 90749246..bd5b3169 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerChatPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerChatPacket.cs @@ -4,19 +4,16 @@ using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Packets.NetworkTypes; +using static MineSharp.Protocol.Packets.Clientbound.Play.PlayerChatPacket; namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 -public class PlayerChatPacket : IPacket +public sealed record PlayerChatPacket(IChatMessageBody Body) : IPacket { - public PlayerChatPacket(IChatMessageBody body) - { - Body = body; - } - - public IChatMessageBody Body { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_PlayerChat; + /// + public static PacketType StaticType => PacketType.CB_Play_PlayerChat; public void Write(PacketBuffer buffer, MinecraftData version) { @@ -43,33 +40,31 @@ public interface IChatMessageBody void Write(PacketBuffer buffer, MinecraftData version); } - public class V119Body : IChatMessageBody + /// + /// Represents the body of a chat message in version 1.19. + /// + /// The signed chat message. + /// The unsigned chat message, if available. + /// The type of the message. + /// The UUID of the sender. + /// The name of the sender. + /// The name of the sender's team, if available. + /// The timestamp of the message. + /// The salt value for the message. + /// The signature of the message. + public sealed record V119Body( + Chat SignedChat, + Chat? UnsignedChat, + int MessageType, + Uuid Sender, + Chat SenderName, + Chat? SenderTeamName, + long Timestamp, + long Salt, + byte[] Signature + ) : IChatMessageBody { - public V119Body(Chat signedChat, Chat? unsignedChat, int messageType, Uuid sender, Chat senderName, - Chat? senderTeamName, - long timestamp, long salt, byte[] signature) - { - SignedChat = signedChat; - UnsignedChat = unsignedChat; - MessageType = messageType; - Sender = sender; - SenderName = senderName; - SenderTeamName = senderTeamName; - Timestamp = timestamp; - Salt = salt; - Signature = signature; - } - - public Chat SignedChat { get; set; } - public Chat? UnsignedChat { get; set; } - public int MessageType { get; set; } - public Uuid Sender { get; set; } - public Chat SenderName { get; set; } - public Chat? SenderTeamName { get; set; } - public long Timestamp { get; set; } - public long Salt { get; set; } - public byte[] Signature { get; set; } - + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteChatComponent(SignedChat); @@ -85,6 +80,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteUuid(Sender); var hasTeamName = SenderTeamName != null; + buffer.WriteBool(hasTeamName); if (hasTeamName) { buffer.WriteChatComponent(SenderTeamName!); @@ -96,6 +92,11 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteBytes(Signature); } + /// + /// Reads a from the given . + /// + /// The buffer to read from. + /// The read . public static V119Body Read(PacketBuffer buffer) { var signedChat = buffer.ReadChatComponent(); @@ -123,13 +124,20 @@ public static V119Body Read(PacketBuffer buffer) var signature = new byte[buffer.ReadVarInt()]; buffer.ReadBytes(signature); - return new(signedChat, unsignedChat, messageType, sender, senderName, senderTeamName, timestamp, salt, - signature); + return new V119Body(signedChat, unsignedChat, messageType, sender, senderName, senderTeamName, timestamp, salt, signature); } } - public class V11923Body : IChatMessageBody + public sealed record V11923Body : IChatMessageBody { + // Here is no non-argument constructor allowed + // Do not use +#pragma warning disable CS8618 + private V11923Body() +#pragma warning restore CS8618 + { + } + private V11923Body(byte[]? previousSignature, Uuid sender, int? index, byte[]? signature, string plainMessage, Chat? formattedMessage, long timestamp, long salt, ChatMessageItem[] previousMessages, Chat? unsignedContent, int filterType, long[]? filterTypeMask, int type, Chat networkName, @@ -237,21 +245,21 @@ public V11923Body( NetworkTargetName = networkTargetName; } - public byte[]? PreviousSignature { get; set; } - public Uuid Sender { get; set; } - public int? Index { get; set; } - public byte[]? Signature { get; set; } - public string PlainMessage { get; set; } - public Chat? FormattedMessage { get; set; } - public long Timestamp { get; set; } - public long Salt { get; set; } - public ChatMessageItem[] PreviousMessages { get; set; } - public Chat? UnsignedContent { get; set; } - public int FilterType { get; set; } - public long[]? FilterTypeMask { get; set; } - public int Type { get; set; } - public Chat NetworkName { get; set; } - public Chat? NetworkTargetName { get; set; } + public byte[]? PreviousSignature { get; init; } + public Uuid Sender { get; init; } + public int? Index { get; init; } + public byte[]? Signature { get; init; } + public string PlainMessage { get; init; } + public Chat? FormattedMessage { get; init; } + public long Timestamp { get; init; } + public long Salt { get; init; } + public ChatMessageItem[] PreviousMessages { get; init; } + public Chat? UnsignedContent { get; init; } + public int FilterType { get; init; } + public long[]? FilterTypeMask { get; init; } + public int Type { get; init; } + public Chat NetworkName { get; init; } + public Chat? NetworkTargetName { get; init; } public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoRemovePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoRemovePacket.cs index 3b7c7302..f64e7539 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoRemovePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoRemovePacket.cs @@ -4,16 +4,12 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 -public class PlayerInfoRemovePacket : IPacket +public sealed record PlayerInfoRemovePacket(Uuid[] Players) : IPacket { - public PlayerInfoRemovePacket(Uuid[] players) - { - Players = players; - } - - public Uuid[] Players { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_PlayerRemove; + /// + public static PacketType StaticType => PacketType.CB_Play_PlayerRemove; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoUpdatePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoUpdatePacket.cs index 5c325b50..fc9e7cbd 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoUpdatePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoUpdatePacket.cs @@ -1,24 +1,22 @@ -using MineSharp.Core; +using System.Collections.Frozen; +using MineSharp.Core; using MineSharp.Core.Common; using MineSharp.Data; using MineSharp.Data.Protocol; +using static MineSharp.Protocol.Packets.Clientbound.Play.PlayerInfoUpdatePacket; +using static MineSharp.Protocol.Packets.Clientbound.Play.PlayerInfoUpdatePacket.AddPlayerAction; +using static MineSharp.Protocol.Packets.Clientbound.Play.PlayerInfoUpdatePacket.CryptoActionV19; +using static MineSharp.Protocol.Packets.Clientbound.Play.PlayerInfoUpdatePacket.InitializeChatAction; namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 -public class PlayerInfoUpdatePacket : IPacket +public sealed record PlayerInfoUpdatePacket(int Action, ActionEntry[] Data) : IPacket { - public PlayerInfoUpdatePacket(int action, ActionEntry[] data) - { - Action = action; - Data = data; - } - - public int Action { get; set; } - - public ActionEntry[] Data { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_PlayerInfo; + /// + public static PacketType StaticType => PacketType.CB_Play_PlayerInfo; public void Write(PacketBuffer buffer, MinecraftData version) { @@ -54,17 +52,8 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) return new PlayerInfoUpdatePacket(action, data); } - public class ActionEntry + public sealed record ActionEntry(Uuid Player, IPlayerInfoAction[] Actions) { - public ActionEntry(Uuid player, IPlayerInfoAction[] actions) - { - Player = player; - Actions = actions; - } - - public Uuid Player { get; set; } - public IPlayerInfoAction[] Actions { get; set; } - public void Write(PacketBuffer buffer) { buffer.WriteUuid(Player); @@ -111,57 +100,70 @@ public static ActionEntry Read(PacketBuffer buffer, MinecraftData version, int a } else { - if ((action & 0x01) != 0) + foreach (var (mask, actionFactory) in ActionRegistry.ActionFactories) { - actions.Add(AddPlayerAction.Read(buffer)); + if ((action & mask) != 0) + { + actions.Add(actionFactory(buffer)); + } } + } - if ((action & 0x02) != 0) - { - actions.Add(InitializeChatAction.Read(buffer)); - } + return new(uuid, actions.ToArray()); + } + } - if ((action & 0x04) != 0) - { - actions.Add(UpdateGameModeAction.Read(buffer)); - } + public static class ActionRegistry + { + public static readonly FrozenDictionary> ActionFactories; - if ((action & 0x08) != 0) - { - actions.Add(UpdateListedAction.Read(buffer)); - } + static ActionRegistry() + { + ActionFactories = InitializeActions(); + } - if ((action & 0x10) != 0) - { - actions.Add(UpdateLatencyAction.Read(buffer)); - } + private static FrozenDictionary> InitializeActions() + { + var dict = new Dictionary>(); - if ((action & 0x20) != 0) - { - actions.Add(UpdateDisplayName.Read(buffer)); - } + void Register() + where T : IPlayerInfoAction, IPlayerInfoActionStatic + { + var mask = T.StaticMask; + var factory = T.Read; + dict.Add(mask, factory); } - return new(uuid, actions.ToArray()); + Register(); + Register(); + Register(); + Register(); + Register(); + Register(); + Register(); + + return dict.ToFrozenDictionary(); } } - public interface IPlayerInfoAction { + public int Mask { get; } + public void Write(PacketBuffer buffer); } - public class AddPlayerAction : IPlayerInfoAction + public interface IPlayerInfoActionStatic { - public AddPlayerAction(string name, Property[] properties) - { - Name = name; - Properties = properties; - } + public static abstract int StaticMask { get; } - public string Name { get; set; } - public Property[] Properties { get; set; } + public static abstract IPlayerInfoAction Read(PacketBuffer buffer); + } + + public sealed record AddPlayerAction(string Name, Property[] Properties) : IPlayerInfoAction, IPlayerInfoActionStatic + { + public static int StaticMask => 0x01; + public int Mask => StaticMask; public void Write(PacketBuffer buffer) { @@ -176,19 +178,13 @@ public static AddPlayerAction Read(PacketBuffer buffer) return new(name, properties); } - public class Property + static IPlayerInfoAction IPlayerInfoActionStatic.Read(PacketBuffer buffer) { - public Property(string name, string value, string? signature) - { - Name = name; - Value = value; - Signature = signature; - } - - public string Name { get; set; } - public string Value { get; set; } - public string? Signature { get; set; } + return Read(buffer); + } + public sealed record Property(string Name, string Value, string? Signature) + { public void Write(PacketBuffer buffer) { buffer.WriteString(Name); @@ -218,14 +214,10 @@ public static Property Read(PacketBuffer buffer) } } - public class UpdateGameModeAction : IPlayerInfoAction + public sealed record UpdateGameModeAction(GameMode GameMode) : IPlayerInfoAction, IPlayerInfoActionStatic { - public UpdateGameModeAction(GameMode gameMode) - { - GameMode = gameMode; - } - - public GameMode GameMode { get; set; } + public static int StaticMask => 0x04; + public int Mask => StaticMask; public void Write(PacketBuffer buffer) { @@ -237,16 +229,17 @@ public static UpdateGameModeAction Read(PacketBuffer buffer) var gameMode = (GameMode)buffer.ReadVarInt(); return new(gameMode); } - } - public class UpdateListedAction : IPlayerInfoAction - { - public UpdateListedAction(bool listed) + static IPlayerInfoAction IPlayerInfoActionStatic.Read(PacketBuffer buffer) { - Listed = listed; + return Read(buffer); } + } - public bool Listed { get; set; } + public sealed record UpdateListedAction(bool Listed) : IPlayerInfoAction, IPlayerInfoActionStatic + { + public static int StaticMask => 0x08; + public int Mask => StaticMask; public void Write(PacketBuffer buffer) { @@ -258,16 +251,17 @@ public static UpdateListedAction Read(PacketBuffer buffer) var listed = buffer.ReadBool(); return new(listed); } - } - public class UpdateLatencyAction : IPlayerInfoAction - { - public UpdateLatencyAction(int ping) + static IPlayerInfoAction IPlayerInfoActionStatic.Read(PacketBuffer buffer) { - Ping = ping; + return Read(buffer); } + } - public int Ping { get; set; } + public sealed record UpdateLatencyAction(int Ping) : IPlayerInfoAction, IPlayerInfoActionStatic + { + public static int StaticMask => 0x10; + public int Mask => StaticMask; public void Write(PacketBuffer buffer) { @@ -279,16 +273,17 @@ public static UpdateLatencyAction Read(PacketBuffer buffer) var ping = buffer.ReadVarInt(); return new(ping); } - } - public class UpdateDisplayName : IPlayerInfoAction - { - public UpdateDisplayName(string? displayName) + static IPlayerInfoAction IPlayerInfoActionStatic.Read(PacketBuffer buffer) { - DisplayName = displayName; + return Read(buffer); } + } - public string? DisplayName { get; set; } + public sealed record UpdateDisplayName(string? DisplayName) : IPlayerInfoAction, IPlayerInfoActionStatic + { + public static int StaticMask => 0x20; + public int Mask => StaticMask; public void Write(PacketBuffer buffer) { @@ -311,46 +306,41 @@ public static UpdateDisplayName Read(PacketBuffer buffer) return new(displayName); } - } - public class InitializeChatAction : IPlayerInfoAction - { - public InitializeChatAction() + static IPlayerInfoAction IPlayerInfoActionStatic.Read(PacketBuffer buffer) { - Present = false; + return Read(buffer); } + } - public InitializeChatAction(Uuid chatSessionId, long publicKeyExpiryTime, byte[] encodedPublicKey, - byte[] publicKeySignature) - { - Present = true; - ChatSessionId = chatSessionId; - PublicKeyExpiryTime = publicKeyExpiryTime; - EncodedPublicKey = encodedPublicKey; - PublicKeySignature = publicKeySignature; - } + public sealed record InitializeChatAction(InitializeChatActionData? Data) : IPlayerInfoAction, IPlayerInfoActionStatic + { + public static int StaticMask => 0x02; + public int Mask => StaticMask; - public bool Present { get; set; } - public Uuid? ChatSessionId { get; set; } - public long? PublicKeyExpiryTime { get; set; } - public byte[]? EncodedPublicKey { get; set; } - public byte[]? PublicKeySignature { get; set; } + public sealed record InitializeChatActionData( + Uuid ChatSessionId, + long PublicKeyExpiryTime, + byte[] EncodedPublicKey, + byte[] PublicKeySignature + ); public void Write(PacketBuffer buffer) { - buffer.WriteBool(Present); + var present = Data != null; + buffer.WriteBool(present); - if (!Present) + if (!present) { return; } - buffer.WriteUuid(ChatSessionId!.Value); - buffer.WriteLong(PublicKeyExpiryTime!.Value); - buffer.WriteVarInt(EncodedPublicKey!.Length); - buffer.WriteBytes(EncodedPublicKey); - buffer.WriteVarInt(PublicKeySignature!.Length); - buffer.WriteBytes(PublicKeySignature); + buffer.WriteUuid(Data!.ChatSessionId); + buffer.WriteLong(Data!.PublicKeyExpiryTime); + buffer.WriteVarInt(Data!.EncodedPublicKey.Length); + buffer.WriteBytes(Data!.EncodedPublicKey); + buffer.WriteVarInt(Data!.PublicKeySignature.Length); + buffer.WriteBytes(Data!.PublicKeySignature); } public static InitializeChatAction Read(PacketBuffer buffer) @@ -358,7 +348,7 @@ public static InitializeChatAction Read(PacketBuffer buffer) var present = buffer.ReadBool(); if (!present) { - return new(); + return new InitializeChatAction((InitializeChatActionData?)null); } var chatSessionId = buffer.ReadUuid(); @@ -368,63 +358,65 @@ public static InitializeChatAction Read(PacketBuffer buffer) var publicKeySignature = new byte[buffer.ReadVarInt()]; buffer.ReadBytes(publicKeySignature); - return new(chatSessionId, publicKeyExpiryTime, encodedPublicKey, publicKeySignature); + return new InitializeChatAction(new InitializeChatActionData(chatSessionId, publicKeyExpiryTime, encodedPublicKey, publicKeySignature)); } - } - public class CryptoActionV19 : IPlayerInfoAction - { - public CryptoActionV19() + static IPlayerInfoAction IPlayerInfoActionStatic.Read(PacketBuffer buffer) { - Present = false; + return Read(buffer); } + } - public CryptoActionV19(Uuid chatSessionId, long timestamp, byte[] encodedPublicKey, byte[] publicKeySignature) - { - Present = true; - Timestamp = timestamp; - EncodedPublicKey = encodedPublicKey; - PublicKeySignature = publicKeySignature; - } + public sealed record CryptoActionV19(CryptoActionV19Data? Data) : IPlayerInfoAction, IPlayerInfoActionStatic + { + public static int StaticMask => 0x30; + public int Mask => StaticMask; - public bool Present { get; set; } - public long? Timestamp { get; set; } - public byte[]? EncodedPublicKey { get; set; } - public byte[]? PublicKeySignature { get; set; } + public sealed record CryptoActionV19Data( + long Timestamp, + byte[] EncodedPublicKey, + byte[] PublicKeySignature + ); public void Write(PacketBuffer buffer) { - buffer.WriteBool(Present); + var present = Data != null; + buffer.WriteBool(present); - if (!Present) + if (!present) { return; } - buffer.WriteLong(Timestamp!.Value); - buffer.WriteVarInt(EncodedPublicKey!.Length); - buffer.WriteBytes(EncodedPublicKey); - buffer.WriteVarInt(PublicKeySignature!.Length); - buffer.WriteBytes(PublicKeySignature); + buffer.WriteLong(Data!.Timestamp); + buffer.WriteVarInt(Data!.EncodedPublicKey.Length); + buffer.WriteBytes(Data!.EncodedPublicKey); + buffer.WriteVarInt(Data!.PublicKeySignature.Length); + buffer.WriteBytes(Data!.PublicKeySignature); } - public static InitializeChatAction Read(PacketBuffer buffer) + public static CryptoActionV19 Read(PacketBuffer buffer) { var present = buffer.ReadBool(); if (!present) { - return new(); + return new CryptoActionV19((CryptoActionV19Data?)null); } - var chatSessionId = buffer.ReadUuid(); - var publicKeyExpiryTime = buffer.ReadLong(); + var timestamp = buffer.ReadLong(); var encodedPublicKey = new byte[buffer.ReadVarInt()]; buffer.ReadBytes(encodedPublicKey); var publicKeySignature = new byte[buffer.ReadVarInt()]; buffer.ReadBytes(publicKeySignature); - return new(chatSessionId, publicKeyExpiryTime, encodedPublicKey, publicKeySignature); + return new CryptoActionV19(new CryptoActionV19Data(timestamp, encodedPublicKey, publicKeySignature)); + } + + static IPlayerInfoAction IPlayerInfoActionStatic.Read(PacketBuffer buffer) + { + return Read(buffer); } } + } #pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerPositionPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerPositionPacket.cs index 90867d8e..5bb58e22 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerPositionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerPositionPacket.cs @@ -6,8 +6,32 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 -public class PlayerPositionPacket : IPacket +public sealed record PlayerPositionPacket : IPacket { + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_Position; + + // Here is no non-argument constructor allowed + // Do not use + private PlayerPositionPacket() + { + } + + private PlayerPositionPacket(double x, double y, double z, float yaw, float pitch, PositionFlags flags, int teleportId, + bool? dismountVehicle) + { + X = x; + Y = y; + Z = z; + Yaw = yaw; + Pitch = pitch; + Flags = flags; + TeleportId = teleportId; + DismountVehicle = dismountVehicle; + } + /// /// Constructor for 1.18.x-1.19.3 /// @@ -19,17 +43,10 @@ public class PlayerPositionPacket : IPacket /// /// /// - public PlayerPositionPacket(double x, double y, double z, float yaw, float pitch, sbyte flags, int teleportId, + public PlayerPositionPacket(double x, double y, double z, float yaw, float pitch, PositionFlags flags, int teleportId, bool dismountVehicle) + : this(x, y, z, yaw, pitch, flags, teleportId, (bool?)dismountVehicle) { - X = x; - Y = y; - Z = z; - Yaw = yaw; - Pitch = pitch; - Flags = flags; - TeleportId = teleportId; - DismountVehicle = dismountVehicle; } /// @@ -42,28 +59,19 @@ public PlayerPositionPacket(double x, double y, double z, float yaw, float pitch /// /// /// - public PlayerPositionPacket(double x, double y, double z, float yaw, float pitch, sbyte flags, int teleportId) + public PlayerPositionPacket(double x, double y, double z, float yaw, float pitch, PositionFlags flags, int teleportId) + : this(x, y, z, yaw, pitch, flags, teleportId, null) { - X = x; - Y = y; - Z = z; - Yaw = yaw; - Pitch = pitch; - Flags = flags; - TeleportId = teleportId; - DismountVehicle = null; } - public double X { get; set; } - public double Y { get; set; } - public double Z { get; set; } - public float Yaw { get; set; } - public float Pitch { get; set; } - public sbyte Flags { get; set; } - public int TeleportId { get; set; } - public bool? DismountVehicle { get; set; } - public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_Position; + public double X { get; init; } + public double Y { get; init; } + public double Z { get; init; } + public float Yaw { get; init; } + public float Pitch { get; init; } + public PositionFlags Flags { get; init; } + public int TeleportId { get; init; } + public bool? DismountVehicle { get; init; } public void Write(PacketBuffer buffer, MinecraftData version) { @@ -72,7 +80,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteDouble(Z); buffer.WriteFloat(Yaw); buffer.WriteFloat(Pitch); - buffer.WriteSByte(Flags); + buffer.WriteSByte((sbyte)Flags); buffer.WriteVarInt(TeleportId); if (version.Version.Protocol >= ProtocolVersion.V_1_19_4) @@ -95,7 +103,7 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) var z = buffer.ReadDouble(); var yaw = buffer.ReadFloat(); var pitch = buffer.ReadFloat(); - var flags = buffer.ReadSByte(); + var flags = (PositionFlags)buffer.ReadSByte(); var teleportId = buffer.ReadVarInt(); if (version.Version.Protocol >= ProtocolVersion.V_1_19_4) @@ -106,5 +114,15 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) var dismountVehicle = buffer.ReadBool(); return new PlayerPositionPacket(x, y, z, yaw, pitch, flags, teleportId, dismountVehicle); } + + [Flags] + public enum PositionFlags : sbyte + { + X = 0x01, + Y = 0x02, + Z = 0x04, + YRot = 0x08, + XRot = 0x10 + } } #pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveEntitiesPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveEntitiesPacket.cs index 488d8c79..dbe2e856 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveEntitiesPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveEntitiesPacket.cs @@ -4,16 +4,12 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 -public class RemoveEntitiesPacket : IPacket +public sealed record RemoveEntitiesPacket(int[] EntityIds) : IPacket { - public RemoveEntitiesPacket(int[] entityIds) - { - EntityIds = entityIds; - } - - public int[] EntityIds { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_EntityDestroy; + /// + public static PacketType StaticType => PacketType.CB_Play_EntityDestroy; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs index efa294f6..5db7e3aa 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs @@ -7,42 +7,25 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 -public class RespawnPacket : IPacket +public sealed record RespawnPacket( + string Dimension, + string DimensionName, + long HashedSeed, + sbyte GameMode, + byte PreviousGameMode, + bool IsDebug, + bool IsFlat, + bool CopyMetadata, + bool? HasDeathLocation, + string? DeathDimensionName, + Position? DeathLocation, + int? PortalCooldown +) : IPacket { - public RespawnPacket(string dimension, string dimensionName, long hashedSeed, sbyte gameMode, byte previousGameMode, - bool isDebug, - bool isFlat, bool copyMetadata, bool? hasDeathLocation, string? deathDimensionName, - Position? deathLocation, - int? portalCooldown) - { - Dimension = dimension; - DimensionName = dimensionName; - HashedSeed = hashedSeed; - GameMode = gameMode; - PreviousGameMode = previousGameMode; - IsDebug = isDebug; - IsFlat = isFlat; - CopyMetadata = copyMetadata; - HasDeathLocation = hasDeathLocation; - DeathDimensionName = deathDimensionName; - DeathLocation = deathLocation; - PortalCooldown = portalCooldown; - } - - public string Dimension { get; set; } - public string DimensionName { get; set; } - public long HashedSeed { get; set; } - public sbyte GameMode { get; set; } - public byte PreviousGameMode { get; set; } - public bool IsDebug { get; set; } - public bool IsFlat { get; set; } - public bool CopyMetadata { get; set; } - public bool? HasDeathLocation { get; set; } - public string? DeathDimensionName { get; set; } - public Position? DeathLocation { get; set; } - public int? PortalCooldown { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_Respawn; + /// + public static PacketType StaticType => PacketType.CB_Play_Respawn; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEntityVelocityPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEntityVelocityPacket.cs index e8bcd141..6af7807b 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEntityVelocityPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEntityVelocityPacket.cs @@ -4,22 +4,12 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 -public class SetEntityVelocityPacket : IPacket +public sealed record SetEntityVelocityPacket(int EntityId, short VelocityX, short VelocityY, short VelocityZ) : IPacket { - public SetEntityVelocityPacket(int entityId, short velocityX, short velocityY, short velocityZ) - { - EntityId = entityId; - VelocityX = velocityX; - VelocityY = velocityY; - VelocityZ = velocityZ; - } - - public int EntityId { get; set; } - public short VelocityX { get; set; } - public short VelocityY { get; set; } - public short VelocityZ { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_EntityVelocity; + /// + public static PacketType StaticType => PacketType.CB_Play_EntityVelocity; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHealthPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHealthPacket.cs index 75c60858..b8ea4a5a 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHealthPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHealthPacket.cs @@ -4,20 +4,12 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 -public class SetHealthPacket : IPacket +public sealed record SetHealthPacket(float Health, int Food, float Saturation) : IPacket { - public SetHealthPacket(float health, int food, float saturation) - { - Health = health; - Food = food; - Saturation = saturation; - } - - public float Health { get; set; } - public int Food { get; set; } - public float Saturation { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_UpdateHealth; + /// + public static PacketType StaticType => PacketType.CB_Play_UpdateHealth; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHeldItemPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHeldItemPacket.cs index cd7bc02d..9858bed5 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHeldItemPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHeldItemPacket.cs @@ -4,16 +4,12 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 -public class SetHeldItemPacket : IPacket +public sealed record SetHeldItemPacket(sbyte Slot) : IPacket { - public SetHeldItemPacket(sbyte slot) - { - Slot = slot; - } - - public sbyte Slot { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_HeldItemSlot; + /// + public static PacketType StaticType => PacketType.CB_Play_HeldItemSlot; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetPassengersPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetPassengersPacket.cs index 045407dd..69d45d21 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetPassengersPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetPassengersPacket.cs @@ -5,19 +5,12 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 -public class SetPassengersPacket : IPacket +public sealed record SetPassengersPacket(int EntityId, int[] PassengersId) : IPacket { - public SetPassengersPacket(int entityId, int[] passengersId) - { - EntityId = entityId; - PassengersId = passengersId; - } - - public int EntityId { get; set; } - - public int[] PassengersId { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_SetPassengers; + /// + public static PacketType StaticType => PacketType.CB_Play_SetPassengers; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs index 96743d37..155f3048 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs @@ -4,36 +4,24 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 -public class SoundEffectPacket : IPacket +public sealed record SoundEffectPacket( + int SoundId, + string? SoundName, + bool? HasFixedRange, + float? Range, + int SoundCategory, + int EffectPositionX, + int EffectPositionY, + int EffectPositionZ, + float Volume, + float Pitch, + long Seed +) : IPacket { - public SoundEffectPacket(int soundId, string? soundName, bool? hasFixedRange, float? range, int soundCategory, int effectPositionX, int effectPositionY, int effectPositionZ, float volume, float pitch, long seed) - { - SoundId = soundId; - SoundName = soundName; - HasFixedRange = hasFixedRange; - Range = range; - SoundCategory = soundCategory; - EffectPositionX = effectPositionX; - EffectPositionY = effectPositionY; - EffectPositionZ = effectPositionZ; - Volume = volume; - Pitch = pitch; - Seed = seed; - } - - public int SoundId { get; set; } - public string? SoundName { get; set; } - public bool? HasFixedRange { get; set; } - public float? Range { get; set; } - public int SoundCategory { get; set; } - public int EffectPositionX { get; set; } - public int EffectPositionY { get; set; } - public int EffectPositionZ { get; set; } - public float Volume { get; set; } - public float Pitch { get; set; } - public long Seed { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_SoundEffect; + /// + public static PacketType StaticType => PacketType.CB_Play_SoundEffect; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnEntityPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnEntityPacket.cs index 25671c25..d5d9de22 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnEntityPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnEntityPacket.cs @@ -5,48 +5,64 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 -public class SpawnEntityPacket : IPacket +public sealed record SpawnEntityPacket( + int EntityId, + Uuid ObjectUuid, + int EntityType, + double X, + double Y, + double Z, + sbyte Pitch, + sbyte Yaw, + sbyte HeadPitch, + int ObjectData, + short VelocityX, + short VelocityY, + short VelocityZ +) : IPacket { - public SpawnEntityPacket(int entityId, Uuid objectUuid, int entityType, double x, double y, double z, sbyte pitch, - sbyte yaw, - sbyte headPitch, int objectData, short velocityX, short velocityY, short velocityZ) - { - EntityId = entityId; - ObjectUuid = objectUuid; - EntityType = entityType; - X = x; - Y = y; - Z = z; - Pitch = pitch; - Yaw = yaw; - HeadPitch = headPitch; - ObjectData = objectData; - VelocityX = velocityX; - VelocityY = velocityY; - VelocityZ = velocityZ; - } - - public int EntityId { get; set; } - public Uuid ObjectUuid { get; set; } - public int EntityType { get; set; } - public double X { get; set; } - public double Y { get; set; } - public double Z { get; set; } - public sbyte Pitch { get; set; } - public sbyte Yaw { get; set; } - public sbyte HeadPitch { get; set; } - public int ObjectData { get; set; } - public short VelocityX { get; set; } - public short VelocityY { get; set; } - public short VelocityZ { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_SpawnEntity; + /// + public static PacketType StaticType => PacketType.CB_Play_SpawnEntity; + /// + /// Writes the packet data to the buffer. + /// + /// The buffer to write to. + /// The Minecraft version. public void Write(PacketBuffer buffer, MinecraftData version) { - throw new NotImplementedException(); + buffer.WriteVarInt(EntityId); + buffer.WriteUuid(ObjectUuid); + buffer.WriteVarInt(EntityType); + buffer.WriteDouble(X); + buffer.WriteDouble(Y); + buffer.WriteDouble(Z); + buffer.WriteSByte(Pitch); + buffer.WriteSByte(Yaw); + + if (version.Version.Protocol >= ProtocolVersion.V_1_19) + { + buffer.WriteSByte(HeadPitch); + buffer.WriteVarInt(ObjectData); + } + else + { + buffer.WriteInt(ObjectData); + } + + buffer.WriteShort(VelocityX); + buffer.WriteShort(VelocityY); + buffer.WriteShort(VelocityZ); } + /// + /// Reads the packet data from the buffer. + /// + /// The buffer to read from. + /// The Minecraft version. + /// A new instance of . public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var entityId = buffer.ReadVarInt(); @@ -73,9 +89,7 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) var velocityY = buffer.ReadShort(); var velocityZ = buffer.ReadShort(); - return new SpawnEntityPacket(entityId, objectUuid, type, x, y, z, pitch, yaw, headPitch, objectData, velocityX, - velocityY, - velocityZ); + return new SpawnEntityPacket(entityId, objectUuid, type, x, y, z, pitch, yaw, headPitch, objectData, velocityX, velocityY, velocityZ); } } #pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnLivingEntityPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnLivingEntityPacket.cs index fa0c566a..1e1a3f64 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnLivingEntityPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnLivingEntityPacket.cs @@ -3,46 +3,43 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 + /// /// SpawnLivingEntityPacket used for versions <= 1.18.2 /// -public class SpawnLivingEntityPacket : IPacket +/// The ID of the entity. +/// The UUID of the entity. +/// The type of the entity. +/// The X coordinate of the entity. +/// The Y coordinate of the entity. +/// The Z coordinate of the entity. +/// The yaw of the entity. +/// The pitch of the entity. +/// The head pitch of the entity. +/// The X velocity of the entity. +/// The Y velocity of the entity. +/// The Z velocity of the entity. +public sealed record SpawnLivingEntityPacket( + int EntityId, + Uuid EntityUuid, + int EntityType, + double X, + double Y, + double Z, + byte Yaw, + byte Pitch, + byte HeadPitch, + short VelocityX, + short VelocityY, + short VelocityZ +) : IPacket { - public SpawnLivingEntityPacket(int entityId, Uuid entityUuid, int entityType, double x, double y, double z, - byte yaw, byte pitch, - byte headPitch, short velocityX, short velocityY, short velocityZ) - { - EntityId = entityId; - EntityUuid = entityUuid; - EntityType = entityType; - X = x; - Y = y; - Z = z; - Yaw = yaw; - Pitch = pitch; - HeadPitch = headPitch; - VelocityX = velocityX; - VelocityY = velocityY; - VelocityZ = velocityZ; - } - - - public int EntityId { get; set; } - public Uuid EntityUuid { get; set; } - public int EntityType { get; set; } - public double X { get; set; } - public double Y { get; set; } - public double Z { get; set; } - public byte Yaw { get; set; } - public byte Pitch { get; set; } - public byte HeadPitch { get; set; } - public short VelocityX { get; set; } - public short VelocityY { get; set; } - public short VelocityZ { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_SpawnEntityLiving; + /// + public static PacketType StaticType => PacketType.CB_Play_SpawnEntityLiving; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteVarInt(EntityId); @@ -59,6 +56,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteShort(VelocityZ); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { return new SpawnLivingEntityPacket( @@ -73,7 +71,7 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) buffer.ReadByte(), buffer.ReadShort(), buffer.ReadShort(), - buffer.ReadShort()); + buffer.ReadShort() + ); } } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPaintingPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPaintingPacket.cs index be600e31..ce237007 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPaintingPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPaintingPacket.cs @@ -4,30 +4,29 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 + /// /// SpawnPaintingPacket used for versions <= 1.18.2 /// -public class SpawnPaintingPacket : IPacket +/// The ID of the entity. +/// The UUID of the entity. +/// The title of the painting. +/// The location of the painting. +/// The direction the painting is facing. +public sealed record SpawnPaintingPacket( + int EntityId, + Uuid EntityUuid, + int Title, + Position Location, + sbyte Direction +) : IPacket { - public SpawnPaintingPacket(int entityId, Uuid entityUuid, int title, Position location, sbyte direction) - { - EntityId = entityId; - EntityUuid = entityUuid; - Title = title; - Location = location; - Direction = direction; - } - - - public int EntityId { get; set; } - public Uuid EntityUuid { get; set; } - public int Title { get; set; } - public Position Location { get; set; } - public sbyte Direction { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_SpawnEntityPainting; + /// + public static PacketType StaticType => PacketType.CB_Play_SpawnEntityPainting; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteVarInt(EntityId); @@ -37,6 +36,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteSByte(Direction); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var entityId = buffer.ReadVarInt(); @@ -47,4 +47,3 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) return new SpawnPaintingPacket(entityId, entityUuid, title, location, direction); } } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPlayerPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPlayerPacket.cs index 4fc05f8b..17850dbb 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPlayerPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPlayerPacket.cs @@ -3,34 +3,34 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 + /// /// SpawnPlayerPacket used for versions <= 1.20.1 /// Merged with SpawnEntityPacket in 1.20.2 /// -public class SpawnPlayerPacket : IPacket +/// The ID of the entity. +/// The UUID of the player. +/// The X coordinate of the player. +/// The Y coordinate of the player. +/// The Z coordinate of the player. +/// The yaw of the player. +/// The pitch of the player. +public sealed record SpawnPlayerPacket( + int EntityId, + Uuid PlayerUuid, + double X, + double Y, + double Z, + byte Yaw, + byte Pitch +) : IPacket { - public SpawnPlayerPacket(int entityId, Uuid playerUuid, double x, double y, double z, byte yaw, byte pitch) - { - EntityId = entityId; - PlayerUuid = playerUuid; - X = x; - Y = y; - Z = z; - Yaw = yaw; - Pitch = pitch; - } - - public int EntityId { get; set; } - public Uuid PlayerUuid { get; set; } - public double X { get; set; } - public double Y { get; set; } - public double Z { get; set; } - public byte Yaw { get; set; } - public byte Pitch { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_NamedEntitySpawn; + /// + public static PacketType StaticType => PacketType.CB_Play_NamedEntitySpawn; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteVarInt(EntityId); @@ -42,6 +42,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteByte(Pitch); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var entityId = buffer.ReadVarInt(); @@ -54,4 +55,3 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) return new SpawnPlayerPacket(entityId, playerUuid, x, y, z, yaw, pitch); } } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SystemChatMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SystemChatMessagePacket.cs index 5f40878b..70bb9b64 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SystemChatMessagePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SystemChatMessagePacket.cs @@ -3,7 +3,6 @@ using MineSharp.Core.Common; using MineSharp.Data; using MineSharp.Data.Protocol; -using MineSharp.Protocol.Exceptions; namespace MineSharp.Protocol.Packets.Clientbound.Play; @@ -11,20 +10,16 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; /// Packet for system messages displayed in chat or hotbar /// See https://wiki.vg/Protocol#System_Chat_Message /// -public abstract class SystemChatMessagePacket : IPacket +public abstract record SystemChatMessagePacket(Chat Message) : IPacket { /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_SystemChat; - - /// - /// The message - /// - public required Chat Message { get; init; } + /// + public static PacketType StaticType => PacketType.CB_Play_SystemChat; /// public abstract void Write(PacketBuffer buffer, MinecraftData version); - + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { @@ -40,14 +35,8 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) /// /// Used before Minecraft Java 1.19.2 /// - public class Before192 : SystemChatMessagePacket + public sealed record Before192(Chat Message, int ChatType) : SystemChatMessagePacket(Message) { - /// - /// Position of the message - /// 0: chat (chat box), 1: system message (chat box), 2: game info (above hotbar), 3: say command, 4: msg command, 5: team msg command, 6: emote command, 7: tellraw command - /// - public required int ChatType { get; init; } - /// public override void Write(PacketBuffer buffer, MinecraftData data) { @@ -57,7 +46,7 @@ public override void Write(PacketBuffer buffer, MinecraftData data) internal static Before192 _Read(PacketBuffer buffer, MinecraftData version) { - return new() { Message = buffer.ReadChatComponent(), ChatType = buffer.ReadInt() }; + return new(buffer.ReadChatComponent(), buffer.ReadInt()); } } @@ -66,13 +55,8 @@ internal static Before192 _Read(PacketBuffer buffer, MinecraftData version) /// /// Used since Minecraft Java 1.19.2 /// - public class Since192 : SystemChatMessagePacket + public sealed record Since192(Chat Message, bool IsOverlay) : SystemChatMessagePacket(Message) { - /// - /// If true, the message is displayed on the action bar - /// - public required bool IsOverlay { get; init; } - /// public override void Write(PacketBuffer buffer, MinecraftData version) { @@ -82,8 +66,7 @@ public override void Write(PacketBuffer buffer, MinecraftData version) internal static Since192 _Read(PacketBuffer buffer, MinecraftData version) { - return new() { Message = buffer.ReadChatComponent(), IsOverlay = buffer.ReadBool() }; + return new(buffer.ReadChatComponent(), buffer.ReadBool()); } } } - diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/TeleportEntityPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/TeleportEntityPacket.cs index 6c266011..15505089 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/TeleportEntityPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/TeleportEntityPacket.cs @@ -4,28 +4,20 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 -public class TeleportEntityPacket : IPacket +public sealed record TeleportEntityPacket( + int EntityId, + double X, + double Y, + double Z, + sbyte Yaw, + sbyte Pitch, + bool OnGround +) : IPacket { - public TeleportEntityPacket(int entityId, double x, double y, double z, sbyte yaw, sbyte pitch, bool onGround) - { - EntityId = entityId; - X = x; - Y = y; - Z = z; - Yaw = yaw; - Pitch = pitch; - OnGround = onGround; - } - - public int EntityId { get; set; } - public double X { get; set; } - public double Y { get; set; } - public double Z { get; set; } - public sbyte Yaw { get; set; } - public sbyte Pitch { get; set; } - public bool OnGround { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_EntityTeleport; + /// + public static PacketType StaticType => PacketType.CB_Play_EntityTeleport; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/UnloadChunkPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UnloadChunkPacket.cs index 6c2b0ff8..2163a43c 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/UnloadChunkPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UnloadChunkPacket.cs @@ -3,26 +3,27 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 -public class UnloadChunkPacket : IPacket -{ - public UnloadChunkPacket(int x, int z) - { - X = x; - Z = z; - } - public int X { get; set; } - public int Z { get; set; } +/// +/// Represents a packet to unload a chunk. +/// +/// The X coordinate of the chunk. +/// The Z coordinate of the chunk. +public sealed record UnloadChunkPacket(int X, int Z) : IPacket +{ + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_UnloadChunk; + /// + public static PacketType StaticType => PacketType.CB_Play_UnloadChunk; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteInt(X); buffer.WriteInt(Z); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var x = buffer.ReadInt(); @@ -30,4 +31,4 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) return new UnloadChunkPacket(x, z); } } -#pragma warning restore CS1591 + diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateAttributesPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateAttributesPacket.cs index 622893d3..ca5ad986 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateAttributesPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateAttributesPacket.cs @@ -1,68 +1,32 @@ using MineSharp.Core.Common; -using MineSharp.Core.Common.Entities.Attributes; using MineSharp.Data; using MineSharp.Data.Protocol; using Attribute = MineSharp.Core.Common.Entities.Attributes.Attribute; namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 -public class UpdateAttributesPacket : IPacket +public sealed record UpdateAttributesPacket( + int EntityId, + Attribute[] Attributes +) : IPacket { - public UpdateAttributesPacket(int entityId, Attribute[] attributes) - { - EntityId = entityId; - Attributes = attributes; - } - - public int EntityId { get; set; } - public Attribute[] Attributes { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_EntityUpdateAttributes; + /// + public static PacketType StaticType => PacketType.CB_Play_EntityUpdateAttributes; public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteVarInt(EntityId); - buffer.WriteVarIntArray(Attributes, WriteAttribute); + buffer.WriteVarIntArray(Attributes, (buffer, attribute) => attribute.Write(buffer)); } public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var entityId = buffer.ReadVarInt(); - var attributes = buffer.ReadVarIntArray(ReadAttribute); + var attributes = buffer.ReadVarIntArray(Attribute.Read); return new UpdateAttributesPacket(entityId, attributes); } - - private void WriteAttribute(PacketBuffer buffer, Attribute attribute) - { - buffer.WriteString(attribute.Key); - buffer.WriteDouble(attribute.Value); - buffer.WriteVarIntArray(attribute.Modifiers.Values, WriteModifier); - } - - private void WriteModifier(PacketBuffer buffer, Modifier modifier) - { - buffer.WriteUuid(modifier.Uuid); - buffer.WriteDouble(modifier.Amount); - buffer.WriteByte((byte)modifier.Operation); - } - - private static Attribute ReadAttribute(PacketBuffer buffer) - { - var key = buffer.ReadString(); - var value = buffer.ReadDouble(); - var modifiers = buffer.ReadVarIntArray(ReadModifier); - - return new(key, value, modifiers); - } - - private static Modifier ReadModifier(PacketBuffer buffer) - { - var uuid = buffer.ReadUuid(); - var amount = buffer.ReadDouble(); - var operation = buffer.ReadByte(); - - return new(uuid, amount, (ModifierOp)operation); - } } #pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowItemsPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowItemsPacket.cs index 4a746e6e..ff90c39b 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowItemsPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowItemsPacket.cs @@ -5,24 +5,22 @@ using MineSharp.Protocol.Packets.NetworkTypes; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 -public class WindowItemsPacket : IPacket -{ - public WindowItemsPacket(byte windowId, int stateId, Item?[] items, Item? selectedItem) - { - WindowId = windowId; - StateId = stateId; - Items = items; - SelectedItem = selectedItem; - } - public byte WindowId { get; set; } - public int StateId { get; set; } - public Item?[] Items { get; set; } - public Item? SelectedItem { get; set; } +/// +/// Represents a packet containing window items. +/// +/// The ID of the window. +/// The state ID of the window. +/// The items in the window. +/// The selected item in the window. +public sealed record WindowItemsPacket(byte WindowId, int StateId, Item?[] Items, Item? SelectedItem) : IPacket +{ + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_WindowItems; + /// + public static PacketType StaticType => PacketType.CB_Play_WindowItems; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteByte(WindowId); @@ -31,6 +29,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteOptionalItem(SelectedItem); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { return new WindowItemsPacket( @@ -40,4 +39,4 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) buffer.ReadOptionalItem(version)); } } -#pragma warning restore CS1591 + diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowSetSlotPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowSetSlotPacket.cs index 306149ed..81952e77 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowSetSlotPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowSetSlotPacket.cs @@ -4,22 +4,21 @@ using MineSharp.Protocol.Packets.NetworkTypes; namespace MineSharp.Protocol.Packets.Clientbound.Play; -#pragma warning disable CS1591 -public class WindowSetSlotPacket : IPacket -{ - public WindowSetSlotPacket(sbyte windowId, int stateId, Slot slot) - { - WindowId = windowId; - StateId = stateId; - Slot = slot; - } - public sbyte WindowId { get; set; } - public int StateId { get; set; } - public Slot Slot { get; set; } +/// +/// Represents a packet that sets a slot in a window. +/// +/// The ID of the window. +/// The state ID of the window. +/// The slot to be set. +public sealed record WindowSetSlotPacket(sbyte WindowId, int StateId, Slot Slot) : IPacket +{ + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Play_SetSlot; + /// + public static PacketType StaticType => PacketType.CB_Play_SetSlot; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteSByte(WindowId); @@ -27,6 +26,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteSlot(Slot); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { return new WindowSetSlotPacket( @@ -35,4 +35,4 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) buffer.ReadSlot(version)); } } -#pragma warning restore CS1591 + diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Status/PongResponsePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Status/PingResponsePacket.cs similarity index 52% rename from Components/MineSharp.Protocol/Packets/Clientbound/Status/PongResponsePacket.cs rename to Components/MineSharp.Protocol/Packets/Clientbound/Status/PingResponsePacket.cs index 470d7415..66c6b307 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Status/PongResponsePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Status/PingResponsePacket.cs @@ -4,25 +4,27 @@ namespace MineSharp.Protocol.Packets.Clientbound.Status; #pragma warning disable CS1591 -public class PongResponsePacket : IPacket +/// +/// Packet for ping response +/// +/// The payload of the ping response +public sealed record PingResponsePacket(long Payload) : IPacket { - public PongResponsePacket(long payload) - { - Payload = payload; - } - - public long Payload { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Status_Ping; + /// + public static PacketType StaticType => PacketType.CB_Status_Ping; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteLong(Payload); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - return new PongResponsePacket(buffer.ReadLong()); + return new PingResponsePacket(buffer.ReadLong()); } } #pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Status/StatusResponsePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Status/StatusResponsePacket.cs index a42877d1..a1b976eb 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Status/StatusResponsePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Status/StatusResponsePacket.cs @@ -4,22 +4,24 @@ namespace MineSharp.Protocol.Packets.Clientbound.Status; #pragma warning disable CS1591 -public class StatusResponsePacket : IPacket +/// +/// Packet for server status response +/// +/// The server response +public sealed record StatusResponsePacket(string Response) : IPacket { - public StatusResponsePacket(string response) - { - Response = response; - } - - public string Response { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.CB_Status_ServerInfo; + /// + public static PacketType StaticType => PacketType.CB_Status_ServerInfo; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteString(Response); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { return new StatusResponsePacket(buffer.ReadString()); diff --git a/Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs index 963ebe5c..5f0f3db4 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs @@ -127,7 +127,7 @@ private Task HandleLoginSuccess(LoginSuccessPacket packet) return Task.CompletedTask; } - _ = client.SendPacket(new AcknowledgeLoginPacket()) + _ = client.SendPacket(new LoginAcknowledgedPacket()) .ContinueWith(_ => client.UpdateGameState(GameState.Configuration)); return Task.CompletedTask; } diff --git a/Components/MineSharp.Protocol/Packets/ISerializable.cs b/Components/MineSharp.Protocol/Packets/ISerializable.cs index 3d1a45ba..dbd76201 100644 --- a/Components/MineSharp.Protocol/Packets/ISerializable.cs +++ b/Components/MineSharp.Protocol/Packets/ISerializable.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Data; namespace MineSharp.Protocol.Packets; @@ -6,7 +7,8 @@ namespace MineSharp.Protocol.Packets; /// Interface for serializing and deserializing objects from and to /// /// -public interface ISerializable where T : ISerializable +public interface ISerializable : IVersionAwareSerializable + where T : ISerializable { /// /// Serialize the object into the buffer @@ -14,10 +16,22 @@ public interface ISerializable where T : ISerializable /// public void Write(PacketBuffer buffer); + /// + void IVersionAwareSerializable.Write(PacketBuffer buffer, MinecraftData version) + { + Write(buffer); + } + /// /// Read the object from the buffer /// /// /// public static abstract T Read(PacketBuffer buffer); + + /// + static T IVersionAwareSerializable.Read(PacketBuffer buffer, MinecraftData version) + { + return T.Read(buffer); + } } diff --git a/Components/MineSharp.Protocol/Packets/IVersionAwareSerializable.cs b/Components/MineSharp.Protocol/Packets/IVersionAwareSerializable.cs new file mode 100644 index 00000000..352e0a91 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/IVersionAwareSerializable.cs @@ -0,0 +1,27 @@ +using MineSharp.Core.Common; +using MineSharp.Data; + +namespace MineSharp.Protocol.Packets; + +/// +/// Interface for serializing and deserializing objects from and to +/// while being aware of the Minecraft version +/// +/// +public interface IVersionAwareSerializable where T : IVersionAwareSerializable +{ + /// + /// Serialize the object into the buffer + /// + /// + /// + public void Write(PacketBuffer buffer, MinecraftData version); + + /// + /// Read the object from the buffer + /// + /// + /// + /// + public static abstract T Read(PacketBuffer buffer, MinecraftData version); +} diff --git a/Components/MineSharp.Protocol/Packets/NetworkTypes/ChatMessageItem.cs b/Components/MineSharp.Protocol/Packets/NetworkTypes/ChatMessageItem.cs index 0ae63272..a402212d 100644 --- a/Components/MineSharp.Protocol/Packets/NetworkTypes/ChatMessageItem.cs +++ b/Components/MineSharp.Protocol/Packets/NetworkTypes/ChatMessageItem.cs @@ -7,7 +7,7 @@ namespace MineSharp.Protocol.Packets.NetworkTypes; /// /// Represents a signed chat message /// -public class ChatMessageItem +public class ChatMessageItem : IVersionAwareSerializable { /// /// Creates a new instance diff --git a/Components/MineSharp.Protocol/Packets/PacketPalette.cs b/Components/MineSharp.Protocol/Packets/PacketPalette.cs index 73ae8561..109e49e0 100644 --- a/Components/MineSharp.Protocol/Packets/PacketPalette.cs +++ b/Components/MineSharp.Protocol/Packets/PacketPalette.cs @@ -85,11 +85,11 @@ void RegisterPacket() RegisterPacket(); RegisterPacket(); RegisterPacket(); - RegisterPacket(); + RegisterPacket(); // Status RegisterPacket(); - RegisterPacket(); + RegisterPacket(); RegisterPacket(); RegisterPacket(); diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ClientInformationPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ClientInformationPacket.cs index c2dcc42a..fe1f1ad0 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ClientInformationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ClientInformationPacket.cs @@ -3,57 +3,60 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Serverbound.Configuration; -#pragma warning disable CS1591 -public class ClientInformationPacket : IPacket -{ - public ClientInformationPacket(string locale, byte viewDistance, int chatMode, bool chatColors, - byte displayedSkinParts, int mainHand, - bool enableTextFiltering, bool allowServerListings) - { - Locale = locale; - ViewDistance = viewDistance; - ChatMode = chatMode; - ChatColors = chatColors; - DisplayedSkinParts = displayedSkinParts; - MainHand = mainHand; - EnableTextFiltering = enableTextFiltering; - AllowServerListings = allowServerListings; - } - public string Locale { get; set; } - public byte ViewDistance { get; set; } - public int ChatMode { get; set; } - public bool ChatColors { get; set; } - public byte DisplayedSkinParts { get; set; } - public int MainHand { get; set; } - public bool EnableTextFiltering { get; set; } - public bool AllowServerListings { get; set; } +/// +/// Client information packet +/// +/// The locale of the client +/// The view distance setting +/// The chat mode setting +/// Whether chat colors are enabled +/// The displayed skin parts +/// The main hand setting +/// Whether text filtering is enabled +/// Whether server listings are allowed +public sealed record ClientInformationPacket( + string Locale, + byte ViewDistance, + ChatMode ChatMode, + bool ChatColors, + SkinPart DisplayedSkinParts, + PlayerHand MainHand, + bool EnableTextFiltering, + bool AllowServerListings +) : IPacket +{ + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Configuration_Settings; + /// + public static PacketType StaticType => PacketType.SB_Configuration_Settings; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteString(Locale); buffer.WriteByte(ViewDistance); - buffer.WriteVarInt(ChatMode); + buffer.WriteVarInt((int)ChatMode); buffer.WriteBool(ChatColors); - buffer.WriteByte(DisplayedSkinParts); - buffer.WriteVarInt(MainHand); + buffer.WriteByte((byte)DisplayedSkinParts); + buffer.WriteVarInt((int)MainHand); buffer.WriteBool(EnableTextFiltering); buffer.WriteBool(AllowServerListings); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { return new ClientInformationPacket( buffer.ReadString(), buffer.ReadByte(), - buffer.ReadVarInt(), + (ChatMode)buffer.ReadVarInt(), buffer.ReadBool(), - buffer.ReadByte(), - buffer.ReadVarInt(), + (SkinPart)buffer.ReadByte(), + (PlayerHand)buffer.ReadVarInt(), buffer.ReadBool(), - buffer.ReadBool()); + buffer.ReadBool() + ); } } -#pragma warning restore CS1591 + diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/FinishConfigurationPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/FinishConfigurationPacket.cs index 47a5e4ab..9d0d1526 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/FinishConfigurationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/FinishConfigurationPacket.cs @@ -4,14 +4,18 @@ namespace MineSharp.Protocol.Packets.Serverbound.Configuration; #pragma warning disable CS1591 -public class FinishConfigurationPacket : IPacket +public sealed record FinishConfigurationPacket : IPacket { + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Configuration_FinishConfiguration; + /// + public static PacketType StaticType => PacketType.SB_Configuration_FinishConfiguration; + /// public void Write(PacketBuffer buffer, MinecraftData version) { } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { return new FinishConfigurationPacket(); diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/KeepAlivePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/KeepAlivePacket.cs index f4d11d47..addcb5fe 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/KeepAlivePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/KeepAlivePacket.cs @@ -3,26 +3,28 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Serverbound.Configuration; -#pragma warning disable CS1591 -public class KeepAlivePacket : IPacket -{ - public KeepAlivePacket(long keepAliveId) - { - KeepAliveId = keepAliveId; - } - public long KeepAliveId { get; set; } +/// +/// Keep alive packet +/// +/// The keep-alive ID +public sealed record KeepAlivePacket(long KeepAliveId) : IPacket +{ + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Configuration_KeepAlive; + /// + public static PacketType StaticType => PacketType.SB_Configuration_KeepAlive; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteLong(KeepAliveId); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { return new KeepAlivePacket(buffer.ReadLong()); } } -#pragma warning restore CS1591 + diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PluginMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PluginMessagePacket.cs index c489385a..f2bb66be 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PluginMessagePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PluginMessagePacket.cs @@ -3,31 +3,31 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Serverbound.Configuration; -#pragma warning disable CS1591 -public class PluginMessagePacket : IPacket -{ - public PluginMessagePacket(string channelName, PacketBuffer data) - { - ChannelName = channelName; - Data = data; - } - public string ChannelName { get; set; } - public PacketBuffer Data { get; set; } +/// +/// Plugin message packet +/// +/// The name of the channel +/// The data of the plugin message +public sealed record PluginMessagePacket(string ChannelName, byte[] Data) : IPacket +{ + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Configuration_CustomPayload; + /// + public static PacketType StaticType => PacketType.SB_Configuration_CustomPayload; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteString(ChannelName); - buffer.WriteBytes(Data.GetBuffer()); + buffer.WriteBytes(Data); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var channelName = buffer.ReadString(); - var clone = new PacketBuffer(buffer.ReadBytes((int)buffer.ReadableBytes), version.Version.Protocol); - return new PluginMessagePacket(channelName, clone); + var data = buffer.RestBuffer(); + return new PluginMessagePacket(channelName, data); } } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PongPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PongPacket.cs index cd666b63..1b001aa6 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PongPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PongPacket.cs @@ -3,27 +3,28 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Serverbound.Configuration; -#pragma warning disable CS1591 -public class PongPacket : IPacket -{ - public PongPacket(int id) - { - Id = id; - } - public int Id { get; set; } +/// +/// Pong packet +/// +/// The ID of the pong packet +public sealed record PongPacket(int Id) : IPacket +{ + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Configuration_Pong; + /// + public static PacketType StaticType => PacketType.SB_Configuration_Pong; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteInt(Id); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - return new PongPacket( - buffer.ReadInt()); + return new PongPacket(buffer.ReadInt()); } } -#pragma warning restore CS1591 + diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ResourcePackResponsePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ResourcePackResponsePacket.cs index a2765b4c..3cba274e 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ResourcePackResponsePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ResourcePackResponsePacket.cs @@ -4,26 +4,44 @@ namespace MineSharp.Protocol.Packets.Serverbound.Configuration; #pragma warning disable CS1591 -public class ResourcePackResponsePacket : IPacket +/// +/// Resource pack response packet +/// +/// The result of the resource pack response +public sealed record ResourcePackResponsePacket(ResourcePackResponsePacket.ResourcePackResult Result) : IPacket { - public ResourcePackResponsePacket(int result) - { - Result = result; - } - - public int Result { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Configuration_ResourcePackReceive; + /// + public static PacketType StaticType => PacketType.SB_Configuration_ResourcePackReceive; + /// public void Write(PacketBuffer buffer, MinecraftData version) { - buffer.WriteVarInt(Result); + buffer.WriteVarInt((int)Result); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - return new ResourcePackResponsePacket( - buffer.ReadVarInt()); + var result = (ResourcePackResult)buffer.ReadVarInt(); + return new ResourcePackResponsePacket(result); + } + + /// + /// Enum representing the possible results of a resource pack response + /// + public enum ResourcePackResult + { + Success = 0, + Declined = 1, + FailedDownload = 2, + Accepted = 3, + Downloaded = 4, + InvalidUrl = 5, + FailedToReload = 6, + Discarded = 7 } } + #pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Handshaking/HandshakePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Handshaking/HandshakePacket.cs index d160115b..944d760b 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Handshaking/HandshakePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Handshaking/HandshakePacket.cs @@ -6,24 +6,21 @@ namespace MineSharp.Protocol.Packets.Serverbound.Handshaking; #pragma warning disable CS1591 - -public class HandshakePacket : IPacket +/// +/// Packet for setting the protocol during handshake +/// +/// The protocol version +/// The host address +/// The port number +/// The next game state +public sealed record HandshakePacket(int ProtocolVersion, string Host, ushort Port, GameState NextState) : IPacket { - public HandshakePacket(int protocolVersion, string host, ushort port, GameState nextState) - { - ProtocolVersion = protocolVersion; - Host = host; - Port = port; - NextState = nextState; - } - - public int ProtocolVersion { get; set; } - public string Host { get; set; } - public ushort Port { get; set; } - public GameState NextState { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Handshake_SetProtocol; + /// + public static PacketType StaticType => PacketType.SB_Handshake_SetProtocol; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteVarInt(ProtocolVersion); @@ -32,6 +29,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteVarInt((int)NextState); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var protocolVersion = buffer.ReadVarInt(); @@ -42,5 +40,4 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) return new HandshakePacket(protocolVersion, host, port, nextState); } } - #pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Login/EncryptionResponsePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Login/EncryptionResponsePacket.cs index 75bee87e..31446970 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Login/EncryptionResponsePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Login/EncryptionResponsePacket.cs @@ -3,24 +3,24 @@ using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Exceptions; +using static MineSharp.Protocol.Packets.Serverbound.Login.EncryptionResponsePacket; namespace MineSharp.Protocol.Packets.Serverbound.Login; -#pragma warning disable CS1591 -public class EncryptionResponsePacket : IPacket -{ - public EncryptionResponsePacket(byte[] sharedSecret, byte[]? verifyToken, CryptoContainer? crypto) - { - SharedSecret = sharedSecret; - VerifyToken = verifyToken; - Crypto = crypto; - } - public byte[] SharedSecret { get; set; } - public byte[]? VerifyToken { get; set; } - public CryptoContainer? Crypto { get; set; } +/// +/// Encryption response packet +/// +/// The shared secret +/// The verify token +/// The crypto container +public sealed record EncryptionResponsePacket(byte[] SharedSecret, byte[]? VerifyToken, CryptoContainer? Crypto) : IPacket +{ + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Login_EncryptionBegin; + /// + public static PacketType StaticType => PacketType.SB_Login_EncryptionBegin; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteVarInt(SharedSecret.Length); @@ -52,6 +52,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteBytes(VerifyToken); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var sharedSecretLength = buffer.ReadVarInt(); @@ -77,18 +78,14 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) return new EncryptionResponsePacket(sharedSecret, verifyToken, crypto); } - - public class CryptoContainer : ISerializable + /// + /// Crypto container class + /// + /// The salt + /// The message signature + public sealed record CryptoContainer(long Salt, byte[] MessageSignature) : ISerializable { - public CryptoContainer(long salt, byte[] messageSignature) - { - Salt = salt; - MessageSignature = messageSignature; - } - - public long Salt { get; set; } - public byte[] MessageSignature { get; set; } - + /// public void Write(PacketBuffer buffer) { buffer.WriteLong(Salt); @@ -96,14 +93,14 @@ public void Write(PacketBuffer buffer) buffer.WriteBytes(MessageSignature.AsSpan()); } + /// public static CryptoContainer Read(PacketBuffer buffer) { var salt = buffer.ReadLong(); var length = buffer.ReadVarInt(); var verifyToken = buffer.ReadBytes(length); - return new(salt, verifyToken); + return new CryptoContainer(salt, verifyToken); } } } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Login/AcknowledgeLoginPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginAcknowledgedPacket.cs similarity index 50% rename from Components/MineSharp.Protocol/Packets/Serverbound/Login/AcknowledgeLoginPacket.cs rename to Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginAcknowledgedPacket.cs index 1b026628..49fac545 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Login/AcknowledgeLoginPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginAcknowledgedPacket.cs @@ -3,18 +3,25 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Serverbound.Login; -#pragma warning disable CS1591 -public class AcknowledgeLoginPacket : IPacket + +/// +/// Login acknowledged packet +/// +public sealed record LoginAcknowledgedPacket() : IPacket { + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Login_LoginAcknowledged; + /// + public static PacketType StaticType => PacketType.SB_Login_LoginAcknowledged; + /// public void Write(PacketBuffer buffer, MinecraftData version) { } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - return new AcknowledgeLoginPacket(); + return new LoginAcknowledgedPacket(); } } -#pragma warning restore CS1591 + diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginPluginResponsePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginPluginResponsePacket.cs index dfdd7a7b..1f7be096 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginPluginResponsePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginPluginResponsePacket.cs @@ -3,20 +3,23 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Serverbound.Login; -#pragma warning disable CS1591 -public class LoginPluginResponsePacket : IPacket -{ - public LoginPluginResponsePacket(int messageId, byte[]? data) - { - MessageId = messageId; - Data = data; - } - public int MessageId { get; set; } - public byte[]? Data { get; set; } +/// +/// Login plugin response packet +/// +/// The message ID +/// The data +public sealed record LoginPluginResponsePacket(int MessageId, byte[]? Data) : IPacket +{ + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Login_LoginPluginResponse; + /// + public static PacketType StaticType => PacketType.SB_Login_LoginPluginResponse; + + /// + public bool Successful => Data != null; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteVarInt(MessageId); @@ -28,6 +31,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) } } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var messageId = buffer.ReadVarInt(); @@ -41,4 +45,4 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) return new LoginPluginResponsePacket(messageId, data); } } -#pragma warning restore CS1591 + diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginStartPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginStartPacket.cs index 0ab69fbe..e03ee0e8 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginStartPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginStartPacket.cs @@ -6,8 +6,21 @@ namespace MineSharp.Protocol.Packets.Serverbound.Login; #pragma warning disable CS1591 -public class LoginStartPacket : IPacket +public sealed record LoginStartPacket : IPacket { + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.SB_Login_LoginStart; + + // Here is no non-argument constructor allowed + // Do not use +#pragma warning disable CS8618 + private LoginStartPacket() +#pragma warning restore CS8618 + { + } + /// /// Constructor for versions before 1.19 /// @@ -28,7 +41,6 @@ public LoginStartPacket(string username, Uuid? playerUuid) PlayerUuid = playerUuid; } - /// /// Constructor for version 1.19-1.19.2 /// @@ -42,11 +54,9 @@ public LoginStartPacket(string username, SignatureContainer? signature, Uuid? pl PlayerUuid = playerUuid; } - public string Username { get; set; } - public SignatureContainer? Signature { get; set; } - public Uuid? PlayerUuid { get; set; } - public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Login_LoginStart; + public string Username { get; init; } + public SignatureContainer? Signature { get; init; } + public Uuid? PlayerUuid { get; init; } public void Write(PacketBuffer buffer, MinecraftData version) { @@ -102,19 +112,8 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) return new LoginStartPacket(username, signature, playerUuid); } - public class SignatureContainer : ISerializable + public sealed record SignatureContainer(long Timestamp, byte[] PublicKey, byte[] Signature) : ISerializable { - public SignatureContainer(long timestamp, byte[] publicKey, byte[] signature) - { - Timestamp = timestamp; - PublicKey = publicKey; - Signature = signature; - } - - public long Timestamp { get; set; } - public byte[] PublicKey { get; set; } - public byte[] Signature { get; set; } - public void Write(PacketBuffer buffer) { buffer.WriteLong(Timestamp); @@ -127,12 +126,12 @@ public void Write(PacketBuffer buffer) public static SignatureContainer Read(PacketBuffer buffer) { var timestamp = buffer.ReadLong(); - Span publicKey = new byte[buffer.ReadVarInt()]; + var publicKey = new byte[buffer.ReadVarInt()]; buffer.ReadBytes(publicKey); - Span signature = new byte[buffer.ReadVarInt()]; + var signature = new byte[buffer.ReadVarInt()]; buffer.ReadBytes(signature); - return new(timestamp, publicKey.ToArray(), signature.ToArray()); + return new(timestamp, publicKey, signature); } } } diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatCommandPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatCommandPacket.cs index de9d843f..6dbcd333 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatCommandPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatCommandPacket.cs @@ -7,8 +7,21 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; #pragma warning disable CS1591 -public class ChatCommandPacket : IPacket +public sealed record ChatCommandPacket : IPacket { + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.SB_Play_ChatCommand; + + // Here is no non-argument constructor allowed + // Do not use +#pragma warning disable CS8618 + private ChatCommandPacket() +#pragma warning restore CS8618 + { + } + /// /// Constructor for 1.19 - 1.19.1 /// @@ -71,17 +84,15 @@ public ChatCommandPacket(string command, long timestamp, long salt, ArgumentSign Acknowledged = acknowledged; } - public string Command { get; set; } - public long Timestamp { get; set; } - public long Salt { get; set; } - public ArgumentSignature[] Signatures { get; set; } - public bool? SignedPreview { get; set; } - public ChatMessageItem[]? PreviousMessages { get; set; } - public ChatMessageItem? LastRejectedMessage { get; set; } - public int? MessageCount { get; set; } - public byte[]? Acknowledged { get; set; } - public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_ChatCommand; + public string Command { get; init; } + public long Timestamp { get; init; } + public long Salt { get; init; } + public ArgumentSignature[] Signatures { get; init; } + public bool? SignedPreview { get; init; } + public ChatMessageItem[]? PreviousMessages { get; init; } + public ChatMessageItem? LastRejectedMessage { get; init; } + public int? MessageCount { get; init; } + public byte[]? Acknowledged { get; init; } public void Write(PacketBuffer buffer, MinecraftData version) { @@ -140,23 +151,57 @@ public void Write(PacketBuffer buffer, MinecraftData version) LastRejectedMessage!.Write(buffer, version); } + private const int AfterMc1192AcknowledgedLength = 20; + public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - throw new NotImplementedException(); - } + var command = buffer.ReadString(); + var timestamp = buffer.ReadLong(); + var salt = buffer.ReadLong(); + var signatures = buffer.ReadVarIntArray((buf) => ArgumentSignature.Read(buf, version)); - public class ArgumentSignature - { - public byte[] Signature; + bool? signedPreview = null; + if (ProtocolVersion.IsBetween(version.Version.Protocol, ProtocolVersion.V_1_19, ProtocolVersion.V_1_19_2)) + { + signedPreview = buffer.ReadBool(); + } + + byte[]? acknowledged = null; + int? messageCount = null; + if (version.Version.Protocol >= ProtocolVersion.V_1_19_3) + { + messageCount = buffer.ReadVarInt(); + acknowledged = buffer.ReadBytes(AfterMc1192AcknowledgedLength); + } - public ArgumentSignature(string argumentName, byte[] signature) + ChatMessageItem[]? previousMessages = null; + ChatMessageItem? lastRejectedMessage = null; + if (version.Version.Protocol == ProtocolVersion.V_1_19_2) { - ArgumentName = argumentName; - Signature = signature; + previousMessages = buffer.ReadVarIntArray((buf) => ChatMessageItem.Read(buf, version)); + var hasLastRejectedMessage = buffer.ReadBool(); + if (hasLastRejectedMessage) + { + lastRejectedMessage = ChatMessageItem.Read(buffer, version); + } } - public string ArgumentName { get; set; } + return new ChatCommandPacket + { + Command = command, + Timestamp = timestamp, + Salt = salt, + Signatures = signatures, + SignedPreview = signedPreview, + PreviousMessages = previousMessages, + LastRejectedMessage = lastRejectedMessage, + MessageCount = messageCount, + Acknowledged = acknowledged + }; + } + public sealed record ArgumentSignature(string ArgumentName, byte[] Signature) + { public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteString(ArgumentName); @@ -171,6 +216,24 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteBytes(Signature); } } + + private const int AfterMc1192SignatureLength = 256; + + public static ArgumentSignature Read(PacketBuffer buffer, MinecraftData version) + { + var argumentName = buffer.ReadString(); + byte[] signature; + if (version.Version.Protocol <= ProtocolVersion.V_1_19_2) + { + var length = buffer.ReadVarInt(); + signature = buffer.ReadBytes(length); + } + else + { + signature = buffer.ReadBytes(AfterMc1192SignatureLength); + } + return new ArgumentSignature(argumentName, signature); + } } } #pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatMessagePacket.cs index 05255921..75a2ad4c 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatMessagePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatMessagePacket.cs @@ -7,8 +7,13 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; #pragma warning disable CS1591 -public class ChatMessagePacket : IPacket +public sealed record ChatMessagePacket : IPacket { + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.SB_Play_ChatMessage; + public ChatMessagePacket( string message, long timestamp, @@ -50,17 +55,15 @@ public ChatMessagePacket(string message, long timestamp, long salt, byte[]? sign : this(message, timestamp, salt, signature, null, null, null, messageCount, acknowledged) { } - public string Message { get; set; } - public long Timestamp { get; set; } - public long Salt { get; set; } - public byte[]? Signature { get; set; } - public bool? SignedPreview { get; set; } - public ChatMessageItem[]? PreviousMessages { get; set; } - public ChatMessageItem? LastRejectedMessage { get; set; } - public int? MessageCount { get; set; } - public byte[]? Acknowledged { get; set; } - public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_ChatMessage; + public string Message { get; init; } + public long Timestamp { get; init; } + public long Salt { get; init; } + public byte[]? Signature { get; init; } + public bool? SignedPreview { get; init; } + public ChatMessageItem[]? PreviousMessages { get; init; } + public ChatMessageItem? LastRejectedMessage { get; init; } + public int? MessageCount { get; init; } + public byte[]? Acknowledged { get; init; } public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatPacket.cs index 42a1ed9c..00e7bd67 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatPacket.cs @@ -7,16 +7,12 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; /// /// ChatPacket used before 1.19 to send a Chat message /// -public class ChatPacket : IPacket +public sealed record ChatPacket(string Message) : IPacket { - public ChatPacket(string message) - { - Message = message; - } - - public string Message { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_Chat; + /// + public static PacketType StaticType => PacketType.SB_Play_Chat; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChunkBatchReceivedPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChunkBatchReceivedPacket.cs index a90ba476..803c41e5 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChunkBatchReceivedPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChunkBatchReceivedPacket.cs @@ -8,25 +8,12 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; /// The ChunkBatchReceived packet, used since 1.20.2. /// https://wiki.vg/Protocol#Chunk_Batch_Received /// -public class ChunkBatchReceivedPacket : IPacket +public sealed record ChunkBatchReceivedPacket(float ChunksPerTick) : IPacket { - /// - /// Create a new ChunkBatchReceivedPacket instance - /// - /// - public ChunkBatchReceivedPacket(float chunksPerTick) - { - ChunksPerTick = chunksPerTick; - } - - /// - /// ChunksPerTick - /// - public float ChunksPerTick { get; set; } - /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_ChunkBatchReceived; + /// + public static PacketType StaticType => PacketType.SB_Play_ChunkBatchReceived; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientCommandPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientCommandPacket.cs index 7c49a14f..17d8862e 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientCommandPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientCommandPacket.cs @@ -3,27 +3,28 @@ using MineSharp.Data.Protocol; namespace MineSharp.Protocol.Packets.Serverbound.Play; -#pragma warning disable CS1591 -public class ClientCommandPacket : IPacket -{ - public ClientCommandPacket(int actionId) - { - ActionId = actionId; - } - public int ActionId { get; set; } +/// +/// Represents a client command packet. +/// +/// The action ID of the client command. +public sealed record ClientCommandPacket(int ActionId) : IPacket +{ + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_ClientCommand; + /// + public static PacketType StaticType => PacketType.SB_Play_ClientCommand; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteVarInt(ActionId); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var actionId = buffer.ReadVarInt(); return new ClientCommandPacket(actionId); } } -#pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientInformationPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientInformationPacket.cs index 5410c2ba..4048e236 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientInformationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientInformationPacket.cs @@ -4,41 +4,30 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; #pragma warning disable CS1591 -public class ClientInformationPacket : IPacket +public sealed record ClientInformationPacket( + string Locale, + byte ViewDistance, + ChatMode ChatMode, + bool ChatColors, + SkinPart DisplayedSkinParts, + PlayerHand MainHand, + bool EnableTextFiltering, + bool AllowServerListings +) : IPacket { - public ClientInformationPacket(string locale, byte viewDistance, int chatMode, bool chatColors, - byte displayedSkinParts, int mainHand, - bool enableTextFiltering, bool allowServerListings) - { - Locale = locale; - ViewDistance = viewDistance; - ChatMode = chatMode; - ChatColors = chatColors; - DisplayedSkinParts = displayedSkinParts; - MainHand = mainHand; - EnableTextFiltering = enableTextFiltering; - AllowServerListings = allowServerListings; - } - - public string Locale { get; set; } - public byte ViewDistance { get; set; } - public int ChatMode { get; set; } - public bool ChatColors { get; set; } - public byte DisplayedSkinParts { get; set; } - public int MainHand { get; set; } - public bool EnableTextFiltering { get; set; } - public bool AllowServerListings { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_Settings; + /// + public static PacketType StaticType => PacketType.SB_Play_Settings; public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteString(Locale); buffer.WriteByte(ViewDistance); - buffer.WriteVarInt(ChatMode); + buffer.WriteVarInt((int)ChatMode); buffer.WriteBool(ChatColors); - buffer.WriteByte(DisplayedSkinParts); - buffer.WriteVarInt(MainHand); + buffer.WriteByte((byte)DisplayedSkinParts); + buffer.WriteVarInt((int)MainHand); buffer.WriteBool(EnableTextFiltering); buffer.WriteBool(AllowServerListings); } @@ -48,12 +37,13 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) return new ClientInformationPacket( buffer.ReadString(), buffer.ReadByte(), - buffer.ReadVarInt(), + (ChatMode)buffer.ReadVarInt(), buffer.ReadBool(), - buffer.ReadByte(), - buffer.ReadVarInt(), + (SkinPart)buffer.ReadByte(), + (PlayerHand)buffer.ReadVarInt(), buffer.ReadBool(), - buffer.ReadBool()); + buffer.ReadBool() + ); } } #pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/CloseWindowPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/CloseWindowPacket.cs index a0391f65..343857b8 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/CloseWindowPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/CloseWindowPacket.cs @@ -4,16 +4,12 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; #pragma warning disable CS1591 -public class CloseWindowPacket : IPacket +public sealed record CloseWindowPacket(byte WindowId) : IPacket { - public CloseWindowPacket(byte windowId) - { - WindowId = windowId; - } - - public byte WindowId { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_CloseWindow; + /// + public static PacketType StaticType => PacketType.SB_Play_CloseWindow; public void Write(PacketBuffer buffer, MinecraftData version) { @@ -22,8 +18,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - return new CloseWindowPacket( - buffer.ReadByte()); + return new CloseWindowPacket(buffer.ReadByte()); } } #pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ConfirmTeleportPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ConfirmTeleportPacket.cs index 5f3a2711..dfa8d037 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ConfirmTeleportPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ConfirmTeleportPacket.cs @@ -4,16 +4,12 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; #pragma warning disable CS1591 -public class ConfirmTeleportPacket : IPacket +public sealed record ConfirmTeleportPacket(int TeleportId) : IPacket { - public ConfirmTeleportPacket(int teleportId) - { - TeleportId = teleportId; - } - - public int TeleportId { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_TeleportConfirm; + /// + public static PacketType StaticType => PacketType.SB_Play_TeleportConfirm; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/EntityActionPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/EntityActionPacket.cs index a7a93447..7ecd5b31 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/EntityActionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/EntityActionPacket.cs @@ -4,33 +4,12 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; #pragma warning disable CS1591 -public class EntityActionPacket : IPacket +public sealed record EntityActionPacket(int EntityId, EntityActionPacket.EntityAction Action, int JumpBoost) : IPacket { - public enum EntityAction - { - StartSneaking = 0, - StopSneaking = 1, - LeaveBed = 2, - StartSprinting = 3, - StopSprinting = 4, - StartJumpWithHorse = 5, - StopJumpWithHorse = 6, - OpenVehicleInventory = 7, - StartFlyingWithElytra = 8 - } - - public EntityActionPacket(int entityId, EntityAction action, int jumpBoost) - { - EntityId = entityId; - Action = action; - JumpBoost = jumpBoost; - } - - public int EntityId { get; set; } - public EntityAction Action { get; set; } - public int JumpBoost { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_EntityAction; + /// + public static PacketType StaticType => PacketType.SB_Play_EntityAction; public void Write(PacketBuffer buffer, MinecraftData version) { @@ -46,6 +25,18 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) (EntityAction)buffer.ReadVarInt(), buffer.ReadVarInt()); } -} + public enum EntityAction + { + StartSneaking = 0, + StopSneaking = 1, + LeaveBed = 2, + StartSprinting = 3, + StopSprinting = 4, + StartJumpWithHorse = 5, + StopJumpWithHorse = 6, + OpenVehicleInventory = 7, + StartFlyingWithElytra = 8 + } +} #pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/InteractPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/InteractPacket.cs index 0e51b672..279526e8 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/InteractPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/InteractPacket.cs @@ -1,60 +1,35 @@ using MineSharp.Core.Common; using MineSharp.Data; using MineSharp.Data.Protocol; +using static MineSharp.Protocol.Packets.Serverbound.Play.InteractPacket; namespace MineSharp.Protocol.Packets.Serverbound.Play; #pragma warning disable CS1591 -public class InteractPacket : IPacket +public sealed record InteractPacket( + int EntityId, + InteractionType Interaction, + float? TargetX, + float? TargetY, + float? TargetZ, + PlayerHand? Hand, + bool Sneaking +) : IPacket { - public enum InteractionType - { - Interact = 0, - Attack = 1, - InteractAt = 2 - } - /// - /// Constructor + /// Constructor for all interaction types except . /// /// /// /// public InteractPacket(int entityId, InteractionType interaction, bool sneaking) + : this(entityId, interaction, null, null, null, null, sneaking) { - EntityId = entityId; - Interaction = interaction; - Sneaking = sneaking; } - /// - /// Constructor for - /// - /// - /// - /// - /// - /// - /// - public InteractPacket(int entityId, float targetX, float targetY, float targetZ, PlayerHand hand, bool sneaking) - { - EntityId = entityId; - Interaction = InteractionType.InteractAt; - TargetX = targetX; - TargetY = targetY; - TargetZ = targetZ; - Hand = hand; - Sneaking = sneaking; - } - - public int EntityId { get; set; } - public InteractionType Interaction { get; set; } - public float? TargetX { get; set; } - public float? TargetY { get; set; } - public float? TargetZ { get; set; } - public PlayerHand? Hand { get; set; } - public bool Sneaking { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_UseEntity; + /// + public static PacketType StaticType => PacketType.SB_Play_UseEntity; public void Write(PacketBuffer buffer, MinecraftData version) { @@ -80,17 +55,31 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) { return new InteractPacket( entityId, + interaction, buffer.ReadFloat(), buffer.ReadFloat(), buffer.ReadFloat(), (PlayerHand)buffer.ReadVarInt(), - buffer.ReadBool()); + buffer.ReadBool() + ); } return new InteractPacket( entityId, interaction, - buffer.ReadBool()); + null, + null, + null, + null, + buffer.ReadBool() + ); + } + + public enum InteractionType + { + Interact = 0, + Attack = 1, + InteractAt = 2 } } #pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/KeepAlivePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/KeepAlivePacket.cs index aba3eb0f..b8c026a6 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/KeepAlivePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/KeepAlivePacket.cs @@ -4,16 +4,12 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; #pragma warning disable CS1591 -public class KeepAlivePacket : IPacket +public sealed record KeepAlivePacket(long KeepAliveId) : IPacket { - public KeepAlivePacket(long id) - { - KeepAliveId = id; - } - - public long KeepAliveId { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_KeepAlive; + /// + public static PacketType StaticType => PacketType.SB_Play_KeepAlive; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/MessageAcknowledgementPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/MessageAcknowledgementPacket.cs index 34461011..b87f0bae 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/MessageAcknowledgementPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/MessageAcknowledgementPacket.cs @@ -7,8 +7,19 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; #pragma warning disable CS1591 -public class MessageAcknowledgementPacket : IPacket +public sealed record MessageAcknowledgementPacket : IPacket { + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.SB_Play_MessageAcknowledgement; + + // Here is no non-argument constructor allowed + // Do not use + private MessageAcknowledgementPacket() + { + } + /** * Constructor for >= 1.19.3 */ @@ -26,11 +37,9 @@ public MessageAcknowledgementPacket(ChatMessageItem[]? previousMessages, ChatMes LastRejectedMessage = lastRejectedMessage; } - public int? Count { get; set; } - public ChatMessageItem[]? PreviousMessages { get; set; } - public ChatMessageItem? LastRejectedMessage { get; set; } - public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_MessageAcknowledgement; + public int? Count { get; init; } + public ChatMessageItem[]? PreviousMessages { get; init; } + public ChatMessageItem? LastRejectedMessage { get; init; } public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlaceBlockPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlaceBlockPacket.cs index 340476c0..8fe70f39 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlaceBlockPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlaceBlockPacket.cs @@ -6,8 +6,21 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; #pragma warning disable CS1591 -public class PlaceBlockPacket : IPacket +public sealed record PlaceBlockPacket : IPacket { + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.SB_Play_BlockPlace; + + // Here is no non-argument constructor allowed + // Do not use +#pragma warning disable CS8618 + private PlaceBlockPacket() +#pragma warning restore CS8618 + { + } + /// /// Constructor >= 1.19 /// @@ -55,16 +68,14 @@ public PlaceBlockPacket(int hand, Position location, BlockFace direction, float InsideBlock = insideBlock; } - public int Hand { get; set; } - public Position Location { get; set; } - public BlockFace Direction { get; set; } - public float CursorX { get; set; } - public float CursorY { get; set; } - public float CursorZ { get; set; } - public bool InsideBlock { get; set; } - public int? SequenceId { get; set; } - public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_BlockPlace; + public int Hand { get; init; } + public Position Location { get; init; } + public BlockFace Direction { get; init; } + public float CursorX { get; init; } + public float CursorY { get; init; } + public float CursorZ { get; init; } + public bool InsideBlock { get; init; } + public int? SequenceId { get; init; } public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerActionPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerActionPacket.cs index 83fe6769..d6be1e62 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerActionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerActionPacket.cs @@ -6,8 +6,21 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; #pragma warning disable CS1591 -public class PlayerActionPacket : IPacket +public sealed record PlayerActionPacket : IPacket { + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.SB_Play_BlockDig; + + // Here is no non-argument constructor allowed + // Do not use +#pragma warning disable CS8618 + private PlayerActionPacket() +#pragma warning restore CS8618 + { + } + /// /// Constructor for versions before 1.19 /// @@ -37,12 +50,10 @@ public PlayerActionPacket(int status, Position location, BlockFace face, int? se SequenceId = sequenceId; } - public int Status { get; set; } - public Position Location { get; set; } - public BlockFace Face { get; set; } - public int? SequenceId { get; set; } - public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_BlockDig; + public int Status { get; init; } + public Position Location { get; init; } + public BlockFace Face { get; init; } + public int? SequenceId { get; init; } public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerSessionPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerSessionPacket.cs index b5e7b047..cb3698c6 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerSessionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerSessionPacket.cs @@ -4,22 +4,12 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; #pragma warning disable CS1591 -public class PlayerSessionPacket : IPacket +public sealed record PlayerSessionPacket(Uuid SessionId, long ExpiresAt, byte[] PublicKey, byte[] KeySignature) : IPacket { - public PlayerSessionPacket(Uuid sessionId, long expiresAt, byte[] publicKey, byte[] keySignature) - { - SessionId = sessionId; - ExpiresAt = expiresAt; - PublicKey = publicKey; - KeySignature = keySignature; - } - - public Uuid SessionId { get; set; } - public long ExpiresAt { get; set; } - public byte[] PublicKey { get; set; } - public byte[] KeySignature { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_ChatSessionUpdate; + /// + public static PacketType StaticType => PacketType.SB_Play_ChatSessionUpdate; public void Write(PacketBuffer buffer, MinecraftData version) { @@ -40,8 +30,7 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) var keySignature = new byte[buffer.ReadVarInt()]; buffer.ReadBytes(keySignature); - return new PlayerSessionPacket( - sessionId, expiresAt, publicKey, keySignature); + return new PlayerSessionPacket(sessionId, expiresAt, publicKey, keySignature); } } #pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PongPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PongPacket.cs index 0a04c80b..47a68da2 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PongPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PongPacket.cs @@ -8,16 +8,12 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; /// Pong Packet https://wiki.vg/Protocol#Ping_Response_.28play.29 /// /// -public class PongPacket(int id) : IPacket +public sealed record PongPacket(int Id) : IPacket { - /// - /// Pong id - /// - public int Id { get; set; } = id; - /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_Pong; + /// + public static PacketType StaticType => PacketType.SB_Play_Pong; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetCreativeSlotPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetCreativeSlotPacket.cs index 4152f47a..0fef40c7 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetCreativeSlotPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetCreativeSlotPacket.cs @@ -9,30 +9,14 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; /// /// Packet used to set slots in creative inventory (https://wiki.vg/Protocol#Set_Creative_Mode_Slot) /// -public class SetCreativeSlotPacket : IPacket +/// The slot index +/// The clicked Item +public sealed record SetCreativeSlotPacket(short SlotIndex, Item? Item) : IPacket { - /// - /// Constructor - /// - public SetCreativeSlotPacket(short slotIndex, Item? item) - { - SlotIndex = slotIndex; - Item = item; - } - - /// - /// The inventory slot index - /// - public short SlotIndex { get; set; } - - /// - /// The clicked item - /// - public Item? Item { get; set; } - /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_SetCreativeSlot; + /// + public static PacketType StaticType => PacketType.SB_Play_SetCreativeSlot; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetHeldItemPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetHeldItemPacket.cs index a6a9755e..8fc0c91b 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetHeldItemPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetHeldItemPacket.cs @@ -7,25 +7,12 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; /// /// Sent when the player changes the slot selection /// -public class SetHeldItemPacket : IPacket +public sealed record SetHeldItemPacket(short Slot) : IPacket { - /// - /// Constructor - /// - /// - public SetHeldItemPacket(short slot) - { - Slot = slot; - } - - /// - /// Index of the new selected hotbar slot (0-8) - /// - public short Slot { get; set; } - /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_HeldItemSlot; + /// + public static PacketType StaticType => PacketType.SB_Play_HeldItemSlot; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionAndRotationPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionAndRotationPacket.cs index c1c8b891..06840995 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionAndRotationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionAndRotationPacket.cs @@ -4,26 +4,12 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; #pragma warning disable CS1591 -public class SetPlayerPositionAndRotationPacket : IPacket +public sealed record SetPlayerPositionAndRotationPacket(double X, double Y, double Z, float Yaw, float Pitch, bool IsOnGround) : IPacket { - public SetPlayerPositionAndRotationPacket(double x, double y, double z, float yaw, float pitch, bool isOnGround) - { - X = x; - Y = y; - Z = z; - Yaw = yaw; - Pitch = pitch; - IsOnGround = isOnGround; - } - - public double X { get; set; } - public double Y { get; set; } - public double Z { get; set; } - public float Yaw { get; set; } - public float Pitch { get; set; } - public bool IsOnGround { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_PositionLook; + /// + public static PacketType StaticType => PacketType.SB_Play_PositionLook; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionPacket.cs index 3f06e246..765f39cd 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionPacket.cs @@ -4,22 +4,12 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; #pragma warning disable CS1591 -public class SetPlayerPositionPacket : IPacket +public sealed record SetPlayerPositionPacket(double X, double Y, double Z, bool IsOnGround) : IPacket { - public SetPlayerPositionPacket(double x, double y, double z, bool isOnGround) - { - X = x; - Y = y; - Z = z; - IsOnGround = isOnGround; - } - - public double X { get; set; } - public double Y { get; set; } - public double Z { get; set; } - public bool IsOnGround { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_Position; + /// + public static PacketType StaticType => PacketType.SB_Play_Position; public void Write(PacketBuffer buffer, MinecraftData version) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SwingArmPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SwingArmPacket.cs index 82b65621..be5a6ed8 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SwingArmPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SwingArmPacket.cs @@ -4,22 +4,20 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; #pragma warning disable CS1591 -public class SwingArmPacket : IPacket +public sealed record SwingArmPacket(PlayerHand Hand) : IPacket { - public SwingArmPacket(PlayerHand hand) - { - Hand = hand; - } - - public PlayerHand Hand { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_ArmAnimation; + /// + public static PacketType StaticType => PacketType.SB_Play_ArmAnimation; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteVarInt((int)Hand); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { return new SwingArmPacket( diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/UpdateCommandBlock.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/UpdateCommandBlock.cs index fc00a52c..0248c78d 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/UpdateCommandBlock.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/UpdateCommandBlock.cs @@ -5,23 +5,14 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; #pragma warning disable CS1591 -public class UpdateCommandBlock : IPacket +public sealed record UpdateCommandBlock(Position Location, string Command, int Mode, byte Flags) : IPacket { - public UpdateCommandBlock(Position location, string command, int mode, byte flags) - { - Location = location; - Command = command; - Mode = mode; - Flags = flags; - } - - public Position Location { get; set; } - public string Command { get; set; } - public int Mode { get; set; } - public byte Flags { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_UpdateCommandBlock; + /// + public static PacketType StaticType => PacketType.SB_Play_UpdateCommandBlock; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteULong(Location.ToULong()); @@ -30,6 +21,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteByte(Flags); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { return new UpdateCommandBlock( @@ -39,5 +31,4 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) buffer.ReadByte()); } } - #pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/UseItemPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/UseItemPacket.cs index e891bb2a..5b2f0732 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/UseItemPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/UseItemPacket.cs @@ -8,41 +8,17 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; /// /// Packet to use an item /// -public class UseItemPacket : IPacket +/// The Hand used +/// +/// Sequence id used to synchronize server and client. +/// Only used for versions >= 1.19 +/// +public sealed record UseItemPacket(PlayerHand Hand, int? SequenceId = null) : IPacket { - /// - /// Constructor for 1.18-1.18.2 - /// - /// - public UseItemPacket(PlayerHand hand) - { - Hand = hand; - } - - /// - /// Constructor for >= 1.19 - /// - /// - /// - public UseItemPacket(PlayerHand hand, int sequenceId) : this(hand) - { - SequenceId = sequenceId; - } - - /// - /// The Hand used - /// - public PlayerHand Hand { get; set; } - - /// - /// Sequence id used to synchronize server and client. - /// Only used for versions >= 1.19 - /// - public int? SequenceId { get; set; } - /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_UseItem; + /// + public static PacketType StaticType => PacketType.SB_Play_UseItem; /// public void Write(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/WindowClickPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/WindowClickPacket.cs index cf4b044c..920d7820 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/WindowClickPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/WindowClickPacket.cs @@ -6,30 +6,20 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; #pragma warning disable CS1591 -public class WindowClickPacket : IPacket +public sealed record WindowClickPacket( + byte WindowId, + int StateId, + short Slot, + sbyte MouseButton, + int Mode, + Slot[] ChangedSlots, + Item? SelectedItem +) : IPacket { - public WindowClickPacket(byte windowId, int stateId, short slot, sbyte mouseButton, int mode, Slot[] changedSlots, - Item? selectedItem) - { - WindowId = windowId; - StateId = stateId; - Slot = slot; - MouseButton = mouseButton; - Mode = mode; - ChangedSlots = changedSlots; - SelectedItem = selectedItem; - } - - public byte WindowId { get; set; } - public int StateId { get; set; } - public short Slot { get; set; } - public sbyte MouseButton { get; set; } - public int Mode { get; set; } - public Slot[] ChangedSlots { get; set; } - public Item? SelectedItem { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Play_WindowClick; - + /// + public static PacketType StaticType => PacketType.SB_Play_WindowClick; public void Write(PacketBuffer buffer, MinecraftData version) { @@ -51,7 +41,8 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) buffer.ReadSByte(), buffer.ReadVarInt(), buffer.ReadVarIntArray(buff => buff.ReadSlot(version)), - buffer.ReadOptionalItem(version)); + buffer.ReadOptionalItem(version) + ); } } #pragma warning restore CS1591 diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Status/PingRequestPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Status/PingRequestPacket.cs index 0f1627ef..c143baa3 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Status/PingRequestPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Status/PingRequestPacket.cs @@ -4,22 +4,24 @@ namespace MineSharp.Protocol.Packets.Serverbound.Status; #pragma warning disable CS1591 -public class PingRequestPacket : IPacket +/// +/// Packet for ping request +/// +/// The payload of the ping request +public sealed record PingRequestPacket(long Payload) : IPacket { - public PingRequestPacket(long payload) - { - Payload = payload; - } - - public long Payload { get; set; } + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Status_Ping; + /// + public static PacketType StaticType => PacketType.SB_Status_Ping; + /// public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteLong(Payload); } + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { return new PingRequestPacket(buffer.ReadLong()); diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Status/StatusRequestPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Status/StatusRequestPacket.cs index e19f8cb1..42291fe6 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Status/StatusRequestPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Status/StatusRequestPacket.cs @@ -4,10 +4,12 @@ namespace MineSharp.Protocol.Packets.Serverbound.Status; #pragma warning disable CS1591 -public class StatusRequestPacket : IPacket +public sealed record StatusRequestPacket : IPacket { + /// public PacketType Type => StaticType; -public static PacketType StaticType => PacketType.SB_Status_PingStart; + /// + public static PacketType StaticType => PacketType.SB_Status_PingStart; public void Write(PacketBuffer buffer, MinecraftData version) { } diff --git a/MineSharp.Bot/Plugins/EntityPlugin.cs b/MineSharp.Bot/Plugins/EntityPlugin.cs index de855eea..e240a9cd 100644 --- a/MineSharp.Bot/Plugins/EntityPlugin.cs +++ b/MineSharp.Bot/Plugins/EntityPlugin.cs @@ -317,7 +317,7 @@ private async Task HandleSynchronizePlayerPosition(PlayerPositionPacket packet) var position = (playerPlugin!.Entity!.Position as MutableVector3)!; - if ((packet.Flags & 0x01) == 0x01) + if (packet.Flags.HasFlag(PlayerPositionPacket.PositionFlags.X)) { position.Add(packet.X, 0, 0); } @@ -326,7 +326,7 @@ private async Task HandleSynchronizePlayerPosition(PlayerPositionPacket packet) position.SetX(packet.X); } - if ((packet.Flags & 0x02) == 0x02) + if (packet.Flags.HasFlag(PlayerPositionPacket.PositionFlags.Y)) { position.Add(0, packet.Y, 0); } @@ -335,7 +335,7 @@ private async Task HandleSynchronizePlayerPosition(PlayerPositionPacket packet) position.SetY(packet.Y); } - if ((packet.Flags & 0x04) == 0x04) + if (packet.Flags.HasFlag(PlayerPositionPacket.PositionFlags.Z)) { position.Add(0, 0, packet.Z); } @@ -344,7 +344,7 @@ private async Task HandleSynchronizePlayerPosition(PlayerPositionPacket packet) position.SetZ(packet.Z); } - if ((packet.Flags & 0x08) == 0x08) + if (packet.Flags.HasFlag(PlayerPositionPacket.PositionFlags.YRot)) { playerPlugin!.Entity!.Pitch += packet.Pitch; } @@ -353,7 +353,7 @@ private async Task HandleSynchronizePlayerPosition(PlayerPositionPacket packet) playerPlugin!.Entity!.Pitch = packet.Pitch; } - if ((packet.Flags & 0x10) == 0x10) + if (packet.Flags.HasFlag(PlayerPositionPacket.PositionFlags.XRot)) { playerPlugin!.Entity!.Yaw += packet.Yaw; } diff --git a/MineSharp.Core/Common/Entities/Attributes/Attribute.cs b/MineSharp.Core/Common/Entities/Attributes/Attribute.cs index ae1b0093..7d3f121c 100644 --- a/MineSharp.Core/Common/Entities/Attributes/Attribute.cs +++ b/MineSharp.Core/Common/Entities/Attributes/Attribute.cs @@ -5,14 +5,14 @@ namespace MineSharp.Core.Common.Entities.Attributes; /// /// Entity Attribute /// -public class Attribute +public sealed record Attribute { /// /// Create a new Attribute /// - /// - /// - /// + /// The name of this Attribute + /// The base value of this attribute + /// The modifiers active for this attribute. Indexed by their UUID public Attribute(string key, double @base, Modifier[] modifiers) { Key = key; @@ -23,17 +23,17 @@ public Attribute(string key, double @base, Modifier[] modifiers) /// /// The name of this Attribute /// - public string Key { get; } + public string Key { get; init; } /// /// The base value of this attribute /// - public double Base { get; } + public double Base { get; init; } /// /// The modifiers active for this attribute. Indexed by their UUID /// - public Dictionary Modifiers { get; } + public Dictionary Modifiers { get; } // must never be set from outside because we do not want uncontrollable Dictionary changes /// /// Calculate the Multiplier of this attribute with all modifiers. @@ -74,4 +74,20 @@ public void RemoveModifier(Uuid uuid) { Modifiers.Remove(uuid); } + + public void Write(PacketBuffer buffer) + { + buffer.WriteString(Key); + buffer.WriteDouble(Value); + buffer.WriteVarIntArray(Modifiers.Values, (buffer, modifier) => modifier.Write(buffer)); + } + + public static Attribute Read(PacketBuffer buffer) + { + var key = buffer.ReadString(); + var value = buffer.ReadDouble(); + var modifiers = buffer.ReadVarIntArray(Modifier.Read); + + return new(key, value, modifiers); + } } diff --git a/MineSharp.Core/Common/Entities/Attributes/Modifier.cs b/MineSharp.Core/Common/Entities/Attributes/Modifier.cs index a052ccb0..732cdb57 100644 --- a/MineSharp.Core/Common/Entities/Attributes/Modifier.cs +++ b/MineSharp.Core/Common/Entities/Attributes/Modifier.cs @@ -3,7 +3,24 @@ /// /// A modifier for an attribute /// -/// The uuid associated with this Modifier. This is a constant value from minecraft java. +/// The uuid associated with this Modifier. This is a constant value from Minecraft java. /// /// -public record Modifier(Uuid Uuid, double Amount, ModifierOp Operation); +public sealed record Modifier(Uuid Uuid, double Amount, ModifierOp Operation) +{ + public void Write(PacketBuffer buffer) + { + buffer.WriteUuid(Uuid); + buffer.WriteDouble(Amount); + buffer.WriteByte((byte)Operation); + } + + public static Modifier Read(PacketBuffer buffer) + { + var uuid = buffer.ReadUuid(); + var amount = buffer.ReadDouble(); + var operation = buffer.ReadByte(); + + return new(uuid, amount, (ModifierOp)operation); + } +} From 3f2e3cbf86558b2d82c68ff72703dc9c9772d28d Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 7 Aug 2024 19:35:14 +0200 Subject: [PATCH 26/73] fixed race condition bug in HandleUpdateAttributesPacket --- MineSharp.Bot/Plugins/EntityPlugin.cs | 6 ++---- MineSharp.Core/Common/Entities/Entity.cs | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/MineSharp.Bot/Plugins/EntityPlugin.cs b/MineSharp.Bot/Plugins/EntityPlugin.cs index e240a9cd..6d02284f 100644 --- a/MineSharp.Bot/Plugins/EntityPlugin.cs +++ b/MineSharp.Bot/Plugins/EntityPlugin.cs @@ -297,10 +297,8 @@ private Task HandleUpdateAttributesPacket(UpdateAttributesPacket packet) foreach (var attribute in packet.Attributes) { - if (!entity.Attributes.TryAdd(attribute.Key, attribute)) - { - entity.Attributes[attribute.Key] = attribute; - } + // must not be Attributes[Key] = attribute because this might cause an exception + entity.Attributes.AddOrUpdate(attribute.Key, attribute, (key, oldvalue) => attribute); } return Task.CompletedTask; diff --git a/MineSharp.Core/Common/Entities/Entity.cs b/MineSharp.Core/Common/Entities/Entity.cs index 96b7b250..7816b20a 100644 --- a/MineSharp.Core/Common/Entities/Entity.cs +++ b/MineSharp.Core/Common/Entities/Entity.cs @@ -74,7 +74,7 @@ public class Entity( /// /// A list of attributes active on this entity /// - public IDictionary Attributes { get; } = new ConcurrentDictionary(); + public ConcurrentDictionary Attributes { get; } = new(); /// /// The entity this entity is riding (f.e. an boat or a minecart) @@ -99,7 +99,7 @@ public class Entity( /// public void AddAttribute(Attribute attribute) { - Attributes.Add(attribute.Key, attribute); + Attributes.TryAdd(attribute.Key, attribute); } /// From d6e2705e5a4acad7bb0b165d733a6365c9b6c192 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 7 Aug 2024 20:03:25 +0200 Subject: [PATCH 27/73] removed unnessecary CryptoActionV19 --- .../Play/PlayerInfoUpdatePacket.cs | 61 ------------------- 1 file changed, 61 deletions(-) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoUpdatePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoUpdatePacket.cs index fc9e7cbd..5dd00e75 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoUpdatePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoUpdatePacket.cs @@ -5,7 +5,6 @@ using MineSharp.Data.Protocol; using static MineSharp.Protocol.Packets.Clientbound.Play.PlayerInfoUpdatePacket; using static MineSharp.Protocol.Packets.Clientbound.Play.PlayerInfoUpdatePacket.AddPlayerAction; -using static MineSharp.Protocol.Packets.Clientbound.Play.PlayerInfoUpdatePacket.CryptoActionV19; using static MineSharp.Protocol.Packets.Clientbound.Play.PlayerInfoUpdatePacket.InitializeChatAction; namespace MineSharp.Protocol.Packets.Clientbound.Play; @@ -76,13 +75,6 @@ public static ActionEntry Read(PacketBuffer buffer, MinecraftData version, int a actions.Add(UpdateGameModeAction.Read(buffer)); actions.Add(UpdateLatencyAction.Read(buffer)); actions.Add(UpdateDisplayName.Read(buffer)); - - if (ProtocolVersion.IsBetween(version.Version.Protocol, ProtocolVersion.V_1_19, - ProtocolVersion.V_1_19_2)) - { - actions.Add(CryptoActionV19.Read(buffer)); - } - break; case 1: actions.Add(UpdateGameModeAction.Read(buffer)); @@ -140,7 +132,6 @@ void Register() Register(); Register(); Register(); - Register(); return dict.ToFrozenDictionary(); } @@ -366,57 +357,5 @@ static IPlayerInfoAction IPlayerInfoActionStatic.Read(PacketBuffer buffer) return Read(buffer); } } - - public sealed record CryptoActionV19(CryptoActionV19Data? Data) : IPlayerInfoAction, IPlayerInfoActionStatic - { - public static int StaticMask => 0x30; - public int Mask => StaticMask; - - public sealed record CryptoActionV19Data( - long Timestamp, - byte[] EncodedPublicKey, - byte[] PublicKeySignature - ); - - public void Write(PacketBuffer buffer) - { - var present = Data != null; - buffer.WriteBool(present); - - if (!present) - { - return; - } - - buffer.WriteLong(Data!.Timestamp); - buffer.WriteVarInt(Data!.EncodedPublicKey.Length); - buffer.WriteBytes(Data!.EncodedPublicKey); - buffer.WriteVarInt(Data!.PublicKeySignature.Length); - buffer.WriteBytes(Data!.PublicKeySignature); - } - - public static CryptoActionV19 Read(PacketBuffer buffer) - { - var present = buffer.ReadBool(); - if (!present) - { - return new CryptoActionV19((CryptoActionV19Data?)null); - } - - var timestamp = buffer.ReadLong(); - var encodedPublicKey = new byte[buffer.ReadVarInt()]; - buffer.ReadBytes(encodedPublicKey); - var publicKeySignature = new byte[buffer.ReadVarInt()]; - buffer.ReadBytes(publicKeySignature); - - return new CryptoActionV19(new CryptoActionV19Data(timestamp, encodedPublicKey, publicKeySignature)); - } - - static IPlayerInfoAction IPlayerInfoActionStatic.Read(PacketBuffer buffer) - { - return Read(buffer); - } - } - } #pragma warning restore CS1591 From 2c70c40670e2c90f0057f047250d6993f75e7691 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 7 Aug 2024 21:15:13 +0200 Subject: [PATCH 28/73] fixed bug when parsing dimension --- .../Packets/Clientbound/Play/RespawnPacket.cs | 12 ++++++------ MineSharp.Bot/Plugins/PlayerPlugin.cs | 18 +++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs index 5db7e3aa..f0fa91fe 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs @@ -8,7 +8,7 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 public sealed record RespawnPacket( - string Dimension, + string DimensionType, string DimensionName, long HashedSeed, sbyte GameMode, @@ -35,7 +35,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) $"{nameof(RespawnPacket)}.Write() is not supported for versions before 1.19."); } - buffer.WriteString(Dimension); + buffer.WriteString(DimensionType); buffer.WriteString(DimensionName); buffer.WriteLong(HashedSeed); buffer.WriteSByte(GameMode); @@ -65,16 +65,16 @@ public void Write(PacketBuffer buffer, MinecraftData version) public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - string dimension; + string dimensionType; if (version.Version.Protocol <= ProtocolVersion.V_1_19) { var dimensionNbt = buffer.ReadNbtCompound(); - dimension = dimensionNbt.Get("effects")!.Value; + dimensionType = dimensionNbt.Get("effects")!.Value; } else { - dimension = buffer.ReadString(); + dimensionType = buffer.ReadString(); } var dimensionName = buffer.ReadString(); @@ -105,7 +105,7 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) } return new RespawnPacket( - dimension, + dimensionType, dimensionName, hashedSeed, gameMode, diff --git a/MineSharp.Bot/Plugins/PlayerPlugin.cs b/MineSharp.Bot/Plugins/PlayerPlugin.cs index 1bc72032..59ef130f 100644 --- a/MineSharp.Bot/Plugins/PlayerPlugin.cs +++ b/MineSharp.Bot/Plugins/PlayerPlugin.cs @@ -91,7 +91,7 @@ public PlayerPlugin(MineSharpBot bot) : base(bot) /// /// The Name of the dimension the bot is currently in. /// - public string? Dimension { get; private set; } + public string? DimensionName { get; private set; } /// /// Whether the bot is alive or dead. @@ -177,17 +177,17 @@ protected override async Task Init() 0, (GameMode)loginPacket.GameMode, entity, - ParseDimension(loginPacket.DimensionName)); + ParseDimension(loginPacket.DimensionType)); PlayerMap.TryAdd(entity.ServerId, Self); Health = loginPacket.HasDeathLocation ? 0f : 20.0f; Food = 20.0f; Saturation = 20.0f; - Dimension = loginPacket.DimensionName; + DimensionName = loginPacket.DimensionName; Logger.Info( - $"Initialized Bot Entity: Position=({Entity!.Position}), GameMode={Self.GameMode}, Dimension={Dimension}."); + "Initialized Bot Entity: Position=({Position}), GameMode={GameMode}, Dimension={DimensionName} ({Dimension}).", Entity!.Position, Self.GameMode, DimensionName, Self!.Dimension); if (!loginPacket.HasDeathLocation) { @@ -294,7 +294,7 @@ private Task HandleRespawnPacket(RespawnPacket packet) return Task.CompletedTask; } - Self!.Dimension = ParseDimension(packet.Dimension); + Self!.Dimension = ParseDimension(packet.DimensionType); OnRespawned.Dispatch(Bot); return Task.CompletedTask; @@ -498,10 +498,10 @@ private Dimension ParseDimension(string dimensionName) { return dimensionName switch { - "minecraft:overworld" => Core.Common.Dimension.Overworld, - "minecraft:the_nether" => Core.Common.Dimension.Nether, - "minecraft:the_end" => Core.Common.Dimension.End, - _ => throw new UnreachableException() + "overworld" => Dimension.Overworld, + "the_nether" => Dimension.Nether, + "the_end" => Dimension.End, + _ => throw new UnreachableException($"{nameof(dimensionName)} was: {dimensionName}") }; } } From 441a153c646dfa20ebdbab17abddf73958c4bbeb Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 7 Aug 2024 21:34:51 +0200 Subject: [PATCH 29/73] suppress exception when tcp stream ends --- .../MineSharp.Protocol/MinecraftClient.cs | 33 +++++++------------ MineSharp.Core/Common/PacketBuffer.cs | 10 ++++-- .../Exceptions/MineSharpException.cs | 5 +-- .../Exceptions/SerializationException.cs | 8 +++++ 4 files changed, 30 insertions(+), 26 deletions(-) create mode 100644 MineSharp.Core/Exceptions/SerializationException.cs diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index 74eb690a..e5fb97b7 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -425,32 +425,21 @@ private async Task StreamLoop() { try { - while (!CancellationToken.IsCancellationRequested) - { - try - { - // run both tasks in parallel - var receiveTask = Task.Run(ReceivePackets); - var sendTask = Task.Run(SendPackets); + // run both tasks in parallel + var receiveTask = Task.Run(ReceivePackets); + var sendTask = Task.Run(SendPackets); - // extract the exception from the task that finished first - await await Task.WhenAny(receiveTask, sendTask); - // DisposeInternal in the catch block will then stop the other task - } - catch (Exception ex) - { - if (ex is SocketException or IOException) - { - // we probably can not continue after this - throw; - } - Logger.Error(ex, "Encountered error in stream loop"); - } - } + // extract the exception from the task that finished first + await await Task.WhenAny(receiveTask, sendTask); + // DisposeInternal in the catch block will then stop the other task } catch (Exception e) { - Logger.Error(e, "Encountered exception in outer stream loop. Connection will be terminated."); + // EndOfStreamException is expected when the connection is closed + if (e is not EndOfStreamException) + { + Logger.Error(e, "Encountered exception in outer stream loop. Connection will be terminated."); + } await DisposeInternal(true); } } diff --git a/MineSharp.Core/Common/PacketBuffer.cs b/MineSharp.Core/Common/PacketBuffer.cs index bfe0df7c..ca6f3898 100644 --- a/MineSharp.Core/Common/PacketBuffer.cs +++ b/MineSharp.Core/Common/PacketBuffer.cs @@ -4,6 +4,7 @@ using System.Text.RegularExpressions; using fNbt; using MineSharp.Core.Common.Blocks; +using MineSharp.Core.Exceptions; namespace MineSharp.Core.Common; @@ -238,6 +239,11 @@ public static int ReadVarInt(Stream stream, out int byteCount) while (true) { var b = stream.ReadByte(); + if (b == -1) + { + throw new EndOfStreamException(); + } + byteCount++; value |= (b & VarIntSegmentBits) << shift; if ((b & VarIntContinueBit) == 0x00) @@ -248,7 +254,7 @@ public static int ReadVarInt(Stream stream, out int byteCount) shift += 7; if (shift >= 32) { - throw new("VarInt is too big"); + throw new SerializationException("VarInt is too big."); } } @@ -278,7 +284,7 @@ public long ReadVarLong() shift += 7; if (shift >= 64) { - throw new("VarLong is too big"); + throw new SerializationException("VarLong is too big."); } } diff --git a/MineSharp.Core/Exceptions/MineSharpException.cs b/MineSharp.Core/Exceptions/MineSharpException.cs index fd2cae3c..da5b0e9e 100644 --- a/MineSharp.Core/Exceptions/MineSharpException.cs +++ b/MineSharp.Core/Exceptions/MineSharpException.cs @@ -1,7 +1,8 @@ namespace MineSharp.Core.Exceptions; /// -/// Exception thrown by MineSharp projects +/// Exception thrown by MineSharp projects. /// /// -public abstract class MineSharpException(string message) : Exception(message); +/// +public abstract class MineSharpException(string message, Exception? innerException = null) : Exception(message, innerException); diff --git a/MineSharp.Core/Exceptions/SerializationException.cs b/MineSharp.Core/Exceptions/SerializationException.cs new file mode 100644 index 00000000..8529ca3a --- /dev/null +++ b/MineSharp.Core/Exceptions/SerializationException.cs @@ -0,0 +1,8 @@ +namespace MineSharp.Core.Exceptions; + +/// +/// Thrown when de-/serialization of anything fails. +/// This might be a packet, from the root stream or a common element such as Attribute, Item or NbtTag, or anything else. +/// +/// +public class SerializationException(string message) : MineSharpException(message); From 01bd4fddc72d5649fae2f8f20c668490b79cb484 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 7 Aug 2024 22:42:17 +0200 Subject: [PATCH 30/73] performance optimization experiments (does not really gain much) --- .../MineSharp.Protocol/MinecraftStream.cs | 19 ++++++++++--------- Data/MineSharp.Data/Protocol/ProtocolData.cs | 9 +++++---- .../Protocol/ProtocolDataBlob.cs | 5 +++-- .../Protocol/ProtocolProvider.cs | 16 +++++++++------- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/Components/MineSharp.Protocol/MinecraftStream.cs b/Components/MineSharp.Protocol/MinecraftStream.cs index 7ec877aa..f7099147 100644 --- a/Components/MineSharp.Protocol/MinecraftStream.cs +++ b/Components/MineSharp.Protocol/MinecraftStream.cs @@ -58,9 +58,10 @@ public PacketBuffer ReadPacket() { var localCompressionThreshold = compressionThreshold; + var uncompressedLength = 0; + byte[] data = Array.Empty(); lock (readLock) { - var uncompressedLength = 0; var length = PacketBuffer.ReadVarInt(stream, out _); if (localCompressionThreshold != CompressionDisabled) @@ -69,22 +70,22 @@ public PacketBuffer ReadPacket() length -= r; } - var data = new byte[length]; + data = new byte[length]; var read = 0; while (read < length) { read += stream.Read(data, read, length - read); } + } - var packetBuffer = uncompressedLength switch - { - > 0 => DecompressBuffer(data, uncompressedLength), - _ => new(data, protocolVersion) - }; + var packetBuffer = uncompressedLength switch + { + > 0 => DecompressBuffer(data, uncompressedLength), + _ => new(data, protocolVersion) + }; - return packetBuffer; - } + return packetBuffer; } public void WritePacket(PacketBuffer buffer) diff --git a/Data/MineSharp.Data/Protocol/ProtocolData.cs b/Data/MineSharp.Data/Protocol/ProtocolData.cs index efbadc24..f8c54f29 100644 --- a/Data/MineSharp.Data/Protocol/ProtocolData.cs +++ b/Data/MineSharp.Data/Protocol/ProtocolData.cs @@ -1,4 +1,5 @@ -using MineSharp.Core.Common.Protocol; +using System.Collections.Frozen; +using MineSharp.Core.Common.Protocol; using MineSharp.Data.Framework; using MineSharp.Data.Framework.Providers; using MineSharp.Data.Internal; @@ -8,8 +9,8 @@ namespace MineSharp.Data.Protocol; internal class ProtocolData(IDataProvider provider) : IndexedData(provider), IProtocolData { - private Dictionary>> idToType = new(); - private Dictionary typeToId = new(); + private FrozenDictionary>> idToType = FrozenDictionary>>.Empty; + private FrozenDictionary typeToId = FrozenDictionary.Empty; public int GetPacketId(PacketType type) { @@ -38,6 +39,6 @@ protected override void InitializeData(ProtocolDataBlob data) typeToId = idToType.Values .SelectMany(x => x.Values) .SelectMany(x => x.ToArray()) - .ToDictionary(x => x.Value, x => x.Key); + .ToFrozenDictionary(x => x.Value, x => x.Key); } } diff --git a/Data/MineSharp.Data/Protocol/ProtocolDataBlob.cs b/Data/MineSharp.Data/Protocol/ProtocolDataBlob.cs index 1bd95db3..432e1aa4 100644 --- a/Data/MineSharp.Data/Protocol/ProtocolDataBlob.cs +++ b/Data/MineSharp.Data/Protocol/ProtocolDataBlob.cs @@ -1,6 +1,7 @@ -using MineSharp.Core.Common.Protocol; +using System.Collections.Frozen; +using MineSharp.Core.Common.Protocol; namespace MineSharp.Data.Protocol; internal record ProtocolDataBlob( - Dictionary>> IdToTypeMap); + FrozenDictionary>> IdToTypeMap); diff --git a/Data/MineSharp.Data/Protocol/ProtocolProvider.cs b/Data/MineSharp.Data/Protocol/ProtocolProvider.cs index aaccdfb2..a0f16b90 100644 --- a/Data/MineSharp.Data/Protocol/ProtocolProvider.cs +++ b/Data/MineSharp.Data/Protocol/ProtocolProvider.cs @@ -1,4 +1,5 @@ -using MineSharp.Core.Common.Protocol; +using System.Collections.Frozen; +using MineSharp.Core.Common.Protocol; using MineSharp.Data.Framework.Providers; using MineSharp.Data.Internal; using Newtonsoft.Json.Linq; @@ -24,10 +25,10 @@ public ProtocolProvider(JToken token) public ProtocolDataBlob GetData() { - var byFlow = new Dictionary>> + var byFlow = new Dictionary>> { - { PacketFlow.Clientbound, new Dictionary>() }, - { PacketFlow.Serverbound, new Dictionary>() } + { PacketFlow.Clientbound, new Dictionary>() }, + { PacketFlow.Serverbound, new Dictionary>() } }; foreach (var ns in token.Properties()) @@ -46,15 +47,16 @@ public ProtocolDataBlob GetData() byFlow[PacketFlow.Serverbound].Add(state, sbPackets); } - return new(byFlow); + var frozenDict = byFlow.ToFrozenDictionary(x => x.Key, y => y.Value.ToFrozenDictionary()); + return new(frozenDict); } - private Dictionary CollectPackets(string ns, string direction) + private FrozenDictionary CollectPackets(string ns, string direction) { var obj = (JObject)token.SelectToken($"{ns}.{direction}.types.packet[1][0].type[1].mappings")!; return obj.Properties() - .ToDictionary( + .ToFrozenDictionary( x => Convert.ToInt32(x.Name, 16), x => TypeLookup.FromName( NameUtils.GetPacketName( From f9254c935fdd232ad69a958fed2715b07d4c69bd Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 7 Aug 2024 22:59:04 +0200 Subject: [PATCH 31/73] added back minecraft prefix for constant identifiers --- MineSharp.Bot/Plugins/ChatPlugin.cs | 2 +- MineSharp.Bot/Plugins/PlayerPlugin.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/MineSharp.Bot/Plugins/ChatPlugin.cs b/MineSharp.Bot/Plugins/ChatPlugin.cs index b0466250..f6b850dc 100644 --- a/MineSharp.Bot/Plugins/ChatPlugin.cs +++ b/MineSharp.Bot/Plugins/ChatPlugin.cs @@ -581,7 +581,7 @@ private Task HandleChatInternal(Uuid? sender, ChatComponent.Chat message, ChatMe ChatComponent.Chat? content, ChatComponent.Chat? target) { - var entry = Bot.Registry["chat_type"]["value"][index]; + var entry = Bot.Registry["minecraft:chat_type"]["value"][index]; var name = entry["name"]!.StringValue!; var element = entry["element"]; var styleCompound = element["chat"]["style"]; diff --git a/MineSharp.Bot/Plugins/PlayerPlugin.cs b/MineSharp.Bot/Plugins/PlayerPlugin.cs index 59ef130f..3e95aba0 100644 --- a/MineSharp.Bot/Plugins/PlayerPlugin.cs +++ b/MineSharp.Bot/Plugins/PlayerPlugin.cs @@ -498,9 +498,9 @@ private Dimension ParseDimension(string dimensionName) { return dimensionName switch { - "overworld" => Dimension.Overworld, - "the_nether" => Dimension.Nether, - "the_end" => Dimension.End, + "minecraft:overworld" => Dimension.Overworld, + "minecraft:the_nether" => Dimension.Nether, + "minecraft:the_end" => Dimension.End, _ => throw new UnreachableException($"{nameof(dimensionName)} was: {dimensionName}") }; } From a7624d09a1c84f0fa5e15d3bde74648a98fdda3a Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 7 Aug 2024 23:23:10 +0200 Subject: [PATCH 32/73] created Identifier type and added methods to PacketBuffer --- MineSharp.Core/Common/Identifier.cs | 173 ++++++++++++++++++++++++++ MineSharp.Core/Common/PacketBuffer.cs | 13 ++ 2 files changed, 186 insertions(+) create mode 100644 MineSharp.Core/Common/Identifier.cs diff --git a/MineSharp.Core/Common/Identifier.cs b/MineSharp.Core/Common/Identifier.cs new file mode 100644 index 00000000..deac2206 --- /dev/null +++ b/MineSharp.Core/Common/Identifier.cs @@ -0,0 +1,173 @@ +using System.Diagnostics.CodeAnalysis; +using System.Text.RegularExpressions; + +namespace MineSharp.Core.Common; + +/// +/// Represents an identifier with a namespace and a name. +/// +public sealed partial record Identifier +{ + /// + /// The namespace that is assumed by default when none is specified. + /// + public const string DefaultNamespace = "minecraft"; + /// + /// The namespace that is used when no namespace is specified. + /// + public const string NoNamespace = ""; + + /// + /// The namespace part of the identifier. + /// + public readonly string Namespace; + + /// + /// The name part of the identifier. + /// + public readonly string Name; + + // This constructor is private to prevent creating identifiers with invalid characters + private Identifier(string @namespace, string name) + { + Namespace = @namespace; + Name = name; + } + + // This constructor is private to prevent creating identifiers with invalid characters + private Identifier(string name) + : this(DefaultNamespace, name) + { + } + + /// + /// Gets a value indicating whether the identifier has a namespace. + /// + public bool HasNamespace => Namespace != NoNamespace; + + /// + /// Gets a value indicating whether the identifier has the default namespace. + /// + public bool HasDefaultNamespace => Namespace == DefaultNamespace; + + /// + /// Converts the identifier to a complete identifier with the default namespace if none is specified. + /// + /// A complete identifier with a namespace. + public Identifier ToCompleteIdentifier() + { + return HasNamespace ? this : new Identifier(DefaultNamespace, Name); + } + + /// + /// Returns a string representation of the identifier. + /// + /// A string in the format "namespace:name" or "name" if no namespace is specified. + public override string ToString() + { + return HasNamespace ? $"{Namespace}:{Name}" : Name; + } + + /// + /// Parses a string into an object. + /// + /// The string to parse. + /// An object. + /// Thrown when the string format is invalid. + public static Identifier Parse(string identifierString) + { + if (!TryParse(identifierString, out var identifier)) + { + throw new FormatException("Invalid identifier format"); + } + return identifier; + } + + /// + /// Tries to parse a string into an object. + /// + /// The string to parse. + /// The resulting object if parsing is successful. + /// true if parsing is successful; otherwise, false. + public static bool TryParse(string identifierString, [NotNullWhen(true)] out Identifier? identifier) + { + var colonIndex = identifierString.IndexOf(':'); + if (colonIndex == -1) + { + return TryCreate(NoNamespace, identifierString, out identifier); + } + return TryCreate(identifierString.Substring(0, colonIndex), identifierString.Substring(colonIndex + 1), out identifier); + } + + private static string? TryCreateInternal(string @namespace, string name, out Identifier? identifier) + { + if (!IsValidNamespace(@namespace)) + { + identifier = null; + return "Invalid namespace"; + } + if (!IsValidName(name)) + { + identifier = null; + return "Invalid name"; + } + identifier = new Identifier(@namespace, name); + return null; + } + + /// + /// Tries to create an object with the specified namespace and name. + /// + /// The namespace part of the identifier. + /// The name part of the identifier. + /// The resulting object if creation is successful. + /// true if creation is successful; otherwise, false. + public static bool TryCreate(string @namespace, string name, [NotNullWhen(true)] out Identifier? identifier) + { + var parseError = TryCreateInternal(@namespace, name, out identifier); + return parseError == null; + } + + /// + /// Creates an object with the specified namespace and name. + /// + /// The namespace part of the identifier. + /// The name part of the identifier. + /// An object. + /// Thrown when the namespace or name is invalid. + public static Identifier Create(string @namespace, string name) + { + var parseError = TryCreateInternal(@namespace, name, out var identifier); + if (parseError != null) + { + throw new FormatException(parseError); + } + return identifier!; + } + + [GeneratedRegex("[a-z0-9.-_]*")] + private static partial Regex NamespaceRegex(); + + /// + /// Determines whether the specified namespace is valid. + /// + /// The namespace to validate. + /// true if the namespace is valid; otherwise, false. + public static bool IsValidNamespace(string @namespace) + { + return NamespaceRegex().IsMatch(@namespace); + } + + [GeneratedRegex("[a-z0-9.-_/]+")] + private static partial Regex NameRegex(); + + /// + /// Determines whether the specified name is valid. + /// + /// The name to validate. + /// true if the name is valid; otherwise, false. + public static bool IsValidName(string name) + { + return NameRegex().IsMatch(name); + } +} diff --git a/MineSharp.Core/Common/PacketBuffer.cs b/MineSharp.Core/Common/PacketBuffer.cs index ca6f3898..b4e736f0 100644 --- a/MineSharp.Core/Common/PacketBuffer.cs +++ b/MineSharp.Core/Common/PacketBuffer.cs @@ -302,6 +302,13 @@ public string ReadString(Encoding? encoding = null) return encoding.GetString(bytes); } + public Identifier ReadIdentifier() + { + var str = ReadString(); + // if the string is not a valid identifier, it will throw an exception + return Identifier.Parse(str); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Uuid ReadUuid() { @@ -558,6 +565,12 @@ public void WriteString(string value, Encoding? encoding = null) WriteBytes(bytes); } + public void WriteIdentifier(Identifier identifier) + { + var str = identifier.ToString(); + WriteString(str); + } + public void WriteUuid(Uuid value) { Write(value.MostSignificantBits); From ff352e7c7a41f91ac69be3ae96a02069d7f3f6e2 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 00:24:52 +0200 Subject: [PATCH 33/73] using the new Identifier type everywhere --- Components/MineSharp.Commands/CommandTree.cs | 4 +- .../Parser/BlockPositionParser.cs | 6 +- .../Parser/ColumnPosParser.cs | 6 +- .../MineSharp.Commands/Parser/DoubleParser.cs | 6 +- .../MineSharp.Commands/Parser/EmptyParser.cs | 4 +- .../MineSharp.Commands/Parser/EntityParser.cs | 6 +- .../MineSharp.Commands/Parser/FloatParser.cs | 6 +- .../MineSharp.Commands/Parser/IParser.cs | 2 +- .../Parser/IntegerParser.cs | 6 +- .../MineSharp.Commands/Parser/LongParser.cs | 6 +- .../Parser/MessageParser.cs | 6 +- .../Parser/ParserRegistry.cs | 405 +++++++++--------- .../MineSharp.Commands/Parser/RangeParser.cs | 6 +- .../Parser/ResourceOrTagParser.cs | 6 +- .../Parser/ResourceParser.cs | 7 +- .../Parser/RotationParser.cs | 6 +- .../Parser/ScoreHolderParser.cs | 6 +- .../MineSharp.Commands/Parser/StringParser.cs | 6 +- .../MineSharp.Commands/Parser/TimeParser.cs | 6 +- .../MineSharp.Commands/Parser/Vec2Parser.cs | 6 +- .../MineSharp.Commands/Parser/Vec3Parser.cs | 6 +- Components/MineSharp.Physics/PhysicsConst.cs | 5 +- .../Configuration/FeatureFlagsPacket.cs | 6 +- .../Configuration/PluginMessagePacket.cs | 6 +- .../Clientbound/Login/DisconnectPacket.cs | 15 +- .../Login/LoginPluginRequestPacket.cs | 6 +- .../Play/EntitySoundEffectPacket.cs | 8 +- .../Packets/Clientbound/Play/LoginPacket.cs | 46 +- .../Packets/Clientbound/Play/RespawnPacket.cs | 24 +- .../Clientbound/Play/SoundEffectPacket.cs | 8 +- .../Configuration/PluginMessagePacket.cs | 6 +- .../Framework/DataInterfaces.cs | 5 +- Data/MineSharp.Data/Windows/WindowData.cs | 7 +- Data/MineSharp.Data/Windows/WindowInfo.cs | 27 +- MineSharp.Bot/Plugins/ChatPlugin.cs | 11 +- MineSharp.Bot/Plugins/PlayerPlugin.cs | 21 +- .../Common/Entities/Attributes/Attribute.cs | 8 +- MineSharp.Core/Common/Entities/Entity.cs | 4 +- MineSharp.Core/Common/Identifier.cs | 33 ++ 39 files changed, 437 insertions(+), 327 deletions(-) diff --git a/Components/MineSharp.Commands/CommandTree.cs b/Components/MineSharp.Commands/CommandTree.cs index 844cbe92..f5c11de4 100644 --- a/Components/MineSharp.Commands/CommandTree.cs +++ b/Components/MineSharp.Commands/CommandTree.cs @@ -74,12 +74,12 @@ private static CommandNode ReadNode(PacketBuffer buffer, MinecraftData data) return null; } - string name; + Identifier name; if (data.Version.Protocol < ProtocolVersion.V_1_19) { // in 1.18.x, the parser was specified by its name. - name = buffer.ReadString(); + name = buffer.ReadIdentifier(); } else { diff --git a/Components/MineSharp.Commands/Parser/BlockPositionParser.cs b/Components/MineSharp.Commands/Parser/BlockPositionParser.cs index e93cd789..07380335 100644 --- a/Components/MineSharp.Commands/Parser/BlockPositionParser.cs +++ b/Components/MineSharp.Commands/Parser/BlockPositionParser.cs @@ -5,9 +5,11 @@ namespace MineSharp.Commands.Parser; public class BlockPositionParser : IParser { - public string GetName() + public static readonly Identifier BlockPosIdentifier = Identifier.Parse("minecraft:block_pos"); + + public Identifier GetName() { - return "minecraft:block_pos"; + return BlockPosIdentifier; } public int GetArgumentCount() diff --git a/Components/MineSharp.Commands/Parser/ColumnPosParser.cs b/Components/MineSharp.Commands/Parser/ColumnPosParser.cs index 38e2b1a1..8e413e16 100644 --- a/Components/MineSharp.Commands/Parser/ColumnPosParser.cs +++ b/Components/MineSharp.Commands/Parser/ColumnPosParser.cs @@ -5,9 +5,11 @@ namespace MineSharp.Commands.Parser; public class ColumnPosParser : IParser { - public string GetName() + public static readonly Identifier ColumnPosIdentifier = Identifier.Parse("minecraft:column_pos"); + + public Identifier GetName() { - return "minecraft:column_pos"; + return ColumnPosIdentifier; } public int GetArgumentCount() diff --git a/Components/MineSharp.Commands/Parser/DoubleParser.cs b/Components/MineSharp.Commands/Parser/DoubleParser.cs index dbd221a5..bbaa213b 100644 --- a/Components/MineSharp.Commands/Parser/DoubleParser.cs +++ b/Components/MineSharp.Commands/Parser/DoubleParser.cs @@ -5,12 +5,14 @@ namespace MineSharp.Commands.Parser; public class DoubleParser : IParser { + public static readonly Identifier BrigadierDoubleIdentifier = Identifier.Parse("brigadier:double"); + public double Min { get; private set; } public double Max { get; private set; } - public string GetName() + public Identifier GetName() { - return "brigadier:double"; + return BrigadierDoubleIdentifier; } public int GetArgumentCount() diff --git a/Components/MineSharp.Commands/Parser/EmptyParser.cs b/Components/MineSharp.Commands/Parser/EmptyParser.cs index 958e6fcb..726705cf 100644 --- a/Components/MineSharp.Commands/Parser/EmptyParser.cs +++ b/Components/MineSharp.Commands/Parser/EmptyParser.cs @@ -5,9 +5,9 @@ namespace MineSharp.Commands.Parser; public class EmptyParser : IParser { - public string GetName() + public Identifier GetName() { - return string.Empty; + return Identifier.Empty; } public int GetArgumentCount() diff --git a/Components/MineSharp.Commands/Parser/EntityParser.cs b/Components/MineSharp.Commands/Parser/EntityParser.cs index 27447449..03115f5f 100644 --- a/Components/MineSharp.Commands/Parser/EntityParser.cs +++ b/Components/MineSharp.Commands/Parser/EntityParser.cs @@ -5,11 +5,13 @@ namespace MineSharp.Commands.Parser; public class EntityParser : IParser { + public static readonly Identifier EntityIdentifier = Identifier.Parse("minecraft:entity"); + public byte Flags { get; private set; } - public string GetName() + public Identifier GetName() { - return "minecraft:entity"; + return EntityIdentifier; } public int GetArgumentCount() diff --git a/Components/MineSharp.Commands/Parser/FloatParser.cs b/Components/MineSharp.Commands/Parser/FloatParser.cs index 6d1dae21..705a5f3f 100644 --- a/Components/MineSharp.Commands/Parser/FloatParser.cs +++ b/Components/MineSharp.Commands/Parser/FloatParser.cs @@ -5,12 +5,14 @@ namespace MineSharp.Commands.Parser; public class FloatParser : IParser { + public static readonly Identifier BrigadierFloatIdentifier = Identifier.Parse("brigadier:float"); + public float Min { get; private set; } public float Max { get; private set; } - public string GetName() + public Identifier GetName() { - return "brigadier:float"; + return BrigadierFloatIdentifier; } public int GetArgumentCount() diff --git a/Components/MineSharp.Commands/Parser/IParser.cs b/Components/MineSharp.Commands/Parser/IParser.cs index fb71df25..38feb3e0 100644 --- a/Components/MineSharp.Commands/Parser/IParser.cs +++ b/Components/MineSharp.Commands/Parser/IParser.cs @@ -5,7 +5,7 @@ namespace MineSharp.Commands.Parser; public interface IParser { - public string GetName(); + public Identifier GetName(); public int GetArgumentCount(); public void ReadProperties(PacketBuffer buffer, MinecraftData data); diff --git a/Components/MineSharp.Commands/Parser/IntegerParser.cs b/Components/MineSharp.Commands/Parser/IntegerParser.cs index 5524ddad..543e4083 100644 --- a/Components/MineSharp.Commands/Parser/IntegerParser.cs +++ b/Components/MineSharp.Commands/Parser/IntegerParser.cs @@ -5,12 +5,14 @@ namespace MineSharp.Commands.Parser; public class IntegerParser : IParser { + public static readonly Identifier BrigadierIntegerIdentifier = Identifier.Parse("brigadier:integer"); + public int Min { get; private set; } public int Max { get; private set; } - public string GetName() + public Identifier GetName() { - return "brigadier:integer"; + return BrigadierIntegerIdentifier; } public int GetArgumentCount() diff --git a/Components/MineSharp.Commands/Parser/LongParser.cs b/Components/MineSharp.Commands/Parser/LongParser.cs index 77cdcf8b..fa9b5c61 100644 --- a/Components/MineSharp.Commands/Parser/LongParser.cs +++ b/Components/MineSharp.Commands/Parser/LongParser.cs @@ -5,12 +5,14 @@ namespace MineSharp.Commands.Parser; public class LongParser : IParser { + public static readonly Identifier BrigadierLongIdentifier = Identifier.Parse("brigadier:long"); + public long Min { get; private set; } public long Max { get; private set; } - public string GetName() + public Identifier GetName() { - return "brigadier:long"; + return BrigadierLongIdentifier; } public int GetArgumentCount() diff --git a/Components/MineSharp.Commands/Parser/MessageParser.cs b/Components/MineSharp.Commands/Parser/MessageParser.cs index fce41a89..5be94c7d 100644 --- a/Components/MineSharp.Commands/Parser/MessageParser.cs +++ b/Components/MineSharp.Commands/Parser/MessageParser.cs @@ -5,9 +5,11 @@ namespace MineSharp.Commands.Parser; public class MessageParser : IParser { - public string GetName() + public static readonly Identifier MessageIdentifier = Identifier.Parse("minecraft:message"); + + public Identifier GetName() { - return "minecraft:message"; + return MessageIdentifier; } public int GetArgumentCount() diff --git a/Components/MineSharp.Commands/Parser/ParserRegistry.cs b/Components/MineSharp.Commands/Parser/ParserRegistry.cs index ec14f9e5..eb5c9b5a 100644 --- a/Components/MineSharp.Commands/Parser/ParserRegistry.cs +++ b/Components/MineSharp.Commands/Parser/ParserRegistry.cs @@ -1,222 +1,223 @@ using MineSharp.Core; +using MineSharp.Core.Common; using MineSharp.Data; namespace MineSharp.Commands.Parser; internal static class ParserRegistry { - private static readonly IDictionary Mapping119 = new Dictionary + private static readonly Dictionary Mapping119 = new() { - { 0, "brigadier:bool" }, - { 1, "brigadier:float" }, - { 2, "brigadier:double" }, - { 3, "brigadier:integer" }, - { 4, "brigadier:long" }, - { 5, "brigadier:string" }, - { 6, "minecraft:entity" }, - { 7, "minecraft:game_profile" }, - { 8, "minecraft:block_pos" }, - { 9, "minecraft:column_pos" }, - { 10, "minecraft:vec3" }, - { 11, "minecraft:vec2" }, - { 12, "minecraft:block_state" }, - { 13, "minecraft:block_predicate" }, - { 14, "minecraft:item_stack" }, - { 15, "minecraft:item_predicate" }, - { 16, "minecraft:color" }, - { 17, "minecraft:component" }, - { 18, "minecraft:message" }, - { 19, "minecraft:nbt" }, - { 20, "minecraft:nbt_tag" }, - { 21, "minecraft:nbt_path" }, - { 22, "minecraft:objective" }, - { 23, "minecraft:objective_criteria" }, - { 24, "minecraft:operation" }, - { 25, "minecraft:particle" }, - { 26, "minecraft:angle" }, - { 27, "minecraft:rotation" }, - { 28, "minecraft:scoreboard_slot" }, - { 29, "minecraft:score_holder" }, - { 30, "minecraft:swizzle" }, - { 31, "minecraft:team" }, - { 32, "minecraft:item_slot" }, - { 33, "minecraft:resource_location" }, - { 34, "minecraft:mob_effect" }, - { 35, "minecraft:function" }, - { 36, "minecraft:entity_anchor" }, - { 37, "minecraft:int_range" }, - { 38, "minecraft:float_range" }, - { 39, "minecraft:item_enchantment" }, - { 40, "minecraft:entity_summon" }, - { 41, "minecraft:dimension" }, - { 42, "minecraft:time" }, - { 43, "minecraft:resource_or_tag" }, - { 44, "minecraft:resource" }, - { 45, "minecraft:template_mirror" }, - { 46, "minecraft:template_rotation" }, - { 47, "minecraft:uuid" } + { 0, Identifier.Parse("brigadier:bool") }, + { 1, Identifier.Parse("brigadier:float") }, + { 2, Identifier.Parse("brigadier:double") }, + { 3, Identifier.Parse("brigadier:integer") }, + { 4, Identifier.Parse("brigadier:long") }, + { 5, Identifier.Parse("brigadier:string") }, + { 6, Identifier.Parse("minecraft:entity") }, + { 7, Identifier.Parse("minecraft:game_profile") }, + { 8, Identifier.Parse("minecraft:block_pos") }, + { 9, Identifier.Parse("minecraft:column_pos") }, + { 10, Identifier.Parse("minecraft:vec3") }, + { 11, Identifier.Parse("minecraft:vec2") }, + { 12, Identifier.Parse("minecraft:block_state") }, + { 13, Identifier.Parse("minecraft:block_predicate") }, + { 14, Identifier.Parse("minecraft:item_stack") }, + { 15, Identifier.Parse("minecraft:item_predicate") }, + { 16, Identifier.Parse("minecraft:color") }, + { 17, Identifier.Parse("minecraft:component") }, + { 18, Identifier.Parse("minecraft:message") }, + { 19, Identifier.Parse("minecraft:nbt") }, + { 20, Identifier.Parse("minecraft:nbt_tag") }, + { 21, Identifier.Parse("minecraft:nbt_path") }, + { 22, Identifier.Parse("minecraft:objective") }, + { 23, Identifier.Parse("minecraft:objective_criteria") }, + { 24, Identifier.Parse("minecraft:operation") }, + { 25, Identifier.Parse("minecraft:particle") }, + { 26, Identifier.Parse("minecraft:angle") }, + { 27, Identifier.Parse("minecraft:rotation") }, + { 28, Identifier.Parse("minecraft:scoreboard_slot") }, + { 29, Identifier.Parse("minecraft:score_holder") }, + { 30, Identifier.Parse("minecraft:swizzle") }, + { 31, Identifier.Parse("minecraft:team") }, + { 32, Identifier.Parse("minecraft:item_slot") }, + { 33, Identifier.Parse("minecraft:resource_location") }, + { 34, Identifier.Parse("minecraft:mob_effect") }, + { 35, Identifier.Parse("minecraft:function") }, + { 36, Identifier.Parse("minecraft:entity_anchor") }, + { 37, Identifier.Parse("minecraft:int_range") }, + { 38, Identifier.Parse("minecraft:float_range") }, + { 39, Identifier.Parse("minecraft:item_enchantment") }, + { 40, Identifier.Parse("minecraft:entity_summon") }, + { 41, Identifier.Parse("minecraft:dimension") }, + { 42, Identifier.Parse("minecraft:time") }, + { 43, Identifier.Parse("minecraft:resource_or_tag") }, + { 44, Identifier.Parse("minecraft:resource") }, + { 45, Identifier.Parse("minecraft:template_mirror") }, + { 46, Identifier.Parse("minecraft:template_rotation") }, + { 47, Identifier.Parse("minecraft:uuid") } }; - private static readonly IDictionary Mapping1193 = new Dictionary + private static readonly Dictionary Mapping1193 = new() { - { 0, "brigadier:bool" }, - { 1, "brigadier:float" }, - { 2, "brigadier:double" }, - { 3, "brigadier:integer" }, - { 4, "brigadier:long" }, - { 5, "brigadier:string" }, - { 6, "minecraft:entity" }, - { 7, "minecraft:game_profile" }, - { 8, "minecraft:block_pos" }, - { 9, "minecraft:column_pos" }, - { 10, "minecraft:vec3" }, - { 11, "minecraft:vec2" }, - { 12, "minecraft:block_state" }, - { 13, "minecraft:block_predicate" }, - { 14, "minecraft:item_stack" }, - { 15, "minecraft:item_predicate" }, - { 16, "minecraft:color" }, - { 17, "minecraft:component" }, - { 18, "minecraft:message" }, - { 19, "minecraft:nbt" }, - { 20, "minecraft:nbt_tag" }, - { 21, "minecraft:nbt_path" }, - { 22, "minecraft:objective" }, - { 23, "minecraft:objective_criteria" }, - { 24, "minecraft:operation" }, - { 25, "minecraft:particle" }, - { 26, "minecraft:angle" }, - { 27, "minecraft:rotation" }, - { 28, "minecraft:scoreboard_slot" }, - { 29, "minecraft:score_holder" }, - { 30, "minecraft:swizzle" }, - { 31, "minecraft:team" }, - { 32, "minecraft:item_slot" }, - { 33, "minecraft:resource_location" }, - { 34, "minecraft:function" }, - { 35, "minecraft:entity_anchor" }, - { 36, "minecraft:int_range" }, - { 37, "minecraft:float_range" }, - { 38, "minecraft:dimension" }, - { 39, "minecraft:gamemode" }, - { 40, "minecraft:time" }, - { 41, "minecraft:resource_or_tag" }, - { 42, "minecraft:resource_or_tag_key" }, - { 43, "minecraft:resource" }, - { 44, "minecraft:resource_key" }, - { 45, "minecraft:template_mirror" }, - { 46, "minecraft:template_rotation" }, - { 47, "minecraft:uuid" } + { 0, Identifier.Parse("brigadier:bool") }, + { 1, Identifier.Parse("brigadier:float") }, + { 2, Identifier.Parse("brigadier:double") }, + { 3, Identifier.Parse("brigadier:integer") }, + { 4, Identifier.Parse("brigadier:long") }, + { 5, Identifier.Parse("brigadier:string") }, + { 6, Identifier.Parse("minecraft:entity") }, + { 7, Identifier.Parse("minecraft:game_profile") }, + { 8, Identifier.Parse("minecraft:block_pos") }, + { 9, Identifier.Parse("minecraft:column_pos") }, + { 10, Identifier.Parse("minecraft:vec3") }, + { 11, Identifier.Parse("minecraft:vec2") }, + { 12, Identifier.Parse("minecraft:block_state") }, + { 13, Identifier.Parse("minecraft:block_predicate") }, + { 14, Identifier.Parse("minecraft:item_stack") }, + { 15, Identifier.Parse("minecraft:item_predicate") }, + { 16, Identifier.Parse("minecraft:color") }, + { 17, Identifier.Parse("minecraft:component") }, + { 18, Identifier.Parse("minecraft:message") }, + { 19, Identifier.Parse("minecraft:nbt") }, + { 20, Identifier.Parse("minecraft:nbt_tag") }, + { 21, Identifier.Parse("minecraft:nbt_path") }, + { 22, Identifier.Parse("minecraft:objective") }, + { 23, Identifier.Parse("minecraft:objective_criteria") }, + { 24, Identifier.Parse("minecraft:operation") }, + { 25, Identifier.Parse("minecraft:particle") }, + { 26, Identifier.Parse("minecraft:angle") }, + { 27, Identifier.Parse("minecraft:rotation") }, + { 28, Identifier.Parse("minecraft:scoreboard_slot") }, + { 29, Identifier.Parse("minecraft:score_holder") }, + { 30, Identifier.Parse("minecraft:swizzle") }, + { 31, Identifier.Parse("minecraft:team") }, + { 32, Identifier.Parse("minecraft:item_slot") }, + { 33, Identifier.Parse("minecraft:resource_location") }, + { 34, Identifier.Parse("minecraft:function") }, + { 35, Identifier.Parse("minecraft:entity_anchor") }, + { 36, Identifier.Parse("minecraft:int_range") }, + { 37, Identifier.Parse("minecraft:float_range") }, + { 38, Identifier.Parse("minecraft:dimension") }, + { 39, Identifier.Parse("minecraft:gamemode") }, + { 40, Identifier.Parse("minecraft:time") }, + { 41, Identifier.Parse("minecraft:resource_or_tag") }, + { 42, Identifier.Parse("minecraft:resource_or_tag_key") }, + { 43, Identifier.Parse("minecraft:resource") }, + { 44, Identifier.Parse("minecraft:resource_key") }, + { 45, Identifier.Parse("minecraft:template_mirror") }, + { 46, Identifier.Parse("minecraft:template_rotation") }, + { 47, Identifier.Parse("minecraft:uuid") } }; - private static readonly IDictionary Mapping1194 = new Dictionary + private static readonly Dictionary Mapping1194 = new() { - { 0, "brigadier:bool" }, - { 1, "brigadier:float" }, - { 2, "brigadier:double" }, - { 3, "brigadier:integer" }, - { 4, "brigadier:long" }, - { 5, "brigadier:string" }, - { 6, "minecraft:entity" }, - { 7, "minecraft:game_profile" }, - { 8, "minecraft:block_pos" }, - { 9, "minecraft:column_pos" }, - { 10, "minecraft:vec3" }, - { 11, "minecraft:vec2" }, - { 12, "minecraft:block_state" }, - { 13, "minecraft:block_predicate" }, - { 14, "minecraft:item_stack" }, - { 15, "minecraft:item_predicate" }, - { 16, "minecraft:color" }, - { 17, "minecraft:component" }, - { 18, "minecraft:message" }, - { 19, "minecraft:nbt" }, - { 20, "minecraft:nbt_tag" }, - { 21, "minecraft:nbt_path" }, - { 22, "minecraft:objective" }, - { 23, "minecraft:objective_criteria" }, - { 24, "minecraft:operation" }, - { 25, "minecraft:particle" }, - { 26, "minecraft:angle" }, - { 27, "minecraft:rotation" }, - { 28, "minecraft:scoreboard_slot" }, - { 29, "minecraft:score_holder" }, - { 30, "minecraft:swizzle" }, - { 31, "minecraft:team" }, - { 32, "minecraft:item_slot" }, - { 33, "minecraft:resource_location" }, - { 34, "minecraft:function" }, - { 35, "minecraft:entity_anchor" }, - { 36, "minecraft:int_range" }, - { 37, "minecraft:float_range" }, - { 38, "minecraft:dimension" }, - { 39, "minecraft:gamemode" }, - { 40, "minecraft:time" }, - { 41, "minecraft:resource_or_tag" }, - { 42, "minecraft:resource_or_tag_key" }, - { 43, "minecraft:resource" }, - { 44, "minecraft:resource_key" }, - { 45, "minecraft:template_mirror" }, - { 46, "minecraft:template_rotation" }, - { 47, "minecraft:heightmap" }, - { 48, "minecraft:uuid" } + { 0, Identifier.Parse("brigadier:bool") }, + { 1, Identifier.Parse("brigadier:float") }, + { 2, Identifier.Parse("brigadier:double") }, + { 3, Identifier.Parse("brigadier:integer") }, + { 4, Identifier.Parse("brigadier:long") }, + { 5, Identifier.Parse("brigadier:string") }, + { 6, Identifier.Parse("minecraft:entity") }, + { 7, Identifier.Parse("minecraft:game_profile") }, + { 8, Identifier.Parse("minecraft:block_pos") }, + { 9, Identifier.Parse("minecraft:column_pos") }, + { 10, Identifier.Parse("minecraft:vec3") }, + { 11, Identifier.Parse("minecraft:vec2") }, + { 12, Identifier.Parse("minecraft:block_state") }, + { 13, Identifier.Parse("minecraft:block_predicate") }, + { 14, Identifier.Parse("minecraft:item_stack") }, + { 15, Identifier.Parse("minecraft:item_predicate") }, + { 16, Identifier.Parse("minecraft:color") }, + { 17, Identifier.Parse("minecraft:component") }, + { 18, Identifier.Parse("minecraft:message") }, + { 19, Identifier.Parse("minecraft:nbt") }, + { 20, Identifier.Parse("minecraft:nbt_tag") }, + { 21, Identifier.Parse("minecraft:nbt_path") }, + { 22, Identifier.Parse("minecraft:objective") }, + { 23, Identifier.Parse("minecraft:objective_criteria") }, + { 24, Identifier.Parse("minecraft:operation") }, + { 25, Identifier.Parse("minecraft:particle") }, + { 26, Identifier.Parse("minecraft:angle") }, + { 27, Identifier.Parse("minecraft:rotation") }, + { 28, Identifier.Parse("minecraft:scoreboard_slot") }, + { 29, Identifier.Parse("minecraft:score_holder") }, + { 30, Identifier.Parse("minecraft:swizzle") }, + { 31, Identifier.Parse("minecraft:team") }, + { 32, Identifier.Parse("minecraft:item_slot") }, + { 33, Identifier.Parse("minecraft:resource_location") }, + { 34, Identifier.Parse("minecraft:function") }, + { 35, Identifier.Parse("minecraft:entity_anchor") }, + { 36, Identifier.Parse("minecraft:int_range") }, + { 37, Identifier.Parse("minecraft:float_range") }, + { 38, Identifier.Parse("minecraft:dimension") }, + { 39, Identifier.Parse("minecraft:gamemode") }, + { 40, Identifier.Parse("minecraft:time") }, + { 41, Identifier.Parse("minecraft:resource_or_tag") }, + { 42, Identifier.Parse("minecraft:resource_or_tag_key") }, + { 43, Identifier.Parse("minecraft:resource") }, + { 44, Identifier.Parse("minecraft:resource_key") }, + { 45, Identifier.Parse("minecraft:template_mirror") }, + { 46, Identifier.Parse("minecraft:template_rotation") }, + { 47, Identifier.Parse("minecraft:heightmap") }, + { 48, Identifier.Parse("minecraft:uuid") } }; - private static readonly IDictionary Mapping1203 = new Dictionary + private static readonly Dictionary Mapping1203 = new() { - { 0, "brigadier:bool" }, - { 1, "brigadier:float" }, - { 2, "brigadier:double" }, - { 3, "brigadier:integer" }, - { 4, "brigadier:long" }, - { 5, "brigadier:string" }, - { 6, "minecraft:entity" }, - { 7, "minecraft:game_profile" }, - { 8, "minecraft:block_pos" }, - { 9, "minecraft:column_pos" }, - { 10, "minecraft:vec3" }, - { 11, "minecraft:vec2" }, - { 12, "minecraft:block_state" }, - { 13, "minecraft:block_predicate" }, - { 14, "minecraft:item_stack" }, - { 15, "minecraft:item_predicate" }, - { 16, "minecraft:color" }, - { 17, "minecraft:component" }, - { 18, "minecraft:style" }, - { 19, "minecraft:message" }, - { 20, "minecraft:nbt" }, - { 21, "minecraft:nbt_tag" }, - { 22, "minecraft:nbt_path" }, - { 23, "minecraft:objective" }, - { 24, "minecraft:objective_criteria" }, - { 25, "minecraft:operation" }, - { 26, "minecraft:particle" }, - { 27, "minecraft:angle" }, - { 28, "minecraft:rotation" }, - { 29, "minecraft:scoreboard_slot" }, - { 30, "minecraft:score_holder" }, - { 31, "minecraft:swizzle" }, - { 32, "minecraft:team" }, - { 33, "minecraft:item_slot" }, - { 34, "minecraft:resource_location" }, - { 35, "minecraft:function" }, - { 36, "minecraft:entity_anchor" }, - { 37, "minecraft:int_range" }, - { 38, "minecraft:float_range" }, - { 39, "minecraft:dimension" }, - { 40, "minecraft:gamemode" }, - { 41, "minecraft:time" }, - { 42, "minecraft:resource_or_tag" }, - { 43, "minecraft:resource_or_tag_key" }, - { 44, "minecraft:resource" }, - { 45, "minecraft:resource_key" }, - { 46, "minecraft:template_mirror" }, - { 47, "minecraft:template_rotation" }, - { 48, "minecraft:heightmap" }, - { 49, "minecraft:uuid" } + { 0, Identifier.Parse("brigadier:bool") }, + { 1, Identifier.Parse("brigadier:float") }, + { 2, Identifier.Parse("brigadier:double") }, + { 3, Identifier.Parse("brigadier:integer") }, + { 4, Identifier.Parse("brigadier:long") }, + { 5, Identifier.Parse("brigadier:string") }, + { 6, Identifier.Parse("minecraft:entity") }, + { 7, Identifier.Parse("minecraft:game_profile") }, + { 8, Identifier.Parse("minecraft:block_pos") }, + { 9, Identifier.Parse("minecraft:column_pos") }, + { 10, Identifier.Parse("minecraft:vec3") }, + { 11, Identifier.Parse("minecraft:vec2") }, + { 12, Identifier.Parse("minecraft:block_state") }, + { 13, Identifier.Parse("minecraft:block_predicate") }, + { 14, Identifier.Parse("minecraft:item_stack") }, + { 15, Identifier.Parse("minecraft:item_predicate") }, + { 16, Identifier.Parse("minecraft:color") }, + { 17, Identifier.Parse("minecraft:component") }, + { 18, Identifier.Parse("minecraft:style") }, + { 19, Identifier.Parse("minecraft:message") }, + { 20, Identifier.Parse("minecraft:nbt") }, + { 21, Identifier.Parse("minecraft:nbt_tag") }, + { 22, Identifier.Parse("minecraft:nbt_path") }, + { 23, Identifier.Parse("minecraft:objective") }, + { 24, Identifier.Parse("minecraft:objective_criteria") }, + { 25, Identifier.Parse("minecraft:operation") }, + { 26, Identifier.Parse("minecraft:particle") }, + { 27, Identifier.Parse("minecraft:angle") }, + { 28, Identifier.Parse("minecraft:rotation") }, + { 29, Identifier.Parse("minecraft:scoreboard_slot") }, + { 30, Identifier.Parse("minecraft:score_holder") }, + { 31, Identifier.Parse("minecraft:swizzle") }, + { 32, Identifier.Parse("minecraft:team") }, + { 33, Identifier.Parse("minecraft:item_slot") }, + { 34, Identifier.Parse("minecraft:resource_location") }, + { 35, Identifier.Parse("minecraft:function") }, + { 36, Identifier.Parse("minecraft:entity_anchor") }, + { 37, Identifier.Parse("minecraft:int_range") }, + { 38, Identifier.Parse("minecraft:float_range") }, + { 39, Identifier.Parse("minecraft:dimension") }, + { 40, Identifier.Parse("minecraft:gamemode") }, + { 41, Identifier.Parse("minecraft:time") }, + { 42, Identifier.Parse("minecraft:resource_or_tag") }, + { 43, Identifier.Parse("minecraft:resource_or_tag_key") }, + { 44, Identifier.Parse("minecraft:resource") }, + { 45, Identifier.Parse("minecraft:resource_key") }, + { 46, Identifier.Parse("minecraft:template_mirror") }, + { 47, Identifier.Parse("minecraft:template_rotation") }, + { 48, Identifier.Parse("minecraft:heightmap") }, + { 49, Identifier.Parse("minecraft:uuid") } }; - public static string GetParserNameById(int parserId, MinecraftData data) + public static Identifier GetParserNameById(int parserId, MinecraftData data) { var mapping = data.Version.Protocol switch { @@ -231,9 +232,9 @@ public static string GetParserNameById(int parserId, MinecraftData data) return mapping[parserId]; } - public static IParser GetParserByName(string name) + public static IParser GetParserByName(Identifier name) { - return name switch + return name.ToString() switch { "brigadier:bool" => new EmptyParser(), "brigadier:float" => new FloatParser(), diff --git a/Components/MineSharp.Commands/Parser/RangeParser.cs b/Components/MineSharp.Commands/Parser/RangeParser.cs index 7afeb1ed..85fe1a08 100644 --- a/Components/MineSharp.Commands/Parser/RangeParser.cs +++ b/Components/MineSharp.Commands/Parser/RangeParser.cs @@ -5,11 +5,13 @@ namespace MineSharp.Commands.Parser; public class RangeParser : IParser { + public static readonly Identifier RangeIdentifier = Identifier.Parse("minecraft:range"); + public bool Decimals { get; private set; } - public string GetName() + public Identifier GetName() { - return "minecraft:range"; + return RangeIdentifier; } public int GetArgumentCount() diff --git a/Components/MineSharp.Commands/Parser/ResourceOrTagParser.cs b/Components/MineSharp.Commands/Parser/ResourceOrTagParser.cs index ffbed038..b5f88e97 100644 --- a/Components/MineSharp.Commands/Parser/ResourceOrTagParser.cs +++ b/Components/MineSharp.Commands/Parser/ResourceOrTagParser.cs @@ -5,11 +5,13 @@ namespace MineSharp.Commands.Parser; public class ResourceOrTagParser : IParser { + public static readonly Identifier ResourceOrTagIdentifier = Identifier.Parse("minecraft:resource_or_tag"); + public string Registry { get; private set; } = string.Empty; - public string GetName() + public Identifier GetName() { - return "minecraft:resource_or_tag"; + return ResourceOrTagIdentifier; } public int GetArgumentCount() diff --git a/Components/MineSharp.Commands/Parser/ResourceParser.cs b/Components/MineSharp.Commands/Parser/ResourceParser.cs index a57ce7a2..80bfc88c 100644 --- a/Components/MineSharp.Commands/Parser/ResourceParser.cs +++ b/Components/MineSharp.Commands/Parser/ResourceParser.cs @@ -5,12 +5,13 @@ namespace MineSharp.Commands.Parser; public class ResourceParser : IParser { - public string? Registry { get; private set; } + public static readonly Identifier ResourceIdentifier = Identifier.Parse("minecraft:resource"); + public string? Registry { get; private set; } - public string GetName() + public Identifier GetName() { - return "minecraft:resource"; + return ResourceIdentifier; } public int GetArgumentCount() diff --git a/Components/MineSharp.Commands/Parser/RotationParser.cs b/Components/MineSharp.Commands/Parser/RotationParser.cs index 52495a08..a33837fd 100644 --- a/Components/MineSharp.Commands/Parser/RotationParser.cs +++ b/Components/MineSharp.Commands/Parser/RotationParser.cs @@ -5,9 +5,11 @@ namespace MineSharp.Commands.Parser; public class RotationParser : IParser { - public string GetName() + public static readonly Identifier RotationIdentifier = Identifier.Parse("minecraft:rotation"); + + public Identifier GetName() { - return "minecraft:rotation"; + return RotationIdentifier; } public int GetArgumentCount() diff --git a/Components/MineSharp.Commands/Parser/ScoreHolderParser.cs b/Components/MineSharp.Commands/Parser/ScoreHolderParser.cs index 07140320..f390c515 100644 --- a/Components/MineSharp.Commands/Parser/ScoreHolderParser.cs +++ b/Components/MineSharp.Commands/Parser/ScoreHolderParser.cs @@ -5,11 +5,13 @@ namespace MineSharp.Commands.Parser; public class ScoreHolderParser : IParser { + public static readonly Identifier ScoreHolderIdentifier = Identifier.Parse("minecraft:score_holder"); + public byte Flags { get; private set; } - public string GetName() + public Identifier GetName() { - return "minecraft:score_holder"; + return ScoreHolderIdentifier; } public int GetArgumentCount() diff --git a/Components/MineSharp.Commands/Parser/StringParser.cs b/Components/MineSharp.Commands/Parser/StringParser.cs index bed0ebd5..f6cb8807 100644 --- a/Components/MineSharp.Commands/Parser/StringParser.cs +++ b/Components/MineSharp.Commands/Parser/StringParser.cs @@ -5,11 +5,13 @@ namespace MineSharp.Commands.Parser; public class StringParser : IParser { + public static readonly Identifier BrigadierStringIdentifier = Identifier.Parse("brigadier:string"); + public StringType Type { get; private set; } - public string GetName() + public Identifier GetName() { - return "brigadier:string"; + return BrigadierStringIdentifier; } public int GetArgumentCount() diff --git a/Components/MineSharp.Commands/Parser/TimeParser.cs b/Components/MineSharp.Commands/Parser/TimeParser.cs index ef562845..5ca6fd6d 100644 --- a/Components/MineSharp.Commands/Parser/TimeParser.cs +++ b/Components/MineSharp.Commands/Parser/TimeParser.cs @@ -6,11 +6,13 @@ namespace MineSharp.Commands.Parser; public class TimeParser : IParser { + public static readonly Identifier TimeIdentifier = Identifier.Parse("minecraft:time"); + public int? Min { get; private set; } - public string GetName() + public Identifier GetName() { - return "minecraft:time"; + return TimeIdentifier; } public int GetArgumentCount() diff --git a/Components/MineSharp.Commands/Parser/Vec2Parser.cs b/Components/MineSharp.Commands/Parser/Vec2Parser.cs index 4323acc9..bbeacf67 100644 --- a/Components/MineSharp.Commands/Parser/Vec2Parser.cs +++ b/Components/MineSharp.Commands/Parser/Vec2Parser.cs @@ -5,9 +5,11 @@ namespace MineSharp.Commands.Parser; public class Vec2Parser : IParser { - public string GetName() + public static readonly Identifier Vec2Identifier = Identifier.Parse("minecraft:vec2"); + + public Identifier GetName() { - return "minecraft:vec2"; + return Vec2Identifier; } public int GetArgumentCount() diff --git a/Components/MineSharp.Commands/Parser/Vec3Parser.cs b/Components/MineSharp.Commands/Parser/Vec3Parser.cs index d3e451bd..ae89122a 100644 --- a/Components/MineSharp.Commands/Parser/Vec3Parser.cs +++ b/Components/MineSharp.Commands/Parser/Vec3Parser.cs @@ -5,9 +5,11 @@ namespace MineSharp.Commands.Parser; public class Vec3Parser : IParser { - public string GetName() + public static readonly Identifier Vec3Identifier = Identifier.Parse("minecraft:vec3"); + + public Identifier GetName() { - return "minecraft:vec3"; + return Vec3Identifier; } public int GetArgumentCount() diff --git a/Components/MineSharp.Physics/PhysicsConst.cs b/Components/MineSharp.Physics/PhysicsConst.cs index 2192e014..79b4c67b 100644 --- a/Components/MineSharp.Physics/PhysicsConst.cs +++ b/Components/MineSharp.Physics/PhysicsConst.cs @@ -1,4 +1,5 @@ -using MineSharp.Core.Common.Blocks; +using MineSharp.Core.Common; +using MineSharp.Core.Common.Blocks; using MineSharp.Core.Geometry; namespace MineSharp.Physics; @@ -20,7 +21,7 @@ internal static class PhysicsConst public const double FluidJumpFactor = 0.04d; public const int JumpDelay = 10; - public const string AttrMovementSpeed = "generic.movement_speed"; + public static readonly Identifier AttrMovementSpeed = Identifier.Parse("generic.movement_speed"); public const string SprintingUuid = "662a6b8d-da3e-4c1c-8813-96ea6097278d"; public const double PlayerSprintSpeed = 0.3d; public const double DefaultPlayerSpeed = 0.1d; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FeatureFlagsPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FeatureFlagsPacket.cs index 81ff79b8..3395d635 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FeatureFlagsPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FeatureFlagsPacket.cs @@ -9,7 +9,7 @@ namespace MineSharp.Protocol.Packets.Clientbound.Configuration; /// See https://wiki.vg/Protocol#Feature_Flags /// /// The enabled feature flags -public sealed record FeatureFlagsPacket(string[] FeatureFlags) : IPacket +public sealed record FeatureFlagsPacket(Identifier[] FeatureFlags) : IPacket { /// public PacketType Type => StaticType; @@ -19,12 +19,12 @@ public sealed record FeatureFlagsPacket(string[] FeatureFlags) : IPacket /// public void Write(PacketBuffer buffer, MinecraftData version) { - buffer.WriteVarIntArray(FeatureFlags, (buff, str) => buff.WriteString(str)); + buffer.WriteVarIntArray(FeatureFlags, (buff, str) => buff.WriteIdentifier(str)); } /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - return new FeatureFlagsPacket(buffer.ReadVarIntArray(buff => buff.ReadString())); + return new FeatureFlagsPacket(buffer.ReadVarIntArray(buff => buff.ReadIdentifier())); } } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PluginMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PluginMessagePacket.cs index 545d84ef..28414721 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PluginMessagePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PluginMessagePacket.cs @@ -9,7 +9,7 @@ namespace MineSharp.Protocol.Packets.Clientbound.Configuration; /// /// The name of the channel the data was sent /// The message data -public sealed record PluginMessagePacket(string ChannelName, byte[] Data) : IPacket +public sealed record PluginMessagePacket(Identifier ChannelName, byte[] Data) : IPacket { /// public PacketType Type => StaticType; @@ -19,14 +19,14 @@ public sealed record PluginMessagePacket(string ChannelName, byte[] Data) : IPac /// public void Write(PacketBuffer buffer, MinecraftData version) { - buffer.WriteString(ChannelName); + buffer.WriteIdentifier(ChannelName); buffer.WriteBytes(Data); } /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - var channelName = buffer.ReadString(); + var channelName = buffer.ReadIdentifier(); var data = buffer.RestBuffer(); return new PluginMessagePacket(channelName, data); } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs index 8263660e..24e760ad 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs @@ -1,4 +1,5 @@ using MineSharp.ChatComponent; +using MineSharp.ChatComponent.Components; using MineSharp.Core.Common; using MineSharp.Data; using MineSharp.Data.Protocol; @@ -28,6 +29,18 @@ public void Write(PacketBuffer buffer, MinecraftData version) public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var reason = buffer.ReadString(); - return new DisconnectPacket(Chat.Parse(reason)); + // Disconnect (login) packet is always sent as JSON text component according to wiki.vg + // But thats wrong. In the wild there were identifiers seen as well. + // So we try parse the indentifier and in case of error we parse the JSON text component + Chat chat; + if (Identifier.TryParse(reason, out var identifier)) + { + chat = new TranslatableComponent(identifier.ToString()); + } + else + { + chat = Chat.Parse(reason); + } + return new DisconnectPacket(chat); } } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginPluginRequestPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginPluginRequestPacket.cs index 11b74422..961e3c1a 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginPluginRequestPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginPluginRequestPacket.cs @@ -10,7 +10,7 @@ namespace MineSharp.Protocol.Packets.Clientbound.Login; /// The message id /// The channel identifier /// The raw message data -public sealed record LoginPluginRequestPacket(int MessageId, string Channel, byte[] Data) : IPacket +public sealed record LoginPluginRequestPacket(int MessageId, Identifier Channel, byte[] Data) : IPacket { /// public PacketType Type => StaticType; @@ -21,7 +21,7 @@ public sealed record LoginPluginRequestPacket(int MessageId, string Channel, byt public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteVarInt(MessageId); - buffer.WriteString(Channel); + buffer.WriteIdentifier(Channel); buffer.WriteBytes(Data.AsSpan()); } @@ -29,7 +29,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var messageId = buffer.ReadVarInt(); - var channel = buffer.ReadString(); + var channel = buffer.ReadIdentifier(); var data = buffer.RestBuffer(); return new LoginPluginRequestPacket(messageId, channel, data); diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs index 030f6eef..b95a5443 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs @@ -6,7 +6,7 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 public sealed record EntitySoundEffectPacket( int SoundId, - string? SoundName, + Identifier? SoundName, bool? HasFixedRange, float? Range, int SoundCategory, @@ -26,7 +26,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteVarInt(SoundId); if (SoundId == 0) { - buffer.WriteString(SoundName!); + buffer.WriteIdentifier(SoundName!); buffer.WriteBool(HasFixedRange!.Value); if (HasFixedRange.Value) { @@ -43,13 +43,13 @@ public void Write(PacketBuffer buffer, MinecraftData version) public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var soundId = buffer.ReadVarInt(); - string? soundName = null; + Identifier? soundName = null; bool? hasFixedRange = null; float? range = null; if (soundId == 0) { - soundName = buffer.ReadString(); + soundName = buffer.ReadIdentifier(); hasFixedRange = buffer.ReadBool(); if (hasFixedRange.Value) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs index e413ac81..1e9339a0 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs @@ -37,10 +37,10 @@ public sealed record LoginPacket( bool IsHardcore, byte GameMode, sbyte PreviousGameMode, - string[] DimensionNames, + Identifier[] DimensionNames, NbtCompound? RegistryCodec, - string DimensionType, - string DimensionName, + Identifier DimensionType, + Identifier DimensionName, long HashedSeed, int MaxPlayers, int ViewDistance, @@ -50,7 +50,7 @@ public sealed record LoginPacket( bool IsDebug, bool IsFlat, bool HasDeathLocation, - string? DeathDimensionName, + Identifier? DeathDimensionName, Position? DeathLocation, int? PortalCooldown, bool? DoLimitedCrafting) : IPacket @@ -77,12 +77,12 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteSByte(PreviousGameMode); } - buffer.WriteVarIntArray(DimensionNames, (buf, val) => buf.WriteString(val)); + buffer.WriteVarIntArray(DimensionNames, (buf, val) => buf.WriteIdentifier(val)); if (version.Version.Protocol < ProtocolVersion.V_1_20_2) { - buffer.WriteNbt(RegistryCodec); - buffer.WriteString(DimensionType); - buffer.WriteString(DimensionName); + buffer.WriteOptionalNbt(RegistryCodec); + buffer.WriteIdentifier(DimensionType); + buffer.WriteIdentifier(DimensionName); buffer.WriteLong(HashedSeed); } @@ -94,8 +94,8 @@ public void Write(PacketBuffer buffer, MinecraftData version) if (version.Version.Protocol >= ProtocolVersion.V_1_20_2) { buffer.WriteBool(DoLimitedCrafting!.Value); - buffer.WriteString(DimensionType); - buffer.WriteString(DimensionName); + buffer.WriteIdentifier(DimensionType); + buffer.WriteIdentifier(DimensionName); buffer.WriteLong(HashedSeed); buffer.WriteByte(GameMode); buffer.WriteSByte(PreviousGameMode); @@ -107,7 +107,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteBool(HasDeathLocation); if (HasDeathLocation) { - buffer.WriteString(DeathDimensionName!); + buffer.WriteIdentifier(DeathDimensionName!); buffer.WriteULong(DeathLocation!.ToULong()); } @@ -134,21 +134,21 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) var isHardcore = buffer.ReadBool(); var gameMode = buffer.ReadByte(); var previousGameMode = buffer.ReadSByte(); - var dimensionNames = buffer.ReadVarIntArray(buf => buf.ReadString()); + var dimensionNames = buffer.ReadVarIntArray(buf => buf.ReadIdentifier()); var registryCodec = buffer.ReadOptionalNbtCompound(); - string dimensionType; + Identifier dimensionType; if (version.Version.Protocol < ProtocolVersion.V_1_19) { var dimensionTypeNbt = buffer.ReadNbtCompound(); - dimensionType = dimensionTypeNbt.Get("effects")!.Value; + dimensionType = Identifier.Parse(dimensionTypeNbt.Get("effects")!.Value); } else { - dimensionType = buffer.ReadString(); + dimensionType = buffer.ReadIdentifier(); } - var dimensionName = buffer.ReadString(); + var dimensionName = buffer.ReadIdentifier(); var hashedSeed = buffer.ReadLong(); var maxPlayers = buffer.ReadVarInt(); var viewDistance = buffer.ReadVarInt(); @@ -158,7 +158,7 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) var isDebug = buffer.ReadBool(); var isFlat = buffer.ReadBool(); bool? hasDeathLocation = null; - string? deathDimensionName = null; + Identifier? deathDimensionName = null; Position? deathLocation = null; if (version.Version.Protocol >= ProtocolVersion.V_1_19) @@ -166,7 +166,7 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) hasDeathLocation = buffer.ReadBool(); if (hasDeathLocation.Value) { - deathDimensionName = buffer.ReadString(); + deathDimensionName = buffer.ReadIdentifier(); deathLocation = new(buffer.ReadULong()); } } @@ -205,26 +205,26 @@ private static LoginPacket ReadV1_20_2(PacketBuffer buffer, MinecraftData data) { var entityId = buffer.ReadInt(); var isHardcode = buffer.ReadBool(); - var dimensionNames = buffer.ReadVarIntArray(buf => buf.ReadString()); + var dimensionNames = buffer.ReadVarIntArray(buf => buf.ReadIdentifier()); 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 dimensionType = buffer.ReadIdentifier(); + var dimensionName = buffer.ReadIdentifier(); 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; + Identifier? deathDimensionName = null; Position? deathLocation = null; if (hasDeathLocation) { - deathDimensionName = buffer.ReadString(); + deathDimensionName = buffer.ReadIdentifier(); deathLocation = new(buffer.ReadULong()); } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs index f0fa91fe..5bbd4ee0 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs @@ -8,8 +8,8 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 public sealed record RespawnPacket( - string DimensionType, - string DimensionName, + Identifier DimensionType, + Identifier DimensionName, long HashedSeed, sbyte GameMode, byte PreviousGameMode, @@ -17,7 +17,7 @@ public sealed record RespawnPacket( bool IsFlat, bool CopyMetadata, bool? HasDeathLocation, - string? DeathDimensionName, + Identifier? DeathDimensionName, Position? DeathLocation, int? PortalCooldown ) : IPacket @@ -35,8 +35,8 @@ public void Write(PacketBuffer buffer, MinecraftData version) $"{nameof(RespawnPacket)}.Write() is not supported for versions before 1.19."); } - buffer.WriteString(DimensionType); - buffer.WriteString(DimensionName); + buffer.WriteIdentifier(DimensionType); + buffer.WriteIdentifier(DimensionName); buffer.WriteLong(HashedSeed); buffer.WriteSByte(GameMode); buffer.WriteByte(PreviousGameMode); @@ -54,7 +54,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) return; } - buffer.WriteString(DeathDimensionName!); + buffer.WriteIdentifier(DeathDimensionName!); buffer.WriteULong(DeathLocation!.ToULong()); if (version.Version.Protocol >= ProtocolVersion.V_1_20) @@ -65,19 +65,19 @@ public void Write(PacketBuffer buffer, MinecraftData version) public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - string dimensionType; + Identifier dimensionType; if (version.Version.Protocol <= ProtocolVersion.V_1_19) { var dimensionNbt = buffer.ReadNbtCompound(); - dimensionType = dimensionNbt.Get("effects")!.Value; + dimensionType = Identifier.Parse(dimensionNbt.Get("effects")!.Value); } else { - dimensionType = buffer.ReadString(); + dimensionType = buffer.ReadIdentifier(); } - var dimensionName = buffer.ReadString(); + var dimensionName = buffer.ReadIdentifier(); var hashedSeed = buffer.ReadLong(); var gameMode = buffer.ReadSByte(); var previousGameMode = buffer.ReadByte(); @@ -86,14 +86,14 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) var copyMetadata = buffer.ReadBool(); bool? hasDeathLocation = null; - string? deathDimensionName = null; + Identifier? deathDimensionName = null; Position? deathLocation = null; if (version.Version.Protocol >= ProtocolVersion.V_1_19) { hasDeathLocation = buffer.ReadBool(); if (hasDeathLocation ?? false) { - deathDimensionName = buffer.ReadString(); + deathDimensionName = buffer.ReadIdentifier(); deathLocation = new(buffer.ReadULong()); } } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs index 155f3048..73b32760 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs @@ -6,7 +6,7 @@ namespace MineSharp.Protocol.Packets.Clientbound.Play; #pragma warning disable CS1591 public sealed record SoundEffectPacket( int SoundId, - string? SoundName, + Identifier? SoundName, bool? HasFixedRange, float? Range, int SoundCategory, @@ -28,7 +28,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteVarInt(SoundId); if (SoundId == 0) { - buffer.WriteString(SoundName!); + buffer.WriteIdentifier(SoundName!); buffer.WriteBool(HasFixedRange!.Value); if (HasFixedRange.Value) { @@ -47,13 +47,13 @@ public void Write(PacketBuffer buffer, MinecraftData version) public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var soundId = buffer.ReadVarInt(); - string? soundName = null; + Identifier? soundName = null; bool? hasFixedRange = null; float? range = null; if (soundId == 0) { - soundName = buffer.ReadString(); + soundName = buffer.ReadIdentifier(); hasFixedRange = buffer.ReadBool(); if (hasFixedRange.Value) { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PluginMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PluginMessagePacket.cs index f2bb66be..7acef5ce 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PluginMessagePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PluginMessagePacket.cs @@ -9,7 +9,7 @@ namespace MineSharp.Protocol.Packets.Serverbound.Configuration; /// /// The name of the channel /// The data of the plugin message -public sealed record PluginMessagePacket(string ChannelName, byte[] Data) : IPacket +public sealed record PluginMessagePacket(Identifier ChannelName, byte[] Data) : IPacket { /// public PacketType Type => StaticType; @@ -19,14 +19,14 @@ public sealed record PluginMessagePacket(string ChannelName, byte[] Data) : IPac /// public void Write(PacketBuffer buffer, MinecraftData version) { - buffer.WriteString(ChannelName); + buffer.WriteIdentifier(ChannelName); buffer.WriteBytes(Data); } /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - var channelName = buffer.ReadString(); + var channelName = buffer.ReadIdentifier(); var data = buffer.RestBuffer(); return new PluginMessagePacket(channelName, data); } diff --git a/Data/MineSharp.Data/Framework/DataInterfaces.cs b/Data/MineSharp.Data/Framework/DataInterfaces.cs index 8dd89647..43226138 100644 --- a/Data/MineSharp.Data/Framework/DataInterfaces.cs +++ b/Data/MineSharp.Data/Framework/DataInterfaces.cs @@ -1,4 +1,5 @@ -using MineSharp.Core.Common.Biomes; +using MineSharp.Core.Common; +using MineSharp.Core.Common.Biomes; using MineSharp.Core.Common.Blocks; using MineSharp.Core.Common.Effects; using MineSharp.Core.Common.Enchantments; @@ -182,5 +183,5 @@ public interface IWindowData /// /// /// - public WindowInfo ByName(string name); + public WindowInfo ByName(Identifier name); } diff --git a/Data/MineSharp.Data/Windows/WindowData.cs b/Data/MineSharp.Data/Windows/WindowData.cs index 782f377e..cd8900b9 100644 --- a/Data/MineSharp.Data/Windows/WindowData.cs +++ b/Data/MineSharp.Data/Windows/WindowData.cs @@ -1,4 +1,5 @@ -using MineSharp.Core.Common.Blocks; +using MineSharp.Core.Common; +using MineSharp.Core.Common.Blocks; using MineSharp.Data.Framework; using MineSharp.Data.Framework.Providers; using MineSharp.Data.Internal; @@ -46,7 +47,7 @@ internal class WindowData(IDataProvider provider) : IndexedData windowMap = new(); + private Dictionary windowMap = new(); private WindowInfo[]? Windows { get; set; } @@ -66,7 +67,7 @@ public WindowInfo ById(int id) return Windows![id]; } - public WindowInfo ByName(string name) + public WindowInfo ByName(Identifier name) { if (!Loaded) { diff --git a/Data/MineSharp.Data/Windows/WindowInfo.cs b/Data/MineSharp.Data/Windows/WindowInfo.cs index 542b935d..a9d9854d 100644 --- a/Data/MineSharp.Data/Windows/WindowInfo.cs +++ b/Data/MineSharp.Data/Windows/WindowInfo.cs @@ -1,4 +1,6 @@ -namespace MineSharp.Data.Windows; +using MineSharp.Core.Common; + +namespace MineSharp.Data.Windows; /// /// Window descriptor. @@ -9,11 +11,30 @@ /// Whether the player's inventory is excluded for this window /// Whether the window has an offhand public record WindowInfo( - string Name, + Identifier Name, string Title, int UniqueSlots, bool ExcludeInventory = false, - bool HasOffHandSlot = false); + bool HasOffHandSlot = false) +{ + /// + /// Constructor for convenience that handles parsing. + /// + /// + /// + /// + /// + /// + public WindowInfo( + string name, + string title, + int uniqueSlots, + bool excludeInventory = false, + bool hasOffHandSlot = false) + : this(Identifier.Parse(name), title, uniqueSlots, excludeInventory, hasOffHandSlot) + { + } +} #pragma warning disable CS1591 diff --git a/MineSharp.Bot/Plugins/ChatPlugin.cs b/MineSharp.Bot/Plugins/ChatPlugin.cs index f6b850dc..041de4ba 100644 --- a/MineSharp.Bot/Plugins/ChatPlugin.cs +++ b/MineSharp.Bot/Plugins/ChatPlugin.cs @@ -136,6 +136,7 @@ public Task SendCommand(string command) }; } + private static readonly Identifier MessageIdentifier = Identifier.Parse("minecraft:message"); /* * Thanks to Minecraft-Console-Client @@ -177,7 +178,7 @@ public Task SendCommand(string command) var arg = command.Split(' ', argCnt + 1); if ((node.Flags & 0x04) > 0) { - if (node.Parser != null && node.Parser.GetName() == "minecraft:message") + if (node.Parser != null && node.Parser.GetName() == MessageIdentifier) { arguments.Add((node.Name!, command)); } @@ -582,7 +583,7 @@ private Task HandleChatInternal(Uuid? sender, ChatComponent.Chat message, ChatMe ChatComponent.Chat? target) { var entry = Bot.Registry["minecraft:chat_type"]["value"][index]; - var name = entry["name"]!.StringValue!; + var name = Identifier.Parse(entry["name"]!.StringValue!); var element = entry["element"]; var styleCompound = element["chat"]["style"]; var translation = element["chat"]["translation_key"].StringValue; @@ -620,9 +621,9 @@ private Task HandleChatInternal(Uuid? sender, ChatComponent.Chat message, ChatMe return (translatable, GetChatMessageType(name)); } - private static ChatMessageType GetChatMessageType(string message) + private static ChatMessageType GetChatMessageType(Identifier message) { - return message switch + return message.ToString() switch { "minecraft:chat" => ChatMessageType.Chat, "minecraft:emote_command" => ChatMessageType.Emote, @@ -633,7 +634,7 @@ private static ChatMessageType GetChatMessageType(string message) }; } - private static ChatMessageType UnknownChatMessage(string msg) + private static ChatMessageType UnknownChatMessage(Identifier msg) { Logger.Debug("Unknown chat message type {message}.", msg); return ChatMessageType.Raw; diff --git a/MineSharp.Bot/Plugins/PlayerPlugin.cs b/MineSharp.Bot/Plugins/PlayerPlugin.cs index 3e95aba0..f81246fa 100644 --- a/MineSharp.Bot/Plugins/PlayerPlugin.cs +++ b/MineSharp.Bot/Plugins/PlayerPlugin.cs @@ -1,4 +1,5 @@ using System.Collections.Concurrent; +using System.Collections.Frozen; using System.Diagnostics; using MineSharp.Bot.Exceptions; using MineSharp.Bot.Utils; @@ -91,7 +92,7 @@ public PlayerPlugin(MineSharpBot bot) : base(bot) /// /// The Name of the dimension the bot is currently in. /// - public string? DimensionName { get; private set; } + public Identifier? DimensionName { get; private set; } /// /// Whether the bot is alive or dead. @@ -493,15 +494,19 @@ private void HandlePlayerSetPermission(EntityStatusPacket packet) player.PermissionLevel = permissionLevel; } + private static readonly FrozenDictionary DimensionByIdentifier = new Dictionary + { + { Identifier.Parse("minecraft:overworld"), Dimension.Overworld }, + { Identifier.Parse("minecraft:the_nether"), Dimension.Nether }, + { Identifier.Parse("minecraft:the_end"), Dimension.End } + }.ToFrozenDictionary(); - private Dimension ParseDimension(string dimensionName) + private Dimension ParseDimension(Identifier dimensionName) { - return dimensionName switch + if (!DimensionByIdentifier.TryGetValue(dimensionName, out var dimension)) { - "minecraft:overworld" => Dimension.Overworld, - "minecraft:the_nether" => Dimension.Nether, - "minecraft:the_end" => Dimension.End, - _ => throw new UnreachableException($"{nameof(dimensionName)} was: {dimensionName}") - }; + throw new UnreachableException($"{nameof(dimensionName)} was: {dimensionName}"); + } + return dimension; } } diff --git a/MineSharp.Core/Common/Entities/Attributes/Attribute.cs b/MineSharp.Core/Common/Entities/Attributes/Attribute.cs index 7d3f121c..02d90c41 100644 --- a/MineSharp.Core/Common/Entities/Attributes/Attribute.cs +++ b/MineSharp.Core/Common/Entities/Attributes/Attribute.cs @@ -13,7 +13,7 @@ public sealed record Attribute /// The name of this Attribute /// The base value of this attribute /// The modifiers active for this attribute. Indexed by their UUID - public Attribute(string key, double @base, Modifier[] modifiers) + public Attribute(Identifier key, double @base, Modifier[] modifiers) { Key = key; Base = @base; @@ -23,7 +23,7 @@ public Attribute(string key, double @base, Modifier[] modifiers) /// /// The name of this Attribute /// - public string Key { get; init; } + public Identifier Key { get; init; } /// /// The base value of this attribute @@ -77,14 +77,14 @@ public void RemoveModifier(Uuid uuid) public void Write(PacketBuffer buffer) { - buffer.WriteString(Key); + buffer.WriteIdentifier(Key); buffer.WriteDouble(Value); buffer.WriteVarIntArray(Modifiers.Values, (buffer, modifier) => modifier.Write(buffer)); } public static Attribute Read(PacketBuffer buffer) { - var key = buffer.ReadString(); + var key = buffer.ReadIdentifier(); var value = buffer.ReadDouble(); var modifiers = buffer.ReadVarIntArray(Modifier.Read); diff --git a/MineSharp.Core/Common/Entities/Entity.cs b/MineSharp.Core/Common/Entities/Entity.cs index 7816b20a..63d3bc5c 100644 --- a/MineSharp.Core/Common/Entities/Entity.cs +++ b/MineSharp.Core/Common/Entities/Entity.cs @@ -74,7 +74,7 @@ public class Entity( /// /// A list of attributes active on this entity /// - public ConcurrentDictionary Attributes { get; } = new(); + public ConcurrentDictionary Attributes { get; } = new(); /// /// The entity this entity is riding (f.e. an boat or a minecart) @@ -87,7 +87,7 @@ public class Entity( /// /// /// - public Attribute? GetAttribute(string name) + public Attribute? GetAttribute(Identifier name) { Attributes.TryGetValue(name, out var attr); return attr; diff --git a/MineSharp.Core/Common/Identifier.cs b/MineSharp.Core/Common/Identifier.cs index deac2206..ca6fa851 100644 --- a/MineSharp.Core/Common/Identifier.cs +++ b/MineSharp.Core/Common/Identifier.cs @@ -5,6 +5,9 @@ namespace MineSharp.Core.Common; /// /// Represents an identifier with a namespace and a name. +/// This class is immutable. +/// The and methods are overridden to compare two identifiers with the following rules: +/// The default namespace is used for the comparison if none is specified. /// public sealed partial record Identifier { @@ -17,6 +20,12 @@ public sealed partial record Identifier /// public const string NoNamespace = ""; + /// + /// Represents an empty identifier. + /// It has no namespace and an empty name. + /// + public static readonly Identifier Empty = new(""); + /// /// The namespace part of the identifier. /// @@ -59,6 +68,30 @@ public Identifier ToCompleteIdentifier() return HasNamespace ? this : new Identifier(DefaultNamespace, Name); } + /// + public bool Equals(Identifier? other) + { + if (other is null) + { + return false; + } + if (ReferenceEquals(this, other)) + { + return true; + } + + var @namespace = HasNamespace ? Namespace : DefaultNamespace; + var otherNamespace = other.HasNamespace ? other.Namespace : DefaultNamespace; + return Namespace == otherNamespace && Name == other.Name; + } + + /// + public override int GetHashCode() + { + var @namespace = HasNamespace ? Namespace : DefaultNamespace; + return HashCode.Combine(@namespace, Name); + } + /// /// Returns a string representation of the identifier. /// From cb2c70e87af78fbeedefdf7546f6ccf9f6594788 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 00:26:58 +0200 Subject: [PATCH 34/73] fix race condition bug in WindowPlugin --- MineSharp.Bot/Plugins/WindowPlugin.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/MineSharp.Bot/Plugins/WindowPlugin.cs b/MineSharp.Bot/Plugins/WindowPlugin.cs index 27acea21..3e3b98d5 100644 --- a/MineSharp.Bot/Plugins/WindowPlugin.cs +++ b/MineSharp.Bot/Plugins/WindowPlugin.cs @@ -58,10 +58,12 @@ public WindowPlugin(MineSharpBot bot) : base(bot) CreativeInventory = new(bot); - Bot.Client.On(HandleWindowItems); - Bot.Client.On(HandleSetSlot); - Bot.Client.On(HandleHeldItemChange); - Bot.Client.On(HandleOpenWindow); + // OnPacketAfterInitialization is required to ensure that the plugin is initialized + // before handling packets. Otherwise we have race conditions that might cause errors + OnPacketAfterInitialization(HandleWindowItems, true); + OnPacketAfterInitialization(HandleSetSlot, true); + OnPacketAfterInitialization(HandleHeldItemChange, true); + OnPacketAfterInitialization(HandleOpenWindow, true); } /// From 016dbb7caa0fed94f182b3e86eeab32fe4ac8cd2 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 00:50:00 +0200 Subject: [PATCH 35/73] fix regex validation in Identifier type --- MineSharp.Core/Common/Identifier.cs | 4 ++-- MineSharp.Core/Common/RegexHelper.cs | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 MineSharp.Core/Common/RegexHelper.cs diff --git a/MineSharp.Core/Common/Identifier.cs b/MineSharp.Core/Common/Identifier.cs index ca6fa851..97d06a25 100644 --- a/MineSharp.Core/Common/Identifier.cs +++ b/MineSharp.Core/Common/Identifier.cs @@ -188,7 +188,7 @@ public static Identifier Create(string @namespace, string name) /// true if the namespace is valid; otherwise, false. public static bool IsValidNamespace(string @namespace) { - return NamespaceRegex().IsMatch(@namespace); + return NamespaceRegex().MatchEntireString(@namespace) != null; } [GeneratedRegex("[a-z0-9.-_/]+")] @@ -201,6 +201,6 @@ public static bool IsValidNamespace(string @namespace) /// true if the name is valid; otherwise, false. public static bool IsValidName(string name) { - return NameRegex().IsMatch(name); + return NameRegex().MatchEntireString(name) != null; } } diff --git a/MineSharp.Core/Common/RegexHelper.cs b/MineSharp.Core/Common/RegexHelper.cs new file mode 100644 index 00000000..0f39988c --- /dev/null +++ b/MineSharp.Core/Common/RegexHelper.cs @@ -0,0 +1,25 @@ +using System.Text.RegularExpressions; + +namespace MineSharp.Core.Common; + +/// +/// Provides helper methods for working with regular expressions. +/// +public static class RegexHelper +{ + /// + /// Matches the entire input string against the regular expression. + /// + /// The regular expression to match against. + /// The input string to match. + /// A object if the entire input string matches the regular expression; otherwise, null. + public static Match? MatchEntireString(this Regex regex, string input) + { + var match = regex.Match(input); + if (match.Success && match.Value.Length == input.Length) + { + return match; + } + return null; + } +} From fa8b72a21b667fc30a41d04482708a3fdb1306f9 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 01:35:35 +0200 Subject: [PATCH 36/73] fixed problem with mismatching Identifiers in RegistryData when on a 1.21 server via ViaProxy --- .../Configuration/RegistryDataPacket.cs | 4 ++- .../Packets/Clientbound/Play/LoginPacket.cs | 1 + MineSharp.Core/Common/NbtExtensions.cs | 30 +++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 MineSharp.Core/Common/NbtExtensions.cs diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RegistryDataPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RegistryDataPacket.cs index 9acbe40a..946885f3 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RegistryDataPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RegistryDataPacket.cs @@ -26,7 +26,9 @@ public void Write(PacketBuffer buffer, MinecraftData version) /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - return new RegistryDataPacket(buffer.ReadNbtCompound()); + var registryData = buffer.ReadNbtCompound(); + registryData = registryData.NormalizeRegistryDataTopLevelIdentifiers(); + return new RegistryDataPacket(registryData); } } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs index 1e9339a0..a49cf119 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs @@ -136,6 +136,7 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) var previousGameMode = buffer.ReadSByte(); var dimensionNames = buffer.ReadVarIntArray(buf => buf.ReadIdentifier()); var registryCodec = buffer.ReadOptionalNbtCompound(); + registryCodec = registryCodec?.NormalizeRegistryDataTopLevelIdentifiers(); Identifier dimensionType; if (version.Version.Protocol < ProtocolVersion.V_1_19) diff --git a/MineSharp.Core/Common/NbtExtensions.cs b/MineSharp.Core/Common/NbtExtensions.cs new file mode 100644 index 00000000..3e3ba0bb --- /dev/null +++ b/MineSharp.Core/Common/NbtExtensions.cs @@ -0,0 +1,30 @@ +using fNbt; + +namespace MineSharp.Core.Common; + +/// +/// Provides extension methods for NbtCompound. +/// +public static class NbtExtensions +{ + /// + /// Normalizes the top-level identifiers in the given NbtCompound. + /// This is required when using the registry of a 1.21 server via ViaProxy. + /// + /// The NbtCompound to normalize. + public static NbtCompound NormalizeRegistryDataTopLevelIdentifiers(this NbtCompound compound) + { + // we need to make copies of every tag because fNbt doesn't allow modifying the collection while iterating + // and there is no way to clear the parent of a tag + var newCompound = new NbtCompound(); + foreach (var tag in compound) + { + var identifier = Identifier.Parse(tag.Name); + var newTag = (NbtTag)tag.Clone(); + newTag.Name = identifier.ToCompleteIdentifier().ToString(); + newCompound.Add(newTag); + } + + return newCompound; + } +} From be8b6a8112ee34a16a6c9ce9d2571123acad180a Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 01:45:24 +0200 Subject: [PATCH 37/73] made loggings structured in WindowPlugin --- MineSharp.Bot/Plugins/WindowPlugin.cs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/MineSharp.Bot/Plugins/WindowPlugin.cs b/MineSharp.Bot/Plugins/WindowPlugin.cs index 3e3b98d5..4fa81953 100644 --- a/MineSharp.Bot/Plugins/WindowPlugin.cs +++ b/MineSharp.Bot/Plugins/WindowPlugin.cs @@ -20,7 +20,7 @@ namespace MineSharp.Bot.Plugins; /// -/// The Window plugin takes care of minecraft window's system. +/// The Window plugin takes care of Minecraft window's system. /// It handles the Bot's Inventory, window slot updates and provides /// methods to open blocks like chests, crafting tables, ... /// @@ -304,11 +304,11 @@ private void CreateInventory() private Window OpenWindow(int id, WindowInfo windowInfo) { - Logger.Debug("Opening window with id=" + id); + Logger.Debug("Opening window with id={WindowId}", id); if (openWindows.ContainsKey(id)) { - throw new ArgumentException("Window with id " + id + " already opened"); + throw new ArgumentException($"Window with id {id} already opened"); } var window = new Window( @@ -322,7 +322,7 @@ private Window OpenWindow(int id, WindowInfo windowInfo) { if (!openWindows.TryAdd(id, window)) { - Logger.Warn($"Could not add window with id {id}, it already existed."); + Logger.Warn("Could not add window with id {WindowId}, it already existed.", id); } } @@ -335,7 +335,7 @@ private Window OpenWindow(int id, WindowInfo windowInfo) && DateTime.Now - cacheTimestamp! <= TimeSpan.FromSeconds(5)) { // use cache - Logger.Debug("Applying cached window items for window with id=" + id); + Logger.Debug("Applying cached window items for window with id={WindowId}", id); HandleWindowItems(cachedWindowItemsPacket); } @@ -387,18 +387,17 @@ private Task HandleSetSlot(WindowSetSlotPacket packet) } else if (!openWindows.TryGetValue(packet.WindowId, out window)) { - Logger.Warn($"Received {nameof(WindowSetSlotPacket)} for windowId={packet.WindowId}, but its not opened"); + Logger.Warn("Received {PacketType} for windowId={WindowId}, but it's not opened", nameof(WindowSetSlotPacket), packet.WindowId); return Task.CompletedTask; } if (window == null) { - Logger.Warn( - $"Received {nameof(WindowSetSlotPacket)} for windowId={packet.WindowId}, but its not opened, {CurrentlyOpenedWindow?.ToString() ?? "null"}, {Inventory?.ToString() ?? "null"}"); + Logger.Warn("Received {PacketType} for windowId={WindowId}, but it's not opened, {CurrentlyOpenedWindow}, {Inventory}", nameof(WindowSetSlotPacket), packet.WindowId, CurrentlyOpenedWindow?.ToString() ?? "null", Inventory?.ToString() ?? "null"); return Task.CompletedTask; } - Logger.Debug("Handle set slot: {Slot}", packet.Slot); + // Logger.Debug("Handle set slot: {Slot}", packet.Slot); window.StateId = packet.StateId; window.SetSlot(packet.Slot); @@ -413,7 +412,7 @@ private Task HandleWindowItems(WindowItemsPacket packet) { if (!openWindows.TryGetValue(packet.WindowId, out window)) { - Logger.Warn($"Received {packet.GetType().Name} for windowId={packet.WindowId}, but its not opened"); + Logger.Warn("Received {PacketType} for windowId={WindowId}, but it's not opened", packet.GetType().Name, packet.WindowId); // Cache items in case it gets opened in a bit cachedWindowItemsPacket = packet; @@ -422,7 +421,7 @@ private Task HandleWindowItems(WindowItemsPacket packet) return Task.CompletedTask; } - Logger.Debug($"HandleWindowItems for window {window.Title}"); + Logger.Debug("HandleWindowItems for window {WindowTitle}", window.Title); } var slots = packet.Items @@ -451,7 +450,7 @@ private Task HandleOpenWindow(OpenWindowPacket packet) var windowInfo = Bot.Data.Windows.ById(packet.InventoryType); windowInfo = windowInfo with { Title = packet.WindowTitle }; - Logger.Debug($"Received Open Window Packet id={packet.WindowId}"); + Logger.Debug("Received Open Window Packet id={WindowId}", packet.WindowId); OpenWindow(packet.WindowId, windowInfo); return Task.CompletedTask; From 032f343bcfbb89bafc36e5a2872b1c288d1f6293 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 02:01:15 +0200 Subject: [PATCH 38/73] moved MinecraftVersion, PacketBuffer and friends to Core.Serialization --- Components/MineSharp.Commands/CommandTree.cs | 1 + .../Parser/BlockPositionParser.cs | 1 + .../MineSharp.Commands/Parser/ColumnPosParser.cs | 1 + .../MineSharp.Commands/Parser/DoubleParser.cs | 1 + .../MineSharp.Commands/Parser/EmptyParser.cs | 1 + .../MineSharp.Commands/Parser/EntityParser.cs | 1 + .../MineSharp.Commands/Parser/FloatParser.cs | 1 + Components/MineSharp.Commands/Parser/IParser.cs | 1 + .../MineSharp.Commands/Parser/IntegerParser.cs | 1 + Components/MineSharp.Commands/Parser/LongParser.cs | 1 + .../MineSharp.Commands/Parser/MessageParser.cs | 1 + .../MineSharp.Commands/Parser/RangeParser.cs | 1 + .../Parser/ResourceOrTagParser.cs | 1 + .../MineSharp.Commands/Parser/ResourceParser.cs | 1 + .../MineSharp.Commands/Parser/RotationParser.cs | 1 + .../MineSharp.Commands/Parser/ScoreHolderParser.cs | 1 + .../MineSharp.Commands/Parser/StringParser.cs | 1 + Components/MineSharp.Commands/Parser/TimeParser.cs | 1 + Components/MineSharp.Commands/Parser/Vec2Parser.cs | 1 + Components/MineSharp.Commands/Parser/Vec3Parser.cs | 1 + Components/MineSharp.Protocol/MinecraftClient.cs | 2 +- Components/MineSharp.Protocol/MinecraftStream.cs | 2 +- .../Clientbound/Configuration/DisconnectPacket.cs | 2 +- .../Configuration/FeatureFlagsPacket.cs | 1 + .../Configuration/FinishConfigurationPacket.cs | 2 +- .../Clientbound/Configuration/KeepAlivePacket.cs | 2 +- .../Clientbound/Configuration/PingPacket.cs | 2 +- .../Configuration/PluginMessagePacket.cs | 1 + .../Configuration/RegistryDataPacket.cs | 2 +- .../Packets/Clientbound/Login/DisconnectPacket.cs | 1 + .../Clientbound/Login/EncryptionRequestPacket.cs | 2 +- .../Clientbound/Login/LoginPluginRequestPacket.cs | 1 + .../Clientbound/Login/LoginSuccessPacket.cs | 1 + .../Clientbound/Login/SetCompressionPacket.cs | 2 +- .../Play/AcknowledgeBlockChangePacket.cs | 2 +- .../Packets/Clientbound/Play/BlockUpdatePacket.cs | 4 ++-- .../Clientbound/Play/BundleDelimiterPacket.cs | 2 +- .../Packets/Clientbound/Play/ChatPacket.cs | 1 + .../Clientbound/Play/ChunkBatchFinishedPacket.cs | 2 +- .../Clientbound/Play/ChunkBatchStartPacket.cs | 2 +- .../Play/ChunkDataAndUpdateLightPacket.cs | 2 +- .../Packets/Clientbound/Play/CloseWindowPacket.cs | 2 +- .../Packets/Clientbound/Play/CombatDeathPacket.cs | 2 +- .../Clientbound/Play/DeclareCommandsPacket.cs | 2 +- .../Packets/Clientbound/Play/DisconnectPacket.cs | 2 +- .../Clientbound/Play/DisguisedChatMessagePacket.cs | 2 +- .../Play/EntityPositionAndRotationPacket.cs | 2 +- .../Clientbound/Play/EntityPositionPacket.cs | 2 +- .../Clientbound/Play/EntityRotationPacket.cs | 2 +- .../Clientbound/Play/EntitySoundEffectPacket.cs | 1 + .../Packets/Clientbound/Play/EntityStatusPacket.cs | 2 +- .../Packets/Clientbound/Play/GameEventPacket.cs | 2 +- .../Packets/Clientbound/Play/KeepAlivePacket.cs | 2 +- .../Packets/Clientbound/Play/LoginPacket.cs | 1 + .../Clientbound/Play/MultiBlockUpdatePacket.cs | 2 +- .../Packets/Clientbound/Play/OpenWindowPacket.cs | 2 +- .../Packets/Clientbound/Play/ParticlePacket.cs | 2 +- .../Packets/Clientbound/Play/PingPacket.cs | 2 +- .../Packets/Clientbound/Play/PlayerChatPacket.cs | 5 +++-- .../Clientbound/Play/PlayerInfoRemovePacket.cs | 1 + .../Clientbound/Play/PlayerInfoUpdatePacket.cs | 1 + .../Clientbound/Play/PlayerPositionPacket.cs | 2 +- .../Clientbound/Play/RemoveEntitiesPacket.cs | 2 +- .../Packets/Clientbound/Play/RespawnPacket.cs | 1 + .../Clientbound/Play/SetEntityVelocityPacket.cs | 2 +- .../Packets/Clientbound/Play/SetHealthPacket.cs | 2 +- .../Packets/Clientbound/Play/SetHeldItemPacket.cs | 2 +- .../Clientbound/Play/SetPassengersPacket.cs | 2 +- .../Packets/Clientbound/Play/SoundEffectPacket.cs | 1 + .../Packets/Clientbound/Play/SpawnEntityPacket.cs | 1 + .../Clientbound/Play/SpawnLivingEntityPacket.cs | 1 + .../Clientbound/Play/SpawnPaintingPacket.cs | 1 + .../Packets/Clientbound/Play/SpawnPlayerPacket.cs | 1 + .../Clientbound/Play/SystemChatMessagePacket.cs | 2 +- .../Clientbound/Play/TeleportEntityPacket.cs | 2 +- .../Packets/Clientbound/Play/UnloadChunkPacket.cs | 2 +- .../Clientbound/Play/UpdateAttributesPacket.cs | 2 +- .../Packets/Clientbound/Play/WindowItemsPacket.cs | 4 ++-- .../Clientbound/Play/WindowSetSlotPacket.cs | 1 + .../Clientbound/Status/PingResponsePacket.cs | 2 +- .../Clientbound/Status/StatusResponsePacket.cs | 2 +- .../Packets/Handlers/LoginPacketHandler.cs | 2 +- Components/MineSharp.Protocol/Packets/IPacket.cs | 2 +- .../Packets/NetworkTypes/ChatMessageItem.cs | 10 +++++----- .../Packets/NetworkTypes/CoreTypeExtensions.cs | 1 + .../Packets/PacketBufferExtensions.cs | 2 +- .../MineSharp.Protocol/Packets/PacketPalette.cs | 2 +- .../Configuration/ClientInformationPacket.cs | 1 + .../Configuration/FinishConfigurationPacket.cs | 2 +- .../Serverbound/Configuration/KeepAlivePacket.cs | 2 +- .../Configuration/PluginMessagePacket.cs | 1 + .../Serverbound/Configuration/PongPacket.cs | 2 +- .../Configuration/ResourcePackResponsePacket.cs | 2 +- .../Serverbound/Handshaking/HandshakePacket.cs | 4 ++-- .../Serverbound/Login/EncryptionResponsePacket.cs | 2 +- .../Serverbound/Login/LoginAcknowledgedPacket.cs | 2 +- .../Serverbound/Login/LoginPluginResponsePacket.cs | 2 +- .../Packets/Serverbound/Login/LoginStartPacket.cs | 1 + .../Packets/Serverbound/Play/ChatCommandPacket.cs | 10 +++++----- .../Packets/Serverbound/Play/ChatMessagePacket.cs | 10 +++++----- .../Packets/Serverbound/Play/ChatPacket.cs | 2 +- .../Serverbound/Play/ChunkBatchReceivedPacket.cs | 2 +- .../Serverbound/Play/ClientCommandPacket.cs | 2 +- .../Serverbound/Play/ClientInformationPacket.cs | 1 + .../Packets/Serverbound/Play/CloseWindowPacket.cs | 2 +- .../Serverbound/Play/ConfirmTeleportPacket.cs | 2 +- .../Packets/Serverbound/Play/EntityActionPacket.cs | 2 +- .../Packets/Serverbound/Play/InteractPacket.cs | 1 + .../Packets/Serverbound/Play/KeepAlivePacket.cs | 2 +- .../Play/MessageAcknowledgementPacket.cs | 6 +++--- .../Packets/Serverbound/Play/PlaceBlockPacket.cs | 2 +- .../Packets/Serverbound/Play/PlayerActionPacket.cs | 2 +- .../Serverbound/Play/PlayerSessionPacket.cs | 1 + .../Packets/Serverbound/Play/PongPacket.cs | 2 +- .../Serverbound/Play/SetCreativeSlotPacket.cs | 4 ++-- .../Packets/Serverbound/Play/SetHeldItemPacket.cs | 2 +- .../Play/SetPlayerPositionAndRotationPacket.cs | 2 +- .../Serverbound/Play/SetPlayerPositionPacket.cs | 2 +- .../Packets/Serverbound/Play/SwingArmPacket.cs | 1 + .../Packets/Serverbound/Play/UpdateCommandBlock.cs | 4 ++-- .../Packets/Serverbound/Play/UseItemPacket.cs | 1 + .../Packets/Serverbound/Play/WindowClickPacket.cs | 1 + .../Serverbound/Status/PingRequestPacket.cs | 2 +- .../Serverbound/Status/StatusRequestPacket.cs | 2 +- .../MineSharp.World/Containers/BiomeContainer.cs | 2 +- .../MineSharp.World/Containers/BlockContainer.cs | 2 +- .../MineSharp.World/Containers/PaletteContainer.cs | 2 +- .../Containers/Palettes/DirectPalette.cs | 2 +- .../Containers/Palettes/IndirectPalette.cs | 2 +- .../Containers/Palettes/SingleValuePalette.cs | 2 +- .../MineSharp.World/V1_18/ChunkSection_1_18.cs | 4 ++-- Components/MineSharp.World/V1_18/Chunk_1_18.cs | 4 ++-- Data/MineSharp.Data/MinecraftData.cs | 5 +++-- MineSharp.Bot/Chat/ChatSignature.cs | 1 + .../Common/Entities/Attributes/Attribute.cs | 1 + .../Common/Entities/Attributes/Modifier.cs | 4 +++- MineSharp.Core/Common/Identifier.cs | 1 + .../Common}/MinecraftVersion.cs | 2 +- MineSharp.Core/MineSharp.Core.csproj | 14 +++++++------- .../Serialization}/ISerializable.cs | 7 +++---- .../Serialization}/IVersionAwareSerializable.cs | 7 +++---- .../{Common => Serialization}/NbtExtensions.cs | 3 ++- .../{Common => Serialization}/PacketBuffer.cs | 11 ++++++----- .../{Common => Serialization}/RegexHelper.cs | 2 +- 144 files changed, 187 insertions(+), 133 deletions(-) rename {Data/MineSharp.Data => MineSharp.Core/Common}/MinecraftVersion.cs (98%) rename {Components/MineSharp.Protocol/Packets => MineSharp.Core/Serialization}/ISerializable.cs (89%) rename {Components/MineSharp.Protocol/Packets => MineSharp.Core/Serialization}/IVersionAwareSerializable.cs (84%) rename MineSharp.Core/{Common => Serialization}/NbtExtensions.cs (93%) rename MineSharp.Core/{Common => Serialization}/PacketBuffer.cs (97%) rename MineSharp.Core/{Common => Serialization}/RegexHelper.cs (95%) diff --git a/Components/MineSharp.Commands/CommandTree.cs b/Components/MineSharp.Commands/CommandTree.cs index f5c11de4..89dbb742 100644 --- a/Components/MineSharp.Commands/CommandTree.cs +++ b/Components/MineSharp.Commands/CommandTree.cs @@ -1,6 +1,7 @@ using MineSharp.Commands.Parser; using MineSharp.Core; using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands; diff --git a/Components/MineSharp.Commands/Parser/BlockPositionParser.cs b/Components/MineSharp.Commands/Parser/BlockPositionParser.cs index 07380335..d744a82a 100644 --- a/Components/MineSharp.Commands/Parser/BlockPositionParser.cs +++ b/Components/MineSharp.Commands/Parser/BlockPositionParser.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Commands/Parser/ColumnPosParser.cs b/Components/MineSharp.Commands/Parser/ColumnPosParser.cs index 8e413e16..b46891cb 100644 --- a/Components/MineSharp.Commands/Parser/ColumnPosParser.cs +++ b/Components/MineSharp.Commands/Parser/ColumnPosParser.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Commands/Parser/DoubleParser.cs b/Components/MineSharp.Commands/Parser/DoubleParser.cs index bbaa213b..4725cf96 100644 --- a/Components/MineSharp.Commands/Parser/DoubleParser.cs +++ b/Components/MineSharp.Commands/Parser/DoubleParser.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Commands/Parser/EmptyParser.cs b/Components/MineSharp.Commands/Parser/EmptyParser.cs index 726705cf..1da7fc8a 100644 --- a/Components/MineSharp.Commands/Parser/EmptyParser.cs +++ b/Components/MineSharp.Commands/Parser/EmptyParser.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Commands/Parser/EntityParser.cs b/Components/MineSharp.Commands/Parser/EntityParser.cs index 03115f5f..6a52fb74 100644 --- a/Components/MineSharp.Commands/Parser/EntityParser.cs +++ b/Components/MineSharp.Commands/Parser/EntityParser.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Commands/Parser/FloatParser.cs b/Components/MineSharp.Commands/Parser/FloatParser.cs index 705a5f3f..55e8f340 100644 --- a/Components/MineSharp.Commands/Parser/FloatParser.cs +++ b/Components/MineSharp.Commands/Parser/FloatParser.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Commands/Parser/IParser.cs b/Components/MineSharp.Commands/Parser/IParser.cs index 38feb3e0..1a92080f 100644 --- a/Components/MineSharp.Commands/Parser/IParser.cs +++ b/Components/MineSharp.Commands/Parser/IParser.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Commands/Parser/IntegerParser.cs b/Components/MineSharp.Commands/Parser/IntegerParser.cs index 543e4083..fa7dbf40 100644 --- a/Components/MineSharp.Commands/Parser/IntegerParser.cs +++ b/Components/MineSharp.Commands/Parser/IntegerParser.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Commands/Parser/LongParser.cs b/Components/MineSharp.Commands/Parser/LongParser.cs index fa9b5c61..0c5189b8 100644 --- a/Components/MineSharp.Commands/Parser/LongParser.cs +++ b/Components/MineSharp.Commands/Parser/LongParser.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Commands/Parser/MessageParser.cs b/Components/MineSharp.Commands/Parser/MessageParser.cs index 5be94c7d..3e5067de 100644 --- a/Components/MineSharp.Commands/Parser/MessageParser.cs +++ b/Components/MineSharp.Commands/Parser/MessageParser.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Commands/Parser/RangeParser.cs b/Components/MineSharp.Commands/Parser/RangeParser.cs index 85fe1a08..f03cfa59 100644 --- a/Components/MineSharp.Commands/Parser/RangeParser.cs +++ b/Components/MineSharp.Commands/Parser/RangeParser.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Commands/Parser/ResourceOrTagParser.cs b/Components/MineSharp.Commands/Parser/ResourceOrTagParser.cs index b5f88e97..9211dce1 100644 --- a/Components/MineSharp.Commands/Parser/ResourceOrTagParser.cs +++ b/Components/MineSharp.Commands/Parser/ResourceOrTagParser.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Commands/Parser/ResourceParser.cs b/Components/MineSharp.Commands/Parser/ResourceParser.cs index 80bfc88c..b9806f67 100644 --- a/Components/MineSharp.Commands/Parser/ResourceParser.cs +++ b/Components/MineSharp.Commands/Parser/ResourceParser.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Commands/Parser/RotationParser.cs b/Components/MineSharp.Commands/Parser/RotationParser.cs index a33837fd..949aaebf 100644 --- a/Components/MineSharp.Commands/Parser/RotationParser.cs +++ b/Components/MineSharp.Commands/Parser/RotationParser.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Commands/Parser/ScoreHolderParser.cs b/Components/MineSharp.Commands/Parser/ScoreHolderParser.cs index f390c515..269c7147 100644 --- a/Components/MineSharp.Commands/Parser/ScoreHolderParser.cs +++ b/Components/MineSharp.Commands/Parser/ScoreHolderParser.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Commands/Parser/StringParser.cs b/Components/MineSharp.Commands/Parser/StringParser.cs index f6cb8807..2bb73dcd 100644 --- a/Components/MineSharp.Commands/Parser/StringParser.cs +++ b/Components/MineSharp.Commands/Parser/StringParser.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Commands/Parser/TimeParser.cs b/Components/MineSharp.Commands/Parser/TimeParser.cs index 5ca6fd6d..bda62512 100644 --- a/Components/MineSharp.Commands/Parser/TimeParser.cs +++ b/Components/MineSharp.Commands/Parser/TimeParser.cs @@ -1,5 +1,6 @@ using MineSharp.Core; using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Commands/Parser/Vec2Parser.cs b/Components/MineSharp.Commands/Parser/Vec2Parser.cs index bbeacf67..a1683a10 100644 --- a/Components/MineSharp.Commands/Parser/Vec2Parser.cs +++ b/Components/MineSharp.Commands/Parser/Vec2Parser.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Commands/Parser/Vec3Parser.cs b/Components/MineSharp.Commands/Parser/Vec3Parser.cs index ae89122a..556fa4ea 100644 --- a/Components/MineSharp.Commands/Parser/Vec3Parser.cs +++ b/Components/MineSharp.Commands/Parser/Vec3Parser.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Commands.Parser; diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index e5fb97b7..c6e66c3c 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -7,10 +7,10 @@ using MineSharp.ChatComponent; using MineSharp.ChatComponent.Components; using MineSharp.Core; -using MineSharp.Core.Common; using MineSharp.Core.Common.Protocol; using MineSharp.Core.Concurrency; using MineSharp.Core.Events; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Connection; diff --git a/Components/MineSharp.Protocol/MinecraftStream.cs b/Components/MineSharp.Protocol/MinecraftStream.cs index f7099147..795ce7eb 100644 --- a/Components/MineSharp.Protocol/MinecraftStream.cs +++ b/Components/MineSharp.Protocol/MinecraftStream.cs @@ -1,6 +1,6 @@ using System.Net.Sockets; using ICSharpCode.SharpZipLib.Zip.Compression; -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Protocol.Cryptography; using NLog; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/DisconnectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/DisconnectPacket.cs index 413bdedb..1cf4255d 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/DisconnectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/DisconnectPacket.cs @@ -1,5 +1,5 @@ using MineSharp.ChatComponent; -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FeatureFlagsPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FeatureFlagsPacket.cs index 3395d635..e706cae6 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FeatureFlagsPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FeatureFlagsPacket.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FinishConfigurationPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FinishConfigurationPacket.cs index f9c54885..feb6472f 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FinishConfigurationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/FinishConfigurationPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/KeepAlivePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/KeepAlivePacket.cs index ef0e6e2c..2604ab43 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/KeepAlivePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/KeepAlivePacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PingPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PingPacket.cs index 1ddea7b3..aca1d853 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PingPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PingPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PluginMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PluginMessagePacket.cs index 28414721..b974b296 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PluginMessagePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/PluginMessagePacket.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RegistryDataPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RegistryDataPacket.cs index 946885f3..65fb189d 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RegistryDataPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RegistryDataPacket.cs @@ -1,5 +1,5 @@ using fNbt; -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs index 24e760ad..62b07f2d 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs @@ -1,6 +1,7 @@ using MineSharp.ChatComponent; using MineSharp.ChatComponent.Components; using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/EncryptionRequestPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/EncryptionRequestPacket.cs index 6577bd36..1ebc4477 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/EncryptionRequestPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/EncryptionRequestPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginPluginRequestPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginPluginRequestPacket.cs index 961e3c1a..f653f89c 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginPluginRequestPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginPluginRequestPacket.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginSuccessPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginSuccessPacket.cs index a4cb5a28..9cc40318 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginSuccessPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/LoginSuccessPacket.cs @@ -1,5 +1,6 @@ using MineSharp.Core; using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Exceptions; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/SetCompressionPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/SetCompressionPacket.cs index 8c966085..13d4310c 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/SetCompressionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/SetCompressionPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/AcknowledgeBlockChangePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/AcknowledgeBlockChangePacket.cs index 1bf5d25a..835a3c8d 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/AcknowledgeBlockChangePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/AcknowledgeBlockChangePacket.cs @@ -1,6 +1,6 @@ using MineSharp.Core; -using MineSharp.Core.Common; using MineSharp.Core.Geometry; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockUpdatePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockUpdatePacket.cs index 28b873f9..5358ee85 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockUpdatePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockUpdatePacket.cs @@ -1,5 +1,5 @@ -using MineSharp.Core.Common; -using MineSharp.Core.Geometry; +using MineSharp.Core.Geometry; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/BundleDelimiterPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BundleDelimiterPacket.cs index 2be2a837..9ae9af88 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/BundleDelimiterPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BundleDelimiterPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChatPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChatPacket.cs index e036fdd6..89a41da4 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChatPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChatPacket.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchFinishedPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchFinishedPacket.cs index f76c6a74..1d50d2f2 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchFinishedPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchFinishedPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchStartPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchStartPacket.cs index 526abc7c..476dbcbf 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchStartPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBatchStartPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkDataAndUpdateLightPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkDataAndUpdateLightPacket.cs index 2364cb93..caf195e2 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkDataAndUpdateLightPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkDataAndUpdateLightPacket.cs @@ -1,7 +1,7 @@ using fNbt; using MineSharp.Core; -using MineSharp.Core.Common; using MineSharp.Core.Common.Blocks; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Exceptions; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/CloseWindowPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/CloseWindowPacket.cs index 709b1ccd..427c4234 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/CloseWindowPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/CloseWindowPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/CombatDeathPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/CombatDeathPacket.cs index 58fa802a..e7c13a53 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/CombatDeathPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/CombatDeathPacket.cs @@ -1,5 +1,5 @@ using MineSharp.Core; -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DeclareCommandsPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DeclareCommandsPacket.cs index 198df3fe..1053a2f2 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DeclareCommandsPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DeclareCommandsPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisconnectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisconnectPacket.cs index 82463e0c..bc6cc656 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisconnectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisconnectPacket.cs @@ -1,5 +1,5 @@ using MineSharp.ChatComponent; -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisguisedChatMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisguisedChatMessagePacket.cs index e84ffb1d..e649c865 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisguisedChatMessagePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisguisedChatMessagePacket.cs @@ -1,5 +1,5 @@ using MineSharp.ChatComponent; -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionAndRotationPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionAndRotationPacket.cs index 299c87da..0e70a4ad 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionAndRotationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionAndRotationPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionPacket.cs index 3c5c1204..288e2445 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityPositionPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityRotationPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityRotationPacket.cs index 473512ed..4303e478 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityRotationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityRotationPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs index b95a5443..c2678cc3 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntitySoundEffectPacket.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityStatusPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityStatusPacket.cs index d8071df8..ce7314f1 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityStatusPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityStatusPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/GameEventPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/GameEventPacket.cs index f6c6b42c..c04cdff1 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/GameEventPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/GameEventPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using static MineSharp.Protocol.Packets.Clientbound.Play.GameEventPacket; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/KeepAlivePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/KeepAlivePacket.cs index 37f41eba..80e0f6bf 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/KeepAlivePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/KeepAlivePacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs index a49cf119..91b3255f 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs @@ -2,6 +2,7 @@ using MineSharp.Core; using MineSharp.Core.Common; using MineSharp.Core.Geometry; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Exceptions; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/MultiBlockUpdatePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/MultiBlockUpdatePacket.cs index d7c08788..d3e9e3d5 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/MultiBlockUpdatePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/MultiBlockUpdatePacket.cs @@ -1,5 +1,5 @@ using MineSharp.Core; -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Exceptions; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenWindowPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenWindowPacket.cs index e02dbeae..270bf6be 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenWindowPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenWindowPacket.cs @@ -1,6 +1,6 @@ using MineSharp.ChatComponent; using MineSharp.Core; -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ParticlePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ParticlePacket.cs index 06f2f130..644d9c6d 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ParticlePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ParticlePacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PingPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PingPacket.cs index ebdda23c..a173e792 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PingPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PingPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerChatPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerChatPacket.cs index bd5b3169..b23929fd 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerChatPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerChatPacket.cs @@ -1,6 +1,7 @@ using MineSharp.ChatComponent; using MineSharp.Core; using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Packets.NetworkTypes; @@ -305,7 +306,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteLong(Timestamp); buffer.WriteLong(Salt); - buffer.WriteVarIntArray(PreviousMessages, (buf, val) => val.Write(buf, version)); + buffer.WriteVarIntArray(PreviousMessages, (buf, val) => val.Write(buf, version.Version)); var hasUnsignedContent = UnsignedContent != null; buffer.WriteBool(hasUnsignedContent); @@ -392,7 +393,7 @@ public static V11923Body Read(PacketBuffer buffer, MinecraftData version) timestamp = buffer.ReadLong(); salt = buffer.ReadLong(); - previousMessages = buffer.ReadVarIntArray(buff => ChatMessageItem.Read(buff, version)); + previousMessages = buffer.ReadVarIntArray(buff => ChatMessageItem.Read(buff, version.Version)); var hasUnsignedContent = buffer.ReadBool(); unsignedContent = null; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoRemovePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoRemovePacket.cs index f64e7539..76dba485 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoRemovePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoRemovePacket.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoUpdatePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoUpdatePacket.cs index 5dd00e75..627e425b 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoUpdatePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerInfoUpdatePacket.cs @@ -1,6 +1,7 @@ using System.Collections.Frozen; using MineSharp.Core; using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using static MineSharp.Protocol.Packets.Clientbound.Play.PlayerInfoUpdatePacket; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerPositionPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerPositionPacket.cs index 5bb58e22..8502b454 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerPositionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerPositionPacket.cs @@ -1,5 +1,5 @@ using MineSharp.Core; -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Exceptions; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveEntitiesPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveEntitiesPacket.cs index dbe2e856..196f01e4 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveEntitiesPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveEntitiesPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs index 5bbd4ee0..dac14bc1 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs @@ -2,6 +2,7 @@ using MineSharp.Core; using MineSharp.Core.Common; using MineSharp.Core.Geometry; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEntityVelocityPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEntityVelocityPacket.cs index 6af7807b..845d6468 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEntityVelocityPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEntityVelocityPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHealthPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHealthPacket.cs index b8ea4a5a..528ac20a 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHealthPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHealthPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHeldItemPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHeldItemPacket.cs index 9858bed5..064a6120 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHeldItemPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHeldItemPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetPassengersPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetPassengersPacket.cs index 69d45d21..0337868e 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetPassengersPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetPassengersPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs index 73b32760..c3e20998 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SoundEffectPacket.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnEntityPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnEntityPacket.cs index d5d9de22..f3a5c0c9 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnEntityPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnEntityPacket.cs @@ -1,5 +1,6 @@ using MineSharp.Core; using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnLivingEntityPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnLivingEntityPacket.cs index 1e1a3f64..5160159d 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnLivingEntityPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnLivingEntityPacket.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPaintingPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPaintingPacket.cs index ce237007..1d5b9d39 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPaintingPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPaintingPacket.cs @@ -1,5 +1,6 @@ using MineSharp.Core.Common; using MineSharp.Core.Geometry; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPlayerPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPlayerPacket.cs index 17850dbb..f8ff8579 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPlayerPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPlayerPacket.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SystemChatMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SystemChatMessagePacket.cs index 70bb9b64..d813307d 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SystemChatMessagePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SystemChatMessagePacket.cs @@ -1,6 +1,6 @@ using MineSharp.ChatComponent; using MineSharp.Core; -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/TeleportEntityPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/TeleportEntityPacket.cs index 15505089..a26aafaa 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/TeleportEntityPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/TeleportEntityPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/UnloadChunkPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UnloadChunkPacket.cs index 2163a43c..e1e3f8a8 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/UnloadChunkPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UnloadChunkPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateAttributesPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateAttributesPacket.cs index ca5ad986..2ac7b818 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateAttributesPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateAttributesPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using Attribute = MineSharp.Core.Common.Entities.Attributes.Attribute; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowItemsPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowItemsPacket.cs index ff90c39b..a4d0f81e 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowItemsPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowItemsPacket.cs @@ -1,5 +1,5 @@ -using MineSharp.Core.Common; -using MineSharp.Core.Common.Items; +using MineSharp.Core.Common.Items; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Packets.NetworkTypes; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowSetSlotPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowSetSlotPacket.cs index 81952e77..71dea1c8 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowSetSlotPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/WindowSetSlotPacket.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Packets.NetworkTypes; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Status/PingResponsePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Status/PingResponsePacket.cs index 66c6b307..1d9b5862 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Status/PingResponsePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Status/PingResponsePacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Status/StatusResponsePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Status/StatusResponsePacket.cs index a1b976eb..f8c7ca30 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Status/StatusResponsePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Status/StatusResponsePacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs index 5f0f3db4..11921a1c 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs @@ -2,8 +2,8 @@ using System.Security.Cryptography; using MineSharp.Auth.Exceptions; using MineSharp.Core; -using MineSharp.Core.Common; using MineSharp.Core.Common.Protocol; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Cryptography; diff --git a/Components/MineSharp.Protocol/Packets/IPacket.cs b/Components/MineSharp.Protocol/Packets/IPacket.cs index f205d553..709e534e 100644 --- a/Components/MineSharp.Protocol/Packets/IPacket.cs +++ b/Components/MineSharp.Protocol/Packets/IPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/NetworkTypes/ChatMessageItem.cs b/Components/MineSharp.Protocol/Packets/NetworkTypes/ChatMessageItem.cs index a402212d..8ef77f17 100644 --- a/Components/MineSharp.Protocol/Packets/NetworkTypes/ChatMessageItem.cs +++ b/Components/MineSharp.Protocol/Packets/NetworkTypes/ChatMessageItem.cs @@ -1,6 +1,6 @@ using MineSharp.Core; using MineSharp.Core.Common; -using MineSharp.Data; +using MineSharp.Core.Serialization; namespace MineSharp.Protocol.Packets.NetworkTypes; @@ -50,9 +50,9 @@ private ChatMessageItem(Uuid? sender, byte[]? signature) /// /// /// - public void Write(PacketBuffer buffer, MinecraftData version) + public void Write(PacketBuffer buffer, MinecraftVersion version) { - if (version.Version.Protocol == ProtocolVersion.V_1_19_2) + if (version.Protocol == ProtocolVersion.V_1_19_2) { buffer.WriteUuid(Sender!.Value); buffer.WriteVarInt(Signature!.Length); @@ -74,12 +74,12 @@ public void Write(PacketBuffer buffer, MinecraftData version) /// /// /// - public static ChatMessageItem Read(PacketBuffer buffer, MinecraftData version) + public static ChatMessageItem Read(PacketBuffer buffer, MinecraftVersion version) { Uuid? uuid = null; byte[]? signature = null; - if (version.Version.Protocol == ProtocolVersion.V_1_19_2) + if (version.Protocol == ProtocolVersion.V_1_19_2) { uuid = buffer.ReadUuid(); signature = new byte[buffer.ReadVarInt()]; diff --git a/Components/MineSharp.Protocol/Packets/NetworkTypes/CoreTypeExtensions.cs b/Components/MineSharp.Protocol/Packets/NetworkTypes/CoreTypeExtensions.cs index ce0b2feb..58579a7b 100644 --- a/Components/MineSharp.Protocol/Packets/NetworkTypes/CoreTypeExtensions.cs +++ b/Components/MineSharp.Protocol/Packets/NetworkTypes/CoreTypeExtensions.cs @@ -1,5 +1,6 @@ using MineSharp.Core.Common; using MineSharp.Core.Common.Items; +using MineSharp.Core.Serialization; using MineSharp.Data; namespace MineSharp.Protocol.Packets.NetworkTypes; diff --git a/Components/MineSharp.Protocol/Packets/PacketBufferExtensions.cs b/Components/MineSharp.Protocol/Packets/PacketBufferExtensions.cs index ddb31baa..1244e9ae 100644 --- a/Components/MineSharp.Protocol/Packets/PacketBufferExtensions.cs +++ b/Components/MineSharp.Protocol/Packets/PacketBufferExtensions.cs @@ -1,6 +1,6 @@ using MineSharp.ChatComponent; using MineSharp.Core; -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; namespace MineSharp.Protocol.Packets; diff --git a/Components/MineSharp.Protocol/Packets/PacketPalette.cs b/Components/MineSharp.Protocol/Packets/PacketPalette.cs index 109e49e0..015a8b31 100644 --- a/Components/MineSharp.Protocol/Packets/PacketPalette.cs +++ b/Components/MineSharp.Protocol/Packets/PacketPalette.cs @@ -1,5 +1,5 @@ using System.Collections.Frozen; -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Packets.Clientbound.Configuration; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ClientInformationPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ClientInformationPacket.cs index fe1f1ad0..b89c1ad2 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ClientInformationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ClientInformationPacket.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/FinishConfigurationPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/FinishConfigurationPacket.cs index 9d0d1526..47f11676 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/FinishConfigurationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/FinishConfigurationPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/KeepAlivePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/KeepAlivePacket.cs index addcb5fe..4ed55555 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/KeepAlivePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/KeepAlivePacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PluginMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PluginMessagePacket.cs index 7acef5ce..06126252 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PluginMessagePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PluginMessagePacket.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PongPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PongPacket.cs index 1b001aa6..1f966fe8 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PongPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/PongPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ResourcePackResponsePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ResourcePackResponsePacket.cs index 3cba274e..3123b324 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ResourcePackResponsePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Configuration/ResourcePackResponsePacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Handshaking/HandshakePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Handshaking/HandshakePacket.cs index 944d760b..54130920 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Handshaking/HandshakePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Handshaking/HandshakePacket.cs @@ -1,5 +1,5 @@ -using MineSharp.Core.Common; -using MineSharp.Core.Common.Protocol; +using MineSharp.Core.Common.Protocol; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Login/EncryptionResponsePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Login/EncryptionResponsePacket.cs index 31446970..5fe94389 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Login/EncryptionResponsePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Login/EncryptionResponsePacket.cs @@ -1,5 +1,5 @@ using MineSharp.Core; -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Exceptions; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginAcknowledgedPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginAcknowledgedPacket.cs index 49fac545..96915af1 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginAcknowledgedPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginAcknowledgedPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginPluginResponsePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginPluginResponsePacket.cs index 1f7be096..94f12880 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginPluginResponsePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginPluginResponsePacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginStartPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginStartPacket.cs index e03ee0e8..846bb6ff 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginStartPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Login/LoginStartPacket.cs @@ -1,5 +1,6 @@ using MineSharp.Core; using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Exceptions; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatCommandPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatCommandPacket.cs index 6dbcd333..6b7088f0 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatCommandPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatCommandPacket.cs @@ -1,5 +1,5 @@ using MineSharp.Core; -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Exceptions; @@ -138,7 +138,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) throw new MineSharpPacketVersionException(nameof(PreviousMessages), version.Version.Protocol); } - buffer.WriteVarIntArray(PreviousMessages, (buf, val) => val.Write(buf, version)); + buffer.WriteVarIntArray(PreviousMessages, (buf, val) => val.Write(buf, version.Version)); var hasLastRejectedMessage = LastRejectedMessage != null; buffer.WriteBool(hasLastRejectedMessage); @@ -148,7 +148,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) return; } - LastRejectedMessage!.Write(buffer, version); + LastRejectedMessage!.Write(buffer, version.Version); } private const int AfterMc1192AcknowledgedLength = 20; @@ -178,11 +178,11 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) ChatMessageItem? lastRejectedMessage = null; if (version.Version.Protocol == ProtocolVersion.V_1_19_2) { - previousMessages = buffer.ReadVarIntArray((buf) => ChatMessageItem.Read(buf, version)); + previousMessages = buffer.ReadVarIntArray((buf) => ChatMessageItem.Read(buf, version.Version)); var hasLastRejectedMessage = buffer.ReadBool(); if (hasLastRejectedMessage) { - lastRejectedMessage = ChatMessageItem.Read(buffer, version); + lastRejectedMessage = ChatMessageItem.Read(buffer, version.Version); } } diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatMessagePacket.cs index 75a2ad4c..c9809c89 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatMessagePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatMessagePacket.cs @@ -1,5 +1,5 @@ using MineSharp.Core; -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Exceptions; @@ -122,7 +122,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) throw new MineSharpPacketVersionException(nameof(PreviousMessages), version.Version.Protocol); } - buffer.WriteVarIntArray(PreviousMessages, (buf, val) => val.Write(buf, version)); + buffer.WriteVarIntArray(PreviousMessages, (buf, val) => val.Write(buf, version.Version)); var hasLastRejectedMessage = LastRejectedMessage != null; buffer.WriteBool(hasLastRejectedMessage); @@ -132,7 +132,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) return; } - LastRejectedMessage!.Write(buffer, version); + LastRejectedMessage!.Write(buffer, version.Version); } public static IPacket Read(PacketBuffer buffer, MinecraftData version) @@ -180,12 +180,12 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) } - previousMessages = buffer.ReadVarIntArray(buff => ChatMessageItem.Read(buff, version)); + previousMessages = buffer.ReadVarIntArray(buff => ChatMessageItem.Read(buff, version.Version)); var hasLastRejectedMessage = buffer.ReadBool(); if (hasLastRejectedMessage) { - lastRejectedMessage = ChatMessageItem.Read(buffer, version); + lastRejectedMessage = ChatMessageItem.Read(buffer, version.Version); } else { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatPacket.cs index 00e7bd67..03f3b8c3 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChunkBatchReceivedPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChunkBatchReceivedPacket.cs index 803c41e5..873e86cb 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChunkBatchReceivedPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChunkBatchReceivedPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientCommandPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientCommandPacket.cs index 17d8862e..bb0b7b73 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientCommandPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientCommandPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientInformationPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientInformationPacket.cs index 4048e236..1c672da1 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientInformationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ClientInformationPacket.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/CloseWindowPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/CloseWindowPacket.cs index 343857b8..2731c572 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/CloseWindowPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/CloseWindowPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ConfirmTeleportPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ConfirmTeleportPacket.cs index dfa8d037..746612b8 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ConfirmTeleportPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ConfirmTeleportPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/EntityActionPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/EntityActionPacket.cs index 7ecd5b31..87ec2e9b 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/EntityActionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/EntityActionPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/InteractPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/InteractPacket.cs index 279526e8..61e5fae0 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/InteractPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/InteractPacket.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using static MineSharp.Protocol.Packets.Serverbound.Play.InteractPacket; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/KeepAlivePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/KeepAlivePacket.cs index b8c026a6..d0075138 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/KeepAlivePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/KeepAlivePacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/MessageAcknowledgementPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/MessageAcknowledgementPacket.cs index b87f0bae..901bed04 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/MessageAcknowledgementPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/MessageAcknowledgementPacket.cs @@ -1,5 +1,5 @@ using MineSharp.Core; -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Exceptions; @@ -59,7 +59,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) throw new MineSharpPacketVersionException(nameof(PreviousMessages), version.Version.Protocol); } - buffer.WriteVarIntArray(PreviousMessages, (buf, val) => val.Write(buf, version)); + buffer.WriteVarIntArray(PreviousMessages, (buf, val) => val.Write(buf, version.Version)); var hasLastRejectedMessage = LastRejectedMessage != null; buffer.WriteBool(hasLastRejectedMessage); @@ -68,7 +68,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) return; } - LastRejectedMessage!.Write(buffer, version); + LastRejectedMessage!.Write(buffer, version.Version); } public static IPacket Read(PacketBuffer buffer, MinecraftData version) diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlaceBlockPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlaceBlockPacket.cs index 8fe70f39..2a3e2cca 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlaceBlockPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlaceBlockPacket.cs @@ -1,6 +1,6 @@ using MineSharp.Core; -using MineSharp.Core.Common; using MineSharp.Core.Geometry; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerActionPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerActionPacket.cs index d6be1e62..ff8290bd 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerActionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerActionPacket.cs @@ -1,6 +1,6 @@ using MineSharp.Core; -using MineSharp.Core.Common; using MineSharp.Core.Geometry; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerSessionPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerSessionPacket.cs index cb3698c6..90af38a4 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerSessionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerSessionPacket.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PongPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PongPacket.cs index 47a68da2..d8c1d2a3 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PongPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PongPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetCreativeSlotPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetCreativeSlotPacket.cs index 0fef40c7..1220aa5f 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetCreativeSlotPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetCreativeSlotPacket.cs @@ -1,5 +1,5 @@ -using MineSharp.Core.Common; -using MineSharp.Core.Common.Items; +using MineSharp.Core.Common.Items; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Packets.NetworkTypes; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetHeldItemPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetHeldItemPacket.cs index 8fc0c91b..aaff55fb 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetHeldItemPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetHeldItemPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionAndRotationPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionAndRotationPacket.cs index 06840995..42ac2242 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionAndRotationPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionAndRotationPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionPacket.cs index 765f39cd..d816dcc9 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SetPlayerPositionPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SwingArmPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SwingArmPacket.cs index be5a6ed8..1421f166 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/SwingArmPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/SwingArmPacket.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/UpdateCommandBlock.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/UpdateCommandBlock.cs index 0248c78d..59300b56 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/UpdateCommandBlock.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/UpdateCommandBlock.cs @@ -1,5 +1,5 @@ -using MineSharp.Core.Common; -using MineSharp.Core.Geometry; +using MineSharp.Core.Geometry; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/UseItemPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/UseItemPacket.cs index 5b2f0732..5df34ff8 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/UseItemPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/UseItemPacket.cs @@ -1,5 +1,6 @@ using MineSharp.Core; using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/WindowClickPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/WindowClickPacket.cs index 920d7820..4563aa42 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/WindowClickPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/WindowClickPacket.cs @@ -1,5 +1,6 @@ using MineSharp.Core.Common; using MineSharp.Core.Common.Items; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Packets.NetworkTypes; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Status/PingRequestPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Status/PingRequestPacket.cs index c143baa3..711b8af7 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Status/PingRequestPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Status/PingRequestPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Status/StatusRequestPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Status/StatusRequestPacket.cs index 42291fe6..e8b87837 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Status/StatusRequestPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Status/StatusRequestPacket.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; diff --git a/Components/MineSharp.World/Containers/BiomeContainer.cs b/Components/MineSharp.World/Containers/BiomeContainer.cs index efcbf041..3fc9a36c 100644 --- a/Components/MineSharp.World/Containers/BiomeContainer.cs +++ b/Components/MineSharp.World/Containers/BiomeContainer.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.World.Containers.Palettes; diff --git a/Components/MineSharp.World/Containers/BlockContainer.cs b/Components/MineSharp.World/Containers/BlockContainer.cs index e3257963..2e10432d 100644 --- a/Components/MineSharp.World/Containers/BlockContainer.cs +++ b/Components/MineSharp.World/Containers/BlockContainer.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.World.Containers.Palettes; diff --git a/Components/MineSharp.World/Containers/PaletteContainer.cs b/Components/MineSharp.World/Containers/PaletteContainer.cs index 92210d18..2084ccbf 100644 --- a/Components/MineSharp.World/Containers/PaletteContainer.cs +++ b/Components/MineSharp.World/Containers/PaletteContainer.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.World.Containers.Palettes; namespace MineSharp.World.Containers; diff --git a/Components/MineSharp.World/Containers/Palettes/DirectPalette.cs b/Components/MineSharp.World/Containers/Palettes/DirectPalette.cs index 3fb747e3..c3458e12 100644 --- a/Components/MineSharp.World/Containers/Palettes/DirectPalette.cs +++ b/Components/MineSharp.World/Containers/Palettes/DirectPalette.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; namespace MineSharp.World.Containers.Palettes; diff --git a/Components/MineSharp.World/Containers/Palettes/IndirectPalette.cs b/Components/MineSharp.World/Containers/Palettes/IndirectPalette.cs index 53600f33..bee4b0bb 100644 --- a/Components/MineSharp.World/Containers/Palettes/IndirectPalette.cs +++ b/Components/MineSharp.World/Containers/Palettes/IndirectPalette.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; namespace MineSharp.World.Containers.Palettes; diff --git a/Components/MineSharp.World/Containers/Palettes/SingleValuePalette.cs b/Components/MineSharp.World/Containers/Palettes/SingleValuePalette.cs index 9ca03dba..07543960 100644 --- a/Components/MineSharp.World/Containers/Palettes/SingleValuePalette.cs +++ b/Components/MineSharp.World/Containers/Palettes/SingleValuePalette.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Core.Serialization; namespace MineSharp.World.Containers.Palettes; diff --git a/Components/MineSharp.World/V1_18/ChunkSection_1_18.cs b/Components/MineSharp.World/V1_18/ChunkSection_1_18.cs index 2c243a9e..ddfdcc6a 100644 --- a/Components/MineSharp.World/V1_18/ChunkSection_1_18.cs +++ b/Components/MineSharp.World/V1_18/ChunkSection_1_18.cs @@ -1,7 +1,7 @@ -using MineSharp.Core.Common; -using MineSharp.Core.Common.Biomes; +using MineSharp.Core.Common.Biomes; using MineSharp.Core.Common.Blocks; using MineSharp.Core.Geometry; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.World.Chunks; using MineSharp.World.Containers; diff --git a/Components/MineSharp.World/V1_18/Chunk_1_18.cs b/Components/MineSharp.World/V1_18/Chunk_1_18.cs index f737c1f0..02a32427 100644 --- a/Components/MineSharp.World/V1_18/Chunk_1_18.cs +++ b/Components/MineSharp.World/V1_18/Chunk_1_18.cs @@ -1,8 +1,8 @@ -using MineSharp.Core.Common; -using MineSharp.Core.Common.Biomes; +using MineSharp.Core.Common.Biomes; using MineSharp.Core.Common.Blocks; using MineSharp.Core.Events; using MineSharp.Core.Geometry; +using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.World.Chunks; using MineSharp.World.Exceptions; diff --git a/Data/MineSharp.Data/MinecraftData.cs b/Data/MineSharp.Data/MinecraftData.cs index a1557403..0aaf1e81 100644 --- a/Data/MineSharp.Data/MinecraftData.cs +++ b/Data/MineSharp.Data/MinecraftData.cs @@ -1,4 +1,5 @@ -using MineSharp.Data.Biomes; +using MineSharp.Core.Common; +using MineSharp.Data.Biomes; using MineSharp.Data.BlockCollisionShapes; using MineSharp.Data.Blocks; using MineSharp.Data.Effects; @@ -127,7 +128,7 @@ private MinecraftData( public ILanguageData Language { get; } /// - /// The minecraft version of this instance + /// The Minecraft version of this instance /// public MinecraftVersion Version { get; } diff --git a/MineSharp.Bot/Chat/ChatSignature.cs b/MineSharp.Bot/Chat/ChatSignature.cs index 68805c9b..a38d5570 100644 --- a/MineSharp.Bot/Chat/ChatSignature.cs +++ b/MineSharp.Bot/Chat/ChatSignature.cs @@ -7,6 +7,7 @@ using System.Security.Cryptography; using System.Text; using MineSharp.Core.Common; +using MineSharp.Core.Serialization; using MineSharp.Data; using Newtonsoft.Json; using Newtonsoft.Json.Linq; diff --git a/MineSharp.Core/Common/Entities/Attributes/Attribute.cs b/MineSharp.Core/Common/Entities/Attributes/Attribute.cs index 02d90c41..9dfadc2e 100644 --- a/MineSharp.Core/Common/Entities/Attributes/Attribute.cs +++ b/MineSharp.Core/Common/Entities/Attributes/Attribute.cs @@ -1,4 +1,5 @@ using System.Diagnostics; +using MineSharp.Core.Serialization; namespace MineSharp.Core.Common.Entities.Attributes; diff --git a/MineSharp.Core/Common/Entities/Attributes/Modifier.cs b/MineSharp.Core/Common/Entities/Attributes/Modifier.cs index 732cdb57..d47d5cc7 100644 --- a/MineSharp.Core/Common/Entities/Attributes/Modifier.cs +++ b/MineSharp.Core/Common/Entities/Attributes/Modifier.cs @@ -1,4 +1,6 @@ -namespace MineSharp.Core.Common.Entities.Attributes; +using MineSharp.Core.Serialization; + +namespace MineSharp.Core.Common.Entities.Attributes; /// /// A modifier for an attribute diff --git a/MineSharp.Core/Common/Identifier.cs b/MineSharp.Core/Common/Identifier.cs index 97d06a25..cedf8977 100644 --- a/MineSharp.Core/Common/Identifier.cs +++ b/MineSharp.Core/Common/Identifier.cs @@ -1,5 +1,6 @@ using System.Diagnostics.CodeAnalysis; using System.Text.RegularExpressions; +using MineSharp.Core.Serialization; namespace MineSharp.Core.Common; diff --git a/Data/MineSharp.Data/MinecraftVersion.cs b/MineSharp.Core/Common/MinecraftVersion.cs similarity index 98% rename from Data/MineSharp.Data/MinecraftVersion.cs rename to MineSharp.Core/Common/MinecraftVersion.cs index dd848d21..e6f1dfb0 100644 --- a/Data/MineSharp.Data/MinecraftVersion.cs +++ b/MineSharp.Core/Common/MinecraftVersion.cs @@ -1,4 +1,4 @@ -namespace MineSharp.Data; +namespace MineSharp.Core.Common; /// /// A Minecraft Version diff --git a/MineSharp.Core/MineSharp.Core.csproj b/MineSharp.Core/MineSharp.Core.csproj index 7cab6d0e..9afdb8d8 100644 --- a/MineSharp.Core/MineSharp.Core.csproj +++ b/MineSharp.Core/MineSharp.Core.csproj @@ -1,4 +1,4 @@ - + enable @@ -24,13 +24,13 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - - - + + + + - - + + True diff --git a/Components/MineSharp.Protocol/Packets/ISerializable.cs b/MineSharp.Core/Serialization/ISerializable.cs similarity index 89% rename from Components/MineSharp.Protocol/Packets/ISerializable.cs rename to MineSharp.Core/Serialization/ISerializable.cs index dbd76201..e5b535e2 100644 --- a/Components/MineSharp.Protocol/Packets/ISerializable.cs +++ b/MineSharp.Core/Serialization/ISerializable.cs @@ -1,7 +1,6 @@ using MineSharp.Core.Common; -using MineSharp.Data; -namespace MineSharp.Protocol.Packets; +namespace MineSharp.Core.Serialization; /// /// Interface for serializing and deserializing objects from and to @@ -17,7 +16,7 @@ public interface ISerializable : IVersionAwareSerializable public void Write(PacketBuffer buffer); /// - void IVersionAwareSerializable.Write(PacketBuffer buffer, MinecraftData version) + void IVersionAwareSerializable.Write(PacketBuffer buffer, MinecraftVersion version) { Write(buffer); } @@ -30,7 +29,7 @@ void IVersionAwareSerializable.Write(PacketBuffer buffer, MinecraftData versi public static abstract T Read(PacketBuffer buffer); /// - static T IVersionAwareSerializable.Read(PacketBuffer buffer, MinecraftData version) + static T IVersionAwareSerializable.Read(PacketBuffer buffer, MinecraftVersion version) { return T.Read(buffer); } diff --git a/Components/MineSharp.Protocol/Packets/IVersionAwareSerializable.cs b/MineSharp.Core/Serialization/IVersionAwareSerializable.cs similarity index 84% rename from Components/MineSharp.Protocol/Packets/IVersionAwareSerializable.cs rename to MineSharp.Core/Serialization/IVersionAwareSerializable.cs index 352e0a91..d9473a5a 100644 --- a/Components/MineSharp.Protocol/Packets/IVersionAwareSerializable.cs +++ b/MineSharp.Core/Serialization/IVersionAwareSerializable.cs @@ -1,7 +1,6 @@ using MineSharp.Core.Common; -using MineSharp.Data; -namespace MineSharp.Protocol.Packets; +namespace MineSharp.Core.Serialization; /// /// Interface for serializing and deserializing objects from and to @@ -15,7 +14,7 @@ public interface IVersionAwareSerializable where T : IVersionAwareSeriali /// /// /// - public void Write(PacketBuffer buffer, MinecraftData version); + public void Write(PacketBuffer buffer, MinecraftVersion version); /// /// Read the object from the buffer @@ -23,5 +22,5 @@ public interface IVersionAwareSerializable where T : IVersionAwareSeriali /// /// /// - public static abstract T Read(PacketBuffer buffer, MinecraftData version); + public static abstract T Read(PacketBuffer buffer, MinecraftVersion version); } diff --git a/MineSharp.Core/Common/NbtExtensions.cs b/MineSharp.Core/Serialization/NbtExtensions.cs similarity index 93% rename from MineSharp.Core/Common/NbtExtensions.cs rename to MineSharp.Core/Serialization/NbtExtensions.cs index 3e3ba0bb..46998c48 100644 --- a/MineSharp.Core/Common/NbtExtensions.cs +++ b/MineSharp.Core/Serialization/NbtExtensions.cs @@ -1,6 +1,7 @@ using fNbt; +using MineSharp.Core.Common; -namespace MineSharp.Core.Common; +namespace MineSharp.Core.Serialization; /// /// Provides extension methods for NbtCompound. diff --git a/MineSharp.Core/Common/PacketBuffer.cs b/MineSharp.Core/Serialization/PacketBuffer.cs similarity index 97% rename from MineSharp.Core/Common/PacketBuffer.cs rename to MineSharp.Core/Serialization/PacketBuffer.cs index b4e736f0..abb81825 100644 --- a/MineSharp.Core/Common/PacketBuffer.cs +++ b/MineSharp.Core/Serialization/PacketBuffer.cs @@ -3,10 +3,11 @@ using System.Text; using System.Text.RegularExpressions; using fNbt; +using MineSharp.Core.Common; using MineSharp.Core.Common.Blocks; using MineSharp.Core.Exceptions; -namespace MineSharp.Core.Common; +namespace MineSharp.Core.Serialization; /// /// Read and write values from and to a byte buffer. @@ -383,7 +384,7 @@ public NbtCompound ReadNbtCompound() public BlockEntity ReadBlockEntity() { var packedXz = ReadByte(); - var x = (byte)((packedXz >> 4) & 0xF); + var x = (byte)(packedXz >> 4 & 0xF); var z = (byte)(packedXz & 0xF); var y = ReadShort(); var type = ReadVarInt(); @@ -533,7 +534,7 @@ public static void WriteVarInt(Stream stream, int value) return; } - stream.WriteByte((byte)((value & 0x7F) | 0x80)); + stream.WriteByte((byte)(value & 0x7F | 0x80)); value >>>= 7; } } @@ -547,7 +548,7 @@ public void WriteVarLong(int value) { while ((value & ~0x7F) != 0x00) { - buffer.WriteByte((byte)((value & 0xFF) | 0x80)); + buffer.WriteByte((byte)(value & 0xFF | 0x80)); value >>>= 7; } @@ -615,7 +616,7 @@ public void WriteOptionalNbt(NbtTag? tag) public void WriteBlockEntity(BlockEntity entity) { - var packedXz = (byte)(((entity.X << 4) & 0xF) | (entity.Z & 0xF)); + var packedXz = (byte)(entity.X << 4 & 0xF | entity.Z & 0xF); WriteByte(packedXz); WriteShort(entity.Y); WriteVarInt(entity.Type); diff --git a/MineSharp.Core/Common/RegexHelper.cs b/MineSharp.Core/Serialization/RegexHelper.cs similarity index 95% rename from MineSharp.Core/Common/RegexHelper.cs rename to MineSharp.Core/Serialization/RegexHelper.cs index 0f39988c..1835b23d 100644 --- a/MineSharp.Core/Common/RegexHelper.cs +++ b/MineSharp.Core/Serialization/RegexHelper.cs @@ -1,6 +1,6 @@ using System.Text.RegularExpressions; -namespace MineSharp.Core.Common; +namespace MineSharp.Core.Serialization; /// /// Provides helper methods for working with regular expressions. From c062387248266fe8a8ca86242dcd1ae47d24c6a6 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 02:02:54 +0200 Subject: [PATCH 39/73] made Attribute and Modifier ISerializable --- MineSharp.Core/Common/Entities/Attributes/Attribute.cs | 4 +++- MineSharp.Core/Common/Entities/Attributes/Modifier.cs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/MineSharp.Core/Common/Entities/Attributes/Attribute.cs b/MineSharp.Core/Common/Entities/Attributes/Attribute.cs index 9dfadc2e..d9c02492 100644 --- a/MineSharp.Core/Common/Entities/Attributes/Attribute.cs +++ b/MineSharp.Core/Common/Entities/Attributes/Attribute.cs @@ -6,7 +6,7 @@ namespace MineSharp.Core.Common.Entities.Attributes; /// /// Entity Attribute /// -public sealed record Attribute +public sealed record Attribute : ISerializable { /// /// Create a new Attribute @@ -76,6 +76,7 @@ public void RemoveModifier(Uuid uuid) Modifiers.Remove(uuid); } + /// public void Write(PacketBuffer buffer) { buffer.WriteIdentifier(Key); @@ -83,6 +84,7 @@ public void Write(PacketBuffer buffer) buffer.WriteVarIntArray(Modifiers.Values, (buffer, modifier) => modifier.Write(buffer)); } + /// public static Attribute Read(PacketBuffer buffer) { var key = buffer.ReadIdentifier(); diff --git a/MineSharp.Core/Common/Entities/Attributes/Modifier.cs b/MineSharp.Core/Common/Entities/Attributes/Modifier.cs index d47d5cc7..438be1d6 100644 --- a/MineSharp.Core/Common/Entities/Attributes/Modifier.cs +++ b/MineSharp.Core/Common/Entities/Attributes/Modifier.cs @@ -8,8 +8,9 @@ namespace MineSharp.Core.Common.Entities.Attributes; /// The uuid associated with this Modifier. This is a constant value from Minecraft java. /// /// -public sealed record Modifier(Uuid Uuid, double Amount, ModifierOp Operation) +public sealed record Modifier(Uuid Uuid, double Amount, ModifierOp Operation) : ISerializable { + /// public void Write(PacketBuffer buffer) { buffer.WriteUuid(Uuid); @@ -17,6 +18,7 @@ public void Write(PacketBuffer buffer) buffer.WriteByte((byte)Operation); } + /// public static Modifier Read(PacketBuffer buffer) { var uuid = buffer.ReadUuid(); From 87d1b5ef31894b8675dfd98eb5436606aa4ea302 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 02:39:57 +0200 Subject: [PATCH 40/73] fixed bug in Identifier.Equals and added EqualsStrict --- MineSharp.Core/Common/Identifier.cs | 31 +++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/MineSharp.Core/Common/Identifier.cs b/MineSharp.Core/Common/Identifier.cs index cedf8977..0670079e 100644 --- a/MineSharp.Core/Common/Identifier.cs +++ b/MineSharp.Core/Common/Identifier.cs @@ -69,7 +69,13 @@ public Identifier ToCompleteIdentifier() return HasNamespace ? this : new Identifier(DefaultNamespace, Name); } - /// + /// + /// Determines whether the specified is equal to the current . + /// The comparison uses the default namespace if none is specified. + /// + /// The to compare with the current . + /// true if the specified is equal to the current ; otherwise, false. + /// public bool Equals(Identifier? other) { if (other is null) @@ -83,7 +89,28 @@ public bool Equals(Identifier? other) var @namespace = HasNamespace ? Namespace : DefaultNamespace; var otherNamespace = other.HasNamespace ? other.Namespace : DefaultNamespace; - return Namespace == otherNamespace && Name == other.Name; + return @namespace == otherNamespace && Name == other.Name; + } + + /// + /// Determines whether the specified is equal to the current . + /// In contrast to this comparison is strict and does not use the default namespace if none is specified. + /// + /// The to compare with the current . + /// true if the specified is equal to the current ; otherwise, false. + /// + public bool EqualsStrict(Identifier? other) + { + if (other is null) + { + return false; + } + if (ReferenceEquals(this, other)) + { + return true; + } + + return Namespace == other.Namespace && Name == other.Name; } /// From b512ad33bbf8820caf19161a1e1bd147e08c4ba1 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 02:44:54 +0200 Subject: [PATCH 41/73] improved exception message in Identifier.Parse --- MineSharp.Core/Common/Identifier.cs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/MineSharp.Core/Common/Identifier.cs b/MineSharp.Core/Common/Identifier.cs index 0670079e..09d82244 100644 --- a/MineSharp.Core/Common/Identifier.cs +++ b/MineSharp.Core/Common/Identifier.cs @@ -137,11 +137,22 @@ public override string ToString() /// Thrown when the string format is invalid. public static Identifier Parse(string identifierString) { - if (!TryParse(identifierString, out var identifier)) + var parseError = TryParseInternal(identifierString, out var identifier); + if (parseError != null) { - throw new FormatException("Invalid identifier format"); + throw new FormatException($"Invalid identifier format: {parseError}"); } - return identifier; + return identifier!; + } + + private static string? TryParseInternal(string identifierString, [NotNullWhen(true)] out Identifier? identifier) + { + var colonIndex = identifierString.IndexOf(':'); + if (colonIndex == -1) + { + return TryCreateInternal(NoNamespace, identifierString, out identifier); + } + return TryCreateInternal(identifierString.Substring(0, colonIndex), identifierString.Substring(colonIndex + 1), out identifier); } /// @@ -152,12 +163,7 @@ public static Identifier Parse(string identifierString) /// true if parsing is successful; otherwise, false. public static bool TryParse(string identifierString, [NotNullWhen(true)] out Identifier? identifier) { - var colonIndex = identifierString.IndexOf(':'); - if (colonIndex == -1) - { - return TryCreate(NoNamespace, identifierString, out identifier); - } - return TryCreate(identifierString.Substring(0, colonIndex), identifierString.Substring(colonIndex + 1), out identifier); + return TryParseInternal(identifierString, out identifier) == null; } private static string? TryCreateInternal(string @namespace, string name, out Identifier? identifier) From 6c33c6e915265c20db6f43fb12510736013df7a6 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 13:40:18 +0200 Subject: [PATCH 42/73] fixed Identifier parsing logic --- MineSharp.Core/Common/Identifier.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MineSharp.Core/Common/Identifier.cs b/MineSharp.Core/Common/Identifier.cs index 09d82244..588d1762 100644 --- a/MineSharp.Core/Common/Identifier.cs +++ b/MineSharp.Core/Common/Identifier.cs @@ -147,11 +147,22 @@ public static Identifier Parse(string identifierString) private static string? TryParseInternal(string identifierString, [NotNullWhen(true)] out Identifier? identifier) { + if (string.IsNullOrEmpty(identifierString)) + { + identifier = Empty; + return null; + } + var colonIndex = identifierString.IndexOf(':'); if (colonIndex == -1) { return TryCreateInternal(NoNamespace, identifierString, out identifier); } + else if (colonIndex == 0 || colonIndex == identifierString.Length - 1) + { + identifier = null; + return "Colon must not be at the very start or end"; + } return TryCreateInternal(identifierString.Substring(0, colonIndex), identifierString.Substring(colonIndex + 1), out identifier); } From e8237b7f6573c27e2b231cb27882ff16172cfea6 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 15:02:00 +0200 Subject: [PATCH 43/73] created and implemented IAsyncWorld --- Components/MineSharp.World/AbstractWorld.cs | 192 +++++++++++++++++--- Components/MineSharp.World/IAsyncWorld.cs | 78 ++++++++ 2 files changed, 248 insertions(+), 22 deletions(-) create mode 100644 Components/MineSharp.World/IAsyncWorld.cs diff --git a/Components/MineSharp.World/AbstractWorld.cs b/Components/MineSharp.World/AbstractWorld.cs index ccf06774..48af62a8 100644 --- a/Components/MineSharp.World/AbstractWorld.cs +++ b/Components/MineSharp.World/AbstractWorld.cs @@ -18,7 +18,7 @@ namespace MineSharp.World; /// /// /// -public abstract class AbstractWorld(MinecraftData data, DimensionInfo dimensionInfo) : IWorld +public abstract class AbstractWorld(MinecraftData data, DimensionInfo dimensionInfo) : IWorld, IAsyncWorld { private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); @@ -39,6 +39,16 @@ public abstract class AbstractWorld(MinecraftData data, DimensionInfo dimensionI /// protected ConcurrentDictionary Chunks = new(); + /// + /// A dictionary that holds for chunks that are yet to be loaded + /// but are requested by some async method in this class. + /// + /// + /// Implementation Note: This could also be done using the event, but this way + /// has less overhead and is more robust. Since the user might remove the event listener. + /// + protected ConcurrentDictionary> ChunkLoadAwaiters = new(); + /// public int MaxY => DimensionInfo.WorldMaxY; @@ -100,20 +110,32 @@ public IChunk GetChunkAt(ChunkCoordinates coordinates) [Pure] public bool IsChunkLoaded(ChunkCoordinates coordinates) { - return IsChunkLoaded(coordinates, out _); + return Chunks.ContainsKey(coordinates); } /// public void LoadChunk(IChunk chunk) { - if (IsChunkLoaded(chunk.Coordinates, out var oldChunk)) + IChunk? oldChunk = null; + // to be thread-safe, we need to use AddOrUpdate + if (Chunks.AddOrUpdate(chunk.Coordinates, chunk, (key, oldValue) => + { + oldChunk = oldValue; + return chunk; + }) != chunk) + { + throw new Exception($"Failed to update chunk at {chunk.Coordinates}. This should never happen."); + } + + if (oldChunk != null) { oldChunk.OnBlockUpdated -= OnChunkBlockUpdate; - Chunks[chunk.Coordinates] = chunk; } - else + + // we complete the chunk load awaiter before firing the events + if (ChunkLoadAwaiters.TryRemove(chunk.Coordinates, out var tcs)) { - Chunks.TryAdd(chunk.Coordinates, chunk); + tcs.SetResult(chunk); } chunk.OnBlockUpdated += OnChunkBlockUpdate; @@ -138,18 +160,41 @@ public void UnloadChunk(ChunkCoordinates coordinates) /// public abstract bool IsOutOfMap(Position position); + /// + /// Get a block that represents the out of map block at the given position. + /// If the position is not out of map, this method returns null. + /// + /// + /// + private Block? GetOutOfMapBlock(Position position) + { + if (IsOutOfMap(position)) + { + return new(outOfMapBlock, outOfMapBlock.DefaultState, position); + } + return null; + } + /// public bool IsBlockLoaded(Position position, [NotNullWhen(true)] out IChunk? chunk) { return Chunks.TryGetValue(ToChunkCoordinates(position), out chunk); } + private Block GetBlockFromChunk(Position position, IChunk chunk) + { + var relative = ToChunkPosition(position); + var blockState = chunk.GetBlockAt(relative); + return new Block(Data.Blocks.ByState(blockState)!, blockState, position); + } + /// public Block GetBlockAt(Position position) { - if (IsOutOfMap(position)) + var block = GetOutOfMapBlock(position); + if (block != null) { - return new(outOfMapBlock, outOfMapBlock.DefaultState, position); + return block; } if (!IsBlockLoaded(position, out var chunk)) @@ -157,18 +202,17 @@ public Block GetBlockAt(Position position) throw new ChunkNotLoadedException($"Block at {position} is not loaded."); } - var relative = ToChunkPosition(position); - var blockState = chunk.GetBlockAt(relative); - var block = new Block( - Data.Blocks.ByState(blockState)!, - blockState, - position); - return block; + return GetBlockFromChunk(position, chunk); } /// public void SetBlock(Block block) { + if (IsOutOfMap(block.Position)) + { + throw new InvalidOperationException("Cannot set block at out of map position."); + } + if (!IsBlockLoaded(block.Position, out var chunk)) { throw new ChunkNotLoadedException($"Block at {block.Position} is not loaded."); @@ -181,6 +225,11 @@ public void SetBlock(Block block) /// public Biome GetBiomeAt(Position position) { + if (IsOutOfMap(position)) + { + throw new InvalidOperationException("Cannot get biome at out of map position."); + } + if (!IsBlockLoaded(position, out var chunk)) { throw new ChunkNotLoadedException($"Position {position} is not loaded."); @@ -240,13 +289,6 @@ protected void MutateToWorldPosition(ChunkCoordinates coordinates, MutablePositi position.Set(position.X + dx, position.Y, position.Z + dz); } - /// - [Pure] - protected bool IsChunkLoaded(ChunkCoordinates coordinates, [NotNullWhen(true)] out IChunk? chunk) - { - return Chunks.TryGetValue(coordinates, out chunk); - } - private void OnChunkBlockUpdate(IChunk chunk, int state, Position position) { var worldPosition = ToWorldPosition(chunk.Coordinates, position); @@ -264,4 +306,110 @@ private int NonNegativeMod(int x, int m) return v; } + + #region IAsyncWorld + + private Task RegisterChunkAwaiter(ChunkCoordinates coordinates) + { + var tcs = ChunkLoadAwaiters.GetOrAdd(coordinates, _ => new TaskCompletionSource()); + return tcs.Task; + } + + /// + public Task GetChunkAtAsync(ChunkCoordinates coordinates) + { + if (Chunks.TryGetValue(coordinates, out var chunk)) + { + return Task.FromResult(chunk); + } + + // If the chunk is not loaded, we need to wait for it to be loaded + return RegisterChunkAwaiter(coordinates); + } + + private Task GetChunkForBlockPosAsync(Position position) + { + return GetChunkAtAsync(ToChunkCoordinates(position)); + } + + /// + public Task GetBlockAtAsync(Position position) + { + var block = GetOutOfMapBlock(position); + if (block != null) + { + return Task.FromResult(block); + } + + var blockTask = GetChunkForBlockPosAsync(position) + .ContinueWith(chunkTask => + { + var chunk = chunkTask.Result; + return GetBlockFromChunk(position, chunk); + }, TaskContinuationOptions.OnlyOnRanToCompletion); + return blockTask; + } + + /// + public Task SetBlockAsync(Block block) + { + if (IsOutOfMap(block.Position)) + { + throw new InvalidOperationException("Cannot set block at out of map position."); + } + + var blockTask = GetChunkForBlockPosAsync(block.Position) + .ContinueWith(chunkTask => + { + var chunk = chunkTask.Result; + var relative = ToChunkPosition(block.Position); + chunk.SetBlockAt(block.State, relative); + }, TaskContinuationOptions.OnlyOnRanToCompletion); + return blockTask; + } + + /// + public Task GetBiomeAtAsync(Position position) + { + if (IsOutOfMap(position)) + { + throw new InvalidOperationException("Cannot get biome at out of map position."); + } + + var biomeTask = GetChunkForBlockPosAsync(position) + .ContinueWith(chunkTask => + { + var chunk = chunkTask.Result; + var relative = ToChunkPosition(position); + return chunk.GetBiomeAt(relative); + }, TaskContinuationOptions.OnlyOnRanToCompletion); + return biomeTask; + } + + /// + public Task SetBiomeAtAsync(Position position, Biome biome) + { + if (IsOutOfMap(position)) + { + throw new InvalidOperationException("Cannot set biome at out of map position."); + } + + var biomeTask = GetChunkForBlockPosAsync(position) + .ContinueWith(chunkTask => + { + var chunk = chunkTask.Result; + var relative = ToChunkPosition(position); + chunk.SetBiomeAt(relative, biome); + }, TaskContinuationOptions.OnlyOnRanToCompletion); + return biomeTask; + } + + /// + public IAsyncEnumerable FindBlocksAsync(BlockType type, IWorldIterator iterator, int? maxCount = null) + { + // can be implemented once FindBlocks is implemented + throw new NotImplementedException(); + } + + #endregion } diff --git a/Components/MineSharp.World/IAsyncWorld.cs b/Components/MineSharp.World/IAsyncWorld.cs new file mode 100644 index 00000000..4fed4174 --- /dev/null +++ b/Components/MineSharp.World/IAsyncWorld.cs @@ -0,0 +1,78 @@ +using MineSharp.Core.Common.Biomes; +using MineSharp.Core.Common.Blocks; +using MineSharp.Core.Geometry; +using MineSharp.World.Chunks; +using MineSharp.World.Iterators; + +namespace MineSharp.World; + +/// +/// Interface for creating a Minecraft world +/// +public interface IAsyncWorld : IWorld +{ + /// + /// Return the chunk at the given chunk position. + /// Waits for the chunk to be loaded if it's not loaded yet. + /// + /// + /// + public Task GetChunkAtAsync(ChunkCoordinates coordinates); + + /// + /// Return the block at the given position. + /// Waits for the chunk the block is in to be loaded if it's not loaded yet. + /// + /// + /// + public Task GetBlockAtAsync(Position position); + + /// + /// Set the block at the given position. + /// Waits for the chunk the block is in to be loaded if it's not loaded yet. + /// + /// + public Task SetBlockAsync(Block block); + + /// + /// Get the biome at the given position. + /// Waits for the chunk the block is in to be loaded if it's not loaded yet. + /// + /// + /// + public Task GetBiomeAtAsync(Position position); + + /// + /// Set the biome at the given position. + /// Waits for the chunk the block is in to be loaded if it's not loaded yet. + /// + /// + /// + public Task SetBiomeAtAsync(Position position, Biome biome); + + /// + /// Query the world for a block type. + /// Waits for the chunks the block are in to be loaded if they are not loaded yet. + /// + /// + /// + /// + /// + public IAsyncEnumerable FindBlocksAsync(BlockType type, IWorldIterator iterator, int? maxCount = null); + + /// + /// Find a block of type . + /// Waits for the chunks the block are in to be loaded if they are not loaded yet. + /// + /// + /// + /// + public async Task FindBlockAsync(BlockType type, IWorldIterator iterator) + { + await foreach (var block in FindBlocksAsync(type, iterator, 1)) + { + return block; + } + return null; + } +} From 6cf904b80a2f5984b3b04ca483e08ffc9e8d49db Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 15:15:02 +0200 Subject: [PATCH 44/73] using new async methods from IAsyncWorld to prevent race conditions --- Components/MineSharp.World/WorldVersion.cs | 2 +- MineSharp.Bot/Plugins/WorldPlugin.cs | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Components/MineSharp.World/WorldVersion.cs b/Components/MineSharp.World/WorldVersion.cs index f5635d65..d6392f29 100644 --- a/Components/MineSharp.World/WorldVersion.cs +++ b/Components/MineSharp.World/WorldVersion.cs @@ -16,7 +16,7 @@ public static class WorldVersion /// /// /// - public static IWorld CreateWorld(MinecraftData version, Dimension dimension) + public static IAsyncWorld CreateWorld(MinecraftData version, Dimension dimension) { if (version.Version >= DimensionInfo.MinecraftVersionMajor118) { diff --git a/MineSharp.Bot/Plugins/WorldPlugin.cs b/MineSharp.Bot/Plugins/WorldPlugin.cs index 7108888d..52a255b8 100644 --- a/MineSharp.Bot/Plugins/WorldPlugin.cs +++ b/MineSharp.Bot/Plugins/WorldPlugin.cs @@ -42,7 +42,7 @@ public WorldPlugin(MineSharpBot bot) : base(bot) /// /// The world of the Minecraft server /// - public IWorld? World { get; private set; } + public IAsyncWorld? World { get; private set; } /// protected override async Task Init() @@ -321,15 +321,14 @@ private Task HandleBlockUpdatePacket(BlockUpdatePacket packet) var blockInfo = Bot.Data.Blocks.ByState(packet.StateId)!; var block = new Block(blockInfo, packet.StateId, packet.Location); - World!.SetBlock(block); - return Task.CompletedTask; + return World!.SetBlockAsync(block); } - private Task HandleMultiBlockUpdatePacket(MultiBlockUpdatePacket packet) + private async Task HandleMultiBlockUpdatePacket(MultiBlockUpdatePacket packet) { if (!IsEnabled) { - return Task.CompletedTask; + return; } var sectionX = packet.ChunkSection >> (64 - 22); // first 22 bits @@ -337,7 +336,7 @@ private Task HandleMultiBlockUpdatePacket(MultiBlockUpdatePacket packet) var sectionY = (packet.ChunkSection << (22 + 22)) >> (64 - 20); // last 20 bits var coords = new ChunkCoordinates((int)sectionX, (int)sectionZ); - var chunk = World!.GetChunkAt(coords); + var chunk = await World!.GetChunkAtAsync(coords); foreach (var l in packet.Blocks) { @@ -348,8 +347,6 @@ private Task HandleMultiBlockUpdatePacket(MultiBlockUpdatePacket packet) chunk.SetBlockAt(stateId, new(blockX, blockY, blockZ)); } - - return Task.CompletedTask; } private Task HandleChunkBatchStartPacket(ChunkBatchStartPacket packet) From 2ec339958855d8c449c53c851e55fb561509b922 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 20:31:35 +0200 Subject: [PATCH 45/73] fixed low chance race condition in AbstractWorld.RegisterChunkAwaiter --- Components/MineSharp.World/AbstractWorld.cs | 16 +++++++++++++++- Components/MineSharp.World/IWorld.cs | 10 ++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Components/MineSharp.World/AbstractWorld.cs b/Components/MineSharp.World/AbstractWorld.cs index 48af62a8..bbadc34c 100644 --- a/Components/MineSharp.World/AbstractWorld.cs +++ b/Components/MineSharp.World/AbstractWorld.cs @@ -96,9 +96,10 @@ public Position ToWorldPosition(ChunkCoordinates coordinates, Position position) } /// + [Pure] public IChunk GetChunkAt(ChunkCoordinates coordinates) { - if (!Chunks.TryGetValue(coordinates, out var chunk)) + if (!TryGetChunkAt(coordinates, out var chunk)) { throw new ChunkNotLoadedException($"The chunk at {coordinates} is not loaded."); } @@ -106,6 +107,13 @@ public IChunk GetChunkAt(ChunkCoordinates coordinates) return chunk; } + /// + [Pure] + public bool TryGetChunkAt(ChunkCoordinates coordinates, [NotNullWhen(true)] out IChunk? chunk) + { + return Chunks.TryGetValue(coordinates, out chunk); + } + /// [Pure] public bool IsChunkLoaded(ChunkCoordinates coordinates) @@ -312,6 +320,12 @@ private int NonNegativeMod(int x, int m) private Task RegisterChunkAwaiter(ChunkCoordinates coordinates) { var tcs = ChunkLoadAwaiters.GetOrAdd(coordinates, _ => new TaskCompletionSource()); + // because there is a small chance that the chunk was loaded before we were able to add the awaiter + // we need to check again if the chunk is loaded + if (TryGetChunkAt(coordinates, out var chunk)) + { + tcs.SetResult(chunk); + } return tcs.Task; } diff --git a/Components/MineSharp.World/IWorld.cs b/Components/MineSharp.World/IWorld.cs index 2dc98a84..e58296e6 100644 --- a/Components/MineSharp.World/IWorld.cs +++ b/Components/MineSharp.World/IWorld.cs @@ -72,6 +72,16 @@ public interface IWorld /// public IChunk GetChunkAt(ChunkCoordinates coordinates); + /// + /// Try to get the chunk at the given chunk coordinates. + /// This method does the same as but does not throw an exception. + /// Instead it returns a boolean indicating the success of the operation. + /// + /// + /// + /// + public bool TryGetChunkAt(ChunkCoordinates coordinates, [NotNullWhen(true)] out IChunk? chunk); + /// /// Whether the chunk at the given coordinates is loaded /// From 1ad3dc91d3d427e474ecc28a91ba2f0e7cd13da3 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 20:33:16 +0200 Subject: [PATCH 46/73] improved Uuid type using MemoryMarshal --- MineSharp.Core/Common/UUID.cs | 132 ++++++++++--------- MineSharp.Core/Serialization/PacketBuffer.cs | 27 +++- 2 files changed, 93 insertions(+), 66 deletions(-) diff --git a/MineSharp.Core/Common/UUID.cs b/MineSharp.Core/Common/UUID.cs index 4ee6a0bf..53ee67f8 100644 --- a/MineSharp.Core/Common/UUID.cs +++ b/MineSharp.Core/Common/UUID.cs @@ -1,4 +1,7 @@ -namespace MineSharp.Core.Common; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace MineSharp.Core.Common; // Thanks to MrZoidberg // https://gist.github.com/MrZoidberg/9bac07cf3f5aa5896f75 @@ -7,17 +10,12 @@ /// Represents an immutable Java universally unique identifier (UUID). /// A UUID represents a 128-bit value. /// -public struct Uuid : IEquatable +public readonly struct Uuid : IEquatable { /// /// Empty UUID /// - public static readonly Uuid Empty; - - static Uuid() - { - Empty = new(); - } + public static readonly Uuid Empty = new(); /// /// Constructs a new UUID using the specified data. @@ -33,32 +31,41 @@ public Uuid(long mostSignificantBits, long leastSignificantBits) /// /// Constructs a new UUID using the specified data. /// - /// Bytes array that represents the UUID. - public Uuid(byte[] b) + /// Bytes array that represents the UUID. Must be 16 bytes in big-endian order. + public Uuid(ReadOnlySpan bytes) { - if (b == null) + if (bytes.Length != 16) { - throw new ArgumentNullException("b"); + throw new ArgumentException("Length of the UUID byte array should be 16"); } - if (b.Length != 16) + Span byteSpan = MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref this, 1)); + if (BitConverter.IsLittleEndian) { - throw new ArgumentException("Length of the UUID byte array should be 16"); + bytes.CopyTo(byteSpan); + byteSpan.Reverse(); } - - MostSignificantBits = BitConverter.ToInt64(b, 0); - LeastSignificantBits = BitConverter.ToInt64(b, 8); + else + { + // architecure is big-endian but our files are little-endian ordered + // so we need to reverse the longs + var longSpan = MemoryMarshal.Cast(byteSpan); + longSpan.Reverse(); + } + // since we do these operations in-place, we are done here } + // The order of the most significant and least significant fields is important + // when serializing and deserializing the UUID as unmanaged data types (little-endian) /// /// The least significant 64 bits of this UUID's 128 bit value. /// - public long LeastSignificantBits { get; } + public readonly long LeastSignificantBits; /// /// The most significant 64 bits of this UUID's 128 bit value. /// - public long MostSignificantBits { get; } + public readonly long MostSignificantBits; /// /// Returns a value that indicates whether this instance is equal to a specified @@ -68,13 +75,11 @@ public Uuid(byte[] b) /// true if o is a that has the same value as this instance; otherwise, false. public override bool Equals(object? obj) { - if (!(obj is Uuid)) + if (!(obj is Uuid uuid)) { return false; } - var uuid = (Uuid)obj; - return Equals(uuid); } @@ -86,7 +91,7 @@ public override bool Equals(object? obj) /// true if is equal to this instance; otherwise, false. public bool Equals(Uuid uuid) { - return MostSignificantBits == uuid.MostSignificantBits && LeastSignificantBits == uuid.LeastSignificantBits; + return LeastSignificantBits == uuid.LeastSignificantBits && MostSignificantBits == uuid.MostSignificantBits; } /// @@ -95,7 +100,8 @@ public bool Equals(Uuid uuid) /// The hash code for this instance. public override int GetHashCode() { - return ((Guid)this).GetHashCode(); + // our hash code must not be compatible with Guid.GetHashCode so we do it ourselves + return HashCode.Combine(LeastSignificantBits, MostSignificantBits); } /// @@ -112,25 +118,47 @@ public override string ToString() GetDigits(LeastSignificantBits, 12); } + private ReadOnlySpan AsByteSpan() + { + return MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in this), 1)); + } + /// - /// Returns a 16-element byte array that contains the value of this instance. + /// Writes the UUID to the specified destination span in big-endian order. + /// + /// The destination span to write the UUID to. + public void WriteTo(Span destination) + { + if (destination.Length != 16) + { + throw new ArgumentException("Destination span must be 16 bytes long"); + } + + var byteSpan = AsByteSpan(); + + if (BitConverter.IsLittleEndian) + { + byteSpan.CopyTo(destination); + destination.Reverse(); + } + else + { + // architecture is big-endian but our fields are little-endian ordered + // so we need to reverse the longs + var longSpan = MemoryMarshal.Cast(destination); + longSpan.Reverse(); + } + } + + /// + /// Returns a 16-element byte array that contains the value of this instance in big-endian. /// /// A 16-element byte array public byte[] ToByteArray() { - var uuidMostSignificantBytes = BitConverter.GetBytes(MostSignificantBits); - var uuidLeastSignificantBytes = BitConverter.GetBytes(LeastSignificantBits); - byte[] bytes = - { - uuidMostSignificantBytes[0], uuidMostSignificantBytes[1], uuidMostSignificantBytes[2], - uuidMostSignificantBytes[3], uuidMostSignificantBytes[4], uuidMostSignificantBytes[5], - uuidMostSignificantBytes[6], uuidMostSignificantBytes[7], uuidLeastSignificantBytes[0], - uuidLeastSignificantBytes[1], uuidLeastSignificantBytes[2], uuidLeastSignificantBytes[3], - uuidLeastSignificantBytes[4], uuidLeastSignificantBytes[5], uuidLeastSignificantBytes[6], - uuidLeastSignificantBytes[7] - }; - - return bytes; + var destinationBytes = new byte[16]; + WriteTo(destinationBytes); + return destinationBytes; } /// Indicates whether the values of two specified objects are equal. @@ -161,19 +189,8 @@ public static explicit operator Guid(Uuid uuid) return default; } - var uuidMostSignificantBytes = BitConverter.GetBytes(uuid.MostSignificantBits); - var uuidLeastSignificantBytes = BitConverter.GetBytes(uuid.LeastSignificantBits); - byte[] guidBytes = - { - uuidMostSignificantBytes[4], uuidMostSignificantBytes[5], uuidMostSignificantBytes[6], - uuidMostSignificantBytes[7], uuidMostSignificantBytes[2], uuidMostSignificantBytes[3], - uuidMostSignificantBytes[0], uuidMostSignificantBytes[1], uuidLeastSignificantBytes[7], - uuidLeastSignificantBytes[6], uuidLeastSignificantBytes[5], uuidLeastSignificantBytes[4], - uuidLeastSignificantBytes[3], uuidLeastSignificantBytes[2], uuidLeastSignificantBytes[1], - uuidLeastSignificantBytes[0] - }; - - return new(guidBytes); + var byteSpan = uuid.AsByteSpan(); + return new(byteSpan, true); } /// Converts a to an . @@ -186,16 +203,9 @@ public static implicit operator Uuid(Guid value) return default; } - var guidBytes = value.ToByteArray(); - byte[] uuidBytes = - { - guidBytes[6], guidBytes[7], guidBytes[4], guidBytes[5], guidBytes[0], guidBytes[1], guidBytes[2], - guidBytes[3], guidBytes[15], guidBytes[14], guidBytes[13], guidBytes[12], guidBytes[11], guidBytes[10], - guidBytes[9], guidBytes[8] - }; - - - return new(BitConverter.ToInt64(uuidBytes, 0), BitConverter.ToInt64(uuidBytes, 8)); + Span byteSpan = stackalloc byte[16]; + value.TryWriteBytes(byteSpan, true, out _); + return new(byteSpan); } /// diff --git a/MineSharp.Core/Serialization/PacketBuffer.cs b/MineSharp.Core/Serialization/PacketBuffer.cs index abb81825..e75a7efb 100644 --- a/MineSharp.Core/Serialization/PacketBuffer.cs +++ b/MineSharp.Core/Serialization/PacketBuffer.cs @@ -111,6 +111,14 @@ private void EnsureEnoughReadableBytes(int count) #region Reading + /// + /// Read an unmanaged value from the buffer. + /// This works great for signed and unsigned integer primitives. + /// For other value types or custom structs this will likely not work (on some systems). + /// Because this method just reverses the bytes if the system is little endian. + /// + /// The unmanaged type to read. + /// public T Read() where T : unmanaged { @@ -313,9 +321,9 @@ public Identifier ReadIdentifier() [MethodImpl(MethodImplOptions.AggressiveInlining)] public Uuid ReadUuid() { - var l1 = Read(); - var l2 = Read(); - return new(l1, l2); + Span bytes = stackalloc byte[16]; + ReadBytes(bytes); + return new(bytes); } public T[] ReadVarIntArray(Func reader) @@ -435,6 +443,14 @@ public T ReadObject() #region Writing + /// + /// Writes an unmanaged value to the buffer. + /// This works great for signed and unsigned integer primitives. + /// For other value types or custom structs this will likely not work (on some systems). + /// Because this method just reverses the bytes if the system is little endian. + /// + /// The unmanaged type to write. + /// public void Write(T value) where T : unmanaged { @@ -574,8 +590,9 @@ public void WriteIdentifier(Identifier identifier) public void WriteUuid(Uuid value) { - Write(value.MostSignificantBits); - Write(value.LeastSignificantBits); + Span bytes = stackalloc byte[16]; + value.WriteTo(bytes); + WriteBytes(bytes); } public void WriteVarIntArray(ICollection collection, Action writer) From 7bd051ce47f392739f0c2ae31ea103ca6730a89c Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 21:27:44 +0200 Subject: [PATCH 47/73] added ReadPosition and WritePosition methods to PacketBuffer --- .../Clientbound/Play/AcknowledgeBlockChangePacket.cs | 4 ++-- .../Packets/Clientbound/Play/BlockUpdatePacket.cs | 4 ++-- .../Packets/Clientbound/Play/LoginPacket.cs | 6 +++--- .../Packets/Clientbound/Play/RespawnPacket.cs | 4 ++-- .../Packets/Clientbound/Play/SpawnPaintingPacket.cs | 4 ++-- .../Packets/Serverbound/Play/PlaceBlockPacket.cs | 4 ++-- .../Packets/Serverbound/Play/PlayerActionPacket.cs | 6 +++--- .../Packets/Serverbound/Play/UpdateCommandBlock.cs | 4 ++-- MineSharp.Core/Serialization/PacketBuffer.cs | 11 +++++++++++ 9 files changed, 29 insertions(+), 18 deletions(-) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/AcknowledgeBlockChangePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/AcknowledgeBlockChangePacket.cs index 835a3c8d..a3d51fe8 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/AcknowledgeBlockChangePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/AcknowledgeBlockChangePacket.cs @@ -104,7 +104,7 @@ public sealed record PacketBody118(Position Location, int Block, int Status, boo /// public void Write(PacketBuffer buffer) { - buffer.WriteULong(Location.ToULong()); + buffer.WritePosition(Location); buffer.WriteVarInt(Block); buffer.WriteVarInt(Status); buffer.WriteBool(Successful); @@ -114,7 +114,7 @@ public void Write(PacketBuffer buffer) public static IPacketBody Read(PacketBuffer buffer) { return new PacketBody118( - new(buffer.ReadULong()), + buffer.ReadPosition(), buffer.ReadVarInt(), buffer.ReadVarInt(), buffer.ReadBool()); diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockUpdatePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockUpdatePacket.cs index 5358ee85..e74a6d31 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockUpdatePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockUpdatePacket.cs @@ -20,14 +20,14 @@ public sealed record BlockUpdatePacket(Position Location, int StateId) : IPacket /// public void Write(PacketBuffer buffer, MinecraftData version) { - buffer.WriteULong(Location.ToULong()); + buffer.WritePosition(Location); buffer.WriteVarInt(StateId); } /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { - var location = new Position(buffer.ReadULong()); + var location = buffer.ReadPosition(); var stateId = buffer.ReadVarInt(); return new BlockUpdatePacket(location, stateId); } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs index 91b3255f..6d917969 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs @@ -109,7 +109,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) if (HasDeathLocation) { buffer.WriteIdentifier(DeathDimensionName!); - buffer.WriteULong(DeathLocation!.ToULong()); + buffer.WritePosition(DeathLocation!); } if (version.Version.Protocol >= ProtocolVersion.V_1_20) @@ -169,7 +169,7 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) if (hasDeathLocation.Value) { deathDimensionName = buffer.ReadIdentifier(); - deathLocation = new(buffer.ReadULong()); + deathLocation = buffer.ReadPosition(); } } @@ -227,7 +227,7 @@ private static LoginPacket ReadV1_20_2(PacketBuffer buffer, MinecraftData data) if (hasDeathLocation) { deathDimensionName = buffer.ReadIdentifier(); - deathLocation = new(buffer.ReadULong()); + deathLocation = buffer.ReadPosition(); } var portalCooldown = buffer.ReadVarInt(); diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs index dac14bc1..3f1ac620 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs @@ -56,7 +56,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) } buffer.WriteIdentifier(DeathDimensionName!); - buffer.WriteULong(DeathLocation!.ToULong()); + buffer.WritePosition(DeathLocation!); if (version.Version.Protocol >= ProtocolVersion.V_1_20) { @@ -95,7 +95,7 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) if (hasDeathLocation ?? false) { deathDimensionName = buffer.ReadIdentifier(); - deathLocation = new(buffer.ReadULong()); + deathLocation = buffer.ReadPosition(); } } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPaintingPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPaintingPacket.cs index 1d5b9d39..66f4faeb 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPaintingPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnPaintingPacket.cs @@ -33,7 +33,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteVarInt(EntityId); buffer.WriteUuid(EntityUuid); buffer.WriteVarInt(Title); - buffer.WriteULong(Location.ToULong()); + buffer.WritePosition(Location); buffer.WriteSByte(Direction); } @@ -43,7 +43,7 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) var entityId = buffer.ReadVarInt(); var entityUuid = buffer.ReadUuid(); var title = buffer.ReadVarInt(); - var location = new Position(buffer.ReadULong()); + var location = buffer.ReadPosition(); var direction = buffer.ReadSByte(); return new SpawnPaintingPacket(entityId, entityUuid, title, location, direction); } diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlaceBlockPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlaceBlockPacket.cs index 2a3e2cca..adf15fdf 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlaceBlockPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlaceBlockPacket.cs @@ -80,7 +80,7 @@ public PlaceBlockPacket(int hand, Position location, BlockFace direction, float public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteVarInt(Hand); - buffer.WriteULong(Location.ToULong()); + buffer.WritePosition(Location); buffer.WriteVarInt((int)Direction); buffer.WriteFloat(CursorX); buffer.WriteFloat(CursorY); @@ -96,7 +96,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var hand = buffer.ReadVarInt(); - var position = new Position(buffer.ReadULong()); + var position = buffer.ReadPosition(); var direction = buffer.ReadVarInt(); var cursorX = buffer.ReadFloat(); var cursorY = buffer.ReadFloat(); diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerActionPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerActionPacket.cs index ff8290bd..9af23661 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerActionPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PlayerActionPacket.cs @@ -58,7 +58,7 @@ public PlayerActionPacket(int status, Position location, BlockFace face, int? se public void Write(PacketBuffer buffer, MinecraftData version) { buffer.WriteVarInt(Status); - buffer.WriteULong(Location.ToULong()); + buffer.WritePosition(Location); buffer.WriteByte((byte)Face); if (version.Version.Protocol >= ProtocolVersion.V_1_19) @@ -73,14 +73,14 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) { return new PlayerActionPacket( buffer.ReadVarInt(), - new(buffer.ReadULong()), + buffer.ReadPosition(), (BlockFace)buffer.ReadByte(), buffer.ReadVarInt()); } return new PlayerActionPacket( buffer.ReadVarInt(), - new(buffer.ReadULong()), + buffer.ReadPosition(), (BlockFace)buffer.ReadByte()); } } diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/UpdateCommandBlock.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/UpdateCommandBlock.cs index 59300b56..79f2a1af 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/UpdateCommandBlock.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/UpdateCommandBlock.cs @@ -15,7 +15,7 @@ public sealed record UpdateCommandBlock(Position Location, string Command, int M /// public void Write(PacketBuffer buffer, MinecraftData version) { - buffer.WriteULong(Location.ToULong()); + buffer.WritePosition(Location); buffer.WriteString(Command); buffer.WriteVarInt(Mode); buffer.WriteByte(Flags); @@ -25,7 +25,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) public static IPacket Read(PacketBuffer buffer, MinecraftData version) { return new UpdateCommandBlock( - new(buffer.ReadULong()), + buffer.ReadPosition(), buffer.ReadString(), buffer.ReadVarInt(), buffer.ReadByte()); diff --git a/MineSharp.Core/Serialization/PacketBuffer.cs b/MineSharp.Core/Serialization/PacketBuffer.cs index e75a7efb..9d0aafc7 100644 --- a/MineSharp.Core/Serialization/PacketBuffer.cs +++ b/MineSharp.Core/Serialization/PacketBuffer.cs @@ -6,6 +6,7 @@ using MineSharp.Core.Common; using MineSharp.Core.Common.Blocks; using MineSharp.Core.Exceptions; +using MineSharp.Core.Geometry; namespace MineSharp.Core.Serialization; @@ -401,6 +402,11 @@ public BlockEntity ReadBlockEntity() return new(x, y, z, type, nbt); } + public Position ReadPosition() + { + return new Position(ReadULong()); + } + public T? ReadOptional() where T : class { @@ -640,6 +646,11 @@ public void WriteBlockEntity(BlockEntity entity) WriteOptionalNbt(entity.Data); } + public void WritePosition(Position position) + { + WriteULong(position.ToULong()); + } + #endregion #pragma warning restore CS1591 From dff40b9930533cf28697fe5fb1d4a62505fb9af6 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 23:09:35 +0200 Subject: [PATCH 48/73] added error log to GetPacketType in case of exception Somehow sometimes the PacketType can not be found?! Possible race condition --- Data/MineSharp.Data/Protocol/ProtocolData.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Data/MineSharp.Data/Protocol/ProtocolData.cs b/Data/MineSharp.Data/Protocol/ProtocolData.cs index f8c54f29..d1de3aef 100644 --- a/Data/MineSharp.Data/Protocol/ProtocolData.cs +++ b/Data/MineSharp.Data/Protocol/ProtocolData.cs @@ -3,12 +3,15 @@ using MineSharp.Data.Framework; using MineSharp.Data.Framework.Providers; using MineSharp.Data.Internal; +using NLog; namespace MineSharp.Data.Protocol; internal class ProtocolData(IDataProvider provider) : IndexedData(provider), IProtocolData { + private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); + private FrozenDictionary>> idToType = FrozenDictionary>>.Empty; private FrozenDictionary typeToId = FrozenDictionary.Empty; @@ -29,7 +32,15 @@ public PacketType GetPacketType(PacketFlow flow, GameState state, int id) Load(); } - return idToType[flow][state][id]; + try + { + return idToType[flow][state][id]; + } + catch (Exception) + { + Logger.Error("Failed to get PacketType for: flow = {Flow}, state = {State}, id = {Id}", flow, state, id); + throw; + } } protected override void InitializeData(ProtocolDataBlob data) From 371e3364ff263cfe8a8b0df08baa5adc5d7b1ecf Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 23:34:39 +0200 Subject: [PATCH 49/73] fix rare deadlock when tcp stream ends --- Components/MineSharp.Protocol/MinecraftStream.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Components/MineSharp.Protocol/MinecraftStream.cs b/Components/MineSharp.Protocol/MinecraftStream.cs index 795ce7eb..0cc7ff36 100644 --- a/Components/MineSharp.Protocol/MinecraftStream.cs +++ b/Components/MineSharp.Protocol/MinecraftStream.cs @@ -72,10 +72,17 @@ public PacketBuffer ReadPacket() data = new byte[length]; - var read = 0; - while (read < length) + var readRemaining = length; + var readStart = 0; + while (readRemaining > 0) { - read += stream.Read(data, read, length - read); + var read = stream.Read(data, readStart, readRemaining); + if (read == 0) + { + throw new EndOfStreamException(); + } + readStart += read; + readRemaining -= read; } } From 9458e9e234c9f05cb0a2579258610b4d602333af Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 23:55:27 +0200 Subject: [PATCH 50/73] add missing null check when translating text component --- .../Components/TranslatableComponent.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Components/MineSharp.ChatComponent/Components/TranslatableComponent.cs b/Components/MineSharp.ChatComponent/Components/TranslatableComponent.cs index 640135c9..939d1e71 100644 --- a/Components/MineSharp.ChatComponent/Components/TranslatableComponent.cs +++ b/Components/MineSharp.ChatComponent/Components/TranslatableComponent.cs @@ -101,11 +101,16 @@ protected override string GetRawMessage(MinecraftData? data) var with = With.Select(x => x.GetMessage(data)).ToArray(); if (data == null) { - Logger.Warn("Cannot translate message because no minecraft data was provided!"); + Logger.Warn("Cannot translate message because no minecraft data was provided! For: {TranslationKey}", Translation); return string.Join(' ', with); } var rule = data.Language.GetTranslation(Translation)!; + if (rule == null) + { + Logger.Warn("Cannot translate message because no translation string was found! For: {TranslationKey}", Translation); + return string.Join(' ', with); + } return TranslateString(rule, with); } From ac4e6d34e2d85dfb201d4071d3d00088ef2f8f3f Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 8 Aug 2024 23:56:33 +0200 Subject: [PATCH 51/73] fix bug in EnsureOnlyRunOnceAsync that causes faulted tasks not to propagate the exception --- MineSharp.Core/Concurrency/ConcurrencyHelper.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/MineSharp.Core/Concurrency/ConcurrencyHelper.cs b/MineSharp.Core/Concurrency/ConcurrencyHelper.cs index d2991cc6..e2e47c7b 100644 --- a/MineSharp.Core/Concurrency/ConcurrencyHelper.cs +++ b/MineSharp.Core/Concurrency/ConcurrencyHelper.cs @@ -18,11 +18,12 @@ public static class ConcurrencyHelper /// public static EnsureOnlyRunOnceAsyncResult EnsureOnlyRunOnceAsync(Func action, ref Task? taskStore) { - var ret = EnsureOnlyRunOnceAsync(() => + var ret = EnsureOnlyRunOnceAsync(async () => { - var actualTask = action(); + // we need to do the typical async/await because otherwise the exception would be lost and the task will not be faulted + await action(); // return value does mean nothing. Is just used to call the other method. - return actualTask.ContinueWith(_ => true, TaskContinuationOptions.ExecuteSynchronously); + return true; }, // this ref type conversion is safe because all Tasks with return type are also normal Tasks ref Unsafe.As?>(ref taskStore)); From 84fe1f338bca2bbd660ce5ecfca20c641407a3ba Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Fri, 9 Aug 2024 00:14:46 +0200 Subject: [PATCH 52/73] Plugins can now handle cancellation while initializing (fixes deadlock) --- MineSharp.Bot/Plugins/ChatPlugin.cs | 2 +- MineSharp.Bot/Plugins/CraftingPlugin.cs | 2 +- MineSharp.Bot/Plugins/EntityPlugin.cs | 2 +- MineSharp.Bot/Plugins/PhysicsPlugin.cs | 6 +++--- MineSharp.Bot/Plugins/PlayerPlugin.cs | 2 +- MineSharp.Bot/Plugins/Plugin.cs | 2 ++ MineSharp.Bot/Plugins/WindowPlugin.cs | 4 ++-- MineSharp.Bot/Plugins/WorldPlugin.cs | 2 +- 8 files changed, 12 insertions(+), 10 deletions(-) diff --git a/MineSharp.Bot/Plugins/ChatPlugin.cs b/MineSharp.Bot/Plugins/ChatPlugin.cs index 041de4ba..50b528c2 100644 --- a/MineSharp.Bot/Plugins/ChatPlugin.cs +++ b/MineSharp.Bot/Plugins/ChatPlugin.cs @@ -72,7 +72,7 @@ await Bot.Client.SendPacket( )); } - await HandleDeclareCommandsPacket(await initDeclareCommandsPacket); + await HandleDeclareCommandsPacket(await initDeclareCommandsPacket.WaitAsync(Bot.CancellationToken)).WaitAsync(Bot.CancellationToken); } /// diff --git a/MineSharp.Bot/Plugins/CraftingPlugin.cs b/MineSharp.Bot/Plugins/CraftingPlugin.cs index ddf5360b..d21ee879 100644 --- a/MineSharp.Bot/Plugins/CraftingPlugin.cs +++ b/MineSharp.Bot/Plugins/CraftingPlugin.cs @@ -22,7 +22,7 @@ protected override async Task Init() { windowPlugin = Bot.GetPlugin(); - await windowPlugin.WaitForInventory(); + await windowPlugin.WaitForInventory().WaitAsync(Bot.CancellationToken); } /// diff --git a/MineSharp.Bot/Plugins/EntityPlugin.cs b/MineSharp.Bot/Plugins/EntityPlugin.cs index 6d02284f..12a4546c 100644 --- a/MineSharp.Bot/Plugins/EntityPlugin.cs +++ b/MineSharp.Bot/Plugins/EntityPlugin.cs @@ -60,7 +60,7 @@ public EntityPlugin(MineSharpBot bot) : base(bot) protected override async Task Init() { playerPlugin = Bot.GetPlugin(); - await playerPlugin.WaitForInitialization(); + await playerPlugin.WaitForInitialization().WaitAsync(Bot.CancellationToken); } internal void AddEntity(Entity entity) diff --git a/MineSharp.Bot/Plugins/PhysicsPlugin.cs b/MineSharp.Bot/Plugins/PhysicsPlugin.cs index b4f23997..1313f321 100644 --- a/MineSharp.Bot/Plugins/PhysicsPlugin.cs +++ b/MineSharp.Bot/Plugins/PhysicsPlugin.cs @@ -67,11 +67,11 @@ protected override async Task Init() playerPlugin = Bot.GetPlugin(); worldPlugin = Bot.GetPlugin(); - await playerPlugin.WaitForInitialization(); - await worldPlugin.WaitForInitialization(); + await playerPlugin.WaitForInitialization().WaitAsync(Bot.CancellationToken); + await worldPlugin.WaitForInitialization().WaitAsync(Bot.CancellationToken); self = playerPlugin.Self; - await UpdateServerPos(); + await UpdateServerPos().WaitAsync(Bot.CancellationToken); Engine = new(Bot.Data, self!, worldPlugin.World!, InputControls); Engine.OnCrouchingChanged += OnSneakingChanged; diff --git a/MineSharp.Bot/Plugins/PlayerPlugin.cs b/MineSharp.Bot/Plugins/PlayerPlugin.cs index f81246fa..95c1bfc2 100644 --- a/MineSharp.Bot/Plugins/PlayerPlugin.cs +++ b/MineSharp.Bot/Plugins/PlayerPlugin.cs @@ -157,7 +157,7 @@ protected override async Task Init() { entities = Bot.GetPlugin(); - await Task.WhenAll(initLoginPacket, initPositionPacket); + await Task.WhenAll(initLoginPacket, initPositionPacket).WaitAsync(Bot.CancellationToken); var loginPacket = await initLoginPacket; var positionPacket = await initPositionPacket; diff --git a/MineSharp.Bot/Plugins/Plugin.cs b/MineSharp.Bot/Plugins/Plugin.cs index 17455236..b8e6d105 100644 --- a/MineSharp.Bot/Plugins/Plugin.cs +++ b/MineSharp.Bot/Plugins/Plugin.cs @@ -43,6 +43,7 @@ protected Plugin(MineSharpBot bot) /// /// This method is called once when the plugin starts. + /// It should stop (cancel) when the is cancelled. /// /// protected virtual Task Init() @@ -160,6 +161,7 @@ internal async Task Initialize() catch (Exception e) { Logger.Error(e, "Plugin {PluginName} threw an exception during Init(). Aborting", GetType().Name); + initializationTask.TrySetException(e); throw; } } diff --git a/MineSharp.Bot/Plugins/WindowPlugin.cs b/MineSharp.Bot/Plugins/WindowPlugin.cs index 4fa81953..7d0ac043 100644 --- a/MineSharp.Bot/Plugins/WindowPlugin.cs +++ b/MineSharp.Bot/Plugins/WindowPlugin.cs @@ -430,9 +430,9 @@ private Task HandleWindowItems(WindowItemsPacket packet) window.StateId = packet.StateId; window.SetSlots(slots); - if (window.WindowId == 0 && !inventoryLoadedTsc.Task.IsCompleted) + if (window.WindowId == 0) { - inventoryLoadedTsc.SetResult(); + inventoryLoadedTsc.TrySetResult(); } return Task.CompletedTask; diff --git a/MineSharp.Bot/Plugins/WorldPlugin.cs b/MineSharp.Bot/Plugins/WorldPlugin.cs index 52a255b8..d667ea48 100644 --- a/MineSharp.Bot/Plugins/WorldPlugin.cs +++ b/MineSharp.Bot/Plugins/WorldPlugin.cs @@ -50,7 +50,7 @@ protected override async Task Init() playerPlugin = Bot.GetPlugin(); windowPlugin = Bot.GetPlugin(); - await playerPlugin.WaitForInitialization(); + await playerPlugin.WaitForInitialization().WaitAsync(Bot.CancellationToken); var dimension = playerPlugin.Self!.Dimension; World = WorldVersion.CreateWorld(Bot.Data, dimension); } From 2e74a368473d1f4cded6b57beb1d453ff3d587ad Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Fri, 9 Aug 2024 00:39:44 +0200 Subject: [PATCH 53/73] extracted ParsePacket method + added unread packet bytes warning --- .../MineSharp.Protocol/MinecraftClient.cs | 80 ++++++++++++------- 1 file changed, 52 insertions(+), 28 deletions(-) diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index c6e66c3c..c15a233a 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -529,6 +529,33 @@ private void DispatchPacket(IPacket packet) } } + // TODO: object is bad but IPacket is not allowed as generic type + private async Task ParsePacket(PacketPalette.PacketFactory packetFactory, PacketType packetType, PacketBuffer buffer) + { + var size = buffer.ReadableBytes; + try + { + var packet = packetFactory(buffer, Data); + + var unreadBytes = buffer.ReadableBytes; + if (unreadBytes != 0) + { + Logger.Warn("After reading the packet {PacketType}, the buffer still contains {unreadBytes}/{Size} bytes.", packetType, unreadBytes, size); + } + + return packet; + } + catch (EndOfStreamException e) + { + Logger.Error(e, "Could not read packet {PacketType}, it was {Size} bytes.", packetType, size); + } + finally + { + await buffer.DisposeAsync(); + } + return null; + } + private async Task HandleIncomingPacket(PacketType packetType, PacketBuffer buffer) { // Only parse packets that are awaited by an handler. @@ -568,45 +595,42 @@ private async Task HandleIncomingPacket(PacketType packetType, PacketBuffer buff return; } - var size = buffer.ReadableBytes; - try + var packet = (IPacket?) await ParsePacket(factory, packetType, buffer); + + if (packet == null) { - var packet = factory(buffer, Data); - await buffer.DisposeAsync(); + // The packet could not be parsed + return; + } - tcs?.TrySetResult(packet); + tcs?.TrySetResult(packet); - var packetHandlersTasks = new List(); - try + var packetHandlersTasks = new List(); + try + { + // Run all handlers in parallel: + foreach (var handler in handlers) { - // Run all handlers in parallel: - foreach (var handler in handlers) + // The synchronous part of the handlers might throw an exception + // So we also do this in a try-catch block + try { - // The synchronous part of the handlers might throw an exception - // So we also do this in a try-catch block - try - { - packetHandlersTasks.Add(handler(packet)); - } - catch (Exception e) - { - Logger.Warn(e, "An packet handler for packet of type {PacketType} threw an exception.", packetType); - } + packetHandlersTasks.Add(handler(packet)); } - - await Task.WhenAll(packetHandlersTasks); - } - catch (Exception) - { - foreach (var faultedTask in packetHandlersTasks.Where(task => task.Status == TaskStatus.Faulted)) + catch (Exception e) { - Logger.Warn(faultedTask.Exception, "An packet handler for packet of type {PacketType} threw an exception.", packetType); + Logger.Warn(e, "An packet handler for packet of type {PacketType} threw an exception.", packetType); } } + + await Task.WhenAll(packetHandlersTasks); } - catch (EndOfStreamException e) + catch (Exception) { - Logger.Error(e, "Could not read packet {PacketType}, it was {Size} bytes.", packetType, size); + foreach (var faultedTask in packetHandlersTasks.Where(task => task.Status == TaskStatus.Faulted)) + { + Logger.Warn(faultedTask.Exception, "An packet handler for packet of type {PacketType} threw an exception.", packetType); + } } } From 8f5616bb5fac7019e40ef486676bac4a8e553dd8 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Fri, 9 Aug 2024 01:07:02 +0200 Subject: [PATCH 54/73] fixed problem with weird disconnect (login) packet --- Components/MineSharp.Protocol/MinecraftClient.cs | 13 +++++++++++++ .../Packets/Clientbound/Login/DisconnectPacket.cs | 11 +++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index c15a233a..4d695492 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -7,6 +7,7 @@ using MineSharp.ChatComponent; using MineSharp.ChatComponent.Components; using MineSharp.Core; +using MineSharp.Core.Common; using MineSharp.Core.Common.Protocol; using MineSharp.Core.Concurrency; using MineSharp.Core.Events; @@ -16,6 +17,7 @@ using MineSharp.Protocol.Connection; using MineSharp.Protocol.Exceptions; using MineSharp.Protocol.Packets; +using MineSharp.Protocol.Packets.Clientbound.Login; using MineSharp.Protocol.Packets.Clientbound.Status; using MineSharp.Protocol.Packets.Handlers; using MineSharp.Protocol.Packets.Serverbound.Configuration; @@ -280,6 +282,17 @@ public async Task SendPacket(IPacket packet, CancellationToken cancellation = de /// public EnsureOnlyRunOnceAsyncResult Disconnect(Chat? reason = null) { + if (reason is TranslatableComponent translatable + && Identifier.TryParse(translatable.Translation, out var identifier) + && identifier == DisconnectPacket.BrandIdentifier) + { + // ignore the disconnect packet if it is the weird brand reason + // because otherwise we can not connect to the server + // maybe this is a test from the server to check whether we know how to deal with this?!? + // and just continue logging in?!? + return new(Task.CompletedTask, true); + } + return ConcurrencyHelper.EnsureOnlyRunOnceAsync(() => DisconnectInternal(reason), ref disconnectTask); } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs index 62b07f2d..7b1e508e 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs @@ -26,17 +26,20 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteString(Reason.ToJson().ToString()); } + public static readonly Identifier BrandIdentifier = Identifier.Parse("minecraft:brand"); + /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var reason = buffer.ReadString(); // Disconnect (login) packet is always sent as JSON text component according to wiki.vg - // But thats wrong. In the wild there were identifiers seen as well. - // So we try parse the indentifier and in case of error we parse the JSON text component + // But thats wrong. + // Sometimes there are to strings sent. The first is always "minecraft:brand" and the second the brand, typically "vanilla". Chat chat; - if (Identifier.TryParse(reason, out var identifier)) + if (Identifier.TryParse(reason, out var identifer) && identifer == BrandIdentifier) { - chat = new TranslatableComponent(identifier.ToString()); + var value = buffer.ReadString(); + chat = new TranslatableComponent(reason, [new TextComponent(value)]); } else { From 27c5a0f16a6cb71792fef18b48cfef2421efc022 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Fri, 9 Aug 2024 01:19:06 +0200 Subject: [PATCH 55/73] added missing Packets - Part 1 --- .../Configuration/AddResourcePackPacket.cs | 57 ++++ .../Configuration/RemoveResourcePackPacket.cs | 38 +++ .../Configuration/UpdateTagsPacket.cs | 107 ++++++++ .../Clientbound/Play/AwardStatisticsPacket.cs | 258 ++++++++++++++++++ .../Clientbound/Play/BlockActionPacket.cs | 42 +++ .../Clientbound/Play/BlockEntityDataPacket.cs | 39 +++ .../Packets/Clientbound/Play/BossBarPacket.cs | 226 +++++++++++++++ .../Play/ChangeDifficultyPacket.cs | 48 ++++ .../Clientbound/Play/ChatSuggestionsPacket.cs | 50 ++++ .../Clientbound/Play/ChunkBiomesPacket.cs | 58 ++++ .../Clientbound/Play/ClearTitlesPacket.cs | 30 ++ .../Play/CommandSuggestionsResponsePacket.cs | 85 ++++++ .../Clientbound/Play/DamageEventPacket.cs | 78 ++++++ .../Clientbound/Play/DeleteMessagePacket.cs | 42 +++ .../Clientbound/Play/EntityAnimationPacket.cs | 49 ++++ .../Clientbound/Play/PluginMessagePacket.cs | 35 +++ .../Play/SetBlockDestroyStagePacket.cs | 41 +++ .../Clientbound/Play/SetCooldownPacket.cs | 34 +++ .../Play/SpawnExperienceOrbPacket.cs | 43 +++ .../Packets/PacketPalette.cs | 28 +- 20 files changed, 1384 insertions(+), 4 deletions(-) create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Configuration/AddResourcePackPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RemoveResourcePackPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Configuration/UpdateTagsPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/AwardStatisticsPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockActionPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockEntityDataPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/BossBarPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/ChangeDifficultyPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/ChatSuggestionsPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBiomesPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/ClearTitlesPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/CommandSuggestionsResponsePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/DamageEventPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/DeleteMessagePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityAnimationPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/PluginMessagePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBlockDestroyStagePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetCooldownPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnExperienceOrbPacket.cs diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/AddResourcePackPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/AddResourcePackPacket.cs new file mode 100644 index 00000000..214df5d2 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/AddResourcePackPacket.cs @@ -0,0 +1,57 @@ +using MineSharp.ChatComponent; +using MineSharp.Core.Common; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Configuration; + +/// +/// Add Resource Pack packet (configuration) +/// +/// The unique identifier of the resource pack. +/// The URL to the resource pack. +/// A 40 character hexadecimal, case-insensitive SHA-1 hash of the resource pack file. +/// Whether the client is forced to use the resource pack. +/// Whether a custom message should be used on the resource pack prompt. +/// The custom message shown in the prompt, if present. +public sealed record AddResourcePackPacket(Uuid Uuid, string Url, string Hash, bool Forced, bool HasPromptMessage, Chat? PromptMessage) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Configuration_AddResourcePack; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteUuid(Uuid); + buffer.WriteString(Url); + buffer.WriteString(Hash); + buffer.WriteBool(Forced); + buffer.WriteBool(HasPromptMessage); + if (HasPromptMessage) + { + buffer.WriteChatComponent(PromptMessage!); + } + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var uuid = buffer.ReadUuid(); + var url = buffer.ReadString(); + var hash = buffer.ReadString(); + var forced = buffer.ReadBool(); + var hasPromptMessage = buffer.ReadBool(); + var promptMessage = hasPromptMessage ? buffer.ReadChatComponent() : null; + + return new AddResourcePackPacket( + uuid, + url, + hash, + forced, + hasPromptMessage, + promptMessage); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RemoveResourcePackPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RemoveResourcePackPacket.cs new file mode 100644 index 00000000..5e7b9954 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/RemoveResourcePackPacket.cs @@ -0,0 +1,38 @@ +using MineSharp.Core.Common; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Configuration; + +/// +/// Packet sent by the server to remove a resource pack (or all of them). +/// +/// The UUID of the resource pack to be removed. Or all of the resource packs if this value is null. +public sealed record RemoveResourcePackPacket(Uuid? Uuid) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Configuration_RemoveResourcePack; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + var hasUuid = Uuid != null; + buffer.WriteBool(hasUuid); + if (hasUuid) + { + buffer.WriteUuid(Uuid!.Value); + } + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var hasUuid = buffer.ReadBool(); + Uuid? uuid = hasUuid ? buffer.ReadUuid() : null; + + return new RemoveResourcePackPacket(uuid); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/UpdateTagsPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/UpdateTagsPacket.cs new file mode 100644 index 00000000..d0781961 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Configuration/UpdateTagsPacket.cs @@ -0,0 +1,107 @@ +using MineSharp.Core.Common; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using static MineSharp.Protocol.Packets.Clientbound.Configuration.UpdateTagsPacket; + +namespace MineSharp.Protocol.Packets.Clientbound.Configuration; + +/// +/// Update Tags (configuration) packet +/// +/// Array of registries with their tags +public sealed record UpdateTagsPacket(Registry[] Registries) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Configuration_Tags; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + WriteRegistries(buffer, Registries); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var registries = ReadRegistries(buffer); + return new UpdateTagsPacket(registries); + } + + private static void WriteRegistries(PacketBuffer buffer, Registry[] registries) + { + buffer.WriteVarInt(registries.Length); + foreach (var registry in registries) + { + buffer.WriteIdentifier(registry.Identifier); + WriteTags(buffer, registry.Tags); + } + } + + private static Registry[] ReadRegistries(PacketBuffer buffer) + { + var registryCount = buffer.ReadVarInt(); + var registries = new Registry[registryCount]; + for (int i = 0; i < registryCount; i++) + { + var registry = buffer.ReadIdentifier(); + var tags = ReadTags(buffer); + registries[i] = new Registry(registry, tags); + } + return registries; + } + + private static void WriteTags(PacketBuffer buffer, Tag[] tags) + { + buffer.WriteVarInt(tags.Length); + foreach (var tag in tags) + { + buffer.WriteIdentifier(tag.Name); + buffer.WriteVarInt(tag.Entries.Length); + foreach (var entry in tag.Entries) + { + buffer.WriteVarInt(entry); + } + } + } + + private static Tag[] ReadTags(PacketBuffer buffer) + { + var tagCount = buffer.ReadVarInt(); + var tags = new Tag[tagCount]; + for (int j = 0; j < tagCount; j++) + { + var tagName = buffer.ReadIdentifier(); + var entries = ReadEntries(buffer); + tags[j] = new Tag(tagName, entries); + } + return tags; + } + + private static int[] ReadEntries(PacketBuffer buffer) + { + var entryCount = buffer.ReadVarInt(); + var entries = new int[entryCount]; + for (int k = 0; k < entryCount; k++) + { + entries[k] = buffer.ReadVarInt(); + } + return entries; + } + + /// + /// Represents a registry with its tags + /// + /// The registry identifier + /// Array of tags + public sealed record Registry(Identifier Identifier, Tag[] Tags); + + /// + /// Represents a tag with its entries + /// + /// The tag name + /// Array of entries + public sealed record Tag(Identifier Name, int[] Entries); +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/AwardStatisticsPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/AwardStatisticsPacket.cs new file mode 100644 index 00000000..763c0e2b --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/AwardStatisticsPacket.cs @@ -0,0 +1,258 @@ +using System.Collections.Frozen; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Award statistics packet sent as a response to Client Command. +/// +/// Number of elements in the statistics array. +/// Array of statistics. +public sealed record AwardStatisticsPacket(int Count, AwardStatisticsPacket.Statistic[] Statistics) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_Statistics; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(Count); + foreach (var statistic in Statistics) + { + buffer.WriteVarInt((int)statistic.CategoryId); + buffer.WriteVarInt((int)statistic.StatisticId); + buffer.WriteVarInt(statistic.Value); + } + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var count = buffer.ReadVarInt(); + var statistics = new Statistic[count]; + for (int i = 0; i < count; i++) + { + var categoryId = (CategoryId)buffer.ReadVarInt(); + var statisticId = (StatisticId)buffer.ReadVarInt(); + var value = buffer.ReadVarInt(); + statistics[i] = new Statistic(categoryId, statisticId, value); + } + + return new AwardStatisticsPacket(count, statistics); + } + + /// + /// Represents a single statistic entry. + /// + /// The category ID of the statistic. + /// The statistic ID. + /// The value of the statistic. + public sealed record Statistic(CategoryId CategoryId, StatisticId StatisticId, int Value); + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + /// + /// Enum representing different types of statistic IDs. + /// + public enum StatisticId + { + LeaveGame = 0, + PlayOneMinute = 1, + TimeSinceDeath = 2, + TimeSinceRest = 3, + SneakTime = 4, + WalkOneCm = 5, + CrouchOneCm = 6, + SprintOneCm = 7, + WalkOnWaterOneCm = 8, + FallOneCm = 9, + ClimbOneCm = 10, + FlyOneCm = 11, + WalkUnderWaterOneCm = 12, + MinecartOneCm = 13, + BoatOneCm = 14, + PigOneCm = 15, + HorseOneCm = 16, + AviateOneCm = 17, + SwimOneCm = 18, + StriderOneCm = 19, + Jump = 20, + Drop = 21, + DamageDealt = 22, + DamageDealtAbsorbed = 23, + DamageDealtResisted = 24, + DamageTaken = 25, + DamageBlockedByShield = 26, + DamageAbsorbed = 27, + DamageResisted = 28, + Deaths = 29, + MobKills = 30, + AnimalsBred = 31, + PlayerKills = 32, + FishCaught = 33, + TalkedToVillager = 34, + TradedWithVillager = 35, + EatCakeSlice = 36, + FillCauldron = 37, + UseCauldron = 38, + CleanArmor = 39, + CleanBanner = 40, + CleanShulkerBox = 41, + InteractWithBrewingStand = 42, + InteractWithBeacon = 43, + InspectDropper = 44, + InspectHopper = 45, + InspectDispenser = 46, + PlayNoteblock = 47, + TuneNoteblock = 48, + PotFlower = 49, + TriggerTrappedChest = 50, + OpenEnderchest = 51, + EnchantItem = 52, + PlayRecord = 53, + InteractWithFurnace = 54, + InteractWithCraftingTable = 55, + OpenChest = 56, + SleepInBed = 57, + OpenShulkerBox = 58, + OpenBarrel = 59, + InteractWithBlastFurnace = 60, + InteractWithSmoker = 61, + InteractWithLectern = 62, + InteractWithCampfire = 63, + InteractWithCartographyTable = 64, + InteractWithLoom = 65, + InteractWithStonecutter = 66, + BellRing = 67, + RaidTrigger = 68, + RaidWin = 69, + InteractWithAnvil = 70, + InteractWithGrindstone = 71, + TargetHit = 72, + InteractWithSmithingTable = 73 + } + + /// + /// Enum representing different categories of statistics. + /// + public enum CategoryId + { + General = 0, + Blocks = 1, + Items = 2, + Mobs = 3 + } +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + + /// + /// Enum representing different units for statistics. + /// + public enum Unit + { + /// + /// No unit. + /// Just a normal number (formatted with 0 decimal places). + /// + None, + /// + /// Unit representing damage. + /// Value is 10 times the normal amount. + /// + Damage, + /// + /// Unit representing distance. + /// A distance in centimeters (hundredths of blocks). + /// + Distance, + /// + /// Unit representing time. + /// A time span in ticks + /// + Time + } + + // TODO: Is this data from a registry? Hardcoded for now. + /// + /// Lookup table for statistic ID to name and unit. + /// + public static readonly FrozenDictionary StatisticLookup = new Dictionary() + { + { StatisticId.LeaveGame, ("minecraft.leave_game", Unit.None) }, + { StatisticId.PlayOneMinute, ("minecraft.play_one_minute", Unit.Time) }, + { StatisticId.TimeSinceDeath, ("minecraft.time_since_death", Unit.Time) }, + { StatisticId.TimeSinceRest, ("minecraft.time_since_rest", Unit.Time) }, + { StatisticId.SneakTime, ("minecraft.sneak_time", Unit.Time) }, + { StatisticId.WalkOneCm, ("minecraft.walk_one_cm", Unit.Distance) }, + { StatisticId.CrouchOneCm, ("minecraft.crouch_one_cm", Unit.Distance) }, + { StatisticId.SprintOneCm, ("minecraft.sprint_one_cm", Unit.Distance) }, + { StatisticId.WalkOnWaterOneCm, ("minecraft.walk_on_water_one_cm", Unit.Distance) }, + { StatisticId.FallOneCm, ("minecraft.fall_one_cm", Unit.Distance) }, + { StatisticId.ClimbOneCm, ("minecraft.climb_one_cm", Unit.Distance) }, + { StatisticId.FlyOneCm, ("minecraft.fly_one_cm", Unit.Distance) }, + { StatisticId.WalkUnderWaterOneCm, ("minecraft.walk_under_water_one_cm", Unit.Distance) }, + { StatisticId.MinecartOneCm, ("minecraft.minecart_one_cm", Unit.Distance) }, + { StatisticId.BoatOneCm, ("minecraft.boat_one_cm", Unit.Distance) }, + { StatisticId.PigOneCm, ("minecraft.pig_one_cm", Unit.Distance) }, + { StatisticId.HorseOneCm, ("minecraft.horse_one_cm", Unit.Distance) }, + { StatisticId.AviateOneCm, ("minecraft.aviate_one_cm", Unit.Distance) }, + { StatisticId.SwimOneCm, ("minecraft.swim_one_cm", Unit.Distance) }, + { StatisticId.StriderOneCm, ("minecraft.strider_one_cm", Unit.Distance) }, + { StatisticId.Jump, ("minecraft.jump", Unit.None) }, + { StatisticId.Drop, ("minecraft.drop", Unit.None) }, + { StatisticId.DamageDealt, ("minecraft.damage_dealt", Unit.Damage) }, + { StatisticId.DamageDealtAbsorbed, ("minecraft.damage_dealt_absorbed", Unit.Damage) }, + { StatisticId.DamageDealtResisted, ("minecraft.damage_dealt_resisted", Unit.Damage) }, + { StatisticId.DamageTaken, ("minecraft.damage_taken", Unit.Damage) }, + { StatisticId.DamageBlockedByShield, ("minecraft.damage_blocked_by_shield", Unit.Damage) }, + { StatisticId.DamageAbsorbed, ("minecraft.damage_absorbed", Unit.Damage) }, + { StatisticId.DamageResisted, ("minecraft.damage_resisted", Unit.Damage) }, + { StatisticId.Deaths, ("minecraft.deaths", Unit.None) }, + { StatisticId.MobKills, ("minecraft.mob_kills", Unit.None) }, + { StatisticId.AnimalsBred, ("minecraft.animals_bred", Unit.None) }, + { StatisticId.PlayerKills, ("minecraft.player_kills", Unit.None) }, + { StatisticId.FishCaught, ("minecraft.fish_caught", Unit.None) }, + { StatisticId.TalkedToVillager, ("minecraft.talked_to_villager", Unit.None) }, + { StatisticId.TradedWithVillager, ("minecraft.traded_with_villager", Unit.None) }, + { StatisticId.EatCakeSlice, ("minecraft.eat_cake_slice", Unit.None) }, + { StatisticId.FillCauldron, ("minecraft.fill_cauldron", Unit.None) }, + { StatisticId.UseCauldron, ("minecraft.use_cauldron", Unit.None) }, + { StatisticId.CleanArmor, ("minecraft.clean_armor", Unit.None) }, + { StatisticId.CleanBanner, ("minecraft.clean_banner", Unit.None) }, + { StatisticId.CleanShulkerBox, ("minecraft.clean_shulker_box", Unit.None) }, + { StatisticId.InteractWithBrewingStand, ("minecraft.interact_with_brewingstand", Unit.None) }, + { StatisticId.InteractWithBeacon, ("minecraft.interact_with_beacon", Unit.None) }, + { StatisticId.InspectDropper, ("minecraft.inspect_dropper", Unit.None) }, + { StatisticId.InspectHopper, ("minecraft.inspect_hopper", Unit.None) }, + { StatisticId.InspectDispenser, ("minecraft.inspect_dispenser", Unit.None) }, + { StatisticId.PlayNoteblock, ("minecraft.play_noteblock", Unit.None) }, + { StatisticId.TuneNoteblock, ("minecraft.tune_noteblock", Unit.None) }, + { StatisticId.PotFlower, ("minecraft.pot_flower", Unit.None) }, + { StatisticId.TriggerTrappedChest, ("minecraft.trigger_trapped_chest", Unit.None) }, + { StatisticId.OpenEnderchest, ("minecraft.open_enderchest", Unit.None) }, + { StatisticId.EnchantItem, ("minecraft.enchant_item", Unit.None) }, + { StatisticId.PlayRecord, ("minecraft.play_record", Unit.None) }, + { StatisticId.InteractWithFurnace, ("minecraft.interact_with_furnace", Unit.None) }, + { StatisticId.InteractWithCraftingTable, ("minecraft.interact_with_crafting_table", Unit.None) }, + { StatisticId.OpenChest, ("minecraft.open_chest", Unit.None) }, + { StatisticId.SleepInBed, ("minecraft.sleep_in_bed", Unit.None) }, + { StatisticId.OpenShulkerBox, ("minecraft.open_shulker_box", Unit.None) }, + { StatisticId.OpenBarrel, ("minecraft.open_barrel", Unit.None) }, + { StatisticId.InteractWithBlastFurnace, ("minecraft.interact_with_blast_furnace", Unit.None) }, + { StatisticId.InteractWithSmoker, ("minecraft.interact_with_smoker", Unit.None) }, + { StatisticId.InteractWithLectern, ("minecraft.interact_with_lectern", Unit.None) }, + { StatisticId.InteractWithCampfire, ("minecraft.interact_with_campfire", Unit.None) }, + { StatisticId.InteractWithCartographyTable, ("minecraft.interact_with_cartography_table", Unit.None) }, + { StatisticId.InteractWithLoom, ("minecraft.interact_with_loom", Unit.None) }, + { StatisticId.InteractWithStonecutter, ("minecraft.interact_with_stonecutter", Unit.None) }, + { StatisticId.BellRing, ("minecraft.bell_ring", Unit.None) }, + { StatisticId.RaidTrigger, ("minecraft.raid_trigger", Unit.None) }, + { StatisticId.RaidWin, ("minecraft.raid_win", Unit.None) }, + { StatisticId.InteractWithAnvil, ("minecraft.interact_with_anvil", Unit.None) }, + { StatisticId.InteractWithGrindstone, ("minecraft.interact_with_grindstone", Unit.None) }, + { StatisticId.TargetHit, ("minecraft.target_hit", Unit.None) }, + { StatisticId.InteractWithSmithingTable, ("minecraft.interact_with_smithing_table", Unit.None) } + }.ToFrozenDictionary(); +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockActionPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockActionPacket.cs new file mode 100644 index 00000000..63f0e7a7 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockActionPacket.cs @@ -0,0 +1,42 @@ +using MineSharp.Core.Geometry; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// This packet is used for a number of actions and animations performed by blocks, usually non-persistent. +/// The client ignores the provided block type and instead uses the block state in their world. +/// +/// Block coordinates. +/// Varies depending on block — see Block Actions. +/// Varies depending on block — see Block Actions. +/// The block type ID for the block. This value is unused by the Notchian client, as it will infer the type of block based on the given position. +public sealed record BlockActionPacket(Position Location, byte ActionId, byte ActionParameter, int BlockType) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_BlockAction; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WritePosition(Location); + buffer.WriteByte(ActionId); + buffer.WriteByte(ActionParameter); + buffer.WriteVarInt(BlockType); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var location = buffer.ReadPosition(); + var actionId = buffer.ReadByte(); + var actionParameter = buffer.ReadByte(); + var blockType = buffer.ReadVarInt(); + + return new BlockActionPacket(location, actionId, actionParameter, blockType); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockEntityDataPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockEntityDataPacket.cs new file mode 100644 index 00000000..4998ec82 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BlockEntityDataPacket.cs @@ -0,0 +1,39 @@ +using fNbt; +using MineSharp.Core.Geometry; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Sets the block entity associated with the block at the given location. +/// +/// The location of the block entity +/// The type of the block entity +/// The NBT data to set +public sealed record BlockEntityDataPacket(Position Location, int BlockEntityType, NbtTag? NbtData) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_TileEntityData; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WritePosition(Location); + buffer.WriteVarInt(BlockEntityType); + buffer.WriteOptionalNbt(NbtData); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var location = buffer.ReadPosition(); + var type = buffer.ReadVarInt(); + var nbtData = buffer.ReadOptionalNbt(); + + return new BlockEntityDataPacket(location, type, nbtData); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/BossBarPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BossBarPacket.cs new file mode 100644 index 00000000..5715115e --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/BossBarPacket.cs @@ -0,0 +1,226 @@ +using System.Collections.Frozen; +using MineSharp.ChatComponent; +using MineSharp.Core.Common; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using static MineSharp.Protocol.Packets.Clientbound.Play.BossBarPacket; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Boss bar packet +/// +/// Unique ID for this bar +/// Determines the layout of the remaining packet +public sealed record BossBarPacket(Uuid Uuid, BossBarAction Action) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_BossBar; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteUuid(Uuid); + buffer.WriteVarInt((int)Action.Type); + Action.Write(buffer); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var uuid = buffer.ReadUuid(); + var actionType = (BossBarActionType)buffer.ReadVarInt(); + var action = BossBarAction.Read(buffer, actionType); + return new BossBarPacket(uuid, action); + } + + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + /// + /// Represents the action of a boss bar packet + /// + public interface IBossBarAction where T : BossBarAction + { + static abstract BossBarActionType StaticType { get; } + void Write(PacketBuffer buffer); + static abstract T Read(PacketBuffer buffer); + } + + public abstract record BossBarAction + { + public abstract BossBarActionType Type { get; } + public abstract void Write(PacketBuffer buffer); + + public static BossBarAction Read(PacketBuffer buffer, BossBarActionType type) + { + if (BossActionReaders.TryGetValue(type, out var reader)) + { + return reader(buffer); + } + throw new ArgumentOutOfRangeException(); + } + + public static readonly FrozenDictionary> BossActionReaders = CreateBossActionReadersLookup(); + + private static FrozenDictionary> CreateBossActionReadersLookup() + { + Dictionary> lookup = new(); + + void Register() where T : BossBarAction, IBossBarAction + { + lookup.Add(T.StaticType, buffer => T.Read(buffer)); + } + + Register(); + Register(); + Register(); + Register(); + Register(); + Register(); + + return lookup.ToFrozenDictionary(); + } + } + + public enum BossBarActionType + { + Add = 0, + Remove = 1, + UpdateHealth = 2, + UpdateTitle = 3, + UpdateStyle = 4, + UpdateFlags = 5 + } + + public enum BossBarColor + { + Pink = 0, + Blue = 1, + Red = 2, + Green = 3, + Yellow = 4, + Purple = 5, + White = 6 + } + + public enum BossBarDivision + { + NoDivision = 0, + SixNotches = 1, + TenNotches = 2, + TwelveNotches = 3, + TwentyNotches = 4 + } + + public sealed record AddBossBarAction(Chat Title, float Health, BossBarColor Color, BossBarDivision Division, byte Flags) : BossBarAction, IBossBarAction + { + public override BossBarActionType Type => StaticType; + public static BossBarActionType StaticType => BossBarActionType.Add; + + public override void Write(PacketBuffer buffer) + { + buffer.WriteChatComponent(Title); + buffer.WriteFloat(Health); + buffer.WriteVarInt((int)Color); + buffer.WriteVarInt((int)Division); + buffer.WriteByte(Flags); + } + + public static AddBossBarAction Read(PacketBuffer buffer) + { + var title = buffer.ReadChatComponent(); + var health = buffer.ReadFloat(); + var color = (BossBarColor)buffer.ReadVarInt(); + var division = (BossBarDivision)buffer.ReadVarInt(); + var flags = buffer.ReadByte(); + return new AddBossBarAction(title, health, color, division, flags); + } + } + + public sealed record RemoveBossBarAction() : BossBarAction(), IBossBarAction + { + public override BossBarActionType Type => StaticType; + public static BossBarActionType StaticType => BossBarActionType.Remove; + + public override void Write(PacketBuffer buffer) { } + + public static RemoveBossBarAction Read(PacketBuffer buffer) + { + return new RemoveBossBarAction(); + } + } + + public sealed record UpdateHealthBossBarAction(float Health) : BossBarAction, IBossBarAction + { + public override BossBarActionType Type => StaticType; + public static BossBarActionType StaticType => BossBarActionType.UpdateHealth; + + public override void Write(PacketBuffer buffer) + { + buffer.WriteFloat(Health); + } + + public static UpdateHealthBossBarAction Read(PacketBuffer buffer) + { + var health = buffer.ReadFloat(); + return new UpdateHealthBossBarAction(health); + } + } + + public sealed record UpdateTitleBossBarAction(Chat Title) : BossBarAction, IBossBarAction + { + public override BossBarActionType Type => StaticType; + public static BossBarActionType StaticType => BossBarActionType.UpdateTitle; + + public override void Write(PacketBuffer buffer) + { + buffer.WriteChatComponent(Title); + } + + public static UpdateTitleBossBarAction Read(PacketBuffer buffer) + { + var title = buffer.ReadChatComponent(); + return new UpdateTitleBossBarAction(title); + } + } + + public sealed record UpdateStyleBossBarAction(BossBarColor Color, BossBarDivision Division) : BossBarAction, IBossBarAction + { + public override BossBarActionType Type => StaticType; + public static BossBarActionType StaticType => BossBarActionType.UpdateStyle; + + public override void Write(PacketBuffer buffer) + { + buffer.WriteVarInt((int)Color); + buffer.WriteVarInt((int)Division); + } + + public static UpdateStyleBossBarAction Read(PacketBuffer buffer) + { + var color = (BossBarColor)buffer.ReadVarInt(); + var division = (BossBarDivision)buffer.ReadVarInt(); + return new UpdateStyleBossBarAction(color, division); + } + } + + public sealed record UpdateFlagsBossBarAction(byte Flags) : BossBarAction, IBossBarAction + { + public override BossBarActionType Type => StaticType; + public static BossBarActionType StaticType => BossBarActionType.UpdateFlags; + + public override void Write(PacketBuffer buffer) + { + buffer.WriteByte(Flags); + } + + public static UpdateFlagsBossBarAction Read(PacketBuffer buffer) + { + var flags = buffer.ReadByte(); + return new UpdateFlagsBossBarAction(flags); + } + } +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChangeDifficultyPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChangeDifficultyPacket.cs new file mode 100644 index 00000000..09a87f19 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChangeDifficultyPacket.cs @@ -0,0 +1,48 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using static MineSharp.Protocol.Packets.Clientbound.Play.ChangeDifficultyPacket; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Change difficulty packet +/// +/// The difficulty setting +/// Whether the difficulty is locked +public sealed record ChangeDifficultyPacket(DifficultyLevel Difficulty, bool DifficultyLocked) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_Difficulty; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.Write((byte)Difficulty); + buffer.WriteBool(DifficultyLocked); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var difficulty = (DifficultyLevel)buffer.ReadByte(); + var difficultyLocked = buffer.ReadBool(); + + return new ChangeDifficultyPacket(difficulty, difficultyLocked); + } + + /// + /// Enum representing the difficulty levels + /// + public enum DifficultyLevel : byte + { +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + Peaceful = 0, + Easy = 1, + Normal = 2, + Hard = 3 +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChatSuggestionsPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChatSuggestionsPacket.cs new file mode 100644 index 00000000..b7cf5930 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChatSuggestionsPacket.cs @@ -0,0 +1,50 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using static MineSharp.Protocol.Packets.Clientbound.Play.ChatSuggestionsPacket; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Chat suggestions packet +/// +/// The action to perform +/// Number of elements in the following array +/// Array of chat suggestions +public sealed record ChatSuggestionsPacket(ChatSuggestionAction Action, int Count, string[] Entries) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_ChatSuggestions; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt((int)Action); + buffer.WriteVarInt(Count); + buffer.WriteVarIntArray(Entries, (buf, entry) => buf.WriteString(entry)); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var action = (ChatSuggestionAction)buffer.ReadVarInt(); + var count = buffer.ReadVarInt(); + var entries = buffer.ReadVarIntArray(buf => buf.ReadString()); + + return new ChatSuggestionsPacket(action, count, entries); + } + + /// + /// Enum representing the action for chat suggestions + /// + public enum ChatSuggestionAction + { +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + Add = 0, + Remove = 1, + Set = 2 +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBiomesPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBiomesPacket.cs new file mode 100644 index 00000000..04dc460b --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ChunkBiomesPacket.cs @@ -0,0 +1,58 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using static MineSharp.Protocol.Packets.Clientbound.Play.ChunkBiomesPacket; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Chunk Biomes packet +/// +/// Number of chunks +/// Array of chunk biome data +public sealed record ChunkBiomesPacket(int NumberOfChunks, ChunkBiomeData[] ChunkBiomes) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_ChunkBiomes; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(NumberOfChunks); + foreach (var chunk in ChunkBiomes) + { + buffer.WriteInt(chunk.ChunkZ); + buffer.WriteInt(chunk.ChunkX); + buffer.WriteVarInt(chunk.Size); + buffer.WriteBytes(chunk.Data); + } + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var numberOfChunks = buffer.ReadVarInt(); + var chunkBiomeData = new ChunkBiomeData[numberOfChunks]; + for (int i = 0; i < numberOfChunks; i++) + { + var chunkZ = buffer.ReadInt(); + var chunkX = buffer.ReadInt(); + var size = buffer.ReadVarInt(); + var data = buffer.ReadBytes(size); + chunkBiomeData[i] = new ChunkBiomeData(chunkZ, chunkX, size, data); + } + + return new ChunkBiomesPacket(numberOfChunks, chunkBiomeData); + } + + /// + /// Represents the chunk biome data + /// + /// Chunk Z coordinate + /// Chunk X coordinate + /// Size of data in bytes + /// Chunk data structure + public sealed record ChunkBiomeData(int ChunkZ, int ChunkX, int Size, byte[] Data); +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ClearTitlesPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ClearTitlesPacket.cs new file mode 100644 index 00000000..3bdaac48 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ClearTitlesPacket.cs @@ -0,0 +1,30 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Clear Titles packet +/// +/// Whether to reset the client's current title information +public sealed record ClearTitlesPacket(bool Reset) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_ClearTitles; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteBool(Reset); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var reset = buffer.ReadBool(); + return new ClearTitlesPacket(reset); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/CommandSuggestionsResponsePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/CommandSuggestionsResponsePacket.cs new file mode 100644 index 00000000..b8ab2471 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/CommandSuggestionsResponsePacket.cs @@ -0,0 +1,85 @@ +using MineSharp.ChatComponent; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using static MineSharp.Protocol.Packets.Clientbound.Play.CommandSuggestionsResponsePacket; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Command Suggestions Response packet +/// +/// Transaction ID +/// Start of the text to replace +/// Length of the text to replace +/// Array of matches +public sealed record CommandSuggestionsResponsePacket(int Id, int Start, int Length, Match[] Matches) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_TabComplete; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(Id); + buffer.WriteVarInt(Start); + buffer.WriteVarInt(Length); + buffer.WriteVarInt(Matches.Length); + foreach (var match in Matches) + { + match.Write(buffer); + } + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var id = buffer.ReadVarInt(); + var start = buffer.ReadVarInt(); + var length = buffer.ReadVarInt(); + var count = buffer.ReadVarInt(); + var matches = new Match[count]; + for (int i = 0; i < count; i++) + { + matches[i] = Match.Read(buffer); + } + + return new CommandSuggestionsResponsePacket(id, start, length, matches); + } + + /// + /// Represents a match in the command suggestions response + /// + /// The match string + /// The tooltip text component or null + public sealed record Match(string Value, Chat? Tooltip) : ISerializable + { + /// + public void Write(PacketBuffer buffer) + { + buffer.WriteString(Value); + var hasTooltip = Tooltip != null; + buffer.WriteBool(hasTooltip); + if (hasTooltip) + { + buffer.WriteChatComponent(Tooltip!); + } + } + + /// + public static Match Read(PacketBuffer buffer) + { + var match = buffer.ReadString(); + var hasTooltip = buffer.ReadBool(); + Chat? tooltip = null; + if (hasTooltip) + { + tooltip = buffer.ReadChatComponent(); + } + + return new Match(match, tooltip); + } + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DamageEventPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DamageEventPacket.cs new file mode 100644 index 00000000..909b7ca9 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DamageEventPacket.cs @@ -0,0 +1,78 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Damage event packet +/// +/// The ID of the entity taking damage +/// The type of damage in the minecraft:damage_type registry +/// The ID + 1 of the entity responsible for the damage, if present +/// The ID + 1 of the entity that directly dealt the damage, if present +/// Indicates the presence of the source position fields +/// The X coordinate of the source position, if present +/// The Y coordinate of the source position, if present +/// The Z coordinate of the source position, if present +public sealed record DamageEventPacket( + int EntityId, + int SourceTypeId, + int SourceCauseId, + int SourceDirectId, + bool HasSourcePosition, + double? SourcePositionX, + double? SourcePositionY, + double? SourcePositionZ) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_DamageEvent; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(EntityId); + buffer.WriteVarInt(SourceTypeId); + buffer.WriteVarInt(SourceCauseId); + buffer.WriteVarInt(SourceDirectId); + buffer.WriteBool(HasSourcePosition); + if (HasSourcePosition) + { + buffer.WriteDouble(SourcePositionX.GetValueOrDefault()); + buffer.WriteDouble(SourcePositionY.GetValueOrDefault()); + buffer.WriteDouble(SourcePositionZ.GetValueOrDefault()); + } + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var entityId = buffer.ReadVarInt(); + var sourceTypeId = buffer.ReadVarInt(); + var sourceCauseId = buffer.ReadVarInt(); + var sourceDirectId = buffer.ReadVarInt(); + var hasSourcePosition = buffer.ReadBool(); + double? sourcePositionX = null; + double? sourcePositionY = null; + double? sourcePositionZ = null; + + if (hasSourcePosition) + { + sourcePositionX = buffer.ReadDouble(); + sourcePositionY = buffer.ReadDouble(); + sourcePositionZ = buffer.ReadDouble(); + } + + return new DamageEventPacket( + entityId, + sourceTypeId, + sourceCauseId, + sourceDirectId, + hasSourcePosition, + sourcePositionX, + sourcePositionY, + sourcePositionZ); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DeleteMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DeleteMessagePacket.cs new file mode 100644 index 00000000..3163eabf --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DeleteMessagePacket.cs @@ -0,0 +1,42 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Packet sent by the server to remove a message from the client's chat. +/// This only works for messages with signatures; system messages cannot be deleted with this packet. +/// +/// The message ID + 1, used for validating message signature. +/// The previous message's signature. Always 256 bytes and not length-prefixed. +public sealed record DeleteMessagePacket(int MessageId, byte[]? Signature) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_HideMessage; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(MessageId); + if (MessageId == 0 && Signature != null) + { + buffer.WriteBytes(Signature); + } + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var messageId = buffer.ReadVarInt(); + byte[]? signature = null; + if (messageId == 0) + { + signature = buffer.ReadBytes(256); + } + + return new DeleteMessagePacket(messageId, signature); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityAnimationPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityAnimationPacket.cs new file mode 100644 index 00000000..69f42cc5 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EntityAnimationPacket.cs @@ -0,0 +1,49 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using static MineSharp.Protocol.Packets.Clientbound.Play.EntityAnimationPacket; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Entity animation packet +/// +/// The entity ID +/// The animation ID +public sealed record EntityAnimationPacket(int EntityId, EntityAnimation Animation) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_Animation; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(EntityId); + buffer.WriteByte((byte)Animation); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var entityId = buffer.ReadVarInt(); + var animation = (EntityAnimation)buffer.ReadByte(); + + return new EntityAnimationPacket(entityId, animation); + } + + /// + /// Enum representing different types of entity animations. + /// + public enum EntityAnimation + { +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + SwingMainArm = 0, + LeaveBed = 2, + SwingOffhand = 3, + CriticalEffect = 4, + MagicCriticalEffect = 5 +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PluginMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PluginMessagePacket.cs new file mode 100644 index 00000000..044c46d4 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PluginMessagePacket.cs @@ -0,0 +1,35 @@ +using MineSharp.Core.Common; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Clientbound Plugin Message packet +/// +/// Name of the plugin channel used to send the data +/// Any data. The length of this array must be inferred from the packet length +public sealed record PluginMessagePacket(Identifier Channel, byte[] Data) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_CustomPayload; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteIdentifier(Channel); + buffer.WriteBytes(Data); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var channel = buffer.ReadObject(); + var data = buffer.RestBuffer(); + + return new PluginMessagePacket(channel, data); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBlockDestroyStagePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBlockDestroyStagePacket.cs new file mode 100644 index 00000000..3c930b61 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBlockDestroyStagePacket.cs @@ -0,0 +1,41 @@ +using MineSharp.Core.Geometry; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Set Block Destroy Stage packet +/// +/// The ID of the entity breaking the block +/// Block Position +/// 0–9 to set it, any other value to remove it +public sealed record SetBlockDestroyStagePacket(int EntityId, Position Location, byte DestroyStage) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_BlockBreakAnimation; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(EntityId); + buffer.WritePosition(Location); + buffer.WriteByte(DestroyStage); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var entityId = buffer.ReadVarInt(); + var location = buffer.ReadPosition(); + var destroyStage = buffer.ReadByte(); + + return new SetBlockDestroyStagePacket( + entityId, + location, + destroyStage); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetCooldownPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetCooldownPacket.cs new file mode 100644 index 00000000..4454c8dc --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetCooldownPacket.cs @@ -0,0 +1,34 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Applies a cooldown period to all items with the given type. +/// +/// Numeric ID of the item to apply a cooldown to. +/// Number of ticks to apply a cooldown for, or 0 to clear the cooldown. +public sealed record SetCooldownPacket(int ItemId, int CooldownTicks) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_SetCooldown; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(ItemId); + buffer.WriteVarInt(CooldownTicks); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var itemId = buffer.ReadVarInt(); + var cooldownTicks = buffer.ReadVarInt(); + + return new SetCooldownPacket(itemId, cooldownTicks); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnExperienceOrbPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnExperienceOrbPacket.cs new file mode 100644 index 00000000..cb325080 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SpawnExperienceOrbPacket.cs @@ -0,0 +1,43 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Spawn Experience Orb packet +/// +/// The entity ID +/// The X coordinate +/// The Y coordinate +/// The Z coordinate +/// The amount of experience this orb will reward once collected +public sealed record SpawnExperienceOrbPacket(int EntityId, double X, double Y, double Z, short Count) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_SpawnEntityExperienceOrb; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(EntityId); + buffer.WriteDouble(X); + buffer.WriteDouble(Y); + buffer.WriteDouble(Z); + buffer.WriteShort(Count); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var entityId = buffer.ReadVarInt(); + var x = buffer.ReadDouble(); + var y = buffer.ReadDouble(); + var z = buffer.ReadDouble(); + var count = buffer.ReadShort(); + + return new SpawnExperienceOrbPacket(entityId, x, y, z, count); + } +} diff --git a/Components/MineSharp.Protocol/Packets/PacketPalette.cs b/Components/MineSharp.Protocol/Packets/PacketPalette.cs index 015a8b31..0a718fc8 100644 --- a/Components/MineSharp.Protocol/Packets/PacketPalette.cs +++ b/Components/MineSharp.Protocol/Packets/PacketPalette.cs @@ -17,7 +17,7 @@ using CBConfigurationKeepAlivePacket = MineSharp.Protocol.Packets.Clientbound.Configuration.KeepAlivePacket; using CBFinishConfigurationPacket = MineSharp.Protocol.Packets.Clientbound.Configuration.FinishConfigurationPacket; using CBKeepAlivePacket = MineSharp.Protocol.Packets.Clientbound.Play.KeepAlivePacket; -using CBPluginMessagePacket = MineSharp.Protocol.Packets.Clientbound.Configuration.PluginMessagePacket; +using CBConfigurationPluginMessagePacket = MineSharp.Protocol.Packets.Clientbound.Configuration.PluginMessagePacket; using CBSetHeldItemPacket = MineSharp.Protocol.Packets.Clientbound.Play.SetHeldItemPacket; using ConfClientInformation = MineSharp.Protocol.Packets.Serverbound.Configuration.ClientInformationPacket; using ConfigurationDisconnectPacket = MineSharp.Protocol.Packets.Clientbound.Configuration.DisconnectPacket; @@ -34,8 +34,9 @@ using SBConfigurationKeepAlivePacket = MineSharp.Protocol.Packets.Serverbound.Configuration.KeepAlivePacket; using SBFinishConfigurationPacket = MineSharp.Protocol.Packets.Serverbound.Configuration.FinishConfigurationPacket; using SBKeepAlivePacket = MineSharp.Protocol.Packets.Serverbound.Play.KeepAlivePacket; -using SBPluginMessagePacket = MineSharp.Protocol.Packets.Serverbound.Configuration.PluginMessagePacket; +using SBConfigurationPluginMessagePacket = MineSharp.Protocol.Packets.Serverbound.Configuration.PluginMessagePacket; using SBSetHeldItemPacket = MineSharp.Protocol.Packets.Serverbound.Play.SetHeldItemPacket; +using CBPlayPluginMessagePacket = MineSharp.Protocol.Packets.Clientbound.Play.PluginMessagePacket; namespace MineSharp.Protocol.Packets; @@ -95,16 +96,19 @@ void RegisterPacket() RegisterPacket(); // Configuration - RegisterPacket(); + RegisterPacket(); RegisterPacket(); RegisterPacket(); RegisterPacket(); RegisterPacket(); RegisterPacket(); RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); RegisterPacket(); - RegisterPacket(); + RegisterPacket(); RegisterPacket(); RegisterPacket(); RegisterPacket(); @@ -155,6 +159,22 @@ void RegisterPacket() RegisterPacket(); RegisterPacket(); RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); RegisterPacket(); RegisterPacket(); From 2261f53f6284171a850089d62ab7994ceb21bf07 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Sat, 10 Aug 2024 00:34:55 +0200 Subject: [PATCH 56/73] fixed PacketBuffer.WriteVarLong --- MineSharp.Core/Serialization/PacketBuffer.cs | 22 ++++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/MineSharp.Core/Serialization/PacketBuffer.cs b/MineSharp.Core/Serialization/PacketBuffer.cs index 9d0aafc7..c0af246e 100644 --- a/MineSharp.Core/Serialization/PacketBuffer.cs +++ b/MineSharp.Core/Serialization/PacketBuffer.cs @@ -256,7 +256,7 @@ public static int ReadVarInt(Stream stream, out int byteCount) byteCount++; value |= (b & VarIntSegmentBits) << shift; - if ((b & VarIntContinueBit) == 0x00) + if ((b & VarIntContinueBit) == 0) { break; } @@ -286,7 +286,7 @@ public long ReadVarLong() { var b = ReadByte(); value |= (long)(b & VarIntSegmentBits) << shift; - if ((b & VarIntContinueBit) == 0x00) + if ((b & VarIntContinueBit) == 0) { break; } @@ -550,13 +550,13 @@ public static void WriteVarInt(Stream stream, int value) { while (true) { - if ((value & ~0x7F) == 0) + if ((value & ~VarIntSegmentBits) == 0) { stream.WriteByte((byte)value); return; } - stream.WriteByte((byte)(value & 0x7F | 0x80)); + stream.WriteByte((byte)(value & VarIntSegmentBits | VarIntContinueBit)); value >>>= 7; } } @@ -566,15 +566,19 @@ public void WriteVarInt(int value) WriteVarInt(buffer, value); } - public void WriteVarLong(int value) + public void WriteVarLong(long value) { - while ((value & ~0x7F) != 0x00) + while (true) { - buffer.WriteByte((byte)(value & 0xFF | 0x80)); + if ((value & ~VarIntSegmentBits) == 0) + { + WriteByte((byte)value); + return; + } + + WriteByte((byte)(value & VarIntSegmentBits | VarIntContinueBit)); value >>>= 7; } - - buffer.WriteByte((byte)value); } public void WriteString(string value, Encoding? encoding = null) From bbb768e77f1d2b58c667f4507de3336fdc3c8e86 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Sat, 10 Aug 2024 02:50:40 +0200 Subject: [PATCH 57/73] added BitSet type --- MineSharp.Core/Common/BitSet.cs | 1019 ++++++++++++++++++ MineSharp.Core/Serialization/PacketBuffer.cs | 14 + 2 files changed, 1033 insertions(+) create mode 100644 MineSharp.Core/Common/BitSet.cs diff --git a/MineSharp.Core/Common/BitSet.cs b/MineSharp.Core/Common/BitSet.cs new file mode 100644 index 00000000..ca0f322e --- /dev/null +++ b/MineSharp.Core/Common/BitSet.cs @@ -0,0 +1,1019 @@ +/* +This file is a port of the BitSet class from Java 7. +The original Java code is available at: https://github.com/openjdk-mirror/jdk7u-jdk/blob/f4d80957e89a19a29bb9f9807d2a28351ed7f7df/src/share/classes/java/util/BitSet.java +The port was made with assistance from GitHub Copilot Chat. +*/ + +using System.Numerics; +using System.Runtime.InteropServices; +using System.Text; + +namespace MineSharp.Core.Common; + +// TODO: Unit tests would be great to see whether the ported code works as expected. + +/// +/// This class implements a vector of bits that grows as needed. Each +/// component of the bit set has a value. The +/// bits of a are indexed by nonnegative integers. +/// Individual indexed bits can be examined, set, or cleared. One +/// may be used to modify the contents of another +/// through logical AND, logical inclusive OR, and +/// logical exclusive OR operations. +/// +/// +/// By default, all bits in the set initially have the value +/// false. +/// Every bit set has a current size, which is the number of bits +/// of space currently in use by the bit set. Note that the size is +/// related to the implementation of a bit set, so it may change with +/// implementation. The length of a bit set relates to logical length +/// of a bit set and is defined independently of implementation. +/// Unless otherwise noted, passing a null parameter to any of the +/// methods in a will result in an +/// ArgumentNullException. +/// +/// A is not safe for multithreaded use without +/// external synchronization. +/// +public sealed class BitSet : IEquatable, ICloneable +{ + /// + /// BitSets are packed into arrays of "words." Currently a word is + /// a long, which consists of 64 bits, requiring 6 address bits. + /// The choice of word size is determined purely by performance concerns. + /// + private const int ADDRESS_BITS_PER_WORD = 6; + private const int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD; + private const int BIT_INDEX_MASK = BITS_PER_WORD - 1; + /// + /// Used to shift left or right for a partial word mask. + /// + private const ulong WORD_MASK = 0xffffffffffffffffUL; + + /// + /// The internal field corresponding to the serialField "bits". + /// + private ulong[] words; + /// + /// The number of words in the logical size of this BitSet. + /// + private int wordsInUse = 0; + /// + /// Whether the size of "words" is user-specified. If so, we assume + /// the user knows what he's doing and try harder to preserve it. + /// + private bool sizeIsSticky = false; + + + /// + /// Given a bit index, return word index containing it. + /// + private static int WordIndex(int bitIndex) => bitIndex >> ADDRESS_BITS_PER_WORD; + + /// + /// Every public method must preserve these invariants. + /// + private void CheckInvariants() + { + // for performance reasons, we only check these in debug mode +#if DEBUG + if (wordsInUse > 0) + { + if (words[wordsInUse - 1] == 0) throw new InvalidOperationException(); + } + if (wordsInUse < 0 || wordsInUse > words.Length) throw new InvalidOperationException(); + if (wordsInUse != words.Length && words[wordsInUse] != 0) throw new InvalidOperationException(); +#endif + } + + /// + /// Sets the field wordsInUse to the logical size in words of the bit set. + /// WARNING: This method assumes that the number of words actually in use is + /// less than or equal to the current value of wordsInUse! + /// + private void RecalculateWordsInUse() + { + var lastUsedIndex = words.AsSpan(0, wordsInUse).LastIndexOfAnyExcept(0ul); + wordsInUse = lastUsedIndex + 1; + } + + private void InitWords(int nbits) + { + words = new ulong[WordIndex(nbits - 1) + 1]; + } + + #region Constructors + + /// + /// Creates a new bit set. All bits are initially false. + /// + public BitSet() + { + InitWords(BITS_PER_WORD); + sizeIsSticky = false; + } + + /// + /// Creates a bit set whose initial size is large enough to explicitly + /// represent bits with indices in the range 0 through + /// nbits-1. All bits are initially false. + /// + /// The initial size of the bit set. + /// If the specified initial size is negative. + public BitSet(int nbits) + { + if (nbits < 0) throw new ArgumentOutOfRangeException(nameof(nbits), "nbits < 0"); + InitWords(nbits); + sizeIsSticky = true; + } + + /// + /// Creates a bit set using words as the internal representation. + /// The last word (if there is one) must be non-zero. + /// + private BitSet(ulong[] words) + { + this.words = words; + this.wordsInUse = words.Length; + CheckInvariants(); + } + + #endregion + + /// + /// Ensures that the BitSet can hold enough words. + /// + /// The minimum acceptable number of words. + private void EnsureCapacity(int wordsRequired) + { + if (words.Length < wordsRequired) + { + int request = Math.Max(2 * words.Length, wordsRequired); + Array.Resize(ref words, request); + sizeIsSticky = false; + } + } + + /// + /// Ensures that the BitSet can accommodate a given wordIndex, + /// temporarily violating the invariants. The caller must + /// restore the invariants before returning to the user, + /// possibly using . + /// + /// The index to be accommodated. + private void ExpandTo(int wordIndex) + { + int wordsRequired = wordIndex + 1; + if (wordsInUse < wordsRequired) + { + EnsureCapacity(wordsRequired); + wordsInUse = wordsRequired; + } + } + + /// + /// Checks that fromIndex ... toIndex is a valid range of bit indices. + /// + private static void CheckRange(int fromIndex, int toIndex) + { + if (fromIndex < 0) throw new ArgumentOutOfRangeException(nameof(fromIndex), "fromIndex < 0"); + if (toIndex < 0) throw new ArgumentOutOfRangeException(nameof(toIndex), "toIndex < 0"); + if (fromIndex > toIndex) throw new ArgumentOutOfRangeException(nameof(fromIndex), $"fromIndex: {fromIndex} > toIndex: {toIndex}"); + } + + /// + /// Sets all of the bits in this BitSet to false. + /// + public void Clear() + { + words.AsSpan(0, wordsInUse).Clear(); + } + + #region Single Bit Operations + + /// + /// Sets the bit at the specified index to the complement of its + /// current value. + /// + /// The index of the bit to flip. + /// If the specified index is negative. + public void Flip(int bitIndex) + { + if (bitIndex < 0) + throw new ArgumentOutOfRangeException(nameof(bitIndex), "bitIndex < 0"); + + int wordIndex = WordIndex(bitIndex); + ExpandTo(wordIndex); + + words[wordIndex] ^= (1UL << bitIndex); + + RecalculateWordsInUse(); + CheckInvariants(); + } + + /// + /// Sets the bit at the specified index to true. + /// + /// A bit index. + /// If the specified index is negative. + public void Set(int bitIndex) + { + if (bitIndex < 0) + throw new ArgumentOutOfRangeException(nameof(bitIndex), "bitIndex < 0"); + + int wordIndex = WordIndex(bitIndex); + ExpandTo(wordIndex); + + words[wordIndex] |= (1UL << bitIndex); // Restores invariants + + CheckInvariants(); + } + + /// + /// Sets the bit at the specified index to the specified value. + /// + /// A bit index. + /// A boolean value to set. + /// If the specified index is negative. + public void Set(int bitIndex, bool value) + { + if (value) + Set(bitIndex); + else + Clear(bitIndex); + } + + /// + /// Sets the bit specified by the index to false. + /// + /// The index of the bit to be cleared. + /// If the specified index is negative. + public void Clear(int bitIndex) + { + if (bitIndex < 0) + throw new ArgumentOutOfRangeException(nameof(bitIndex), "bitIndex < 0"); + + int wordIndex = WordIndex(bitIndex); + if (wordIndex >= wordsInUse) + return; + + words[wordIndex] &= ~(1UL << bitIndex); + + RecalculateWordsInUse(); + CheckInvariants(); + } + + /// + /// Returns the index of the first bit that is set to true + /// that occurs on or after the specified starting index. If no such + /// bit exists then -1 is returned. + /// + /// The index to start checking from (inclusive). + /// The index of the next set bit, or -1 if there is no such bit. + /// If the specified index is negative. + public int NextSetBit(int fromIndex) + { + if (fromIndex < 0) + throw new ArgumentOutOfRangeException(nameof(fromIndex), "fromIndex < 0"); + + CheckInvariants(); + + int u = WordIndex(fromIndex); + if (u >= wordsInUse) + return -1; + + ulong word = words[u] & (WORD_MASK << fromIndex); + + + // TODO: Use Span + while (true) + { + if (word != 0) + return (u * BITS_PER_WORD) + BitOperations.TrailingZeroCount(word); + if (++u == wordsInUse) + return -1; + word = words[u]; + } + } + + /// + /// Returns the index of the first bit that is set to false + /// that occurs on or after the specified starting index. + /// + /// The index to start checking from (inclusive). + /// The index of the next clear bit. + /// If the specified index is negative. + public int NextClearBit(int fromIndex) + { + if (fromIndex < 0) + throw new ArgumentOutOfRangeException(nameof(fromIndex), "fromIndex < 0"); + + CheckInvariants(); + + int u = WordIndex(fromIndex); + if (u >= wordsInUse) + return fromIndex; + + ulong word = ~words[u] & (WORD_MASK << fromIndex); + + while (true) + { + if (word != 0) + return (u * BITS_PER_WORD) + BitOperations.TrailingZeroCount(word); + if (++u == wordsInUse) + return wordsInUse * BITS_PER_WORD; + word = ~words[u]; + } + } + + /// + /// Returns the index of the nearest bit that is set to true + /// that occurs on or before the specified starting index. + /// If no such bit exists, or if -1 is given as the + /// starting index, then -1 is returned. + /// + /// The index to start checking from (inclusive). + /// The index of the previous set bit, or -1 if there is no such bit. + /// If the specified index is less than -1. + public int PreviousSetBit(int fromIndex) + { + if (fromIndex < 0) + { + if (fromIndex == -1) + return -1; + throw new ArgumentOutOfRangeException(nameof(fromIndex), "fromIndex < -1"); + } + + CheckInvariants(); + + int u = WordIndex(fromIndex); + if (u >= wordsInUse) + return Length() - 1; + + ulong word = words[u] & (WORD_MASK >> -(fromIndex + 1)); + + while (true) + { + if (word != 0) + return (u + 1) * BITS_PER_WORD - 1 - BitOperations.LeadingZeroCount(word); + if (u-- == 0) + return -1; + word = words[u]; + } + } + + /// + /// Returns the index of the nearest bit that is set to false + /// that occurs on or before the specified starting index. + /// If no such bit exists, or if -1 is given as the + /// starting index, then -1 is returned. + /// + /// The index to start checking from (inclusive). + /// The index of the previous clear bit, or -1 if there is no such bit. + /// If the specified index is less than -1. + public int PreviousClearBit(int fromIndex) + { + if (fromIndex < 0) + { + if (fromIndex == -1) + return -1; + throw new ArgumentOutOfRangeException(nameof(fromIndex), "fromIndex < -1"); + } + + CheckInvariants(); + + int u = WordIndex(fromIndex); + if (u >= wordsInUse) + return fromIndex; + + ulong word = ~words[u] & (WORD_MASK >> -(fromIndex + 1)); + + while (true) + { + if (word != 0) + return (u + 1) * BITS_PER_WORD - 1 - BitOperations.LeadingZeroCount(word); + if (u-- == 0) + return -1; + word = ~words[u]; + } + } + + /// + /// Returns the value of the bit with the specified index. The value + /// is true if the bit with the index bitIndex + /// is currently set in this BitSet; otherwise, the result + /// is false. + /// + /// The bit index. + /// The value of the bit with the specified index. + /// If the specified index is negative. + public bool Get(int bitIndex) + { + if (bitIndex < 0) throw new ArgumentOutOfRangeException(nameof(bitIndex), "bitIndex < 0"); + + CheckInvariants(); + + int wordIndex = WordIndex(bitIndex); + return (wordIndex < wordsInUse) && ((words[wordIndex] & (1UL << bitIndex)) != 0); + } + + #endregion + + #region BitSet Operations + + + /// + /// Returns a new composed of bits from this + /// from (inclusive) to (exclusive). + /// + /// Index of the first bit to include. + /// Index after the last bit to include. + /// A new from a range of this . + /// If is negative, + /// or is negative, or is + /// larger than . + public BitSet Get(int fromIndex, int toIndex) + { + CheckRange(fromIndex, toIndex); + CheckInvariants(); + + int len = Length(); + + // If no set bits in range return empty bitset + if (len <= fromIndex || fromIndex == toIndex) + return new BitSet(0); + + // An optimization + if (toIndex > len) + toIndex = len; + + BitSet result = new BitSet(toIndex - fromIndex); + int targetWords = WordIndex(toIndex - fromIndex - 1) + 1; + int sourceIndex = WordIndex(fromIndex); + bool wordAligned = ((fromIndex & BIT_INDEX_MASK) == 0); + + // Process all words but the last word + for (int i = 0; i < targetWords - 1; i++, sourceIndex++) + result.words[i] = wordAligned ? words[sourceIndex] : + (words[sourceIndex] >>> fromIndex) | + (words[sourceIndex + 1] << -fromIndex); + + // Process the last word + ulong lastWordMask = WORD_MASK >>> -toIndex; + result.words[targetWords - 1] = + ((toIndex - 1) & BIT_INDEX_MASK) < (fromIndex & BIT_INDEX_MASK) + ? /* straddles source words */ + ((words[sourceIndex] >>> fromIndex) | + (words[sourceIndex + 1] & lastWordMask) << -fromIndex) + : + ((words[sourceIndex] & lastWordMask) >>> fromIndex); + + // Set wordsInUse correctly + result.wordsInUse = targetWords; + result.RecalculateWordsInUse(); + result.CheckInvariants(); + + return result; + } + + /// + /// Sets the bits from the specified (inclusive) to the + /// specified (exclusive) to true. + /// + /// Index of the first bit to be set. + /// Index after the last bit to be set. + /// If is negative, + /// or is negative, or is + /// larger than . + public void Set(int fromIndex, int toIndex) + { + CheckRange(fromIndex, toIndex); + + if (fromIndex == toIndex) + return; + + // Increase capacity if necessary + int startWordIndex = WordIndex(fromIndex); + int endWordIndex = WordIndex(toIndex - 1); + ExpandTo(endWordIndex); + + ulong firstWordMask = WORD_MASK << fromIndex; + ulong lastWordMask = WORD_MASK >>> -toIndex; + if (startWordIndex == endWordIndex) + { + // Case 1: One word + words[startWordIndex] |= (firstWordMask & lastWordMask); + } + else + { + // Case 2: Multiple words + // Handle first word + words[startWordIndex] |= firstWordMask; + + // Handle intermediate words, if any + for (int i = startWordIndex + 1; i < endWordIndex; i++) + words[i] = WORD_MASK; + + // Handle last word (restores invariants) + words[endWordIndex] |= lastWordMask; + } + + CheckInvariants(); + } + + /// + /// Sets the bits from the specified (inclusive) to the + /// specified (exclusive) to the specified value. + /// + /// Index of the first bit to be set. + /// Index after the last bit to be set. + /// Value to set the selected bits to. + /// If is negative, + /// or is negative, or is + /// larger than . + public void Set(int fromIndex, int toIndex, bool value) + { + if (value) + Set(fromIndex, toIndex); + else + Clear(fromIndex, toIndex); + } + + /// + /// Sets the bits from the specified (inclusive) to the + /// specified (exclusive) to false. + /// + /// Index of the first bit to be cleared. + /// Index after the last bit to be cleared. + /// If is negative, + /// or is negative, or is + /// larger than . + public void Clear(int fromIndex, int toIndex) + { + CheckRange(fromIndex, toIndex); + + if (fromIndex == toIndex) + return; + + int startWordIndex = WordIndex(fromIndex); + if (startWordIndex >= wordsInUse) + return; + + int endWordIndex = WordIndex(toIndex - 1); + if (endWordIndex >= wordsInUse) + { + toIndex = Length(); + endWordIndex = wordsInUse - 1; + } + + ulong firstWordMask = WORD_MASK << fromIndex; + ulong lastWordMask = WORD_MASK >>> -toIndex; + if (startWordIndex == endWordIndex) + { + // Case 1: One word + words[startWordIndex] &= ~(firstWordMask & lastWordMask); + } + else + { + // Case 2: Multiple words + // Handle first word + words[startWordIndex] &= ~firstWordMask; + + // Handle intermediate words, if any + for (int i = startWordIndex + 1; i < endWordIndex; i++) + words[i] = 0; + + // Handle last word + words[endWordIndex] &= ~lastWordMask; + } + + RecalculateWordsInUse(); + CheckInvariants(); + } + + /// + /// Sets each bit from the specified (inclusive) to the + /// specified (exclusive) to the complement of its current + /// value. + /// + /// Index of the first bit to flip. + /// Index after the last bit to flip. + /// If is negative, + /// or is negative, or is + /// larger than . + public void Flip(int fromIndex, int toIndex) + { + CheckRange(fromIndex, toIndex); + + if (fromIndex == toIndex) + return; + + int startWordIndex = WordIndex(fromIndex); + int endWordIndex = WordIndex(toIndex - 1); + ExpandTo(endWordIndex); + + ulong firstWordMask = WORD_MASK << fromIndex; + ulong lastWordMask = WORD_MASK >>> -toIndex; + if (startWordIndex == endWordIndex) + { + // Case 1: One word + words[startWordIndex] ^= (firstWordMask & lastWordMask); + } + else + { + // Case 2: Multiple words + // Handle first word + words[startWordIndex] ^= firstWordMask; + + // Handle intermediate words, if any + for (int i = startWordIndex + 1; i < endWordIndex; i++) + words[i] ^= WORD_MASK; + + // Handle last word + words[endWordIndex] ^= lastWordMask; + } + + RecalculateWordsInUse(); + CheckInvariants(); + } + + #endregion + + #region Serialization + + /// + /// Returns a new bit set containing all the bits in the given ulong array. + /// + /// A ulong array containing a little-endian representation + /// of a sequence of bits to be used as the initial bits of the new bit set. + /// A new containing all the bits in the given ulong array. + public static BitSet Create(ReadOnlySpan longs) + { + if (longs.IsEmpty) + return new BitSet(); + + var lastUsedIndex = longs.LastIndexOfAnyExcept(0ul); + var newWords = longs.Slice(0, lastUsedIndex + 1).ToArray(); + return new BitSet(newWords); + } + + /// + /// Returns a new bit set containing all the bits in the given byte array. + /// + /// A byte array containing a little-endian representation + /// of a sequence of bits to be used as the initial bits of the new bit set. + /// A new containing all the bits in the given byte array. + public static BitSet Create(ReadOnlySpan bytes) + { + if (bytes.Length % 8 != 0) + throw new ArgumentException("byte array length must be a multiple of 8", nameof(bytes)); + return Create(MemoryMarshal.Cast(bytes)); + } + + /// + /// Returns a new byte array containing all the bits in this bit set. + /// + /// A byte array containing a little-endian representation + /// of all the bits in this bit set. + public byte[] ToByteArray() + { + var bytes = new byte[wordsInUse * 8]; + WriteTo(MemoryMarshal.Cast(bytes)); + return bytes; + } + + /// + /// Returns a new long array containing all the bits in this bit set. + /// + /// A long array containing a little-endian representation + /// of all the bits in this bit set. + public ulong[] ToLongArray() + { + var newWords = words.AsSpan(0, wordsInUse).ToArray(); + return newWords; + } + + public void WriteTo(Span longs) + { + if (longs.Length < wordsInUse) + throw new ArgumentException("byte array length is too small", nameof(longs)); + + words.AsSpan(0, wordsInUse).CopyTo(longs); + } + + #endregion + + #region Logical BitSet Operations + + /// + /// Returns true if the specified has any bits set to + /// true that are also set to true in this . + /// + /// to intersect with. + /// Boolean indicating whether this intersects + /// the specified . + public bool Intersects(BitSet set) + { + // TODO: Optimize using Vector + for (int i = Math.Min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--) + if ((words[i] & set.words[i]) != 0) + return true; + return false; + } + + /// + /// Returns the number of bits set to true in this . + /// + /// The number of bits set to true in this . + public int Cardinality() + { + // TODO: Optimize using Vector + int sum = 0; + for (int i = 0; i < wordsInUse; i++) + sum += BitOperations.PopCount(words[i]); + return sum; + } + + /// + /// Performs a logical AND of this target bit set with the + /// argument bit set. This bit set is modified so that each bit in it + /// has the value true if and only if it both initially + /// had the value true and the corresponding bit in the + /// bit set argument also had the value true. + /// + /// A bit set. + public void And(BitSet set) + { + if (this == set) + return; + + words.AsSpan(set.wordsInUse, wordsInUse - set.wordsInUse).Clear(); + + // TODO: Optimize using Vector + // Perform logical AND on words in common + for (int i = 0; i < wordsInUse; i++) + words[i] &= set.words[i]; + + RecalculateWordsInUse(); + CheckInvariants(); + } + + /// + /// Performs a logical OR of this bit set with the bit set + /// argument. This bit set is modified so that a bit in it has the + /// value true if and only if it either already had the + /// value true or the corresponding bit in the bit set + /// argument has the value true. + /// + /// A bit set. + public void Or(BitSet set) + { + if (this == set) + return; + + int wordsInCommon = Math.Min(wordsInUse, set.wordsInUse); + + if (wordsInUse < set.wordsInUse) + { + EnsureCapacity(set.wordsInUse); + wordsInUse = set.wordsInUse; + } + + // TODO: Optimize using Vector + // Perform logical OR on words in common + for (int i = 0; i < wordsInCommon; i++) + words[i] |= set.words[i]; + + // Copy any remaining words + if (wordsInCommon < set.wordsInUse) + Array.Copy(set.words, wordsInCommon, words, wordsInCommon, set.wordsInUse - wordsInCommon); + + // RecalculateWordsInUse() is unnecessary + CheckInvariants(); + } + + /// + /// Performs a logical XOR of this bit set with the bit set + /// argument. This bit set is modified so that a bit in it has the + /// value true if and only if one of the following + /// statements holds: + /// + /// The bit initially has the value true, and the + /// corresponding bit in the argument has the value false. + /// The bit initially has the value false, and the + /// corresponding bit in the argument has the value true. + /// + /// + /// A bit set. + public void Xor(BitSet set) + { + int wordsInCommon = Math.Min(wordsInUse, set.wordsInUse); + + if (wordsInUse < set.wordsInUse) + { + EnsureCapacity(set.wordsInUse); + wordsInUse = set.wordsInUse; + } + + // TODO: Optimize using Vector + // Perform logical XOR on words in common + for (int i = 0; i < wordsInCommon; i++) + words[i] ^= set.words[i]; + + // Copy any remaining words + if (wordsInCommon < set.wordsInUse) + Array.Copy(set.words, wordsInCommon, words, wordsInCommon, set.wordsInUse - wordsInCommon); + + RecalculateWordsInUse(); + CheckInvariants(); + } + + /// + /// Clears all of the bits in this whose corresponding + /// bit is set in the specified . + /// + /// The with which to mask this + /// . + public void AndNot(BitSet set) + { + // TODO: Optimize using Vector + // Perform logical (a & !b) on words in common + for (int i = Math.Min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--) + words[i] &= ~set.words[i]; + + RecalculateWordsInUse(); + CheckInvariants(); + } + + #endregion + + #region HashCode, Equals, Clone and ToString + + /// + /// Returns the hash code value for this bit set. The hash code depends + /// only on which bits are set within this . + /// + /// The hash code value for this bit set. + public override int GetHashCode() + { + ulong h = 1234; + // TODO: Optimize using Vector + for (int i = wordsInUse; --i >= 0;) + h ^= words[i] * (ulong)(i + 1); + + return (int)((h >> 32) ^ h); + } + + /// + /// + /// + /// + /// + public bool Equals(BitSet? other) + { + if (other == null) + return false; + if (ReferenceEquals(this, other)) + return true; + + CheckInvariants(); + other.CheckInvariants(); + + if (wordsInUse != other.wordsInUse) + return false; + + // Check words in use by both BitSets + return words.AsSpan(0, wordsInUse).SequenceEqual(other.words.AsSpan(0, wordsInUse)); + } + + /// + /// Compares this object against the specified object. + /// The result is true if and only if the argument is + /// not null and is a object that has + /// exactly the same set of bits set to true as this bit + /// set. + /// + /// The object to compare with. + /// true if the objects are the same; false otherwise. + public override bool Equals(object? obj) + { + if (ReferenceEquals(this, obj)) + return true; + if (obj is not BitSet other) + return false; + + return Equals(other); + } + + /// + /// Cloning this produces a new + /// that is equal to it. + /// The clone of the bit set is another bit set that has exactly the + /// same bits set to true as this bit set. + /// + /// A clone of this bit set. + public BitSet CloneTyped() + { + if (!sizeIsSticky) + TrimToSize(); + + try + { + BitSet result = (BitSet)MemberwiseClone(); + result.words = (ulong[])words.Clone(); + result.CheckInvariants(); + return result; + } + catch (Exception e) + { + throw new InvalidOperationException("Clone not supported", e); + } + } + + /// + /// + /// + public object Clone() + { + return CloneTyped(); + } + + /// + /// Returns a string representation of this bit set. For every index + /// for which this contains a bit in the set + /// state, the decimal representation of that index is included in + /// the result. Such indices are listed in order from lowest to + /// highest, separated by ", " (a comma and a space) and + /// surrounded by braces, resulting in the usual mathematical + /// notation for a set of integers. + /// + /// A string representation of this bit set. + public override string ToString() + { + CheckInvariants(); + + int numBits = (wordsInUse > 128) ? Cardinality() : wordsInUse * BITS_PER_WORD; + StringBuilder b = new StringBuilder(6 * numBits + 2); + b.Append('{'); + + int i = NextSetBit(0); + if (i != -1) + { + b.Append(i); + for (i = NextSetBit(i + 1); i >= 0; i = NextSetBit(i + 1)) + { + int endOfRun = NextClearBit(i); + do { b.Append(", ").Append(i); } + while (++i < endOfRun); + } + } + + b.Append('}'); + return b.ToString(); + } + + #endregion + + /// + /// Returns the number of bits of space actually in use by this + /// BitSet to represent bit values. + /// The maximum element in the set is the size - 1st element. + /// + /// The number of bits currently in this bit set. + public int Size() => words.Length * BITS_PER_WORD; + + /// + /// Attempts to reduce internal storage used for the bits in this bit set. + /// Calling this method may, but is not required to, affect the value + /// returned by a subsequent call to the method. + /// + private void TrimToSize() + { + if (wordsInUse != words.Length) + { + Array.Resize(ref words, wordsInUse); + CheckInvariants(); + } + } + + /// + /// Returns the "logical size" of this BitSet: the index of + /// the highest set bit in the BitSet plus one. Returns zero + /// if the BitSet contains no set bits. + /// + /// The logical size of this BitSet. + public int Length() + { + if (wordsInUse == 0) return 0; + + return BITS_PER_WORD * (wordsInUse - 1) + (BITS_PER_WORD - BitOperations.LeadingZeroCount(words[wordsInUse - 1])); + } + + /// + /// Returns true if this BitSet contains no bits that are set + /// to true. + /// + /// Boolean indicating whether this BitSet is empty. + public bool IsEmpty() => wordsInUse == 0; +} diff --git a/MineSharp.Core/Serialization/PacketBuffer.cs b/MineSharp.Core/Serialization/PacketBuffer.cs index c0af246e..d36329b6 100644 --- a/MineSharp.Core/Serialization/PacketBuffer.cs +++ b/MineSharp.Core/Serialization/PacketBuffer.cs @@ -327,6 +327,13 @@ public Uuid ReadUuid() return new(bytes); } + public BitSet ReadBitSet() + { + var length = ReadVarInt(); + var bytes = ReadBytes(length * sizeof(ulong)); + return BitSet.Create(bytes); + } + public T[] ReadVarIntArray(Func reader) { var array = new T[ReadVarInt()]; @@ -605,6 +612,13 @@ public void WriteUuid(Uuid value) WriteBytes(bytes); } + public void WriteBitSet(BitSet bitSet) + { + var bytes = bitSet.ToByteArray(); + WriteVarInt(bytes.Length / sizeof(ulong)); + WriteBytes(bytes); + } + public void WriteVarIntArray(ICollection collection, Action writer) { WriteVarInt(collection.Count); From ff5087bf0acb63ed1d47949ef876a9df27f61bd2 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Sat, 10 Aug 2024 03:44:10 +0200 Subject: [PATCH 58/73] fixed CombatDeathPacket --- .../Clientbound/Play/CombatDeathPacket.cs | 15 ++++++----- .../Packets/Clientbound/Play/RespawnPacket.cs | 27 ++++++++++--------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/CombatDeathPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/CombatDeathPacket.cs index e7c13a53..b3b7bb04 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/CombatDeathPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/CombatDeathPacket.cs @@ -1,4 +1,5 @@ -using MineSharp.Core; +using MineSharp.ChatComponent; +using MineSharp.Core; using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; @@ -29,7 +30,7 @@ private CombatDeathPacket() /// /// /// - public CombatDeathPacket(int playerId, int entityId, string message) + public CombatDeathPacket(int playerId, int entityId, Chat message) { PlayerId = playerId; EntityId = entityId; @@ -41,13 +42,13 @@ public CombatDeathPacket(int playerId, int entityId, string message) /// /// /// - public CombatDeathPacket(int playerId, string message) + public CombatDeathPacket(int playerId, Chat message) { PlayerId = playerId; Message = message; } - private CombatDeathPacket(int playerId, int? entityId, string message) + private CombatDeathPacket(int playerId, int? entityId, Chat message) { PlayerId = playerId; EntityId = entityId; @@ -67,7 +68,7 @@ private CombatDeathPacket(int playerId, int? entityId, string message) /// /// Death message /// - public string Message { get; init; } + public Chat Message { get; init; } /// public void Write(PacketBuffer buffer, MinecraftData version) @@ -78,7 +79,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteInt(EntityId!.Value); } - buffer.WriteString(Message); + buffer.WriteChatComponent(Message); } /// @@ -91,7 +92,7 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) entityId = buffer.ReadInt(); } - var message = buffer.ReadString(); + var message = buffer.ReadChatComponent(); return new CombatDeathPacket(playerId, entityId, message); } } diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs index 3f1ac620..683fc15a 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs @@ -12,8 +12,8 @@ public sealed record RespawnPacket( Identifier DimensionType, Identifier DimensionName, long HashedSeed, - sbyte GameMode, - byte PreviousGameMode, + byte GameMode, + sbyte PreviousGameMode, bool IsDebug, bool IsFlat, bool CopyMetadata, @@ -39,8 +39,8 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteIdentifier(DimensionType); buffer.WriteIdentifier(DimensionName); buffer.WriteLong(HashedSeed); - buffer.WriteSByte(GameMode); - buffer.WriteByte(PreviousGameMode); + buffer.WriteByte(GameMode); + buffer.WriteSByte(PreviousGameMode); buffer.WriteBool(IsDebug); buffer.WriteBool(IsFlat); buffer.WriteBool(CopyMetadata); @@ -50,17 +50,15 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteBool(HasDeathLocation.Value); } - if (!HasDeathLocation ?? false) + if ((HasDeathLocation ?? false)) { - return; + buffer.WriteIdentifier(DeathDimensionName!); + buffer.WritePosition(DeathLocation!); } - buffer.WriteIdentifier(DeathDimensionName!); - buffer.WritePosition(DeathLocation!); - if (version.Version.Protocol >= ProtocolVersion.V_1_20) { - buffer.WriteVarInt(PortalCooldown!.Value); + buffer.WriteVarInt(PortalCooldown ?? 0); } } @@ -80,8 +78,8 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) var dimensionName = buffer.ReadIdentifier(); var hashedSeed = buffer.ReadLong(); - var gameMode = buffer.ReadSByte(); - var previousGameMode = buffer.ReadByte(); + var gameMode = buffer.ReadByte(); + var previousGameMode = buffer.ReadSByte(); var isDebug = buffer.ReadBool(); var isFlat = buffer.ReadBool(); var copyMetadata = buffer.ReadBool(); @@ -92,7 +90,7 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) if (version.Version.Protocol >= ProtocolVersion.V_1_19) { hasDeathLocation = buffer.ReadBool(); - if (hasDeathLocation ?? false) + if (hasDeathLocation.Value) { deathDimensionName = buffer.ReadIdentifier(); deathLocation = buffer.ReadPosition(); @@ -105,6 +103,9 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) portalCooldown = buffer.ReadVarInt(); } + // Here is still something left in the buffer, but I can not figure out what it is. + // wiki.vg says something different for every version. But it does not match for the exact version I am using (1.20.4). + return new RespawnPacket( dimensionType, dimensionName, From 2d65b50dcfb700a898613c29c263560af81cfaac Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Sat, 10 Aug 2024 03:52:18 +0200 Subject: [PATCH 59/73] added missing Packets - Part 2 --- .../Clientbound/Play/HurtAnimationPacket.cs | 34 +++ .../Play/InitializeWorldBorderPacket.cs | 68 ++++++ .../Packets/Clientbound/Play/MapDataPacket.cs | 211 ++++++++++++++++++ .../Clientbound/Play/OpenHorseScreenPacket.cs | 40 ++++ .../Clientbound/Play/UpdateLightPacket.cs | 113 ++++++++++ .../Clientbound/Play/WorldEventPacket.cs | 156 +++++++++++++ .../Packets/PacketPalette.cs | 6 + 7 files changed, 628 insertions(+) create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/HurtAnimationPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/InitializeWorldBorderPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/MapDataPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenHorseScreenPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateLightPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/WorldEventPacket.cs diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/HurtAnimationPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/HurtAnimationPacket.cs new file mode 100644 index 00000000..2be5c4e5 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/HurtAnimationPacket.cs @@ -0,0 +1,34 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Hurt Animation packet +/// +/// The ID of the entity taking damage +/// The direction the damage is coming from in relation to the entity +public sealed record HurtAnimationPacket(int EntityId, float Yaw) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_HurtAnimation; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(EntityId); + buffer.WriteFloat(Yaw); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var entityId = buffer.ReadVarInt(); + var yaw = buffer.ReadFloat(); + + return new HurtAnimationPacket(entityId, yaw); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/InitializeWorldBorderPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/InitializeWorldBorderPacket.cs new file mode 100644 index 00000000..6f086d2e --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/InitializeWorldBorderPacket.cs @@ -0,0 +1,68 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Initialize World Border packet +/// +/// The X coordinate of the world border center +/// The Z coordinate of the world border center +/// Current length of a single side of the world border, in meters +/// Target length of a single side of the world border, in meters +/// Number of real-time milliseconds until New Diameter is reached +/// Resulting coordinates from a portal teleport are limited to ±value +/// Warning distance in meters +/// Warning time in seconds +public sealed record InitializeWorldBorderPacket( + double X, + double Z, + double OldDiameter, + double NewDiameter, + long Speed, + int PortalTeleportBoundary, + int WarningBlocks, + int WarningTime) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_InitializeWorldBorder; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteDouble(X); + buffer.WriteDouble(Z); + buffer.WriteDouble(OldDiameter); + buffer.WriteDouble(NewDiameter); + buffer.WriteVarLong(Speed); + buffer.WriteVarInt(PortalTeleportBoundary); + buffer.WriteVarInt(WarningBlocks); + buffer.WriteVarInt(WarningTime); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var x = buffer.ReadDouble(); + var z = buffer.ReadDouble(); + var oldDiameter = buffer.ReadDouble(); + var newDiameter = buffer.ReadDouble(); + var speed = buffer.ReadVarLong(); + var portalTeleportBoundary = buffer.ReadVarInt(); + var warningBlocks = buffer.ReadVarInt(); + var warningTime = buffer.ReadVarInt(); + + return new InitializeWorldBorderPacket( + x, + z, + oldDiameter, + newDiameter, + speed, + portalTeleportBoundary, + warningBlocks, + warningTime); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/MapDataPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/MapDataPacket.cs new file mode 100644 index 00000000..ca0a11d2 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/MapDataPacket.cs @@ -0,0 +1,211 @@ +using MineSharp.ChatComponent; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using static MineSharp.Protocol.Packets.Clientbound.Play.MapDataPacket; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Updates a rectangular area on a map item. +/// +/// Map ID of the map being modified +/// From 0 for a fully zoomed-in map (1 block per pixel) to 4 for a fully zoomed-out map (16 blocks per pixel) +/// True if the map has been locked in a cartography table +/// Indicates if the map has icons +/// Array of icons on the map +/// Details of the color patch update +public sealed record MapDataPacket(int MapId, byte Scale, bool Locked, bool HasIcons, Icon[]? Icons, ColorPatchInfo ColorPatch) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_Map; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(MapId); + buffer.WriteByte(Scale); + buffer.WriteBool(Locked); + buffer.WriteBool(HasIcons); + + if (HasIcons) + { + buffer.WriteVarInt(Icons?.Length ?? 0); + if (Icons != null) + { + foreach (var icon in Icons) + { + icon.Write(buffer); + } + } + } + + ColorPatch.Write(buffer); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var mapId = buffer.ReadVarInt(); + var scale = buffer.ReadByte(); + var locked = buffer.ReadBool(); + var hasIcons = buffer.ReadBool(); + + Icon[]? icons = null; + if (hasIcons) + { + var iconCount = buffer.ReadVarInt(); + icons = new Icon[iconCount]; + for (int i = 0; i < iconCount; i++) + { + icons[i] = Icon.Read(buffer); + } + } + + var colorPatch = ColorPatchInfo.Read(buffer); + + return new MapDataPacket(mapId, scale, locked, hasIcons, icons, colorPatch); + } + + /// + /// Represents an icon on the map. + /// + /// Type of the icon + /// X coordinate of the icon + /// Z coordinate of the icon + /// Direction of the icon + /// Indicates if the icon has a display name + /// Display name of the icon + public sealed record Icon(MapIconType Type, byte X, byte Z, byte Direction, bool HasDisplayName, Chat? DisplayName) : ISerializable + { + /// + public void Write(PacketBuffer buffer) + { + buffer.WriteVarInt((int)Type); + buffer.WriteByte(X); + buffer.WriteByte(Z); + buffer.WriteByte(Direction); + buffer.WriteBool(HasDisplayName); + if (HasDisplayName) + { + buffer.WriteChatComponent(DisplayName); + } + } + + /// + public static Icon Read(PacketBuffer buffer) + { + var type = (MapIconType)buffer.ReadVarInt(); + var x = buffer.ReadByte(); + var z = buffer.ReadByte(); + var direction = buffer.ReadByte(); + var hasDisplayName = buffer.ReadBool(); + Chat? displayName = null; + if (hasDisplayName) + { + displayName = buffer.ReadChatComponent(); + } + + return new Icon(type, x, z, direction, hasDisplayName, displayName); + } + } + + /// + /// Represents the color patch update on the map. + /// + /// Number of columns updated + /// Number of rows updated + /// X offset of the westernmost column + /// Z offset of the northernmost row + /// Length of the following array + /// Array of updated data + public sealed record ColorPatchInfo(byte Columns, byte? Rows, byte? X, byte? Z, int? Length, byte[]? Data) : ISerializable + { + /// + public void Write(PacketBuffer buffer) + { + buffer.WriteByte(Columns); + if (Columns > 0) + { + buffer.WriteByte(Rows ?? 0); + buffer.WriteByte(X ?? 0); + buffer.WriteByte(Z ?? 0); + buffer.WriteVarInt(Length ?? 0); + if (Data != null) + { + buffer.WriteBytes(Data); + } + } + } + + /// + public static ColorPatchInfo Read(PacketBuffer buffer) + { + var columns = buffer.ReadByte(); + byte? rows = null, x = null, z = null; + int? length = null; + byte[]? data = null; + + if (columns > 0) + { + rows = buffer.ReadByte(); + x = buffer.ReadByte(); + z = buffer.ReadByte(); + length = buffer.ReadVarInt(); + data = buffer.ReadBytes(length.Value); + } + + return new ColorPatchInfo(columns, rows, x, z, length, data); + } + } + + /// + /// Represents the types of icons on a map. + /// + public enum MapIconType + { +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + /// + /// Alternative meaning: players + /// + WhiteArrow = 0, + /// + /// Alternative meaning: item frames + /// + GreenArrow = 1, + RedArrow = 2, + BlueArrow = 3, + WhiteCross = 4, + RedPointer = 5, + /// + /// Alternative meaning: off-map players + /// + WhiteCircle = 6, + /// + /// Alternative meaning: far-off-map players + /// + SmallWhiteCircle = 7, + Mansion = 8, + Monument = 9, + WhiteBanner = 10, + OrangeBanner = 11, + MagentaBanner = 12, + LightBlueBanner = 13, + YellowBanner = 14, + LimeBanner = 15, + PinkBanner = 16, + GrayBanner = 17, + LightGrayBanner = 18, + CyanBanner = 19, + PurpleBanner = 20, + BlueBanner = 21, + BrownBanner = 22, + GreenBanner = 23, + RedBanner = 24, + BlackBanner = 25, + TreasureMarker = 26 +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenHorseScreenPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenHorseScreenPacket.cs new file mode 100644 index 00000000..b828788e --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenHorseScreenPacket.cs @@ -0,0 +1,40 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Open Horse Screen packet +/// +/// The window ID +/// The number of slots in the horse inventory +/// The entity ID of the horse +public sealed record OpenHorseScreenPacket(byte WindowId, int SlotCount, int EntityId) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_OpenHorseWindow; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteByte(WindowId); + buffer.WriteVarInt(SlotCount); + buffer.WriteInt(EntityId); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var windowId = buffer.ReadByte(); + var slotCount = buffer.ReadVarInt(); + var entityId = buffer.ReadInt(); + + return new OpenHorseScreenPacket( + windowId, + slotCount, + entityId); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateLightPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateLightPacket.cs new file mode 100644 index 00000000..034f5e6e --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateLightPacket.cs @@ -0,0 +1,113 @@ +using MineSharp.Core.Common; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using static MineSharp.Protocol.Packets.Clientbound.Play.UpdateLightPacket; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Updates light levels for a chunk. +/// +/// Chunk coordinate (block coordinate divided by 16, rounded down) +/// Chunk coordinate (block coordinate divided by 16, rounded down) +/// BitSet for sky light sections +/// BitSet for block light sections +/// BitSet for empty sky light sections +/// BitSet for empty block light sections +/// Array of sky light data +/// Array of block light data +public sealed record UpdateLightPacket( + int ChunkX, + int ChunkZ, + BitSet SkyLightMask, + BitSet BlockLightMask, + BitSet EmptySkyLightMask, + BitSet EmptyBlockLightMask, + LightArray[] SkyLightArrays, + LightArray[] BlockLightArrays +) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_UpdateLight; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(ChunkX); + buffer.WriteVarInt(ChunkZ); + buffer.WriteBitSet(SkyLightMask); + buffer.WriteBitSet(BlockLightMask); + buffer.WriteBitSet(EmptySkyLightMask); + buffer.WriteBitSet(EmptyBlockLightMask); + buffer.WriteVarInt(SkyLightArrays.Length); + foreach (var array in SkyLightArrays) + { + array.Write(buffer); + } + buffer.WriteVarInt(BlockLightArrays.Length); + foreach (var array in BlockLightArrays) + { + array.Write(buffer); + } + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var chunkX = buffer.ReadVarInt(); + var chunkZ = buffer.ReadVarInt(); + var skyLightMask = buffer.ReadBitSet(); + var blockLightMask = buffer.ReadBitSet(); + var emptySkyLightMask = buffer.ReadBitSet(); + var emptyBlockLightMask = buffer.ReadBitSet(); + var skyLightArrayCount = buffer.ReadVarInt(); + var skyLightArrays = new LightArray[skyLightArrayCount]; + for (int i = 0; i < skyLightArrayCount; i++) + { + skyLightArrays[i] = LightArray.Read(buffer); + } + var blockLightArrayCount = buffer.ReadVarInt(); + var blockLightArrays = new LightArray[blockLightArrayCount]; + for (int i = 0; i < blockLightArrayCount; i++) + { + blockLightArrays[i] = LightArray.Read(buffer); + } + + return new UpdateLightPacket( + chunkX, + chunkZ, + skyLightMask, + blockLightMask, + emptySkyLightMask, + emptyBlockLightMask, + skyLightArrays, + blockLightArrays + ); + } + + /// + /// Represents a light array. + /// + /// Length of the array in bytes (always 2048) + /// The light data + public sealed record LightArray(int Length, byte[] Data) : ISerializable + { + /// + public void Write(PacketBuffer buffer) + { + buffer.WriteVarInt(Length); + buffer.WriteBytes(Data); + } + + /// + public static LightArray Read(PacketBuffer buffer) + { + var length = buffer.ReadVarInt(); + var data = buffer.ReadBytes(length); + return new LightArray(length, data); + } + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/WorldEventPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/WorldEventPacket.cs new file mode 100644 index 00000000..f10c7d53 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/WorldEventPacket.cs @@ -0,0 +1,156 @@ +using System.Diagnostics.Tracing; +using MineSharp.Core.Geometry; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using static MineSharp.Protocol.Packets.Clientbound.Play.WorldEventPacket; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Sent when a client is to play a sound or particle effect. +/// +/// The event, see below. +/// The location of the event. +/// Extra data for certain events, see below. +/// +/// If true, the effect is played from 2 blocks away in the correct direction, ignoring distance-based volume adjustment. +/// +public sealed record WorldEventPacket(EventType Event, Position Location, int Data, bool DisableRelativeVolume) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_WorldEvent; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteInt((int)Event); + buffer.WritePosition(Location); + buffer.WriteInt(Data); + buffer.WriteBool(DisableRelativeVolume); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var eventType = (EventType)buffer.ReadInt(); + var location = buffer.ReadPosition(); + var data = buffer.ReadInt(); + var disableRelativeVolume = buffer.ReadBool(); + + return new WorldEventPacket(eventType, location, data, disableRelativeVolume); + } + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + /// + /// Enum representing the possible events. + /// + public enum EventType + { + #region Sound Events + DispenserDispenses = 1000, + DispenserFailsToDispense = 1001, + DispenserShoots = 1002, + EnderEyeLaunched = 1003, + FireworkShot = 1004, + FireExtinguished = 1009, + /// + /// Meaning of Data field: + /// An ID in the minecraft:item registry, corresponding to a record item. + /// If the ID doesn't correspond to a record, the packet is ignored. + /// Any record already being played at the given location is overwritten. + /// See Data Generators for information on item IDs. + /// + PlayRecord = 1010, + StopRecord = 1011, + GhastWarns = 1015, + GhastShoots = 1016, + EnderdragonShoots = 1017, + BlazeShoots = 1018, + ZombieAttacksWoodDoor = 1019, + ZombieAttacksIronDoor = 1020, + ZombieBreaksWoodDoor = 1021, + WitherBreaksBlock = 1022, + WitherSpawned = 1023, + WitherShoots = 1024, + BatTakesOff = 1025, + ZombieInfects = 1026, + ZombieVillagerConverted = 1027, + EnderDragonDeath = 1028, + AnvilDestroyed = 1029, + AnvilUsed = 1030, + AnvilLanded = 1031, + PortalTravel = 1032, + ChorusFlowerGrown = 1033, + ChorusFlowerDied = 1034, + BrewingStandBrewed = 1035, + IronTrapdoorOpened = 1036, + IronTrapdoorClosed = 1037, + EndPortalCreatedInOverworld = 1038, + PhantomBites = 1039, + ZombieConvertsToDrowned = 1040, + HuskConvertsToZombieByDrowning = 1041, + GrindstoneUsed = 1042, + BookPageTurned = 1043, + #endregion + + #region Particle Events + ComposterComposts = 1500, + LavaConvertsBlock = 1501, + RedstoneTorchBurnsOut = 1502, + EnderEyePlaced = 1503, + /// + /// Meaning of Data field: + /// See + /// + SpawnsSmokeParticles = 2000, + /// + /// Meaning of Data field: + /// Block state ID (see Chunk Format#Block state registry). + /// + BlockBreak = 2001, + /// + /// Meaning of Data field: + /// RGB color as an integer (e.g. 8364543 for #7FA1FF). + /// + SplashPotion = 2002, + EyeOfEnderBreak = 2003, + MobSpawnParticleEffect = 2004, + /// + /// Meaning of Data field: + /// How many particles to spawn (if set to 0, 15 are spawned). + /// + BonemealParticles = 2005, + DragonBreath = 2006, + /// + /// Meaning of Data field: + /// RGB color as an integer (e.g. 8364543 for #7FA1FF). + /// + InstantSplashPotion = 2007, + EnderDragonDestroysBlock = 2008, + WetSpongeVaporizesInNether = 2009, + EndGatewaySpawn = 3000, + EnderdragonGrowl = 3001, + ElectricSpark = 3002, + CopperApplyWax = 3003, + CopperRemoveWax = 3004, + CopperScrapeOxidation = 3005 + #endregion + } + + /// + /// Enum representing the possible smoke directions. + /// + public enum SmokeDirection + { + Down = 0, + Up = 1, + North = 2, + South = 3, + West = 4, + East = 5 + } +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member +} diff --git a/Components/MineSharp.Protocol/Packets/PacketPalette.cs b/Components/MineSharp.Protocol/Packets/PacketPalette.cs index 0a718fc8..143282c0 100644 --- a/Components/MineSharp.Protocol/Packets/PacketPalette.cs +++ b/Components/MineSharp.Protocol/Packets/PacketPalette.cs @@ -175,6 +175,12 @@ void RegisterPacket() RegisterPacket(); RegisterPacket(); RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); RegisterPacket(); RegisterPacket(); From cef45a062dba2abc67ccb0cb5b46b7988283b43c Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Sat, 10 Aug 2024 14:33:03 +0200 Subject: [PATCH 60/73] fixed reading and writing of BitSet --- .../Packets/Clientbound/Play/MapDataPacket.cs | 2 +- .../Packets/Serverbound/Play/PongPacket.cs | 2 +- MineSharp.Core/Common/BitSet.cs | 7 +++++++ MineSharp.Core/Serialization/PacketBuffer.cs | 12 +++++------- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/MapDataPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/MapDataPacket.cs index ca0a11d2..5a0857bd 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/MapDataPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/MapDataPacket.cs @@ -90,7 +90,7 @@ public void Write(PacketBuffer buffer) buffer.WriteBool(HasDisplayName); if (HasDisplayName) { - buffer.WriteChatComponent(DisplayName); + buffer.WriteChatComponent(DisplayName!); } } diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PongPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PongPacket.cs index d8c1d2a3..90bdeff9 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/PongPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/PongPacket.cs @@ -7,7 +7,7 @@ namespace MineSharp.Protocol.Packets.Serverbound.Play; /// /// Pong Packet https://wiki.vg/Protocol#Ping_Response_.28play.29 /// -/// +/// public sealed record PongPacket(int Id) : IPacket { /// diff --git a/MineSharp.Core/Common/BitSet.cs b/MineSharp.Core/Common/BitSet.cs index ca0f322e..634cea42 100644 --- a/MineSharp.Core/Common/BitSet.cs +++ b/MineSharp.Core/Common/BitSet.cs @@ -105,6 +105,7 @@ private void InitWords(int nbits) #region Constructors +#pragma warning disable CS8618 // words in initialized in InitWords /// /// Creates a new bit set. All bits are initially false. /// @@ -138,6 +139,7 @@ private BitSet(ulong[] words) this.wordsInUse = words.Length; CheckInvariants(); } +#pragma warning restore CS8618 #endregion @@ -694,6 +696,11 @@ public ulong[] ToLongArray() return newWords; } + /// + /// Writes the bits in this bit set to the specified span of ulongs. + /// + /// A span of ulongs to write the bits to. + /// Thrown if the length of the span is less than the number of words in use. public void WriteTo(Span longs) { if (longs.Length < wordsInUse) diff --git a/MineSharp.Core/Serialization/PacketBuffer.cs b/MineSharp.Core/Serialization/PacketBuffer.cs index d36329b6..5e049881 100644 --- a/MineSharp.Core/Serialization/PacketBuffer.cs +++ b/MineSharp.Core/Serialization/PacketBuffer.cs @@ -329,9 +329,8 @@ public Uuid ReadUuid() public BitSet ReadBitSet() { - var length = ReadVarInt(); - var bytes = ReadBytes(length * sizeof(ulong)); - return BitSet.Create(bytes); + var longs = ReadLongArray(); + return BitSet.Create(MemoryMarshal.Cast(longs)); } public T[] ReadVarIntArray(Func reader) @@ -614,9 +613,8 @@ public void WriteUuid(Uuid value) public void WriteBitSet(BitSet bitSet) { - var bytes = bitSet.ToByteArray(); - WriteVarInt(bytes.Length / sizeof(ulong)); - WriteBytes(bytes); + var longs = bitSet.ToLongArray(); + WriteLongArray(MemoryMarshal.Cast(longs)); } public void WriteVarIntArray(ICollection collection, Action writer) @@ -629,7 +627,7 @@ public void WriteVarIntArray(ICollection collection, Action array) { WriteVarInt(array.Length); foreach (var l in array) From 422a80441ea89a92388e5e6400af4d0f54270e3b Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Sat, 10 Aug 2024 15:06:17 +0200 Subject: [PATCH 61/73] replaced IVersionAwareSerializable with ISerializableWithMinecraftData IVersionAwareSerializable was unnecessary because the buffer already knows the protocol version --- .../Clientbound/Play/PlayerChatPacket.cs | 4 ++-- .../Packets/NetworkTypes/ChatMessageItem.cs | 10 +++++----- .../ISerializableWithMinecraftData.cs | 12 ++++++------ .../Serverbound/Play/ChatCommandPacket.cs | 8 ++++---- .../Serverbound/Play/ChatMessagePacket.cs | 8 ++++---- .../Play/MessageAcknowledgementPacket.cs | 4 ++-- MineSharp.Core/Serialization/ISerializable.cs | 18 ++---------------- 7 files changed, 25 insertions(+), 39 deletions(-) rename MineSharp.Core/Serialization/IVersionAwareSerializable.cs => Components/MineSharp.Protocol/Packets/NetworkTypes/ISerializableWithMinecraftData.cs (67%) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerChatPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerChatPacket.cs index b23929fd..60d14ab1 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerChatPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerChatPacket.cs @@ -306,7 +306,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteLong(Timestamp); buffer.WriteLong(Salt); - buffer.WriteVarIntArray(PreviousMessages, (buf, val) => val.Write(buf, version.Version)); + buffer.WriteVarIntArray(PreviousMessages, (buf, val) => val.Write(buf)); var hasUnsignedContent = UnsignedContent != null; buffer.WriteBool(hasUnsignedContent); @@ -393,7 +393,7 @@ public static V11923Body Read(PacketBuffer buffer, MinecraftData version) timestamp = buffer.ReadLong(); salt = buffer.ReadLong(); - previousMessages = buffer.ReadVarIntArray(buff => ChatMessageItem.Read(buff, version.Version)); + previousMessages = buffer.ReadVarIntArray(ChatMessageItem.Read); var hasUnsignedContent = buffer.ReadBool(); unsignedContent = null; diff --git a/Components/MineSharp.Protocol/Packets/NetworkTypes/ChatMessageItem.cs b/Components/MineSharp.Protocol/Packets/NetworkTypes/ChatMessageItem.cs index 8ef77f17..252cdd30 100644 --- a/Components/MineSharp.Protocol/Packets/NetworkTypes/ChatMessageItem.cs +++ b/Components/MineSharp.Protocol/Packets/NetworkTypes/ChatMessageItem.cs @@ -7,7 +7,7 @@ namespace MineSharp.Protocol.Packets.NetworkTypes; /// /// Represents a signed chat message /// -public class ChatMessageItem : IVersionAwareSerializable +public class ChatMessageItem : ISerializable { /// /// Creates a new instance @@ -50,9 +50,9 @@ private ChatMessageItem(Uuid? sender, byte[]? signature) /// /// /// - public void Write(PacketBuffer buffer, MinecraftVersion version) + public void Write(PacketBuffer buffer) { - if (version.Protocol == ProtocolVersion.V_1_19_2) + if (buffer.ProtocolVersion == ProtocolVersion.V_1_19_2) { buffer.WriteUuid(Sender!.Value); buffer.WriteVarInt(Signature!.Length); @@ -74,12 +74,12 @@ public void Write(PacketBuffer buffer, MinecraftVersion version) /// /// /// - public static ChatMessageItem Read(PacketBuffer buffer, MinecraftVersion version) + public static ChatMessageItem Read(PacketBuffer buffer) { Uuid? uuid = null; byte[]? signature = null; - if (version.Protocol == ProtocolVersion.V_1_19_2) + if (buffer.ProtocolVersion == ProtocolVersion.V_1_19_2) { uuid = buffer.ReadUuid(); signature = new byte[buffer.ReadVarInt()]; diff --git a/MineSharp.Core/Serialization/IVersionAwareSerializable.cs b/Components/MineSharp.Protocol/Packets/NetworkTypes/ISerializableWithMinecraftData.cs similarity index 67% rename from MineSharp.Core/Serialization/IVersionAwareSerializable.cs rename to Components/MineSharp.Protocol/Packets/NetworkTypes/ISerializableWithMinecraftData.cs index d9473a5a..f80eb65a 100644 --- a/MineSharp.Core/Serialization/IVersionAwareSerializable.cs +++ b/Components/MineSharp.Protocol/Packets/NetworkTypes/ISerializableWithMinecraftData.cs @@ -1,4 +1,4 @@ -using MineSharp.Core.Common; +using MineSharp.Data; namespace MineSharp.Core.Serialization; @@ -7,20 +7,20 @@ namespace MineSharp.Core.Serialization; /// while being aware of the Minecraft version /// /// -public interface IVersionAwareSerializable where T : IVersionAwareSerializable +public interface ISerializableWithMinecraftData where T : ISerializableWithMinecraftData { /// /// Serialize the object into the buffer /// /// - /// - public void Write(PacketBuffer buffer, MinecraftVersion version); + /// + public void Write(PacketBuffer buffer, MinecraftData data); /// /// Read the object from the buffer /// /// - /// + /// /// - public static abstract T Read(PacketBuffer buffer, MinecraftVersion version); + public static abstract T Read(PacketBuffer buffer, MinecraftData data); } diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatCommandPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatCommandPacket.cs index 6b7088f0..b1dc971b 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatCommandPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatCommandPacket.cs @@ -138,7 +138,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) throw new MineSharpPacketVersionException(nameof(PreviousMessages), version.Version.Protocol); } - buffer.WriteVarIntArray(PreviousMessages, (buf, val) => val.Write(buf, version.Version)); + buffer.WriteVarIntArray(PreviousMessages, (buf, val) => val.Write(buf)); var hasLastRejectedMessage = LastRejectedMessage != null; buffer.WriteBool(hasLastRejectedMessage); @@ -148,7 +148,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) return; } - LastRejectedMessage!.Write(buffer, version.Version); + LastRejectedMessage!.Write(buffer); } private const int AfterMc1192AcknowledgedLength = 20; @@ -178,11 +178,11 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) ChatMessageItem? lastRejectedMessage = null; if (version.Version.Protocol == ProtocolVersion.V_1_19_2) { - previousMessages = buffer.ReadVarIntArray((buf) => ChatMessageItem.Read(buf, version.Version)); + previousMessages = buffer.ReadVarIntArray(ChatMessageItem.Read); var hasLastRejectedMessage = buffer.ReadBool(); if (hasLastRejectedMessage) { - lastRejectedMessage = ChatMessageItem.Read(buffer, version.Version); + lastRejectedMessage = ChatMessageItem.Read(buffer); } } diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatMessagePacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatMessagePacket.cs index c9809c89..48cb27ce 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatMessagePacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/ChatMessagePacket.cs @@ -122,7 +122,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) throw new MineSharpPacketVersionException(nameof(PreviousMessages), version.Version.Protocol); } - buffer.WriteVarIntArray(PreviousMessages, (buf, val) => val.Write(buf, version.Version)); + buffer.WriteVarIntArray(PreviousMessages, (buf, val) => val.Write(buf)); var hasLastRejectedMessage = LastRejectedMessage != null; buffer.WriteBool(hasLastRejectedMessage); @@ -132,7 +132,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) return; } - LastRejectedMessage!.Write(buffer, version.Version); + LastRejectedMessage!.Write(buffer); } public static IPacket Read(PacketBuffer buffer, MinecraftData version) @@ -180,12 +180,12 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) } - previousMessages = buffer.ReadVarIntArray(buff => ChatMessageItem.Read(buff, version.Version)); + previousMessages = buffer.ReadVarIntArray(ChatMessageItem.Read); var hasLastRejectedMessage = buffer.ReadBool(); if (hasLastRejectedMessage) { - lastRejectedMessage = ChatMessageItem.Read(buffer, version.Version); + lastRejectedMessage = ChatMessageItem.Read(buffer); } else { diff --git a/Components/MineSharp.Protocol/Packets/Serverbound/Play/MessageAcknowledgementPacket.cs b/Components/MineSharp.Protocol/Packets/Serverbound/Play/MessageAcknowledgementPacket.cs index 901bed04..b7e4afb1 100644 --- a/Components/MineSharp.Protocol/Packets/Serverbound/Play/MessageAcknowledgementPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Serverbound/Play/MessageAcknowledgementPacket.cs @@ -59,7 +59,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) throw new MineSharpPacketVersionException(nameof(PreviousMessages), version.Version.Protocol); } - buffer.WriteVarIntArray(PreviousMessages, (buf, val) => val.Write(buf, version.Version)); + buffer.WriteVarIntArray(PreviousMessages, (buf, val) => val.Write(buf)); var hasLastRejectedMessage = LastRejectedMessage != null; buffer.WriteBool(hasLastRejectedMessage); @@ -68,7 +68,7 @@ public void Write(PacketBuffer buffer, MinecraftData version) return; } - LastRejectedMessage!.Write(buffer, version.Version); + LastRejectedMessage!.Write(buffer); } public static IPacket Read(PacketBuffer buffer, MinecraftData version) diff --git a/MineSharp.Core/Serialization/ISerializable.cs b/MineSharp.Core/Serialization/ISerializable.cs index e5b535e2..eed07f80 100644 --- a/MineSharp.Core/Serialization/ISerializable.cs +++ b/MineSharp.Core/Serialization/ISerializable.cs @@ -1,12 +1,10 @@ -using MineSharp.Core.Common; - -namespace MineSharp.Core.Serialization; +namespace MineSharp.Core.Serialization; /// /// Interface for serializing and deserializing objects from and to /// /// -public interface ISerializable : IVersionAwareSerializable +public interface ISerializable where T : ISerializable { /// @@ -15,22 +13,10 @@ public interface ISerializable : IVersionAwareSerializable /// public void Write(PacketBuffer buffer); - /// - void IVersionAwareSerializable.Write(PacketBuffer buffer, MinecraftVersion version) - { - Write(buffer); - } - /// /// Read the object from the buffer /// /// /// public static abstract T Read(PacketBuffer buffer); - - /// - static T IVersionAwareSerializable.Read(PacketBuffer buffer, MinecraftVersion version) - { - return T.Read(buffer); - } } From 35be4a0afd7ef447ccd3ea9011169710ba8681f9 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Sat, 10 Aug 2024 16:01:56 +0200 Subject: [PATCH 62/73] added missing Packets - Part 3 --- .../Clientbound/Play/AddResourcePackPacket.cs | 51 +++++++ .../Play/DisplayObjectivePacket.cs | 34 +++++ .../Clientbound/Play/EndCombatPacket.cs | 30 ++++ .../Clientbound/Play/EnterCombatPacket.cs | 29 ++++ .../Packets/Clientbound/Play/LookAtPacket.cs | 77 ++++++++++ .../Clientbound/Play/MerchantOffersPacket.cs | 107 ++++++++++++++ .../Clientbound/Play/MoveVehiclePacket.cs | 43 ++++++ .../Clientbound/Play/OpenBookPacket.cs | 31 +++++ .../Clientbound/Play/OpenSignEditorPacket.cs | 36 +++++ .../Play/PlaceGhostRecipePacket.cs | 35 +++++ .../Clientbound/Play/PlayerAbilitiesPacket.cs | 63 +++++++++ .../Play/RemoveEntityEffectPacket.cs | 34 +++++ .../Play/RemoveResourcePackPacket.cs | 38 +++++ .../Clientbound/Play/ResetScorePacket.cs | 44 ++++++ .../Play/SelectAdvancementTabPacket.cs | 52 +++++++ .../Clientbound/Play/ServerDataPacket.cs | 51 +++++++ .../Play/SetActionBarTextPacket.cs | 32 +++++ .../Clientbound/Play/SetBorderCenterPacket.cs | 34 +++++ .../Play/SetBorderLerpSizePacket.cs | 37 +++++ .../Clientbound/Play/SetBorderSizePacket.cs | 30 ++++ .../Play/SetBorderWarningDelayPacket.cs | 30 ++++ .../Play/SetBorderWarningDistancePacket.cs | 30 ++++ .../Clientbound/Play/SetCameraPacket.cs | 30 ++++ .../Clientbound/Play/SetCenterChunkPacket.cs | 34 +++++ .../Play/SetDefaultSpawnPositionPacket.cs | 35 +++++ .../Clientbound/Play/SetHeadRotationPacket.cs | 34 +++++ .../Play/SetRenderDistancePacket.cs | 31 +++++ .../Play/UpdateRecipeBookPacket.cs | 131 ++++++++++++++++++ .../Packets/PacketPalette.cs | 36 ++++- 29 files changed, 1277 insertions(+), 2 deletions(-) create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/AddResourcePackPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/DisplayObjectivePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/EndCombatPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/EnterCombatPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/LookAtPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/MerchantOffersPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/MoveVehiclePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenBookPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenSignEditorPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/PlaceGhostRecipePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerAbilitiesPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveEntityEffectPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveResourcePackPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/ResetScorePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SelectAdvancementTabPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/ServerDataPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetActionBarTextPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderCenterPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderLerpSizePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderSizePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderWarningDelayPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderWarningDistancePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetCameraPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetCenterChunkPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetDefaultSpawnPositionPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHeadRotationPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetRenderDistancePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateRecipeBookPacket.cs diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/AddResourcePackPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/AddResourcePackPacket.cs new file mode 100644 index 00000000..d46e930f --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/AddResourcePackPacket.cs @@ -0,0 +1,51 @@ +using MineSharp.ChatComponent; +using MineSharp.Core.Common; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Packet sent by the server to add a resource pack. +/// +/// The unique identifier of the resource pack. +/// The URL to the resource pack. +/// A 40 character hexadecimal, case-insensitive SHA-1 hash of the resource pack file. +/// Whether the client is forced to use the resource pack. +/// The custom message shown in the prompt, if present. +public sealed record AddResourcePackPacket(Uuid Uuid, string Url, string Hash, bool Forced, Chat? PromptMessage) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_AddResourcePack; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteUuid(Uuid); + buffer.WriteString(Url); + buffer.WriteString(Hash); + buffer.WriteBool(Forced); + var hasPromptMessage = PromptMessage is not null; + buffer.WriteBool(hasPromptMessage); + if (hasPromptMessage && PromptMessage is not null) + { + buffer.WriteChatComponent(PromptMessage); + } + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var uuid = buffer.ReadUuid(); + var url = buffer.ReadString(); + var hash = buffer.ReadString(); + var forced = buffer.ReadBool(); + var hasPromptMessage = buffer.ReadBool(); + Chat? promptMessage = hasPromptMessage ? buffer.ReadChatComponent() : null; + + return new AddResourcePackPacket(uuid, url, hash, forced, promptMessage); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisplayObjectivePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisplayObjectivePacket.cs new file mode 100644 index 00000000..f0bb9da6 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/DisplayObjectivePacket.cs @@ -0,0 +1,34 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Display Objective packet sent to the client to display a scoreboard. +/// +/// The position of the scoreboard. +/// The unique name for the scoreboard to be displayed. +public sealed record DisplayObjectivePacket(int Position, string ScoreName) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_ScoreboardDisplayObjective; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(Position); + buffer.WriteString(ScoreName); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var position = buffer.ReadVarInt(); + var scoreName = buffer.ReadString(); + + return new DisplayObjectivePacket(position, scoreName); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EndCombatPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EndCombatPacket.cs new file mode 100644 index 00000000..4b0a2e36 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EndCombatPacket.cs @@ -0,0 +1,30 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// End Combat packet +/// +/// Length of the combat in ticks +public sealed record EndCombatPacket(int Duration) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_EndCombatEvent; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(Duration); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var duration = buffer.ReadVarInt(); + return new EndCombatPacket(duration); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/EnterCombatPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EnterCombatPacket.cs new file mode 100644 index 00000000..c8412768 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/EnterCombatPacket.cs @@ -0,0 +1,29 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Enter Combat packet +/// +public sealed record EnterCombatPacket() : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_EnterCombatEvent; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + // No fields to write + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + // No fields to read + return new EnterCombatPacket(); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/LookAtPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/LookAtPacket.cs new file mode 100644 index 00000000..23965fb0 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/LookAtPacket.cs @@ -0,0 +1,77 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using static MineSharp.Protocol.Packets.Clientbound.Play.LookAtPacket; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Used to rotate the client player to face the given location or entity. +/// +/// Values are feet=0, eyes=1. If set to eyes, aims using the head position; otherwise aims using the feet position. +/// X coordinate of the point to face towards. +/// Y coordinate of the point to face towards. +/// Z coordinate of the point to face towards. +/// If true, additional information about an entity is provided. +/// The entity to face towards. Only if IsEntity is true. +/// Whether to look at the entity's eyes or feet. Same values and meanings as FeetOrEyes, just for the entity's head/feet. Only if IsEntity is true. +public sealed record LookAtPacket(LookAtPosition FeetOrEyes, double TargetX, double TargetY, double TargetZ, bool IsEntity, int? EntityId, LookAtPosition? EntityFeetOrEyes) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_FacePlayer; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt((int)FeetOrEyes); + buffer.WriteDouble(TargetX); + buffer.WriteDouble(TargetY); + buffer.WriteDouble(TargetZ); + buffer.WriteBool(IsEntity); + + if (IsEntity) + { + buffer.WriteVarInt(EntityId.GetValueOrDefault()); + buffer.WriteVarInt((int)EntityFeetOrEyes.GetValueOrDefault()); + } + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var feetOrEyes = (LookAtPosition)buffer.ReadVarInt(); + var targetX = buffer.ReadDouble(); + var targetY = buffer.ReadDouble(); + var targetZ = buffer.ReadDouble(); + var isEntity = buffer.ReadBool(); + + int? entityId = null; + LookAtPosition? entityFeetOrEyes = null; + + if (isEntity) + { + entityId = buffer.ReadVarInt(); + entityFeetOrEyes = (LookAtPosition)buffer.ReadVarInt(); + } + + return new LookAtPacket( + feetOrEyes, + targetX, targetY, targetZ, + isEntity, + entityId, entityFeetOrEyes); + } + + /// + /// Enum representing the position to look at (feet or eyes). + /// + public enum LookAtPosition + { +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + Feet = 0, + Eyes = 1 +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + } +} + diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/MerchantOffersPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/MerchantOffersPacket.cs new file mode 100644 index 00000000..d147414c --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/MerchantOffersPacket.cs @@ -0,0 +1,107 @@ +using MineSharp.Core.Common; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using MineSharp.Protocol.Packets.NetworkTypes; +using static MineSharp.Protocol.Packets.Clientbound.Play.MerchantOffersPacket; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// The list of trades a villager NPC is offering. +/// +/// The ID of the window that is open; this is an int rather than a byte. +/// The number of trades in the following array. +/// The trades offered by the villager. +/// The level of the villager. +/// Total experience for this villager (always 0 for the wandering trader). +/// True if this is a regular villager; false for the wandering trader. +/// True for regular villagers and false for the wandering trader. +public sealed record MerchantOffersPacket(int WindowId, int Size, Trade[] Trades, int VillagerLevel, int Experience, bool IsRegularVillager, bool CanRestock) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_TradeList; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(WindowId); + buffer.WriteVarInt(Size); + foreach (var trade in Trades) + { + trade.Write(buffer, version); + } + buffer.WriteVarInt(VillagerLevel); + buffer.WriteVarInt(Experience); + buffer.WriteBool(IsRegularVillager); + buffer.WriteBool(CanRestock); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var windowId = buffer.ReadVarInt(); + var size = buffer.ReadVarInt(); + var trades = new Trade[size]; + for (int i = 0; i < size; i++) + { + trades[i] = Trade.Read(buffer, version); + } + var villagerLevel = buffer.ReadVarInt(); + var experience = buffer.ReadVarInt(); + var isRegularVillager = buffer.ReadBool(); + var canRestock = buffer.ReadBool(); + + return new MerchantOffersPacket(windowId, size, trades, villagerLevel, experience, isRegularVillager, canRestock); + } + + /// + /// Represents a trade offered by a villager. + /// + /// The first item the player has to supply for this villager trade. + /// The item the player will receive from this villager trade. + /// The second item the player has to supply for this villager trade. May be an empty slot. + /// True if the trade is disabled; false if the trade is enabled. + /// Number of times the trade has been used so far. + /// Number of times this trade can be used before it's exhausted. + /// Amount of XP the villager will earn each time the trade is used. + /// The number added to the price when an item is discounted due to player reputation or other effects. + /// Determines how much demand, player reputation, and temporary effects will adjust the price. + /// If positive, causes the price to increase. Negative values seem to be treated the same as zero. + public sealed record Trade(Slot InputItem1, Slot OutputItem, Slot InputItem2, bool TradeDisabled, int NumberOfTradeUses, int MaximumNumberOfTradeUses, int XP, int SpecialPrice, float PriceMultiplier, int Demand) : ISerializableWithMinecraftData + { + /// + public void Write(PacketBuffer buffer, MinecraftData data) + { + buffer.WriteSlot(InputItem1); + buffer.WriteSlot(OutputItem); + buffer.WriteSlot(InputItem2); + buffer.WriteBool(TradeDisabled); + buffer.WriteInt(NumberOfTradeUses); + buffer.WriteInt(MaximumNumberOfTradeUses); + buffer.WriteInt(XP); + buffer.WriteInt(SpecialPrice); + buffer.WriteFloat(PriceMultiplier); + buffer.WriteInt(Demand); + } + + /// + public static Trade Read(PacketBuffer buffer, MinecraftData data) + { + var inputItem1 = buffer.ReadSlot(data); + var outputItem = buffer.ReadSlot(data); + var inputItem2 = buffer.ReadSlot(data); + var tradeDisabled = buffer.ReadBool(); + var numberOfTradeUses = buffer.ReadInt(); + var maximumNumberOfTradeUses = buffer.ReadInt(); + var xp = buffer.ReadInt(); + var specialPrice = buffer.ReadInt(); + var priceMultiplier = buffer.ReadFloat(); + var demand = buffer.ReadInt(); + + return new Trade(inputItem1, outputItem, inputItem2, tradeDisabled, numberOfTradeUses, maximumNumberOfTradeUses, xp, specialPrice, priceMultiplier, demand); + } + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/MoveVehiclePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/MoveVehiclePacket.cs new file mode 100644 index 00000000..d05510d4 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/MoveVehiclePacket.cs @@ -0,0 +1,43 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Move Vehicle packet +/// +/// Absolute position (X coordinate) +/// Absolute position (Y coordinate) +/// Absolute position (Z coordinate) +/// Absolute rotation on the vertical axis, in degrees +/// Absolute rotation on the horizontal axis, in degrees +public sealed record MoveVehiclePacket(double X, double Y, double Z, float Yaw, float Pitch) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_VehicleMove; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteDouble(X); + buffer.WriteDouble(Y); + buffer.WriteDouble(Z); + buffer.WriteFloat(Yaw); + buffer.WriteFloat(Pitch); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var x = buffer.ReadDouble(); + var y = buffer.ReadDouble(); + var z = buffer.ReadDouble(); + var yaw = buffer.ReadFloat(); + var pitch = buffer.ReadFloat(); + + return new MoveVehiclePacket(x, y, z, yaw, pitch); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenBookPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenBookPacket.cs new file mode 100644 index 00000000..7896533a --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenBookPacket.cs @@ -0,0 +1,31 @@ +using MineSharp.Core.Common; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Sent when a player right clicks with a signed book. This tells the client to open the book GUI. +/// +/// The hand used to open the book. +public sealed record OpenBookPacket(PlayerHand Hand) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_OpenBook; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt((int)Hand); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var hand = (PlayerHand)buffer.ReadVarInt(); + return new OpenBookPacket(hand); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenSignEditorPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenSignEditorPacket.cs new file mode 100644 index 00000000..04543ad4 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/OpenSignEditorPacket.cs @@ -0,0 +1,36 @@ +using MineSharp.Core.Geometry; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Sent when the client has placed a sign and is allowed to send Update Sign. +/// There must already be a sign at the given location. +/// +/// The position of the sign +/// Whether the opened editor is for the front or on the back of the sign +public sealed record OpenSignEditorPacket(Position Location, bool IsFrontText) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_OpenSignEntity; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WritePosition(Location); + buffer.WriteBool(IsFrontText); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var location = buffer.ReadPosition(); + var isFrontText = buffer.ReadBool(); + + return new OpenSignEditorPacket(location, isFrontText); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlaceGhostRecipePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlaceGhostRecipePacket.cs new file mode 100644 index 00000000..36cb9279 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlaceGhostRecipePacket.cs @@ -0,0 +1,35 @@ +using MineSharp.Core.Common; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Response to the serverbound packet (Place Recipe), with the same recipe ID. Appears to be used to notify the UI. +/// +/// The window ID +/// A recipe ID +public sealed record PlaceGhostRecipePacket(byte WindowId, Identifier Recipe) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_CraftRecipeResponse; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteByte(WindowId); + buffer.WriteIdentifier(Recipe); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var windowId = buffer.ReadByte(); + var recipe = buffer.ReadIdentifier(); + + return new PlaceGhostRecipePacket(windowId, recipe); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerAbilitiesPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerAbilitiesPacket.cs new file mode 100644 index 00000000..da9fec4a --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PlayerAbilitiesPacket.cs @@ -0,0 +1,63 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using static MineSharp.Protocol.Packets.Clientbound.Play.PlayerAbilitiesPacket; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Player abilities packet sent by the server to update the player's abilities. +/// +/// Bit field indicating various abilities. +/// The flying speed of the player. +/// Modifies the field of view, like a speed potion. +public sealed record PlayerAbilitiesPacket(PlayerAbilitiesFlags Flags, float FlyingSpeed, float FieldOfViewModifier) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_Abilities; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteByte((byte)Flags); + buffer.WriteFloat(FlyingSpeed); + buffer.WriteFloat(FieldOfViewModifier); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var flags = (PlayerAbilitiesFlags)buffer.ReadByte(); + var flyingSpeed = buffer.ReadByte(); + var fieldOfViewModifier = buffer.ReadByte(); + + return new PlayerAbilitiesPacket(flags, flyingSpeed, fieldOfViewModifier); + } + + /// + /// Flags representing various player abilities. + /// + [Flags] + public enum PlayerAbilitiesFlags : byte + { + /// + /// Player is invulnerable. + /// + Invulnerable = 0x01, + /// + /// Player is flying. + /// + Flying = 0x02, + /// + /// Player is allowed to fly. + /// + AllowFlying = 0x04, + /// + /// Player is in creative mode. + /// And can instantly break blocks. + /// + CreativeMode = 0x08, + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveEntityEffectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveEntityEffectPacket.cs new file mode 100644 index 00000000..1dab7f86 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveEntityEffectPacket.cs @@ -0,0 +1,34 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Remove Entity Effect packet +/// +/// The entity ID +/// The effect ID +public sealed record RemoveEntityEffectPacket(int EntityId, int EffectId) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_RemoveEntityEffect; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(EntityId); + buffer.WriteVarInt(EffectId); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var entityId = buffer.ReadVarInt(); + var effectId = buffer.ReadVarInt(); + + return new RemoveEntityEffectPacket(entityId, effectId); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveResourcePackPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveResourcePackPacket.cs new file mode 100644 index 00000000..8298275d --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RemoveResourcePackPacket.cs @@ -0,0 +1,38 @@ +using MineSharp.Core.Common; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Packet sent by the server to remove a resource pack. +/// +/// The UUID of the resource pack to be removed. +public sealed record RemoveResourcePackPacket(Uuid? Uuid) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_RemoveResourcePack; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + var hasUuid = Uuid != null; + buffer.WriteBool(hasUuid); + if (hasUuid) + { + buffer.WriteUuid(Uuid!.Value); + } + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var hasUuid = buffer.ReadBool(); + Uuid? uuid = hasUuid ? buffer.ReadUuid() : null; + + return new RemoveResourcePackPacket(uuid); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ResetScorePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ResetScorePacket.cs new file mode 100644 index 00000000..09d308ec --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ResetScorePacket.cs @@ -0,0 +1,44 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Reset Score packet +/// +/// The entity whose score this is. For players, this is their username; for other entities, it is their UUID. +/// Whether the score should be removed for the specified objective, or for all of them. +/// The name of the objective the score belongs to. Only present if the previous field is true. +public sealed record ResetScorePacket(string EntityName, bool HasObjectiveName, string? ObjectiveName) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_ResetScore; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteString(EntityName); + buffer.WriteBool(HasObjectiveName); + if (HasObjectiveName) + { + buffer.WriteString(ObjectiveName!); + } + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var entityName = buffer.ReadString(); + var hasObjectiveName = buffer.ReadBool(); + string? objectiveName = null; + if (hasObjectiveName) + { + objectiveName = buffer.ReadString(); + } + + return new ResetScorePacket(entityName, hasObjectiveName, objectiveName); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SelectAdvancementTabPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SelectAdvancementTabPacket.cs new file mode 100644 index 00000000..fdf64eef --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SelectAdvancementTabPacket.cs @@ -0,0 +1,52 @@ +using System.Collections.Frozen; +using MineSharp.Core.Common; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Sent by the server to indicate that the client should switch advancement tab. +/// Sent either when the client switches tab in the GUI or when an advancement in another tab is made. +/// +/// The identifier of the advancement tab. If no or an invalid identifier is sent, the client will switch to the first tab in the GUI. +public sealed record SelectAdvancementTabPacket(Identifier? Identifier) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_SelectAdvancementTab; + + /// + /// Set of all possible identifiers. + /// + public static readonly FrozenSet PossibleIdentifiers = new HashSet() + { + Identifier.Parse("minecraft:story/root"), + Identifier.Parse("minecraft:nether/root"), + Identifier.Parse("minecraft:end/root"), + Identifier.Parse("minecraft:adventure/root"), + Identifier.Parse("minecraft:husbandry/root") + }.ToFrozenSet(); + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + var hasId = Identifier is not null; + buffer.WriteBool(hasId); + if (hasId) + { + buffer.WriteIdentifier(Identifier!); + } + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var hasId = buffer.ReadBool(); + Identifier? identifier = hasId ? buffer.ReadIdentifier() : null; + + return new SelectAdvancementTabPacket(identifier); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/ServerDataPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ServerDataPacket.cs new file mode 100644 index 00000000..d5ff4f51 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/ServerDataPacket.cs @@ -0,0 +1,51 @@ +using MineSharp.ChatComponent; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Sent by the server to provide server data such as MOTD, icon, and secure chat enforcement. +/// +/// The message of the day (MOTD) as a chat component. +/// Indicates if the server has an icon. +/// Optional icon bytes in the PNG format. +/// Indicates if the server enforces secure chat. +public sealed record ServerDataPacket(Chat Motd, bool HasIcon, byte[]? Icon, bool EnforcesSecureChat) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_ServerData; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteChatComponent(Motd); + buffer.WriteBool(HasIcon); + if (HasIcon && Icon is not null) + { + buffer.WriteVarInt(Icon.Length); + buffer.WriteBytes(Icon); + } + buffer.WriteBool(EnforcesSecureChat); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var motd = buffer.ReadChatComponent(); + var hasIcon = buffer.ReadBool(); + byte[]? icon = null; + if (hasIcon) + { + // TODO: Is the Size of the icon byte array always present? + var size = buffer.ReadVarInt(); + icon = buffer.ReadBytes(size); + } + var enforcesSecureChat = buffer.ReadBool(); + + return new ServerDataPacket(motd, hasIcon, icon, enforcesSecureChat); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetActionBarTextPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetActionBarTextPacket.cs new file mode 100644 index 00000000..95218632 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetActionBarTextPacket.cs @@ -0,0 +1,32 @@ +using MineSharp.ChatComponent; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Displays a message above the hotbar. Equivalent to System Chat Message with Overlay set to true, +/// except that chat message blocking isn't performed. Used by the Notchian server only to implement the /title command. +/// +/// The text to display in the action bar +public sealed record SetActionBarTextPacket(Chat ActionBarText) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_ActionBar; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteChatComponent(ActionBarText); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var actionBarText = buffer.ReadChatComponent(); + return new SetActionBarTextPacket(actionBarText); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderCenterPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderCenterPacket.cs new file mode 100644 index 00000000..439cafe9 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderCenterPacket.cs @@ -0,0 +1,34 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Packet sent by the server to set the world border center. +/// +/// The X coordinate of the world border center. +/// The Z coordinate of the world border center. +public sealed record SetBorderCenterPacket(double X, double Z) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_WorldBorderCenter; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteDouble(X); + buffer.WriteDouble(Z); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var x = buffer.ReadDouble(); + var z = buffer.ReadDouble(); + + return new SetBorderCenterPacket(x, z); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderLerpSizePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderLerpSizePacket.cs new file mode 100644 index 00000000..cc153246 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderLerpSizePacket.cs @@ -0,0 +1,37 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Packet sent by the server to set the world border lerp size. +/// +/// Current length of a single side of the world border, in meters. +/// Target length of a single side of the world border, in meters. +/// Number of real-time milliseconds until New Diameter is reached. +public sealed record SetBorderLerpSizePacket(double OldDiameter, double NewDiameter, long Speed) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_WorldBorderLerpSize; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteDouble(OldDiameter); + buffer.WriteDouble(NewDiameter); + buffer.WriteVarLong(Speed); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var oldDiameter = buffer.ReadDouble(); + var newDiameter = buffer.ReadDouble(); + var speed = buffer.ReadVarLong(); + + return new SetBorderLerpSizePacket(oldDiameter, newDiameter, speed); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderSizePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderSizePacket.cs new file mode 100644 index 00000000..dd068c1b --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderSizePacket.cs @@ -0,0 +1,30 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Packet sent by the server to set the world border size. +/// +/// Length of a single side of the world border, in meters. +public sealed record SetBorderSizePacket(double Diameter) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_WorldBorderSize; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteDouble(Diameter); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var diameter = buffer.ReadDouble(); + return new SetBorderSizePacket(diameter); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderWarningDelayPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderWarningDelayPacket.cs new file mode 100644 index 00000000..49a6dc56 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderWarningDelayPacket.cs @@ -0,0 +1,30 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Packet sent by the server to set the border warning delay. +/// +/// The warning time in seconds as set by /worldborder warning time. +public sealed record SetBorderWarningDelayPacket(int WarningTime) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_WorldBorderWarningDelay; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(WarningTime); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var warningTime = buffer.ReadVarInt(); + return new SetBorderWarningDelayPacket(warningTime); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderWarningDistancePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderWarningDistancePacket.cs new file mode 100644 index 00000000..e1c87f37 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetBorderWarningDistancePacket.cs @@ -0,0 +1,30 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Packet sent by the server to set the border warning distance. +/// +/// The warning distance in meters. +public sealed record SetBorderWarningDistancePacket(int WarningBlocks) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_WorldBorderWarningReach; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(WarningBlocks); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var warningBlocks = buffer.ReadVarInt(); + return new SetBorderWarningDistancePacket(warningBlocks); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetCameraPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetCameraPacket.cs new file mode 100644 index 00000000..6c914e6b --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetCameraPacket.cs @@ -0,0 +1,30 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Sets the entity that the player renders from. This is normally used when the player left-clicks an entity while in spectator mode. +/// +/// ID of the entity to set the client's camera to. +public sealed record SetCameraPacket(int CameraId) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_Camera; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(CameraId); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var cameraId = buffer.ReadVarInt(); + return new SetCameraPacket(cameraId); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetCenterChunkPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetCenterChunkPacket.cs new file mode 100644 index 00000000..21e1afdd --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetCenterChunkPacket.cs @@ -0,0 +1,34 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Sets the center position of the client's chunk loading area. +/// +/// Chunk X coordinate of the loading area center. +/// Chunk Z coordinate of the loading area center. +public sealed record SetCenterChunkPacket(int ChunkX, int ChunkZ) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_UpdateViewPosition; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(ChunkX); + buffer.WriteVarInt(ChunkZ); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var chunkX = buffer.ReadVarInt(); + var chunkZ = buffer.ReadVarInt(); + + return new SetCenterChunkPacket(chunkX, chunkZ); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetDefaultSpawnPositionPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetDefaultSpawnPositionPacket.cs new file mode 100644 index 00000000..769b8894 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetDefaultSpawnPositionPacket.cs @@ -0,0 +1,35 @@ +using MineSharp.Core.Geometry; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Set Default Spawn Position packet +/// +/// The spawn location +/// The angle at which to respawn at +public sealed record SetDefaultSpawnPositionPacket(Position Location, float Angle) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_SpawnPosition; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WritePosition(Location); + buffer.WriteFloat(Angle); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var location = buffer.ReadPosition(); + var angle = buffer.ReadFloat(); + + return new SetDefaultSpawnPositionPacket(location, angle); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHeadRotationPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHeadRotationPacket.cs new file mode 100644 index 00000000..9a37b78f --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetHeadRotationPacket.cs @@ -0,0 +1,34 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Changes the direction an entity's head is facing. +/// +/// The entity ID +/// New angle, not a delta +public sealed record SetHeadRotationPacket(int EntityId, byte HeadYaw) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_EntityHeadRotation; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(EntityId); + buffer.WriteByte(HeadYaw); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var entityId = buffer.ReadVarInt(); + var headYaw = buffer.ReadByte(); + + return new SetHeadRotationPacket(entityId, headYaw); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetRenderDistancePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetRenderDistancePacket.cs new file mode 100644 index 00000000..34b6740b --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetRenderDistancePacket.cs @@ -0,0 +1,31 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Sent by the integrated singleplayer server when changing render distance. +/// This packet is sent by the server when the client reappears in the overworld after leaving the end. +/// +/// Render distance (2-32). +public sealed record SetRenderDistancePacket(int ViewDistance) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_UpdateViewDistance; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(ViewDistance); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var viewDistance = buffer.ReadVarInt(); + return new SetRenderDistancePacket(viewDistance); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateRecipeBookPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateRecipeBookPacket.cs new file mode 100644 index 00000000..3d93568a --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateRecipeBookPacket.cs @@ -0,0 +1,131 @@ +using MineSharp.Core.Common; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using static MineSharp.Protocol.Packets.Clientbound.Play.UpdateRecipeBookPacket; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Packet sent by the server to update the recipe book. +/// +/// The action to perform (init, add, remove). +/// If true, the crafting recipe book will be open when the player opens its inventory. +/// If true, the filtering option is active when the player opens its inventory. +/// If true, the smelting recipe book will be open when the player opens its inventory. +/// If true, the filtering option is active when the player opens its inventory. +/// If true, the blast furnace recipe book will be open when the player opens its inventory. +/// If true, the filtering option is active when the player opens its inventory. +/// If true, the smoker recipe book will be open when the player opens its inventory. +/// If true, the filtering option is active when the player opens its inventory. +/// List of recipe IDs. +/// Optional list of recipe IDs, only present if action is Init. +public sealed record UpdateRecipeBookPacket( + RecipeBookAction Action, + bool CraftingRecipeBookOpen, + bool CraftingRecipeBookFilterActive, + bool SmeltingRecipeBookOpen, + bool SmeltingRecipeBookFilterActive, + bool BlastFurnaceRecipeBookOpen, + bool BlastFurnaceRecipeBookFilterActive, + bool SmokerRecipeBookOpen, + bool SmokerRecipeBookFilterActive, + Identifier[] RecipeIds, + Identifier[]? OptionalRecipeIds) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_UnlockRecipes; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt((int)Action); + buffer.WriteBool(CraftingRecipeBookOpen); + buffer.WriteBool(CraftingRecipeBookFilterActive); + buffer.WriteBool(SmeltingRecipeBookOpen); + buffer.WriteBool(SmeltingRecipeBookFilterActive); + buffer.WriteBool(BlastFurnaceRecipeBookOpen); + buffer.WriteBool(BlastFurnaceRecipeBookFilterActive); + buffer.WriteBool(SmokerRecipeBookOpen); + buffer.WriteBool(SmokerRecipeBookFilterActive); + buffer.WriteVarInt(RecipeIds.Length); + foreach (var recipeId in RecipeIds) + { + buffer.WriteIdentifier(recipeId); + } + if (Action == RecipeBookAction.Init) + { + buffer.WriteVarInt(OptionalRecipeIds?.Length ?? 0); + if (OptionalRecipeIds != null) + { + foreach (var optionalRecipeId in OptionalRecipeIds) + { + buffer.WriteIdentifier(optionalRecipeId); + } + } + } + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var action = (RecipeBookAction)buffer.ReadVarInt(); + var craftingRecipeBookOpen = buffer.ReadBool(); + var craftingRecipeBookFilterActive = buffer.ReadBool(); + var smeltingRecipeBookOpen = buffer.ReadBool(); + var smeltingRecipeBookFilterActive = buffer.ReadBool(); + var blastFurnaceRecipeBookOpen = buffer.ReadBool(); + var blastFurnaceRecipeBookFilterActive = buffer.ReadBool(); + var smokerRecipeBookOpen = buffer.ReadBool(); + var smokerRecipeBookFilterActive = buffer.ReadBool(); + var recipeIdsLength = buffer.ReadVarInt(); + var recipeIds = new Identifier[recipeIdsLength]; + for (int i = 0; i < recipeIdsLength; i++) + { + recipeIds[i] = buffer.ReadIdentifier(); + } + Identifier[]? optionalRecipeIds = null; + if (action == RecipeBookAction.Init) + { + var optionalRecipeIdsLength = buffer.ReadVarInt(); + optionalRecipeIds = new Identifier[optionalRecipeIdsLength]; + for (int i = 0; i < optionalRecipeIdsLength; i++) + { + optionalRecipeIds[i] = buffer.ReadIdentifier(); + } + } + return new UpdateRecipeBookPacket( + action, + craftingRecipeBookOpen, + craftingRecipeBookFilterActive, + smeltingRecipeBookOpen, + smeltingRecipeBookFilterActive, + blastFurnaceRecipeBookOpen, + blastFurnaceRecipeBookFilterActive, + smokerRecipeBookOpen, + smokerRecipeBookFilterActive, + recipeIds, + optionalRecipeIds); + } + + /// + /// Enum representing the action to perform on the recipe book. + /// + public enum RecipeBookAction + { + /// + /// All the recipes in list 1 will be tagged as displayed, and all the recipes in list 2 will be added to the recipe book. Recipes that aren't tagged will be shown in the notification. + /// + Init = 0, + /// + /// All the recipes in the list are added to the recipe book and their icons will be shown in the notification. + /// + Add = 1, + /// + /// Remove all the recipes in the list. This allows them to be re-displayed when they are re-added. + /// + Remove = 2 + } +} diff --git a/Components/MineSharp.Protocol/Packets/PacketPalette.cs b/Components/MineSharp.Protocol/Packets/PacketPalette.cs index 143282c0..686023f1 100644 --- a/Components/MineSharp.Protocol/Packets/PacketPalette.cs +++ b/Components/MineSharp.Protocol/Packets/PacketPalette.cs @@ -37,6 +37,10 @@ using SBConfigurationPluginMessagePacket = MineSharp.Protocol.Packets.Serverbound.Configuration.PluginMessagePacket; using SBSetHeldItemPacket = MineSharp.Protocol.Packets.Serverbound.Play.SetHeldItemPacket; using CBPlayPluginMessagePacket = MineSharp.Protocol.Packets.Clientbound.Play.PluginMessagePacket; +using CBConfigurationAddResourcePackPacket = MineSharp.Protocol.Packets.Clientbound.Configuration.AddResourcePackPacket; +using CBConfigurationRemoveResourcePackPacket = MineSharp.Protocol.Packets.Clientbound.Configuration.RemoveResourcePackPacket; +using CBPlayAddResourcePackPacket = MineSharp.Protocol.Packets.Clientbound.Play.AddResourcePackPacket; +using CBPlayRemoveResourcePackPacket = MineSharp.Protocol.Packets.Clientbound.Play.RemoveResourcePackPacket; namespace MineSharp.Protocol.Packets; @@ -103,8 +107,8 @@ void RegisterPacket() RegisterPacket(); RegisterPacket(); RegisterPacket(); - RegisterPacket(); - RegisterPacket(); + RegisterPacket(); + RegisterPacket(); RegisterPacket(); RegisterPacket(); @@ -181,6 +185,34 @@ void RegisterPacket() RegisterPacket(); RegisterPacket(); RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); RegisterPacket(); RegisterPacket(); From 54214b0efa802b771e29edd7dff65d513fe2b769 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Sat, 10 Aug 2024 17:35:32 +0200 Subject: [PATCH 63/73] added EntityMetadata type --- .../Clientbound/Play/WorldEventPacket.cs | 17 +- .../Packets/NetworkTypes/EntityMetadata.cs | 445 ++++++++++++++++++ MineSharp.Core/Common/Direction.cs | 16 + 3 files changed, 463 insertions(+), 15 deletions(-) create mode 100644 Components/MineSharp.Protocol/Packets/NetworkTypes/EntityMetadata.cs create mode 100644 MineSharp.Core/Common/Direction.cs diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/WorldEventPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/WorldEventPacket.cs index f10c7d53..5c125e0a 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/WorldEventPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/WorldEventPacket.cs @@ -1,4 +1,4 @@ -using System.Diagnostics.Tracing; +using MineSharp.Core.Common; using MineSharp.Core.Geometry; using MineSharp.Core.Serialization; using MineSharp.Data; @@ -103,7 +103,7 @@ public enum EventType EnderEyePlaced = 1503, /// /// Meaning of Data field: - /// See + /// See /// SpawnsSmokeParticles = 2000, /// @@ -139,18 +139,5 @@ public enum EventType CopperScrapeOxidation = 3005 #endregion } - - /// - /// Enum representing the possible smoke directions. - /// - public enum SmokeDirection - { - Down = 0, - Up = 1, - North = 2, - South = 3, - West = 4, - East = 5 - } #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member } diff --git a/Components/MineSharp.Protocol/Packets/NetworkTypes/EntityMetadata.cs b/Components/MineSharp.Protocol/Packets/NetworkTypes/EntityMetadata.cs new file mode 100644 index 00000000..14a6abd6 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/NetworkTypes/EntityMetadata.cs @@ -0,0 +1,445 @@ +using System.Collections.Frozen; +using System.Diagnostics.Contracts; +using fNbt; +using MineSharp.ChatComponent; +using MineSharp.Core.Common; +using MineSharp.Core.Geometry; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using static MineSharp.Protocol.Packets.NetworkTypes.SnifferStateMetadata; + +namespace MineSharp.Protocol.Packets.NetworkTypes; + +/// +/// Represents the metadata of an entity. +/// +/// The metadata entries. +public sealed record EntityMetadata(EntityMetadataEntry[] Entries) : ISerializableWithMinecraftData +{ + /// + /// Represents the end of metadata index. + /// + public const byte EndOfMetadataIndex = 0xff; + + /// + public void Write(PacketBuffer buffer, MinecraftData data) + { + foreach (var entry in Entries) + { + entry.Write(buffer, data); + } + // Write the terminating entry + buffer.WriteByte(EndOfMetadataIndex); + } + + /// + public static EntityMetadata Read(PacketBuffer buffer, MinecraftData data) + { + var entries = new List(); + while (true) + { + var index = buffer.Peek(); + if (index == EndOfMetadataIndex) + { + buffer.ReadByte(); // Consume the index + break; + } + + var entry = EntityMetadataEntry.Read(buffer, data); + entries.Add(entry); + } + return new EntityMetadata(entries.ToArray()); + } +} + +/// +/// Represents a entity metadata entry. +/// +public sealed record EntityMetadataEntry(byte Index, int Type, IMetadataValue Value) : ISerializableWithMinecraftData +{ + /// + public void Write(PacketBuffer buffer, MinecraftData data) + { + buffer.WriteByte(Index); + buffer.WriteVarInt(Type); + Value!.Write(buffer, data); + } + + /// + public static EntityMetadataEntry Read(PacketBuffer buffer, MinecraftData data) + { + var index = buffer.ReadByte(); + var type = buffer.ReadVarInt(); + var value = MetadataValueFactory.Create(type, buffer, data); + + return new(index, type, value); + } +} + +/// +/// Factory for creating metadata values based on type. +/// +public static class MetadataValueFactory +{ + private static readonly FrozenDictionary> TypeToReadDelegate = new Dictionary>() + { + { 0, ByteMetadata.Read }, + { 1, VarIntMetadata.Read }, + { 2, VarLongMetadata.Read }, + { 3, FloatMetadata.Read }, + { 4, StringMetadata.Read }, + { 5, TextComponentMetadata.Read }, + { 6, OptionalTextComponentMetadata.Read }, + { 7, SlotMetadata.Read }, + { 8, BooleanMetadata.Read }, + { 9, RotationsMetadata.Read }, + { 10, PositionMetadata.Read }, + { 11, OptionalPositionMetadata.Read }, + { 12, DirectionMetadata.Read }, + { 13, OptionalUuidMetadata.Read }, + { 14, BlockStateMetadata.Read }, + { 15, OptionalBlockStateMetadata.Read }, + { 16, NbtMetadata.Read }, + { 17, ParticleMetadata.Read }, + { 18, VillagerDataMetadata.Read }, + { 19, OptionalVarIntMetadata.Read }, + { 20, PoseMetadata.Read }, + { 21, CatVariantMetadata.Read }, + { 22, FrogVariantMetadata.Read }, + { 23, OptionalGlobalPositionMetadata.Read }, + { 24, PaintingVariantMetadata.Read }, + { 25, SnifferStateMetadata.Read }, + { 26, Vector3Metadata.Read }, + { 27, QuaternionMetadata.Read }, + }.ToFrozenDictionary(); + + /// + /// Creates an instance of based on the provided type. + /// + /// The type of the metadata value. + /// The packet buffer to read from. + /// The Minecraft data context. + /// An instance of . + /// Thrown when the type is unknown. + public static IMetadataValue Create(int type, PacketBuffer buffer, MinecraftData data) + { + if (TypeToReadDelegate.TryGetValue(type, out var readDelegate)) + { + return readDelegate(buffer, data); + } + + throw new ArgumentOutOfRangeException(nameof(type), $"Unknown metadata type: {type}"); + } +} + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +/// +/// Interface for metadata values. +/// +public interface IMetadataValue +{ + public abstract void Write(PacketBuffer buffer, MinecraftData data); +} + +public sealed record ByteMetadata(byte Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteByte(Value); + public static ByteMetadata Read(PacketBuffer buffer, MinecraftData data) => new(buffer.ReadByte()); +} + +public sealed record VarIntMetadata(int Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteVarInt(Value); + public static VarIntMetadata Read(PacketBuffer buffer, MinecraftData data) => new(buffer.ReadVarInt()); +} + +public sealed record VarLongMetadata(long Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteVarLong(Value); + public static VarLongMetadata Read(PacketBuffer buffer, MinecraftData data) => new(buffer.ReadVarLong()); +} + +public sealed record FloatMetadata(float Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteFloat(Value); + public static FloatMetadata Read(PacketBuffer buffer, MinecraftData data) => new(buffer.ReadFloat()); +} + +public sealed record StringMetadata(string Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteString(Value); + public static StringMetadata Read(PacketBuffer buffer, MinecraftData data) => new(buffer.ReadString()); +} + +public sealed record TextComponentMetadata(Chat Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteChatComponent(Value); + public static TextComponentMetadata Read(PacketBuffer buffer, MinecraftData data) => new(buffer.ReadChatComponent()); +} + +public sealed record OptionalTextComponentMetadata(Chat? Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) + { + var hasValue = Value != null; + buffer.WriteBool(hasValue); + if (hasValue) buffer.WriteChatComponent(Value!); + } + + public static OptionalTextComponentMetadata Read(PacketBuffer buffer, MinecraftData data) + { + var hasValue = buffer.ReadBool(); + var value = hasValue ? buffer.ReadChatComponent() : null; + return new(value); + } +} + +public sealed record SlotMetadata(Slot Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteSlot(Value); + public static SlotMetadata Read(PacketBuffer buffer, MinecraftData data) => new(buffer.ReadSlot(data)); +} + +public sealed record BooleanMetadata(bool Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteBool(Value); + public static BooleanMetadata Read(PacketBuffer buffer, MinecraftData data) => new(buffer.ReadBool()); +} + +public sealed record RotationsMetadata(float X, float Y, float Z) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) + { + buffer.WriteFloat(X); + buffer.WriteFloat(Y); + buffer.WriteFloat(Z); + } + + public static RotationsMetadata Read(PacketBuffer buffer, MinecraftData data) + { + var x = buffer.ReadFloat(); + var y = buffer.ReadFloat(); + var z = buffer.ReadFloat(); + return new(x, y, z); + } +} + +public sealed record PositionMetadata(Position Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WritePosition(Value); + public static PositionMetadata Read(PacketBuffer buffer, MinecraftData data) => new(buffer.ReadPosition()); +} + +/// Position is present if the Boolean is set to true. +public sealed record OptionalPositionMetadata(Position? Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) + { + var hasValue = Value != null; + buffer.WriteBool(hasValue); + if (hasValue) buffer.WritePosition(Value); + } + + public static OptionalPositionMetadata Read(PacketBuffer buffer, MinecraftData data) + { + var hasValue = buffer.ReadBool(); + var value = hasValue ? buffer.ReadPosition() : null; + return new(value); + } +} + +public sealed record DirectionMetadata(Direction Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteVarInt((int)Value); + public static DirectionMetadata Read(PacketBuffer buffer, MinecraftData data) => new((Direction)buffer.ReadVarInt()); +} + +public sealed record OptionalUuidMetadata(Uuid? Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) + { + var hasValue = Value.HasValue; + buffer.WriteBool(hasValue); + if (hasValue) buffer.WriteUuid(Value.Value); + } + + public static OptionalUuidMetadata Read(PacketBuffer buffer, MinecraftData data) + { + var hasValue = buffer.ReadBool(); + Uuid? value = hasValue ? buffer.ReadUuid() : null; + return new(value); + } +} + +/// An ID in the block state registry. +public sealed record BlockStateMetadata(int Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteVarInt(Value); + public static BlockStateMetadata Read(PacketBuffer buffer, MinecraftData data) => new(buffer.ReadVarInt()); +} + +/// 0 for absent (air is unrepresentable); otherwise, an ID in the block state registry. +public sealed record OptionalBlockStateMetadata(int Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteVarInt(Value); + public static OptionalBlockStateMetadata Read(PacketBuffer buffer, MinecraftData data) => new(buffer.ReadVarInt()); +} + +public sealed record NbtMetadata(NbtTag Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteNbt(Value); + public static NbtMetadata Read(PacketBuffer buffer, MinecraftData data) => new(buffer.ReadNbt()); +} + +public sealed record ParticleMetadata(int ParticleType, byte[]? ParticleData) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) + { + buffer.WriteVarInt(ParticleType); + // TODO: Write particle data + //buffer.WriteObject(ParticleData); + } + + public static ParticleMetadata Read(PacketBuffer buffer, MinecraftData data) + { + var particleType = buffer.ReadVarInt(); + //var particleData = buffer.ReadObject(); + return new(particleType, null); + } +} + +public sealed record VillagerDataMetadata(int VillagerType, int VillagerProfession, int Level) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) + { + buffer.WriteVarInt(VillagerType); + buffer.WriteVarInt(VillagerProfession); + buffer.WriteVarInt(Level); + } + + public static VillagerDataMetadata Read(PacketBuffer buffer, MinecraftData data) + { + var villagerType = buffer.ReadVarInt(); + var villagerProfession = buffer.ReadVarInt(); + var level = buffer.ReadVarInt(); + return new(villagerType, villagerProfession, level); + } +} + +public sealed record OptionalVarIntMetadata(int? Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) + { + buffer.WriteVarInt(Value.HasValue ? Value.Value + 1 : 0); + } + + public static OptionalVarIntMetadata Read(PacketBuffer buffer, MinecraftData data) + { + var value = buffer.ReadVarInt(); + return new(value == 0 ? (int?)null : value - 1); + } +} + +public sealed record PoseMetadata(EntityPose Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteVarInt((int)Value); + public static PoseMetadata Read(PacketBuffer buffer, MinecraftData data) => new((EntityPose)buffer.ReadVarInt()); +} + +public sealed record CatVariantMetadata(int Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteVarInt(Value); + public static CatVariantMetadata Read(PacketBuffer buffer, MinecraftData data) => new(buffer.ReadVarInt()); +} + +public sealed record FrogVariantMetadata(int Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteVarInt(Value); + public static FrogVariantMetadata Read(PacketBuffer buffer, MinecraftData data) => new(buffer.ReadVarInt()); +} + +public sealed record OptionalGlobalPositionMetadata(bool HasValue, Identifier? DimensionIdentifier, Position? Position) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) + { + buffer.WriteBool(HasValue); + if (HasValue) + { + buffer.WriteIdentifier(DimensionIdentifier); + buffer.WritePosition(Position); + } + } + + public static OptionalGlobalPositionMetadata Read(PacketBuffer buffer, MinecraftData data) + { + var hasValue = buffer.ReadBool(); + var dimensionIdentifier = hasValue ? buffer.ReadIdentifier() : null; + var position = hasValue ? buffer.ReadPosition() : null; + return new(hasValue, dimensionIdentifier, position); + } +} + +public sealed record PaintingVariantMetadata(int Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteVarInt(Value); + public static PaintingVariantMetadata Read(PacketBuffer buffer, MinecraftData data) => new(buffer.ReadVarInt()); +} + +public sealed record SnifferStateMetadata(SnifferState Value) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteVarInt((int)Value); + public static SnifferStateMetadata Read(PacketBuffer buffer, MinecraftData data) => new((SnifferState)buffer.ReadVarInt()); + + public enum SnifferState + { + Idling = 0, + FeelingHappy = 1, + Scenting = 2, + Sniffing = 3, + Searching = 4, + Digging = 5, + Rising = 6 + } +} + +public sealed record Vector3Metadata(float X, float Y, float Z) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) + { + buffer.WriteFloat(X); + buffer.WriteFloat(Y); + buffer.WriteFloat(Z); + } + + public static Vector3Metadata Read(PacketBuffer buffer, MinecraftData data) + { + var x = buffer.ReadFloat(); + var y = buffer.ReadFloat(); + var z = buffer.ReadFloat(); + return new(x, y, z); + } + + [Pure] + public Vector3 ToVector3() => new(X, Y, Z); +} + +public sealed record QuaternionMetadata(float X, float Y, float Z, float W) : IMetadataValue, ISerializableWithMinecraftData +{ + public void Write(PacketBuffer buffer, MinecraftData data) + { + buffer.WriteFloat(X); + buffer.WriteFloat(Y); + buffer.WriteFloat(Z); + buffer.WriteFloat(W); + } + + public static QuaternionMetadata Read(PacketBuffer buffer, MinecraftData data) + { + var x = buffer.ReadFloat(); + var y = buffer.ReadFloat(); + var z = buffer.ReadFloat(); + var w = buffer.ReadFloat(); + return new(x, y, z, w); + } +} +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member diff --git a/MineSharp.Core/Common/Direction.cs b/MineSharp.Core/Common/Direction.cs new file mode 100644 index 00000000..e4c9d6e7 --- /dev/null +++ b/MineSharp.Core/Common/Direction.cs @@ -0,0 +1,16 @@ +namespace MineSharp.Core.Common; + +/// +/// Enum representing the directions. +/// +public enum Direction +{ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + Down = 0, + Up = 1, + North = 2, + South = 3, + West = 4, + East = 5 +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member +} From 47bc369960cba06b8433906b47bd309c3a7cf67b Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Sat, 10 Aug 2024 17:36:00 +0200 Subject: [PATCH 64/73] add SetEntityMetadataPacket --- .../Play/SetEntityMetadataPacket.cs | 36 +++++++++++++++++++ .../Packets/PacketPalette.cs | 1 + 2 files changed, 37 insertions(+) create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEntityMetadataPacket.cs diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEntityMetadataPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEntityMetadataPacket.cs new file mode 100644 index 00000000..c0dbdaaf --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEntityMetadataPacket.cs @@ -0,0 +1,36 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using MineSharp.Protocol.Packets.NetworkTypes; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Updates one or more metadata properties for an existing entity. +/// Any properties not included in the Metadata field are left unchanged. +/// +/// The entity ID +/// The entity metadata +public sealed record SetEntityMetadataPacket(int EntityId, EntityMetadata Metadata) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_EntityMetadata; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(EntityId); + Metadata.Write(buffer, version); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var entityId = buffer.ReadVarInt(); + var metadata = EntityMetadata.Read(buffer, version); + + return new SetEntityMetadataPacket(entityId, metadata); + } +} diff --git a/Components/MineSharp.Protocol/Packets/PacketPalette.cs b/Components/MineSharp.Protocol/Packets/PacketPalette.cs index 686023f1..d78d408e 100644 --- a/Components/MineSharp.Protocol/Packets/PacketPalette.cs +++ b/Components/MineSharp.Protocol/Packets/PacketPalette.cs @@ -213,6 +213,7 @@ void RegisterPacket() RegisterPacket(); RegisterPacket(); RegisterPacket(); + RegisterPacket(); RegisterPacket(); RegisterPacket(); From a7d5f21442ea3015ec9f5b57d76fcacec1098eac Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Sat, 10 Aug 2024 17:59:43 +0200 Subject: [PATCH 65/73] fixed some race condition bugs within ChunkSection --- Components/MineSharp.World/Chunks/IChunkSection.cs | 2 +- .../Containers/Palettes/SingleValuePalette.cs | 5 +++-- Components/MineSharp.World/V1_18/ChunkSection_1_18.cs | 9 +++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Components/MineSharp.World/Chunks/IChunkSection.cs b/Components/MineSharp.World/Chunks/IChunkSection.cs index f03bb443..d877d9df 100644 --- a/Components/MineSharp.World/Chunks/IChunkSection.cs +++ b/Components/MineSharp.World/Chunks/IChunkSection.cs @@ -13,7 +13,7 @@ public interface IChunkSection /// /// The number of solid blocks in this chunk section. /// - public short SolidBlockCount { get; protected set; } + public short SolidBlockCount { get; } /// /// Returns the Block at the given position. diff --git a/Components/MineSharp.World/Containers/Palettes/SingleValuePalette.cs b/Components/MineSharp.World/Containers/Palettes/SingleValuePalette.cs index 07543960..31f496c7 100644 --- a/Components/MineSharp.World/Containers/Palettes/SingleValuePalette.cs +++ b/Components/MineSharp.World/Containers/Palettes/SingleValuePalette.cs @@ -32,8 +32,9 @@ public int Get(int index) var count = (int)Math.Ceiling(container.Capacity / (64.0F / container.MinBits)); var lData = new long[count]; - container.Data = new(lData, container.MaxBits); - container.Data.Set(index, 1); + var newData = new IntBitArray(lData, container.MinBits); + newData.Set(index, 1); + container.Data = newData; return new IndirectPalette(map); } diff --git a/Components/MineSharp.World/V1_18/ChunkSection_1_18.cs b/Components/MineSharp.World/V1_18/ChunkSection_1_18.cs index ddfdcc6a..19763c8c 100644 --- a/Components/MineSharp.World/V1_18/ChunkSection_1_18.cs +++ b/Components/MineSharp.World/V1_18/ChunkSection_1_18.cs @@ -19,12 +19,13 @@ internal class ChunkSection118 : IChunkSection public ChunkSection118(MinecraftData data, short blockCount, BlockContainer blocks, BiomeContainer biomes) { this.data = data; - SolidBlockCount = blockCount; + solidBlockCount = blockCount; blockContainer = blocks; biomeContainer = biomes; } - public short SolidBlockCount { get; set; } + private int solidBlockCount; + public short SolidBlockCount => (short)solidBlockCount; public int GetBlockAt(Position position) { @@ -44,11 +45,11 @@ public void SetBlockAt(int state, Position position) { if (isSolid) { - SolidBlockCount++; + Interlocked.Increment(ref solidBlockCount); } else { - SolidBlockCount--; + Interlocked.Decrement(ref solidBlockCount); } } From 45c4eafe15825bf7622694e7ed9f8580022e23fc Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Sat, 10 Aug 2024 18:11:58 +0200 Subject: [PATCH 66/73] added OnPacketReceived method --- .../MineSharp.Protocol/MinecraftClient.cs | 55 ++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index 4d695492..8d924431 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -3,6 +3,7 @@ using System.Net; using System.Net.Sockets; using System.Threading.Tasks.Dataflow; +using ConcurrentCollections; using MineSharp.Auth; using MineSharp.ChatComponent; using MineSharp.ChatComponent.Components; @@ -109,6 +110,7 @@ public sealed class MinecraftClient : IAsyncDisposable, IDisposable private readonly ConcurrentDictionary> packetHandlers; private readonly ConcurrentDictionary> packetWaiters; + private readonly ConcurrentHashSet packetReceivers; private GameStatePacketHandler gameStatePacketHandler; private readonly BufferBlock packetQueue; private bool bundlePackets; @@ -148,6 +150,7 @@ public MinecraftClient( gameStatePacketHandler = new HandshakePacketHandler(this); packetHandlers = new(); packetWaiters = new(); + packetReceivers = new(); gameJoinedTcs = new(); bundledPackets = new(); tcpTcpFactory = tcpFactory; @@ -344,6 +347,42 @@ public Task WaitForPacket() where T : IPacket return tcs.Task.ContinueWith(prev => (T)prev.Result); } + public sealed class OnPacketReceivedRegistration : IDisposable + { + private readonly MinecraftClient client; + private readonly AsyncPacketHandler handler; + public bool Disposed { get; private set; } + + internal OnPacketReceivedRegistration(MinecraftClient client, AsyncPacketHandler handler) + { + this.client = client; + this.handler = handler; + } + + public void Dispose() + { + if (Disposed) + { + return; + } + client.packetReceivers.TryRemove(handler); + Disposed = true; + } + } + + /// + /// Registers a handler that will be called whenever a packet is received. + /// CAUTION: This will parse all packets, even if they are not awaited by any other handler. + /// This can lead to performance issues if the server sends a lot of packets. + /// Use this for debugging purposes only. + /// + /// A delegate that will be called when a packet is received. + public OnPacketReceivedRegistration? OnPacketReceived(AsyncPacketHandler handler) + { + var added = packetReceivers.Add(handler); + return added ? new(this, handler) : null; + } + /// /// Waits until the client jumps into the state. /// @@ -602,7 +641,7 @@ private async Task HandleIncomingPacket(PacketType packetType, PacketBuffer buff packetWaiters.TryGetValue(packetType, out var tcs); - if (handlers.Count == 0 && tcs == null) + if (handlers.Count == 0 && tcs == null && packetReceivers.IsEmpty) { await buffer.DisposeAsync(); return; @@ -622,6 +661,20 @@ private async Task HandleIncomingPacket(PacketType packetType, PacketBuffer buff try { // Run all handlers in parallel: + foreach (var packetReceiver in packetReceivers) + { + // The synchronous part of the handlers might throw an exception + // So we also do this in a try-catch block + try + { + packetHandlersTasks.Add(packetReceiver(packet)); + } + catch (Exception e) + { + Logger.Warn(e, "An packet receiver threw an exception when receiving a packet of type {PacketType}.", packetType); + } + } + foreach (var handler in handlers) { // The synchronous part of the handlers might throw an exception From 1b2626e8d749e8d55f9b599c566ef474c0ed819c Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Sat, 10 Aug 2024 21:11:46 +0200 Subject: [PATCH 67/73] made Position a readonly struct + removed MutablePosition --- .../Components/FluidPhysicsComponent.cs | 8 +- .../Packets/Clientbound/Play/LoginPacket.cs | 4 +- .../Packets/Clientbound/Play/RespawnPacket.cs | 4 +- .../Packets/NetworkTypes/EntityMetadata.cs | 15 ++-- Components/MineSharp.World/AbstractWorld.cs | 12 --- MineSharp.Core/Geometry/Position.cs | 76 ++++++++----------- 6 files changed, 46 insertions(+), 73 deletions(-) diff --git a/Components/MineSharp.Physics/Components/FluidPhysicsComponent.cs b/Components/MineSharp.Physics/Components/FluidPhysicsComponent.cs index e61e0c12..100f8939 100644 --- a/Components/MineSharp.Physics/Components/FluidPhysicsComponent.cs +++ b/Components/MineSharp.Physics/Components/FluidPhysicsComponent.cs @@ -62,14 +62,14 @@ private bool DoFluidPushing(BlockType type, double factor, out double height) var vel = Vector3.Zero.Clone(); var k1 = 0; - var pos = new MutablePosition(0, 0, 0); + var pos = Position.Zero; for (var x = fromX; x < toX; ++x) // TODO: Implement world iterators, that would be nicer { for (var y = fromY; y < toY; ++y) { for (var z = fromZ; z < toZ; ++z) { - pos.Set(x, y, z); + pos = new(x, y, z); var block = World.GetBlockAt(pos); if (block.Info.Type != type) @@ -143,12 +143,12 @@ private MutableVector3 GetFlow(IWorld world, Block fluid) { var dX = 0.0d; var dZ = 0.0d; - var pos = new MutablePosition(0, 0, 0); + var pos = Position.Zero; var height = GetFluidHeight(world, fluid); foreach (var direction in XzPlane) { - pos.Set( + pos = new( fluid.Position.X + (int)direction.X, fluid.Position.Y + (int)direction.Y, fluid.Position.Z + (int)direction.Z); diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs index 6d917969..6f8ecf7a 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/LoginPacket.cs @@ -108,8 +108,8 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteBool(HasDeathLocation); if (HasDeathLocation) { - buffer.WriteIdentifier(DeathDimensionName!); - buffer.WritePosition(DeathLocation!); + buffer.WriteIdentifier(DeathDimensionName ?? throw new InvalidOperationException($"{nameof(DeathDimensionName)} must not be null if {nameof(HasDeathLocation)} is true.")); + buffer.WritePosition(DeathLocation ?? throw new InvalidOperationException($"{nameof(DeathLocation)} must not be null if {nameof(HasDeathLocation)} is true.")); } if (version.Version.Protocol >= ProtocolVersion.V_1_20) diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs index 683fc15a..ef4f020b 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/RespawnPacket.cs @@ -52,8 +52,8 @@ public void Write(PacketBuffer buffer, MinecraftData version) if ((HasDeathLocation ?? false)) { - buffer.WriteIdentifier(DeathDimensionName!); - buffer.WritePosition(DeathLocation!); + buffer.WriteIdentifier(DeathDimensionName ?? throw new InvalidOperationException($"{nameof(DeathDimensionName)} must not be null if {nameof(HasDeathLocation)} is true.")); + buffer.WritePosition(DeathLocation ?? throw new InvalidOperationException($"{nameof(DeathLocation)} must not be null if {nameof(HasDeathLocation)} is true.")); } if (version.Version.Protocol >= ProtocolVersion.V_1_20) diff --git a/Components/MineSharp.Protocol/Packets/NetworkTypes/EntityMetadata.cs b/Components/MineSharp.Protocol/Packets/NetworkTypes/EntityMetadata.cs index 14a6abd6..fd8bfe0e 100644 --- a/Components/MineSharp.Protocol/Packets/NetworkTypes/EntityMetadata.cs +++ b/Components/MineSharp.Protocol/Packets/NetworkTypes/EntityMetadata.cs @@ -38,6 +38,7 @@ public static EntityMetadata Read(PacketBuffer buffer, MinecraftData data) var entries = new List(); while (true) { + // TODO: Some metadata is broken and causes exceptions var index = buffer.Peek(); if (index == EndOfMetadataIndex) { @@ -235,15 +236,15 @@ public sealed record OptionalPositionMetadata(Position? Value) : IMetadataValue, { public void Write(PacketBuffer buffer, MinecraftData data) { - var hasValue = Value != null; + var hasValue = Value.HasValue; buffer.WriteBool(hasValue); - if (hasValue) buffer.WritePosition(Value); + if (hasValue) buffer.WritePosition(Value!.Value); } public static OptionalPositionMetadata Read(PacketBuffer buffer, MinecraftData data) { var hasValue = buffer.ReadBool(); - var value = hasValue ? buffer.ReadPosition() : null; + Position? value = hasValue ? buffer.ReadPosition() : null; return new(value); } } @@ -260,7 +261,7 @@ public void Write(PacketBuffer buffer, MinecraftData data) { var hasValue = Value.HasValue; buffer.WriteBool(hasValue); - if (hasValue) buffer.WriteUuid(Value.Value); + if (hasValue) buffer.WriteUuid(Value!.Value); } public static OptionalUuidMetadata Read(PacketBuffer buffer, MinecraftData data) @@ -365,8 +366,8 @@ public void Write(PacketBuffer buffer, MinecraftData data) buffer.WriteBool(HasValue); if (HasValue) { - buffer.WriteIdentifier(DimensionIdentifier); - buffer.WritePosition(Position); + buffer.WriteIdentifier(DimensionIdentifier ?? throw new InvalidOperationException($"{nameof(DimensionIdentifier)} must not be null if {nameof(HasValue)} is true.")); + buffer.WritePosition(Position ?? throw new InvalidOperationException($"{nameof(Position)} must not be null if {nameof(HasValue)} is true.")); } } @@ -374,7 +375,7 @@ public static OptionalGlobalPositionMetadata Read(PacketBuffer buffer, Minecraft { var hasValue = buffer.ReadBool(); var dimensionIdentifier = hasValue ? buffer.ReadIdentifier() : null; - var position = hasValue ? buffer.ReadPosition() : null; + Position? position = hasValue ? buffer.ReadPosition() : null; return new(hasValue, dimensionIdentifier, position); } } diff --git a/Components/MineSharp.World/AbstractWorld.cs b/Components/MineSharp.World/AbstractWorld.cs index bbadc34c..1e84690d 100644 --- a/Components/MineSharp.World/AbstractWorld.cs +++ b/Components/MineSharp.World/AbstractWorld.cs @@ -285,18 +285,6 @@ public IEnumerable FindBlocks(BlockType type, int? maxCount = null) } } - /// - /// Mutate to a world position - /// - /// - /// - protected void MutateToWorldPosition(ChunkCoordinates coordinates, MutablePosition position) - { - var dx = coordinates.X * IChunk.Size; - var dz = coordinates.Z * IChunk.Size; - position.Set(position.X + dx, position.Y, position.Z + dz); - } - private void OnChunkBlockUpdate(IChunk chunk, int state, Position position) { var worldPosition = ToWorldPosition(chunk.Coordinates, position); diff --git a/MineSharp.Core/Geometry/Position.cs b/MineSharp.Core/Geometry/Position.cs index fb39d0e7..a70d02ed 100644 --- a/MineSharp.Core/Geometry/Position.cs +++ b/MineSharp.Core/Geometry/Position.cs @@ -3,8 +3,28 @@ /// /// Represents a 3D-Position /// -public class Position +public readonly struct Position : IEquatable { + /// + /// A Position with all coordinates set to zero + /// + public static Position Zero => new(0, 0, 0); + + /// + /// The X coordinate + /// + public readonly int X; + + /// + /// The Y coordinate + /// + public readonly int Y; + + /// + /// The Z coordinate + /// + public readonly int Z; + /// /// Create a new Position from a packed ulong /// @@ -49,21 +69,6 @@ public Position(double x, double y, double z) Z = (int)Math.Floor(z); } - /// - /// The X coordinate - /// - public int X { get; protected set; } - - /// - /// The Y coordinate - /// - public int Y { get; protected set; } - - /// - /// The Z coordinate - /// - public int Z { get; protected set; } - /// /// Check if the two positions represent the same point /// @@ -72,7 +77,7 @@ public Position(double x, double y, double z) /// public static bool operator ==(Position a, Position b) { - return a.ToULong() == b.ToULong(); + return a.Equals(b); } /// @@ -83,7 +88,13 @@ public Position(double x, double y, double z) /// public static bool operator !=(Position a, Position b) { - return a.ToULong() != b.ToULong(); + return !(a == b); + } + + /// + public bool Equals(Position other) + { + return ToULong() == other.ToULong(); } /// @@ -91,7 +102,7 @@ public override bool Equals(object? obj) { if (obj is Position pos) { - return pos.ToULong() == ToULong(); + return Equals(pos); } return false; @@ -128,30 +139,3 @@ public static explicit operator Vector3(Position x) return new(x.X, x.Y, x.Z); } } - -/// -/// A whose coordinates are mutable. -/// -public class MutablePosition : Position -{ - /// - public MutablePosition(ulong value) : base(value) - { } - - /// - public MutablePosition(int x, int y, int z) : base(x, y, z) - { } - - /// - /// Update the X, Y, Z coordinates of this position - /// - /// - /// - /// - public void Set(int x, int y, int z) - { - X = x; - Y = y; - Z = z; - } -} From a47103939822c6a9c55c8597f26ca7c42f7dab3e Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Sat, 10 Aug 2024 21:28:03 +0200 Subject: [PATCH 68/73] fix race condition with bundled packets --- .../MineSharp.Protocol/MinecraftClient.cs | 44 ++++++++++++------- .../Packets/Handlers/PlayPacketHandler.cs | 3 +- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index 8d924431..f7298432 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -113,8 +113,14 @@ public sealed class MinecraftClient : IAsyncDisposable, IDisposable private readonly ConcurrentHashSet packetReceivers; private GameStatePacketHandler gameStatePacketHandler; private readonly BufferBlock packetQueue; - private bool bundlePackets; - private readonly ConcurrentQueue<(PacketType, PacketBuffer)> bundledPackets; + /// + /// Contains the packets that are bundled together. + /// + /// If this field is null, packets are not bundled. + /// If this field is not null, packets are bundled. + /// This way we can avoid all race conditions that would occur if we would use a boolean flag. + /// + private ConcurrentQueue<(PacketType Type, PacketBuffer Buffer)>? bundledPackets; private readonly CancellationTokenSource cancellationTokenSource; @@ -152,7 +158,7 @@ public MinecraftClient( packetWaiters = new(); packetReceivers = new(); gameJoinedTcs = new(); - bundledPackets = new(); + bundledPackets = null; tcpTcpFactory = tcpFactory; ip = IpHelper.ResolveHostname(hostnameOrIp, ref port); @@ -447,29 +453,36 @@ internal void SetCompression(int threshold) stream!.SetCompression(threshold); } - internal void HandleBundleDelimiter() + internal async Task HandleBundleDelimiter() { - bundlePackets = !bundlePackets; - if (!bundlePackets) + var bundledPackets = Interlocked.Exchange(ref this.bundledPackets, null); + if (bundledPackets != null) { Logger.Debug("Processing bundled packets"); var tasks = bundledPackets.Select( - p => HandleIncomingPacket(p.Item1, p.Item2)) + p => HandleIncomingPacket(p.Type, p.Buffer)) .ToArray(); - Task.WaitAll(tasks); + // no clearing required the queue will no longer be used and will get GCed + //bundledPackets.Clear(); + + await Task.WhenAll(tasks); - var errors = tasks.Where(x => x.Exception != null); - foreach (var error in errors) + foreach (var faultedTask in tasks.Where(task => task.Status == TaskStatus.Faulted)) { - Logger.Error("Error handling bundled packet: {e}", error); + Logger.Error(faultedTask.Exception, "Error handling bundled packet."); } - - bundledPackets.Clear(); } else { - Logger.Debug("Bundling packets!"); + if (Interlocked.CompareExchange(ref this.bundledPackets, new(), null) == null) + { + Logger.Debug("Bundling packets!"); + } + else + { + Logger.Warn("Bundling could not be enabled because it was already enabled. This is a race condition."); + } } } @@ -514,7 +527,8 @@ private async Task ReceivePackets() } else { - if (bundlePackets) + var bundledPackets = this.bundledPackets; + if (bundledPackets != null) { bundledPackets.Enqueue((packetType, buffer)); } diff --git a/Components/MineSharp.Protocol/Packets/Handlers/PlayPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/PlayPacketHandler.cs index 96834e04..4777a488 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/PlayPacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/PlayPacketHandler.cs @@ -50,8 +50,7 @@ private Task HandleKeepAlive(KeepAlivePacket packet) private Task HandleBundleDelimiter(BundleDelimiterPacket bundleDelimiter) { - client.HandleBundleDelimiter(); - return Task.CompletedTask; + return client.HandleBundleDelimiter(); } private Task HandlePing(PingPacket ping) From c35c7611551870b28b74f7b023f5ad3c8344f0a2 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Sun, 11 Aug 2024 03:16:57 +0200 Subject: [PATCH 69/73] fixed bug with receiving invalid disconnect (login) packet by reworking game static handling logic --- .../MineSharp.Protocol/MinecraftClient.cs | 100 +++++++----------- .../Clientbound/Login/DisconnectPacket.cs | 15 +-- .../Handlers/ConfigurationPacketHandler.cs | 32 ++---- .../Handlers/GameStatePacketHandler.cs | 12 ++- .../Handlers/HandshakePacketHandler.cs | 11 +- .../Packets/Handlers/IPacketHandler.cs | 11 -- .../Packets/Handlers/LoginPacketHandler.cs | 28 ++--- .../Packets/Handlers/NoStatePacketHandler.cs | 25 +++++ .../Packets/Handlers/PlayPacketHandler.cs | 25 +++-- .../Packets/Handlers/StatusPacketHandler.cs | 7 +- .../Packets/HandshakeProtocol.cs | 9 +- MineSharp.Core/Common/Protocol/GameState.cs | 2 + 12 files changed, 125 insertions(+), 152 deletions(-) delete mode 100644 Components/MineSharp.Protocol/Packets/Handlers/IPacketHandler.cs create mode 100644 Components/MineSharp.Protocol/Packets/Handlers/NoStatePacketHandler.cs diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index f7298432..35960a2e 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -7,8 +7,6 @@ using MineSharp.Auth; using MineSharp.ChatComponent; using MineSharp.ChatComponent.Components; -using MineSharp.Core; -using MineSharp.Core.Common; using MineSharp.Core.Common.Protocol; using MineSharp.Core.Concurrency; using MineSharp.Core.Events; @@ -18,7 +16,6 @@ using MineSharp.Protocol.Connection; using MineSharp.Protocol.Exceptions; using MineSharp.Protocol.Packets; -using MineSharp.Protocol.Packets.Clientbound.Login; using MineSharp.Protocol.Packets.Clientbound.Status; using MineSharp.Protocol.Packets.Handlers; using MineSharp.Protocol.Packets.Serverbound.Configuration; @@ -124,7 +121,10 @@ public sealed class MinecraftClient : IAsyncDisposable, IDisposable private readonly CancellationTokenSource cancellationTokenSource; - private readonly TaskCompletionSource gameJoinedTcs; + /// + /// Will be completed once the client has entered the state. + /// + internal readonly TaskCompletionSource GameJoinedTcs; /// @@ -153,11 +153,11 @@ public MinecraftClient( { CancellationToken = CancellationToken }); - gameStatePacketHandler = new HandshakePacketHandler(this); + gameStatePacketHandler = new NoStatePacketHandler(this); packetHandlers = new(); packetWaiters = new(); packetReceivers = new(); - gameJoinedTcs = new(); + GameJoinedTcs = new(); bundledPackets = null; tcpTcpFactory = tcpFactory; ip = IpHelper.ResolveHostname(hostnameOrIp, ref port); @@ -270,11 +270,17 @@ public async Task SendPacket(IPacket packet, CancellationToken cancellation = de // if the packetQueue is completed we can not send any more packets // so we need to cancel the task here // this must have happened because the CancellationToken was cancelled + Logger.Warn("Packet {PacketType} could not be added send queue. Queue closed.", packet.Type); sendingTask.Task.TrySetCanceled(CancellationToken); } + else + { + Logger.Trace("Packet {PacketType} was added to send queue", packet.Type); + } } catch (OperationCanceledException e) { + Logger.Warn("Packet {PacketType} could not be added send queue. Sending Packet CancellationToken was cancelled.", packet.Type); sendingTask.Task.TrySetCanceled(e.CancellationToken); throw; } @@ -291,17 +297,6 @@ public async Task SendPacket(IPacket packet, CancellationToken cancellation = de /// public EnsureOnlyRunOnceAsyncResult Disconnect(Chat? reason = null) { - if (reason is TranslatableComponent translatable - && Identifier.TryParse(translatable.Translation, out var identifier) - && identifier == DisconnectPacket.BrandIdentifier) - { - // ignore the disconnect packet if it is the weird brand reason - // because otherwise we can not connect to the server - // maybe this is a test from the server to check whether we know how to deal with this?!? - // and just continue logging in?!? - return new(Task.CompletedTask, true); - } - return ConcurrencyHelper.EnsureOnlyRunOnceAsync(() => DisconnectInternal(reason), ref disconnectTask); } @@ -312,7 +307,7 @@ private async Task DisconnectInternal(Chat? reason = null) var message = reason.GetMessage(Data); Logger.Info($"Disconnecting: {message}"); - gameJoinedTcs.TrySetException(new DisconnectedException("Client has been disconnected", message)); + GameJoinedTcs.TrySetException(new DisconnectedException("Client has been disconnected", message)); if (client is null || !client.Connected) { @@ -395,12 +390,25 @@ public void Dispose() /// public Task WaitForGame() { - return gameJoinedTcs.Task; + return GameJoinedTcs.Task; + } + + internal Task SendClientInformationPacket() + { + return SendPacket(new ClientInformationPacket( + Settings.Locale, + Settings.ViewDistance, + Settings.ChatMode, + Settings.ColoredChat, + Settings.DisplayedSkinParts, + Settings.MainHand, + Settings.EnableTextFiltering, + Settings.AllowServerListings)); } - internal void UpdateGameState(GameState next) + internal async Task ChangeGameState(GameState next) { - gameStatePacketHandler = next switch + GameStatePacketHandler newGameStatePacketHandler = next switch { GameState.Handshaking => new HandshakePacketHandler(this), GameState.Login => new LoginPacketHandler(this, Data), @@ -409,38 +417,8 @@ internal void UpdateGameState(GameState next) GameState.Play => new PlayPacketHandler(this, Data), _ => throw new UnreachableException() }; - - if (next == GameState.Play && !gameJoinedTcs.Task.IsCompleted) - { - if (Data.Version.Protocol <= ProtocolVersion.V_1_20) - { - Task.Delay(10) - .ContinueWith(x => - SendPacket(new Packets.Serverbound.Play.ClientInformationPacket( - Settings.Locale, - Settings.ViewDistance, - Settings.ChatMode, - Settings.ColoredChat, - Settings.DisplayedSkinParts, - Settings.MainHand, - Settings.EnableTextFiltering, - Settings.AllowServerListings))); - } - gameJoinedTcs.TrySetResult(); - } - - if (next == GameState.Configuration) - { - _ = SendPacket(new ClientInformationPacket( - Settings.Locale, - Settings.ViewDistance, - Settings.ChatMode, - Settings.ColoredChat, - Settings.DisplayedSkinParts, - Settings.MainHand, - Settings.EnableTextFiltering, - Settings.AllowServerListings)); - } + gameStatePacketHandler = newGameStatePacketHandler; + await newGameStatePacketHandler.StateEntered(); } internal void EnableEncryption(byte[] key) @@ -491,8 +469,8 @@ private async Task StreamLoop() try { // run both tasks in parallel - var receiveTask = Task.Run(ReceivePackets); - var sendTask = Task.Run(SendPackets); + var receiveTask = Task.Factory.StartNew(ReceivePackets, TaskCreationOptions.LongRunning); + var sendTask = Task.Factory.StartNew(SendPackets, TaskCreationOptions.LongRunning); // extract the exception from the task that finished first await await Task.WhenAny(receiveTask, sendTask); @@ -521,7 +499,9 @@ private async Task ReceivePackets() var gameState = gameStatePacketHandler.GameState; var packetType = Data.Protocol.GetPacketType(PacketFlow.Clientbound, gameState, packetId); - if (gameState == GameState.Login) + Logger.Trace("Received packet {PacketType}. GameState = {GameState}, PacketId = {PacketId}", packetType, gameState, packetId); + + if (gameState != GameState.Play) { await HandleIncomingPacket(packetType, buffer); } @@ -554,7 +534,9 @@ private async Task SendPackets() try { DispatchPacket(task.Packet); - task.Task.TrySetResult(); + // TrySetResult must be run from a different task to prevent blocking the stream loop + // because the task continuation will be executed inline and might block or cause a deadlock + _ = Task.Run(task.Task.TrySetResult); // TODO: this feels wrong // we probably should ask outgoing packet listeners before sending the packet @@ -611,7 +593,7 @@ private void DispatchPacket(IPacket packet) return packet; } - catch (EndOfStreamException e) + catch (Exception e) { Logger.Error(e, "Could not read packet {PacketType}, it was {Size} bytes.", packetType, size); } @@ -631,7 +613,7 @@ private async Task HandleIncomingPacket(PacketType packetType, PacketBuffer buff // - MinecraftClient.OnPacketReceived <-- Forces all packets to be parsed // - The internal IPacketHandler - Logger.Trace("Received packet {PacketType}", packetType); + Logger.Trace("Handling packet {PacketType}", packetType); var factory = PacketPalette.GetFactory(packetType); if (factory == null) { diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs index 7b1e508e..4e6ac2a1 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Login/DisconnectPacket.cs @@ -26,25 +26,12 @@ public void Write(PacketBuffer buffer, MinecraftData version) buffer.WriteString(Reason.ToJson().ToString()); } - public static readonly Identifier BrandIdentifier = Identifier.Parse("minecraft:brand"); - /// public static IPacket Read(PacketBuffer buffer, MinecraftData version) { var reason = buffer.ReadString(); // Disconnect (login) packet is always sent as JSON text component according to wiki.vg - // But thats wrong. - // Sometimes there are to strings sent. The first is always "minecraft:brand" and the second the brand, typically "vanilla". - Chat chat; - if (Identifier.TryParse(reason, out var identifer) && identifer == BrandIdentifier) - { - var value = buffer.ReadString(); - chat = new TranslatableComponent(reason, [new TextComponent(value)]); - } - else - { - chat = Chat.Parse(reason); - } + var chat = Chat.Parse(reason); return new DisconnectPacket(chat); } } diff --git a/Components/MineSharp.Protocol/Packets/Handlers/ConfigurationPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/ConfigurationPacketHandler.cs index 4594b53a..bc39a5db 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/ConfigurationPacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/ConfigurationPacketHandler.cs @@ -3,16 +3,13 @@ using MineSharp.Data.Protocol; using MineSharp.Protocol.Packets.Clientbound.Configuration; using MineSharp.Protocol.Packets.Serverbound.Configuration; -using NLog; using FinishConfigurationPacket = MineSharp.Protocol.Packets.Clientbound.Configuration.FinishConfigurationPacket; using KeepAlivePacket = MineSharp.Protocol.Packets.Clientbound.Configuration.KeepAlivePacket; namespace MineSharp.Protocol.Packets.Handlers; -internal class ConfigurationPacketHandler : GameStatePacketHandler +internal sealed class ConfigurationPacketHandler : GameStatePacketHandler { - private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); - private readonly MinecraftClient client; private readonly MinecraftData data; @@ -23,6 +20,11 @@ public ConfigurationPacketHandler(MinecraftClient client, MinecraftData data) this.data = data; } + public override Task StateEntered() + { + return client.SendClientInformationPacket(); + } + public override Task HandleIncoming(IPacket packet) { return packet switch @@ -36,16 +38,6 @@ public override Task HandleIncoming(IPacket packet) }; } - public override Task HandleOutgoing(IPacket packet) - { - if (packet is Serverbound.Configuration.FinishConfigurationPacket) - { - client.UpdateGameState(GameState.Play); - } - - return Task.CompletedTask; - } - public override bool HandlesIncoming(PacketType type) { return type is PacketType.CB_Configuration_Disconnect @@ -61,21 +53,19 @@ private Task HandleDisconnect(DisconnectPacket packet) return Task.CompletedTask; } - private Task HandleFinishConfiguration(FinishConfigurationPacket packet) + private async Task HandleFinishConfiguration(FinishConfigurationPacket packet) { - _ = client.SendPacket(new Serverbound.Configuration.FinishConfigurationPacket()); - return Task.CompletedTask; + await client.SendPacket(new Serverbound.Configuration.FinishConfigurationPacket()); + await client.ChangeGameState(GameState.Play); } private Task HandleKeepAlive(KeepAlivePacket packet) { - client.SendPacket(new Serverbound.Configuration.KeepAlivePacket(packet.KeepAliveId)); - return Task.CompletedTask; + return client.SendPacket(new Serverbound.Configuration.KeepAlivePacket(packet.KeepAliveId)); } private Task HandlePing(PingPacket packet) { - client.SendPacket(new PongPacket(packet.Id)); - return Task.CompletedTask; + return client.SendPacket(new PongPacket(packet.Id)); } } diff --git a/Components/MineSharp.Protocol/Packets/Handlers/GameStatePacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/GameStatePacketHandler.cs index 3dff6289..040a0140 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/GameStatePacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/GameStatePacketHandler.cs @@ -3,7 +3,7 @@ namespace MineSharp.Protocol.Packets.Handlers; -internal abstract class GameStatePacketHandler : IPacketHandler +internal abstract class GameStatePacketHandler { public readonly GameState GameState; @@ -12,7 +12,15 @@ protected GameStatePacketHandler(GameState gameState) GameState = gameState; } + public virtual Task StateEntered() + { + return Task.CompletedTask; + } public abstract Task HandleIncoming(IPacket packet); - public abstract Task HandleOutgoing(IPacket packet); + // normally this is not required + public virtual Task HandleOutgoing(IPacket packet) + { + return Task.CompletedTask; + } public abstract bool HandlesIncoming(PacketType type); } diff --git a/Components/MineSharp.Protocol/Packets/Handlers/HandshakePacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/HandshakePacketHandler.cs index 7cae3007..84823267 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/HandshakePacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/HandshakePacketHandler.cs @@ -1,11 +1,10 @@ using MineSharp.Core.Common.Protocol; using MineSharp.Data.Protocol; using MineSharp.Protocol.Exceptions; -using MineSharp.Protocol.Packets.Serverbound.Handshaking; namespace MineSharp.Protocol.Packets.Handlers; -internal class HandshakePacketHandler : GameStatePacketHandler +internal sealed class HandshakePacketHandler : GameStatePacketHandler { private readonly MinecraftClient client; @@ -24,7 +23,6 @@ public override Task HandleOutgoing(IPacket packet) { return packet switch { - HandshakePacket handshake => HandleHandshake(handshake), _ => throw new UnexpectedPacketException( $"unexpected outgoing packet during handshaking: {packet.GetType().FullName}") }; @@ -34,11 +32,4 @@ public override bool HandlesIncoming(PacketType type) { return false; } - - - private Task HandleHandshake(HandshakePacket packet) - { - client.UpdateGameState(packet.NextState); - return Task.CompletedTask; - } } diff --git a/Components/MineSharp.Protocol/Packets/Handlers/IPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/IPacketHandler.cs deleted file mode 100644 index f099b29b..00000000 --- a/Components/MineSharp.Protocol/Packets/Handlers/IPacketHandler.cs +++ /dev/null @@ -1,11 +0,0 @@ -using MineSharp.Data.Protocol; - -namespace MineSharp.Protocol.Packets.Handlers; - -internal interface IPacketHandler -{ - public Task HandleIncoming(IPacket packet); - public Task HandleOutgoing(IPacket packet); - - public bool HandlesIncoming(PacketType type); -} diff --git a/Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs index 11921a1c..efd98c69 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/LoginPacketHandler.cs @@ -13,7 +13,7 @@ namespace MineSharp.Protocol.Packets.Handlers; -internal class LoginPacketHandler : GameStatePacketHandler +internal sealed class LoginPacketHandler : GameStatePacketHandler { private static readonly ILogger Logger = LogManager.GetCurrentClassLogger(); @@ -27,6 +27,12 @@ public LoginPacketHandler(MinecraftClient client, MinecraftData data) this.data = data; } + public override Task StateEntered() + { + var login = HandshakeProtocol.GetLoginPacket(data, client.Session); + return client.SendPacket(login); + } + public override Task HandleIncoming(IPacket packet) { return packet switch @@ -34,16 +40,12 @@ public override Task HandleIncoming(IPacket packet) DisconnectPacket disconnect => HandleDisconnect(disconnect), EncryptionRequestPacket encryption => HandleEncryptionRequest(encryption), SetCompressionPacket compression => HandleSetCompression(compression), + // TODO: handle LoginPluginRequestPacket LoginSuccessPacket success => HandleLoginSuccess(success), _ => throw new UnreachableException() }; } - public override Task HandleOutgoing(IPacket packet) - { - return Task.CompletedTask; - } - public override bool HandlesIncoming(PacketType type) { return type is PacketType.CB_Login_Disconnect @@ -119,16 +121,16 @@ private Task HandleSetCompression(SetCompressionPacket packet) return Task.CompletedTask; } - private Task HandleLoginSuccess(LoginSuccessPacket packet) + private async Task HandleLoginSuccess(LoginSuccessPacket packet) { if (data.Version.Protocol < ProtocolVersion.V_1_20_2) { - client.UpdateGameState(GameState.Play); - return Task.CompletedTask; + await client.ChangeGameState(GameState.Play); + } + else + { + await client.SendPacket(new LoginAcknowledgedPacket()); + await client.ChangeGameState(GameState.Configuration); } - - _ = client.SendPacket(new LoginAcknowledgedPacket()) - .ContinueWith(_ => client.UpdateGameState(GameState.Configuration)); - return Task.CompletedTask; } } diff --git a/Components/MineSharp.Protocol/Packets/Handlers/NoStatePacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/NoStatePacketHandler.cs new file mode 100644 index 00000000..d26c7074 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Handlers/NoStatePacketHandler.cs @@ -0,0 +1,25 @@ +using MineSharp.Core.Common.Protocol; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Handlers; + +internal sealed class NoStatePacketHandler : GameStatePacketHandler +{ + private readonly MinecraftClient client; + + public NoStatePacketHandler(MinecraftClient client) + : base(GameState.None) + { + this.client = client; + } + + public override Task HandleIncoming(IPacket packet) + { + return Task.CompletedTask; + } + + public override bool HandlesIncoming(PacketType type) + { + return false; + } +} diff --git a/Components/MineSharp.Protocol/Packets/Handlers/PlayPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/PlayPacketHandler.cs index 4777a488..3d8811c0 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/PlayPacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/PlayPacketHandler.cs @@ -1,4 +1,5 @@ -using MineSharp.Core.Common.Protocol; +using MineSharp.Core; +using MineSharp.Core.Common.Protocol; using MineSharp.Data; using MineSharp.Data.Protocol; using MineSharp.Protocol.Packets.Clientbound.Play; @@ -7,7 +8,7 @@ namespace MineSharp.Protocol.Packets.Handlers; -internal class PlayPacketHandler : GameStatePacketHandler +internal sealed class PlayPacketHandler : GameStatePacketHandler { private readonly MinecraftClient client; private readonly MinecraftData data; @@ -19,6 +20,15 @@ public PlayPacketHandler(MinecraftClient client, MinecraftData data) this.data = data; } + public override async Task StateEntered() + { + if (data.Version.Protocol <= ProtocolVersion.V_1_20) + { + await client.SendClientInformationPacket(); + } + client.GameJoinedTcs.SetResult(); + } + public override Task HandleIncoming(IPacket packet) { return packet switch @@ -31,11 +41,6 @@ public override Task HandleIncoming(IPacket packet) }; } - public override Task HandleOutgoing(IPacket packet) - { - return Task.CompletedTask; - } - public override bool HandlesIncoming(PacketType type) { return type is PacketType.CB_Play_KeepAlive or PacketType.CB_Play_BundleDelimiter or PacketType.CB_Play_Ping @@ -44,8 +49,7 @@ public override bool HandlesIncoming(PacketType type) private Task HandleKeepAlive(KeepAlivePacket packet) { - _ = client.SendPacket(new Serverbound.Play.KeepAlivePacket(packet.KeepAliveId)); - return Task.CompletedTask; + return client.SendPacket(new Serverbound.Play.KeepAlivePacket(packet.KeepAliveId)); } private Task HandleBundleDelimiter(BundleDelimiterPacket bundleDelimiter) @@ -55,8 +59,7 @@ private Task HandleBundleDelimiter(BundleDelimiterPacket bundleDelimiter) private Task HandlePing(PingPacket ping) { - _ = client.SendPacket(new PongPacket(ping.Id)); - return Task.CompletedTask; + return client.SendPacket(new PongPacket(ping.Id)); } private Task HandleDisconnect(DisconnectPacket packet) diff --git a/Components/MineSharp.Protocol/Packets/Handlers/StatusPacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/StatusPacketHandler.cs index bb949540..a47cd10a 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/StatusPacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/StatusPacketHandler.cs @@ -3,7 +3,7 @@ namespace MineSharp.Protocol.Packets.Handlers; -internal class StatusPacketHandler : GameStatePacketHandler +internal sealed class StatusPacketHandler : GameStatePacketHandler { private readonly MinecraftClient client; @@ -18,11 +18,6 @@ public override Task HandleIncoming(IPacket packet) return Task.CompletedTask; } - public override Task HandleOutgoing(IPacket packet) - { - return Task.CompletedTask; - } - public override bool HandlesIncoming(PacketType type) { return false; diff --git a/Components/MineSharp.Protocol/Packets/HandshakeProtocol.cs b/Components/MineSharp.Protocol/Packets/HandshakeProtocol.cs index d56d188e..d7323ea0 100644 --- a/Components/MineSharp.Protocol/Packets/HandshakeProtocol.cs +++ b/Components/MineSharp.Protocol/Packets/HandshakeProtocol.cs @@ -12,24 +12,23 @@ internal static class HandshakeProtocol { public static async Task PerformHandshake(MinecraftClient client, GameState next, MinecraftData data) { - if (next is GameState.Play or GameState.Handshaking) + if (!(next is GameState.Status or GameState.Login)) { throw new ArgumentException($"{nameof(next)} must either be {GameState.Status} or {GameState.Login}"); } var handshake = new HandshakePacket(data.Version.Protocol, client.Hostname, client.Port, next); + await client.ChangeGameState(GameState.Handshaking); await client.SendPacket(handshake); + await client.ChangeGameState(next); if (next == GameState.Status) { return; } - - var login = GetLoginPacket(data, client.Session); - await client.SendPacket(login); } - private static LoginStartPacket GetLoginPacket(MinecraftData data, Session session) + internal static LoginStartPacket GetLoginPacket(MinecraftData data, Session session) { LoginStartPacket.SignatureContainer? signature = null; diff --git a/MineSharp.Core/Common/Protocol/GameState.cs b/MineSharp.Core/Common/Protocol/GameState.cs index 5337ee46..eae5fc17 100644 --- a/MineSharp.Core/Common/Protocol/GameState.cs +++ b/MineSharp.Core/Common/Protocol/GameState.cs @@ -11,5 +11,7 @@ public enum GameState Login = 2, Play = 3, Configuration = 4, + + None = -1 #pragma warning restore CS1591 } From 6f77541442cc8f66589512364f3a934caf5c134a Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Sun, 11 Aug 2024 18:10:59 +0200 Subject: [PATCH 70/73] added missing Packets - Part 4 --- .../Clientbound/Play/MerchantOffersPacket.cs | 15 +- .../Clientbound/Play/PickupItemPacket.cs | 41 ++ .../Clientbound/Play/SetEquipmentPacket.cs | 111 ++++++ .../Clientbound/Play/SetExperiencePacket.cs | 37 ++ .../Play/SetSimulationDistancePacket.cs | 30 ++ .../Clientbound/Play/SetSubtitleTextPacket.cs | 31 ++ .../Play/SetTabListHeaderFooterPacket.cs | 35 ++ .../Clientbound/Play/SetTickingStatePacket.cs | 34 ++ .../Play/SetTitleAnimationTimesPacket.cs | 37 ++ .../Clientbound/Play/SetTitleTextPacket.cs | 31 ++ .../Play/StartConfigurationPacket.cs | 30 ++ .../Clientbound/Play/StepTickPacket.cs | 30 ++ .../Clientbound/Play/StopSoundPacket.cs | 76 ++++ .../Play/TagQueryResponsePacket.cs | 35 ++ .../Play/UpdateObjectivesPacket.cs | 104 +++++ .../Clientbound/Play/UpdateScorePacket.cs | 83 ++++ .../Clientbound/Play/UpdateTeamsPacket.cs | 361 ++++++++++++++++++ .../Clientbound/Play/UpdateTimePacket.cs | 38 ++ .../Packets/NetworkTypes/EntityMetadata.cs | 7 +- .../NetworkTypes/ScoreboardNumberFormat.cs | 152 ++++++++ .../Packets/PacketPalette.cs | 17 + MineSharp.Core/Common/TextColor.cs | 35 ++ 22 files changed, 1360 insertions(+), 10 deletions(-) create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/PickupItemPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEquipmentPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetExperiencePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetSimulationDistancePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetSubtitleTextPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetTabListHeaderFooterPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetTickingStatePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetTitleAnimationTimesPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/SetTitleTextPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/StartConfigurationPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/StepTickPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/StopSoundPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/TagQueryResponsePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateObjectivesPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateScorePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateTeamsPacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateTimePacket.cs create mode 100644 Components/MineSharp.Protocol/Packets/NetworkTypes/ScoreboardNumberFormat.cs create mode 100644 MineSharp.Core/Common/TextColor.cs diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/MerchantOffersPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/MerchantOffersPacket.cs index d147414c..44c0211a 100644 --- a/Components/MineSharp.Protocol/Packets/Clientbound/Play/MerchantOffersPacket.cs +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/MerchantOffersPacket.cs @@ -1,4 +1,5 @@ using MineSharp.Core.Common; +using MineSharp.Core.Common.Items; using MineSharp.Core.Serialization; using MineSharp.Data; using MineSharp.Data.Protocol; @@ -70,14 +71,14 @@ public static IPacket Read(PacketBuffer buffer, MinecraftData version) /// The number added to the price when an item is discounted due to player reputation or other effects. /// Determines how much demand, player reputation, and temporary effects will adjust the price. /// If positive, causes the price to increase. Negative values seem to be treated the same as zero. - public sealed record Trade(Slot InputItem1, Slot OutputItem, Slot InputItem2, bool TradeDisabled, int NumberOfTradeUses, int MaximumNumberOfTradeUses, int XP, int SpecialPrice, float PriceMultiplier, int Demand) : ISerializableWithMinecraftData + public sealed record Trade(Item? InputItem1, Item? OutputItem, Item? InputItem2, bool TradeDisabled, int NumberOfTradeUses, int MaximumNumberOfTradeUses, int XP, int SpecialPrice, float PriceMultiplier, int Demand) : ISerializableWithMinecraftData { /// public void Write(PacketBuffer buffer, MinecraftData data) { - buffer.WriteSlot(InputItem1); - buffer.WriteSlot(OutputItem); - buffer.WriteSlot(InputItem2); + buffer.WriteOptionalItem(InputItem1); + buffer.WriteOptionalItem(OutputItem); + buffer.WriteOptionalItem(InputItem2); buffer.WriteBool(TradeDisabled); buffer.WriteInt(NumberOfTradeUses); buffer.WriteInt(MaximumNumberOfTradeUses); @@ -90,9 +91,9 @@ public void Write(PacketBuffer buffer, MinecraftData data) /// public static Trade Read(PacketBuffer buffer, MinecraftData data) { - var inputItem1 = buffer.ReadSlot(data); - var outputItem = buffer.ReadSlot(data); - var inputItem2 = buffer.ReadSlot(data); + var inputItem1 = buffer.ReadOptionalItem(data); + var outputItem = buffer.ReadOptionalItem(data); + var inputItem2 = buffer.ReadOptionalItem(data); var tradeDisabled = buffer.ReadBool(); var numberOfTradeUses = buffer.ReadInt(); var maximumNumberOfTradeUses = buffer.ReadInt(); diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/PickupItemPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PickupItemPacket.cs new file mode 100644 index 00000000..602531ab --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/PickupItemPacket.cs @@ -0,0 +1,41 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Sent by the server when someone picks up an item lying on the ground. +/// Its sole purpose appears to be the animation of the item flying towards you. +/// +/// The ID of the collected entity +/// The ID of the collector entity +/// The number of items picked up. Seems to be 1 for XP orbs, otherwise the number of items in the stack. +public sealed record PickupItemPacket(int CollectedEntityId, int CollectorEntityId, int PickupItemCount) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_Collect; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(CollectedEntityId); + buffer.WriteVarInt(CollectorEntityId); + buffer.WriteVarInt(PickupItemCount); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var collectedEntityId = buffer.ReadVarInt(); + var collectorEntityId = buffer.ReadVarInt(); + var pickupItemCount = buffer.ReadVarInt(); + + return new PickupItemPacket( + collectedEntityId, + collectorEntityId, + pickupItemCount); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEquipmentPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEquipmentPacket.cs new file mode 100644 index 00000000..f00ceaf4 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetEquipmentPacket.cs @@ -0,0 +1,111 @@ +using MineSharp.Core.Common; +using MineSharp.Core.Common.Items; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using MineSharp.Protocol.Packets.NetworkTypes; +using static MineSharp.Protocol.Packets.Clientbound.Play.SetEquipmentPacket; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Set Equipment packet +/// +/// The entity ID +/// The equipment list +public sealed record SetEquipmentPacket(int EntityId, EquipmentEntry[] Equipment) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_EntityEquipment; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(EntityId); + for (int i = 0; i < Equipment.Length; i++) + { + var entry = Equipment[i]; + var isLastEntry = i == Equipment.Length - 1; + entry.Write(buffer, version, isLastEntry); + } + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var entityId = buffer.ReadVarInt(); + var equipment = new List(); + while (true) + { + var slot = buffer.Peek(); + // wiki.vg says: "has the top bit set if another entry follows, and otherwise unset if this is the last item in the array" + var isLast = (slot & 0x80) == 0; + equipment.Add(EquipmentEntry.Read(buffer, version)); + if (isLast) + { + break; + } + } + + return new SetEquipmentPacket(entityId, equipment.ToArray()); + } + + /// + /// Equipment entry + /// + /// The equipment slot + /// The item in the slot + public sealed record EquipmentEntry(EquipmentSlot SlotId, Item? Item) : ISerializableWithMinecraftData + { + /// + [Obsolete("Use the Write method with the isLastEntry parameter instead")] + public void Write(PacketBuffer buffer, MinecraftData data) + { + Write(buffer, data, true); + } + + /// + /// Writes the equipment entry to the packet buffer. + /// This method is required because the slotId needs to be changed when its not the last entry + /// + /// The packet buffer to write to. + /// The Minecraft data. + /// Indicates if this is the last entry in the equipment list. + public void Write(PacketBuffer buffer, MinecraftData data, bool isLastEntry) + { + var slotId = (byte)SlotId; + if (!isLastEntry) + { + // wiki.vg says: "has the top bit set if another entry follows, and otherwise unset if this is the last item in the array" + slotId |= 0x80; // Set the top bit if another entry follows + } + buffer.WriteByte(slotId); + buffer.WriteOptionalItem(Item); + } + + /// + public static EquipmentEntry Read(PacketBuffer buffer, MinecraftData data) + { + var slotId = (EquipmentSlot)(buffer.ReadByte() & 0x7F); // Unset the top bit + var item = buffer.ReadOptionalItem(data); + return new EquipmentEntry(slotId, item); + } + } + + /// + /// Equipment slot enumeration + /// + public enum EquipmentSlot : byte + { +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + MainHand = 0, + OffHand = 1, + Boots = 2, + Leggings = 3, + Chestplate = 4, + Helmet = 5 +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetExperiencePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetExperiencePacket.cs new file mode 100644 index 00000000..d21ee6fa --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetExperiencePacket.cs @@ -0,0 +1,37 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Set Experience packet +/// +/// The experience bar value between 0 and 1 +/// The experience level +/// The total experience points +public sealed record SetExperiencePacket(float ExperienceBar, int Level, int TotalExperience) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_Experience; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteFloat(ExperienceBar); + buffer.WriteVarInt(Level); + buffer.WriteVarInt(TotalExperience); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var experienceBar = buffer.ReadFloat(); + var level = buffer.ReadVarInt(); + var totalExperience = buffer.ReadVarInt(); + + return new SetExperiencePacket(experienceBar, level, totalExperience); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetSimulationDistancePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetSimulationDistancePacket.cs new file mode 100644 index 00000000..4e2fd85e --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetSimulationDistancePacket.cs @@ -0,0 +1,30 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Set Simulation Distance packet +/// +/// The distance that the client will process specific things, such as entities. +public sealed record SetSimulationDistancePacket(int SimulationDistance) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_SimulationDistance; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(SimulationDistance); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var simulationDistance = buffer.ReadVarInt(); + return new SetSimulationDistancePacket(simulationDistance); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetSubtitleTextPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetSubtitleTextPacket.cs new file mode 100644 index 00000000..94d49e3f --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetSubtitleTextPacket.cs @@ -0,0 +1,31 @@ +using MineSharp.ChatComponent; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Packet sent by the server to set the subtitle text. +/// +/// The subtitle text to be displayed. +public sealed record SetSubtitleTextPacket(Chat SubtitleText) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_SetTitleSubtitle; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteChatComponent(SubtitleText); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var subtitleText = buffer.ReadChatComponent(); + return new SetSubtitleTextPacket(subtitleText); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetTabListHeaderFooterPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetTabListHeaderFooterPacket.cs new file mode 100644 index 00000000..af6c78af --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetTabListHeaderFooterPacket.cs @@ -0,0 +1,35 @@ +using MineSharp.ChatComponent; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Set Tab List Header And Footer packet +/// +/// The header text component +/// The footer text component +public sealed record SetTabListHeaderFooterPacket(Chat Header, Chat Footer) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_PlayerlistHeader; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteChatComponent(Header); + buffer.WriteChatComponent(Footer); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var header = buffer.ReadChatComponent(); + var footer = buffer.ReadChatComponent(); + + return new SetTabListHeaderFooterPacket(header, footer); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetTickingStatePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetTickingStatePacket.cs new file mode 100644 index 00000000..9230384c --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetTickingStatePacket.cs @@ -0,0 +1,34 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Packet used to adjust the ticking rate of the client, and whether it's frozen. +/// +/// The tick rate of the client +/// Whether the client is frozen +public sealed record SetTickingStatePacket(float TickRate, bool IsFrozen) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_SetTickingState; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteFloat(TickRate); + buffer.WriteBool(IsFrozen); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var tickRate = buffer.ReadFloat(); + var isFrozen = buffer.ReadBool(); + + return new SetTickingStatePacket(tickRate, isFrozen); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetTitleAnimationTimesPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetTitleAnimationTimesPacket.cs new file mode 100644 index 00000000..5d3ccaef --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetTitleAnimationTimesPacket.cs @@ -0,0 +1,37 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Packet sent by the server to set the title animation times. +/// +/// Ticks to spend fading in. +/// Ticks to keep the title displayed. +/// Ticks to spend fading out, not when to start fading out. +public sealed record SetTitleAnimationTimesPacket(int FadeIn, int Stay, int FadeOut) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_SetTitleTime; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteInt(FadeIn); + buffer.WriteInt(Stay); + buffer.WriteInt(FadeOut); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var fadeIn = buffer.ReadInt(); + var stay = buffer.ReadInt(); + var fadeOut = buffer.ReadInt(); + + return new SetTitleAnimationTimesPacket(fadeIn, stay, fadeOut); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetTitleTextPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetTitleTextPacket.cs new file mode 100644 index 00000000..281b3db9 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/SetTitleTextPacket.cs @@ -0,0 +1,31 @@ +using MineSharp.ChatComponent; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Packet sent by the server to set the title text in the client. +/// +/// The title text to be displayed +public sealed record SetTitleTextPacket(Chat TitleText) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_SetTitleText; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteChatComponent(TitleText); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var titleText = buffer.ReadChatComponent(); + return new SetTitleTextPacket(titleText); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/StartConfigurationPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/StartConfigurationPacket.cs new file mode 100644 index 00000000..78394dbb --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/StartConfigurationPacket.cs @@ -0,0 +1,30 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Sent during gameplay in order to redo the configuration process. +/// The client must respond with Acknowledge Configuration for the process to start. +/// +public sealed record StartConfigurationPacket() : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_StartConfiguration; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + // No fields to write + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + // No fields to read + return new StartConfigurationPacket(); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/StepTickPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/StepTickPacket.cs new file mode 100644 index 00000000..1c4e7c03 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/StepTickPacket.cs @@ -0,0 +1,30 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Advances the client processing by the specified number of ticks. Has no effect unless client ticking is frozen. +/// +/// The number of tick steps to advance +public sealed record StepTickPacket(int TickSteps) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_StepTick; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(TickSteps); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var tickSteps = buffer.ReadVarInt(); + return new StepTickPacket(tickSteps); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/StopSoundPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/StopSoundPacket.cs new file mode 100644 index 00000000..5fdadda7 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/StopSoundPacket.cs @@ -0,0 +1,76 @@ +using MineSharp.Core.Common; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using static MineSharp.Protocol.Packets.Clientbound.Play.StopSoundPacket; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Stop Sound packet +/// +/// Optional category of the sound. If not present, then sounds from all sources are cleared. +/// Optional sound effect name. If not present, then all sounds are cleared. +public sealed record StopSoundPacket(SoundCategory? Category, Identifier? Sound) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_StopSound; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + byte flags = 0; + flags |= (byte)(Category.HasValue ? 0x1 : 0); + flags |= (byte)(Sound != null ? 0x2 : 0); + + buffer.WriteByte(flags); + if (Category.HasValue) + { + buffer.WriteVarInt((int)Category.GetValueOrDefault()); + } + if (Sound != null) + { + buffer.WriteIdentifier(Sound); + } + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var flags = buffer.ReadByte(); + SoundCategory? category = null; + Identifier? sound = null; + + if ((flags & 0x1) != 0) + { + category = (SoundCategory)buffer.ReadVarInt(); + } + if ((flags & 0x2) != 0) + { + sound = buffer.ReadIdentifier(); + } + + return new StopSoundPacket(category, sound); + } + + /// + /// Enum representing sound categories + /// + public enum SoundCategory + { +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + Master = 0, + Music = 1, + Record = 2, + Weather = 3, + Block = 4, + Hostile = 5, + Neutral = 6, + Player = 7, + Ambient = 8, + Voice = 9 +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/TagQueryResponsePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/TagQueryResponsePacket.cs new file mode 100644 index 00000000..071b1221 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/TagQueryResponsePacket.cs @@ -0,0 +1,35 @@ +using fNbt; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Tag Query Response packet +/// +/// The transaction ID +/// The NBT of the block or entity +public sealed record TagQueryResponsePacket(int TransactionId, NbtTag? Nbt) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_NbtQueryResponse; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteVarInt(TransactionId); + buffer.WriteOptionalNbt(Nbt); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var transactionId = buffer.ReadVarInt(); + var nbt = buffer.ReadOptionalNbt(); + + return new TagQueryResponsePacket(transactionId, nbt); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateObjectivesPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateObjectivesPacket.cs new file mode 100644 index 00000000..b052d766 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateObjectivesPacket.cs @@ -0,0 +1,104 @@ +using MineSharp.ChatComponent; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using MineSharp.Protocol.Packets.NetworkTypes; +using static MineSharp.Protocol.Packets.Clientbound.Play.UpdateObjectivesPacket; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Update Objectives packet +/// +/// A unique name for the objective +/// The mode of the objective update +/// The text to be displayed for the score +/// The type of the objective +/// The number format for the score +public sealed record UpdateObjectivesPacket( + string ObjectiveName, + ObjectiveMode Mode, + Chat? ObjectiveValue, + // this field can not be named "Type" or "ObjectiveType" + ObjectiveType? ObjectiveTypeValue, + IScoreboardNumberFormat? NumberFormat +) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_ScoreboardObjective; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteString(ObjectiveName); + buffer.WriteByte((byte)Mode); + + if (Mode == ObjectiveMode.Create || Mode == ObjectiveMode.Update) + { + buffer.WriteChatComponent(ObjectiveValue ?? throw new InvalidOperationException($"{nameof(ObjectiveValue)} is required if Mode is Create or Update")); + buffer.WriteVarInt((int)(ObjectiveTypeValue ?? throw new InvalidOperationException($"{nameof(ObjectiveTypeValue)} is required if Mode is Create or Update"))); + var hasNumberFormat = NumberFormat != null; + buffer.WriteBool(hasNumberFormat); + + if (hasNumberFormat) + { + buffer.WriteVarInt((int)NumberFormat!.Type); + NumberFormat!.Write(buffer); + } + } + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var objectiveName = buffer.ReadString(); + var mode = (ObjectiveMode)buffer.ReadByte(); + Chat? objectiveValue = null; + ObjectiveType? objectiveType = null; + IScoreboardNumberFormat? numberFormat = null; + + if (mode == ObjectiveMode.Create || mode == ObjectiveMode.Update) + { + objectiveValue = buffer.ReadChatComponent(); + objectiveType = (ObjectiveType)buffer.ReadVarInt(); + var hasNumberFormat = buffer.ReadBool(); + + if (hasNumberFormat) + { + var type = (ScoreboardNumberFormatType)buffer.ReadVarInt(); + numberFormat = ScoreboardNumberFormatRegistry.Read(buffer, type); + } + } + + return new UpdateObjectivesPacket( + objectiveName, + mode, + objectiveValue, + objectiveType, + numberFormat + ); + } + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + /// + /// Objective mode enumeration + /// + public enum ObjectiveMode : byte + { + Create = 0, + Remove = 1, + Update = 2 + } + + /// + /// Objective type enumeration + /// + public enum ObjectiveType : int + { + Integer = 0, + Hearts = 1 + } +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateScorePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateScorePacket.cs new file mode 100644 index 00000000..791290bd --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateScorePacket.cs @@ -0,0 +1,83 @@ +using MineSharp.ChatComponent; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using MineSharp.Protocol.Packets.NetworkTypes; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Update Score packet +/// +/// The entity whose score this is. For players, this is their username; for other entities, it is their UUID. +/// The name of the objective the score belongs to +/// The score to be displayed next to the entry +/// The custom display name +/// The number format for the score +public sealed record UpdateScorePacket( + string EntityName, + string ObjectiveName, + int Value, + Chat? DisplayName, + IScoreboardNumberFormat? NumberFormat +) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_ScoreboardScore; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteString(EntityName); + buffer.WriteString(ObjectiveName); + buffer.WriteVarInt(Value); + var hasDisplayName = DisplayName != null; + buffer.WriteBool(hasDisplayName); + + if (hasDisplayName) + { + buffer.WriteChatComponent(DisplayName!); + } + + var hasNumberFormat = NumberFormat != null; + buffer.WriteBool(hasNumberFormat); + + if (hasNumberFormat) + { + buffer.WriteVarInt((int)NumberFormat!.Type); + NumberFormat!.Write(buffer); + } + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var entityName = buffer.ReadString(); + var objectiveName = buffer.ReadString(); + var value = buffer.ReadVarInt(); + var hasDisplayName = buffer.ReadBool(); + Chat? displayName = null; + if (hasDisplayName) + { + displayName = buffer.ReadChatComponent(); + } + + var hasNumberFormat = buffer.ReadBool(); + IScoreboardNumberFormat? numberFormat = null; + if (hasNumberFormat) + { + var type = (ScoreboardNumberFormatType)buffer.ReadVarInt(); + numberFormat = ScoreboardNumberFormatRegistry.Read(buffer, type); + } + + return new UpdateScorePacket( + entityName, + objectiveName, + value, + displayName, + numberFormat + ); + } +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateTeamsPacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateTeamsPacket.cs new file mode 100644 index 00000000..dc702a84 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateTeamsPacket.cs @@ -0,0 +1,361 @@ +using System.Collections.Frozen; +using MineSharp.ChatComponent; +using MineSharp.Core.Common; +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; +using static MineSharp.Protocol.Packets.Clientbound.Play.UpdateTeamsPacket; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Update Teams packet +/// +/// A unique name for the team +/// The data for the method type of this packet +public sealed record UpdateTeamsPacket(string TeamName, IUpdateTeamsMethod MethodData) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_Teams; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteString(TeamName); + buffer.WriteByte((byte)MethodData.MethodType); + MethodData.Write(buffer); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var teamName = buffer.ReadString(); + var method = (UpdateTeamsMethodType)buffer.ReadByte(); + var methodData = UpdateTeamsMethodRegistry.Read(buffer, method); + return new UpdateTeamsPacket(teamName, methodData); + } + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + public enum UpdateTeamsMethodType + { + CreateTeam = 0, + RemoveTeam = 1, + UpdateTeamInfo = 2, + AddEntitiesToTeam = 3, + RemoveEntitiesFromTeam = 4 + } + + public interface IUpdateTeamsMethod + { + public UpdateTeamsMethodType MethodType { get; } + + public void Write(PacketBuffer buffer); + } + + public interface IUpdateTeamsMethodStatic + { + public static abstract UpdateTeamsMethodType StaticMethodType { get; } + + public static abstract IUpdateTeamsMethod Read(PacketBuffer buffer); + } + + public static class UpdateTeamsMethodRegistry + { + public static IUpdateTeamsMethod Read(PacketBuffer buffer, UpdateTeamsMethodType method) + { + if (!UpdateTeamsMethodFactories.TryGetValue(method, out var reader)) + { + throw new InvalidOperationException($"Unsupported UpdateTeamsMethodType: {method}"); + } + return reader(buffer); + } + + public static readonly FrozenDictionary> UpdateTeamsMethodFactories; + + static UpdateTeamsMethodRegistry() + { + UpdateTeamsMethodFactories = InitializeUpdateTeamsMethod(); + } + + private static FrozenDictionary> InitializeUpdateTeamsMethod() + { + var dict = new Dictionary>(); + + void Register() + where T : IUpdateTeamsMethod, IUpdateTeamsMethodStatic + { + var mask = T.StaticMethodType; + var factory = T.Read; + dict.Add(mask, factory); + } + + Register(); + Register(); + Register(); + Register(); + Register(); + + return dict.ToFrozenDictionary(); + } + } + + #region Parts + + /// + /// Marker interface for the parts of the UpdateTeams packet. + /// + public interface IUpdateTeamsPart + { + } + + public sealed record UpdateTeamsTeamInfoPart( + Chat TeamDisplayName, + byte FriendlyFlags, + NameTagVisibility NameTagVisibility, + CollisionRule CollisionRule, + TextColor TeamColor, + Chat TeamPrefix, + Chat TeamSuffix + ) : IUpdateTeamsPart, ISerializable + { + public void Write(PacketBuffer buffer) + { + buffer.WriteChatComponent(TeamDisplayName); + buffer.WriteByte(FriendlyFlags); + buffer.WriteString(NameTagVisibilityExtensions.ToUpdateTeamPacketString(NameTagVisibility)); + buffer.WriteString(CollisionRuleExtensions.ToUpdateTeamPacketString(CollisionRule)); + buffer.WriteVarInt((int)TeamColor); + buffer.WriteChatComponent(TeamPrefix); + buffer.WriteChatComponent(TeamSuffix); + } + + public static UpdateTeamsTeamInfoPart Read(PacketBuffer buffer) + { + var teamDisplayName = buffer.ReadChatComponent(); + var friendlyFlags = buffer.ReadByte(); + var nameTagVisibility = NameTagVisibilityExtensions.FromUpdateTeamPacketString(buffer.ReadString()); + var collisionRule = CollisionRuleExtensions.FromUpdateTeamPacketString(buffer.ReadString()); + var teamColor = (TextColor)buffer.ReadVarInt(); + var teamPrefix = buffer.ReadChatComponent(); + var teamSuffix = buffer.ReadChatComponent(); + return new UpdateTeamsTeamInfoPart(teamDisplayName, friendlyFlags, nameTagVisibility, collisionRule, teamColor, teamPrefix, teamSuffix); + } + } + + /// Identifiers entities. For players, this is their username; for other entities, it is their UUID. + public sealed record UpdateTeamsEntityInfoPart( + string[] Entities + ) : IUpdateTeamsPart, ISerializable + { + public void Write(PacketBuffer buffer) + { + buffer.WriteVarIntArray(Entities, (buffer, entity) => buffer.WriteString(entity)); + } + + public static UpdateTeamsEntityInfoPart Read(PacketBuffer buffer) + { + var entities = buffer.ReadVarIntArray((buffer) => buffer.ReadString()); + return new UpdateTeamsEntityInfoPart(entities); + } + } + + /// + /// Enum representing the visibility options for name tags in Minecraft. + /// + public enum NameTagVisibility + { + Always, + HideForOtherTeams, + HideForOwnTeam, + Never + } + + public static class NameTagVisibilityExtensions + { + private static readonly FrozenDictionary EnumToString = new Dictionary() + { + { NameTagVisibility.Always, "always" }, + { NameTagVisibility.HideForOtherTeams, "hideForOtherTeams" }, + { NameTagVisibility.HideForOwnTeam, "hideForOwnTeam" }, + { NameTagVisibility.Never, "never" } + }.ToFrozenDictionary(); + + private static readonly FrozenDictionary StringToEnum = EnumToString + .ToDictionary(kvp => kvp.Value, kvp => kvp.Key).ToFrozenDictionary(); + + // can't be an extension method because this class is not top level + public static string ToUpdateTeamPacketString(NameTagVisibility visibility) + { + return EnumToString[visibility]; + } + + public static NameTagVisibility FromUpdateTeamPacketString(string visibility) + { + if (StringToEnum.TryGetValue(visibility, out var enumValue)) + { + return enumValue; + } + throw new ArgumentException($"Invalid visibility string: {visibility}", nameof(visibility)); + } + } + + /// + /// Enum representing the collision rules in Minecraft. + /// + public enum CollisionRule + { + Always, + PushOtherTeams, + PushOwnTeam, + Never + } + + public static class CollisionRuleExtensions + { + private static readonly FrozenDictionary EnumToString = new Dictionary() + { + { CollisionRule.Always, "always" }, + { CollisionRule.PushOtherTeams, "pushOtherTeams" }, + { CollisionRule.PushOwnTeam, "pushOwnTeam" }, + { CollisionRule.Never, "never" } + }.ToFrozenDictionary(); + + private static readonly FrozenDictionary StringToEnum = EnumToString + .ToDictionary(kvp => kvp.Value, kvp => kvp.Key).ToFrozenDictionary(); + + // can't be an extension method because this class is not top level + public static string ToUpdateTeamPacketString(CollisionRule rule) + { + return EnumToString[rule]; + } + + public static CollisionRule FromUpdateTeamPacketString(string rule) + { + if (StringToEnum.TryGetValue(rule, out var enumValue)) + { + return enumValue; + } + throw new ArgumentException($"Invalid collision rule string: {rule}", nameof(rule)); + } + } + + #endregion + + public sealed record CreateTeam( + UpdateTeamsTeamInfoPart TeamInfoPart, + UpdateTeamsEntityInfoPart EntityInfoPart + ) : IUpdateTeamsMethod, IUpdateTeamsMethodStatic, ISerializable + { + public UpdateTeamsMethodType MethodType => StaticMethodType; + public static UpdateTeamsMethodType StaticMethodType => UpdateTeamsMethodType.CreateTeam; + + public void Write(PacketBuffer buffer) + { + TeamInfoPart.Write(buffer); + EntityInfoPart.Write(buffer); + } + + public static CreateTeam Read(PacketBuffer buffer) + { + var teamInfoPart = UpdateTeamsTeamInfoPart.Read(buffer); + var entityInfoPart = UpdateTeamsEntityInfoPart.Read(buffer); + return new(teamInfoPart, entityInfoPart); + } + + static IUpdateTeamsMethod IUpdateTeamsMethodStatic.Read(PacketBuffer buffer) + { + return Read(buffer); + } + } + + public sealed record RemoveTeam() + : IUpdateTeamsMethod, IUpdateTeamsMethodStatic, ISerializable + { + public UpdateTeamsMethodType MethodType => StaticMethodType; + public static UpdateTeamsMethodType StaticMethodType => UpdateTeamsMethodType.RemoveTeam; + + public void Write(PacketBuffer buffer) { } + + public static RemoveTeam Read(PacketBuffer buffer) => new(); + + static IUpdateTeamsMethod IUpdateTeamsMethodStatic.Read(PacketBuffer buffer) + { + return Read(buffer); + } + } + + public sealed record UpdateTeamInfo( + UpdateTeamsTeamInfoPart TeamInfoPart + ) : IUpdateTeamsMethod, IUpdateTeamsMethodStatic, ISerializable + { + public UpdateTeamsMethodType MethodType => StaticMethodType; + public static UpdateTeamsMethodType StaticMethodType => UpdateTeamsMethodType.UpdateTeamInfo; + + public void Write(PacketBuffer buffer) + { + TeamInfoPart.Write(buffer); + } + + public static UpdateTeamInfo Read(PacketBuffer buffer) + { + var teamInfoPart = UpdateTeamsTeamInfoPart.Read(buffer); + return new(teamInfoPart); + } + + static IUpdateTeamsMethod IUpdateTeamsMethodStatic.Read(PacketBuffer buffer) + { + return Read(buffer); + } + } + + public sealed record AddEntitiesToTeam( + UpdateTeamsEntityInfoPart EntityInfoPart + ) : IUpdateTeamsMethod, IUpdateTeamsMethodStatic, ISerializable + { + public UpdateTeamsMethodType MethodType => StaticMethodType; + public static UpdateTeamsMethodType StaticMethodType => UpdateTeamsMethodType.AddEntitiesToTeam; + + public void Write(PacketBuffer buffer) + { + EntityInfoPart.Write(buffer); + } + + public static AddEntitiesToTeam Read(PacketBuffer buffer) + { + var entityInfoPart = UpdateTeamsEntityInfoPart.Read(buffer); + return new(entityInfoPart); + } + + static IUpdateTeamsMethod IUpdateTeamsMethodStatic.Read(PacketBuffer buffer) + { + return Read(buffer); + } + } + + public sealed record RemoveEntitiesFromTeam( + UpdateTeamsEntityInfoPart EntityInfoPart + ) : IUpdateTeamsMethod, IUpdateTeamsMethodStatic, ISerializable + { + public UpdateTeamsMethodType MethodType => StaticMethodType; + public static UpdateTeamsMethodType StaticMethodType => UpdateTeamsMethodType.RemoveEntitiesFromTeam; + + public void Write(PacketBuffer buffer) + { + EntityInfoPart.Write(buffer); + } + + public static RemoveEntitiesFromTeam Read(PacketBuffer buffer) + { + var entityInfoPart = UpdateTeamsEntityInfoPart.Read(buffer); + return new(entityInfoPart); + } + + static IUpdateTeamsMethod IUpdateTeamsMethodStatic.Read(PacketBuffer buffer) + { + return Read(buffer); + } + } +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member +} diff --git a/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateTimePacket.cs b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateTimePacket.cs new file mode 100644 index 00000000..30d253eb --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/Clientbound/Play/UpdateTimePacket.cs @@ -0,0 +1,38 @@ +using MineSharp.Core.Serialization; +using MineSharp.Data; +using MineSharp.Data.Protocol; + +namespace MineSharp.Protocol.Packets.Clientbound.Play; + +/// +/// Update Time packet +/// +/// Time is based on ticks, where 20 ticks happen every second. There are 24000 ticks in a day, making Minecraft days exactly 20 minutes long. +/// The time of day is based on the timestamp modulo 24000. 0 is sunrise, 6000 is noon, 12000 is sunset, and 18000 is midnight. +/// The default SMP server increments the time by 20 every second. +/// +/// The world age in ticks +/// The time of day in ticks +public sealed record UpdateTimePacket(long WorldAge, long TimeOfDay) : IPacket +{ + /// + public PacketType Type => StaticType; + /// + public static PacketType StaticType => PacketType.CB_Play_UpdateTime; + + /// + public void Write(PacketBuffer buffer, MinecraftData version) + { + buffer.WriteLong(WorldAge); + buffer.WriteLong(TimeOfDay); + } + + /// + public static IPacket Read(PacketBuffer buffer, MinecraftData version) + { + var worldAge = buffer.ReadLong(); + var timeOfDay = buffer.ReadLong(); + + return new UpdateTimePacket(worldAge, timeOfDay); + } +} diff --git a/Components/MineSharp.Protocol/Packets/NetworkTypes/EntityMetadata.cs b/Components/MineSharp.Protocol/Packets/NetworkTypes/EntityMetadata.cs index fd8bfe0e..5d270a49 100644 --- a/Components/MineSharp.Protocol/Packets/NetworkTypes/EntityMetadata.cs +++ b/Components/MineSharp.Protocol/Packets/NetworkTypes/EntityMetadata.cs @@ -3,6 +3,7 @@ using fNbt; using MineSharp.ChatComponent; using MineSharp.Core.Common; +using MineSharp.Core.Common.Items; using MineSharp.Core.Geometry; using MineSharp.Core.Serialization; using MineSharp.Data; @@ -195,10 +196,10 @@ public static OptionalTextComponentMetadata Read(PacketBuffer buffer, MinecraftD } } -public sealed record SlotMetadata(Slot Value) : IMetadataValue, ISerializableWithMinecraftData +public sealed record SlotMetadata(Item? Value) : IMetadataValue, ISerializableWithMinecraftData { - public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteSlot(Value); - public static SlotMetadata Read(PacketBuffer buffer, MinecraftData data) => new(buffer.ReadSlot(data)); + public void Write(PacketBuffer buffer, MinecraftData data) => buffer.WriteOptionalItem(Value); + public static SlotMetadata Read(PacketBuffer buffer, MinecraftData data) => new(buffer.ReadOptionalItem(data)); } public sealed record BooleanMetadata(bool Value) : IMetadataValue, ISerializableWithMinecraftData diff --git a/Components/MineSharp.Protocol/Packets/NetworkTypes/ScoreboardNumberFormat.cs b/Components/MineSharp.Protocol/Packets/NetworkTypes/ScoreboardNumberFormat.cs new file mode 100644 index 00000000..ad8f8ed7 --- /dev/null +++ b/Components/MineSharp.Protocol/Packets/NetworkTypes/ScoreboardNumberFormat.cs @@ -0,0 +1,152 @@ +using System.Collections.Frozen; +using fNbt; +using MineSharp.ChatComponent; +using MineSharp.Core.Serialization; + +namespace MineSharp.Protocol.Packets.NetworkTypes; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +/// +/// Scoreboard number format type enumeration +/// +public enum ScoreboardNumberFormatType +{ + Blank = 0, + Styled = 1, + Fixed = 2 +} + +public interface IScoreboardNumberFormat +{ + public ScoreboardNumberFormatType Type { get; } + + public void Write(PacketBuffer buffer); +} + +public interface IScoreboardNumberFormatStatic +{ + public static abstract ScoreboardNumberFormatType StaticType { get; } + + public static abstract IScoreboardNumberFormat Read(PacketBuffer buffer); +} + +public static class ScoreboardNumberFormatRegistry +{ + public static IScoreboardNumberFormat Read(PacketBuffer buffer, ScoreboardNumberFormatType type) + { + if (!ScoreboardNumberFormatFactories.TryGetValue(type, out var reader)) + { + throw new InvalidOperationException($"Unsupported UpdateTeamsMethodType: {type}"); + } + return reader(buffer); + } + + public static readonly FrozenDictionary> ScoreboardNumberFormatFactories; + + static ScoreboardNumberFormatRegistry() + { + ScoreboardNumberFormatFactories = InitializeUpdateTeamsMethod(); + } + + private static FrozenDictionary> InitializeUpdateTeamsMethod() + { + var dict = new Dictionary>(); + + void Register() + where T : IScoreboardNumberFormat, IScoreboardNumberFormatStatic + { + var mask = T.StaticType; + var factory = T.Read; + dict.Add(mask, factory); + } + + Register(); + Register(); + Register(); + + return dict.ToFrozenDictionary(); + } +} +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + +/// +/// Blank number format +/// +public sealed record BlankNumberFormat() : IScoreboardNumberFormat, IScoreboardNumberFormatStatic, ISerializable +{ + /// + public ScoreboardNumberFormatType Type => StaticType; + /// + public static ScoreboardNumberFormatType StaticType => ScoreboardNumberFormatType.Blank; + + /// + public void Write(PacketBuffer buffer) { } + + /// + public static BlankNumberFormat Read(PacketBuffer buffer) => new(); + + static IScoreboardNumberFormat IScoreboardNumberFormatStatic.Read(PacketBuffer buffer) + { + return Read(buffer); + } +} + +/// +/// Styled number format +/// +/// The styling to be used when formatting the score number +public sealed record StyledNumberFormat(NbtCompound Styling) : IScoreboardNumberFormat, IScoreboardNumberFormatStatic, ISerializable +{ + /// + public ScoreboardNumberFormatType Type => StaticType; + /// + public static ScoreboardNumberFormatType StaticType => ScoreboardNumberFormatType.Blank; + + /// + public void Write(PacketBuffer buffer) + { + buffer.WriteNbt(Styling); + } + + /// + public static StyledNumberFormat Read(PacketBuffer buffer) + { + var styling = buffer.ReadNbtCompound(); + return new(styling); + } + + static IScoreboardNumberFormat IScoreboardNumberFormatStatic.Read(PacketBuffer buffer) + { + return Read(buffer); + } +} + +/// +/// Fixed number format +/// +/// The text to be used as placeholder +public sealed record FixedNumberFormat(Chat Content) : IScoreboardNumberFormat, IScoreboardNumberFormatStatic, ISerializable +{ + /// + public ScoreboardNumberFormatType Type => StaticType; + /// + public static ScoreboardNumberFormatType StaticType => ScoreboardNumberFormatType.Blank; + + /// + public void Write(PacketBuffer buffer) + { + buffer.WriteChatComponent(Content); + } + + /// + public static FixedNumberFormat Read(PacketBuffer buffer) + { + var content = buffer.ReadChatComponent(); + return new(content); + } + + static IScoreboardNumberFormat IScoreboardNumberFormatStatic.Read(PacketBuffer buffer) + { + return Read(buffer); + } +} diff --git a/Components/MineSharp.Protocol/Packets/PacketPalette.cs b/Components/MineSharp.Protocol/Packets/PacketPalette.cs index d78d408e..2de2b3d4 100644 --- a/Components/MineSharp.Protocol/Packets/PacketPalette.cs +++ b/Components/MineSharp.Protocol/Packets/PacketPalette.cs @@ -214,6 +214,23 @@ void RegisterPacket() RegisterPacket(); RegisterPacket(); RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); + RegisterPacket(); RegisterPacket(); RegisterPacket(); diff --git a/MineSharp.Core/Common/TextColor.cs b/MineSharp.Core/Common/TextColor.cs new file mode 100644 index 00000000..6da6a1ba --- /dev/null +++ b/MineSharp.Core/Common/TextColor.cs @@ -0,0 +1,35 @@ +namespace MineSharp.Core.Common; + +// TODO: use this enum in more places like Chat +// and add extension methods that convert it to and from the §0-9a-fk-r format + +/// +/// Enum representing the various text colors (and stylings) available in Minecraft. +/// +public enum TextColor +{ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + Black = 0, + DarkBlue = 1, + DarkGreen = 2, + DarkAqua = 3, + DarkRed = 4, + DarkPurple = 5, + Gold = 6, + Gray = 7, + DarkGray = 8, + Blue = 9, + Green = 10, + Aqua = 11, + Red = 12, + LightPurple = 13, + Yellow = 14, + White = 15, + Obfuscated = 16, + Bold = 17, + Strikethrough = 18, + Underlined = 19, + Italic = 20, + Reset = 21 +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member +} From 1249d37a04480022994276e338c0809390156403 Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 14 Aug 2024 23:42:06 +0200 Subject: [PATCH 71/73] fix exception from StatusResponsePacket handler in RequestServerStatus --- Components/MineSharp.Protocol/MinecraftClient.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index 35960a2e..9f41733a 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -750,8 +750,8 @@ public static async Task RequestServerStatus( // the server closes the connection // after sending the StatusResponsePacket - await client.Disconnect(); - client.Dispose(); + // so just dispose the client (no point in disconnecting) + await client.DisposeAsync(); }); await client.SendPacket(new StatusRequestPacket(), responseTimeoutCancellationToken); From 52fd5bcba0debe5e1ad3bed5903459b0a4236eba Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Wed, 14 Aug 2024 23:47:54 +0200 Subject: [PATCH 72/73] removed now unused method HandleOutgoing in GameStatePacketHandler --- Components/MineSharp.Protocol/MinecraftClient.cs | 16 ---------------- .../Packets/Handlers/GameStatePacketHandler.cs | 5 ----- .../Packets/Handlers/HandshakePacketHandler.cs | 10 ---------- 3 files changed, 31 deletions(-) diff --git a/Components/MineSharp.Protocol/MinecraftClient.cs b/Components/MineSharp.Protocol/MinecraftClient.cs index 9f41733a..61568fff 100644 --- a/Components/MineSharp.Protocol/MinecraftClient.cs +++ b/Components/MineSharp.Protocol/MinecraftClient.cs @@ -537,10 +537,6 @@ private async Task SendPackets() // TrySetResult must be run from a different task to prevent blocking the stream loop // because the task continuation will be executed inline and might block or cause a deadlock _ = Task.Run(task.Task.TrySetResult); - - // TODO: this feels wrong - // we probably should ask outgoing packet listeners before sending the packet - await HandleOutgoingPacket(task.Packet); } catch (SocketException e) { @@ -696,18 +692,6 @@ private async Task HandleIncomingPacket(PacketType packetType, PacketBuffer buff } } - private async Task HandleOutgoingPacket(IPacket packet) - { - try - { - await gameStatePacketHandler.HandleOutgoing(packet); - } - catch (Exception e) - { - Logger.Error(e, $"error in outgoing packet handler. Packet={packet.Type}"); - } - } - /// /// Requests the server status and closes the connection. /// Works only when is . diff --git a/Components/MineSharp.Protocol/Packets/Handlers/GameStatePacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/GameStatePacketHandler.cs index 040a0140..d23c5d0c 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/GameStatePacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/GameStatePacketHandler.cs @@ -17,10 +17,5 @@ public virtual Task StateEntered() return Task.CompletedTask; } public abstract Task HandleIncoming(IPacket packet); - // normally this is not required - public virtual Task HandleOutgoing(IPacket packet) - { - return Task.CompletedTask; - } public abstract bool HandlesIncoming(PacketType type); } diff --git a/Components/MineSharp.Protocol/Packets/Handlers/HandshakePacketHandler.cs b/Components/MineSharp.Protocol/Packets/Handlers/HandshakePacketHandler.cs index 84823267..b0dfc443 100644 --- a/Components/MineSharp.Protocol/Packets/Handlers/HandshakePacketHandler.cs +++ b/Components/MineSharp.Protocol/Packets/Handlers/HandshakePacketHandler.cs @@ -1,6 +1,5 @@ using MineSharp.Core.Common.Protocol; using MineSharp.Data.Protocol; -using MineSharp.Protocol.Exceptions; namespace MineSharp.Protocol.Packets.Handlers; @@ -19,15 +18,6 @@ public override Task HandleIncoming(IPacket packet) return Task.CompletedTask; } - public override Task HandleOutgoing(IPacket packet) - { - return packet switch - { - _ => throw new UnexpectedPacketException( - $"unexpected outgoing packet during handshaking: {packet.GetType().FullName}") - }; - } - public override bool HandlesIncoming(PacketType type) { return false; From f09627a1d3e58622abc1909dcc546ad5fd1e4cfd Mon Sep 17 00:00:00 2001 From: Klotzi111 Date: Thu, 15 Aug 2024 00:17:03 +0200 Subject: [PATCH 73/73] fixed wrong player health upon joining --- MineSharp.Bot/Plugins/PlayerPlugin.cs | 21 +++++++++++++-------- MineSharp.Bot/Plugins/Plugin.cs | 6 ++++++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/MineSharp.Bot/Plugins/PlayerPlugin.cs b/MineSharp.Bot/Plugins/PlayerPlugin.cs index 95c1bfc2..2a3181f0 100644 --- a/MineSharp.Bot/Plugins/PlayerPlugin.cs +++ b/MineSharp.Bot/Plugins/PlayerPlugin.cs @@ -15,7 +15,7 @@ namespace MineSharp.Bot.Plugins; /// -/// This Plugins provides basic functionality for the minecraft player. +/// This Plugins provides basic functionality for the Minecraft player. /// It keeps track of things like Health and initializes the Bot entity, /// which is required for many other plugins. /// @@ -25,6 +25,7 @@ public class PlayerPlugin : Plugin private readonly Task initLoginPacket; private readonly Task initPositionPacket; + private readonly Task initHealthPacket; private EntityPlugin? entities; private PhysicsPlugin? physics; @@ -51,6 +52,7 @@ public PlayerPlugin(MineSharpBot bot) : base(bot) // already start listening to the packets here, as they sometimes get lost when calling in init() initLoginPacket = Bot.Client.WaitForPacket(); initPositionPacket = Bot.Client.WaitForPacket(); + initHealthPacket = Bot.Client.WaitForPacket(); } /// @@ -180,17 +182,20 @@ protected override async Task Init() entity, ParseDimension(loginPacket.DimensionType)); - PlayerMap.TryAdd(entity.ServerId, Self); - - Health = loginPacket.HasDeathLocation ? 0f : 20.0f; - Food = 20.0f; - Saturation = 20.0f; DimensionName = loginPacket.DimensionName; + var healthPacket = await initHealthPacket.WaitAsync(Bot.CancellationToken); + + Health = healthPacket.Health; + Food = healthPacket.Food; + Saturation = healthPacket.Saturation; + Logger.Info( - "Initialized Bot Entity: Position=({Position}), GameMode={GameMode}, Dimension={DimensionName} ({Dimension}).", Entity!.Position, Self.GameMode, DimensionName, Self!.Dimension); + "Initialized Bot Entity: Position=({Position}), GameMode={GameMode}, Health={Health}, Dimension={DimensionName} ({Dimension}).", Entity!.Position, Self.GameMode, Health, DimensionName, Self!.Dimension); + + PlayerMap.TryAdd(entity.ServerId, Self); - if (!loginPacket.HasDeathLocation) + if (Health > 0) { await Bot.Client.SendPacket( new SetPlayerPositionAndRotationPacket( diff --git a/MineSharp.Bot/Plugins/Plugin.cs b/MineSharp.Bot/Plugins/Plugin.cs index b8e6d105..17411d51 100644 --- a/MineSharp.Bot/Plugins/Plugin.cs +++ b/MineSharp.Bot/Plugins/Plugin.cs @@ -158,6 +158,12 @@ internal async Task Initialize() Logger.Info("Plugin loaded: {PluginName}", GetType().Name); } + catch (OperationCanceledException e) + { + Logger.Error(e, "Plugin {PluginName} was cancelled during Init()", GetType().Name); + initializationTask.TrySetCanceled(e.CancellationToken); + throw; + } catch (Exception e) { Logger.Error(e, "Plugin {PluginName} threw an exception during Init(). Aborting", GetType().Name);