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! :)
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.