NMS How to override default Minecraft mobs

Discussion in 'Resources' started by TeeePeee, Jan 6, 2014.

Thread Status:
Not open for further replies.
  1. Jalau
    How did you spawn the CustomZombies manually??
     
  2. Offline

    Jalau

    DoppelRR
    CustomZombie z = new CustomZombie(location.getWorld());
    z.setLocation(location.getBlockX(), location.getBlockY(), location.getBlockZ(), 0, 0);
    ((CraftWorld)location.getWorld()).getHandle().addEntity(z, SpawnReason.CUSTOM);
     
    DoppelRR likes this.
  3. TeeePeee
    Should this work for Falling Blocks too?
    They are not extending EntityInsentient, so i just changed every Class<? extends EntityInsentient> to Class<?>.
    But now every time i spawn the Entity my Server crashes giving me an Entity Ticking Exception.
    do you know whats the Problem about this??

    DoppelRR

    BorisTheTerrible
    Im not sure who did it but i found after Long Research another method wich Registers an custom entity without replacing.
    Code:
     @SuppressWarnings("unchecked")
        public static void registerEntity(String name, int id, Class<? extends EntityInsentient> customClass) {
            try {
                List<Map<?, ?>> dataMaps = new ArrayList<Map<?, ?>>();
                for (Field f : EntityTypes.class.getDeclaredFields()) {
                    if (f.getType().getSimpleName().equals(Map.class.getSimpleName())) {
                        f.setAccessible(true);
                        dataMaps.add((Map<?, ?>) f.get(null));
                    }
                }
                ((Map<Class<? extends EntityInsentient>, String>) dataMaps.get(1)).put(customClass, name);
                ((Map<Class<? extends EntityInsentient>, Integer>) dataMaps.get(3)).put(customClass, id);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    for me this works fine just add it to your CustomEntityType.class and call it in your onEnable().

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jan 25, 2016
  4. Offline

    TeeePeee

    DoppelRR
    I'd have to test that out but I know you can just do something like:
    Blocks.REGISTRY.put(...);
    Or something similar to replace a normal block class with a custom one. I've done it on my home computer but I'm in Paris right now so I can't give any example code or test the overriding.
    Pacothegint
    Post the custom entity class giving the error if you still have it and I'll see what I can do.
     
  5. TeeePeee
    Thx for the quick answer,
    it would be nice if you could give me an code example when you're back.
    Ohh, and maybe you want to add the method just above youre post to the tutorial, not everybody wants to replace the old entity.

    DoppelRR
     
  6. Offline

    Force_Update1

    Hello,
    I have make a CustomBat Class, but why is not performed unleash event

    Code:java
    1. Bat entity = (Bat) bat.getBukkitEntity();
    2. entity.setLeashHolder(player);
     
  7. Offline

    TeeePeee

    DoppelRR
    That won't be for another week. You'll have to remind me via. a tahg or PM at that time. I'll also try to edit in the method you provided.

    Force_Update1
    It should be firing the event unless you overrode the leashing method. Provide your code and I'll see.
     
  8. Offline

    McPhillygin

    TeeePeee I have a problem, no error... yet. As I log into my server my Minecraft client crashes. not sure of what but if you have any idea, Please let me know! :/

    This is every time I reload the server... it may have something to do with registering and unregistering the entities? Not sure though.
     
  9. Offline

    TeeePeee

    McPhillygin
    If you spawn in an unregistered entity, the client will crash. Otherwise, it's hard to say without seeing some code.
     
    ChipDev likes this.
  10. Offline

    McPhillygin

    TeeePeee Here is my code... Need a lot of help with it. Not sure of what is wrong... for now I can only spawn by eggs and then on a reload my client crashes.

    CustomEntityType Enum
    Code:java
    1.  
    2. package me.mcphillygin.NMSTut;
    3.  
    4. import java.lang.reflect.Field;
    5.  
    6. import java.util.List;
    7.  
    8. import java.util.Map;
    9.  
    10. import net.minecraft.server.v1_7_R3.BiomeBase;
    11.  
    12. import net.minecraft.server.v1_7_R3.BiomeMeta;
    13.  
    14. import net.minecraft.server.v1_7_R3.EntityInsentient;
    15.  
    16. import net.minecraft.server.v1_7_R3.EntityTypes;
    17.  
    18. import net.minecraft.server.v1_7_R3.EntityZombie;
    19.  
    20. import org.bukkit.entity.EntityType;
    21.  
    22. public enum CustomEntityType {
    23.  
    24.  
    25.  
    26.  
    27.  
    28. ZOMBIE("Zombie", 54, EntityType.ZOMBIE, EntityZombie.class, CustomEntityZombie.class);
    29.  
    30.  
    31.  
    32. private String name;
    33.  
    34.  
    35.  
    36. private int id;
    37.  
    38.  
    39.  
    40. private EntityType entityType;
    41.  
    42.  
    43.  
    44. private Class<? extends EntityInsentient> nmsClass;
    45.  
    46.  
    47.  
    48. private Class<? extends EntityInsentient> customClass;
    49.  
    50.  
    51.  
    52. private CustomEntityType(String name, int id, EntityType entityType, Class<? extends EntityInsentient> nmsClass, Class<? extends EntityInsentient> customClass) {
    53.  
    54.  
    55.  
    56. this.name = name;
    57.  
    58.  
    59.  
    60. this.id = id;
    61.  
    62.  
    63.  
    64. this.entityType = entityType;
    65.  
    66.  
    67.  
    68. this.nmsClass = nmsClass;
    69.  
    70.  
    71.  
    72. this.customClass = customClass;
    73.  
    74. }
    75.  
    76.  
    77.  
    78. public String getName() {
    79.  
    80. return name;
    81.  
    82. }
    83.  
    84.  
    85.  
    86. public int getID() {
    87.  
    88. return id;
    89.  
    90. }
    91.  
    92.  
    93.  
    94. public EntityType getEntityType() {
    95.  
    96. return entityType;
    97.  
    98. }
    99.  
    100.  
    101.  
    102. public Class<? extends EntityInsentient> getNMSClass() {
    103.  
    104. return nmsClass;
    105.  
    106. }
    107.  
    108.  
    109.  
    110. public Class<? extends EntityInsentient> getCustomClass() {
    111.  
    112. return customClass;
    113.  
    114. }
    115.  
    116.  
    117.  
    118. /**
    119.  
    120. * Register our entities
    121.  
    122. */
    123.  
    124.  
    125.  
    126. public static void registerEntites() {
    127.  
    128. for (CustomEntityType entity : values())
    129.  
    130. a(entity.getCustomClass(), entity.getName(), entity.getID());
    131.  
    132.  
    133.  
    134.  
    135.  
    136. //BiomeBase#Biomes become private.
    137.  
    138.  
    139.  
    140. BiomeBase[] biomes;
    141.  
    142.  
    143.  
    144. try {
    145.  
    146. biomes = (BiomeBase[]) getPrivateStatic(BiomeBase.class, "biomes");
    147.  
    148.  
    149.  
    150. } catch (Exception e){
    151.  
    152. //unable to fetch
    153.  
    154. return;
    155.  
    156. }
    157.  
    158.  
    159.  
    160. for (BiomeBase biomeBase : biomes){
    161.  
    162. if (biomeBase == null)
    163.  
    164. break;
    165.  
    166.  
    167.  
    168.  
    169.  
    170. //this changed names from J, K, L, and M.
    171.  
    172.  
    173.  
    174. for (String field : new String[] { "as", "at", "au", "av"})
    175.  
    176.  
    177.  
    178. try {
    179.  
    180. Field list = BiomeBase.class.getDeclaredField(field);
    181.  
    182. list.setAccessible(true);
    183.  
    184. @SuppressWarnings("unchecked")
    185.  
    186. List<BiomeMeta> mobList = (List<BiomeMeta>) list.get(biomeBase);
    187.  
    188.  
    189.  
    190. //Write in our custom class.
    191.  
    192.  
    193.  
    194. for (BiomeMeta meta : mobList)
    195.  
    196.  
    197.  
    198. for (CustomEntityType entity : values())
    199.  
    200.  
    201.  
    202. if (entity.getNMSClass().equals(meta.b))
    203.  
    204.  
    205.  
    206. meta.b = entity.getCustomClass();
    207.  
    208.  
    209.  
    210. } catch (Exception e) {
    211.  
    212. e.printStackTrace();
    213.  
    214. }
    215.  
    216. }
    217.  
    218. }
    219.  
    220.  
    221.  
    222. /**
    223.  
    224. * Unregister our entities to avoid memory leakage.
    225.  
    226. */
    227.  
    228.  
    229.  
    230. @SuppressWarnings("rawtypes")
    231.  
    232. public static void unregisterEntities() {
    233.  
    234.  
    235.  
    236. for (CustomEntityType entity : values()){
    237.  
    238.  
    239.  
    240. //remove our class reference
    241.  
    242.  
    243.  
    244. try {
    245.  
    246. ((Map) getPrivateStatic(EntityTypes.class, "d")).remove(entity.getCustomClass());
    247.  
    248. } catch (Exception e) {
    249.  
    250. e.printStackTrace();
    251.  
    252. }
    253.  
    254. try {
    255.  
    256. ((Map) getPrivateStatic(EntityTypes.class, "f")).remove(entity.getCustomClass());
    257.  
    258. } catch (Exception e) {
    259.  
    260. e.printStackTrace();
    261.  
    262. }
    263.  
    264. }
    265.  
    266.  
    267.  
    268. for (CustomEntityType entity : values())
    269.  
    270. try {
    271.  
    272. // Unregister each entity by writing the NMS back in place of the custom class.
    273.  
    274. a(entity.getNMSClass(), entity.getName(), entity.getID());
    275.  
    276. } catch (Exception e) {
    277.  
    278. e.printStackTrace();
    279.  
    280. }
    281.  
    282.  
    283.  
    284. // Biomes#biomes was made private so use reflection to get it.
    285.  
    286. BiomeBase[] biomes;
    287.  
    288. try {
    289.  
    290. biomes = (BiomeBase[]) getPrivateStatic(BiomeBase.class, "biomes");
    291.  
    292. } catch (Exception exc) {
    293.  
    294. // Unable to fetch.
    295.  
    296. return;
    297.  
    298. }
    299.  
    300.  
    301.  
    302. for (BiomeBase biomeBase : biomes) {
    303.  
    304. if (biomeBase == null) break;
    305.  
    306. // The list fields changed names but update the meta regardless.
    307.  
    308. for (String field : new String[] { "as", "at", "au", "av" })
    309.  
    310. try {
    311.  
    312. Field list = BiomeBase.class.getDeclaredField(field);
    313.  
    314. list.setAccessible(true);
    315.  
    316. @SuppressWarnings("unchecked")
    317.  
    318. List<BiomeMeta> mobList = (List<BiomeMeta>) list.get(biomeBase);
    319.  
    320. // Make sure the NMS class is written back over our custom class.
    321.  
    322. for (BiomeMeta meta : mobList)
    323.  
    324. for (CustomEntityType entity : values())
    325.  
    326. if (entity.getCustomClass().equals(meta.b))
    327.  
    328. meta.b = entity.getNMSClass();
    329.  
    330.  
    331.  
    332. } catch (Exception e) {
    333.  
    334. e.printStackTrace();
    335.  
    336. }
    337.  
    338.  
    339.  
    340.  
    341.  
    342. }
    343.  
    344. }
    345.  
    346.  
    347.  
    348. /**
    349.  
    350. * A convenience method.
    351.  
    352. * @param clazz The class.
    353.  
    354. * @param f The string representation of the private static field.
    355.  
    356. * @return The object found
    357.  
    358. * @throws Exception if unable to get the object.
    359.  
    360. */
    361.  
    362.  
    363.  
    364.  
    365.  
    366. @SuppressWarnings("rawtypes")
    367.  
    368. private static Object getPrivateStatic(Class clazz, String f) throws Exception {
    369.  
    370. Field field = clazz.getDeclaredField(f);
    371.  
    372. field.setAccessible(true);
    373.  
    374. return field.get(null);
    375.  
    376. }
    377.  
    378.  
    379.  
    380. /*
    381.  
    382. * Since 1.7.2 added a check in their entity registration, simply bypass it and write to the maps ourself.
    383.  
    384. */
    385.  
    386.  
    387.  
    388. @SuppressWarnings({ "unchecked", "rawtypes" })
    389.  
    390. private static void a(Class paramClass, String paramString, int paramInt) {
    391.  
    392. try {
    393.  
    394. ((Map) getPrivateStatic(EntityTypes.class, "c")).put(paramString, paramClass);
    395.  
    396. ((Map) getPrivateStatic(EntityTypes.class, "d")).put(paramClass, paramString);
    397.  
    398. ((Map) getPrivateStatic(EntityTypes.class, "e")).put(Integer.valueOf(paramInt), paramClass);
    399.  
    400. ((Map) getPrivateStatic(EntityTypes.class, "f")).put(paramClass, Integer.valueOf(paramInt));
    401.  
    402. ((Map) getPrivateStatic(EntityTypes.class, "g")).put(paramString, Integer.valueOf(paramInt));
    403.  
    404. } catch (Exception exc) {
    405.  
    406. // Unable to register the new class.
    407.  
    408. }
    409.  
    410.  
    411.  
    412. }
    413.  
    414. }
    415.  


    CustomEntityZombie Class

    Code:java
    1.  
    2. package me.mcphillygin.NMSTut;
    3.  
    4. import java.lang.reflect.Field;
    5.  
    6. import net.minecraft.server.v1_7_R3.EntityHuman;
    7.  
    8. import net.minecraft.server.v1_7_R3.EntityZombie;
    9.  
    10. import net.minecraft.server.v1_7_R3.GenericAttributes;
    11.  
    12. import net.minecraft.server.v1_7_R3.PathfinderGoalFloat;
    13.  
    14. import net.minecraft.server.v1_7_R3.PathfinderGoalHurtByTarget;
    15.  
    16. import net.minecraft.server.v1_7_R3.PathfinderGoalLookAtPlayer;
    17.  
    18. import net.minecraft.server.v1_7_R3.PathfinderGoalMeleeAttack;
    19.  
    20. import net.minecraft.server.v1_7_R3.PathfinderGoalMoveThroughVillage;
    21.  
    22. import net.minecraft.server.v1_7_R3.PathfinderGoalMoveTowardsRestriction;
    23.  
    24. import net.minecraft.server.v1_7_R3.PathfinderGoalNearestAttackableTarget;
    25.  
    26. import net.minecraft.server.v1_7_R3.PathfinderGoalRandomLookaround;
    27.  
    28. import net.minecraft.server.v1_7_R3.PathfinderGoalRandomStroll;
    29.  
    30. import net.minecraft.server.v1_7_R3.PathfinderGoalSelector;
    31.  
    32. import net.minecraft.server.v1_7_R3.World;
    33.  
    34. import org.bukkit.craftbukkit.v1_7_R3.util.UnsafeList;
    35.  
    36. public class CustomEntityZombie extends EntityZombie{
    37.  
    38. public CustomEntityZombie(World world) {
    39.  
    40. super(world);
    41.  
    42.  
    43.  
    44.  
    45.  
    46. try {
    47.  
    48. Field bField = PathfinderGoalSelector.class.getDeclaredField("b");
    49.  
    50. bField.setAccessible(true);
    51.  
    52. Field cField = PathfinderGoalSelector.class.getDeclaredField("c");
    53.  
    54. cField.setAccessible(true);
    55.  
    56. bField.set(goalSelector, new UnsafeList<PathfinderGoalSelector>());
    57.  
    58. bField.set(targetSelector, new UnsafeList<PathfinderGoalSelector>());
    59.  
    60. cField.set(goalSelector, new UnsafeList<PathfinderGoalSelector>());
    61.  
    62. cField.set(targetSelector, new UnsafeList<PathfinderGoalSelector>());
    63.  
    64. } catch (Exception e) {
    65.  
    66. e.printStackTrace();
    67.  
    68. }
    69.  
    70.  
    71.  
    72. this.goalSelector.a(0, new PathfinderGoalFloat(this));
    73.  
    74. this.goalSelector.a(2, new PathfinderGoalMeleeAttack(this, EntityHuman.class, 1.0D, false));
    75.  
    76. this.goalSelector.a(5, new PathfinderGoalMoveTowardsRestriction(this, 1.0D));
    77.  
    78. this.goalSelector.a(6, new PathfinderGoalMoveThroughVillage(this, 1.0D, false));
    79.  
    80. this.goalSelector.a(7, new PathfinderGoalRandomStroll(this, 1.0D));
    81.  
    82. this.goalSelector.a(8, new PathfinderGoalLookAtPlayer(this, EntityHuman.class, 8.0F));
    83.  
    84. this.goalSelector.a(8, new PathfinderGoalRandomLookaround(this));
    85.  
    86. this.targetSelector.a(1, new PathfinderGoalHurtByTarget(this, true));
    87.  
    88. this.targetSelector.a(2, new PathfinderGoalNearestAttackableTarget(this, EntityHuman.class, 0, true));
    89.  
    90. }
    91.  
    92.  
    93.  
    94. @Override
    95.  
    96. protected void aC() {
    97.  
    98. super.aC();
    99.  
    100. this.bb().b(GenericAttributes.e);
    101.  
    102. this.getAttributeInstance(GenericAttributes.e).setValue(300.0D);
    103.  
    104. }
    105.  
    106.  
    107.  
    108.  
    109.  
    110. }
    111.  


    Main class

    Code:java
    1.  
    2. package me.mcphillygin.NMSTut;
    3.  
    4. import org.bukkit.plugin.java.JavaPlugin;
    5.  
    6. public class Main extends JavaPlugin{
    7.  
    8.  
    9.  
    10. public void onEnable() {
    11.  
    12.  
    13. this.getServer().getLogger().info("First NMS Plugin has been enabled.");
    14.  
    15. CustomEntityType.registerEntites();
    16.  
    17. }
    18.  
    19.  
    20.  
    21. public void onDisable() {
    22.  
    23. CustomEntityType.unregisterEntities();
    24.  
    25. }
    26.  
    27.  
    28.  
    29. }
    30.  


    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jan 25, 2016
  11. Offline

    TeeePeee

    McPhillygin
    You should be looping through all the entities in the world and despawning any custom ones when the plugin is disabled before you unregister the custom entities.

    And next time, please Pastebin your code and post it in one post.
     
  12. Offline

    McPhillygin

    TeeePeee Could you by any chance show me or direct me towards doing that? And okay I will use pastebin next time.
     
  13. Offline

    TeeePeee

    McPhillygin
    Your onDisable should look like the following:

    Code:java
    1. public void onDisable() {
    2. for(World world : Bukkit.getWorlds()) {
    3. for(Entity e : world.getEntities()) {
    4. // You can change this to see if it's a CraftLivingEntity and if so, if it's CraftLivingEntity#getHandle() is an instance of your custom mob.
    5. // Alternatively you can change this to check if the entity has any fixed metadata set (that you would set on spawn) to see if it's a custom mob.
    6. if(e.getType() == EntityType.ZOMBIE) {
    7. e.remove();
    8. }
    9. }
    10. }
    11. CustomEntityType.unregisterEntities();
    12. }
     
  14. Offline

    McPhillygin

    Thank you TeeePeee , I will try and see if this works :)

    TeeePeee well, My Client does not crash, just now the errors come...

    it is just a few of these:
    java.lang.IllegalArgumentException: Attribute is already registered!
    and
    java.lang.reflect.InvocationTargetException

    Sorry for being a noob at this type of code :/

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jan 25, 2016
  15. Offline

    gilgamesh523

    Any idea on how to change the mobs AI so that it will change from friendly to attack when angered, sort of like a zombie pigman. I want to change it so a cow does this and I can have cows that attack people on my server.
     
  16. gilgamesh523
    You can make an cuatom Zombie pigman and when you add it to the enum and use the cowname and cow id instead of the Zombie pigmans Name and id.

    TeeePeee
    You told me to come back on my question about custom falling blocks a the end of the week.
    So here i am.
     
  17. Offline

    gilgamesh523

  18. Offline

    TeeePeee

    McPhillygin Maybe try removing this.bb().b(GenericAttributes.e); although I'm not positive. I haven't had the time to work out attributes 100%.

    DoppelRR
    Perfect timing.

    I was going to suggest doing the following in order to have custom blocks, but it only occurred to me now that a default falling block will still spawn. Here's the code regardless, in case it helps you:

    (see Block.java)
    Code:java
    1. Block.REGISTRY.a(/*block ID*/47, /*block name*/"bookshelf", /*block with attributes*/((CustomBlockBookshelf) (new CustomBlockBookshelf()).c(1.5F).a(Block.f).c("bookshelf")).d("bookshelf"));


    Otherwise, I believe that what you're doing should work. The ticking exception may be caused for a variety of reasons, but many times, it's actually another error. If you look at your entire stack trace, you should see Caused by: followed by the real issue. Very possibly it's a CME or a NPE. If you post your custom falling block class, I can take a look.
     
  19. TeeePeee
    Just tried my old code, was working on something else,
    it works now im not sure what the Problem was but its away now.
     
  20. Offline

    qsik

    I can't seem to get custom zombies to defend the player like wolves do. I got them to follow me but they just stare if I attack mobs or am attacked by mobs. Is there something I missed when I copied the PathfinderGoalOwnerHurtByTarget/HurtTarget code?
     
  21. Offline

    TeeePeee

    qsik
    When you copied the code, did you:
    a) Change EntityTameableAnimal to EntityInsentient
    b) Remove the check for isTamed()
    c) Change the call to getOwner() to one that works to retrieve the player

    I'm not sure how you've got the zombie following the player. Likely it's a custom PathfinderGoalFollowOwner and if so, the getOwner() call will work.
     
  22. Offline

    qsik

    I did make a custom PathfinderGoalFollowOwner, changing the parameters listed above. I tried to do the same with PathfinderGoalOwnerHurtTarget and OwnerHurtByTarget but it doesn't seem to work properly. They just stand and stare while I hit other mobs (like a spider).
     
  23. Offline

    qsik

    Nevermind, I got it to work after digging deeper into the NMS code.
     
  24. Offline

    XLordalX

    TeeePeee

    If the chunk of a custom entity gets unloaded and then loaded again, the entity disappears with this message in the console: "Skipping Entity with id <id>". How can I fix this?
     
  25. Offline

    TeeePeee

    XLordalX
    I believe this will happen if the plugin gets disabled (whether it's reenabled or not) while a custom entity is still in the world. Make sure the plugin isn't getting disabled and it should be fine.

    Otherwise, the quick and dirty solution would be to spawn in a copy of the entity onChunkLoad... I haven't experienced the problem myself and I don't have the time to check NMS code so I'm not entirely sure what its solution is.
     
  26. Offline

    1928i

    TeeePeee Whenever I try to use this code I get errors in the CustomEntityType class. On "Map" and "class" It says they need to be parameterized. Can you help?

    Code:
     package me.i1928i.Prison;
     
    import java.lang.reflect.Field;
    import java.util.List;
    import java.util.Map;
     
    import net.minecraft.server.v1_7_R3.BiomeBase;
    import net.minecraft.server.v1_7_R3.BiomeMeta;
    import net.minecraft.server.v1_7_R3.EntityInsentient;
    import net.minecraft.server.v1_7_R3.EntityTypes;
    import net.minecraft.server.v1_7_R3.EntityZombie;
     
    import org.bukkit.entity.EntityType;
     
    public enum CustomEntityType {
     
    ZOMBIE("Zombie", 54, EntityType.ZOMBIE, EntityZombie.class, CustomEntityZombie.class);
     
    private String name;
    private int id;
    private EntityType entityType;
    private Class<? extends EntityInsentient> nmsClass;
    private Class<? extends EntityInsentient> customClass;
     
    private CustomEntityType(String name, int id, EntityType entityType, Class<? extends EntityInsentient> nmsClass,
    Class<? extends EntityInsentient> customClass) {
    this.name = name;
    this.id = id;
    this.entityType = entityType;
    this.nmsClass = nmsClass;
    this.customClass = customClass;
    }
     
    public String getName() {
    return name;
    }
     
    public int getID() {
    return id;
    }
     
    public EntityType getEntityType() {
    return entityType;
    }
     
    public Class<? extends EntityInsentient> getNMSClass() {
    return nmsClass;
    }
     
    public Class<? extends EntityInsentient> getCustomClass() {
    return customClass;
    }
     
    /**
    * Register our entities.
    */
    public static void registerEntities() {
    for (CustomEntityType entity : values())
    a(entity.getCustomClass(), entity.getName(), entity.getID());
     
    // BiomeBase#biomes became private.
    BiomeBase[] biomes;
    try {
    biomes = (BiomeBase[]) getPrivateStatic(BiomeBase.class, "biomes");
    } catch (Exception exc) {
    // Unable to fetch.
    return;
    }
    for (BiomeBase biomeBase : biomes) {
    if (biomeBase == null)
    break;
     
    // This changed names from J, K, L and M.
    for (String field : new String[] { "as", "at", "au", "av" })
    try {
    Field list = BiomeBase.class.getDeclaredField(field);
    list.setAccessible(true);
    @SuppressWarnings("unchecked")
    List<BiomeMeta> mobList = (List<BiomeMeta>) list.get(biomeBase);
     
    // Write in our custom class.
    for (BiomeMeta meta : mobList)
    for (CustomEntityType entity : values())
    if (entity.getNMSClass().equals(meta.b))
    meta.b = entity.getCustomClass();
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
     
    /**
    * Unregister our entities to prevent memory leaks. Call on disable.
    */
    public static void unregisterEntities() {
    for (CustomEntityType entity : values()) {
    // Remove our class references.
    try {
    ((Map) getPrivateStatic(EntityTypes.class, "d")).remove(entity.getCustomClass());
    } catch (Exception e) {
    e.printStackTrace();
    }
     
    try {
    ((Map) getPrivateStatic(EntityTypes.class, "f")).remove(entity.getCustomClass());
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
     
    for (CustomEntityType entity : values())
    try {
    // Unregister each entity by writing the NMS back in place of the custom class.
    a(entity.getNMSClass(), entity.getName(), entity.getID());
    } catch (Exception e) {
    e.printStackTrace();
    }
     
    // Biomes#biomes was made private so use reflection to get it.
    BiomeBase[] biomes;
    try {
    biomes = (BiomeBase[]) getPrivateStatic(BiomeBase.class, "biomes");
    } catch (Exception exc) {
    // Unable to fetch.
    return;
    }
    for (BiomeBase biomeBase : biomes) {
    if (biomeBase == null)
    break;
     
    // The list fields changed names but update the meta regardless.
    for (String field : new String[] { "as", "at", "au", "av" })
    try {
    Field list = BiomeBase.class.getDeclaredField(field);
    list.setAccessible(true);
    @SuppressWarnings("unchecked")
    List<BiomeMeta> mobList = (List<BiomeMeta>) list.get(biomeBase);
     
    // Make sure the NMS class is written back over our custom class.
    for (BiomeMeta meta : mobList)
    for (CustomEntityType entity : values())
    if (entity.getCustomClass().equals(meta.b))
    meta.b = entity.getNMSClass();
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    }
     
    /**
    * A convenience method.
    * @param clazz The class.
    * @param f The string representation of the private static field.
    * @return The object found
    * @throws Exception if unable to get the object.
    */
    private static Object getPrivateStatic(Class clazz, String f) throws Exception {
    Field field = clazz.getDeclaredField(f);
    field.setAccessible(true);
    return field.get(null);
    }
     
    /*
    * Since 1.7.2 added a check in their entity registration, simply bypass it and write to the maps ourself.
    */
    private static void a(Class paramClass, String paramString, int paramInt) {
    try {
    ((Map) getPrivateStatic(EntityTypes.class, "c")).put(paramString, paramClass);
    ((Map) getPrivateStatic(EntityTypes.class, "d")).put(paramClass, paramString);
    ((Map) getPrivateStatic(EntityTypes.class, "e")).put(Integer.valueOf(paramInt), paramClass);
    ((Map) getPrivateStatic(EntityTypes.class, "f")).put(paramClass, Integer.valueOf(paramInt));
    ((Map) getPrivateStatic(EntityTypes.class, "g")).put(paramString, Integer.valueOf(paramInt));
    } catch (Exception exc) {
    // Unable to register the new class.
    }
    }
    }
     
  27. Offline

    xTigerRebornx

    1928i Not sure why you think making another post for a problem that multiple people have told you how to solve would change anything, it won't. The solution persists, it is valid, and you should expect the same response from those who you keep going to.
     
    TeeePeee likes this.
  28. Offline

    XLordalX

    TeeePeee As far as I can tell it happends when the entity is null when the chunk loads. I don't know why my entity becomes null though.
     
  29. Offline

    XLordalX

    Bump, still not fixed.
     
  30. Offline

    pongo1231

    How would I create multiple classes for one Entity and let it randomly choose, which one to spawn each time?
     
Thread Status:
Not open for further replies.

Share This Page