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

@ -112,7 +112,7 @@ namespace MinecraftClient.ChatBots
/// <returns>If the entity should be attacked</returns> /// <returns>If the entity should be attacked</returns>
public bool handleEntity(Entity entity) public bool handleEntity(Entity entity)
{ {
if (!entity.IsHostile()) if (!entity.Type.IsHostile())
return false; return false;
bool isBeingAttacked = entitiesToAttack.ContainsKey(entity.ID); bool isBeingAttacked = entitiesToAttack.ContainsKey(entity.ID);

View file

@ -46,7 +46,7 @@ namespace MinecraftClient.ChatBots
public override void OnEntitySpawn(Entity entity) public override void OnEntitySpawn(Entity entity)
{ {
if (entity.TypeID == 102) if (entity.Type == EntityType.FishingBobber)
{ {
if (GetCurrentLocation().Distance(entity.Location) < 2 && !isFishing) if (GetCurrentLocation().Distance(entity.Location) < 2 && !isFishing)
{ {
@ -60,7 +60,7 @@ namespace MinecraftClient.ChatBots
public override void OnEntityDespawn(Entity entity) public override void OnEntityDespawn(Entity entity)
{ {
if(entity.TypeID == 102 && isFishing) if (entity.Type == EntityType.FishingBobber)
{ {
if(entity.ID == fishingRod.ID) if(entity.ID == fishingRod.ID)
{ {

View file

@ -1,7 +1,4 @@
using System; using MinecraftClient.Protocol;
using System.Collections.Generic;
using System.Linq;
using System.IO;
namespace MinecraftClient.Inventory namespace MinecraftClient.Inventory
{ {
@ -14,45 +11,10 @@ namespace MinecraftClient.Inventory
/// Generate ItemType.cs from Minecraft registries.json /// Generate ItemType.cs from Minecraft registries.json
/// </summary> /// </summary>
/// <param name="registriesJsonFile">path to registries.json</param> /// <param name="registriesJsonFile">path to registries.json</param>
/// <param name="outputEnum">output path for ItemTypes.cs</param>
/// <remarks>java -cp minecraft_server.jar net.minecraft.data.Main --reports</remarks> /// <remarks>java -cp minecraft_server.jar net.minecraft.data.Main --reports</remarks>
public static void JsonToClass(string registriesJsonFile, string outputEnum) public static void GenerateItemTypes(string registriesJsonFile)
{ {
HashSet<int> itemIds = new HashSet<int>(); DataTypeGenerator.GenerateEnum(registriesJsonFile, "minecraft:item", "ItemType", "MinecraftClient.Inventory");
Json.JSONData registries = Json.ParseJson(File.ReadAllText(registriesJsonFile));
Json.JSONData itemRegistry = registries.Properties["minecraft:item"].Properties["entries"];
List<string> outFile = new List<string>();
outFile.AddRange(new[] {
"namespace MinecraftClient.Inventory",
"{",
" public enum ItemType",
" {"
});
foreach (KeyValuePair<string, Json.JSONData> item in itemRegistry.Properties)
{
int itemId = int.Parse(item.Value.Properties["protocol_id"].StringValue);
//minecraft:item_name => ItemName
string itemName = String.Concat(
item.Key.Replace("minecraft:", "")
.Split('_')
.Select(word => char.ToUpper(word[0]) + word.Substring(1))
);
if (itemIds.Contains(itemId))
throw new InvalidDataException("Duplicate item ID " + itemId + "!?");
outFile.Add(" " + itemName + " = " + itemId + ',');
}
outFile.AddRange(new[] {
" }",
"}"
});
File.WriteAllLines(outputEnum, outFile);
} }
} }
} }

View file

@ -15,7 +15,7 @@ namespace MinecraftClient.Mapping
/// Get or set global block ID to Material mapping /// Get or set global block ID to Material mapping
/// The global Palette is a concept introduced with Minecraft 1.13 /// The global Palette is a concept introduced with Minecraft 1.13
/// </summary> /// </summary>
public static BlockPaletteMapping Palette { get; set; } public static BlockPalette Palette { get; set; }
/// <summary> /// <summary>
/// Storage for block ID and metadata, as ushort for compatibility, performance and lower memory footprint /// Storage for block ID and metadata, as ushort for compatibility, performance and lower memory footprint

View file

@ -5,7 +5,7 @@ using System.Text;
namespace MinecraftClient.Mapping.BlockPalettes namespace MinecraftClient.Mapping.BlockPalettes
{ {
public abstract class BlockPaletteMapping public abstract class BlockPalette
{ {
/// <summary> /// <summary>
/// Get mapping dictionary. Must be overriden with proper implementation. /// Get mapping dictionary. Must be overriden with proper implementation.

View file

@ -9,7 +9,7 @@ namespace MinecraftClient.Mapping.BlockPalettes
/// Some blocks previously had different IDs depending on state, they have been merged here /// Some blocks previously had different IDs depending on state, they have been merged here
/// Comments correspond to changed material names since previous MCC versions /// Comments correspond to changed material names since previous MCC versions
/// </summary> /// </summary>
public class Palette112 : BlockPaletteMapping public class Palette112 : BlockPalette
{ {
private static Dictionary<int, Material> materials = new Dictionary<int, Material>() private static Dictionary<int, Material> materials = new Dictionary<int, Material>()
{ {

View file

@ -7,7 +7,7 @@ namespace MinecraftClient.Mapping.BlockPalettes
/// Defines mappings for Minecraft 1.13. /// Defines mappings for Minecraft 1.13.
/// Automatically generated using BlockPaletteGenerator.cs /// Automatically generated using BlockPaletteGenerator.cs
/// </summary> /// </summary>
public class Palette113 : BlockPaletteMapping public class Palette113 : BlockPalette
{ {
private static Dictionary<int, Material> materials = new Dictionary<int, Material>(); private static Dictionary<int, Material> materials = new Dictionary<int, Material>();

View file

@ -7,7 +7,7 @@ namespace MinecraftClient.Mapping.BlockPalettes
/// Defines mappings for Minecraft 1.14. /// Defines mappings for Minecraft 1.14.
/// Automatically generated using BlockPaletteGenerator.cs /// Automatically generated using BlockPaletteGenerator.cs
/// </summary> /// </summary>
public class Palette114 : BlockPaletteMapping public class Palette114 : BlockPalette
{ {
private static Dictionary<int, Material> materials = new Dictionary<int, Material>(); private static Dictionary<int, Material> materials = new Dictionary<int, Material>();

View file

@ -7,7 +7,7 @@ namespace MinecraftClient.Mapping.BlockPalettes
/// Defines mappings for Minecraft 1.15. /// Defines mappings for Minecraft 1.15.
/// Automatically generated using BlockPaletteGenerator.cs /// Automatically generated using BlockPaletteGenerator.cs
/// </summary> /// </summary>
public class Palette115 : BlockPaletteMapping public class Palette115 : BlockPalette
{ {
private static Dictionary<int, Material> materials = new Dictionary<int, Material>(); private static Dictionary<int, Material> materials = new Dictionary<int, Material>();

View file

@ -21,60 +21,15 @@ namespace MinecraftClient.Mapping
public Guid UUID; public Guid UUID;
/// <summary> /// <summary>
/// Entity type determined by Minecraft Console Client /// Entity type
/// </summary> /// </summary>
public EntityType Type; public EntityType Type;
/// <summary>
/// Entity type ID (more precise than Type, but may change between Minecraft versions)
/// </summary>
public int TypeID;
/// <summary> /// <summary>
/// Entity location in the Minecraft world /// Entity location in the Minecraft world
/// </summary> /// </summary>
public Location Location; public Location Location;
/// <summary>
/// Create a new entity based on Entity ID and location
/// </summary>
/// <param name="ID">Entity ID</param>
/// <param name="location">Entity location</param>
public Entity(int ID, Location location)
{
this.ID = ID;
this.Location = location;
}
/// <summary>
/// Create a new entity based on Entity ID, Entity Type and location
/// </summary>
/// <param name="ID">Entity ID</param>
/// <param name="TypeID">Entity Type ID</param>
/// <param name="location">Entity location</param>
public Entity(int ID, int TypeID, Location location)
{
this.ID = ID;
this.TypeID = TypeID;
this.Location = location;
}
/// <summary>
/// Create a new entity based on Entity ID, Entity Type, location, and UUID
/// </summary>
/// <param name="ID">Entity ID</param>
/// <param name="TypeID">Entity Type ID</param>
/// <param name="type">Entity Type Enum</param>
/// <param name="location">Entity location</param>
public Entity(int ID, int TypeID, EntityType type, Location location, Guid uuid)
{
this.ID = ID;
this.TypeID = TypeID;
this.Type = type;
this.Location = location;
this.UUID = uuid;
}
/// <summary> /// <summary>
/// Create a new entity based on Entity ID, Entity Type and location /// Create a new entity based on Entity ID, Entity Type and location
/// </summary> /// </summary>
@ -100,41 +55,5 @@ namespace MinecraftClient.Mapping
this.Location = location; this.Location = location;
this.UUID = uuid; this.UUID = uuid;
} }
/// <summary>
/// Return TRUE if the Entity is an hostile mob
/// </summary>
/// <remarks>New mobs added in newer Minecraft versions might be absent from the list</remarks>
/// <returns>TRUE if hostile</returns>
public bool IsHostile()
{
switch (TypeID)
{
case 5: return true; // Blaze;
case 12: return true; // Creeper
case 16: return true; // Drowned
case 23: return true; // Evoker
case 29: return true; // Ghast
case 31: return true; // Guardian
case 33: return true; // Husk
case 41: return true; // Magma Cube
case 57: return true; // Zombie Pigman
case 63: return true; // Shulker
case 65: return true; // Silverfish
case 66: return true; // Skeleton
case 68: return true; // Slime
case 75: return true; // Stray
case 84: return true; // Vex
case 87: return true; // Vindicator
case 88: return true; // Pillager
case 90: return true; // Witch
case 92: return true; // Wither Skeleton
case 95: return true; // Zombie
case 97: return true; // Zombie Villager
case 98: return true; // Phantom
case 99: return true; // Ravager
default: return false;
}
}
} }
} }

View file

@ -0,0 +1,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MinecraftClient.Mapping.EntityPalettes
{
public abstract class EntityPalette
{
/// <summary>
/// Get mapping dictionary. Must be overriden with proper implementation.
/// </summary>
/// <returns>Palette dictionary</returns>
protected abstract Dictionary<int, EntityType> GetDict();
/// <summary>
/// Get mapping dictionary for pre-1.13. May be overriden with proper implementation.
/// </summary>
/// <returns>Palette dictionary for non-living entities (pre-1.13)</returns>
protected virtual Dictionary<int, EntityType> GetDictNonLiving()
{
return null;
}
/// <summary>
/// Get entity type from type ID
/// </summary>
/// <param name="id">Entity type ID</param>
/// <returns>EntityType corresponding to the specified ID</returns>
public EntityType FromId(int id, bool living)
{
Dictionary<int, EntityType> entityTypes = GetDict();
Dictionary<int, EntityType> entityTypesNonLiving = GetDictNonLiving();
if (entityTypesNonLiving != null && !living)
{
//Pre-1.13 non-living entities have a different set of IDs (entityTypesNonLiving != null)
if (entityTypesNonLiving.ContainsKey(id))
return entityTypesNonLiving[id];
}
else
{
//Post-1.13 entities have the same set of IDs regardless of living status
if (entityTypes.ContainsKey(id))
return entityTypes[id];
}
throw new System.IO.InvalidDataException("Unknown Entity ID " + id + ". Is Entity Palette up to date for this Minecraft version?");
}
}
}

View file

@ -0,0 +1,156 @@
using System;
using System.Collections.Generic;
namespace MinecraftClient.Mapping.EntityPalettes
{
/// <summary>
/// Defines mappings for pre-1.14 entitiy IDs
/// Pre-1.14 Minecraft has 2 set of ids: One for non-living objects and one for living mobs
/// Post-1.14 Minecraft has only one set of ids for all types of entities
/// </summary>
public class EntityPalette113 : EntityPalette
{
private static Dictionary<int, EntityType> mappingsObjects = new Dictionary<int, EntityType>()
{
// https://wiki.vg/Entity_metadata#Objects
{ 1, EntityType.Boat },
{ 2, EntityType.Item },
{ 3, EntityType.AreaEffectCloud },
{ 10, EntityType.Minecart },
{ 50, EntityType.Tnt },
{ 51, EntityType.EndCrystal },
{ 60, EntityType.Arrow },
{ 61, EntityType.Snowball },
{ 62, EntityType.Egg },
{ 63, EntityType.Fireball },
{ 64, EntityType.SmallFireball },
{ 65, EntityType.EnderPearl },
{ 66, EntityType.WitherSkull },
{ 67, EntityType.ShulkerBullet },
{ 68, EntityType.LlamaSpit },
{ 70, EntityType.FallingBlock },
{ 71, EntityType.ItemFrame },
{ 72, EntityType.EyeOfEnder },
{ 73, EntityType.Potion },
{ 75, EntityType.ExperienceBottle },
{ 76, EntityType.FireworkRocket },
{ 77, EntityType.LeashKnot },
{ 78, EntityType.ArmorStand },
{ 79, EntityType.EvokerFangs },
{ 90, EntityType.FishingBobber },
{ 91, EntityType.SpectralArrow },
{ 93, EntityType.DragonFireball },
{ 94, EntityType.Trident },
};
private static Dictionary<int, EntityType> mappingsMobs = new Dictionary<int, EntityType>()
{
// https://wiki.vg/Entity_metadata#Mobs
{ 0, EntityType.AreaEffectCloud },
{ 1, EntityType.ArmorStand },
{ 2, EntityType.Arrow },
{ 3, EntityType.Bat },
{ 4, EntityType.Blaze },
{ 5, EntityType.Boat },
{ 6, EntityType.CaveSpider },
{ 7, EntityType.Chicken },
{ 8, EntityType.Cod },
{ 9, EntityType.Cow },
{ 10, EntityType.Creeper },
{ 11, EntityType.Donkey },
{ 12, EntityType.Dolphin },
{ 13, EntityType.DragonFireball },
{ 14, EntityType.Drowned },
{ 15, EntityType.ElderGuardian },
{ 16, EntityType.EndCrystal },
{ 17, EntityType.EnderDragon },
{ 18, EntityType.Enderman },
{ 19, EntityType.Endermite },
{ 20, EntityType.EvokerFangs },
{ 21, EntityType.Evoker },
{ 22, EntityType.ExperienceBottle },
{ 23, EntityType.EyeOfEnder },
{ 24, EntityType.FallingBlock },
{ 25, EntityType.FireworkRocket },
{ 26, EntityType.Ghast },
{ 27, EntityType.Giant },
{ 28, EntityType.Guardian },
{ 29, EntityType.Horse },
{ 30, EntityType.Husk },
{ 31, EntityType.Illusioner },
{ 32, EntityType.Item },
{ 33, EntityType.ItemFrame },
{ 34, EntityType.Fireball },
{ 35, EntityType.LeashKnot },
{ 36, EntityType.Llama },
{ 37, EntityType.LlamaSpit },
{ 38, EntityType.MagmaCube },
{ 39, EntityType.Minecart },
{ 40, EntityType.ChestMinecart },
{ 41, EntityType.CommandBlockMinecart },
{ 42, EntityType.FurnaceMinecart },
{ 43, EntityType.HopperMinecart },
{ 44, EntityType.SpawnerMinecart },
{ 45, EntityType.TntMinecart },
{ 46, EntityType.Mule },
{ 47, EntityType.Mooshroom },
{ 48, EntityType.Ocelot },
{ 49, EntityType.Painting },
{ 50, EntityType.Parrot },
{ 51, EntityType.Pig },
{ 52, EntityType.Pufferfish },
{ 53, EntityType.ZombiePigman },
{ 54, EntityType.PolarBear },
{ 55, EntityType.Tnt },
{ 56, EntityType.Rabbit },
{ 57, EntityType.Salmon },
{ 58, EntityType.Sheep },
{ 59, EntityType.Shulker },
{ 60, EntityType.ShulkerBullet },
{ 61, EntityType.Silverfish },
{ 62, EntityType.Skeleton },
{ 63, EntityType.SkeletonHorse },
{ 64, EntityType.Slime },
{ 65, EntityType.SmallFireball },
{ 66, EntityType.SnowGolem },
{ 67, EntityType.Snowball },
{ 68, EntityType.SpectralArrow },
{ 69, EntityType.Spider },
{ 70, EntityType.Squid },
{ 71, EntityType.Stray },
{ 72, EntityType.TropicalFish },
{ 73, EntityType.Turtle },
{ 74, EntityType.Egg },
{ 75, EntityType.EnderPearl },
{ 76, EntityType.ExperienceBottle },
{ 77, EntityType.Potion },
{ 78, EntityType.Vex },
{ 79, EntityType.Villager },
{ 80, EntityType.IronGolem },
{ 81, EntityType.Vindicator },
{ 82, EntityType.Witch },
{ 83, EntityType.Wither },
{ 84, EntityType.WitherSkeleton },
{ 85, EntityType.WitherSkull },
{ 86, EntityType.Wolf },
{ 87, EntityType.Zombie },
{ 88, EntityType.ZombieHorse },
{ 89, EntityType.ZombieVillager },
{ 90, EntityType.Phantom },
{ 91, EntityType.LightningBolt },
{ 92, EntityType.Player },
{ 93, EntityType.FishingBobber },
{ 94, EntityType.Trident },
};
protected override Dictionary<int, EntityType> GetDict()
{
return mappingsMobs;
}
protected override Dictionary<int, EntityType> GetDictNonLiving()
{
return mappingsObjects;
}
}
}

View file

@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
namespace MinecraftClient.Mapping.EntityPalettes
{
/// <summary>
/// Defines mappings for Minecraft 1.14.
/// Automatically generated using EntityPaletteGenerator.cs
/// </summary>
public class EntityPalette114 : EntityPalette
{
private static Dictionary<int, EntityType> mappings = new Dictionary<int, EntityType>();
static EntityPalette114()
{
mappings[0] = EntityType.AreaEffectCloud;
mappings[1] = EntityType.ArmorStand;
mappings[2] = EntityType.Arrow;
mappings[3] = EntityType.Bat;
mappings[4] = EntityType.Blaze;
mappings[5] = EntityType.Boat;
mappings[6] = EntityType.Cat;
mappings[7] = EntityType.CaveSpider;
mappings[8] = EntityType.Chicken;
mappings[9] = EntityType.Cod;
mappings[10] = EntityType.Cow;
mappings[11] = EntityType.Creeper;
mappings[12] = EntityType.Donkey;
mappings[13] = EntityType.Dolphin;
mappings[14] = EntityType.DragonFireball;
mappings[15] = EntityType.Drowned;
mappings[16] = EntityType.ElderGuardian;
mappings[17] = EntityType.EndCrystal;
mappings[18] = EntityType.EnderDragon;
mappings[19] = EntityType.Enderman;
mappings[20] = EntityType.Endermite;
mappings[21] = EntityType.EvokerFangs;
mappings[22] = EntityType.Evoker;
mappings[23] = EntityType.ExperienceOrb;
mappings[24] = EntityType.EyeOfEnder;
mappings[25] = EntityType.FallingBlock;
mappings[26] = EntityType.FireworkRocket;
mappings[27] = EntityType.Fox;
mappings[28] = EntityType.Ghast;
mappings[29] = EntityType.Giant;
mappings[30] = EntityType.Guardian;
mappings[31] = EntityType.Horse;
mappings[32] = EntityType.Husk;
mappings[33] = EntityType.Illusioner;
mappings[34] = EntityType.Item;
mappings[35] = EntityType.ItemFrame;
mappings[36] = EntityType.Fireball;
mappings[37] = EntityType.LeashKnot;
mappings[38] = EntityType.Llama;
mappings[39] = EntityType.LlamaSpit;
mappings[40] = EntityType.MagmaCube;
mappings[41] = EntityType.Minecart;
mappings[42] = EntityType.ChestMinecart;
mappings[43] = EntityType.CommandBlockMinecart;
mappings[44] = EntityType.FurnaceMinecart;
mappings[45] = EntityType.HopperMinecart;
mappings[46] = EntityType.SpawnerMinecart;
mappings[47] = EntityType.TntMinecart;
mappings[48] = EntityType.Mule;
mappings[49] = EntityType.Mooshroom;
mappings[50] = EntityType.Ocelot;
mappings[51] = EntityType.Painting;
mappings[52] = EntityType.Panda;
mappings[53] = EntityType.Parrot;
mappings[54] = EntityType.Pig;
mappings[55] = EntityType.Pufferfish;
mappings[56] = EntityType.ZombiePigman;
mappings[57] = EntityType.PolarBear;
mappings[58] = EntityType.Tnt;
mappings[59] = EntityType.Rabbit;
mappings[60] = EntityType.Salmon;
mappings[61] = EntityType.Sheep;
mappings[62] = EntityType.Shulker;
mappings[63] = EntityType.ShulkerBullet;
mappings[64] = EntityType.Silverfish;
mappings[65] = EntityType.Skeleton;
mappings[66] = EntityType.SkeletonHorse;
mappings[67] = EntityType.Slime;
mappings[68] = EntityType.SmallFireball;
mappings[69] = EntityType.SnowGolem;
mappings[70] = EntityType.Snowball;
mappings[71] = EntityType.SpectralArrow;
mappings[72] = EntityType.Spider;
mappings[73] = EntityType.Squid;
mappings[74] = EntityType.Stray;
mappings[75] = EntityType.TraderLlama;
mappings[76] = EntityType.TropicalFish;
mappings[77] = EntityType.Turtle;
mappings[78] = EntityType.Egg;
mappings[79] = EntityType.EnderPearl;
mappings[80] = EntityType.ExperienceBottle;
mappings[81] = EntityType.Potion;
mappings[82] = EntityType.Trident;
mappings[83] = EntityType.Vex;
mappings[84] = EntityType.Villager;
mappings[85] = EntityType.IronGolem;
mappings[86] = EntityType.Vindicator;
mappings[87] = EntityType.Pillager;
mappings[88] = EntityType.WanderingTrader;
mappings[89] = EntityType.Witch;
mappings[90] = EntityType.Wither;
mappings[91] = EntityType.WitherSkeleton;
mappings[92] = EntityType.WitherSkull;
mappings[93] = EntityType.Wolf;
mappings[94] = EntityType.Zombie;
mappings[95] = EntityType.ZombieHorse;
mappings[96] = EntityType.ZombieVillager;
mappings[97] = EntityType.Phantom;
mappings[98] = EntityType.Ravager;
mappings[99] = EntityType.LightningBolt;
mappings[100] = EntityType.Player;
mappings[101] = EntityType.FishingBobber;
}
protected override Dictionary<int, EntityType> GetDict()
{
return mappings;
}
}
}

View file

@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
namespace MinecraftClient.Mapping.EntityPalettes
{
/// <summary>
/// Defines mappings for Minecraft 1.15.
/// Automatically generated using EntityPaletteGenerator.cs
/// </summary>
public class EntityPalette115 : EntityPalette
{
private static Dictionary<int, EntityType> mappings = new Dictionary<int, EntityType>();
static EntityPalette115()
{
mappings[0] = EntityType.AreaEffectCloud;
mappings[1] = EntityType.ArmorStand;
mappings[2] = EntityType.Arrow;
mappings[3] = EntityType.Bat;
mappings[4] = EntityType.Bee;
mappings[5] = EntityType.Blaze;
mappings[6] = EntityType.Boat;
mappings[7] = EntityType.Cat;
mappings[8] = EntityType.CaveSpider;
mappings[9] = EntityType.Chicken;
mappings[10] = EntityType.Cod;
mappings[11] = EntityType.Cow;
mappings[12] = EntityType.Creeper;
mappings[13] = EntityType.Donkey;
mappings[14] = EntityType.Dolphin;
mappings[15] = EntityType.DragonFireball;
mappings[16] = EntityType.Drowned;
mappings[17] = EntityType.ElderGuardian;
mappings[18] = EntityType.EndCrystal;
mappings[19] = EntityType.EnderDragon;
mappings[20] = EntityType.Enderman;
mappings[21] = EntityType.Endermite;
mappings[22] = EntityType.EvokerFangs;
mappings[23] = EntityType.Evoker;
mappings[24] = EntityType.ExperienceOrb;
mappings[25] = EntityType.EyeOfEnder;
mappings[26] = EntityType.FallingBlock;
mappings[27] = EntityType.FireworkRocket;
mappings[28] = EntityType.Fox;
mappings[29] = EntityType.Ghast;
mappings[30] = EntityType.Giant;
mappings[31] = EntityType.Guardian;
mappings[32] = EntityType.Horse;
mappings[33] = EntityType.Husk;
mappings[34] = EntityType.Illusioner;
mappings[35] = EntityType.Item;
mappings[36] = EntityType.ItemFrame;
mappings[37] = EntityType.Fireball;
mappings[38] = EntityType.LeashKnot;
mappings[39] = EntityType.Llama;
mappings[40] = EntityType.LlamaSpit;
mappings[41] = EntityType.MagmaCube;
mappings[42] = EntityType.Minecart;
mappings[43] = EntityType.ChestMinecart;
mappings[44] = EntityType.CommandBlockMinecart;
mappings[45] = EntityType.FurnaceMinecart;
mappings[46] = EntityType.HopperMinecart;
mappings[47] = EntityType.SpawnerMinecart;
mappings[48] = EntityType.TntMinecart;
mappings[49] = EntityType.Mule;
mappings[50] = EntityType.Mooshroom;
mappings[51] = EntityType.Ocelot;
mappings[52] = EntityType.Painting;
mappings[53] = EntityType.Panda;
mappings[54] = EntityType.Parrot;
mappings[55] = EntityType.Pig;
mappings[56] = EntityType.Pufferfish;
mappings[57] = EntityType.ZombiePigman;
mappings[58] = EntityType.PolarBear;
mappings[59] = EntityType.Tnt;
mappings[60] = EntityType.Rabbit;
mappings[61] = EntityType.Salmon;
mappings[62] = EntityType.Sheep;
mappings[63] = EntityType.Shulker;
mappings[64] = EntityType.ShulkerBullet;
mappings[65] = EntityType.Silverfish;
mappings[66] = EntityType.Skeleton;
mappings[67] = EntityType.SkeletonHorse;
mappings[68] = EntityType.Slime;
mappings[69] = EntityType.SmallFireball;
mappings[70] = EntityType.SnowGolem;
mappings[71] = EntityType.Snowball;
mappings[72] = EntityType.SpectralArrow;
mappings[73] = EntityType.Spider;
mappings[74] = EntityType.Squid;
mappings[75] = EntityType.Stray;
mappings[76] = EntityType.TraderLlama;
mappings[77] = EntityType.TropicalFish;
mappings[78] = EntityType.Turtle;
mappings[79] = EntityType.Egg;
mappings[80] = EntityType.EnderPearl;
mappings[81] = EntityType.ExperienceBottle;
mappings[82] = EntityType.Potion;
mappings[83] = EntityType.Trident;
mappings[84] = EntityType.Vex;
mappings[85] = EntityType.Villager;
mappings[86] = EntityType.IronGolem;
mappings[87] = EntityType.Vindicator;
mappings[88] = EntityType.Pillager;
mappings[89] = EntityType.WanderingTrader;
mappings[90] = EntityType.Witch;
mappings[91] = EntityType.Wither;
mappings[92] = EntityType.WitherSkeleton;
mappings[93] = EntityType.WitherSkull;
mappings[94] = EntityType.Wolf;
mappings[95] = EntityType.Zombie;
mappings[96] = EntityType.ZombieHorse;
mappings[97] = EntityType.ZombieVillager;
mappings[98] = EntityType.Phantom;
mappings[99] = EntityType.Ravager;
mappings[100] = EntityType.LightningBolt;
mappings[101] = EntityType.Player;
mappings[102] = EntityType.FishingBobber;
}
protected override Dictionary<int, EntityType> GetDict()
{
return mappings;
}
}
}

View file

@ -0,0 +1,20 @@
using MinecraftClient.Protocol;
namespace MinecraftClient.Mapping.EntityPalettes
{
/// <summary>
/// Generator for MCC ItemType enumeration
/// </summary>
public static class EntityPaletteGenerator
{
/// <summary>
/// Generate EntityType.cs from Minecraft registries.json
/// </summary>
/// <param name="registriesJsonFile">path to registries.json</param>
/// <remarks>java -cp minecraft_server.jar net.minecraft.data.Main --reports</remarks>
public static void GenerateEntityTypes(string registriesJsonFile)
{
DataTypeGenerator.GenerateEnumWithPalette(registriesJsonFile, "minecraft:entity_type", "EntityType", "MinecraftClient.Mapping", "EntityPalette", "MinecraftClient.Mapping.EntityPalettes");
}
}
}

View file

@ -0,0 +1,108 @@
namespace MinecraftClient.Mapping
{
public enum EntityType115
{
AreaEffectCloud = 0,
ArmorStand = 1,
Arrow = 2,
Bat = 3,
Blaze = 4,
Boat = 5,
Cat = 6,
CaveSpider = 7,
Chicken = 8,
Cod = 9,
Cow = 10,
Creeper = 11,
Donkey = 12,
Dolphin = 13,
DragonFireball = 14,
Drowned = 15,
ElderGuardian = 16,
EndCrystal = 17,
EnderDragon = 18,
Enderman = 19,
Endermite = 20,
EvokerFangs = 21,
Evoker = 22,
ExperienceOrb = 23,
EyeOfEnder = 24,
FallingBlock = 25,
FireworkRocket = 26,
Fox = 27,
Ghast = 28,
Giant = 29,
Guardian = 30,
Horse = 31,
Husk = 32,
Illusioner = 33,
Item = 34,
ItemFrame = 35,
Fireball = 36,
LeashKnot = 37,
Llama = 38,
LlamaSpit = 39,
MagmaCube = 40,
Minecart = 41,
ChestMinecart = 42,
CommandBlockMinecart = 43,
FurnaceMinecart = 44,
HopperMinecart = 45,
SpawnerMinecart = 46,
TntMinecart = 47,
Mule = 48,
Mooshroom = 49,
Ocelot = 50,
Painting = 51,
Panda = 52,
Parrot = 53,
Pig = 54,
Pufferfish = 55,
ZombiePigman = 56,
PolarBear = 57,
Tnt = 58,
Rabbit = 59,
Salmon = 60,
Sheep = 61,
Shulker = 62,
ShulkerBullet = 63,
Silverfish = 64,
Skeleton = 65,
SkeletonHorse = 66,
Slime = 67,
SmallFireball = 68,
SnowGolem = 69,
Snowball = 70,
SpectralArrow = 71,
Spider = 72,
Squid = 73,
Stray = 74,
TraderLlama = 75,
TropicalFish = 76,
Turtle = 77,
Egg = 78,
EnderPearl = 79,
ExperienceBottle = 80,
Potion = 81,
Trident = 82,
Vex = 83,
Villager = 84,
IronGolem = 85,
Vindicator = 86,
Pillager = 87,
WanderingTrader = 88,
Witch = 89,
Wither = 90,
WitherSkeleton = 91,
WitherSkull = 92,
Wolf = 93,
Zombie = 94,
ZombieHorse = 95,
ZombieVillager = 96,
Phantom = 97,
Ravager = 98,
LightningBolt = 99,
Player = 100,
FishingBobber = 101,
}
}

View file

@ -0,0 +1,109 @@
namespace MinecraftClient.Mapping
{
public enum EntityType114
{
AreaEffectCloud = 0,
ArmorStand = 1,
Arrow = 2,
Bat = 3,
Bee = 4,
Blaze = 5,
Boat = 6,
Cat = 7,
CaveSpider = 8,
Chicken = 9,
Cod = 10,
Cow = 11,
Creeper = 12,
Donkey = 13,
Dolphin = 14,
DragonFireball = 15,
Drowned = 16,
ElderGuardian = 17,
EndCrystal = 18,
EnderDragon = 19,
Enderman = 20,
Endermite = 21,
EvokerFangs = 22,
Evoker = 23,
ExperienceOrb = 24,
EyeOfEnder = 25,
FallingBlock = 26,
FireworkRocket = 27,
Fox = 28,
Ghast = 29,
Giant = 30,
Guardian = 31,
Horse = 32,
Husk = 33,
Illusioner = 34,
Item = 35,
ItemFrame = 36,
Fireball = 37,
LeashKnot = 38,
Llama = 39,
LlamaSpit = 40,
MagmaCube = 41,
Minecart = 42,
ChestMinecart = 43,
CommandBlockMinecart = 44,
FurnaceMinecart = 45,
HopperMinecart = 46,
SpawnerMinecart = 47,
TntMinecart = 48,
Mule = 49,
Mooshroom = 50,
Ocelot = 51,
Painting = 52,
Panda = 53,
Parrot = 54,
Pig = 55,
Pufferfish = 56,
ZombiePigman = 57,
PolarBear = 58,
Tnt = 59,
Rabbit = 60,
Salmon = 61,
Sheep = 62,
Shulker = 63,
ShulkerBullet = 64,
Silverfish = 65,
Skeleton = 66,
SkeletonHorse = 67,
Slime = 68,
SmallFireball = 69,
SnowGolem = 70,
Snowball = 71,
SpectralArrow = 72,
Spider = 73,
Squid = 74,
Stray = 75,
TraderLlama = 76,
TropicalFish = 77,
Turtle = 78,
Egg = 79,
EnderPearl = 80,
ExperienceBottle = 81,
Potion = 82,
Trident = 83,
Vex = 84,
Villager = 85,
IronGolem = 86,
Vindicator = 87,
Pillager = 88,
WanderingTrader = 89,
Witch = 90,
Wither = 91,
WitherSkeleton = 92,
WitherSkull = 93,
Wolf = 94,
Zombie = 95,
ZombieHorse = 96,
ZombieVillager = 97,
Phantom = 98,
Ravager = 99,
LightningBolt = 100,
Player = 101,
FishingBobber = 102,
}
}

View file

@ -1,14 +1,121 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MinecraftClient.Mapping namespace MinecraftClient.Mapping
{ {
/// <summary>
/// Represents Minecraft Entity Types
/// </summary>
/// <remarks>
/// Generated from registries.json using EntityPaletteGenerator.cs.
/// Typical steps to handle new entity IDs for newer Minecraft versions:
/// 1. Generate registries.json using data reporting on Vanilla Minecraft (https://wiki.vg/Data_Generators)
/// 2. Generate temporary EntityTypeXXX.cs and EntityPaletteXXX.cs using EntityPaletteGenerator.cs
/// 3. Perform a diff with existing versions, add missing entries in EntityType.cs and EntityTypeExtensions.cs
/// 4. If existing entity IDs were not randomized by Mojang, simply add missing state entries to the latest existing PaletteXXX.cs
/// 5. If existing entity IDs were randomized, add a new palette as PaletteXXX.cs into the codebase (worst case)
/// </remarks>
public enum EntityType public enum EntityType
{ {
MobAndAnimal, AreaEffectCloud,
ArmorStand,
Arrow,
Bat,
Bee,
Blaze,
Boat,
Cat,
CaveSpider,
Chicken,
Cod,
Cow,
Creeper,
Donkey,
Dolphin,
DragonFireball,
Drowned,
ElderGuardian,
EndCrystal,
EnderDragon,
Enderman,
Endermite,
EvokerFangs,
Evoker,
ExperienceOrb,
EyeOfEnder,
FallingBlock,
FireworkRocket,
Fox,
Ghast,
Giant,
Guardian,
Horse,
Husk,
Illusioner,
Item,
ItemFrame,
Fireball,
LeashKnot,
Llama,
LlamaSpit,
MagmaCube,
Minecart,
ChestMinecart,
CommandBlockMinecart,
FurnaceMinecart,
HopperMinecart,
SpawnerMinecart,
TntMinecart,
Mule,
Mooshroom,
Ocelot,
Painting,
Panda,
Parrot,
Pig,
Pufferfish,
ZombiePigman,
PolarBear,
Tnt,
Rabbit,
Salmon,
Sheep,
Shulker,
ShulkerBullet,
Silverfish,
Skeleton,
SkeletonHorse,
Slime,
SmallFireball,
SnowGolem,
Snowball,
SpectralArrow,
Spider,
Squid,
Stray,
TraderLlama,
TropicalFish,
Turtle,
Egg,
EnderPearl,
ExperienceBottle,
Potion,
Trident,
Vex,
Villager,
IronGolem,
Vindicator,
Pillager,
WanderingTrader,
Witch,
Wither,
WitherSkeleton,
WitherSkull,
Wolf,
Zombie,
ZombieHorse,
ZombieVillager,
Phantom,
Ravager,
LightningBolt,
Player, Player,
NonLivingThings, FishingBobber,
} }
} }

View file

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MinecraftClient.Mapping
{
public static class EntityTypeExtensions
{
/// <summary>
/// Return TRUE if the Entity is an hostile mob
/// </summary>
/// <remarks>New mobs added in newer Minecraft versions might be absent from the list</remarks>
/// <returns>TRUE if hostile</returns>
public static bool IsHostile(this EntityType e)
{
switch (e)
{
case EntityType.Blaze:
case EntityType.Creeper:
case EntityType.Drowned:
case EntityType.Evoker:
case EntityType.Ghast:
case EntityType.Guardian:
case EntityType.Husk:
case EntityType.MagmaCube:
case EntityType.Phantom:
case EntityType.Pillager:
case EntityType.Ravager:
case EntityType.Shulker:
case EntityType.Silverfish:
case EntityType.Skeleton:
case EntityType.Slime:
case EntityType.Stray:
case EntityType.Vex:
case EntityType.Vindicator:
case EntityType.Witch:
case EntityType.WitherSkeleton:
case EntityType.Zombie:
case EntityType.ZombiePigman:
case EntityType.ZombieVillager:
return true;
default:
return false;
}
}
}
}

View file

@ -1222,47 +1222,16 @@ namespace MinecraftClient
} }
/// <summary> /// <summary>
/// Called when a non-living entity spawned (fishing hook, minecart, etc) /// Called when an entity spawned
/// </summary> /// </summary>
/// <param name="EntityID"></param> public void OnSpawnEntity(Entity entity)
/// <param name="TypeID"></param>
/// <param name="UUID"></param>
/// <param name="location"></param>
public void OnSpawnEntity(int EntityID, int TypeID, Guid UUID, Location location)
{ {
if (entities.ContainsKey(EntityID)) return; // The entity should not already exist, but if it does, let's consider the previous one is being destroyed
Entity entity = new Entity(EntityID, TypeID, EntityType.NonLivingThings, location, UUID); if (entities.ContainsKey(entity.ID))
entities.Add(EntityID, entity); OnDestroyEntities(new[] { entity.ID });
foreach (ChatBot bot in bots.ToArray())
{ entities.Add(entity.ID, entity);
try
{
bot.OnEntitySpawn(entity);
}
catch (Exception e)
{
if (!(e is ThreadAbortException))
{
ConsoleIO.WriteLogLine("OnEntitySpawn: Got error from " + bot.ToString() + ": " + e.ToString());
}
else throw; //ThreadAbortException should not be caught
}
}
}
/// <summary>
/// Called when an Entity was created/spawned.
/// </summary>
/// <param name="EntityID"></param>
/// <param name="TypeID"></param>
/// <param name="UUID"></param>
/// <param name="location"></param>
/// <remarks>Cannot determine is a Mob or a Cuty Animal</remarks>
public void OnSpawnLivingEntity(int EntityID, int TypeID, Guid UUID, Location location)
{
if (entities.ContainsKey(EntityID)) return;
Entity entity = new Entity(EntityID, TypeID, EntityType.MobAndAnimal, location, UUID);
entities.Add(EntityID, entity);
foreach (ChatBot bot in bots.ToArray()) foreach (ChatBot bot in bots.ToArray())
{ {
try try

View file

@ -117,9 +117,15 @@
<Compile Include="Mapping\BlockPalettes\Palette114.cs" /> <Compile Include="Mapping\BlockPalettes\Palette114.cs" />
<Compile Include="Mapping\BlockPalettes\Palette115.cs" /> <Compile Include="Mapping\BlockPalettes\Palette115.cs" />
<Compile Include="Mapping\BlockPalettes\BlockPaletteGenerator.cs" /> <Compile Include="Mapping\BlockPalettes\BlockPaletteGenerator.cs" />
<Compile Include="Mapping\BlockPalettes\BlockPaletteMapping.cs" /> <Compile Include="Mapping\BlockPalettes\BlockPalette.cs" />
<Compile Include="Mapping\Entity.cs" /> <Compile Include="Mapping\Entity.cs" />
<Compile Include="Mapping\EntityPalettes\EntityPalette113.cs" />
<Compile Include="Mapping\EntityPalettes\EntityPalette.cs" />
<Compile Include="Mapping\EntityPalettes\EntityPalette114.cs" />
<Compile Include="Mapping\EntityPalettes\EntityPalette115.cs" />
<Compile Include="Mapping\EntityType.cs" /> <Compile Include="Mapping\EntityType.cs" />
<Compile Include="Mapping\EntityPalettes\EntityPaletteGenerator.cs" />
<Compile Include="Mapping\EntityTypeExtensions.cs" />
<Compile Include="Mapping\MaterialExtensions.cs" /> <Compile Include="Mapping\MaterialExtensions.cs" />
<Compile Include="Protocol\EntityActionType.cs" /> <Compile Include="Protocol\EntityActionType.cs" />
<Compile Include="Protocol\Handlers\DataTypes.cs" /> <Compile Include="Protocol\Handlers\DataTypes.cs" />
@ -129,6 +135,7 @@
<Compile Include="Protocol\Handlers\Protocol18PacketTypes.cs" /> <Compile Include="Protocol\Handlers\Protocol18PacketTypes.cs" />
<Compile Include="Protocol\Handlers\Protocol18Terrain.cs" /> <Compile Include="Protocol\Handlers\Protocol18Terrain.cs" />
<Compile Include="Protocol\Handlers\SocketWrapper.cs" /> <Compile Include="Protocol\Handlers\SocketWrapper.cs" />
<Compile Include="Protocol\DataTypeGenerator.cs" />
<Compile Include="Protocol\Session\SessionFileMonitor.cs" /> <Compile Include="Protocol\Session\SessionFileMonitor.cs" />
<Compile Include="WinAPI\ConsoleIcon.cs" /> <Compile Include="WinAPI\ConsoleIcon.cs" />
<Compile Include="ConsoleIO.cs" /> <Compile Include="ConsoleIO.cs" />

View file

@ -20,6 +20,7 @@ namespace MinecraftClient
/// Typical steps to update MCC for a new Minecraft version /// Typical steps to update MCC for a new Minecraft version
/// - Implement protocol changes (see Protocol18.cs) /// - Implement protocol changes (see Protocol18.cs)
/// - Handle new block types and states (see Material.cs) /// - Handle new block types and states (see Material.cs)
/// - Add support for new entity types (see EntityType.cs)
/// - Add new item types for inventories (see ItemType.cs) /// - Add new item types for inventories (see ItemType.cs)
/// - Mark new version as handled (see ProtocolHandler.cs) /// - Mark new version as handled (see ProtocolHandler.cs)
/// - Update MCHighestVersion field below (for versionning) /// - Update MCHighestVersion field below (for versionning)

View file

@ -0,0 +1,144 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
namespace MinecraftClient.Protocol
{
/// <summary>
/// Generic generator for MCC Enumerations such as ItemType or EntityType, mapping protocol IDs to actual enumeration fields such as 1 => Stone for inventories.
/// Works by processing Minecraft registries.json exported from minecraft_server.jar
/// </summary>
/// <remarks>java -cp minecraft_server.jar net.minecraft.data.Main --reports</remarks>
public static class DataTypeGenerator
{
/// <summary>
/// Read Minecraft registry from Json and build a dictionary
/// </summary>
/// <param name="registriesJsonFile">Path to registries.json generated from Minecraft server Jar</param>
/// <param name="jsonRegistryName">Name of registry we want to process, e.g. minecraft:item</param>
/// <returns></returns>
private static Dictionary<int, string> LoadRegistry(string registriesJsonFile, string jsonRegistryName)
{
Json.JSONData rawJson = Json.ParseJson(File.ReadAllText(registriesJsonFile));
Json.JSONData rawRegistry = rawJson.Properties[jsonRegistryName].Properties["entries"];
Dictionary<int, string> registry = new Dictionary<int, string>();
foreach (KeyValuePair<string, Json.JSONData> entry in rawRegistry.Properties)
{
int entryId = int.Parse(entry.Value.Properties["protocol_id"].StringValue);
//minecraft:item_name => ItemName
string entryName = String.Concat(
entry.Key.Replace("minecraft:", "")
.Split('_')
.Select(word => char.ToUpper(word[0]) + word.Substring(1))
);
if (registry.ContainsKey(entryId))
throw new InvalidDataException("Duplicate entry ID " + entryId + "!?");
registry.Add(entryId, entryName);
}
return registry;
}
/// <summary>
/// Generate MCC Enum from a Minecraft registry without Palette (static enum that does not change between versions)
/// </summary>
/// <param name="registriesJsonFile">Path to registries.json generated from Minecraft server Jar</param>
/// <param name="jsonRegistryName">Name of registry we want to process, e.g. minecraft:item</param>
/// <param name="outputEnum">Output enum name, e.g. ItemType (output file will be ItemType.cs)</param>
/// <param name="enumNamespace">Output enum namespace, e.g. MinecraftClient.Inventory</param>
public static void GenerateEnum(string registriesJsonFile, string jsonRegistryName, string outputEnum, string enumNamespace)
{
List<string> outputEnumLines = new List<string>();
outputEnumLines.AddRange(new[] {
"namespace " + enumNamespace,
"{",
" public enum " + outputEnum,
" {"
});
Dictionary<int, string> registry = LoadRegistry(registriesJsonFile, jsonRegistryName);
foreach (KeyValuePair<int, string> entry in registry)
outputEnumLines.Add(" " + entry.Value + " = " + entry.Key + ',');
outputEnumLines.AddRange(new[] {
" }",
"}"
});
string outputEnumPath = Path.Combine(Path.GetDirectoryName(registriesJsonFile), outputEnum + "XXX.cs");
File.WriteAllLines(outputEnumPath, outputEnumLines);
}
/// <summary>
/// Generate MCC Enum from a Minecraft registry with Palette (dynamic enum that changes between versions)
/// </summary>
/// <param name="registriesJsonFile">Path to registries.json generated from Minecraft server Jar</param>
/// <param name="jsonRegistryName">Name of registry we want to process, e.g. minecraft:item</param>
/// <param name="outputEnum">Output enum name, e.g. ItemType (output file will be ItemType.cs)</param>
/// <param name="enumNamespace">Enum namespace, e.g. MinecraftClient.Mapping</param>
/// <param name="outputPalette">Output palette name, e.g. ItemPalette (output file will be ItemPalette.cs and ItemPaletteXXX.cs)</param>
/// <param name="paletteNamespace">Palette namespace, e.g. MinecraftClient.EntityPalettes</param>
public static void GenerateEnumWithPalette(string registriesJsonFile, string jsonRegistryName, string outputEnum, string enumNamespace, string outputPalette, string paletteNamespace)
{
List<string> outputEnumLines = new List<string>();
List<string> outputPaletteLines = new List<string>();
outputEnumLines.AddRange(new[] {
"namespace " + enumNamespace,
"{",
" public enum " + outputEnum,
" {"
});
outputPaletteLines.AddRange(new[] {
"using System;",
"using System.Collections.Generic;",
"",
"namespace " + paletteNamespace,
"{",
" public class " + outputPalette + "XXX : " + outputPalette,
" {",
" private static Dictionary<int, " + outputEnum + "> mappings = new Dictionary<int, " + outputEnum + ">();",
"",
" static " + outputPalette + "XXX()",
" {",
});
Dictionary<int, string> registry = LoadRegistry(registriesJsonFile, jsonRegistryName);
foreach (KeyValuePair<int, string> entry in registry)
{
outputEnumLines.Add(" " + entry.Value + ',');
outputPaletteLines.Add(" mappings[" + entry.Key + "] = " + outputEnum + "." + entry.Value + ";");
}
outputEnumLines.AddRange(new[] {
" }",
"}"
});
outputPaletteLines.AddRange(new[] {
" }",
"",
" protected override Dictionary<int, " + outputEnum + "> GetDict()",
" {",
" return mappings;",
" }",
" }",
"}"
});
string outputEnumPath = Path.Combine(Path.GetDirectoryName(registriesJsonFile), outputEnum + "XXX.cs");
string outputPalettePath = Path.Combine(Path.GetDirectoryName(registriesJsonFile), outputPalette + "XXX.cs");
File.WriteAllLines(outputEnumPath, outputEnumLines);
File.WriteAllLines(outputPalettePath, outputPaletteLines);
}
}
}

View file

@ -6,6 +6,7 @@ using System.Net.Sockets;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using MinecraftClient.Crypto; using MinecraftClient.Crypto;
using MinecraftClient.Inventory; using MinecraftClient.Inventory;
using MinecraftClient.Mapping.EntityPalettes;
namespace MinecraftClient.Protocol.Handlers namespace MinecraftClient.Protocol.Handlers
{ {
@ -321,9 +322,8 @@ namespace MinecraftClient.Protocol.Handlers
} }
/// <summary> /// <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> /// </summary>
/// <param name="item">Item</param>
/// <returns>The item that was read or NULL for an empty slot</returns> /// <returns>The item that was read or NULL for an empty slot</returns>
public Item ReadNextItemSlot(Queue<byte> cache) 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> /// <summary>
/// Read an uncompressed Named Binary Tag blob and remove it from the cache (internal) /// Read an uncompressed Named Binary Tag blob and remove it from the cache (internal)
/// </summary> /// </summary>

View file

@ -9,6 +9,7 @@ using MinecraftClient.Proxy;
using System.Security.Cryptography; using System.Security.Cryptography;
using MinecraftClient.Mapping; using MinecraftClient.Mapping;
using MinecraftClient.Mapping.BlockPalettes; using MinecraftClient.Mapping.BlockPalettes;
using MinecraftClient.Mapping.EntityPalettes;
using MinecraftClient.Protocol.Handlers.Forge; using MinecraftClient.Protocol.Handlers.Forge;
using MinecraftClient.Inventory; using MinecraftClient.Inventory;
@ -50,6 +51,7 @@ namespace MinecraftClient.Protocol.Handlers
Protocol18Forge pForge; Protocol18Forge pForge;
Protocol18Terrain pTerrain; Protocol18Terrain pTerrain;
IMinecraftComHandler handler; IMinecraftComHandler handler;
EntityPalette entityPalette;
SocketWrapper socketWrapper; SocketWrapper socketWrapper;
DataTypes dataTypes; DataTypes dataTypes;
Thread netRead; Thread netRead;
@ -94,6 +96,16 @@ namespace MinecraftClient.Protocol.Handlers
else Block.Palette = new Palette113(); else Block.Palette = new Palette113();
} }
else Block.Palette = new Palette112(); 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> /// <summary>
@ -195,7 +207,7 @@ namespace MinecraftClient.Protocol.Handlers
} }
} }
// Regular in-game packets // Regular in-game packets
switch (Protocol18PacketTypes.GetPacketIncomingType(packetID, protocolversion)) else switch (Protocol18PacketTypes.GetPacketIncomingType(packetID, protocolversion))
{ {
case PacketIncomingType.KeepAlive: case PacketIncomingType.KeepAlive:
SendPacket(PacketOutgoingType.KeepAlive, packetData); SendPacket(PacketOutgoingType.KeepAlive, packetData);
@ -569,54 +581,18 @@ namespace MinecraftClient.Protocol.Handlers
case PacketIncomingType.SpawnEntity: case PacketIncomingType.SpawnEntity:
if (handler.GetEntityHandlingEnabled()) if (handler.GetEntityHandlingEnabled())
{ {
int EntityID = dataTypes.ReadNextVarInt(packetData); Entity entity = dataTypes.ReadNextEntity(packetData, entityPalette, false);
Guid EntityUUID = Guid.Empty; handler.OnSpawnEntity(entity);
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);
} }
break; break;
case PacketIncomingType.SpawnLivingEntity: case PacketIncomingType.SpawnLivingEntity:
if (login_phase) break; // same packet ID with login packet
if (handler.GetEntityHandlingEnabled()) if (handler.GetEntityHandlingEnabled())
{ {
int EntityID = dataTypes.ReadNextVarInt(packetData); Entity entity = dataTypes.ReadNextEntity(packetData, entityPalette, true);
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);
// packet before 1.15 has metadata at the end // packet before 1.15 has metadata at the end
// this is not handled in dataTypes.ReadNextEntity()
Location EntityLocation = new Location(X, Y, Z); // we are simply ignoring leftover data in packet
handler.OnSpawnEntity(entity);
handler.OnSpawnLivingEntity(EntityID, EntityType, EntityUUID, EntityLocation);
} }
break; break;
case PacketIncomingType.SpawnPlayer: case PacketIncomingType.SpawnPlayer:
@ -713,7 +689,6 @@ namespace MinecraftClient.Protocol.Handlers
} }
break; break;
case PacketIncomingType.TimeUpdate: case PacketIncomingType.TimeUpdate:
if (login_phase) break;
long WorldAge = dataTypes.ReadNextLong(packetData); long WorldAge = dataTypes.ReadNextLong(packetData);
long TimeOfday = dataTypes.ReadNextLong(packetData); long TimeOfday = dataTypes.ReadNextLong(packetData);
handler.OnTimeUpdate(WorldAge, TimeOfday); handler.OnTimeUpdate(WorldAge, TimeOfday);

View file

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

View file

@ -131,22 +131,10 @@ namespace MinecraftClient.Protocol
void OnPluginChannelMessage(string channel, byte[] data); void OnPluginChannelMessage(string channel, byte[] data);
/// <summary> /// <summary>
/// Called when a non-living entity has spawned /// Called when an entity has spawned
/// </summary> /// </summary>
/// <param name="EntityID">Entity ID</param> /// <param name="entity">Spawned entity</param>
/// <param name="EntityType">Entity Type ID</param> void OnSpawnEntity(Entity entity);
/// <param name="UUID">Entity UUID</param>
/// <param name="location">Entity location</param>
void OnSpawnEntity(int EntityID, int EntityType, Guid UUID, Location location);
/// <summary>
/// Called when a living entity has spawned
/// </summary>
/// <param name="EntityID">Entity ID</param>
/// <param name="EntityType">Entity Type ID</param>
/// <param name="UUID">Entity UUID</param>
/// <param name="location">Entity location</param>
void OnSpawnLivingEntity(int EntityID, int EntityType, Guid UUID, Location location);
/// <summary> /// <summary>
/// Called when a player has spawned /// Called when a player has spawned
@ -156,7 +144,7 @@ namespace MinecraftClient.Protocol
/// <param name="location">Entity location</param> /// <param name="location">Entity location</param>
/// <param name="Yaw">Player head yaw</param> /// <param name="Yaw">Player head yaw</param>
/// <param name="Pitch">Player head pitch</param> /// <param name="Pitch">Player head pitch</param>
void OnSpawnPlayer(int EntityID, Guid UUID, Location location, byte Yaw, byte Pitch); void OnSpawnPlayer(int entityID, Guid uuid, Location location, byte yaw, byte pitch);
/// <summary> /// <summary>
/// Called when entities have despawned /// Called when entities have despawned
@ -172,7 +160,7 @@ namespace MinecraftClient.Protocol
/// <param name="Dy">Y offset</param> /// <param name="Dy">Y offset</param>
/// <param name="Dz">Z offset</param> /// <param name="Dz">Z offset</param>
/// <param name="onGround">TRUE if on ground</param> /// <param name="onGround">TRUE if on ground</param>
void OnEntityPosition(int EntityID, Double Dx, Double Dy, Double Dz,bool onGround); void OnEntityPosition(int entityID, Double dx, Double dy, Double dz,bool onGround);
/// <summary> /// <summary>
/// Called when an entity moved to fixed coordinates /// Called when an entity moved to fixed coordinates
@ -182,28 +170,28 @@ namespace MinecraftClient.Protocol
/// <param name="Dy">Y</param> /// <param name="Dy">Y</param>
/// <param name="Dz">Z</param> /// <param name="Dz">Z</param>
/// <param name="onGround">TRUE if on ground</param> /// <param name="onGround">TRUE if on ground</param>
void OnEntityTeleport(int EntityID, Double X, Double Y, Double Z, bool onGround); void OnEntityTeleport(int entityID, Double x, Double y, Double z, bool onGround);
/// <summary> /// <summary>
/// Called when additional properties have been received for an entity /// Called when additional properties have been received for an entity
/// </summary> /// </summary>
/// <param name="EntityID">Entity ID</param> /// <param name="EntityID">Entity ID</param>
/// <param name="prop">Dictionary of properties</param> /// <param name="prop">Dictionary of properties</param>
void OnEntityProperties(int EntityID, Dictionary<string, Double> prop); void OnEntityProperties(int entityID, Dictionary<string, Double> prop);
/// <summary> /// <summary>
/// Called when the world age has been updated /// Called when the world age has been updated
/// </summary> /// </summary>
/// <param name="WorldAge">World age</param> /// <param name="WorldAge">World age</param>
/// <param name="TimeOfDay">Time of Day</param> /// <param name="TimeOfDay">Time of Day</param>
void OnTimeUpdate(long WorldAge, long TimeOfDay); void OnTimeUpdate(long worldAge, long timeOfDay);
/// <summary> /// <summary>
/// Called when inventory items have been received /// Called when inventory items have been received
/// </summary> /// </summary>
/// <param name="inventoryID">Inventory ID</param> /// <param name="inventoryID">Inventory ID</param>
/// <param name="itemList">Item list</param> /// <param name="itemList">Item list</param>
void OnWindowItems(byte inventoryID, Dictionary<int, MinecraftClient.Inventory.Item> itemList); void OnWindowItems(byte inventoryID, Dictionary<int, Item> itemList);
/// <summary> /// <summary>
/// Called when a single slot has been updated inside an inventory /// Called when a single slot has been updated inside an inventory