[Util][1.7.2] Auto-Respawn

Discussion in 'Resources' started by kreashenz, Jun 16, 2013.

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

    kreashenz

    So, I know I'm not the best with making plugins, but people are always requesting or needing help with making auto-respawn. I made this to show you how to do it, and I'm going to make it short and sweet. There is 3 methods that can be used in this.

    Method one
    So first off, you need to have CraftBukkit as a Java Build Path so you can use the NMS (net.minecraft.server) & OBC (org.bukkit.craftbukkit) codes. You will need to import 2 things.
    Code:java
    1. import net.minecraft.server.v1_7_R1.EntityPlayer;
    2. import net.minecraft.server.v1_7_R1.EnumClientCommand;
    3. import net.minecraft.server.v1_7_R1.PacketPlayInClientCommand;
    4. import org.bukkit.craftbukkit.v1_7_R1.entity.CraftPlayer;

    These imports are from the 1.7.2 Development Build. Download here.

    Secondly, you're going to need to use it in the PlayerDeathEvent or EntityDeathEvent, even though casted to a CraftPlayer, I believe it'd still work with the EntityDeathEvent.

    The packet is called "Packet205ClientCommand" and this will click the 'Respawn' button on your screen when you die. The code you should use, to call this is
    Code:java
    1. @EventHandler
    2. public void onPlayerDeath(PlayerDeathEvent e){
    3. Player p = e.getEntity();
    4. PacketPlayInClientCommand in = new PacketPlayInClientCommand(EnumClientCommand.PERFORM_RESPAWN); // Gets the packet class
    5. EntityPlayer cPlayer = ((CraftPlayer)p).getHandle(); // Gets the EntityPlayer class
    6. cPlayer.playerConnection.a(in); // Handles the rest of it
    7. }


    Method two
    This method CAN leave a little bug with it, that may leave you still laying down dead, but it still respawns you.

    First you need to get the EntityDamageEvent/EntityDamageByEntityEvent, then heal and do whatever the that player. This way, a player will actually not die, but it is still a sort of auto-respawn, I guess.
    Code:java
    1. @EventHandler
    2. public void onEntityGetHit(EntityDamageEvent e){
    3. if(e.getEntity() instanceof Player){
    4. Player p = (Player)e.getEntity(); // p is going to be the one getting teleported.
    5. if(p.getHealth() <= 0){
    6. p.setHealth(20);
    7. p.setFoodLevel(20);
    8. p.setFireTicks(0);
    9. for(PotionEffect pot: p.getActivePotionEffects())p.removePotionEffect(pot.getType()); //Removes all the active potion effects the player has.
    10. // Do whatever else needs doing.
    11. }
    12. }
    13. }


    Method three
    This method is using reflection, something that I'm not very good at, and hope to learn soon. Credits go to Minecrell for this one! And to me for updating it!
    Code:java
    1. @EventHandler
    2. public void onPlayerDeath(PlayerDeathEvent e){
    3. Player p = e.getEntity();
    4. try {
    5. Object nmsPlayer = p.getClass().getMethod("getHandle").invoke(p);
    6. Object packet = Class.forName(nmsPlayer.getClass().getPackage().getName() + ".PacketPlayInClientCommand").newInstance();
    7. Class<?> enumClass = Class.forName(nmsPlayer.getClass().getPackage().getName() + ".EnumClientCommand");
    8.  
    9. for(Object ob : enumClass.getEnumConstants()){
    10. if(ob.toString().equals("PERFORM_RESPAWN")){
    11. packet = packet.getClass().getConstructor(enumClass).newInstance(ob);
    12. }
    13. }
    14.  
    15. Object con = nmsPlayer.getClass().getField("playerConnection").get(nmsPlayer);
    16. con.getClass().getMethod("a", packet.getClass()).invoke(con, packet);
    17. }
    18. catch(Throwable t){
    19. t.printStackTrace();
    20. }
    21. }


    So that's basically it. I personally don't like the second method because you have to do all the stuff manually, and because it doesn't count the kill. But the first one also has some downsides, and that is the constant updating of the plugin/code.

    Hopefully this helped some of you, and I was mainly aiming this at the newbies! :) Thanks for reading, and hope you learned something from this.
     
  2. Offline

    SgtPunishment

    I have actually learned something lol... I've been wondering how to import the whole NMS stuff... your post explains it lol
     
  3. Offline

    GaaTavares

    I was searching that, i have a kitpvp server and i think this can fix bugs ( lol ), thank you man :D
    U helped a brazilian :)
     
  4. Offline

    Tzeentchful

    kreashenz
    Your first method is not ideal as it requires importing of NMS code which will make plugins break every minecraft update.
    You can achieve the same thing with reflection without it breaking every update.
    Code:java
    1. public static void forceRespawn(Player player, YourPlugin plugin) {
    2. String version = getVersion(plugin);
    3. try {
    4. Class<?> packet = Class.forName("net.minecraft.server."+version.replace(".", "_") +".Packet205ClientCommand");
    5. Object name = packet.getConstructor(new Class[0]).newInstance(new Object[0]);
    6. Field a = packet.getDeclaredField("a");
    7. a.setAccessible(true);
    8. a.set(name, 1);
    9. Object nmsPlayer = Class.forName("org.bukkit.craftbukkit."+version.replace(".", "_")+".entity.CraftPlayer").getMethod("getHandle", new Class[0]).invoke(player, new Object[0]);
    10. Field con = Class.forName("net.minecraft.server."+version.replace(".", "_") +".EntityPlayer").getDeclaredField("playerConnection");
    11. con.setAccessible(true);
    12. Object handle = con.get(nmsPlayer);
    13. packet.getDeclaredMethod("handle", Class.forName("net.minecraft.server."+version.replace(".", "_") +".Connection")).invoke(name, handle);
    14. } catch(Exception e) {
    15. e.printStackTrace();
    16. }
    17. }
    18.  
    19. private static String getVersion(YourPlugin plugin) {
    20. String packageName = plugin.getServer().getClass().getPackage().getName();
    21. return packageName.substring(packageName.lastIndexOf('.') + 1);
    22. }


    The code isn't very optimized. I might make another thread with a better version.
     
    jimuskin, Cirno, kreashenz and 3 others like this.
  5. Offline

    skipperguy12

    Tzeentchful

    Thanks, but I tried this:
    Code:
            String version = NoDSOD.packageName;
            Bukkit.getLogger().info(version);
            try {
                Class<?> packet = Class.forName("net.minecraft.server." + version.replace(".", "_")
                        + ".Packet205ClientCommand");
                Object name = packet.getConstructor(new Class[0]).newInstance(new Object[0]);
                Field a = packet.getDeclaredField("a");
                a.setAccessible(true);
                a.set(name, 1);
                Object nmsPlayer = Class
                        .forName(
                                "org.bukkit.craftbukkit." + version.replace(".", "_")
                                        + ".entity.CraftPlayer").getMethod("getHandle", new Class[0])
                        .invoke(player, new Object[0]);
                Field con = Class.forName(
                        "net.minecraft.server." + version.replace(".", "_") + ".EntityPlayer")
                        .getDeclaredField("playerConnection");
                con.setAccessible(true);
                Object handle = con.get(nmsPlayer);
                packet.getDeclaredMethod(
                        "handle",
                        Class.forName("net.minecraft.server." + version.replace(".", "_")
                                + ".Connection")).invoke(name, handle);
            } catch (Exception e) {
                e.printStackTrace();
            }
    And my logger says:
    v1_5_R3
    And that seems right, but the player does not respawn? Why is this?
     
  6. Offline

    Tzeentchful

  7. Offline

    GaaTavares

    The first way is not working, but the 2 way is working.
     
  8. Offline

    skipperguy12

    Tzeentchful
    Not at all, I'm trying to use your method for a plugin I wrote a while back called NoDSOD, it just removes the death screen, but I'm too lazy to update it every time.
     
  9. Offline

    kreashenz

    Well, thanks Tzeentchful and I am not really a fan of reflection, so that's new to me. I can add your method above, if you want?
     
  10. Offline

    TheTinySpider

    Can't you wait 1 or 2 ticks, and then force respawn? So the server has a little time to remove your dead body before respawning you :)
     
  11. Offline

    Minecrell

    I would do it like this using reflection. Maybe it is a little bit simpler than Tzeentchful's ones. Use it if you want :p
    Code:java
    1. @EventHandler
    2. public void onPlayerDeath(PlayerDeathEvent event) {
    3. Player player = event.getEntity();
    4.  
    5. try {
    6. Object nmsPlayer = player.getClass().getMethod("getHandle").invoke(player);
    7.  
    8. Object packet = Class.forName(nmsPlayer.getClass().getPackage().getName() + ".Packet205ClientCommand").newInstance();
    9. packet.getClass().getField("a").set(packet, 1);
    10.  
    11. Object con = nmsPlayer.getClass().getField("playerConnection").get(nmsPlayer);
    12. con.getClass().getMethod("a", packet.getClass()).invoke(con, packet);
    13. } catch (Throwable e) {
    14. e.printStackTrace();
    15. }
    16. }
     
  12. Offline

    mbaxter ʇıʞʞnq ɐ sɐɥ ı

    No, you can pray it doesn't break on updates. Your reflection approach could instead result in a client or server crash or worse world corruption due to changing internals. Building against specific versions is the safest way to handle something. Check my tutorial in the resources forum on building support for multiple versions with maven for a way to build a plugin that supports multiple versions of minecraft.
     
  13. Offline

    Tzeentchful

    It would be extremely unlikely that my method would cause any sort of damage to a server. The only way it could cause damage is if Mojang decided to change the respawn packet to another one or some internals changed very distractedly and keept the same package/method name. The chance of it doing damage is negligible. And perhaps if the bukkit API allowed us more freedom with packtets and stuff you wouldn't have to have package versioning and force us to find ways around it using reflection or annoying maven setups.
     
    microgeek and Bone008 like this.
  14. Offline

    Ultimate_n00b

    While I know that this is old, I would like to point out that the packet 205 is considered a bad id in 1.6.4. What packet do you use now?
    mbaxter I feel like it not working now strengthens your point =p
     
  15. Offline

    BungeeTheCookie

    Ultimate_n00b
    This wouldn't even work in 1.7.2. What class replaced Packet205CilentCommand?
     
  16. Offline

    kreashenz

    BungeeTheCookie Uh, I'll figure the thing out for 1.7.2. Gimme a few hours, need to see if it is still just changing an int.
     
  17. Offline

    chasechocolate

    Stigosaurus likes this.
  18. Offline

    MrInspector

    Yeah, pain in the a**, some of my plugins stopped working because I was using packets that have been changed to something I don't know about.

    Packet205ClientCommand was in a lot of plugins I was using, did they change it to something else or remove it?
     
  19. Offline

    kreashenz

    Updated for 1.7.2. Reflectionized method included.
     
  20. Offline

    Mang0eZPvP

    Look for PacketPlayInClientCommand

    Look for PacketPlayInClientCommand sorry sent to wrong person

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

    kreashenz

  22. Offline

    Mang0eZPvP

    since when... it seems to be the same for me... :p
     
  23. Offline

    xTrollxDudex

    Mang0eZPvP
    Refresh your page...
     
  24. Offline

    xepisolonxx

    Thank you
     
Thread Status:
Not open for further replies.

Share This Page