Plugin optimisation

Discussion in 'Plugin Development' started by WauloK, Jun 25, 2014.

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

    WauloK

    Hey guys!

    I have a plugin which creates a Temple Run type game.

    To detect players touching blocks I intercept onPlayerMoveEvent(PlayerMoveEvent event).

    Unfortunately, I expect this event gets 1,000s of triggers per second based on the fact that it'd get sent when they turn their head or any tiny movement. If there's 100s of players then this happens exponentially.

    The first thing my code does is to check if the player has joined the game. If a the player object has not been created for that player, then I use 'return' to jump out as quickly as possible.

    However, since this happens so often it creates some lag for the players. Especially since the code has to go through each type of block they are standing on with a switch statement.

    Is there a better method for doing this?

    You can see my code here: https://github.com/WauloK/InsanityR...anloft/insanityrun/events/PlayerListener.java

    It's not pretty, but it works. ;)

    TIA :)
     
  2. Offline

    AoH_Ruthless

    WauloK
    You could make a timer that repeats every 3 ticks which checks the block the player is standing on and run the same code. Maybe even 4 ticks but I don't know if that's pushing it a bit (If a player is sprinting, they can probably run at most 5 blocks in one second excluding jumps, so 20ticks/5blocks = 4 ticks / block roughly, you'd have to do some more testing to find a good amount).
     
    WauloK likes this.
  3. Offline

    fireblast709

    WauloK
    • Use an EnumSet to avoid going to the switch at all with a Material that is not in the switch.
    • Instead of storing last pos, you could use both the from and to Locations, toVector(), toBlockVector(), equals
    • Why are you putting them back in the Map at line 202, you never removed them, did you?
     
    WauloK likes this.
  4. Offline

    WauloK

    AoH_Ruthless I'd be concerned execuring every 3 ticks may miss some movements if there's so many people on the server..

    fireblast709

    That's a good point. I can remove that from 202.

    With this update people are also telling me the player teleports no longer work. I had a ticket raised saying players use /spawn or other commands to teleport out of the game and they wanted this blocked. I only block teleports created with Ender Pearls or Commands but they say a lot of players no longer teleport at all or only sometimes while in the game. Not sure why cancelling Ender Pearl and Command teleports would affect plugin-initiated teleports. Any ideas there ? ie. starting line 209. Thanks :)
     
  5. Offline

    mythbusterma


    Every three ticks may be even too dense, that's approximately 6.5 times a second, which is more than enough to detect every block change (as long as they're not running diagonally, in which case it may miss a couple that they don't run over completely).

    This is because the player's max running speed being 5.612 m/s, and since each block is a meter, and 6.5>5.612, this should run well.

    For the best optimization, you could divide the players into three groups, and each one gets operated on each tick, so a third of the server gets checked this tick, the next the next tick, and the last on the third tick.

    Just my two cents.
     
    WauloK likes this.
  6. Offline

    MCForger

    mythbusterma
    I can not believe you just used a Food Lion quote :p
     
  7. Offline

    unrealdesign

    Oh god that code. So much in one class and method. My eyes hurt :'(
     
  8. MCForger The two cents thing? That's not where that came from.
     
  9. Offline

    WauloK

  10. Offline

    Loogeh

    For my factions style plugin I came across this problem when checking for territory changes. I decided to make a new event, PlayerMoveBlockEvent. It still runs in PlayerMoveEvent but it is only called when a player moves 1 block instead of every slight movement. Since it still runs in PlayerMoveEvent it still checks if the player has moved a block as fast as possible; however, it only checks one thing rather than checking multiple things each time it is called.

    I found it to be significantly more efficient and I have been flying around a map at ~25 m/s with it still alerting me to territory changes almost instantaneously.

    These tests were run on a localhost server with only ~4 people on it, though.

    Code:

    Code:java
    1. import org.bukkit.Location;
    2. import org.bukkit.entity.Player;
    3. import org.bukkit.event.Event;
    4. import org.bukkit.event.HandlerList;
    5.  
    6. public class PlayerMoveBlockEvent extends Event {
    7.  
    8. private static final HandlerList handlers = new HandlerList();
    9.  
    10. private Player player;
    11. private Location from;
    12. private Location to;
    13.  
    14. public PlayerMoveBlockEvent(Player player, Location from, Location to) {
    15. this.player = player;
    16. this.from = from;
    17. this.to = to;
    18. }
    19.  
    20. public Player getPlayer() {
    21. return this.player;
    22. }
    23.  
    24. public Location getFrom() {
    25. return this.from;
    26. }
    27.  
    28. public Location getTo() {
    29. return this.to;
    30. }
    31.  
    32.  
    33. public HandlerList getHandlers() {
    34. return handlers;
    35. }
    36.  
    37. public static HandlerList getHandlerList() {
    38. return handlers;
    39. }
    40.  
    41.  
    42.  
    43. }



    How it is called:

    Code:java
    1. @EventHandler
    2. public void onPlayerMoveEvent(PlayerMoveEvent event) {
    3. Player player = event.getPlayer();
    4. Location from = event.getFrom();
    5. Location to = event.getTo();
    6. int fx = event.getFrom().getBlockX();
    7. int fz = event.getFrom().getBlockZ();
    8. int tx = event.getTo().getBlockX();
    9. int tz = event.getTo().getBlockZ();
    10. if((fx != tx) || (fz != tz)) Main.plugin.getServer().getPluginManager().callEvent(new PlayerMoveBlockEvent(player, from, to));
    11. }


    Hope this helps, not sure if you already solved it before this.
     
    WauloK likes this.
  11. Loogeh No need for that to be an event - doing it in an event would be slightly less efficient than simply checking within the PlayerMoveEvent itself, since that's what you do anyway.
     
  12. Offline

    Gater12

    Loogeh
    Also for OOP,

    You can have your event inherit PlayerEvent since it involves a player. It already provides you with getPlayer and all you need to do is define player to the super class.
     
    WauloK and AdamQpzm like this.
  13. Offline

    Syd

    WauloK
    Running the stuff in an own Runnable should help. Even a run every 2 ticks could reduce the usage of the method by 1/2.

    Also, you should take some measurements what part of your code takes what time to execute on average. There is no point in optimising something, that only takes 1% of the overall time. ;)
     
    WauloK likes this.
  14. Offline

    Loogeh

    AdamQpzm Yeah I realize that it would be slightly less efficient; however, I chose to do it through an event because I used it more than once and I like neat code even if it costs a bit of efficiency.

    Gater12 Did not think of this, good idea.
     
    AdamQpzm likes this.
Thread Status:
Not open for further replies.

Share This Page