[Resource] Custom Players that extends EntityPlayer

Discussion in 'Resources' started by ResultStatic, Jun 3, 2014.

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

    ResultStatic

    I made a compact (5 classes) method of spawning fake players. I used a few resource which i will credit while making this and updating it. since it extends EntityPlayer you can use standard bukkit events like EntityDamageEvent and PlayerInteractEntityEvent. THIS WILL ONLY WORK WITH 1.7.9 because it is nms. a few bukkit methods dont work for instance i couldnt get it to add potions to it and any movement to it will appear that they have no knockback hacks since movement is handled client side and there is no client. also if someone wants to make a good movement method with speeds ill add it to the NPCEntity class.

    credit go to https://github.com/caliog/NPCLib for the contact "bounce" method or collision listener

    credit goes to http://forums.bukkit.org/threads/nms-player-entities-and-general-npcs.227116/
    for replacing the NetworkManager and PlayerConnection to prevent NPE's

    class 1

    Code:
    import java.net.SocketAddress;
    import net.minecraft.util.io.netty.channel.AbstractChannel;
    import net.minecraft.util.io.netty.channel.Channel;
    import net.minecraft.util.io.netty.channel.ChannelConfig;
    import net.minecraft.util.io.netty.channel.ChannelMetadata;
    import net.minecraft.util.io.netty.channel.ChannelOutboundBuffer;
    import net.minecraft.util.io.netty.channel.DefaultChannelConfig;
    import net.minecraft.util.io.netty.channel.EventLoop;
     
    public class NPCChannel extends AbstractChannel {
     
    protected final ChannelConfig config = new DefaultChannelConfig(this);
     
    protected NPCChannel(Channel parent) {
    super(parent);
    }
     
    @Override
    protected AbstractUnsafe newUnsafe() {
    return null;
    }
     
    @Override
    protected boolean isCompatible(EventLoop eventExecutors) {
    return true;
    }
     
    @Override
    protected SocketAddress localAddress0() {
    return null;
    }
     
    @Override
    protected SocketAddress remoteAddress0() {
    return null;
    }
     
    @Override
    protected void doBind(SocketAddress socketAddress) throws Exception {
     
    }
     
    @Override
    protected void doDisconnect() throws Exception {
     
    }
     
    @Override
    protected void doClose() throws Exception {
     
    }
     
    @Override
    protected void doBeginRead() throws Exception {
     
    }
     
    @Override
    protected void doWrite(ChannelOutboundBuffer channelOutboundBuffer) throws Exception {
     
    }
     
    @Override
    public ChannelConfig config() {
    return config;
    }
     
    @Override
    public boolean isOpen() {
    return true;
    }
     
    @Override
    public boolean isActive() {
    return false;
    }
     
    @Override
    public ChannelMetadata metadata() {
    return null;
    }
    }
    class 2
    Code:
     
    import net.minecraft.server.v1_7_R3.EntityHuman;
    import net.minecraft.server.v1_7_R3.EntityPlayer;
    import net.minecraft.server.v1_7_R3.EnumGamemode;
    import net.minecraft.server.v1_7_R3.MinecraftServer;
    import net.minecraft.server.v1_7_R3.NetworkManager;
    import net.minecraft.server.v1_7_R3.PlayerInteractManager;
    import net.minecraft.server.v1_7_R3.WorldServer;
    import net.minecraft.util.com.mojang.authlib.GameProfile;
     
    import org.bukkit.Bukkit;
    import org.bukkit.craftbukkit.v1_7_R3.CraftServer;
    import org.bukkit.craftbukkit.v1_7_R3.entity.CraftPlayer;
    import org.bukkit.entity.Player;
     
    public class NPCEntity extends EntityPlayer {
     
        private int lastTargetId;
        private long lastBounceTick;
        private int lastBounceId;
     
        static MinecraftServer server = ((CraftServer)Bukkit.getServer()).getHandle().getServer();
        public NPCEntity(NPCManager npcManager, WorldServer world, GameProfile s, PlayerInteractManager itemInWorldManager) {
        super(server , world, s, itemInWorldManager);
        NetworkManager manager = new FixedNetworkManager();
        playerConnection = new NPCPlayerConnection(server, manager, this);
        manager.a(playerConnection);
        itemInWorldManager.b(EnumGamemode.SURVIVAL);
        lastTargetId = -1;
        lastBounceId = -1;
        lastBounceTick = 0;
        fauxSleeping = true;
        }
     
        @Override
        public void b_(EntityHuman entity) {
        if ((lastBounceId != entity.getId() || System.currentTimeMillis() - lastBounceTick > 1000)
            && entity.getBukkitEntity().getLocation().distanceSquared(getBukkitEntity().getLocation()) <= 1) {
          //this is when you collide with the entity
            lastBounceTick = System.currentTimeMillis();
            lastBounceId = entity.getId();
        }
     
        if (lastTargetId == -1 || lastTargetId != entity.getId()) {
            lastTargetId = entity.getId();
        }
        super.b_(entity);
        }
     
     
        public void setpassenger(Player player){
        this.mount(((CraftPlayer)player).getHandle());
     
        }
    }
    class 3

    Code:
     
    import net.minecraft.server.v1_7_R3.NetworkManager;
     
    import java.lang.reflect.Field;
     
    public class FixedNetworkManager extends NetworkManager {
     
     
        public FixedNetworkManager() {
            super(false);
            try {
                try {
                    this.swapFields();
                } catch (NoSuchFieldException | SecurityException e) {
                    e.printStackTrace();
                }
            } catch (IllegalArgumentException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
     
        protected void swapFields() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
            Field channelField = NetworkManager.class.getDeclaredField( "m" );
            channelField.setAccessible( true );
            channelField.set( this , new NPCChannel( null ) );
            channelField.setAccessible( false );
     
            Field socketAddressField = NetworkManager.class.getDeclaredField( "n" );
            socketAddressField.setAccessible( true );
            socketAddressField.set( this , null );
            socketAddressField.setAccessible( true );
            socketAddressField.set(this, null);
        }
    }
    class 4

    Code:
    import java.util.HashMap;
    import java.util.UUID;
    import net.minecraft.server.v1_7_R3.MinecraftServer;
    import net.minecraft.server.v1_7_R3.PlayerInteractManager;
    import net.minecraft.server.v1_7_R3.WorldServer;
    import net.minecraft.util.com.mojang.authlib.GameProfile;
     
    import org.bukkit.Bukkit;
    import org.bukkit.Location;
    import org.bukkit.craftbukkit.v1_7_R3.CraftServer;
    import org.bukkit.craftbukkit.v1_7_R3.CraftWorld;
     
    public class NPCManager {
            public static HashMap<Integer,NPCEntity> npcs = new HashMap<Integer, NPCEntity>();
     
            public NPCEntity spawnHumanNPC(String name, Location l, UUID id, int i) {
            CraftWorld w = (((CraftWorld)l.getWorld()));
            WorldServer world = w.getHandle();
            final NPCEntity npcEntity = new NPCEntity(this,world, new GameProfile(id, name), new PlayerInteractManager(world));
            npcEntity.setPositionRotation(l.getX(), l.getY(), l.getZ(), l.getYaw(), l.getPitch());
            npcs.put(i, npcEntity);
            world.addEntity(npcEntity);
            world.players.remove(npcEntity);
     
            return npcEntity;
            }
     
     
            public MinecraftServer getServer(){
                return ((CraftServer)Bukkit.getServer()).getHandle().getServer();
            }
     
     
     
    }
    
    class 5

    Code:
    import net.minecraft.server.v1_7_R3.EntityPlayer;
    import net.minecraft.server.v1_7_R3.MinecraftServer;
    import net.minecraft.server.v1_7_R3.NetworkManager;
    import net.minecraft.server.v1_7_R3.Packet;
    import net.minecraft.server.v1_7_R3.PacketPlayInBlockDig;
    import net.minecraft.server.v1_7_R3.PacketPlayInBlockPlace;
    import net.minecraft.server.v1_7_R3.PacketPlayInChat;
    import net.minecraft.server.v1_7_R3.PacketPlayInFlying;
    import net.minecraft.server.v1_7_R3.PacketPlayInHeldItemSlot;
    import net.minecraft.server.v1_7_R3.PacketPlayInTransaction;
    import net.minecraft.server.v1_7_R3.PacketPlayInUpdateSign;
    import net.minecraft.server.v1_7_R3.PacketPlayInWindowClick;
    import net.minecraft.server.v1_7_R3.PlayerConnection;
     
    public class NPCPlayerConnection extends PlayerConnection {
     
        public NPCPlayerConnection(MinecraftServer minecraftserver, NetworkManager networkmanager, EntityPlayer entityplayer) {
            super(minecraftserver, networkmanager, entityplayer);
        }
     
        @Override
        public void a(PacketPlayInWindowClick packet) {
        }
     
        @Override
        public void a(PacketPlayInTransaction packet) {
        }
     
        @Override
        public void a(PacketPlayInFlying packet) {
        }
     
        @Override
        public void a(PacketPlayInUpdateSign packet) {
        }
     
        @Override
        public void a(PacketPlayInBlockDig packet) {
        }
     
        @Override
        public void a(PacketPlayInBlockPlace packet) {
        }
     
        @Override
        public void disconnect(String s) {
        }
     
        @Override
        public void a(PacketPlayInHeldItemSlot packetplayinhelditemslot) {
        }
     
        @Override
        public void a(PacketPlayInChat packetplayinchat) {
        }
     
        @Override
        public void sendPacket(Packet packet) {
        }
    }
    to spawn one
    Code:
            NPCManager npc = new NPCManager();
                int i = new Random().nextInt() * new Random().nextInt() + new Random().nextInt();
                    npc.spawnHumanNPC(name, location, new UUID(100, 1000),i);
                    NPCEntity n  = NPCManager.npcs.get(i);

    Code:
    listening for damage to it
     
    @EventHandler
    public void onhit(EntityDamageByEntityEvent e){
    EntityPlayer damaged = NmsApi.getCraftPlayer(((Player)e.getEntity()));
    if (NPCManager.npcs.containsValue(damaged)){
    // whatever you want
    }
    }
     
  2. Offline

    BungeeTheCookie

  3. Offline

    ResultStatic

    Last edited by a moderator: Jun 30, 2016
  4. ResultStatic thanks, is there anyway to add to the entity PathFinder?
     
  5. Offline

    bigteddy98

    does this also add your player to the tab list, and does it call events (like entitydamagebyentity when I hit it)?
     
    Plo124 likes this.
  6. Offline

    minelazz

    How do you update the entity?
    I tried to add armor, but the armor is not visible until the npc die.


    Code:java
    1. Player pl = (Player)n.getBukkitEntity();
    2. System.out.print(toItemStack(p.getArmorContens().get(2)));
    3. pl.getInventory().setChestplate(toItemStack(p.getArmorContens().get(2)));
    4. pl.getInventory().setLeggings(toItemStack(p.getArmorContens().get(1)));
    5. pl.getInventory().setBoots(toItemStack(p.getArmorContens().get(0)));
     
  7. Offline

    ResultStatic

    bigteddy98 no i dont think the server counts it as an actual player but im sure u can make your own ways of adding them with packets. the events i have notice that it calls are. EntityDamageByEntityEvent EntityDeatEvent and EntityInteractEntityEvent
    but it didnt take lava damage when i place lava

    minelazz yea i havent tested all the methods but i know a couple of them dont work. so you will have to make your own with packets. like this. this should put armor on them if u use the id that they are spawned with. the id is the id used to spawn them on PacketPlayOutNamedEntitySpawn. so u can do

    Code:
    public void updateItems(ItemStack hand, ItemStack boots, ItemStack legs, ItemStack chest, ItemStack helmet) {
       
        PacketPlayOutEntityEquipment[] ps = new PacketPlayOutEntityEquipment[]{
        new PacketPlayOutEntityEquipment(id, 1, CraftItemStack.asNMSCopy(boots)),
        new PacketPlayOutEntityEquipment(id, 2, CraftItemStack.asNMSCopy(legs)),
        new PacketPlayOutEntityEquipment(id, 3, CraftItemStack.asNMSCopy(chest)),
        new PacketPlayOutEntityEquipment(id, 4, CraftItemStack.asNMSCopy(helmet)),
        new PacketPlayOutEntityEquipment(id, 0, CraftItemStack.asNMSCopy(hand))
        };
        for (PacketPlayOutEntityEquipment pack : ps) {
        for (Player p : Bukkit.getOnlinePlayers()) {
        ((CraftPlayer) p).getHandle().playerConnection.sendPacket(pack);
        }
        }
        }
    im not 100 percent sure on the which id is used for packet updating on EntityPlayer but try npc.getId();

    Someone_Like_You It's nearly impossible to use Minecrafts pathfinding for this because of 2 reasons: the Navigation can only be applied to entities which extend EntityInsentient and because if you do want to use it you'll have to recreate so many classes that it's just not worth it. - CaptainBern

    as cool as it would be to do that it looks like you might just end up with a huge mess. ill take a look at it tho

    bigteddy98 Someone_Like_You i came up with a neat way to add default creature pathfinders to the players. this is what i did. basically im getting the player to walk where the zombie goes. so then you can edit path finders all you want for that zombie.

    Code:
    public class NPCGoals {
     
     
    public NPCGoals(WorldServer world, final NPCEntity n, Player player){
      final EntityZombie zombie = new EntityZombie(world);
      zombie.teleportTo(player.getLocation(), false);
      this.destroy(zombie.getBukkitEntity().getEntityId());
      Bukkit.getScheduler().scheduleSyncRepeatingTask(Main.getInstance(), new BukkitRunnable(){
     
      public void run(){
      Location loc = zombie.getBukkitEntity().getLocation();
      n.setPositionRotation(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch()); 
    }
    }, 1, 1);
    }
     
    public void destroy(int id) {
    PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(id);
    for (Player p : Bukkit.getOnlinePlayers()) {
    ((CraftPlayer) p).getHandle().playerConnection.sendPacket(packet);
    }
    }
    }
    i have run into a few problems. first zombie

    zombie.extinguish();
    zombie.setOnFire(i);
    do nothing.

    second the player pitch and yaw wont update right

    3rd there is zombie sounds

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 30, 2016
  8. Offline

    bigteddy98

    Awesum :D
    That's probably because you set them on fire before sending the transformation packet, this way your client will recieve a PacketPlayOutEntityMetadata without a known id. It will just ignore it, can you try to do the transformation first before you put them on fire?
    I think this is caused by the same problem as the one with the fire.
    You could fix this by spawning a custom zombie, and override the sound methods.

    In total, it looks good but I wouldn't do it like this if I were you. Teleporting many npcs every tick can cause high server load, which server owners do not like. If I were you I would also destory the NPC with the same way you're doing it now. Then, send a PacketPlayOutNamedEntitySpawn with the NPC data but the ID of the zombie (important, if you take the wrong ID it will not work). All packets send now which are ment for the zombie ID (including the location) are now handled like it's the NPC, because the client thinks the zombie ID is your NPC (because you send a PacketPlayOutNamedEntitySpawn with the zombie ID).

    BigTeddy98, Sander.
     
  9. Offline

    ResultStatic

    bigteddy98 ok ill take a look and post some updated code
     
  10. Offline

    lenis0012

    1) Dont store entity instances in a list.
    2) You arte checking if you bukkit entity equals to an nms entity in your example.
    Your code will never be executed.
    3) You are not calling entity base ticks, the fake players wont get damages when hit by potions or standing in lava.
    4) You don't need to use packets to change player equipment
    5) There is no need to override each methods on PlayerConnection, it doesn't block all functions either.
    6) Isn't all this code just a NPCLib rip-off?
     
    elementalgodz11 and Garris0n like this.
  11. Im just wondering, how did Citizens made their NPC's move? (like walking, sneaking, etc)
    I know I can make the entity sneak, but walk?
     
  12. Offline

    lenis0012

    Check my npcfactory
     
    Someone_Like_You likes this.
  13. Offline

    minelazz

    thanks, works like a charm :)
     
  14. Offline

    ResultStatic

    lenis0012 npclib is 1.7.2 and some people dont want to download libraries and rely on them. o and stop advertising your npc factory here. people on this thread want to make their own not download one. this converts the player into a EntityPlayer. the only mistake i made was not checking if its a player before casting.
    Code:
    EntityPlayer damaged = NmsApi.getCraftPlayer(((Player)e.getEntity()));
    if (NPCManager.npcs.containsValue(damaged)){

    1. i dont see why its a problem unlike real players they dont log out and their data isnt updated because they cant log back in which is the problem with storing players instances.

    2. already explained why you are wrong there

    3. thanks ill update that. :rolleyes:

    4. he said the method didnt work so i gave him a way to do it.

    5. i heard that if you dont override them it results in NPE errors from a bukkit staff member.

    6. npclib is a 1.7.2 library this is a 1.7.9 resource so please hop off.

    bigteddy98 dude that is awesome. i got it to work ill post some code soon now that i can use the zombie pathfinders

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

    lenis0012

    I meant the code.
    You can look at how i did the pathfinding.
    And when soneone needs something and you give him a inkl that helps its not advertising.
    Otherwise anyone who replies to a plugin request with an already existing plugin would be advertising.

    bigteddy98
    Faking spawn packets to use zombies is not safe.
    It will send player packet for a zombie, including their datawatcher.
    A lot of player functions will not work on the npc, and the npc will randomly turn on fire.
    He will make zombie noises.
    He will not store an inventory.
    He will not be recognized as a player so the zombie will msot likeely get removed with /butcher.
    A zombie can randomly despawn from mob limiters.

    Very funny that you linked a 1.7.9 compatible npclib above then.
    https://github.com/caliog/NPCLib

    But i must be mistaken, sorry.

    One last thing tho, storing EntityPlayer instnaces is still not right.
    Regular plugins would be relying on it, and if people doint understand NMS they will make sill checks that will never be true. Its also known to be a memory leak.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 30, 2016
  16. Offline

    bigteddy98

    If you do it in the good sequence, you will cancel the spawn packet and send the player spawn packet instead. The datawatcher will be send and can most of it can probably be read normally by the client.

    An inventory seems not necessarily to an NPC for me, because setting armour and weapons is possible.

    The zombie will make noises, but like I said, spawn a custom zombie without noises or spawn a creeper and make in invinsible.

    And indeed, it won't be recognized as a player, that's logic. I don't think this will be a problem because you want it to have the behaviour of a mob, so why not the properties of the mob.
     
  17. Offline

    Plo124

    I dont think you should cast the n.getBukkitEntity() to a Player since they aren't online (sending a packet to that player wouldnt do anything)



    You can make a method which will call an event when the entity takes damage, and stuff like that.
     
  18. Offline

    ResultStatic

    Plo124 it should be fine because you can cast Player to CraftPlayer which is what n.getBukkitEntity returns.
     
  19. Offline

    Plo124

    ResultStatic
    I guess.. Unless your getting a ClassCastException I guess it will work
     
  20. Offline

    ResultStatic

    bigteddy98 um not sure what im doing wrong but i have been stuck. the client crashes when ever i try to spawn a custom zombie. the transform packet and everything works fine but now just spawning a zombie that extend EntityZombie works fine in the console but crashes the client. its so annoying because the only error log is in the minecraft client. spawning a zombie with EntityZombie zombie = new EntityZombie(world); works fine i can even transform it into a player and do everything but for some reason extending EntityZombie crashes the client.

    minecraft client side stack trace
    Code:
    java.lang.NullPointerException: Unexpected error
        at bln.a(SourceFile:508)
        at fz.a(SourceFile:97)
        at fz.a(SourceFile:15)
        at ej.a(SourceFile:174)
        at blq.e(SourceFile:212)
        at ban.p(SourceFile:1306)
        at ban.ak(SourceFile:774)
        at ban.f(SourceFile:728)
        at net.minecraft.client.main.Main.main(SourceFile:148)
     
     
    A detailed walkthrough of the error, its code path and all known details is as follows:
    ---------------------------------------------------------------------------------------
     
    -- Head --
    Stacktrace:
        at bln.a(SourceFile:508)
        at fz.a(SourceFile:97)
        at fz.a(SourceFile:15)
        at ej.a(SourceFile:174)
        at blq.e(SourceFile:212)
    

    Code:
    import net.minecraft.server.v1_7_R3.WorldServer;
    import org.bukkit.Location;
    import org.bukkit.craftbukkit.v1_7_R3.CraftWorld;
     
    public class NPC {
     
        public void spawnHumanNPC(String name, Location l) {
            CraftWorld w = (((CraftWorld)l.getWorld()));
            WorldServer world = w.getHandle();
            CustomZombie zombie = new CustomZombie(world);
            zombie.setPositionRotation(l.getX(), l.getY(), l.getZ(), l.getYaw(), l.getPitch()); // doesnt show the zombie or send any data to the client
            // world.addEntity(zombie); tried this, crashes the client
            zombie.teleportTo(l, false); // crashes the client. anything that causes custom zombie packets to be spawned crashes the client
            }
     
    }
    Code:
    import net.minecraft.server.v1_7_R3.EntityZombie;
    import net.minecraft.server.v1_7_R3.World;
     
    public class CustomZombie extends EntityZombie {
       
    public CustomZombie(World world) {
    super(world);
     
    }
    }
    
    Code:
    public class TestFor implements CommandExecutor{
       
     
          public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args){
          if (sender instanceof Player){
            if (commandLabel.equalsIgnoreCase("testfor")) {
                Player player = (Player)sender;
                NPC npc = new NPC();
                npc.spawnHumanNPC(args[0], player.getLocation());
    } 
         
          }
        return false;
          }
          }
     
  21. Offline

    bigteddy98

    Spawning custom entities (which extend an EntityInsentient, almost all mobs do) require to be registered. Otherwise the client does not know the ID of the entity and it will crash. I made a simple method for this you could use a few eeks ago: https://forums.bukkit.org/threads/e...obs-without-replacing-the-default-mob.264172/

    The method should only be called once, I prefer in the onEnable. I hope this helps you,

    BigTeddy98, Sander.

    EDIT: if you have more questions msg me, because we're going a bit off-topic here ;)
     
Thread Status:
Not open for further replies.

Share This Page