Implement entity types (#1001)

Implement palette generation and investigate palette changes between
versions. Turns out 1.13- has legacy IDs, 1.14 switches to entity
palette and 1.15 refreshes the whole palette just to insert Bee.

Also refactor entity handling code here and there.
This commit is contained in:
ORelio 2020-05-24 18:21:22 +02:00
parent 5b0b0c9cc3
commit bd85c46663
27 changed files with 1113 additions and 259 deletions

View file

@ -6,6 +6,7 @@ using System.Net.Sockets;
using MinecraftClient.Mapping;
using MinecraftClient.Crypto;
using MinecraftClient.Inventory;
using MinecraftClient.Mapping.EntityPalettes;
namespace MinecraftClient.Protocol.Handlers
{
@ -321,9 +322,8 @@ namespace MinecraftClient.Protocol.Handlers
}
/// <summary>
/// Read a single item slot from a cache of byte and remove it from the cache
/// Read a single item slot from a cache of bytes and remove it from the cache
/// </summary>
/// <param name="item">Item</param>
/// <returns>The item that was read or NULL for an empty slot</returns>
public Item ReadNextItemSlot(Queue<byte> cache)
{
@ -354,6 +354,45 @@ namespace MinecraftClient.Protocol.Handlers
}
}
/// <summary>
/// Read entity information from a cache of bytes and remove it from the cache
/// </summary>
/// <param name="entityPalette">Mappings for converting entity type Ids to EntityType</param>
/// <param name="living">TRUE for living entities (layout differs)</param>
/// <returns>Entity information</returns>
public Entity ReadNextEntity(Queue<byte> cache, EntityPalette entityPalette, bool living)
{
int entityID = ReadNextVarInt(cache);
Guid entityUUID = Guid.Empty;
if (protocolversion > Protocol18Handler.MC18Version)
{
entityUUID = ReadNextUUID(cache);
}
EntityType entityType = entityPalette.FromId(ReadNextVarInt(cache), living);
Double entityX = ReadNextDouble(cache);
Double entityY = ReadNextDouble(cache);
Double entityZ = ReadNextDouble(cache);
byte entityYaw = ReadNextByte(cache);
byte entityPitch = ReadNextByte(cache);
if (living)
{
byte entityHeadPitch = ReadNextByte(cache);
}
else
{
int metadata = ReadNextInt(cache);
}
short velocityX = ReadNextShort(cache);
short velocityY = ReadNextShort(cache);
short velocityZ = ReadNextShort(cache);
return new Entity(entityID, entityType, new Location(entityX, entityY, entityZ));
}
/// <summary>
/// Read an uncompressed Named Binary Tag blob and remove it from the cache (internal)
/// </summary>

View file

