Player Join Packet (serverside)

Discussion in 'Spigot Plugin Development' started by Litona, May 16, 2016.

  1. Hii devs!
    I want to reset a player. Not like just teleport them back to the worldspawn and clear their inventory, I want to pretend they join again!
    Have you got any idea of a packet which handles this serverside?


    Alternative way:
    As I think it's pretty unlikely that there's a perfect packet for my need, I want to ask you about an alternative way. Could I maybe despawn all players and spawn them again at the worldspawn(packets!!!!)


    The general problem is that I've got the player stuck in a way, that only a rejoin can fix it. So I want to pretend a rejoin via packets!
     
    #1 Litona, May 16, 2016
    Last edited: May 16, 2016
  2. What do you want? Is this a plugin request if it is it's in the wrong section, but I can probably code it for you
     
  3. No, this isn't a plugin request. I just want to know a packet!
    Anyways, if you know about a packet that I could use to pretend a rejoin for a player or a packet to respawn a player at the worldspawn, please tell me :)
     
  4. What would packets have anything to do with this? If you want to reset a player delete their inventory, delete their player.dat file, teleport them to the spawn, and basically get rid of any connection to the server? I am failing to see the need of packets and what you are exactly trying to accomplish?
     
    • Like Like x 1
  5. The problem is that I've got the player stuck in a way, that only a rejoin can fix it. So I want to pretend a rejoin via packets!
    I hope it's clear what I mean, else just ask again, please.
     
  6. Sounds like an XYProblem... What is it you are trying to do?
     
    • Like Like x 2
  7. xD wow, this is the first time I hear about this.
    But yeah If you search the internet for an effective way to freeze a player, you'll find nothing. Aaaand I got an effective way to freeze a player, but sadly no way to unfreeze him, only let them reconnect.
    I freeze the player by playing the PacketPlayOutEntityDestroy packet for themself to them. But if I now want to respawn the player with their information, I get an uncontrollable Player Entity. There's a player entity, but the player can't move this entity and can't move at all.
    Sooo I'm looking to pretend a rejoin for the player.
     
  8. Instead of destroying their player object, simply restrict their movement in PlayerMoveEvent and apply a slowness potion to them to minimize jitter
     
  9. Yeah, but using the PlayerMoveEvent makes laag and the player isn't 1000% frozen :(
    But by destroying the player they can't move at all, so I'd like to go that way ..
     
  10. What you have described is the XY problem.

    XY Problem:

    Please provide details about the problem and not about your attempted solution.
     
  11. Well, once you've destroyed the player's game object there is no way to get it back. The thing was authenticated through Mojang's API and everything. You are causing a lot of harm doing it that way.

    And with PlayerMoveEvent + Slowness Potion there wont be lag and they will be frozen...
     
  12. Hmm.. Is there maybe a way to store the Game Object and later get it back into the player?
     
  13. It's a shot in the dark, but I've had luck tricking the server into thinking an EntityPlayer object has joined the server, using
    Code (Text):
    <CraftServer>.getHandle().a(<NetworkManager>, <EntityPlayer>);
    I don't know how it would react to a player that's already online, but to me, it would be worth it to get their EntityPlayer object and its network manager and trying it.
     
    • Like Like x 2
  14. Phew... The idea is great(!!!), but how do I get the NetworkManager, the WorldServer and the PlayerInteractManager?? Aswell MinecraftServer=CraftServer?
     
  15. NetworkManager and PlayerInteractManager should already be instantiated by the server when you get the EntityPlayer object.

    WorldServer either means getting your spawn's world, which I don't know how to do by name, but you can use <MinecraftServer>.getWorldServer(number)where number is the world number (default world is 0, nether is 1, end is 2). Or alternatively you can use <EntityPlayer>.getWorld().

    Getting the EntityPlayer object should be casting Player to CraftPlayer and calling getHandle().
    CraftServer you have to cast from Bukkit.getServer().

    MinecraftServer there is probably a better non-static and non-deprecated method for, but I think I just used MinecraftServer.getServer().

    keep in mind they're all unsupported by spigot and will break every update, but I figure you're already into that since you're using packets.
     
    • Agree Agree x 1
    • Optimistic Optimistic x 1
  16. D: It doesn't work :'( :'(
    I really liked that idea, but when I run this method on a frozen player, nothing changes. Aswell I don't get any errors.
    I'm pretty tired now, I'll have a second look on all that tomorrow.
    Anyways, many many thanks to all of you. Maybe we'll find a solution(at least I still hope so :D)
     
  17. You might be able to take it one step farther and manipulate the Player List more by making the server think that the player quit, but keeping alive their connection and reconstructing a new EntityPlayer before you add it?..it seems like a stretch (maybe you can make a wrapper for EntityPlayer to keep alive their connection). I don't think I will be able to help much more than offer up that one method name above, so good luck :)
     
  18. Sooo.. I've been on a short vacation, but I tried your idea again. I've also experimented with some other random methods I found, but your idea is really good. Sadly I don't know how to finish it. Here's the progress I made:
    These are the only lines of code I added:
    Code (Text):
    EntityPlayer ep = ((CraftPlayer) player).getHandle();
    ((CraftServer) Bukkit.getServer()).getHandle().a(ep.playerConnection.networkManager, ep);
    However, they do very much. The frozen player is sent to the 'downloading terrain' screen. To me it looks like this: They are sent back to the worldspawn, but still hovering in the air(as the terrain is still downloaded I guess). Sadly the (once) frozen player never gets to download all the terrain because their connection seems to be broken. On TAB their connection is red and after some time the (once) frozen player gets timed out.
    Last but not least the console displays an error:
    org.bukkit.event.EventException
    at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:310) ~[spigot.jar:git-Spigot-8a048fe-3c19fef]
    at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:62) ~[spigot.jar:git-Spigot-8a048fe-3c19fef]
    at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:502) [spigot.jar:git-Spigot-8a048fe-3c19fef]
    at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:487) [spigot.jar:git-Spigot-8a048fe-3c19fef]
    at net.minecraft.server.v1_9_R2.PlayerConnection.a(PlayerConnection.java:1851) [spigot.jar:git-Spigot-8a048fe-3c19fef]
    at net.minecraft.server.v1_9_R2.PacketPlayInWindowClick.a(SourceFile:33) [spigot.jar:git-Spigot-8a048fe-3c19fef]
    at net.minecraft.server.v1_9_R2.PacketPlayInWindowClick.a(SourceFile:10) [spigot.jar:git-Spigot-8a048fe-3c19fef]
    at net.minecraft.server.v1_9_R2.PlayerConnectionUtils$1.run(SourceFile:13) [spigot.jar:git-Spigot-8a048fe-3c19fef]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) [?:1.7.0_101]
    at java.util.concurrent.FutureTask.run(FutureTask.java:262) [?:1.7.0_101]
    at net.minecraft.server.v1_9_R2.SystemUtils.a(SourceFile:45) [spigot.jar:git-Spigot-8a048fe-3c19fef]
    at net.minecraft.server.v1_9_R2.MinecraftServer.D(MinecraftServer.java:726) [spigot.jar:git-Spigot-8a048fe-3c19fef]
    at net.minecraft.server.v1_9_R2.DedicatedServer.D(DedicatedServer.java:399) [spigot.jar:git-Spigot-8a048fe-3c19fef]
    at net.minecraft.server.v1_9_R2.MinecraftServer.C(MinecraftServer.java:665) [spigot.jar:git-Spigot-8a048fe-3c19fef]
    at net.minecraft.server.v1_9_R2.MinecraftServer.run(MinecraftServer.java:564) [spigot.jar:git-Spigot-8a048fe-3c19fef]
    at java.lang.Thread.run(Thread.java:745) [?:1.7.0_101]
    Caused by: java.lang.IllegalArgumentException: Listener already listening
    at net.minecraft.server.v1_9_R2.Container.addSlotListener(Container.java:57) ~[spigot.jar:git-Spigot-8a048fe-3c19fef]
    at net.minecraft.server.v1_9_R2.EntityPlayer.syncInventory(EntityPlayer.java:173) ~[spigot.jar:git-Spigot-8a048fe-3c19fef]
    at net.minecraft.server.v1_9_R2.PlayerList.a(PlayerList.java:220) ~[spigot.jar:git-Spigot-8a048fe-3c19fef]
    at litona.freeze.onItemClick(freeze.java:41) ~[?:?]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.7.0_101]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[?:1.7.0_101]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.7.0_101]
    at java.lang.reflect.Method.invoke(Method.java:606) ~[?:1.7.0_101]
    at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:306) ~[spigot.jar:git-Spigot-8a048fe-3c19fef]
    ... 15 more
    It seems like there's a listener for the player, but it can't be re-set for the 'pretended new spawned' player.
    I guess, if we keep the players connection and set this listener for the 'pretended new spawned' player, we'll be able to unfreeze the player.
    Maybe it might be already enough to keep the player connection alive, but sadly I don't know how to do this and neither I know anything about the listener..
    @akselm , you've already helped me so much, I hope you've got a solution for this (maybe last) task too ... :)
     
  19. Sorry I haven't been on the forums lately otherwise I would have replied sooner, my best guess is you should find a way to trick the server into thinking that the player disconnected without actually destroying the connection before you call the re-join method. If there isn't a method in MinecraftServer or DedicatedPlayerList you can call that works, you can try making an EntityPlayer wrapper class that overrides disconnect() with all the same code except for the lines that kill their connection, and call that. To instantiate the wrapper class you would probably have to set all the variables yourself taking the old entityplayer in the constructor (using reflection for private fields), but I would bet that most of the fields are negligible.
     
  20. PlayerInteractManager