Mobdisguise feature

Discussion in 'Plugin Development' started by black_ixx, Nov 4, 2012.

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

    I want to add a new feature to my plugin which allows the player to disguise into a zombie/skeleton/pigzombie.

    Why dont you use Mobdisguise or Disguisecraft?
    The plugins are nice but I dont need their features. They also need alot of RAM.
    I just want the players to transform into the three mobs.

    Thats my code (a part was copied from the Mobdisguise-source (the developer allowed me to do that)):


    Code:
        public static void disguiseToAll(Player p1, byte type) {
            //Make packets out of loop!
            Packet24MobSpawn p24 = packetMaker(p1,type);
            for (Player p2 : p1.getWorld().getPlayers()) {
                if (p2 == p1) {
                    continue;
                }
                p2.hidePlayer(p1);
                ((CraftPlayer) p2).getHandle().netServerHandler.sendPacket(p24);
            }
        }
       
       
        public static Packet24MobSpawn packetMaker(Player p1, Byte id) {
            DataWatcher tmp = null;
            if(MobDisguise.data.get(p1.getName()) == null) {
                tmp = new DataWatcher();
                MobDisguise.data.put(p1.getName(), tmp);
            }
            else {
                tmp = MobDisguise.data.get(p1.getName());
            }
            Location loc = p1.getLocation();
            Packet24MobSpawn packet = new Packet24MobSpawn();
            packet.a = ((CraftPlayer) p1).getEntityId();
            packet.b = id.byteValue();
            packet.c = MathHelper.floor(loc.getX() * 32.0D);
            packet.d = MathHelper.floor(loc.getY() * 32.0D);
            packet.e = MathHelper.floor(loc.getZ() * 32.0D);
            packet.j = (byte) ((int) (loc.getPitch() ));
            packet.i = (byte) ((int) loc.getYaw() );
            packet.k=packet.i;
            //packet.f = (byte) ((int) loc.getYaw() * 256.0F / 360.0F);
          // packet.g = (byte) ((int) (loc.getPitch() * 256.0F / 360.0F));
          // packet.h= packet.f;
            //Field datawatcher;
            try {
                Field metadataField = packet.getClass().getDeclaredField("s");
                metadataField.setAccessible(true);
                metadataField.set(packet, tmp);
                /*datawatcher = packet.getClass().getDeclaredField("i");
                datawatcher.setAccessible(true);
                datawatcher.set(packet, tmp);
                datawatcher.setAccessible(false);*/
            } catch (Exception e) {
                System.out.print(e.getStackTrace().toString());
                System.out.print(e.getMessage());
                System.out.println("Error making packet?!");
                return null;
            }
            return packet;
        }
    The packet was successfully created, but the players client crashed as he got it. I think something is missing. But what?

    Help is welcome!
     
  2. Because the client already has an entity with that id. You need to remote that one first using the despawn packet.
     
    black_ixx likes this.
  3. with Packet29DestroyEntity?
     
  4. Possibly, I haven't taken a look into packets and such that much, so how about trying it out by yourself? If it fails we and you know more than before...
     
  5. Ive added the destroy-packet but the client is still crashing... same error it looks like the packet was sent without success. Code:
    Code:
        Set<String> disguisedPlayers = new HashSet<String>();   
        public static Map<String, DataWatcher> data = new HashMap<String, DataWatcher>();
     
        public static void setPToZombie(Player p1) {
            disguiseToAll(p1, (byte)54);
        }
        public static void setPToSkeleton(Player p1) {
            disguiseToAll(p1, (byte)51);
        }
        public static void setPToPigzombie(Player p1) {
            disguiseToAll(p1, (byte)57);
        }
       
       
        public static void disguiseToAll(Player p1, byte type) {
            Packet24MobSpawn p24 = packetMaker(p1,type);
            Packet29DestroyEntity p29 = new Packet29DestroyEntity(((CraftPlayer)p1).getEntityId());
            for (Player p2 : p1.getWorld().getPlayers()) {
                if (p2 == p1) {
                    continue;
                }
     
                ((CraftPlayer) p2).getHandle().netServerHandler.sendPacket(p29);
                ((CraftPlayer) p2).getHandle().netServerHandler.sendPacket(p24);
            }
        }
       
       
        public static Packet24MobSpawn packetMaker(Player p1, Byte id) {
            DataWatcher tmp = null;
            if(MobDisguise.data.get(p1.getName()) == null) {
                tmp = new DataWatcher();
                MobDisguise.data.put(p1.getName(), tmp);
            }
            else {
                tmp = MobDisguise.data.get(p1.getName());
            }
            Location loc = p1.getLocation();
            Packet24MobSpawn packet = new Packet24MobSpawn();
            packet.a = ((CraftPlayer) p1).getEntityId();
            packet.b = id.byteValue();
            packet.c = MathHelper.floor(loc.getX() * 32.0D);
            packet.d = MathHelper.floor(loc.getY() * 32.0D);
            packet.e = MathHelper.floor(loc.getZ() * 32.0D);
            packet.j = (byte) ((int) (loc.getPitch() ));
            packet.i = (byte) ((int) loc.getYaw() );
            packet.k=packet.i;
            try {
                Field metadataField = packet.getClass().getDeclaredField("s");
                metadataField.setAccessible(true);
                metadataField.set(packet, tmp);
            } catch (Exception e) {
                System.out.print(e.getStackTrace().toString());
                System.out.print(e.getMessage());
                System.out.println("Error making packet?!");
                return null;
            }
            return packet;
        }
     
  6. Try sending the destroy of the player entity id first, then sending the spawning of a mob with a new id to the client.
    That's all I can think of, but it would mean you had to pass all movement that were made on the server (by the player entity ID) to the client as movements of the fake entity ID you sent them.

    I'm giving a work-around solution here, I don't guarantee it works and it is BAD, so I hope there's others who can solve this :)
     
    black_ixx likes this.
  7. Offline

    fireblast709

    I think I have pinpointed the problem.
    Code:java
    1. public static Packet24MobSpawn packetMaker(Player p1, Byte id) {
    2. DataWatcher tmp = null;
    3. if(data.get(p1.getName()) == null)
    4. {
    5. tmp = new DataWatcher();
    6. data.put(p1.getName(), tmp);
    7. }
    8. else {
    9. tmp = data.get(p1.getName());
    10. }
    11. Location loc = p1.getLocation();
    12. EntityZombie zom = new EntityZombie(((CraftWorld)loc.getWorld()).getHandle());
    13. zom.setLocation(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch());
    14. Packet24MobSpawn packet = new Packet24MobSpawn(zom);
    15. /*try {
    16.   Field metadataField = packet.getClass().getDeclaredField("s");
    17.   metadataField.setAccessible(true);
    18.   metadataField.set(packet, tmp);
    19.   } catch (Exception ex) {
    20.   System.out.print(ex.getStackTrace().toString());
    21.   System.out.print(ex.getMessage());
    22.   System.out.println("Error making packet?!");
    23.   return null;
    24.   }*/
    25. if(packet == null)
    26. {
    27. log.info("NUUUUUUUUULLLLPOOOOIINNNTTEEEREEEXXCEEEPPTTIIIOOOONN");
    28. }
    29. return packet;
    30. }

    I commented out the try/set and suddenly it stopped crashing the client :3 (though it spawns a zombie that does absolutely nothing). So you should somehow fill the datawatcher, as it throws a NPE in the client. (searching for a solution at the very moment :3)
     

  8. Indeed by

    Spawn Mob (0x18)

    Server to Client
    Sent by the server when a Mob Entity is Spawned
    Packet ID Field Name Field Type Example Notes
    0x18 EID int 446 Entity ID
    Type byte 91 The type of mob. See Entities#Mobs
    X int 13366 The Absolute Integer X Position of the object
    Y int 2176 The Absolute Integer Y Position of the object
    Z int 1680 The Absolute Integer Z Position of the object
    Yaw byte -27 The yaw in steps of 2p/256
    Pitch byte 0 The pitch in steps of 2p/256
    Head Yaw byte Head yaw in steps of 2p/256
    Velocity Z short 0
    Velocity X short 0
    Velocity Y short 0
    Metadata Metadata 127 Varies by mob, see Entities
    Total Size:
    27 bytes + Metadata (at least 1)

    (from http://wiki.vg/Protocol)

    it seems that all of these must have a value in the packet or the client will probably crash. Sometimes the client doesn't crash but that will mean the client has given some object a state that is not possible, which will usually result in the server kicking the client for 'illegal <insert action here haha>'.

    For example if you don't specify a metadata the client will usually crash. Best thing to try is send an empty metadata. And of course make sure the packet has all the other values set. Not just initialized, but really set to some value.

    If I'm posting this at the wrong time at the wrong place, then sorry in advance. XD
     
  9. Offline

    fireblast709

    Muizers no his original code threw a NPE in the client. My code does not, but properly defined movements are still needed. This code actually uses one of the Packet24MobSpawn's constructors to fill in that data, so the packet I use is legit
     
  10. I know that's what I got.

    Justed wanted to add some information.
     
Thread Status:
Not open for further replies.

Share This Page