Effective way to "Freeze" a player? (no movement)

Discussion in 'Plugin Development' started by Fishrock123, Dec 15, 2011.

Thread Status:
Not open for further replies.
  1. Yes, exactly. Those blocks will be client-side. The server just tells the one client "block at x,y,z changed to id abc", without actually setting the block. One problem is that when the client right-clicks on one of those fake blocks, they vanish (or go back to the real block, to be precise).
    I don't know if a PlayerInteractEvent is thrown for that when there is actually an air block. If not, you'd probably need to resend the fake blocks every couple of seconds or so (if the player manages to "click-break" those blocks fast enough, it's the job of the PlayerMoveEvent listener to keep him inside).
    Otherwise, resend the specific block on interact.
  2. Offline


    There is a PlayerInteractEvent, but it's of type RIGHT_CLICK_AIR I believe
  3. Offline


    I like the idea of surrounding them with glass blocks and then canceling the break event as well as sending them a message :)
  4. Offline


    Yes of course there is no way to actually constantly hold them perfectly in position, as Fishrock123 said. I thought you wanted the API to do what a plugin can do but do it for you. I didn't realize you were asking for something that is actually completely impossible. :)
  5. Offline


    Oh... I think we don't require API, we need a solution.
    I did not test a every-tick-teleporting yet, but I'll do it to day and will write here after tests.
  6. Offline


    Honestly. I'm think that freezing a player completely is not possible without a client side modification. The packet for movement will still be sent whether the server responds with a position or not.

    event.setCancelled(true); is about the best you get. Time to get your glitch on.
  7. Offline


    Talking from a specific stand point, I put my opinion on the previous mentioned methods and how it would effect their server. Read before you make accusations like, "You don't know what you're talking about at all" and making this into a flame thread. As with a hashmap, I still believe my method brings more of a less "lag" enducing method than an PlayerMoveEvent. By your arguments you have disagreed that basically PlayerMoveEvents do not have an impact on the server whatsoever. When you call from the hashmap what does it do? It reads PlayerMoveEvents of said person. How many times? 10 times per second. 600 calls of 1 player every minute. And that only applies to that one person. Reading from the hashmap is easy, calling back events is potentially harmful if they're not handled right. I am blatantly saying that PlayerMoveEvents aren't the best way of doing a "freeze" method and you insult me with your ignorance. And you just contradicted yourself:
    By this knowledge, the event is still being called but is being cancelled. Which is what I said. You can't read an event if there isn't an event handler. Therefore:
    No EventHandler = No checking

    As you, yourself noted, I made a method, you agreed with it, yet you are saying that PlayerMoveEvents are the best method? If you are, you should uninstall Eclipse and find a job at McDonalds.
    @Op : Make it so that it creates the blocks and the player receives said block data as Air entities.
  8. I didn't say anything against your suggested methods. You claimed that using PlayerMoveEvent would bring your server from 20 TPS to 5 TPS, with the argument of how often it is called.
    That's the point where I was contradicting, saying that unless the operations that you do in PlayerMoveEvent are extremely extensive or not filtered out properly it wouldn't cause any noticable difference. And that's regardless of how many players, thus how many events there are.
    The average footprint of a filtered onPlayerMove(...) method call stays very small compared to the footprint of the rest of the server's actions to handle the movement.
    My post was saying that, I tried to explain it as detailed as possible.

    I did say nothing against that (I don't know where the HashMap is coming from, though).

    (I'll assume you meant that I stated that they don't have an impact, the sentence is kind of ambiguous)
    Yes, I more or less said that. As long as it is implemented efficiently, I hope I made that clear.
    Of course, we can't generalize too much here. When one has to do slow iterations in that event - for example checking when any Player enters a region - it can quickly become an issue because it then takes up too much time for however often it is called.
    What I am trying to bring across is that you should not refrain from using it just for the sake of not using it.

    Okay, sorry, I couldn't follow you at this part. First off, I was talking about a HashSet, containing the player's that currently have to be checked. Where does it "read PlayerMoveEvents of said person"? The contains-check of the Set (if that's really what you are referring to, it's kind of hard to tell) is fast and has almost no impact - especially when considering that there are most likely just a couple of player names in there.
    And I don't care if that happens once a day or every nanosecond. It needs almost no time compared to what the server has to do at the very same rate at which the event is called.

    And I said that as well (in another post). But you were saying more than that (that using it would cause terrible lag on a big server).

    How did I contradict myself? You said "even if the event is cancelled on checking something, it is recorded and there is no way to make it not do that with an EventHandler".
    First of all, I'd like you to make a difference between cancelling the event, and returning from the event handler method. Next, I really don't know what exactly you want to express with "it is recorded", but I just assumed it means something like "the handler processes the event" in this context. If you now read my lines again, you'll (hopefully) notice that I did not contradict myself.

    Yes, of course the event is still being called, guess what, it is even called when you don't even have an EventHandler. That's what bukkit does, calling events. If you mean "the event handler ist still being called but is being [returned from]", that is also true, but I don't consider that "recording the event", because that's the part of the handler that takes up virtually no time when you have to do something extensive in the rest of it.

    So who's the one flaming now? ;) Once again: I did never say using PlayerMoveEvent is the best method, the whole post wasn't even directly aimed at the whole "freeze player" problem. Just at the fact that using it for something simple isn't going to cause the lag you claimed it to cause.

    And please, don't reply before you've read this post carefully. Thanks.
  9. Bone008 is the only one contributing usefull information in here, it seems.
    Let me add something to that, then enough should be sayd to let this thread die.
    What happens if a player presses the W key? The client renders the movement and sends a packet that the plaer moved. At the time the server is notified about the movement the client may have renderet the animation if there's network lag! There's no way to stop this except for minimizing network lag.
    What the server does with the received packet and how bukkit handles it was described by Bone008 - Did anyone look at the codes he linked? <.<
    here's the important part:
    1. // Skip the first time we do this
    2. if (from.getX() != Double.MAX_VALUE) {
    3. PlayerMoveEvent event = new PlayerMoveEvent(player, from, to);
    4. this.server.getPluginManager().callEvent(event);
    6. // If the event is cancelled we move the player back to their old location.
    7. if (event.isCancelled()) {
    8. this.player.netServerHandler.sendPacket(new Packet13PlayerLookMove(from.getX(), from.getY() + 1.6200000047683716D, from.getY(), from.getZ(), from.getYaw(), from.getPitch(), false));
    9. return;
    10. }
    12. /* If a Plugin has changed the To destination then we teleport the Player
    13. there to avoid any 'Moved wrongly' or 'Moved too quickly' errors.
    14. We only do this if the Event was not cancelled. */
    15. if (!to.equals(event.getTo()) && !event.isCancelled()) {
    16. this.player.getBukkitEntity().teleport(event.getTo(), PlayerTeleportEvent.TeleportCause.UNKNOWN);
    17. return;
    18. }
    20. /* Check to see if the Players Location has some how changed during the call of the event.
    21. This can happen due to a plugin teleporting the player instead of using .setTo() */
    22. if (!from.equals(this.getPlayer().getLocation()) && this.justTeleported) {
    23. this.justTeleported = false;
    24. return;
    25. }
    26. }

    Here a summary:
    Canceling the event imidiately sends a packet to the client, informing it that the movement was illegal. That's the best way to freeze a player cause all depends on code efficiency of your plugins code and network lag now.
    Using event.setTo(event.getFrom()); does the same as teleporting the player inside of the event: It calls a lot of bukkit code and as such is the worst solution.
    Cirno, desht, imjake9 and 1 other person like this.
  10. Offline


    This is how i did mine:
     @EventHandler(priority = EventPriority.HIGHEST)
        public void onPlayerMove(PlayerMoveEvent e) {
                e.getPlayer().sendMessage(ChatColor.YELLOW+"You have been frozen");

    And in the main class i have a Arraylist, and a cmd that adds ppl to the list. I will be posting a tut on how to use lists, and using freezing ppl as an example when i actually get chance to record it

    NEVER use event.setCanceled(true); for player movement, it'll lag like hell, just tp the player to the player(as i showed above this)

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
    Last edited by a moderator: May 22, 2016
  11. As V10lator stated above, it's better than teleporting:
    Have fun waiting 6 seconds to do a contains check on a list with 1.000.000 entries. Sure, this is a number you won't get when using the list for players but please use a Set.
  12. Offline


    Nope, i tired using that in my plugin where u have to login with a password b4 u move(like authme but only for perm nodes) and i have it so it'll send u a msg saying log in first. and once u move or do one thing, it'll spam u, lags u, server, and other ppl
  13. xXSniperzzXx_SD This is cause of the message spam and has nothing to do with the way you freeze the player! Reduce the message to be send only once every 5 seconds, like this:
    1. @EventHandler
    2. public void freezePlayer(PlayerMoveEvent event)
    3. {
    4. if(set.contains(player.getName())
    5. {
    6. event.setCancelled(true);
    7. if(!set2.contains(player.getName())
    8. {
    9. player.sendMessage("You're frozen!");
    10. final String name = player.getName();
    11. set2.add(name);
    12. Bukkit.getScheduler().scheduleSyncDelayedTask(new Runnable() { public void run() { set2.remove(name); } }, 100L);
    13. }
    14. }
    15. }
  14. Offline


    But for the people who want just a simple freeze without the timer, teleporting is the best, Although i never thought of a timer, which would make it ALOT better then teleporting.
  15. xXSniperzzXx_SD You don't understand. Your problem was that you were spamming that messages, that caused lag to the server (all the chat packages to be send), the client (all the chat packages to be received) and other clients (affected by server lag) but this has nothing to do with the topic we're talking about here, that counts to
    Teleporting the player instead of cancelling the event is not the solution here, in fact that would even make the lag more worse.
  16. Offline


    Effective-non-lag-way is to place blocks around the player. Teleporting the player, as V10 said, would cause lag. Cancelling movement would do the same, and also have the player screaming "LAG!1!!" If you really want to freeze a player, place bedrock around them and place the portal block (ID:90) inside the bedrock. Then, when the player is attempting to enter the nether, cancel it if the player's name that is entering is the one that is frozen. Or at least, that's how I would do it. Being stuck inside of a portal restricts the player in chatting (effect for spambots), however.
  17. Offline


    What if you just applied a potion effect of slowness for the duration with a really high amplifier?
    V10lator likes this.
  18. Offline


    @Bone008 You just agreed to everything I just said. Where does the fact that I don't know what I'm talking about come in. So you agree to disagree with yourself which inturn, I'm right.
    @op There are plugins that do the kind of thing I'm talking about in similarity but, as I said, it requires a alot of coding. Anti-Xray is one of those plugins. Perhaps, you should look at the source and see what they did and relate it to your own code. This function of changing the way players look at blocks, is not client-side. Granted, it would be a hell of alot easier to make it client-side, plugins like Anti-Xray provide a non-arguable fact that these functions do exist.
  19. I really hope you are trolling right now. If you don't even bother reading my posts, I don't need to bother writing them.
    That was my only point. Seriously, explain how I ever disagreed with myself.

    Regarding the rest of your post: It appears to me that you don't know what "client-side block changes" mean. Because that's all that happens in Anti-Xray plugins that don't directly modify the real world data, and that's what was suggested here as well.
  20. Offline


    Simplest solution would be to modify the handling of the entity movement packet so that on receiving the packet (and ensuring the players position has changed, not the direction its facing, nor the direction its looking) it checks to see if a bool in the Player entity, named frozen is set, if so send a entity movement packet back to reset its position and (most crucially) doesnt send the entity movement packet to the rest of the players on the server.

    Obviously the problem with this is that you need to modify core systems which are not easily editable through plugins, it does however fix all the issues with the events re-firing over and over.

    Personally i would like to see bukkit add event handling for packet receiving so that things like this could actually be done with ease by people with the ability, allows for much greater flexibility with plugins.
  21. Which is exactly what bukkit does if you call event.setCancelled(true); except that it handles position and facing. A boolen isn't needed, just a simple HashSet<String> containing the names of frozen players.
  22. Offline


    Can you link the bukkit handling of the entity movement packet for me?

    And while yes a collection might be simpler, its way over the top for something like this, it simply isnt required.
  23. It is exactly what's required:
    1. @EventHandler
    2. public void freeze(PlayerMoveEvent event)
    3. {
    4. if(freezedSet.contains(event.getPlayer().getName())
    5. event.setCancelled(true);
    6. }

    Extending the Player object would be way over the top for something like this. ;)
    Fishrock123 and desht like this.
  24. Offline


    https://github.com/Bukkit/CraftBukk...va/net/minecraft/server/NetServerHandler.java, look at line 212.

    If you want to freeze certain players, then a collection (Set, in this case) is not over the top, and is exactly the right way to do it.

    Anyway, the fundamental problem here is that no matter how clever you get on the server side, without a client mod, there is no perfect way of freezing a player without some glitching. If you press a movement key the client will move you and then tell the server. The server can respond and reposition the client, but there's every chance that the player will see a rubber-banding effect, depending on network latency. This has been stated already on this thread, but it obviously needs repeating.

    The two best methods are (as many people have said already) are 1) cancelling the PlayerMoveEvent for frozen players, and 2) surrounding the player in some kind of unbreakable prison (or a "fake" prison with a combination of player.sendBlockChange() and cancelling the PlayerMoveEvent).

    Don't use event.setTo() inside a PlayerMoveEvent handler, and definitely don't use player.teleport() inside a PlayerMoveEvent handler. The first is a waste of CPU cycles, and the second will get players kicked.
    hawkfalcon and Bone008 like this.
  25. Offline


    Well you say "that's exactly what it does" but actually there's alot of handling that occurs before that line that could all be skipped if the player is frozen, so no thats not exactly what it does, and from an efficiency and purely programming point of view using a collection just to see if a player is or isnt frozen is completely over the top.

    But like i said its impractical, but it is the simplest solution in an ideal world.

    If you want the most elegant solution then you need a client mod obviously so that once the client is told its frozen it disables user movement input.
  26. Offline


    Having a look through this thread it does not look like it is worth using cancel event or teleporting and the like.

    I am opting to just simply teleport them on join to a jail cell or some holding location until they enter a valid password for the name they are using and then teleport them back to where they were supposed to be.
    Fishrock123 likes this.
  27. Offline


    How about an ArrayList ? In the onPlayerMove Event you check whether list.contains(player) and then event.setCanceled(true);
  28. that has already been mentioned:
    + ->
  29. Offline


    Your sig pisses me off.
  30. Offline


Thread Status:
Not open for further replies.

Share This Page