Search code examples
javapluginsminecraftbukkit

Glitchy Scoreboard


I am creating a scoreboard with a timer that updates every second. It works perfectly the problem is about every 2-5 seconds the scoreboard glitches (flashes). Here is my code:

    Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable() { 
        public void run() {
             ScoreboardManager manager = Bukkit.getScoreboardManager();
                final Scoreboard board = manager.getNewScoreboard();
                final Objective o = board.registerNewObjective("Timer", "dummy");

            o.setDisplayName(ChatColor.DARK_GRAY + "" + ChatColor.BOLD + "-- " + ChatColor.DARK_RED + ChatColor.BOLD + "Minecraft" + ChatColor.DARK_GRAY + ChatColor.BOLD + " --");
            o.setDisplaySlot(DisplaySlot.SIDEBAR);  

            Score score = o.getScore(ChatColor.GOLD + "Chest Restock in:");
            score.setScore(10);

            if (seconds < 0 ){
                seconds = 118;
                minutes--;
            }

            long second = seconds/2;
            int s = Math.round(second);

            if (seconds > 18 ){
                Score score1 = o.getScore(minutes+":"+s);
                score1.setScore(9);
            } else {
                Score score1 = o.getScore(minutes+":0"+s);
                score1.setScore(9);
            }

            Score score2 = o.getScore(" ");
            score2.setScore(8);

            Score scoreName = o.getScore(""+ChatColor.GOLD + ChatColor.BOLD + player.getName());
            scoreName.setScore(7);

            Score score3 = o.getScore("  ");
            score3.setScore(6);

            int kills = kdData.getInt(player.getName() + ".Kills");

            Score score4 = o.getScore("Kills: " + ChatColor.DARK_RED + kills);
            score4.setScore(5);

            Score score5 = o.getScore("   ");
            score5.setScore(4);

            int deaths = kdData.getInt(player.getName() + ".Deaths");

            Score score6 = o.getScore("Deaths: " + ChatColor.DARK_RED + deaths);
            score6.setScore(3);

            Score score7 = o.getScore("    ");
            score7.setScore(2);


            double killsD = kdData.getInt(player.getName() + ".Kills");
            double deathsD = kdData.getInt(player.getName() + ".Deaths");

            if( kills >= 0 && deaths == 0){ 
            double kd = killsD/1;
            Score score8 = o.getScore("KD Ratio: " + ChatColor.GOLD + kd);
            score8.setScore(1);
            }
            if( kills >= 0 && deaths > 0){
                double kd = killsD/deathsD;
                double kdRounded = Math.round(kd * 100.0) / 100.0;

                Score score8 = o.getScore("KD Ratio: " + ChatColor.GOLD + String.valueOf(kdRounded));
                score8.setScore(1); 
            }

            Score score9 = o.getScore("     ");
            score9.setScore(0);
            player.setScoreboard(board);

        }

    }, 0, 20L);

}   

Basically I am creating a new scoreboard every second. Is it possible to update only the timer (Chest Restock in:) every second? What can I do to stop this glitching? Thank you! :)


Solution

  • Changing score values in scoreboards without having to create a new board and/or objective is entirely possible and removes the flickering as far as I can tell (I'm assuming creating a lot of new scoreboards is the primary cause of the flickering). You'll need to keep track of the Objective for each Player which you can then use to retrieve and edit the individual Score values. Once you change the values, the display will be automatically updated for the client with no need to re-set the player's scoreboard. Here is an example of a task that can be run at any interval to update a general display (that should not flicker) with multiple scores:

    public class ScoreboardUpdater implements Runnable {
    
        // A map that associates a player's ID to their objective (you can of course use something completely different)
        private static HashMap<UUID, Objective> playerObjectiveMap = new HashMap<UUID, Objective>();
    
        public void run() {
            for (Player player : Bukkit.getOnlinePlayers()) { // Loop through all plauers
                UUID id = player.getUniqueId(); // Get their unique ID
    
                if (!playerObjectiveMap.containsKey(id)) { // If they don't have an objective yet
                    Scoreboard board = Bukkit.getScoreboardManager().getNewScoreboard(); // Get a new scoreboard
                    Objective objective = board.registerNewObjective("test", "dummy"); // Create the objective that will contain the scores
                    objective.setDisplaySlot(DisplaySlot.SIDEBAR); // Move the display to the sidebar
                    objective.setDisplayName("Name of Display"); // Name the display something
                    // Here you can optionally initialize the score values for the player by using the getScore() method like below
                    player.setScoreboard(board); // Display the initial scoreboard to the player
                    playerObjectiveMap.put(id, objective); // Add the objective to the map
                }
    
                Objective objective = playerObjectiveMap.get(id); // Retrieve objective for the player from map
    
                // Now that you have the player's objective, you can change the value of any scores!
                Score score = objective.getScore("Example Score: "); // Create a score
                score.setScore((int) (Math.random() * 10)); // Set a value (automatically updates for the client)
                Score score2 = objective.getScore("Another Score: "); // Create another score
                score2.setScore((int) (Math.random() * 50)); // Update
            }
        }
    }
    

    You would then schedule this task like so:

    Bukkit.getScheduler().scheduleSyncRepeatingTask(this, new ScoreboardUpdater(), 0, 20L);
    

    I used this method for a scoreboard that updated a value every tick (20 times a second) to create an animation and it seemed to work fairly well without any flickering.