Solved [1.9.2] Scoreboard issue

Discussion in 'Spigot Plugin Development' started by NicoTehUnicorn, May 29, 2016.

  1. Hey There!
    I need help. Scoreboards are very confusing. (To me at least). I am trying to give every player on my server individual scoreboards that update every second. I've kind of done that. Expect, there is this issue that when player1 joins, the scoreboard updates! But, if player2 joins, player1's scoreboard will stop updating and player2's scoreboard will start updating. I hope you can understand what I'm trying to say, Its late at night and I'm tired. Keep in mind, I am still learning Java, so tell me if I am not following a Java convention or if my code isn't very efficient. Here is my code:

    Scoreboard class:

    If you need any other information, please tell me.
    - Nico
     
  2. Update your scoreboard in a for loop that will work
    Code (Text):
    for (Player players : Bukkit.getOnlinePlayers()) {
    UPDATE HERE
    }
     
    • Agree Agree x 1
  3. But won't that send the same scoreboard for ever player?
     
  4. Thanks for your response mist69! I have done this to my code.
    Code (Text):
    Bukkit.getScheduler().scheduleSyncRepeatingTask(pl, new Runnable() {
                @Override
                public void run() {
                    for(Player players : Bukkit.getOnlinePlayers()) {
                        players.getScoreboard().getObjective(DisplaySlot.SIDEBAR).unregister();
                     
                        objective = board.registerNewObjective("test", "dummy");
                     
                        objective.setDisplaySlot(DisplaySlot.SIDEBAR);
                        objective.setDisplayName("§cU§6n§ei§ap§bl§dex");
                     
                        objective.getScore("§b§lPlayers Online:").setScore(9);
                        objective.getScore("§d§l" + Bukkit.getServer().getOnlinePlayers().size()).setScore(8);
                        objective.getScore("§f").setScore(7);
                        objective.getScore("§b§lBalance:").setScore(6);
                        objective.getScore("§d§l" + UniCore.economy.getBalance(players)).setScore(5);
                        objective.getScore("").setScore(4);
                        objective.getScore("§b§lWebsite:").setScore(3);
                        objective.getScore("§d§luniplexmc.enjin.com").setScore(2);
                        objective.getScore("§a===================").setScore(1);
                     
                        players.setScoreboard(board);
                    }
                }
            }, 0, 20);
    But now, when 2 players are online. It removes the scoreboard of player1 and it spams the console with
    Task #553 / #557 for Uniplex v1.9 generated an exception.
    java.lang.NullPointerException.

    That's what I was thinking. I tried anyways.
     
  5. Remove that line
     
  6. Serializator

    Supporter

    This issue is probably caused by the fact that you assign a value to the `board` and `objective` variables each time a player joins and you expect it to know that it needs to use the previous assigned value to those variables as the scoreboard for the previously joined player, but that's not how it works.

    Their are three things you could do to fix it:
    • Use a method level variable instead of a class level variable, that should fix your problem.
    • Have a single repeating task with a for-loop, create a new instance of Scoreboard and Objective for each player.
    • Only update the scoreboard of a player when something changes that's displayed as a score.
     
    • Agree Agree x 1
  7. When I remove that line, It generates a IllegalArgumentException that "An objective of name 'test' already exists. That's why I added that line.
     
  8. Serializator

    Supporter

    I almost forgot, initializing the scoreboard before the repeating task and in the repeating task is unnecessary.
    You've set the delay of the repeating task to 0 ticks and the interval 20 ticks, which means that the repeating task will start in 0 ticks (directly) and repeats itself every 20 ticks, when the repeating task starts itself it actually executes the code it also executes every 20 ticks.
     
  9. Thanks for the help! I've tried your first solution, making the variables method level. But, when I make objective a method level variable, in the repeating task, when I set the scores, it says "Local variable objective defined in an enclosing scope must be final or effectively final". Sorry for the inconvenience :p
    Here is the Scoreboard class code.
    Code (Text):
    package com.Uniplex.Hub.Scoreboards;

    import java.util.HashMap;
    import java.util.UUID;

    import org.bukkit.Bukkit;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.player.PlayerJoinEvent;
    import org.bukkit.event.player.PlayerQuitEvent;
    import org.bukkit.plugin.Plugin;
    import org.bukkit.scoreboard.DisplaySlot;
    import org.bukkit.scoreboard.Objective;
    import org.bukkit.scoreboard.Score;
    import org.bukkit.scoreboard.Scoreboard;
    import org.bukkit.scoreboard.ScoreboardManager;

    import com.Uniplex.Core.UniCore;

    public class HubScoreboard implements Listener {
       
        public static Plugin pl;
        UniCore c;
       
        @EventHandler
        public void onPlayerJoin(PlayerJoinEvent event) {
            Player p = event.getPlayer();
            ScoreboardManager manager = Bukkit.getScoreboardManager();
            Scoreboard board = manager.getNewScoreboard();
            Objective objective = board.registerNewObjective("test", "dummy");
            objective.setDisplaySlot(DisplaySlot.SIDEBAR);
            objective.setDisplayName("§cU§6n§ei§ap§bl§dex");
           
            objective.getScore("§b§lPlayers Online:").setScore(9);
            objective.getScore("§d§l" + Bukkit.getServer().getOnlinePlayers().size()).setScore(8);
            objective.getScore("§f").setScore(7);
            objective.getScore("§b§lBalance:").setScore(6);
            objective.getScore("§d§l" + UniCore.economy.getBalance(p)).setScore(5);
            objective.getScore("").setScore(4);
            objective.getScore("§b§lWebsite:").setScore(3);
            objective.getScore("§d§luniplexmc.enjin.com").setScore(2);
            objective.getScore("§a===================").setScore(1);
           
            p.setScoreboard(board);
           
            Bukkit.getScheduler().scheduleSyncRepeatingTask(pl, new Runnable() {
                @Override
                public void run() {
                    p.getScoreboard().getObjective(DisplaySlot.SIDEBAR).unregister();
                   
                    objective = board.registerNewObjective("test", "dummy");
                       
                    objective.setDisplaySlot(DisplaySlot.SIDEBAR);
                    objective.setDisplayName("§cU§6n§ei§ap§bl§dex");
                       
                    objective.getScore("§b§lPlayers Online:").setScore(9);
                    objective.getScore("§d§l" + Bukkit.getServer().getOnlinePlayers().size()).setScore(8);
                    objective.getScore("§f").setScore(7);
                    objective.getScore("§b§lBalance:").setScore(6);
                    objective.getScore("§d§l" + UniCore.economy.getBalance(p)).setScore(5);
                    objective.getScore("").setScore(4);
                    objective.getScore("§b§lWebsite:").setScore(3);
                    objective.getScore("§d§luniplexmc.enjin.com").setScore(2);
                    objective.getScore("§a===================").setScore(1);
                       
                    p.setScoreboard(board);
                }
            }, 20, 20);
        }
       
        @EventHandler
        public void onPlayerQuit(PlayerQuitEvent event) {
            event.getPlayer().getScoreboard().clearSlot(DisplaySlot.SIDEBAR);
        }
    }
    Thanks!
     
  10. Do NOT put objective = board.registerNewObjective("test", "dummy"); inside the bukkit runnable! Put it outside the bukkit runnable, because then it creates the same objective
    every second, and that error occurs.
     
  11. Thanks for your reply! I have removed "objective = board.registerNewObjective("test", "dummy");", I also removed "p.getScoreboard().getObjective(DisplaySlot.SIDEBAR).unregister();". Now, the players now have individual scoreboards! Except, when they get payed or if another player joins, it doesn't reset the scores, it just stacks up on top of each other. Its hard to explain, here are some screenshots.

    Player 1 when another player joins.
    [​IMG]

    When Player 1 gets payed.
    [​IMG]

    Player 2 when they get payed.
    [​IMG]

    I hope you understand what I'm trying to say :p

    Thanks for your help!
    - Nico
     
  12. The same thing happens to me! Ill stay here to see if there is any solution :p
     
  13. the best scoreboard i've saw until now its a Util called SimpleScoreBoard, you should really try it! its really Easy!
     
  14. Hopefully we can find a solution! :p

    Yeah, thanks for the suggestion! But, I would prefer to try to code it by myself, without a Util :p
     
    • Agree Agree x 1
  15. Hope for the best for you! :D
     
  16. Thanks!
     
  17. Store the previously send lines of the scoreboard on a new iteration check if the new lines doesn't match the old one. If so remove the old score and place the new score, otherwise just continue.
     
  18. This may seem like a dumb question, but, how do I reset a score? I tried using
    Code (Text):
    board.resetScores(String);
    but, it doesn't reset the score. I think I'm using the wrong method but I'm not sure.
    Sorry :p
     
  19. I have found a solution! Well, @Nosma_Stew found it :p.
    This is my working Scoreboard Class
    Code (Text):
    package com.Uniplex.Hub.Scoreboards;

    import java.util.ArrayList;
    import java.util.Iterator;

    import org.bukkit.Bukkit;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.player.PlayerJoinEvent;
    import org.bukkit.event.player.PlayerQuitEvent;
    import org.bukkit.plugin.Plugin;
    import org.bukkit.scoreboard.DisplaySlot;
    import org.bukkit.scoreboard.Objective;
    import org.bukkit.scoreboard.Scoreboard;
    import org.bukkit.scoreboard.ScoreboardManager;

    import com.Uniplex.Core.UniCore;

    public class HubScoreboard implements Listener {
       

       
         public void setupScoreboard(final Player player){
             final ScoreboardManager manager = Bukkit.getScoreboardManager();
             final Scoreboard board = manager.getNewScoreboard();    
             final Objective o = board.registerNewObjective("Scoreboard", "dummy");
             o.setDisplaySlot(DisplaySlot.SIDEBAR);
             o.setDisplayName("§cU§6n§ei§ap§bl§dex");  
           
             double balance = UniCore.economy.getBalance(player.getName());
           
             o.getScore("§b§lPlayers Online:").setScore(9);
             o.getScore("§d§l" + Bukkit.getServer().getOnlinePlayers().size()).setScore(8);
             o.getScore("§f").setScore(7);
             o.getScore("§b§lBalance:").setScore(6);
             o.getScore("§d§l" + balance).setScore(5);
             o.getScore("").setScore(4);
             o.getScore("§b§lWebsite:").setScore(3);
             o.getScore("§d§luniplexmc.enjin.com").setScore(2);
             o.getScore("§a===================").setScore(1);
             
             player.setScoreboard(board);  
         }
    }
     
    and in your onEnable, you add
    Code (Text):
    BukkitScheduler scheduler = Bukkit.getServer().getScheduler();
            scheduler.scheduleSyncRepeatingTask(this, new Runnable() {
                @Override
                public void run() {
                    for(Player p : Bukkit.getServer().getOnlinePlayers()) {
                        scoreboard.setupScoreboard(p);
                    }
                }
            }, 0, 60L);
    Thanks for the help @Nosma_Stew!
     
    • Friendly Friendly x 1
  20. Glad i helped!!