@ -9,6 +9,7 @@ using MinecraftClient.Proxy;
using System.Security.Cryptography;
using MinecraftClient.Mapping;
using MinecraftClient.Mapping.BlockPalettes;
using MinecraftClient.Mapping.EntityPalettes;
using MinecraftClient.Protocol.Handlers.Forge;
using MinecraftClient.Inventory;
@ -50,6 +51,7 @@ namespace MinecraftClient.Protocol.Handlers
Protocol18Forge pForge;
Protocol18Terrain pTerrain;
IMinecraftComHandler handler;
EntityPalette entityPalette;
SocketWrapper socketWrapper;
DataTypes dataTypes;
Thread netRead;
@ -94,6 +96,16 @@ namespace MinecraftClient.Protocol.Handlers
else Block.Palette = new Palette113();
}
else Block.Palette = new Palette112();
if (protocolversion >= MC114Version)
{
if (protocolversion > MC1152Version && handler.GetEntityHandlingEnabled())
throw new NotImplementedException("Please update entity types handling for this Minecraft version. See EntityType.cs");
if (protocolversion >= MC115Version)
entityPalette = new EntityPalette115();
else entityPalette = new EntityPalette114();
}
else entityPalette = new EntityPalette113();
}
/// <summary>
@ -195,7 +207,7 @@ namespace MinecraftClient.Protocol.Handlers
}
}
// Regular in-game packets
switch (Protocol18PacketTypes.GetPacketIncomingType(packetID, protocolversion))
else switch (Protocol18PacketTypes.GetPacketIncomingType(packetID, protocolversion))
{
case PacketIncomingType.KeepAlive:
SendPacket(PacketOutgoingType.KeepAlive, packetData);
@ -569,54 +581,18 @@ namespace MinecraftClient.Protocol.Handlers
case PacketIncomingType.SpawnEntity:
if (handler.GetEntityHandlingEnabled())
{
int EntityID = dataTypes.ReadNextVarInt(packetData);
Guid EntityUUID = Guid.Empty;
if (protocolversion > MC18Version)
{
EntityUUID = dataTypes.ReadNextUUID(packetData);
}
int EntityType = dataTypes.ReadNextVarInt(packetData);
Double X = dataTypes.ReadNextDouble(packetData);
Double Y = dataTypes.ReadNextDouble(packetData);
Double Z = dataTypes.ReadNextDouble(packetData);
byte EntityYaw = dataTypes.ReadNextByte(packetData);
byte EntityPitch = dataTypes.ReadNextByte(packetData);
int Data = dataTypes.ReadNextInt(packetData);
short VelocityX = dataTypes.ReadNextShort(packetData);
short VelocityY = dataTypes.ReadNextShort(packetData);
short VelocityZ = dataTypes.ReadNextShort(packetData);
Location EntityLocation = new Location(X, Y, Z);
handler.OnSpawnEntity(EntityID, EntityType, EntityUUID, EntityLocation);
Entity entity = dataTypes.ReadNextEntity(packetData, entityPalette, false);
handler.OnSpawnEntity(entity);
}
break;
case PacketIncomingType.SpawnLivingEntity:
if (login_phase) break; // same packet ID with login packet
if (handler.GetEntityHandlingEnabled())
{
int EntityID = dataTypes.ReadNextVarInt(packetData);
Guid EntityUUID = Guid.Empty;
if (protocolversion > MC18Version)
{
EntityUUID = dataTypes.ReadNextUUID(packetData);
}
int EntityType = dataTypes.ReadNextVarInt(packetData);
Double X = dataTypes.ReadNextDouble(packetData);
Double Y = dataTypes.ReadNextDouble(packetData);
Double Z = dataTypes.ReadNextDouble(packetData);
byte EntityYaw = dataTypes.ReadNextByte(packetData);
byte EntityPitch = dataTypes.ReadNextByte(packetData);
byte EntityHeadPitch = dataTypes.ReadNextByte(packetData);
short VelocityX = dataTypes.ReadNextShort(packetData);
short VelocityY = dataTypes.ReadNextShort(packetData);
short VelocityZ = dataTypes.ReadNextShort(packetData);
Entity entity = dataTypes.ReadNextEntity(packetData, entityPalette, true);
// packet before 1.15 has metadata at the end
Location EntityLocation = new Location(X, Y, Z);
handler.OnSpawnLivingEntity(EntityID, EntityType, EntityUUID, EntityLocation);
// this is not handled in dataTypes.ReadNextEntity()
// we are simply ignoring leftover data in packet
handler.OnSpawnEntity(entity);
}
break;
case PacketIncomingType.SpawnPlayer:
@ -713,7 +689,6 @@ namespace MinecraftClient.Protocol.Handlers
}
break;
case PacketIncomingType.TimeUpdate:
if (login_phase) break;
long WorldAge = dataTypes.ReadNextLong(packetData);
long TimeOfday = dataTypes.ReadNextLong(packetData);
handler.OnTimeUpdate(WorldAge, TimeOfday);

View file

