Disguising a Player as a Mob

Discussion in 'Plugin Development' started by TeeePeee, Mar 17, 2015.

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

    TeeePeee

    Hi guys,

    I'm at my wit's end trying to figure out how to do this, so here goes.

    I'm trying to disguise a player as a mob. Yes, I know there are disguise plugins and I have perused some source codes, but to no avail. This is what I do:

    Definitions:
    • disguised: The Player being disguised
    • entity: The faux-mob (disguise)
    1. Construct a PacketPlayOutEntityDestroy packet using the entity ID of disguised.
    2. Create a new NMS EntityLiving (entity), setting its position and ID to the position/ID of disguised.
    3. Construct a PacketPlayOutSpawnEntityLiving packet using entity.
    4. Send the packet created in (1), and then the packet created in (2) to all players.
    Code:
    Player disguised;
    Class<? extends EntityLiving> disguise;
    
    PacketPlayOutEntityDestroy destroyPacket = new PacketPlayOutEntityDestroy(disguised.getEntityId());
    
    World world = ((CraftWorld) disguised.getWorld()).getHandle();
    
    // Same as (ie.) new EntityZombie(world)
    EntityLiving entity = disguise.getConstructor(World.class).newInstance(world);
    
    entity.setPosition(...);
    // Sets the entity's ID.
    entity.d(disguised.getEntityId());
    
    PacketPlayOutSpawnEntityLiving spawnPacket = new PacketPlayOutSpawnEntityLiving(entity);
    
    for(Player inPlayer : Bukkit.getOnlinePlayers()) {
        if(inPlayer.equals(disguised)) { continue; }
    
        PlayerConnection connection = ((CraftPlayer) inPlayer).getHandle().playerConnection;
        connection.sendPacket(destroyPacket);
        connection.sendPacket(spawnPacket);
    }
    And that's all well and good. The only problem is that the observers don't render the disguise. In fact, they don't render anything at all, until randomly, they start rendering the disguise (ie. Observers see nothing, then randomly start seeing disguise). I can't figure out what I have to do to force a refresh to make the disguise show... I've tried sending teleport, metadata, and attribute packets as well as trying to refresh the trackers (EntityTrackerEntry) for each player, but nothing is doing the trick.

    tl;dr:

    When I send a destroy packet, followed by a spawn packet (of an entity with the same ID), clients fail to render the spawn packet for a random length of time.


    Thanks for your insight!
     
    ChipDev likes this.
  2. Offline

    Funergy

    @TeeePeee Make sure your spawning is right.
    Code:
    World mcWorld = ((CraftWorld) p.getWorld()).getHandle();
                CustomEntity sp = new CustomEntity(mcWorld);
                sp.setLocation(p.getLocation().getX(), p.getLocation().getY(),
                        p.getLocation().getZ(), p.getLocation().getYaw(), p.getLocation().getPitch());
                ((CraftLivingEntity) sp.getBukkitEntity())
                        .setRemoveWhenFarAway(false);
               // mcWorld.addEntity(sp, CreatureSpawnEvent.SpawnReason.CUSTOM); This line is for showing it for everyone
     
  3. Offline

    TeeePeee

  4. Offline

    Funergy

    @TeeePeee
    Have you tried
    PacketPlayOutEntityMetadata?
    Or
    ((CraftLivingEntity) sp.getBukkitEntity()).setRemoveWhenFarAway(false);

    I dont see why it doesnt spawn, the packet for the spawning works perfectly fine for me.
     
  5. Offline

    TeeePeee

    @Funergy
    Just tried both, and no dice :(.

    I constructed the Metadata packet such that:
    Code:
    Player disguised;
    EntityLiving entity;
    
    PacketPlayOutEntityMetadata meta = new PacketPlayOutEntityMetadata(disguised.getEntityId(), entity.getDataWatcher(), true);
     
  6. Offline

    Funergy

    @TeeePeee I'm going to see how I did it(switching OS).

    The answer will be located in this post.

    Answer:

    Idk why. But you are destroying 2 entities with the same id.

    1. you create the packet with the player's entity id.
    2. you give the zombie the same id as the player.
    3. and then you send the destroy packet.

    I think you should send the destroy packet first. and then change the id.

    And the reason it comes back is because of the tracker. It tracks the entity and then it shows it to you.
     
    Last edited: Mar 17, 2015
    ChipDev likes this.
  7. Offline

    TeeePeee

    @Funergy
    Thanks in advance! I'll update my post when I see your response, letting you know the results.

    [EDIT]
    @Funergy
    Interesting. I don't know why I didn't think to do that in the first place, but thanks!

    Now, the observer sees the spawn packet. But it doesn't track to the disguised player's location (it's just a stationary mob). I'll try messing with the trackers to see if I can make it track properly.
     
    Last edited: Mar 17, 2015
  8. Offline

    Funergy

    @TeeePeee Well now you should try updating the PacketPlayOutEntityMetadata and also check if it actually changes it to the player's location.
     
  9. Offline

    TeeePeee

    @Funergy
    Tried the following:

    1. Send PacketPlayOutEntityMetadata(id, <DATAWATCHER OF SPAWNED ENTITY>, true) immediately after spawn packet.
    2. Send Metadata packet after 20 tick delay (ensuring to move the disguised player).
    3. Refresh trackers for the player that is being disguised.
    The first two had the same result: The mob packet is sent to the observer and seen, but the disguised player disappears completely and the mob packet does not follow their location. The metadata had no visible effect.

    The third did almost the same as the first two, only once the trackers were refreshed, the player reappeared (along with the stationary mob packet), but not disguised.

    Thanks for everything thus far, but do you have any other ideas?
     
  10. Offline

    ChipDev

    Im wondering this too just so I can know about it..!
     
  11. Offline

    Funergy

    @TeeePeee Create a custom mob get the move method and add a little debug message if it actually updates.
    And are you sure changing the entity his id to the one of the player actually works?
     
  12. Offline

    Cycryl

    alternatively use
    Entity e = world.spawnEntity(Location,EntityType)
    PacketPlayOutSpawnEntity packet = new PacketPlayOutSpawnEntity(e);
    try{
    Field f = packet.getClass().getDeclaredField("a");
    f.setAccessible(true);
    f.setInt(player.getEntityId());
    f.setAccessible(false);
    }catch(Exception e){}
    e.remove();
    for(){
    ((CraftPlayer)player).getHandle().playerConnection().sendPacket();
    }
     
  13. Offline

    TeeePeee

    @Funergy
    The problem is that I don't want to spawn in a real mob. I just want the clients to track as if there was one at that position (the position of the player). I know that this is how most disguise plugins work; trick the observers to think that a player connection is actually a mob so they track it as the player instead. But as soon as I add a real mob to the game, it's pathfinders and such will take over.

    I am sure that the d(Id) method sets the entity ID though.
     
  14. Offline

    Funergy

    @TeeePeee Clear the mob its path finders then with reflection.

    And also there is a simple resource from @mine-care in the resource section! You can check here if its the right way you're doing.
     
    mine-care likes this.
Thread Status:
Not open for further replies.

Share This Page