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 import net.minecraft.server.v1_7_R1.EntityPlayer;import net.minecraft.server.v1_7_R1.EnumClientCommand;import net.minecraft.server.v1_7_R1.PacketPlayInClientCommand;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 @EventHandler public void onPlayerDeath(PlayerDeathEvent e){ Player p = e.getEntity(); PacketPlayInClientCommand in = new PacketPlayInClientCommand(EnumClientCommand.PERFORM_RESPAWN); // Gets the packet class EntityPlayer cPlayer = ((CraftPlayer)p).getHandle(); // Gets the EntityPlayer class cPlayer.playerConnection.a(in); // Handles the rest of it } 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 @EventHandler public void onEntityGetHit(EntityDamageEvent e){ if(e.getEntity() instanceof Player){ Player p = (Player)e.getEntity(); // p is going to be the one getting teleported. if(p.getHealth() <= 0){ p.setHealth(20); p.setFoodLevel(20); p.setFireTicks(0); for(PotionEffect pot: p.getActivePotionEffects())p.removePotionEffect(pot.getType()); //Removes all the active potion effects the player has. // Do whatever else needs doing. } } } 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 @EventHandler public void onPlayerDeath(PlayerDeathEvent e){ Player p = e.getEntity(); try { Object nmsPlayer = p.getClass().getMethod("getHandle").invoke(p); Object packet = Class.forName(nmsPlayer.getClass().getPackage().getName() + ".PacketPlayInClientCommand").newInstance(); Class<?> enumClass = Class.forName(nmsPlayer.getClass().getPackage().getName() + ".EnumClientCommand"); for(Object ob : enumClass.getEnumConstants()){ if(ob.toString().equals("PERFORM_RESPAWN")){ packet = packet.getClass().getConstructor(enumClass).newInstance(ob); } } Object con = nmsPlayer.getClass().getField("playerConnection").get(nmsPlayer); con.getClass().getMethod("a", packet.getClass()).invoke(con, packet); } catch(Throwable t){ t.printStackTrace(); } } 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.
I have actually learned something lol... I've been wondering how to import the whole NMS stuff... your post explains it lol
I was searching that, i have a kitpvp server and i think this can fix bugs ( lol ), thank you man U helped a brazilian
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 public static void forceRespawn(Player player, YourPlugin plugin) { String version = getVersion(plugin); 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(); }} private static String getVersion(YourPlugin plugin) { String packageName = plugin.getServer().getClass().getPackage().getName(); return packageName.substring(packageName.lastIndexOf('.') + 1);} The code isn't very optimized. I might make another thread with a better version.
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?
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.
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?
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
I would do it like this using reflection. Maybe it is a little bit simpler than Tzeentchful's ones. Use it if you want Code:java @EventHandler public void onPlayerDeath(PlayerDeathEvent event) { Player player = event.getEntity(); try { Object nmsPlayer = player.getClass().getMethod("getHandle").invoke(player); Object packet = Class.forName(nmsPlayer.getClass().getPackage().getName() + ".Packet205ClientCommand").newInstance(); packet.getClass().getField("a").set(packet, 1); Object con = nmsPlayer.getClass().getField("playerConnection").get(nmsPlayer); con.getClass().getMethod("a", packet.getClass()).invoke(con, packet); } catch (Throwable e) { e.printStackTrace(); } }
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.
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.
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
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.
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?
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.