@ -46,8 +46,8 @@ namespace MinecraftClient.Protocol.Handlers
// Set Cooldown does not exists
case 0x03: return PacketIncomingType.TimeUpdate;
// Entity handling
case 0x0E: return PacketIncomingType.SpawnEntity; // for non-living entity
case 0x0F: return PacketIncomingType.SpawnLivingEntity; // for living entity
case 0x0E: return PacketIncomingType.SpawnEntity;
case 0x0F: return PacketIncomingType.SpawnLivingEntity;
case 0x05: return PacketIncomingType.SpawnPlayer;
case 0x13: return PacketIncomingType.DestroyEntities;
case 0x15: return PacketIncomingType.EntityPosition;
@ -85,8 +85,8 @@ namespace MinecraftClient.Protocol.Handlers
case 0x17: return PacketIncomingType.SetCooldown;
case 0x44: return PacketIncomingType.TimeUpdate;
// Entity handling
case 0x00: return PacketIncomingType.SpawnEntity; // for non-living entity
case 0x03: return PacketIncomingType.SpawnLivingEntity; // for living entity
case 0x00: return PacketIncomingType.SpawnEntity;
case 0x03: return PacketIncomingType.SpawnLivingEntity;
case 0x05: return PacketIncomingType.SpawnPlayer;
case 0x30: return PacketIncomingType.DestroyEntities;
case 0x25: return PacketIncomingType.EntityPosition;
@ -122,8 +122,8 @@ namespace MinecraftClient.Protocol.Handlers
case 0x17: return PacketIncomingType.SetCooldown;
case 0x46: return PacketIncomingType.TimeUpdate;
// Entity handling
case 0x00: return PacketIncomingType.SpawnEntity; // for non-living entity
case 0x03: return PacketIncomingType.SpawnLivingEntity; // for living entity
case 0x00: return PacketIncomingType.SpawnEntity;
case 0x03: return PacketIncomingType.SpawnLivingEntity;
case 0x05: return PacketIncomingType.SpawnPlayer;
case 0x31: return PacketIncomingType.DestroyEntities;
case 0x26: return PacketIncomingType.EntityPosition;
@ -159,8 +159,8 @@ namespace MinecraftClient.Protocol.Handlers
case 0x17: return PacketIncomingType.SetCooldown;
case 0x47: return PacketIncomingType.TimeUpdate;
// Entity handling
case 0x00: return PacketIncomingType.SpawnEntity; // for non-living entity
case 0x03: return PacketIncomingType.SpawnLivingEntity; // for living entity
case 0x00: return PacketIncomingType.SpawnEntity;
case 0x03: return PacketIncomingType.SpawnLivingEntity;
case 0x05: return PacketIncomingType.SpawnPlayer;
case 0x32: return PacketIncomingType.DestroyEntities;
case 0x26: return PacketIncomingType.EntityPosition;
@ -196,8 +196,8 @@ namespace MinecraftClient.Protocol.Handlers
case 0x18: return PacketIncomingType.SetCooldown;
case 0x4A: return PacketIncomingType.TimeUpdate;
// Entity handling
case 0x00: return PacketIncomingType.SpawnEntity; // for non-living entity
case 0x03: return PacketIncomingType.SpawnLivingEntity; // for living entity
case 0x00: return PacketIncomingType.SpawnEntity;
case 0x03: return PacketIncomingType.SpawnLivingEntity;
case 0x05: return PacketIncomingType.SpawnPlayer;
case 0x35: return PacketIncomingType.DestroyEntities;
case 0x28: return PacketIncomingType.EntityPosition;
@ -232,8 +232,8 @@ namespace MinecraftClient.Protocol.Handlers
case 0x17: return PacketIncomingType.SetCooldown;
case 0x4E: return PacketIncomingType.TimeUpdate;
// Entity handling
case 0x00: return PacketIncomingType.SpawnEntity; // for non-living entity
case 0x03: return PacketIncomingType.SpawnLivingEntity; // for living entity
case 0x00: return PacketIncomingType.SpawnEntity;
case 0x03: return PacketIncomingType.SpawnLivingEntity;
case 0x05: return PacketIncomingType.SpawnPlayer;
case 0x37: return PacketIncomingType.DestroyEntities;
case 0x28: return PacketIncomingType.EntityPosition;
@ -268,8 +268,8 @@ namespace MinecraftClient.Protocol.Handlers
case 0x18: return PacketIncomingType.SetCooldown;
case 0x4F: return PacketIncomingType.TimeUpdate;
// Entity handling
case 0x00: return PacketIncomingType.SpawnEntity; // for non-living entity
case 0x03: return PacketIncomingType.SpawnLivingEntity; // for living entity
case 0x00: return PacketIncomingType.SpawnEntity;
case 0x03: return PacketIncomingType.SpawnLivingEntity;
case 0x05: return PacketIncomingType.SpawnPlayer;
case 0x38: return PacketIncomingType.DestroyEntities;
case 0x29: return PacketIncomingType.EntityPosition;