diff --git a/Obsidian/Net/MinecraftStream.Writing.cs b/Obsidian/Net/MinecraftStream.Writing.cs index 11a4a6223..9670de5e5 100644 --- a/Obsidian/Net/MinecraftStream.Writing.cs +++ b/Obsidian/Net/MinecraftStream.Writing.cs @@ -1194,4 +1194,28 @@ public void WriteParticleData(ParticleData value) break; } } + + [WriteMethod] + public void WriteMatchItem(MatchItem matchItem) + { + WriteString(matchItem.Match); + WriteBoolean(matchItem.HasTooltip); + if (matchItem.HasTooltip && matchItem.Tooltip is not null) WriteChat(matchItem.Tooltip); + } + + [WriteMethod] + public async void WriteTrade(Trade trade) + { + await WriteSlotAsync(trade.InputItem1); + await WriteSlotAsync(trade.OutputItem); + WriteBoolean(trade.HasSecondItem); + if (trade.HasSecondItem && trade.InputItem2 is not null) await WriteSlotAsync(trade.InputItem2); + WriteBoolean(trade.TradeDisabled); + WriteInt(trade.NumberOfTradeUses); + WriteInt(trade.MaximumNumberOfTradeUses); + WriteInt(trade.Xp); + WriteInt(trade.SpecialPrice); + WriteFloat(trade.PriceMultiplier); + WriteInt(trade.Demand); + } } diff --git a/Obsidian/Net/Packets/Login/LoginPluginRequest.cs b/Obsidian/Net/Packets/Login/LoginPluginRequest.cs new file mode 100644 index 000000000..39bd5cb24 --- /dev/null +++ b/Obsidian/Net/Packets/Login/LoginPluginRequest.cs @@ -0,0 +1,18 @@ +using Obsidian.Serialization.Attributes; + +namespace Obsidian.Net.Packets.Login; + +public partial class LoginPluginRequest : IClientboundPacket +{ + [Field(0), VarLength] + public int MessageId { get; set; } + + [Field(1)] + public string Channel { get; set; } + + [Field(2)] + public byte[] Data { get; set; } + + public int Id => 0x04; + +} diff --git a/Obsidian/Net/Packets/Login/LoginPluginResponse.cs b/Obsidian/Net/Packets/Login/LoginPluginResponse.cs new file mode 100644 index 000000000..32713e36e --- /dev/null +++ b/Obsidian/Net/Packets/Login/LoginPluginResponse.cs @@ -0,0 +1,20 @@ +using Obsidian.Entities; +using Obsidian.Serialization.Attributes; + +namespace Obsidian.Net.Packets.Login; + +public partial class LoginPluginResponse : IServerboundPacket +{ + [Field(0), VarLength] + public int MessageId { get; set; } + + [Field(1)] + public bool Successful { get; set; } + + [Field(2)] + public byte[] Data { get; set; } + + public int Id => 0x04; + + public ValueTask HandleAsync(Server server, Player player) => ValueTask.CompletedTask; +} diff --git a/Obsidian/Net/Packets/Play/Clientbound/MatchItem.cs b/Obsidian/Net/Packets/Play/Clientbound/MatchItem.cs new file mode 100644 index 000000000..4659a631a --- /dev/null +++ b/Obsidian/Net/Packets/Play/Clientbound/MatchItem.cs @@ -0,0 +1,15 @@ +namespace Obsidian.Net.Packets.Play.Clientbound; + +public class MatchItem +{ + public MatchItem(string match, bool hasTooltip, ChatMessage? tooltip = null) + { + Match = match; + HasTooltip = hasTooltip; + Tooltip = tooltip; + } + + public string Match { get; init; } + public bool HasTooltip { get; init; } + public ChatMessage? Tooltip { get; init; } +} diff --git a/Obsidian/Net/Packets/Play/Clientbound/TabCompleteResponse.cs b/Obsidian/Net/Packets/Play/Clientbound/TabCompleteResponse.cs new file mode 100644 index 000000000..bcfa60d5d --- /dev/null +++ b/Obsidian/Net/Packets/Play/Clientbound/TabCompleteResponse.cs @@ -0,0 +1,33 @@ +using Obsidian.Serialization.Attributes; + +namespace Obsidian.Net.Packets.Play.Clientbound; + +public partial class TabCompleteResponse : IClientboundPacket +{ + public TabCompleteResponse(int transactionId, int start, int length, int count, List matches) + { + TransactionId = transactionId; + Start = start; + Length = length; + Count = count; + Matches = matches; + } + + [Field(0), VarLength] + public int TransactionId { get; init; } + + [Field(1), VarLength] + public int Start { get; init; } + + [Field(2), VarLength] + public int Length { get; init; } + + [Field(3), VarLength] + public int Count { get; init; } + + [Field(4)] + public List Matches { get; init; } + + public int Id => 0x11; + +} diff --git a/Obsidian/Net/Packets/Play/Clientbound/Trade.cs b/Obsidian/Net/Packets/Play/Clientbound/Trade.cs new file mode 100644 index 000000000..16843a8dd --- /dev/null +++ b/Obsidian/Net/Packets/Play/Clientbound/Trade.cs @@ -0,0 +1,42 @@ +namespace Obsidian.Net.Packets.Play.Clientbound; + +public class Trade +{ + public Trade(ItemStack inputItem1, ItemStack outputItem, bool hasSecondItem, ItemStack inputItem2, bool tradeDisabled, int numberOfTradeUses, int maximumNumberOfTradeUses, int xp, int specialPrice, float priceMultiplier, int demand) : base() + { + InputItem1 = inputItem1; + OutputItem = outputItem; + HasSecondItem = hasSecondItem; + InputItem2 = inputItem2; + TradeDisabled = tradeDisabled; + NumberOfTradeUses = numberOfTradeUses; + MaximumNumberOfTradeUses = maximumNumberOfTradeUses; + Xp = xp; + SpecialPrice = specialPrice; + PriceMultiplier = priceMultiplier; + Demand = demand; + } + + public ItemStack InputItem1 { get; init; } + + public ItemStack OutputItem { get; init; } + + public bool HasSecondItem { get; init; } + + public ItemStack InputItem2 { get; init; } + + public bool TradeDisabled { get; init; } + + public int NumberOfTradeUses { get; init; } + + public int MaximumNumberOfTradeUses { get; init; } + + public int Xp { get; init; } + + public int SpecialPrice { get; init; } + + public float PriceMultiplier { get; init; } + + public int Demand { get; init; } + +} diff --git a/Obsidian/Net/Packets/Play/Clientbound/TradeList.cs b/Obsidian/Net/Packets/Play/Clientbound/TradeList.cs new file mode 100644 index 000000000..c80c1b0f4 --- /dev/null +++ b/Obsidian/Net/Packets/Play/Clientbound/TradeList.cs @@ -0,0 +1,42 @@ +using Obsidian.Serialization.Attributes; + +namespace Obsidian.Net.Packets.Play.Clientbound; + +public partial class TradeList : IClientboundPacket +{ + public TradeList(int windowId, sbyte size, List trades, VillagerLevel villagerLevel, int experience, bool isRegularVillager, bool canRestock) + { + WindowId = windowId; + Size = size; + Trades = trades; + VillagerLevel = villagerLevel; + Experience = experience; + IsRegularVillager = isRegularVillager; + CanRestock = canRestock; + } + + [Field(0), VarLength] + public int WindowId { get; init; } + + [Field(1)] + public sbyte Size { get; init; } + + [Field(2)] + public List Trades { get; init; } + + [Field(3), ActualType(typeof(int)), VarLength] + public VillagerLevel VillagerLevel { get; init; } + + [Field(4), VarLength] + public int Experience { get; init; } + + [Field(5)] + public bool IsRegularVillager { get; init; } + + [Field(6)] + public bool CanRestock { get; init; } + + + public int Id => 0x28; + +} diff --git a/Obsidian/Net/Packets/Play/Clientbound/VillagerLevel.cs b/Obsidian/Net/Packets/Play/Clientbound/VillagerLevel.cs new file mode 100644 index 000000000..21c532f77 --- /dev/null +++ b/Obsidian/Net/Packets/Play/Clientbound/VillagerLevel.cs @@ -0,0 +1,10 @@ +namespace Obsidian.Net.Packets.Play.Clientbound; + +public enum VillagerLevel +{ + Novice = 1, + Apprentice = 2, + Journeyman = 3, + Expert = 4, + Master = 5 +} diff --git a/Obsidian/Net/Packets/Play/Serverbound/EditBook.cs b/Obsidian/Net/Packets/Play/Serverbound/EditBook.cs new file mode 100644 index 000000000..3e5f2d5b1 --- /dev/null +++ b/Obsidian/Net/Packets/Play/Serverbound/EditBook.cs @@ -0,0 +1,26 @@ +using Obsidian.Entities; +using Obsidian.Serialization.Attributes; + +namespace Obsidian.Net.Packets.Play.Serverbound; + +public partial class EditBook : IServerboundPacket +{ + [Field(0), VarLength, ActualType(typeof(int))] + public Hand Hand { get; set; } + + [Field(1), VarLength] + public int Count { get; set; } + + [Field(2), ActualType(typeof(string))] + public List Entries { get; set; } + + [Field(3)] + public bool HasTitle { get; set; } + + [Field(4)] + public string Title { get; set; } + + public int Id => 0x15; + + public ValueTask HandleAsync(Server server, Player player) => ValueTask.CompletedTask; +} diff --git a/Obsidian/Net/Packets/Play/Serverbound/GenerateStructure.cs b/Obsidian/Net/Packets/Play/Serverbound/GenerateStructure.cs new file mode 100644 index 000000000..53f66aacd --- /dev/null +++ b/Obsidian/Net/Packets/Play/Serverbound/GenerateStructure.cs @@ -0,0 +1,20 @@ +using Obsidian.Entities; +using Obsidian.Serialization.Attributes; + +namespace Obsidian.Net.Packets.Play.Serverbound; + +public partial class GenerateStructure : IServerboundPacket +{ + [Field(0)] + public VectorF Position { get; set; } + + [Field(1), VarLength] + public int Levels { get; set; } + + [Field(2)] + public bool KeepJigsaws { get; set; } + + public int Id => 0x0E; + + public ValueTask HandleAsync(Server server, Player player) => ValueTask.CompletedTask; +} diff --git a/Obsidian/Net/Packets/Play/Serverbound/LockDifficulty.cs b/Obsidian/Net/Packets/Play/Serverbound/LockDifficulty.cs new file mode 100644 index 000000000..669fbe64d --- /dev/null +++ b/Obsidian/Net/Packets/Play/Serverbound/LockDifficulty.cs @@ -0,0 +1,14 @@ +using Obsidian.Entities; +using Obsidian.Serialization.Attributes; + +namespace Obsidian.Net.Packets.Play.Serverbound; + +public partial class LockDifficulty : IServerboundPacket +{ + [Field(0)] + public bool Locked { get; set; } + + public int Id => 0x10; + + public ValueTask HandleAsync(Server server, Player player) => ValueTask.CompletedTask; +} diff --git a/Obsidian/Net/Packets/Play/Serverbound/PlayerMovement.cs b/Obsidian/Net/Packets/Play/Serverbound/PlayerMovement.cs new file mode 100644 index 000000000..785fbfadf --- /dev/null +++ b/Obsidian/Net/Packets/Play/Serverbound/PlayerMovement.cs @@ -0,0 +1,14 @@ +using Obsidian.Entities; +using Obsidian.Serialization.Attributes; + +namespace Obsidian.Net.Packets.Play.Serverbound; + +public partial class PlayerMovement : IServerboundPacket +{ + [Field(0)] + public bool OnGround { get; set; } + + public int Id => 0x14; + + public ValueTask HandleAsync(Server server, Player player) => ValueTask.CompletedTask; +} diff --git a/Obsidian/Net/Packets/Play/Serverbound/QueryEntityNbt.cs b/Obsidian/Net/Packets/Play/Serverbound/QueryEntityNbt.cs new file mode 100644 index 000000000..d5d7b4261 --- /dev/null +++ b/Obsidian/Net/Packets/Play/Serverbound/QueryEntityNbt.cs @@ -0,0 +1,17 @@ +using Obsidian.Entities; +using Obsidian.Serialization.Attributes; + +namespace Obsidian.Net.Packets.Play.Serverbound; + +public partial class QueryEntityNbt : IServerboundPacket +{ + [Field(0), VarLength] + public int TransactionId { get; set; } + + [Field(1), VarLength] + public int EntityId { get; set; } + + public int Id => 0x15; + + public ValueTask HandleAsync(Server server, Player player) => ValueTask.CompletedTask; +} diff --git a/Obsidian/Net/Packets/Play/Serverbound/RecipeBookType.cs b/Obsidian/Net/Packets/Play/Serverbound/RecipeBookType.cs new file mode 100644 index 000000000..814baecb1 --- /dev/null +++ b/Obsidian/Net/Packets/Play/Serverbound/RecipeBookType.cs @@ -0,0 +1,9 @@ +namespace Obsidian.Net.Packets.Play.Serverbound; + +public enum RecipeBookType +{ + Crafting, + Furnace, + BlastFurnace, + Smoker +} diff --git a/Obsidian/Net/Packets/Play/Serverbound/SelectTrade.cs b/Obsidian/Net/Packets/Play/Serverbound/SelectTrade.cs new file mode 100644 index 000000000..0149959cc --- /dev/null +++ b/Obsidian/Net/Packets/Play/Serverbound/SelectTrade.cs @@ -0,0 +1,14 @@ +using Obsidian.Entities; +using Obsidian.Serialization.Attributes; + +namespace Obsidian.Net.Packets.Play.Serverbound; + +public partial class SelectTrade : IServerboundPacket +{ + [Field(0), VarLength] + public int SelectedSlot { get; set; } + + public int Id => 0x23; + + public ValueTask HandleAsync(Server server, Player player) => ValueTask.CompletedTask; +} diff --git a/Obsidian/Net/Packets/Play/Serverbound/SetBeaconEffect.cs b/Obsidian/Net/Packets/Play/Serverbound/SetBeaconEffect.cs new file mode 100644 index 000000000..998147018 --- /dev/null +++ b/Obsidian/Net/Packets/Play/Serverbound/SetBeaconEffect.cs @@ -0,0 +1,17 @@ +using Obsidian.Entities; +using Obsidian.Serialization.Attributes; + +namespace Obsidian.Net.Packets.Play.Serverbound; + +public partial class SetBeaconEffect : IServerboundPacket +{ + [Field(0), VarLength] + public int PrimaryEffect { get; set; } + + [Field(1), VarLength] + public int SecondaryEffect { get; set; } + + public int Id => 0x24; + + public ValueTask HandleAsync(Server server, Player player) => ValueTask.CompletedTask; +} diff --git a/Obsidian/Net/Packets/Play/Serverbound/SetRecipeBookState.cs b/Obsidian/Net/Packets/Play/Serverbound/SetRecipeBookState.cs new file mode 100644 index 000000000..d54395795 --- /dev/null +++ b/Obsidian/Net/Packets/Play/Serverbound/SetRecipeBookState.cs @@ -0,0 +1,21 @@ +using Obsidian.Entities; +using Obsidian.Serialization.Attributes; + +namespace Obsidian.Net.Packets.Play.Serverbound; + +public partial class SetRecipeBookState : IServerboundPacket +{ + [Field(0), VarLength, ActualType(typeof(int))] + public RecipeBookType BookId { get; private set; } + + [Field(1)] + public bool BookOpen { get; private set; } + + [Field(2)] + public bool FilterActive { get; private set; } + + public int Id => 0x1E; + + public ValueTask HandleAsync(Server server, Player player) => ValueTask.CompletedTask; + +} diff --git a/Obsidian/Net/Packets/Play/Serverbound/Spectate.cs b/Obsidian/Net/Packets/Play/Serverbound/Spectate.cs new file mode 100644 index 000000000..d38680ae1 --- /dev/null +++ b/Obsidian/Net/Packets/Play/Serverbound/Spectate.cs @@ -0,0 +1,14 @@ +using Obsidian.Entities; +using Obsidian.Serialization.Attributes; + +namespace Obsidian.Net.Packets.Play.Serverbound; + +public partial class Spectate : IServerboundPacket +{ + [Field(0)] + public Guid TargetPlayer { get; set; } + + public int Id => 0x2D; + + public ValueTask HandleAsync(Server server, Player player) => ValueTask.CompletedTask; +} diff --git a/Obsidian/Net/Packets/Play/Serverbound/SteerBoat.cs b/Obsidian/Net/Packets/Play/Serverbound/SteerBoat.cs new file mode 100644 index 000000000..d63621050 --- /dev/null +++ b/Obsidian/Net/Packets/Play/Serverbound/SteerBoat.cs @@ -0,0 +1,16 @@ +using Obsidian.Entities; +using Obsidian.Serialization.Attributes; + +namespace Obsidian.Net.Packets.Play.Serverbound; + +public partial class SteerBoat : IServerboundPacket +{ + [Field(0)] + public bool LeftPaddleTurning { get; set; } + [Field(1)] + public bool RightPaddleTurning { get; set; } + + public int Id => 0x16; + + public ValueTask HandleAsync(Server server, Player player) => ValueTask.CompletedTask; +} diff --git a/Obsidian/Net/Packets/Play/Serverbound/TabCompleteRequest.cs b/Obsidian/Net/Packets/Play/Serverbound/TabCompleteRequest.cs new file mode 100644 index 000000000..cfe70eb0a --- /dev/null +++ b/Obsidian/Net/Packets/Play/Serverbound/TabCompleteRequest.cs @@ -0,0 +1,17 @@ +using Obsidian.Entities; +using Obsidian.Serialization.Attributes; + +namespace Obsidian.Net.Packets.Play.Serverbound; + +public partial class TabCompleteRequest : IServerboundPacket +{ + [Field(0), VarLength] + public int TransactionId { get; private set; } + + [Field(1)] + public string Text { get; private set; } + + public int Id => 0x06; + + public ValueTask HandleAsync(Server server, Player player) => ValueTask.CompletedTask; +} diff --git a/Obsidian/Net/Packets/Play/Serverbound/UpdateJigsawBlock.cs b/Obsidian/Net/Packets/Play/Serverbound/UpdateJigsawBlock.cs new file mode 100644 index 000000000..839473f78 --- /dev/null +++ b/Obsidian/Net/Packets/Play/Serverbound/UpdateJigsawBlock.cs @@ -0,0 +1,30 @@ +using Obsidian.Entities; +using Obsidian.Serialization.Attributes; + +namespace Obsidian.Net.Packets.Play.Serverbound; + +public partial class UpdateJigsawBlock : IServerboundPacket +{ + [Field(0)] + public VectorF Location { get; set; } + + [Field(1)] + public string Name { get; set; } + + [Field(2)] + public string Target { get; set; } + + [Field(3)] + public string Pool { get; set; } + + [Field(4)] + public string FinalState { get; set; } + + [Field(5)] + public string JointType { get; set; } + + public int Id => 0x29; + + public ValueTask HandleAsync(Server server, Player player) => ValueTask.CompletedTask; + +} diff --git a/Obsidian/Net/Packets/Play/Serverbound/UpdateSign.cs b/Obsidian/Net/Packets/Play/Serverbound/UpdateSign.cs new file mode 100644 index 000000000..4dbcda58e --- /dev/null +++ b/Obsidian/Net/Packets/Play/Serverbound/UpdateSign.cs @@ -0,0 +1,26 @@ +using Obsidian.Entities; +using Obsidian.Serialization.Attributes; + +namespace Obsidian.Net.Packets.Play.Serverbound; + +public partial class UpdateSign : IServerboundPacket +{ + [Field(0)] + public VectorF Location { get; set; } + + [Field(1), FixedLength(384)] + public string Line1 { get; set; } + + [Field(2), FixedLength(384)] + public string Line2 { get; set; } + + [Field(3), FixedLength(384)] + public string Line3 { get; set; } + + [Field(4), FixedLength(384)] + public string Line4 { get; set; } + + public int Id => 0x2B; + + public ValueTask HandleAsync(Server server, Player player) => ValueTask.CompletedTask; +} diff --git a/Obsidian/Net/Packets/Play/Serverbound/VehicleMove.cs b/Obsidian/Net/Packets/Play/Serverbound/VehicleMove.cs new file mode 100644 index 000000000..e51c85916 --- /dev/null +++ b/Obsidian/Net/Packets/Play/Serverbound/VehicleMove.cs @@ -0,0 +1,20 @@ +using Obsidian.Entities; +using Obsidian.Serialization.Attributes; + +namespace Obsidian.Net.Packets.Play.Serverbound; + +public partial class VehicleMove : IServerboundPacket +{ + [Field(0), DataFormat(typeof(double))] + public VectorF Position { get; set; } + + [Field(1)] + public float Yaw { get; set; } + + [Field(2)] + public float Pitch { get; set; } + + public int Id => 0x15; + + public ValueTask HandleAsync(Server server, Player player) => ValueTask.CompletedTask; +} diff --git a/Obsidian/Utilities/ClientHandler.cs b/Obsidian/Utilities/ClientHandler.cs index 65123d55d..45a847117 100644 --- a/Obsidian/Utilities/ClientHandler.cs +++ b/Obsidian/Utilities/ClientHandler.cs @@ -19,52 +19,10 @@ public ClientHandler(Config config) public void RegisterHandlers() { - // ! == moved to HandlePlayPackets - //Packets.TryAdd(0x00, new TeleportConfirm()); ! - //Packets.TryAdd(0x01, QueryBlockNBT); - //Packets.TryAdd(0x02, SetDifficulty); - //Packets.TryAdd(0x03, new IncomingChatMessage()); ! - //Packets.TryAdd(0x04, ClientStatus); - //Packets.TryAdd(0x05, new ClientSettings()); ! - //Packets.TryAdd(0x06, TabComplete); - //Packets.TryAdd(0x07, new WindowConfirmation()); ! - //Packets.TryAdd(0x08, new ClickWindowButton()); ! - //Packets.TryAdd(0x09, new ClickWindow()); ! - //Packets.TryAdd(0x0A, new CloseWindow()); ! - //Packets.TryAdd(0x0B, new PluginMessage()); ! - //Packets.TryAdd(0x0C, EditBook); - //Packets.TryAdd(0x0E, InteractEntity); - //Packets.TryAdd(0x0F, GenerateStructure); - //Packets.TryAdd(0x11, LockDifficulty); Packets.TryAdd(0x11, new PlayerPosition()); Packets.TryAdd(0x12, new PlayerPositionAndRotation()); Packets.TryAdd(0x13, new PlayerRotation()); - //Packets.TryAdd(0x15, PlayerMovement); - //Packets.TryAdd(0x16, VehicleMove); - //Packets.TryAdd(0x17, SteerBoat); - //Packets.TryAdd(0x18, new PickItem()); ! - //Packets.TryAdd(0x19, new CraftRecipeRequest()); ! - //Packets.TryAdd(0x1A, PlayerAbilities); - //Packets.TryAdd(0x1B, new PlayerDigging()); ! - //Packets.TryAdd(0x1C, new EntityAction()); ! - //Packets.TryAdd(0x1D, SteerVehicle); - //Packets.TryAdd(0x1E, new SetDisplayedRecipe()); ! - //Packets.TryAdd(0x1F, SetRecipeBookState); - //Packets.TryAdd(0x20, new NameItem()); ! - //Packets.TryAdd(0x21, ResourcePackStatus); - //Packets.TryAdd(0x22, AdvancementTab); - //Packets.TryAdd(0x23, SelectTrade); - //Packets.TryAdd(0x24, SetBeaconEffect); Packets.TryAdd(0x25, new ServerHeldItemChange()); - //Packets.TryAdd(0x26, UpdateCommandBlock); - //Packets.TryAdd(0x27, UpdateCommandBlockMinecart); - //Packets.TryAdd(0x28, new CreativeInventoryAction()); ! - //Packets.TryAdd(0x29, UpdateJigsawBlock); - //Packets.TryAdd(0x2A, UpdateStructureBlock); - //Packets.TryAdd(0x2B, UpdateSign); - //Packets.TryAdd(0x2C, new Animation()); - //Packets.TryAdd(0x2D, Spectate); - //Packets.TryAdd(0x2E, new PlayerBlockPlacement()); ! Packets.TryAdd(0x2F, new UseItem()); } @@ -76,6 +34,10 @@ public async Task HandlePlayPackets(int id, byte[] data, Client client) await HandleFromPoolAsync(data, client); break; + case 0x02: + // Only used on integrated server + break; + case 0x03: await HandleFromPoolAsync(data, client); break; @@ -86,6 +48,10 @@ public async Task HandlePlayPackets(int id, byte[] data, Client client) await HandleFromPoolAsync(data, client); break; + case 0x06: + await HandleFromPoolAsync(data, client); + break; + case 0x07: await HandleFromPoolAsync(data, client); break; @@ -101,14 +67,43 @@ public async Task HandlePlayPackets(int id, byte[] data, Client client) case 0x0A: await HandleFromPoolAsync(data, client); break; - case 0x0F: - await HandleFromPoolAsync(data, client); + + case 0x0B: + await HandleFromPoolAsync(data, client); // TODO: Not finished + break; + + case 0x0C: + await HandleFromPoolAsync(data, client); // TODO: Not finished break; case 0x0D: await HandleFromPoolAsync(data, client); break; + case 0x0E: + await HandleFromPoolAsync(data, client); // TODO: Not finished + break; + + case 0x0F: + await HandleFromPoolAsync(data, client); + break; + + case 0x10: + await HandleFromPoolAsync(data, client); // TODO: Not finished + break; + + case 0x14: + await HandleFromPoolAsync(data, client); // TODO: Not finished + break; + + case 0x15: + await HandleFromPoolAsync(data, client); + break; + + case 0x16: + await HandleFromPoolAsync(data, client); // TODO: Not finished + break; + case 0x17: await HandleFromPoolAsync(data, client); break; @@ -125,6 +120,10 @@ public async Task HandlePlayPackets(int id, byte[] data, Client client) await HandleFromPoolAsync(data, client); break; + case 0x1E: + await HandleFromPoolAsync(data, client); + break; + case 0x1F: await HandleFromPoolAsync(data, client); break; @@ -133,14 +132,34 @@ public async Task HandlePlayPackets(int id, byte[] data, Client client) await HandleFromPoolAsync(data, client); break; + case 0x23: + await HandleFromPoolAsync(data, client); + break; + + case 0x24: + await HandleFromPoolAsync(data, client); + break; + case 0x28: await HandleFromPoolAsync(data, client); break; + case 0x29: + await HandleFromPoolAsync(data, client); // TODO: Not finished + break; + + case 0x2B: + await HandleFromPoolAsync(data, client); // TODO: Not finished + break; + case 0x2C: await HandleFromPoolAsync(data, client); break; + case 0x2D: + await HandleFromPoolAsync(data, client); // TODO: Not finished + break; + case 0x2E: await HandleFromPoolAsync(data, client); break;