[Tutorial] Creating custom entities with PathfinderGoals

Discussion in 'Spigot Plugin Development' started by XlordalX, May 11, 2014.

  1. A nice tutorial. Thanks, but can spawn golems ¿
     
  2. @Frekit instead of extending EntityZombie, extend EntityIronGolem
     
  3. Any way to set a mobs pathfinder in a util class. Im adding in 3 versions of each mob: good/evil/neutral. And they attack each other accordingly. Its like 30 classes, and I know I need 30 classes, but I wanna cut down on the code inside these.
     
  4. I am getting an error, and I don't have a clue why.
    Console:
    Code (Text):
    Caused by: java.lang.NullPointerException
            at me.skyGeneral.customEntity.CustomZombie.<init>(CustomZombie.java:24)
    Lines 22-24 in class CustomZombie:

    Code (Text):
    public class CustomZombie extends EntityZombie {
        public CustomZombie(org.bukkit.World world){
            super(((CraftWorld)world).getHandle());
    Imports that I think are needed to know:

    Code (Text):
    import net.minecraft.server.v1_7_R3.EntityZombie;
    import org.bukkit.craftbukkit.v1_7_R3.CraftWorld;
    Anyone know what I am messing up on?

    P.S. The server is running off the save craftbukkit version that I have in my libraries.
     
  5. Yeah.. I realized that soon after I posted.. I felt really dumb, and forgot to post that I figured it out.
     
  6. I need some help. From your tutorial i tried to create a chicken that will follow a determined player. But it's not what happen. i clear all the pathfinders and i add one similar to FollowOwner. However it makes my server crash because i try to cast a player to an entity. Someone could help ?
     
  7. @Madricas start by posting the code & stacktrace.
     
    • Like Like x 1
    • Agree Agree x 1
  8. Code (Text):
    package fr.madricas;

    import java.lang.reflect.Field;

    import net.minecraft.server.v1_7_R4.Entity;
    import net.minecraft.server.v1_7_R4.EntityChicken;
    import net.minecraft.server.v1_7_R4.EntityHuman;
    import net.minecraft.server.v1_7_R4.EntityOwnable;
    import net.minecraft.server.v1_7_R4.PathfinderGoalFloat;
    import net.minecraft.server.v1_7_R4.PathfinderGoalLookAtPlayer;
    import net.minecraft.server.v1_7_R4.PathfinderGoalRandomStroll;
    import net.minecraft.server.v1_7_R4.PathfinderGoalSelector;
    import net.minecraft.server.v1_7_R4.World;

    import org.bukkit.craftbukkit.v1_7_R4.util.UnsafeList;
    import org.bukkit.entity.Player;

    public class FollowerChicken extends EntityChicken implements EntityOwnable,
            Chicken {

        public static Player owner;

        public FollowerChicken(World world) {
            super(world);

            // on efface les Pathfinders
            try {
                Field bField = PathfinderGoalSelector.class.getDeclaredField("b");
                bField.setAccessible(true);
                Field cField = PathfinderGoalSelector.class.getDeclaredField("c");
                cField.setAccessible(true);
                bField.set(goalSelector, new UnsafeList<PathfinderGoalSelector>());
                bField.set(targetSelector, new UnsafeList<PathfinderGoalSelector>());
                cField.set(goalSelector, new UnsafeList<PathfinderGoalSelector>());
                cField.set(targetSelector, new UnsafeList<PathfinderGoalSelector>());
            } catch (Exception exc) {
                exc.printStackTrace();
            }

            // On donne au poulet deux Pathfinders, celui de suivre le joueur
            // (son maitre) et de le regarder

            this.goalSelector.a(0, new PathfinderGoalFloat(this));
            this.goalSelector.a(5, new PathfinderGoalRandomStroll(this, 1.0D));
            this.goalSelector.a(6, new PathfinderGoalLookAtPlayer(this,
                    EntityHuman.class, 6.0F));
            this.goalSelector.a(10, new PathFinderGoalFollowPlayer(this, 1.0D,
                     10.0F, 5.0F));
        }

        @Override
        public Entity getOwner() {
            if (FollowerChicken.owner == null)
                return null;
            return (Entity) owner;
        }

        // interface de l'EntityOwnable
        @Override
        public String getOwnerUUID() {
            return null;
        }
    }
     

    Code (Text):
    package fr.madricas;

    import net.minecraft.server.v1_7_R4.Entity;
    import net.minecraft.server.v1_7_R4.EntityLiving;
    import net.minecraft.server.v1_7_R4.IBlockAccess;
    import net.minecraft.server.v1_7_R4.MathHelper;
    import net.minecraft.server.v1_7_R4.Navigation;
    import net.minecraft.server.v1_7_R4.PathfinderGoal;
    import net.minecraft.server.v1_7_R4.World;

    public class PathFinderGoalFollowPlayer extends PathfinderGoal {

        private FollowerChicken d;
        private EntityLiving e;
        World a;
        private double f;
        private Navigation g;
        private int h;
        float b;
        float c;
        private boolean i;

        public PathFinderGoalFollowPlayer(FollowerChicken followerChicken,
                double d0, float f, float f1) {
            this.d = followerChicken;
            this.a = followerChicken.world;
            this.f = d0;
            this.g = followerChicken.getNavigation();
            this.c = f;
            this.b = f1;
            this.a(3);
        }

        public boolean a() {
            EntityLiving entityliving = (EntityLiving) this.d.getOwner();

            if (entityliving == null) {
                return false;
            }
            if (this.d.f(entityliving) < (double) (this.c * this.c)) {
                return false;
            } else {
                this.e = entityliving;
                return true;
            }
        }

        @Override
        public boolean b() {
            return !this.g.g() && this.d.f(this.e) > (double) (this.b * this.b);
        }

        @Override
        public void c() {
            this.h = 0;
            this.i = this.d.getNavigation().a();
            this.d.getNavigation().a(false);
        }

        @Override
        public void d() {
            this.e = null;
            this.g.h();
            this.d.getNavigation().a(this.i);
        }

        @Override
        public void e() {
            this.d.getControllerLook().a(this.e, 10.0F, this.d.x());
            if (--this.h <= 0) {
                this.h = 10;
                if (!this.g.a((Entity) this.e, this.f)) {
                    if (!this.d.bN()) {
                        if (this.d.f(this.e) >= 144.0D) {
                            int i = MathHelper.floor(this.e.locX) - 2;
                            int j = MathHelper.floor(this.e.locZ) - 2;
                            int k = MathHelper.floor(this.e.boundingBox.b);

                            for (int l = 0; l <= 4; ++l) {
                                for (int i1 = 0; i1 <= 4; ++i1) {
                                    if ((l < 1 || i1 < 1 || l > 3 || i1 > 3)
                                            && World.a((IBlockAccess) this.a,
                                                    i + l, k - 1, j + i1)
                                            && !this.a.getType(i + l, k, j + i1)
                                                    .r()
                                            && !this.a
                                                    .getType(i + l, k + 1, j + i1)
                                                    .r()) {
                                        this.d.setPositionRotation(
                                                (double) ((float) (i + l) + 0.5F),
                                                (double) k,
                                                (double) ((float) (j + i1) + 0.5F),
                                                this.d.yaw, this.d.pitch);
                                        this.g.h();
                                        return;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
     

    Code (Text):
    ---- Minecraft Crash Report ----
    // Surprise! Haha. Well, this is awkward.

    Time: 23/10/14 19:42
    Description: Ticking entity

    java.lang.ClassCastException: org.bukkit.craftbukkit.v1_7_R4.entity.CraftPlayer cannot be cast to net.minecraft.server.v1_7_R4.EntityLiving
        at fr.madricas.PathFinderGoalFollowPlayer.a(PathFinderGoalFollowPlayer.java:35)
        at net.minecraft.server.v1_7_R4.PathfinderGoalSelector.a(PathfinderGoalSelector.java:70)
        at net.minecraft.server.v1_7_R4.EntityInsentient.bn(EntityInsentient.java:420)
        at net.minecraft.server.v1_7_R4.EntityLiving.e(EntityLiving.java:1549)
        at net.minecraft.server.v1_7_R4.EntityInsentient.e(EntityInsentient.java:293)
        at net.minecraft.server.v1_7_R4.EntityAgeable.e(EntityAgeable.java:112)
        at net.minecraft.server.v1_7_R4.EntityAnimal.e(SourceFile:37)
        at net.minecraft.server.v1_7_R4.EntityChicken.e(EntityChicken.java:43)
        at net.minecraft.server.v1_7_R4.EntityLiving.h(EntityLiving.java:1409)
        at net.minecraft.server.v1_7_R4.EntityInsentient.h(EntityInsentient.java:154)
        at net.minecraft.server.v1_7_R4.World.entityJoinedWorld(World.java:1620)
        at net.minecraft.server.v1_7_R4.World.playerJoinedWorld(World.java:1595)
        at net.minecraft.server.v1_7_R4.World.tickEntities(World.java:1460)
        at net.minecraft.server.v1_7_R4.WorldServer.tickEntities(WorldServer.java:516)
        at net.minecraft.server.v1_7_R4.MinecraftServer.v(MinecraftServer.java:706)
        at net.minecraft.server.v1_7_R4.DedicatedServer.v(DedicatedServer.java:289)
        at net.minecraft.server.v1_7_R4.MinecraftServer.u(MinecraftServer.java:584)
        at net.minecraft.server.v1_7_R4.MinecraftServer.run(MinecraftServer.java:490)
        at net.minecraft.server.v1_7_R4.ThreadServerApplication.run(SourceFile:628)


    A detailed walkthrough of the error, its code path and all known details is as follows:
    ---------------------------------------------------------------------------------------

    -- Head --
    Stacktrace:
        at fr.madricas.PathFinderGoalFollowPlayer.a(PathFinderGoalFollowPlayer.java:35)
        at net.minecraft.server.v1_7_R4.PathfinderGoalSelector.a(PathfinderGoalSelector.java:70)
        at net.minecraft.server.v1_7_R4.EntityInsentient.bn(EntityInsentient.java:420)
        at net.minecraft.server.v1_7_R4.EntityLiving.e(EntityLiving.java:1549)
        at net.minecraft.server.v1_7_R4.EntityInsentient.e(EntityInsentient.java:293)
        at net.minecraft.server.v1_7_R4.EntityAgeable.e(EntityAgeable.java:112)
        at net.minecraft.server.v1_7_R4.EntityAnimal.e(SourceFile:37)
        at net.minecraft.server.v1_7_R4.EntityChicken.e(EntityChicken.java:43)
        at net.minecraft.server.v1_7_R4.EntityLiving.h(EntityLiving.java:1409)
        at net.minecraft.server.v1_7_R4.EntityInsentient.h(EntityInsentient.java:154)
        at net.minecraft.server.v1_7_R4.World.entityJoinedWorld(World.java:1620)
        at net.minecraft.server.v1_7_R4.World.playerJoinedWorld(World.java:1595)

    -- Entity being ticked --
    Details:
        Entity Type: Chicken (fr.madricas.FollowerChicken)
        Entity ID: 342
        Entity Name: Chicken
        Entity's Exact location: -76,56, 63,30, 239,59
        Entity's Block location: World: (-77,63,239), Chunk: (at 3,3,15 in -5,14; contains blocks -80,0,224 to -65,255,239), Region: (-1,0; contains chunks -32,0 to -1,31, blocks -512,0,0 to -1,255,511)
        Entity's Momentum: 0,00, 0,00, 0,00
    Stacktrace:
        at net.minecraft.server.v1_7_R4.World.tickEntities(World.java:1460)
        at net.minecraft.server.v1_7_R4.WorldServer.tickEntities(WorldServer.java:516)

    -- Affected level --
    Details:
        Level name: world
        All players: 1 total; [EntityPlayer['Madricas'/200, l='world', x=-76,56, y=63,00, z=239,59](Madricas at -76.56347237354227,63.0,239.59090318218765)]
        Chunk stats: ServerChunkCache: 554 Drop: 0
        Level seed: 618395269584543744
        Level generator: ID 00 - default, ver 1. Features enabled: true
        Level generator options:
        Level spawn location: World: (72,64,256), Chunk: (at 8,4,0 in 4,16; contains blocks 64,0,256 to 79,255,271), Region: (0,0; contains chunks 0,0 to 31,31, blocks 0,0,0 to 511,255,511)
        Level time: 455694 game time, 455694 day time
        Level dimension: 0
        Level storage version: 0x04ABD - Anvil
        Level weather: Rain time: 122709 (now: false), thunder time: 8289 (now: true)
        Level game mode: Game mode: survival (ID 0). Hardcore: false. Cheats: false
    Stacktrace:
        at net.minecraft.server.v1_7_R4.MinecraftServer.v(MinecraftServer.java:706)
        at net.minecraft.server.v1_7_R4.DedicatedServer.v(DedicatedServer.java:289)
        at net.minecraft.server.v1_7_R4.MinecraftServer.u(MinecraftServer.java:584)
        at net.minecraft.server.v1_7_R4.MinecraftServer.run(MinecraftServer.java:490)
        at net.minecraft.server.v1_7_R4.ThreadServerApplication.run(SourceFile:628)

    -- System Details --
    Details:
        Minecraft Version: 1.7.10
        Operating System: Windows 8.1 (amd64) version 6.3
        Java Version: 1.7.0_67, Oracle Corporation
        Java VM Version: Java HotSpot(TM) 64-Bit Server VM (mixed mode), Oracle Corporation
        Memory: 362934752 bytes (346 MB) / 690487296 bytes (658 MB) up to 1431830528 bytes (1365 MB)
        JVM Flags: 3 total; -Xms512M -Xmx1536M -XX:MaxPermSize=128M
        AABB Pool Size: 0 (0 bytes; 0 MB) allocated, 0 (0 bytes; 0 MB) used
        IntCache: cache: 0, tcache: 0, allocated: 12, tallocated: 94
        CraftBukkit Information:
       Running: CraftBukkit version git-Spigot-1649 (MC: 1.7.10) (Implementing API version 1.7.10-R0.1-SNAPSHOT) true
       Plugins: { Pouleaaypierre v1.0 fr.madricas.Pouleaypierre [],}
       Warnings: DEFAULT
       Threads: { RUNNABLE Server thread: [java.lang.Thread.dumpThreads(Native Method), java.lang.Thread.getAllStackTraces(Unknown Source), org.bukkit.craftbukkit.v1_7_R4.CraftCrashReport.call(CraftCrashReport.java:28), net.minecraft.server.v1_7_R4.CrashReportSystemDetails.a(SourceFile:74), net.minecraft.server.v1_7_R4.CrashReport.h(CrashReport.java:45), net.minecraft.server.v1_7_R4.CrashReport.<init>(CrashReport.java:33), net.minecraft.server.v1_7_R4.CrashReport.a(CrashReport.java:230), net.minecraft.server.v1_7_R4.World.tickEntities(World.java:1463), net.minecraft.server.v1_7_R4.WorldServer.tickEntities(WorldServer.java:516), net.minecraft.server.v1_7_R4.MinecraftServer.v(MinecraftServer.java:706), net.minecraft.server.v1_7_R4.DedicatedServer.v(DedicatedServer.java:289), net.minecraft.server.v1_7_R4.MinecraftServer.u(MinecraftServer.java:584), net.minecraft.server.v1_7_R4.MinecraftServer.run(MinecraftServer.java:490), net.minecraft.server.v1_7_R4.ThreadServerApplication.run(SourceFile:628)], RUNNABLE Server console handler: [org.fusesource.jansi.internal.Kernel32._getch(Native Method), org.fusesource.jansi.internal.WindowsSupport.readByte(WindowsSupport.java:46), org.bukkit.craftbukkit.libs.jline.WindowsTerminal.readByte(WindowsTerminal.java:184), org.bukkit.craftbukkit.libs.jline.WindowsTerminal.access$000(WindowsTerminal.java:53), org.bukkit.craftbukkit.libs.jline.WindowsTerminal$1.read(WindowsTerminal.java:151), java.io.FilterInputStream.read(Unknown Source), org.bukkit.craftbukkit.libs.jline.console.ConsoleReader$1.read(ConsoleReader.java:167), org.bukkit.craftbukkit.libs.jline.internal.InputStreamReader.read(InputStreamReader.java:267), org.bukkit.craftbukkit.libs.jline.internal.InputStreamReader.read(InputStreamReader.java:204), org.bukkit.craftbukkit.libs.jline.console.ConsoleReader.readCharacter(ConsoleReader.java:995), org.bukkit.craftbukkit.libs.jline.console.ConsoleReader.readLine(ConsoleReader.java:1167), net.minecraft.server.v1_7_R4.ThreadCommandReader.run(ThreadCommandReader.java:32)], WAITING Thread-5: [sun.misc.Unsafe.park(Native Method), java.util.concurrent.locks.LockSupport.park(Unknown Source), java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(Unknown Source), java.util.concurrent.LinkedBlockingQueue.take(Unknown Source), net.minecraft.util.com.mojang.util.QueueLogAppender.getNextLogEvent(QueueLogAppender.java:73), org.bukkit.craftbukkit.v1_7_R4.util.TerminalConsoleWriterThread.run(TerminalConsoleWriterThread.java:25), java.lang.Thread.run(Unknown Source)], TIMED_WAITING File IO Thread: [java.lang.Thread.sleep(Native Method), net.minecraft.server.v1_7_R4.FileIOThread.b(SourceFile:44), net.minecraft.server.v1_7_R4.FileIOThread.run(SourceFile:23), java.lang.Thread.run(Unknown Source)], RUNNABLE Netty IO #2: [sun.nio.ch.WindowsSelectorImpl$SubSelector.poll0(Native Method), sun.nio.ch.WindowsSelectorImpl$SubSelector.poll(Unknown Source), sun.nio.ch.WindowsSelectorImpl$SubSelector.access$400(Unknown Source), sun.nio.ch.WindowsSelectorImpl.doSelect(Unknown Source), sun.nio.ch.SelectorImpl.lockAndDoSelect(Unknown Source), sun.nio.ch.SelectorImpl.select(Unknown Source), net.minecraft.util.io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:591), net.minecraft.util.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:301), net.minecraft.util.io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101), java.lang.Thread.run(Unknown Source)], TIMED_WAITING Spigot Watchdog Thread: [java.lang.Thread.sleep(Native Method), org.spigotmc.WatchdogThread.run(WatchdogThread.java:92)], TIMED_WAITING Server Infinisleeper: [java.lang.Thread.sleep(Native Method), net.minecraft.server.v1_7_R4.ThreadSleepForever.run(SourceFile:63)], RUNNABLE Netty IO #0: [sun.nio.ch.WindowsSelectorImpl$SubSelector.poll0(Native Method), sun.nio.ch.WindowsSelectorImpl$SubSelector.poll(Unknown Source), sun.nio.ch.WindowsSelectorImpl$SubSelector.access$400(Unknown Source), sun.nio.ch.WindowsSelectorImpl.doSelect(Unknown Source), sun.nio.ch.SelectorImpl.lockAndDoSelect(Unknown Source), sun.nio.ch.SelectorImpl.select(Unknown Source), net.minecraft.util.io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:591), net.minecraft.util.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:301), net.minecraft.util.io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101), java.lang.Thread.run(Unknown Source)], RUNNABLE Signal Dispatcher: [], RUNNABLE Netty IO #1: [sun.nio.ch.WindowsSelectorImpl$SubSelector.poll0(Native Method), sun.nio.ch.WindowsSelectorImpl$SubSelector.poll(Unknown Source), sun.nio.ch.WindowsSelectorImpl$SubSelector.access$400(Unknown Source), sun.nio.ch.WindowsSelectorImpl.doSelect(Unknown Source), sun.nio.ch.SelectorImpl.lockAndDoSelect(Unknown Source), sun.nio.ch.SelectorImpl.select(Unknown Source), net.minecraft.util.io.netty.channel.nio.NioEventLoop.select(NioEventLoop.java:591), net.minecraft.util.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:301), net.minecraft.util.io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101), java.lang.Thread.run(Unknown Source)], TIMED_WAITING Snooper Timer: [java.lang.Object.wait(Native Method), java.util.TimerThread.mainLoop(Unknown Source), java.util.TimerThread.run(Unknown Source)], RUNNABLE Attach Listener: [], WAITING Reference Handler: [java.lang.Object.wait(Native Method), java.lang.Object.wait(Object.java:503), java.lang.ref.Reference$ReferenceHandler.run(Unknown Source)], WAITING Finalizer: [java.lang.Object.wait(Native Method), java.lang.ref.ReferenceQueue.remove(Unknown Source), java.lang.ref.ReferenceQueue.remove(Unknown Source), java.lang.ref.Finalizer$FinalizerThread.run(Unknown Source)], TIMED_WAITING Spigot Metrics Thread: [java.lang.Object.wait(Native Method), java.util.TimerThread.mainLoop(Unknown Source), java.util.TimerThread.run(Unknown Source)], WAITING Chunk I/O Executor Thread-1: [sun.misc.Unsafe.park(Native Method), java.util.concurrent.locks.LockSupport.park(Unknown Source), java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(Unknown Source), java.util.concurrent.LinkedBlockingQueue.take(Unknown Source), java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source), java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source), java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source), java.lang.Thread.run(Unknown Source)], RUNNABLE DestroyJavaVM: [],}
       Recent tasks from 13388-13418{}
        Profiler Position: N/A (disabled)
        Vec3 Pool Size: 0 (0 bytes; 0 MB) allocated, 0 (0 bytes; 0 MB) used
        Player Count: 1 / 20; [EntityPlayer['Madricas'/200, l='world', x=-76,56, y=63,00, z=239,59](Madricas at -76.56347237354227,63.0,239.59090318218765)]
        Is Modded: Definitely; Server brand changed to 'Spigot'
        Type: Dedicated Server (map_server.txt)

    Thanks for the time spending on the help ;)
     
  9. @Madricas instead of instantly casting, invoke getHandle() on the CraftPlayer (if it's a Player, a cast to CraftPlayer is required before you get access to getHandle()). That will give you an EntityPlayer, which is a subclass of EntityLiving :p.
     
    • Like Like x 1
  10. Thanks @DarkSeraphim the server doesn't crash anymore but the chicken still doesn't move, following me :c
     
  11. #32 candyfloss20, Oct 24, 2014
    Last edited: Oct 24, 2014
  12. @Madricas you probably need to debug it. For example, see if the code is being ran, if the pathfinder goal is ever active, etc.

    [EDIT] set the priority of the pathfinder lower (from 10 to 1, for example). Also, for the love of everything remove that static Player field from the chicken class and create a non static field. Lastly make sure that you don't leak memory when the player logs out!
     
    • Like Like x 1
    • Agree Agree x 1
    • Informative Informative x 1
  13. @DarkSeraphim Thank again for the fast answer but I don't have any idea at the moment on how to access my EntityPlayer non-static field.
    I set the priority to 1 of the Pathfinder and I have already added a listener to remove the entities when the player disconnect, preventing memory leaks, but without the field owner i can't do so much.
     
    • Like Like x 1
  14. @DarkSeraphim Yeah , and i tried a setOwner method
    Code (Text):
        public void setOwner(EntityPlayer player) {
            this.owner = player;
        }
    but using it on the other class just let me the choice to add a static reference. But because its accessing a non static field EntityPlayer owner i cant go further. And by creating an instance of my ChickenFollower class i don't know what to put there on "world" :
    Code (Text):
    public class Pouleaypierre extends JavaPlugin implements Listener {
     
            //Add un world qconque
        FollowerChicken fc = new FollowerChicken(world);
     
        @Override
        public void onEnable() {
    I hope your not discouraged by my "nullitude". Thanks again for the answer.
     
  15. @Madricas you shouldn't be creating FollowerChickens before you have a Player to create it for. Furthermore, if you don't have a FollowerChicken instance, there would be no reason why you need to know the owner. Once you have a Player, you will also have a World.

    If you don't know an alternative for static, then you most likely don't know enough Java. Almost every static keyword has a non static alternative ;3. But regardless of that, static doesn't even make sense in this case. Each FollowerChicken is supposed to have it's own owner, but static fields are not instance fields, they are class fields. This means that all FollowerChickens will have one owners (which is most likely undesired)
     
    • Like Like x 1
  16. @DarkSeraphim You have right and briefly i already have in another project the HashMap that stores each Player with his chicken, but i dont spawn them with nms until i got this working.

    So you recommend me creating the FollowerChicken just before seting the owner in the method ? Did I understand right ?
    --------------------------------------
    [edit] Since i manage to assign the owner of the chicken it does not take effect :
    i verify in the setter and in the pathfinder the value that is return by owner, and with the setter the EntityPlayer is correctly display, but the getter implemented by EntityOwnable return a null owner. If someone could indicate me where i get wrong ...
     
    #38 Madricas, Oct 25, 2014
    Last edited: Oct 25, 2014
  17. This is version dependant ... you should specify which version, then :)

    Still, thanks :)
     
  18. @Madricas your getOwnerUUID returns null :p. A few suggestions:
    • Create two fields in your FollowerChicken class (one is most likely already there):
      • An EntityPlayer field that holds a reference to the EntityPlayer that it's supposed to follow (in other words: the owner).
      • A UUID field that holds the UUID of the owner.
    • In the getOwnerUUID() method, return the UUID.
    • In the pathfinder, make sure you don't use the owner if (s)he is not online. Also, don't store the EntityPlayer in the pathfinder, always use the getOwner() method to get it. Secondly, ensure that it isn't null (simply null check) to prevent NullPointerExceptions. Overall, the pathfinder should be inactive if the owner is null.
    • When the player logs off, set the owner field to null (but leave the UUID field set). When the player joins and the entity is still alive (as in, hasn't despawned yet), set the owner again so the FollowerChicken starts following the owner again.
    • Make sure that the UUID is persistent. In the case that NBT doesn't do the trick, use the NBT save method to save it yourself (in a YAML file). Moreover, if NBT doesn't do the trick you can load the owner in the constructor. Just use the entity's UUID (which is supposed to persist already) as key (path) in the file.