Bypass respawn screen

Discussion in 'Plugin Development' started by slater96, Aug 1, 2012.

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

    slater96

    How do I do it so that when a player dies, they don't have the respawn screen. because for lives I want it so they just respawn. Thanks
     
  2. Offline

    d33k40

    If player get damage:
    -if damage >= than health:
    --Cancel event
    --Announce his death to all users
    --Reset his health, food level, inventory, armors, potion effects
    --Teleport to spawn the player
     
    gidonyou likes this.
  3. Offline

    slater96

    Ugh I have to reset it all :(
    Thanks
     
  4. Offline

    d33k40

    np mate

    check this, i use it for one of my plugins:
    Code:
                        //Clear inventory
                        PlayerInventory inv = player.getInventory();
                        inv.clear();
     
                        //Reset armors
                        inv.setHelmet(new ItemStack(Material.AIR));
                        inv.setChestplate(new ItemStack(Material.AIR));
                        inv.setLeggings(new ItemStack(Material.AIR));
                        inv.setBoots(new ItemStack(Material.AIR));
                       
                        //Reset potion efects
                        for(PotionEffect e : player.getActivePotionEffects()){
                        player.addPotionEffect(new PotionEffect(e.getType(), 0 ,0), true);
                        }
    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 27, 2016
  5. Offline

    Chlorek

    However method that d33k40 said is not too good. Some other plugins may do not work properly, because player never really dies. I do not know any other mehod, but I think this one is not right good.
     
    Chr0mosom3 likes this.
  6. Offline

    d33k40

    I know that the method isnt good but, as you say you dont know other method and me neither.

    PD: anyway, thanks for the tip
     
  7. The method is pretty ugly and breaks a LOT!
    I've heard of a way to make the client bypass the respawn screen:
    [Open the Spoiler to see some thoughts of mine while writing, that lead to a simpler solution described below]
    foobar (open)
    On PlayerDeathEvent, call player.setHealth(SOMETHING_BIGGER_THAN_0).

    I've no idea if it still works, but I believe it made the player "stand back up" from death at his current (death) location. The thing is, it happens after he actually died on the server, so other plugins will work fine and his items/player state is actually reset.

    After that, you only need to make him respawn properly. I hope you understand that simply teleporting him to world's spawn isn't enough. I would directly call the native server method that is issued when the client actually sends a real respawn, let me check ...

    Okay, it seems to be ServerConfigurationManager.moveToWorld(...).
    Either call it directly (CraftServer --> MinecraftServer --> ServerConfigurationManager), or simply fake a respawn packet.
    That does validate that the player's health isn't above 0, though. So you have to reset it at first. Thinking of it again, the hack with setting health back up might even not be necessary. If you just make the player respawn on the server side (with the method described above), it probably overrides the "respawn" screen on the client. Not sure.

    Actually, let me try ...
    ... Found something very simple! See below.


    Okay, so the solution is actually REALLY simple! Simply tell the server the client pressed "Respawn", it will send appropiate packets and just ... cause a regular respawn. Everything on the server side works exactly the same.

    In your PlayerDeathEvent handler, simply do the following:
    Code:
            Bukkit.getScheduler().scheduleSyncDelayedTask(pluginInstance, new Runnable() {
                @Override
                public void run() {
                    ((CraftPlayer) player).getHandle().netServerHandler.a(new Packet9Respawn());
                }
            }, 10L); // change the delay to whatever you want; without any delay the player respawns before actually noticing that he is dead, dunno if you want that.
    What this exactly does is explained in the spoiler above.
     
    slater96 and d33k40 like this.
  8. Offline

    d33k40


    Good, thanks, nice to know.
     
  9. Offline

    Golui

    Tried to do it in 1.3, and it does not seem to be working. Unless, I am doing something wrong.
     
  10. Apparently, the packet sent is different now. They for some reason left in the method accepting a Packet9Respawn, but it doesn't do anything now.
    The new packet sent is Packet205ClientCommand with a payload of 1.

    New code as follows (untested, the client might bitch around since it loves doing that since 1.3):
    Code:
            Bukkit.getScheduler().scheduleSyncDelayedTask(pluginInstance, new Runnable() {
                @Override
                public void run() {
                    Packet205ClientCommand packet = new Packet205ClientCommand();
                    packet.a = 1;
                    ((CraftPlayer) player).getHandle().netServerHandler.a(packet);
                }
            }, someDelay);
     
  11. Offline

    aaomidi

    Makes the player invisible
     
  12. Offline

    Golui

    Bone008 Thanks! That came in handy! But, could you tell me what exactly does the "a" method do? It sends packet from client to server?

    aaomidi I believe it's a client-side glitch. Simple relog should fix that.
     
  13. Offline

    MrPmiguelP

    Or do inv.setArmourContents(null);
     
  14. Technically it's not "sending" the packet, it's not actually doing anything networking related.
    It's just the method that is normally called when a packet from the client is received, and it proccesses it. By calling it manually with a "fake" packet, it's just like the client actually sent the packet for the server.
    Here's the code that is executed in the method.
     
  15. Offline

    d33k40

    thats new
     
  16. Offline

    the_merciless

    Yeah, i was going to post my way but that is better.

    Heres mine anyway:

    p.getInventory().clear();
    p.getInventory().setArmorContents(new ItemStack[p.getInventory().getArmorContents().length]);
    p.setHealth(20);
    p.setFoodLevel(20);

    Im sure i tried, and was told, Material.AIR doesnt work? Guess i got it wrong if it works for you.
     
  17. Offline

    one4me

    If all you do is clear the inventory and set the health back up the player never actually dies, which could mess with other plugins; that and when a player dies, a lot more than just resetting the health and clearing the inventory happens.
     
  18. Offline

    the_merciless

    This is just a paste from one of my plugins, its used on a teleport not a death.
     
  19. Offline

    one4me

    Oh, ok. Also, I'm not sure if you'll find this helpful, but if you want to reset the other player variables: like xp, fire ticks, potion effects, etc - you can use reset() found in EntityPlayer.
     
  20. Offline

    the_merciless

    Thanks i have never come across that before, i think we have officialy jacked this thread now so lets let some people help with the problem in question.

    Also mcmyadmin does not edit the game in anyway, so it doesnt explain the severe lag.
     
  21. I think I'll bump this just to see if there is a way to do this in 1.4.6
     
  22. My described method should still work, they did however rename NetServerHandler to PlayerConnection:

    New Code (untested):
    Code:
    Packet205ClientCommand packet = new Packet205ClientCommand();
    packet.a = 1;
    ((CraftPlayer) player).getHandle().playerConnection.a(packet);
    (The method you are calling is this one)

    Still requires native classes, and I highly doubt they will ever add API for it, because it's "too technical" *cough*cough* ...
     
  23. Offline

    fireblast709

    Good luck with sending a client->server packet as a server->client packet :3
     
  24. Offline

    tommycake50

    and call a death event.
    Code:
    Bukkit.getPluginManager().callEvent(new PlayerDeathEvent(event.getPlayer(), event.getPlayer().getInventory(), 0, event.getPlayer().getExp(),event.getPlayer().getExp(),event.getPlayer().getExpToLevel(), event.getPlayer().getName() + "Has died"));
    otherwise plugins WILL break,
     
  25. Thanks for both reading the whole thread and for informing yourself before posting about something :)

    Giving you a real answer (even though it could be reasoned from the rest of the thread):
    The NetServerHandler/PlayerConnection class handles both packet directions. Its smaller part (mainly the method sendPacket(Packet)) is what handles a server->client packet, and is (obviously) called by the server.
    But here is also where client->server packets are being passed and processed. Those are usually the methods "a(PacketSubclass)" and are normally called by the part of the code that waits for incoming client packets.

    This is where my solution walks in: It simply tells that part of the class that a Packet205ClientCommand with payload 1 has been received by the player (which is a technique I refer to as "faking a client packet"). Thus, the whole server simply behaves as if the client actually pressed respawn.

    ... and handle possible changes of the death event, then call a respawn event, handle possible changes of that one as well, handle gamerules like "keepInventory", handle bukkit's API of keeping experience and handle everything else that is done in the background to correctly reset the player's state.

    Is it becoming clear why I highly dislike this way of manually "respawning" the player?
     
    Comphenix likes this.
  26. Offline

    RingOfStorms

    Manually doing it and calling the event would probably be the easiest way but not very reliable and good.

    I am going to experiment with the KeepAlive packet and see what it does - never tested it before so I won't say it works or doesn't work yet. I'll report back if I find anything useful within the next few days.
     
  27. Offline

    nitrousspark

    would it be new PlayerDeathEvent? or would it be new PlayerRespawnEvent? and when i put in new PlayerRespawnEvent it asked me for a location, why?
     
    GrandmaJam likes this.
  28. Offline

    looparound

    how does this work for 1.6?
     
  29. Offline

    fanaticmw2

    By sending packet 205ClientCommand on the PlayerDeathEvent.
     
    GrandmaJam likes this.
  30. Offline

    kreashenz

    looparound

    Code:java
    1. new BukkitRunnable(){
    2. public void run(){
    3. try {
    4. Object nmsPlayer = p.getClass().getMethod("getHandle").invoke(p);
    5. Object packet = Class.forName("net.minecraft.server." + Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3] + ".Packet205ClientCommand").newInstance();
    6. packet.getClass().getField("a").set(packet, 1);
    7. Object con = nmsPlayer.getClass().getField("playerConnection").get(nmsPlayer);
    8. con.getClass().getMethod("a", packet.getClass()).invoke(con, packet);
    9. } catch (Throwable e) {
    10. e.printStackTrace();
    11. }
    12. }
    13. }.runTaskLater(plugin, 2L);


    The runnable is on it so you don't bug out or anything. This also shouldn't break per update.
     
    BajanAmerican and Kainzo like this.
Thread Status:
Not open for further replies.

Share This Page