Need some help optimizing and improving this code.

Discussion in 'Plugin Development' started by flyingtacoz, Mar 10, 2013.

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

    flyingtacoz

    Hello, I run a skyblock server, and I have to remove inactive worldguard regions/islands from time to time to reduce the amount of lag it causes.
    I was wondering if anyone would be willing to help me optimize or improve this code to make it run smoother and faster, this does work, but the thing is that it completely freezes/times out/locks up (whatever the term is) the server so that no one can login intill the process is done (which can take hours). Along with that, if it runs to long it will slow down and go from deleting an island/region a second to deleting one a minute. Which is horrible as due the fact that the only way to stop it is to force kill java, which will then revert anything it deleted as it had no time to save. I think the cause of this is the poor lookup process of inactive players, rather than the island and region deletion method.
    This is really crappy code I am sure, but I am still trying to learn the ropes.

    This is the command used to start the process of looking up inactive players and then deleting the players skyblock island.
    Code:
    if (split[0].equals("purge") && player.isOp())
        {
            OfflinePlayer[] oplayers;
            long offlineTime;
            oplayers = Bukkit.getServer().getOfflinePlayers();
            for (int i = 0; i < oplayers.length; i++)
            {
                offlineTime = oplayers[i].getLastPlayed();
                offlineTime = (System.currentTimeMillis() - offlineTime)/3600000;
                if (offlineTime > 744) //31days
                {
                    plugin.deleteIsland(oplayers[i].getName(), Bukkit.getWorld("skyblockworld"));
                }
            }
            }
        return true;
    }
    }
    And this is the code in which deletes the players island, along with that it also deletes their worldguard region.
    Code:
      public void deleteIsland(String playerName, World world) {
        if (hasIsland(playerName)) {
        if (getWorldGuard().getRegionManager(getServer().getWorld("skyblockworld")).hasRegion(playerName.toLowerCase() + "island"))
          getWorldGuard().getRegionManager(getServer().getWorld("skyblockworld")).removeRegion(playerName.toLowerCase() + "island");
          Island island = getPlayerIsland(playerName);
          for (int x = island.x - 100; x < island.x + 100; x++) {
            for (int y = ISLANDS_Y - 200; y < world.getMaxHeight(); y++)
              for (int z = island.z - 100; z < island.z + 100; z++) {
                Block block = world.getBlockAt(x, y, z);
                if (block.getTypeId() != 0)
                  block.setTypeId(0);
              }
          }
          this.orphaned.push(island);
          this.playerIslands.remove(playerName);
          System.out.println("Player \"" + playerName + "\" island removed.");
        }
      } 
    I appreciate any help that anyone offers, and sorry if I confused you. Thanks. :)
     
  2. Offline

    stirante

    I think it's caused by changing blocks to AIR, becouse minecraft have to update near blocks. Try editing chunk's bytes. I'll try to write some code for changing massive amount of blocks but i won't promise anything :)

    EDIT:Try changing setBlockTypeId(0) to setBlockTypeId(0, false);
     
  3. Offline

    flyingtacoz

    Ok, i'll test that out later and see if anything improves.
    Thank you. :p

    Does anyone have any other improvements? Would love to see them. :D
     
  4. Perhaps you should only delete one or two regions in each 20 ticks or something like that, to split the time needed over multiple game ticks. This doesn't reduce the time needed in sum, but if deleting one region is fast enough, you will not even recognize it.
     
  5. Offline

    flyingtacoz

    How could I exactly do this? =p
     
  6. Offline

    flyingtacoz

  7. Offline

    SyTeck

    You can do it in a repeating task which runs every 10 second or so.
     
  8. Offline

    flyingtacoz

    Sorry, I'm still a beginner, any idea how I can do something like this?
     
  9. Offline

    ZeusAllMighty11

  10. Offline

    chasechocolate

    An easier way so you don't have to make a class that extends BukkitRunnable:
    Code:java
    1. new BukkitRunnable(){
    2. @Override
    3. public void run(){
    4. //Do code
    5. }
    6. }.runTaskTimer(<plugin instance>, 0L, 200L); //20 ticks * 10 seconds = 200 ticks
     
    flyingtacoz likes this.
  11. Offline

    flyingtacoz

    Also, is there a way I can run this task Asynchronously?
     
  12. Offline

    flyingtacoz

    Please can anyone show me how to run this Asynchronously?
     
  13. Offline

    xmarinusx

    .runTaskTimerAsynchronously?
     
  14. Offline

    flyingtacoz

    Like this?
    Code:
        }else if (split[0].equals("purge") && player.isOp())
        {
            Bukkit.getServer().getScheduler().runTaskAsynchronously((Plugin) this, new Runnable() {
            public void run() {
            OfflinePlayer[] oplayers;
            long offlineTime = 0L;
            oplayers = Bukkit.getServer().getOfflinePlayers();
            for (int i = 0; i < oplayers.length; i++)
            {
                offlineTime = oplayers[i].getLastPlayed();
                offlineTime = (System.currentTimeMillis() - offlineTime) / 3600000L;
                if (offlineTime > 744) //31days
                {
                    plugin.deleteIsland(oplayers[i].getName(), Bukkit.getWorld("world"));
                   
                }
            }
            }
        return true;
    }
    }
     
  15. Offline

    dillyg10

    DO NOT EVER edit bukkit worlds Async, EVER. Run it synch, this will cause lag becuase your editing large portions of the world, i would reccomend having this done periodically, and jus warning the players when the world is about to be purged.
     
    ferrybig likes this.
  16. Offline

    flyingtacoz

    I can't get it working right, willing to pay someone for them to make this code run Async and not freeze up the server when running. PM me if interested.
     
  17. Offline

    flyingtacoz

    Willing to pay $25.
     
  18. Offline

    Codisimus

    flyingtacoz Did you even read this post?
     
  19. Offline

    flyingtacoz

    I don't want the island deletion done Async, just the process of finding offline players and if their offline time exceeds the set number. (It's the first bit of code I posted) Also I can't warn the players when it is being purged, because this current methord completely freezes the server for hours.
     
  20. Offline

    Codisimus

    Finding which players are inactive does not need to be async, it shouldn't take much time at all to complete.
     
  21. Offline

    flyingtacoz

    It does though. D:
    It takes hours just to go through a couple thousand.
     
  22. Offline

    Codisimus

    Use the code below and you will see that finding the players does not take long. It is actually deleting the islands that is the long part.
    Code:
    if (split[0].equals("purge") && player.isOp()) {
        sender.sendMessage("Finding Inactive Players...");
        ArrayList<OfflinePlayer> inactive = new ArrayList<OfflinePlayer>();
        long cutoff = System.currentTimeMillis() - MILLIS_PER_MONTH;
        for (OfflinePlayer oplayer : Bukkit.getServer().getOfflinePlayers()) {
            if (oplayer.getLastPlayed() < cutoff) {
                inactive.add(oplayer);
            }
        }
        int size = inactive.size;
        sender.sendMessage(size + " Inactive Players found!");
        sender.sendMessage("Deleting Islands, expect lag!");
        int completed = 0;
        for (OfflinePlayer oplayer : inactive) {
            plugin.deleteIsland(oplayer.getName(), Bukkit.getWorld("skyblockworld"));
            completed++;
            sender.sendMessage(completed / size * 100 + "%");
        }
        sender.sendMessage("Purge Completed Succesfully!!");
        return true;
    }
    You also need to add the following final variable to your class:
    Code:
    public static final MILLIS_PER_MONTH = 1000 * 60 * 60 * 24 * 31;
     
    flyingtacoz likes this.
  23. if the users online get at least 1 message each 30 sec, then they wont get kicked by the lagg of your task, but new users cant join
     
  24. Offline

    flyingtacoz

    Ok, thanks. =-p
    Any idea on how I can improve this code to make it run better?
    Code:
    public void deleteIsland(String playerName, World world) {
        if (hasIsland(playerName)) {
        if (getWorldGuard().getRegionManager(getServer().getWorld("skyblockworld")).hasRegion(playerName.toLowerCase() + "island"))
          getWorldGuard().getRegionManager(getServer().getWorld("skyblockworld")).removeRegion(playerName.toLowerCase() + "island");
          Island island = getPlayerIsland(playerName);
          for (int x = island.x - 100; x < island.x + 100; x++) {
            for (int y = ISLANDS_Y - 200; y < world.getMaxHeight(); y++)
              for (int z = island.z - 100; z < island.z + 100; z++) {
                Block block = world.getBlockAt(x, y, z);
                if (block.getTypeId() != 0)
                  block.setTypeId(0);
              }
          }
          this.orphaned.push(island);
          this.playerIslands.remove(playerName);
          System.out.println("Player \"" + playerName + "\" island removed.");
        }
      } 
     
  25. Offline

    flyingtacoz

Thread Status:
Not open for further replies.

Share This Page