Solved How to spawn custom animals in v1.14+?

Discussion in 'Plugin Development' started by Ice Drake, Jul 16, 2020.

  1. Offline

    Ice Drake

    Hi, I am slowly getting familiar with the plugin development after successfully finishing two plugins so far. Now on my third plugin, I am completely stuck on how to spawn a custom animal, in particular, tameable ocelot, to the world.

    So far, I found two methods of spawning custom animals or mobs: bukkit method and NMS method.

    Method A: Using bukkit method, I believe I can spawn my ocelot via the code below:
    Code:
    private class OcelotListener implements Listener {
            @EventHandler
            public void onCreatureSpawn(CreatureSpawnEvent evt) {
                Entity entity = evt.getEntity();
                if (entity instanceof Ocelot && !(entity instanceof TameableOcelot)) {
                    entity.getWorld().spawn(evt.getLocation(), TameableOcelot.class);
                    evt.setCancelled(true);
                }
            }
        }
    Given that TameableOcelot implements Ocelot, Tameable, and Sittable.

    CONS:
    I have to initialize all the default meta data of an ocelot in the TameableOcelot class. Also, the original ocelot always get initialized, then get destroyed, and recreate with the new custom one. It is a waste of resources if I can't reused the existing one or stop it from creating one in the first place.

    Questions:
    1. Does this method even work? Is bukkit API smart enough to know that Ocelot is now tameable and sittable?
    2. Is there any other issues I should be aware of when using this method?

    Method B: Using NMS (net.minecraft.server) method, I can simplify the implementation of the TameableOcelot to extend from EntityOcelot to modify only what I needed, but I don't know how to spawn it as it seems that I need to register it somehow like how it is done in v1.13+. Also, I don't know how to write the constructor for it.
    Code:
    public EntityOcelot(EntityTypes<? extends EntityOcelot> entitytypes, World world)
    The reason is that I don't know if I should use EntityOcelot::new or TameableOcelot::new when supplying for entitytypes parameter.
    Code:
    public static final EntityTypes<EntityOcelot> OCELOT = a("ocelot", a.<Entity>a(EntityOcelot::new, EnumCreatureType.CREATURE).a(0.6F, 0.7F));
    CONS:
    I would have to write a separate version of this plugin if I want it to work on v1.15 and v1.16 in the future.

    Questions:
    1. How do I spawn the custom animal?
    2. How should I instantiate the constructor of EntityOcelot in the constructor of TameableOcelot?
    3. Is there issues when using this method?
     
  2. Offline

    Ice Drake

    After studying various codes in various sites, it seems that spawning a custom animal or mobs is not possible using bukkit method. NMS method is the only solution. While it seems that you can do almost everything with this approach, it is limiting as well. You can't make a pig tameable likewise you can't make a tropical fish attack unless, of course, you use Lib's Disguises plugin to disguise a wolf as a pig or you modify the server itself. If you want to use this method, you might as well make things simple for yourself by using MythicMobs plugin for that purpose then.

    Going back to the questions, how do you spawn a custom animal?
    Code:
    public class EntityTameableOcelot extends EntityCat {
        public EntityTameableOcelot(Location location) {
            super(EntityTypes.CAT, ((CraftWorld)location.getWorld()).getHandle());
            setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
        }
        ...
    }
    Code:
    public void onPlayerJoin(PlayerJoinEvent evt) {
        Player player = evt.getPlayer();
        Location location = player.getLocation();
        WorldServer world = ((CraftWorld)player.getWorld()).getHandle();
        EntityTameableCat ocelot = new EntityTameableCat(location);
        world.addEntity(ocelot);
    }
    This code will spawn a custom cat. To make it look like an ocelot, you need to use ProtocolLib if you want to be challenged or use Lib's Disguises with the additional code below:
    Code:
    CraftTameableOcelot craftOcelot = new CraftTameableOcelot((CraftServer)getServer(), ocelot);
    MobDisguise disguise = new MobDisguise(DisguiseType.OCELOT);
    DisguiseAPI.disguiseEntity(craftOcelot, disguise);
    Of course, if you tried to tame it in-game, you will crash the server with Lib's Disguises. It seems that you might need to do something else from this point onward, but I am not going to bother with this issue any further since I can accomplish this task just by using MythicMobs. There is no point to re-invent the wheel.
     
    Last edited: Jul 28, 2020

Share This Page