[Solved] Using Bukkit's Timers or Java's repeating methods.

Discussion in 'Spigot Plugin Development' started by RandomPanda30, May 3, 2015.

  1. I've been having some big performance troubles with the plugin I am currently working on with tick counts as high as 120%. I was wondering is this because I'm using Bukkit's own schedulers or should I be using Java's repeating tasks instead?

    Thanks for any help.
     
  2. Tux

    Tux

    Bukkit's scheduler shouldn't be causing lag. Can you post your code?
     
  3. Sure thing. These are my last timings and they are just, well, astounding really... http://timings.aikar.co/?url=10980749.

    I'll start with the purge timer class and see where I could be going wrong there. I have a feeling it's due to my coding habits I reckon...

    PHP:
    public class PurgeTimer extends BukkitRunnable {

        public PurgeTimer (Murge plugin) {
            MurgeData.plugin = plugin;
        }

        public PurgeTime handle = new PurgeTime();
        public final InworldHandler general = new InworldHandler();
        public final WorldCollection wc = new WorldCollection();
        public final DayExecutor de = new DayExecutor();

        @Override
        public void run() {
            if (handle.getTickTime() != 0) {
                if (wc.getTime() != 1000) {
                    if (wc.getTime() >= 13000) {
                        wc.setTime(wc.getTime() + (handle.getTimeLeft() * 20));
                    } else {
                        if (wc.getTime() < 1000) {
                            if (wc.getTime() + (handle.getTimeLeft() * 20) > 1000) {
                                wc.setTime(1000);
                            } else {
                                wc.setTime(wc.getTime()
                                        + (handle.getTimeLeft() * 20));
                            }
                        } else {
                            wc.setTime(1000);
                        }
                    }
                }

                handle.decrementTickTime();
                general.sendActionBar(StringMethods
                        .formatMessage(MurgeData.messagesC
                                .get("MURGE.ACTIONBAR.PURGEENDCOUNTDOWN")
                                .toString()
                                .replace(
                                        "%time",
                                        StringMethods
                                                .convertTicksToTimeString(handle
                                                        .getTickTime()))));

                switch (handle.getTickTime()) {
                case 600:
                    general.sendCountdown((String) MurgeData.messagesC
                            .get("MURGE.PURGECOUNTDOWN.TOEND.10MINS"), false);
                    break;
                case 300:
                    general.sendCountdown((String) MurgeData.messagesC
                            .get("MURGE.PURGECOUNTDOWN.TOEND.5MINS"), false);
                    break;
                case 60:
                    general.sendCountdown((String) MurgeData.messagesC
                            .get("MURGE.PURGECOUNTDOWN.TOEND.1MINS"), false);
                    break;
                case 5:
                    general.sendCountdown(
                            (String) MurgeData.messagesC.get("MURGE.ENDSIN.5"),
                            true);
                    break;
                case 4:
                    general.sendCountdown(
                            (String) MurgeData.messagesC.get("MURGE.ENDSIN.4"),
                            true);
                    break;
                case 3:
                    general.sendCountdown(
                            (String) MurgeData.messagesC.get("MURGE.ENDSIN.3"),
                            true);
                    break;
                case 2:
                    general.sendCountdown(
                            (String) MurgeData.messagesC.get("MURGE.ENDSIN.2"),
                            true);
                    break;
                case 1:
                    general.sendCountdown(
                            (String) MurgeData.messagesC.get("MURGE.ENDSIN.1"),
                            true);
                    break;
                case 0:
                    de.execute();
                    this.cancel();
                    break;
                }
            } else {
                handle.resetTime();
            }
        }
    }
     
  4. gigosaurus

    Supporter

    Nothing in that timer seems like it should take a long time executing, from what I can see in a quick glance, except maybe for de.execute();

    Do you have multiple instances of that timer running?
    What is OnPlayerDeaathEvent the SpawnHandler task doing to also be so high?
     
  5. Here is the onPlayerDeathEvent

    Code (Text):
                if (MurgeData.isPurge()) {
                    if (StatsHandler.inCombatLog(uuid)) {
                        StatsHandler.removeCombatLog(uuid);
                    }

                    if (MiscCollection.isStrikeOnDeath()) {
                        MurgeData.getWorld().strikeLightning(player.getLocation());
                    }

                    event.setDeathMessage(StringMethods
                            .formatMessage((String) MurgeData.messagesC
                                    .get("MURGE.PLAYERDIED").toString()
                                    .replace("%player", player.getName())));
                    StringMethods
                            .sendMessageToWorldPlayers((String) MurgeData.messagesC
                                    .get("MURGE.MOVEDTOSPECTATE").toString()
                                    .replace("%player", player.getName()));

                    for (ItemStack i : player.getInventory().getContents()) {
                        if (i != null) {
                            if (i.getType() != Material.AIR) {
                                player.getWorld().dropItemNaturally(
                                        player.getLocation(), i);
                                player.getInventory().remove(i);
                            }
                        }
                    }

                    for (ItemStack i : player.getInventory().getArmorContents()) {
                        if (i != null) {
                            if (i.getType() != Material.AIR) {
                                player.getWorld().dropItemNaturally(
                                        player.getLocation(), i);
                                player.getInventory().remove(i);
                            }
                        }
                    }

                    player.spigot().respawn();

                    SpawnHandler.getHandler().respawnAsSpectator(player);

                    for (Player players : Bukkit.getOnlinePlayers()) {
                        if (players.getWorld().equals(MurgeData.getWorld())) {
                            if (StatsHandler.inSpectators(uuid)) {
                                players.showPlayer(player);
                            } else {
                                players.hidePlayer(player);
                            }
                        }
                    }

                    DeathsCollection.getCollection().addValue(uuid);

                } else {
                    event.setDeathMessage(StringMethods
                            .formatMessage((String) MurgeData.messagesC
                                    .get("MURGE.PLAYERDIED").toString()
                                    .replace("%player", player.getName())));
                    if (MiscCollection.shouldRespawnAsSpectator()) {
                        player.spigot().respawn();
                        SpawnHandler.getHandler().respawnAsSpectator(player);
                        for (Player players : Bukkit.getOnlinePlayers()) {
                            if (players.getWorld().equals(MurgeData.getWorld())) {
                                if (StatsHandler.inSpectators(uuid)) {
                                    players.showPlayer(player);
                                } else {
                                    players.hidePlayer(player);
                                }
                            }
                        }
                    } else {
                        if (LocationCollection.isSpawnSet()) {
                            player.teleport(LocationCollection.getSpawn());
                        } else {
                            player.teleport(MurgeData.getWorld().getSpawnLocation());
                        }
                    }
                }
                ScoreboardHandler.getHandler().doScoreboard(player);
            }
    and the spawn handler class:

    Code (Text):
    public class SpawnHandler {

        private static SpawnHandler rh = new SpawnHandler();

        public static SpawnHandler getHandler() {
            return rh;
        }

        public void spawnAsSpectator(final Player player) {
            MurgeData.getPlugin().getServer().getScheduler()
                    .scheduleSyncDelayedTask(MurgeData.getPlugin(), new Runnable() {
                        @Override
                        public void run() {
                            // Any lists here

                            StatsHandler.addSpectator(player.getUniqueId());
                            StatsHandler.addFlySpeed(player.getUniqueId(), 1);

                            // Dump collection here

                            if (DumpCollection.getCollection().isPunishDump(
                                    player.getUniqueId())) {
                                StringMethods.sendMessage(
                                        (String) MurgeData.messagesC
                                                .get("MURGE.YOUQUITED"), player);
                                player.playSound(player.getLocation(),
                                        Sound.NOTE_BASS, 1, 1);
                                DumpCollection.getCollection().removePunish(
                                        player.getUniqueId());
                            }

                            DumpCollection.getCollection().dump(
                                    player.getInventory().getContents(),
                                    player.getInventory().getArmorContents(),
                                    player.getUniqueId());

                            // Messages here

                            StringMethods
                                    .sendMessageToWorldPlayers((String) MurgeData.messagesC
                                            .get("MURGE.MOVEDTOSPECTATE")
                                            .toString()
                                            .replace("%player", player.getName()));

                            // Inventory manipulation here
                            player.getInventory().clear();
                            player.getInventory().setItem(0,
                                    SpectatorItems.obtainCompass());
                            player.getInventory().setItem(2,
                                    SpectatorItems.obtainAdjustFly());
                            player.getInventory().setItem(8,
                                    SpectatorItems.obtainLeave());

                            // Teleportation here
                            if (LocationCollection.isSpectatorSpawnSet()) {
                                player.teleport(LocationCollection
                                        .getSpectatorSpawn());
                            } else {
                                player.teleport(MurgeData.getWorld()
                                        .getSpawnLocation());
                            }

                            player.setGameMode(GameMode.CREATIVE);
                            ScoreboardHandler.getHandler().doScoreboard(player);
                        }
                    }, 10L);
        }

        public void spawnAsPlayer(final Player player) {
            MurgeData.getPlugin().getServer().getScheduler()
                    .scheduleSyncDelayedTask(MurgeData.getPlugin(), new Runnable() {
                        @Override
                        public void run() {
                            StatsHandler.addPlayer(player.getUniqueId());

                            player.getInventory().clear();
                           
                            if (DumpCollection.getCollection().isPunishDump(
                                    player.getUniqueId())) {
                                StringMethods.sendMessage(
                                        (String) MurgeData.messagesC
                                                .get("MURGE.YOUQUITED"), player);
                                player.playSound(player.getLocation(),
                                        Sound.NOTE_BASS, 1, 1);
                                DumpCollection.getCollection().removePunish(
                                        player.getUniqueId());
                            }

                            if (DumpCollection.getCollection().isDumped(
                                    player.getUniqueId())) {
                                player.getInventory().setContents(
                                        DumpCollection.getCollection()
                                                .getInventoryDump(
                                                        player.getUniqueId()));
                                player.getInventory()
                                        .setArmorContents(
                                                DumpCollection
                                                        .getCollection()
                                                        .getArmourDump(
                                                                player.getUniqueId()));
                            }

                            for (Player players : InworldHandler.getHandler()
                                    .getPlayers()) {
                                players.showPlayer(player);
                            }

                            if (LocationCollection.isSpawnSet()) {
                                player.teleport(LocationCollection.getSpawn());
                            } else {
                                player.teleport(MurgeData.getWorld()
                                        .getSpawnLocation());
                            }

                            player.setGameMode(GameMode.SURVIVAL);
                            ScoreboardHandler.getHandler().doScoreboard(player);
                        }
                    }, 10L);
        }

        public void respawnAsSpectator(final Player player) {
            MurgeData.getPlugin().getServer().getScheduler()
                    .scheduleSyncDelayedTask(MurgeData.getPlugin(), new Runnable() {
                        @Override
                        public void run() {

                            UUID uuid = player.getUniqueId();

                            StatsHandler.removePlayerData(uuid);

                            StatsHandler.addSpectator(uuid);
                            StatsHandler.addFlySpeed(uuid, 1);

                            StatsHandler.removeCombatLog(uuid);

                            player.getInventory().clear();
                            player.setGameMode(GameMode.CREATIVE);
                            player.getInventory().setItem(0,
                                    SpectatorItems.obtainCompass());
                            player.getInventory().setItem(2,
                                    SpectatorItems.obtainAdjustFly());
                            player.getInventory().setItem(8,
                                    SpectatorItems.obtainLeave());

                            if (LocationCollection.isSpectatorSpawnSet()) {
                                player.teleport(LocationCollection
                                        .getSpectatorSpawn());
                            } else {
                                player.teleport(MurgeData.getWorld()
                                        .getSpawnLocation());
                            }
                        }
                    }, 10L);
        }
    }
    I have to use the timers since player.Spigot.respawn is a bit buggy and it just saves the hassle ;P
     
  6. gigosaurus

    Supporter

    Again, nothing seems to be out of the ordinary with a quick glance, but it is very hard to tell when there are so many method calls which could be doing something big. Someone else might notice something I haven't.

    Have you tried timing it yourself? Store a System.currentTimeMillis() at the start of the method, and then compare it to another System.currentTimeMillis() at the end of the method. If the difference is more than a couple of milliseconds then there could be a problem somewhere there. Keep narrowing down the amount of code you are timing like this and you should be able to find out what is causing these high timings.
     
  7. Didn't thin of this. I will try this with the classes now and let you know the results. Just weird really how I've never had performance issues with most plugins and now this occurs. Thanks for the help.
     
  8. Quick thought, could it be this I'm doing (I only did it temporary) buuuut I'm unsure.

    The BukkitTask variable is public and static (For ease of coding at first) And I keep doing this -

    Code (Text):
            Murge.purgeChecker = new PurgeTimer(MurgeData.getPlugin())
                        .runTaskTimer(MurgeData.getPlugin(), 0, 20);
    Could this be doing something bad since it's a static variable? ;-;
     
  9. gigosaurus

    Supporter

    Although static variables like that are normally not recommended, they shouldn't cause a huge drop in performance.
     
  10. Could this just be down to a hardware issue then? I am only letting the server use 512MB of RAM.....Might be the cause?
     
  11. gigosaurus

    Supporter

    Quite possibly. If you can't get any results out of what I suggested earlier, try increasing that.
     
  12. I'll have a crack at that now. It's weird since the timings can increase randomly. Anyway I'll post the result
     
  13. Tux

    Tux

    Can we see your Collection classes?
     
  14. Can you post your code that you are running with this line?
    Code (Text):
    DeathsCollection.getCollection().addValue(uuid);
    And somewhat sniped by @Tux :(
     
  15. PHP:
    public class DeathsCollection implements PlayerBase {

        private static DeathsCollection instance = new DeathsCollection();

        public static DeathsCollection getCollection() {
            return instance;
        }

        @Override
        public int getValue(UUID uuid) {
            return (Integer) MurgeData.dataC.get(uuid.toString() + ".deaths");
        }

        @Override
        public void addValue(UUID uuid) {
            MurgeData.dataC.set(uuid.toString() + ".deaths", getValue(uuid) + 1);
            ConfigMethods.saveData();
        }

        @Override
        public void removeValue(UUID uuid) {
            if (getValue(uuid) != 0) {
                MurgeData.dataC
                        .set(uuid.toString() + ".deaths", getValue(uuid) - 1);
            } else {
                MurgeData.dataC.set(uuid.toString() + ".deaths", 0);
            }
            ConfigMethods.saveData();
        }

        @Override
        public void addValues(UUID uuid, int amount) {
            MurgeData.dataC.set(uuid.toString() + ".deaths", getValue(uuid)
                    + amount);
            ConfigMethods.saveData();
        }

        @Override
        public void setValue(UUID uuid, int amount) {
            MurgeData.dataC.set(uuid.toString() + ".deaths", getValue(uuid));
            ConfigMethods.saveData();
        }

        @Override
        public void removeValues(UUID uuid, int amount) {
            if (getValue(uuid) - amount != 0) {
                MurgeData.dataC.set(uuid.toString() + ".deaths", getValue(uuid)
                        - amount);
            } else {
                MurgeData.dataC.set(uuid.toString() + ".deaths", 0);
            }
            ConfigMethods.saveData();
        }

        @Override
        public void resetValues(UUID uuid) {
            MurgeData.dataC.set(uuid.toString() + ".deaths", 0);
            ConfigMethods.saveData();
        }
    }
     
  16. Erm I think this explains itself - http://timings.aikar.co/?url=10981314
     
  17. gigosaurus

    Supporter

    Is dataC the config file by any chance? If so, the lag is probably caused by writing to that file constantly.
    Only write to it when you really need to, like onDisable or possibly when a player leaves.
     
    #17 gigosaurus, May 3, 2015
    Last edited: May 3, 2015
  18. It's a separate config file. But to be honest I use this all the time and I need it to save the changes immediately so I can get them again and I've never had any noticeable issues. The weird thing is, I'm not really getting any noticeable issues in-game but the tick count suggests otherwise.

    EDIT: Don't think I'm not taking in what you're saying by the way. Just trying to rule out all the causes ;P
     
  19. Yeah most likely it's the config saving. Try taking that out and see if it improves
     
  20. gigosaurus

    Supporter

    The data you are storing in this config file - does it all need to be kept between server restarts?

    Disk writing speeds can be very unpredictable, which would explain the weird timings.