Tutorial [1.8 ONLY]WASD Entity control

Discussion in 'Resources' started by Funergy, Feb 17, 2015.

Thread Status:
Not open for further replies.
  1. Offline

    GayZoTe

    hey ! i've problems with this tutorial, in my custom Entity, there is the fully code :

    Code:
    package fr.azote.ride;
    
    
    import java.lang.reflect.Field;
    
    import net.minecraft.server.v1_8_R2.EntityCow;
    import net.minecraft.server.v1_8_R2.EntityHuman;
    import net.minecraft.server.v1_8_R2.EntityLiving;
    import net.minecraft.server.v1_8_R2.EntityPig;
    import net.minecraft.server.v1_8_R2.MathHelper;
    import net.minecraft.server.v1_8_R2.PathfinderGoalSelector;
    import net.minecraft.server.v1_8_R2.World;
    
    import org.bukkit.craftbukkit.v1_8_R2.util.UnsafeList;
    
    public class CustomEntityCow extends EntityCow {
    
    
        public CustomEntityCow(World world) {
        super(world);
    
        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();
        }
        }
    
        @Override
        public void g(float sideMot, float forMot) {
        if (this.passenger != null && this.passenger instanceof EntityHuman) {
        this.lastYaw = this.yaw = this.passenger.yaw;
        this.pitch = this.passenger.pitch * 0.5F;
        this.setYawPitch(this.yaw, this.pitch);
        this.aI = this.aG = this.yaw;
        sideMot = ((EntityLiving) this.passenger).aX * 0.5F;
        forMot = ((EntityLiving) this.passenger).aY;
        if (forMot <= 0.0F) {
        forMot *= 0.25F;
        }
    
        Field jump = null;
        try {
        jump = EntityLiving.class.getDeclaredField("aW");
        } catch (NoSuchFieldException e1) {
        e1.printStackTrace();
        } catch (SecurityException e1) {
        e1.printStackTrace();
        }
        jump.setAccessible(true);
    
        if (jump != null && this.onGround) {
        try {
        if (jump.getBoolean(this.passenger)) {
        double jumpHeight = 0.5D;
        this.motY = jumpHeight;
        }
        } catch (IllegalAccessException e) {
        e.printStackTrace();
        }
        }
    
        this.S = 1.0F;
        this.aK = this.bH() * 0.1F;
        if (!this.world.isStatic) {
        this.j(0.35F);
        super.g(sideMot, forMot);
        }
    
        this.ay = this.az;//Some extra things
        double d0 = this.locX - this.lastX;
        double d1 = this.locZ - this.lastZ;
        float f4 = MathHelper.sqrt(d0 * d0 + d1 * d1) * 4.0F;
        if (f4 > 1.0F) {
        f4 = 1.0F;
        }
    
        this.az += (f4 - this.az) * 0.4F;
        this.aA += this.az;
        } else {
        this.S = 0.5F;
        this.aK = 0.02F;
        super.g(sideMot, forMot);
        }
        }
    
       }
    

    and there is the errors :
    [​IMG]

    help me please :( (sorry for my bad english)
     
    Last edited: Jul 19, 2015
  2. Offline

    Funergy

  3. Offline

    GuliPlays

    I'm using your method but it still not working.

    Here is the method I'm using:
    Code:
    class CustomCow extends EntityCow {
    
        public CustomCow(World world) {
            super(world);
        }
      
        @Override
        public void g(float f, float f1) {
        if(this.passenger != null && this.passenger instanceof EntityHuman) {
        this.lastYaw = this.yaw = this.passenger.yaw; this.pitch = this.passenger.pitch * 0.5F; this.setYawPitch(this.yaw, this.pitch); this.aK = this.aI = this.yaw;f = ((EntityLiving)this.passenger).aZ * 0.5F;f1 = ((EntityLiving)this.passenger).ba; if(f1 <= 0.0F) {
        f1 *= 0.25F;}
        Field jump = null; try {
        jump = EntityLiving.class.getDeclaredField("aY");} catch (NoSuchFieldException e1) {
        // TODO Auto-generated catch blocke1.printStackTrace();} catch (SecurityException e1) {
        // TODO Auto-generated catch blocke1.printStackTrace();}
        jump.setAccessible(true); if (jump != null) { // Wouldn't want it jumping while on the ground would we?try {
            try {
                if (jump.getBoolean(this.passenger)) {
               
                double jumpHeight = 0.5D; this.motY = jumpHeight; // Used all the time in NMS for entity jumping}
                this.S = 1.0F; this.aM = this.bI() * 0.1F; if(!this.world.isClientSide) {
                this.k((float)this.getAttributeInstance(GenericAttributes.c).getValue()); super.g(f, f1);}
               
                this.aA = this.aB; double d0 = this.locX - this.lastX; double d1 = this.locZ - this.lastZ; float f4 = MathHelper.sqrt(d0 * d0 + d1 * d1) * 4.0F; if(f4 > 1.0F) {
                f4 = 1.0F;}
               
                this.aB += (f4 - this.aB) * 0.4F; this.aC += this.aB;} else {
                this.S = 0.5F; this.aM = 0.02F; super.g(f, f1);
                }
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        }
        }
        }
    }
    Cow spawns, but it doesnt move... :(. And no errors in the console.
    If I'm riding the cow it doesn't move to.

    QIxXzVP.png
     
    Last edited: Aug 16, 2015
  4. How could I make players ride other players but they don't control them by WASD they move same as the player they riding?
     
  5. Offline

    crolemol

  6. Oh ok! I thought it needs NMS! Thanks a lot!
     
  7. Offline

    VortexGmer

    Hey! Thanks for the tutorial but I am getting an error on this part:
    Code:
    this.k((float) this.getAttributeInstance(
    
    GenericAttributes.d).getValue());
    
    The error is
    d cannot be resolved or is not a field
    Oh yeah, This is an endermite. Registered it fine spawns fine but controlling it not fine.
    CraftBukkit version git-Spigot-fdc1440-880a532 (MC: 1.8.8) (Implementing API version 1.8.8-R0.1-SNAPSHOT)
     
    Last edited: Aug 22, 2015
  8. Offline

    Funergy

    @VortexGmer I'm not planning right now to update the code to 1.8.8, Sorry.
     
  9. Offline

    MrGlue

    @Funergy It has a problem with jump.getBoolean(this.passenger) in 1.8.3. I'm using your 1.8.3 code with Spigot 1.8.3 and Client 1.8.3. When I try to set a Player as Passenger the server is crashing.

    And it is not possible to make a Minecart controlable on ground, is it?
     
  10. Offline

    Battlecraftman

    Heres my CustomCow Class
    Show Spoiler

    Code:
    import java.lang.reflect.Field;
    
    import net.minecraft.server.v1_8_R1.EntityCow;
    import net.minecraft.server.v1_8_R1.EntityHuman;
    import net.minecraft.server.v1_8_R1.EntityLiving;
    import net.minecraft.server.v1_8_R1.MathHelper;
    import net.minecraft.server.v1_8_R1.World;
    
    public class CustomEntityCow extends EntityCow{
    
       public CustomEntityCow(World world) {
         super(world);
         // TODO Auto-generated constructor stub
       }
      
      @Override
      public void g(float sideMot, float forMot) {
      if(this.passenger != null && this.passenger instanceof EntityHuman) {
      this.lastYaw = this.yaw = this.passenger.yaw;
      this.pitch = this.passenger.pitch * 0.5F;
      this.setYawPitch(this.yaw, this.pitch);//Update the pitch and yaw
      this.aI = this.aG = this.yaw;
      sideMot = ((EntityLiving)this.passenger).aX * 0.5F;
      forMot = ((EntityLiving)this.passenger).aY;
      if(forMot <= 0.0F) {
      forMot *= 0.25F;// Make backwards slower
      }
      Field jump = null; //Jumping
      try {
      jump = EntityLiving.class.getDeclaredField("aW");
      } catch (NoSuchFieldException e1) {
      // TODO Auto-generated catch block
      e1.printStackTrace();
      } catch (SecurityException e1) {
      // TODO Auto-generated catch block
      e1.printStackTrace();
      }
      jump.setAccessible(true);
      if (jump != null && this.onGround) {  // Wouldn't want it jumping while on the ground would we?
      try {
      if (jump.getBoolean(this.passenger)) {
      double jumpHeight = 0.5D;//Here you can set the jumpHeight
      this.motY = jumpHeight;  // Used all the time in NMS for entity jumping
      }
      } catch (IllegalAccessException e) {
      e.printStackTrace();
      }
      }
      this.S = 1.0F;// The custom entity will now automatically climb up 1 high blocks
      this.aK = this.bH() * 0.1F;
      if(!this.world.isStatic) {
      this.j(0.35F);//Here is the speed the entity will walk.
      super.g(sideMot, forMot);
      }
      this.ay = this.az;//Some extra things
      double d0 = this.locX - this.lastX;
      double d1 = this.locZ - this.lastZ;
      float f4 = MathHelper.sqrt(d0 * d0 + d1 * d1) * 4.0F;
      if(f4 > 1.0F) {
      f4 = 1.0F;
      }
      this.az += (f4 - this.az) * 0.4F;
      this.aA += this.az;
      } else {
      this.S = 0.5F;
      this.aK = 0.02F;
      super.g(sideMot, forMot);
      }
      }
    }
    

    Looks fine, here my CustomEntityTypes Enum
    Show Spoiler

    Code:
    import net.minecraft.server.v1_8_R1.EntityCow;
    import net.minecraft.server.v1_8_R1.EntityInsentient;
    
    import org.bukkit.entity.EntityType;
    
    public enum CustomEntityType {
      
      COW("Cow", 92, EntityType.COW, EntityCow.class, CustomEntityCow.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 this.name;
      }
      public int getID(){
      return this.id;
      }
      public EntityType getEntityType(){
      return this.entityType;
      }
      
      public Class<? extends EntityInsentient> getNMSClass()
      {
         return this.nmsClass;
      }
      
      public Class<? extends EntityInsentient> getCustomClass()
      {
         return this.customClass;
      }
      
      //https://github.com/Bukkit/mc-dev/blob/master/net/minecraft/server/EntityTypes.java
      
      public static void registerEntities(){
      for (CustomEntityType entity : values()){
         NMSUtil.registerEntity(entity.getName(), entity.getID(), entity.getNMSClass(), entity.getCustomClass());
      }
      }
    }
    

    And i am simply spawning it:
    Code:
    l.getWorld().spawnEntity(l, EntityType.COW); //CustomEntityType.COW changes nothing!
    But it is not possible to control it with WASD while riding :(
    I called the registerEntities function onEnable
    Show Spoiler

    Code:
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    import net.minecraft.server.v1_8_R1.BiomeBase;
    import net.minecraft.server.v1_8_R1.BiomeMeta;
    import net.minecraft.server.v1_8_R1.EntityInsentient;
    import net.minecraft.server.v1_8_R1.EntityTypes;
    
    public class NMSUtil {
       public static void registerEntity(String name, int id, Class<? extends EntityInsentient> nmsClass, Class<? extends EntityInsentient> customClass) {
      try {
      /*
      * First, we make a list of all HashMap's in the EntityTypes class
      * by looping through all fields. I am using reflection here so we
      * have no problems later when minecraft changes the field's name.
      * By creating a list of these maps we can easily modify them later
      * on.
      */
      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));
      }
      }
      /*
      * since minecraft checks if an id has already been registered, we
      * have to remove the old entity class before we can register our
      * custom one
      *
      * map 0 is the map with names and map 2 is the map with ids
      */
      if (dataMaps.get(2).containsKey(id)) {
      dataMaps.get(0).remove(name);
      dataMaps.get(2).remove(id);
      }
      /*
      * now we call the method which adds the entity to the lists in the
      * EntityTypes class, now we are actually 'registering' our entity
      */
      Method method = EntityTypes.class.getDeclaredMethod("a", Class.class, String.class, int.class);
      method.setAccessible(true);
      method.invoke(null, customClass, name, id);
      /*
      * after doing the basic registering stuff , we have to register our
      * mob as to be the default for every biome. This can be done by
      * looping through all BiomeBase fields in the BiomeBase class, so
      * we can loop though all available biomes afterwards. Here, again,
      * I am using reflection so we have no problems later when minecraft
      * changes the fields name
      */
      for (Field f : BiomeBase.class.getDeclaredFields()) {
      if (f.getType().getSimpleName().equals(BiomeBase.class.getSimpleName())) {
      if (f.get(null) != null) {
      /*
      * this peace of code is being called for every biome,
      * we are going to loop through all fields in the
      * BiomeBase class so we can detect which of them are
      * Lists (again, to prevent problems when the field's
      * name changes), by doing this we can easily get the 4
      * required lists without using the name (which probably
      * changes every version)
      */
      for (Field list : BiomeBase.class.getDeclaredFields()) {
      if (list.getType().getSimpleName().equals(List.class.getSimpleName())) {
      list.setAccessible(true);
      @SuppressWarnings("unchecked")
      List<BiomeMeta> metaList = (List<BiomeMeta>) list.get(f.get(null));
      /*
      * now we are almost done. This peace of code
      * we're in now is called for every biome. Loop
      * though the list with BiomeMeta, if the
      * BiomeMeta's entity is the one you want to
      * change (for example if EntitySkeleton matches
      * EntitySkeleton) we will change it to our
      * custom entity class
      */
      for (BiomeMeta meta : metaList) {
      Field clazz = BiomeMeta.class.getDeclaredFields()[0];
      if (clazz.get(meta).equals(nmsClass)) {
      clazz.set(meta, customClass);
      }
      }
      }
      }
      }
      }
      }
      } catch (Exception e) {
      e.printStackTrace();
      }
      }
    }
    
    

    Please, need help.
     
    Last edited: Aug 30, 2015
  11. Offline

    MrGlue

    @Battlecraftman
    Try to use
    SpawningMethode (open)
    Code:
    CostumEntityCow cow= new CostumEntityCow(world, ((Player)sender).getLocation(), this);
    world.addEntity(cow);

    instead of your spawn method and in your CostumCowEntity Class use this constructor:
    CostumEntityConstructor (open)
    Code:
    public CostumEntityCow(World world,Location location) {
                super(world);
                setLocation(location.getX(), location.getY(), location.getZ(), location.getYaw(),               location.getPitch());
                setCustomName("YourCostumName");
                setCustomNameVisible(true);
    }
     
    Last edited: Sep 2, 2015
  12. Offline

    Battlecraftman

    @MrGlue
    Tried, no Errors but also no Cow :(
     
  13. Offline

    Funergy

  14. Offline

    MrGlue

    @Battlecraftman try my first answer + this register method in onEnable:
    new register method (open)
    Code:
    private void register(){
                try {
                        Field c = EntityTypes.class.getDeclaredField("c");
                        Field f = EntityTypes.class.getDeclaredField("f");
                        c.setAccessible(true);
                        f.setAccessible(true);
                        ((Map<Class<? extends EntityInsentient>, String>) c.get(null)).put(CustomZombie.class, "Zombie");
                        ((Map<Class<? extends EntityInsentient>, Integer>) f.get(null)).put(CustomZombie.class, 54);
                } catch (Exception e) {
                    e.printStackTrace();
                }
        }

    notice that I'm not using an enum.

    @Funergy Please fix your 1.8.3 code. Sidemot is not az but aZ and jumping is not working.
    Hope you update the code to 1.9.
     
  15. Offline

    Battlecraftman

    @Funergy
    Code:
      @Override
       public void onEnable()
       {
         loadConfig();
        
         CustomEntityType.registerEntities();
       }
    
    The rest code is in the other post.

    @MrGlue
    What will this change, i see no difference but will try.[/code]
     
  16. Offline

    MrGlue

    In 1.8.3 jump is aY, sideMot is aZ and forMot is ba.


    @Battlecraftman Did it work for you?
     
  17. Offline

    dadus33

    Just being currious, how do you guys manage to figure out what each field does?
     
  18. Offline

    MrGlue

    @dadus33 You have to decompile the EntityClass(example: EntitySilverfish) and look for the import(example: net.minecraft.server.v1_8_R2.EntitySilverfish) then download JD(http://jd.benow.ca/) and navigate to the EntitySilverfish class or EntityLiving try both. There you have lots of variables(some of them are private so use reflection). You have to try and Broadcast every variable(I know in EntityLiving are a lot). If a variable with a boolean change only when you jump it is the right variable for jumping.

    Example:
    Code:
    @Override
    public void g(float sideMot, float forMot) {
       
            Object obj = false;
            Field f = null; // 
            try{
                f = EntityLiving.class.getDeclaredField((a variable from Entity class));
            }catch (NoSuchFieldException e1){
                e1.printStackTrace();
            }catch (SecurityException e1){
                e1.printStackTrace();
            }
            f.setAccessible(true);
            try{
                obj = f.get(this.passenger);
            }catch (IllegalAccessException e){
                e.printStackTrace();
            }
            Bukkit.broadcastMessage(ret + "");
    }
    
     
  19. Offline

    dadus33

    Oh, I see, that however sounds like a lot of work :\ So many fields and methods in each class...
     
  20. Offline

    Battlecraftman

    @MrGlue

    Hey there, it still does not work, and i am using 1_8_R1 so your way sohuldnt work, but i will try laterly and thanks for the help anyway!!! Writing my results later...

    Edit:

    Yep, cant use these field cause i am using 1.8R1, and other ideas?
     
    Last edited: Nov 2, 2015
  21. Offline

    hamster6

    Please update on 1.8.8 ! :/
     
  22. Offline

    gal0511Dev

    I know this is not the same exact code as yours but do you think you could see why it only lets me move when i jump and walk forward if i just press the W key nothing will happen but if i jump and click W it works
    Here is my code(And yes im registering the entity): http://pastebin.com/JKKLDip7
     
  23. Offline

    MrGlue

    @gal0511Dev I think you have to execute the registration
    Show Spoiler
    Code:
    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 e) {
                e.printStackTrace(e);
    }


    on onEnable and not after/while creating the NMS Object
    Show Spoiler
    Code:
    new IronGolemMount(world);
     
  24. Offline

    Skilly

    The method works in 1.10 or is it only in 1.8 ?
     
  25. Offline

    MrGlue

    @Skilly Unfortunately Minecraft obfuscates the code in every version. I don't think it will work in other versions than 1.83. You have to manually look for every method and field used in this tutorial. But there actually is a tutorial for 1.8.8.
     
  26. Offline

    PhantomUnicorns

    Couldn't you just get the to and from get the difference in x y z and add that to the entity? Then set the to location to the from location w/ the direction of the to. e.i.:
    Code:
    // inClass
        Map<String, Entity> test = new HashMap<>();
    // onEnable
    
            for (Player player : Bukkit.getOnlinePlayers()) {
                Entity entity = player.getWorld().spawnEntity(player.getLocation().add(0, -1, 0), EntityType.MINECART);
                test.put(player.getName(), entity);
            }
    // onMoveEvent
            if (test.containsKey(event.getPlayer().getName())) {
                Entity entity = test.get(event.getPlayer().getName());
                double x = event.getTo().getX() - event.getFrom().getX();
                double y = event.getTo().getY() - event.getFrom().getY();
                double z = event.getTo().getZ() - event.getFrom().getZ();
                Location addLocal = new Location(event.getTo().getWorld(), entity.getLocation().getX() + x,
                        entity.getLocation().getY() + y, entity.getLocation().getZ() + z);
                /* This is if you don't want the player to move (alittle glitchy)
                Location newTo = event.getFrom();
                newTo.setDirection(event.getTo().getDirection());
                newTo.setY(event.getTo().getY());
                event.setTo(newTo);
                */
                boolean teleport = true;
                for (double i = -0.5; i < 0.6; i += 0.1) {
                    if (addLocal.clone().add(i, 0, 0).getBlock().getType() != Material.AIR) {
                        teleport = false;
                    } else if (addLocal.clone().add(0, 0, i).getBlock().getType() != Material.AIR) {
                        teleport = false;
                    }
                }
                if (teleport) {
                    entity.teleport(addLocal);
                }
            }
    
    Tested and does work!
     
    Last edited: Nov 29, 2016
  27. Offline

    MrGlue

    @PhantomUnicorns Unfortunately you will NOT receive any move events when the entity(player) is riding :(
     
  28. Offline

    PhantomUnicorns

    @MrGlue Hmm what do you mean? You could do the same thing but with entityrideevent (I will post some working code soon and maybe rewrite this post so don't barrage me yet please!)

    EDIT: Ok I understand now, ama try to find a solution
     
    Last edited: Dec 1, 2016
  29. Offline

    Proudyy

    How can i spawn now the living entities?

    PLS help me :cc

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jan 13, 2017
  30. Offline

    Proudyy

    Oh it works!
    Finally! I used NMSUtils.
    How can I make then free to move them self for yaw and pitch.
    The entities looking like some roboters :D
    And how can I get the right EntityType..
    I tried to make entity.getMonsterType().
    But it gives UNDEFINED.
     
Thread Status:
Not open for further replies.

Share This Page