Running Two, Working, Scoreboards At The Same Time?

Discussion in 'Spigot Plugin Development' started by fujiboy4, Apr 25, 2017.

  1. Hello!! I had a question for you guys hoping that I can get by this... but..
    Are you able to run two scoreboards at the same time?

    One scoreboard handles above head player name tag prefixes and suffixes using scoreboard teams while the other uses the sidebar scoreboard... Is there a way I could combine both them into the same scoreboard? Hope you guys can answer my questions!! :)
     
  2. As far as I am aware a player can only use one scoreboard at once (meaning either the main scoreboard, or a new plugin-created scoreboard, but not multiple scoreboards at one time).

    Is there any reason that your scoreboard teams and sidebar scoreboard aren't the same scoreboard?

    For example, I do:

    Code (Text):
    Scoreboard gameboard = Bukkit.getServer().getScoreboardManager().getNewScoreboard();
    Objective kills = gameboard.registerNewObjective("kills", "dummy"); // Set this as your kills score or whatever you're counting, set display slot etc after this.
    Team staff = gameboard.registerNewTeam("staff"); // Register a new team and set prefixes etc after this.
    If you do it this way you can have multiple objectives being shown at once (above players head, tab list, or sidebar) while still having team colours (because the team and objectives are on the same scoreboard).
     
  3. You can use 1 scoreoard to handle both the SIDEBAR and Team prefixes. I did it and its pretty easy. Just do what you're doing now but use the same scoreboard.
     
  4. Okay, my setup involves 2 different classes to handle the scoreboards, can I just get the Main Scoreboard in both classes rather than combining the 2 classes into one?
     
  5. It really depends on your setup. If you have a scoreboard showing per-player data like the players rank you need to create a new scoreboard for every player and save it, if you want to display global data you can use the main scoreboard.

    I recommend you make one ScoreboardManager Class and handle everything scoreboard related in that Class.
     
    • Creative Creative x 1
  6. Okay, here is my code...
    Code (Text):
    public class Titles {

        Player p;
        String prefix;
        String suffix;

        Scoreboard scoreboard;
        Team team;

        @SuppressWarnings("deprecation")
        public Titles(Player player, String prefix, String suffix) {
            scoreboard = Bukkit.getScoreboardManager().getMainScoreboard();
            System.out.println("Registered Scoreboard...");
         
            try {
                team = scoreboard.registerNewTeam(player.getName());
                System.out.println("Registered Team...");
            } catch (IllegalArgumentException e) {
                team = scoreboard.getTeam(player.getName());
                System.out.println("Team Already Exists..");
            }
         
         
            this.prefix = prefix;
            this.suffix = suffix;

            team.setPrefix(this.prefix);
            team.setSuffix(this.suffix);

            System.out.println(" Prefix: " + this.prefix + " Suffix: " + this.suffix);
         
            this.p = player;
         
            if (!team.hasEntry(player.getDisplayName())) {
                System.out.println("Doesn't have player... adding it to the list.");
                team.addEntry(player.getDisplayName());
                System.out.println(team.getPlayers().toString());
            }

            if (scoreboard != null) {
                if (p != null) {
                    p.setScoreboard(scoreboard);
                    System.out.println("Set scoreboard : " + scoreboard.toString());
                } else {
                    System.out.println("Player = null");
                }
            } else {
                System.out.println("Scoreboard = null");
            }

        }
     
        public Team getTeam() {
            return team;
        }

        public void setPrefix(String newPrefix) {
            this.prefix = newPrefix;
            team.setPrefix(prefix);
        }

        public void setSuffix(String newSuffix) {
            this.suffix = newSuffix;
            team.setSuffix(suffix);
        }

        public String getPrefix() {
            return this.prefix;
        }

        public String getSuffix() {
            return this.suffix;
        }
    }

    Code (Text):
    public class Scoreboards {

        Player p;
     
        Scoreboard scoreboard;
        Objective obj;

        public Scoreboards(Player p, String title, ArrayList<String> lines) {
            scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
         
            obj = scoreboard.registerNewObjective("test", "dummy");
            obj.setDisplaySlot(DisplaySlot.SIDEBAR);
            obj.setDisplayName(ChatColor.translateAlternateColorCodes('&', title));

            if (!(lines.size() > 16) || !(lines.size() < 0)) {
                for (int i = lines.size() - 1; i > -1; i--) {
                    Score score = obj.getScore(ChatColor.translateAlternateColorCodes('&', lines.get(i)));
                    score.setScore(lines.size() - i);
                }
            } else {
                throw new IllegalArgumentException();
            }

            p.setScoreboard(scoreboard);

            this.p = p;      
        }

        public boolean hasScoreboard() {
            if (p != null) {
                if (p.getScoreboard() != null) {
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }

        public static void resetBoard(Player p) {
            Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
            p.setScoreboard(scoreboard);
        }

        public void removeAll() {
            for (String entry : this.scoreboard.getEntries()) {
                this.scoreboard.resetScores(entry);
            }
        }

        public void removeLine(int line) {
            for (String entry : this.scoreboard.getEntries()) {
                if (this.obj.getScore(entry).getScore() == line) {
                    this.scoreboard.resetScores(entry);
                    break;
                }
            }
        }

        public Scoreboard getScoreboard() {
            return scoreboard;
        }

        public String getTitle() {
            return obj.getDisplayName();
        }

        public void setTitle(String name) {
            this.obj.setDisplayName(ChatColor.translateAlternateColorCodes('&', name));
        }

        public void set(int row, String text) {
            Validate.isTrue(16 > row, "Row can't be higher than 16");
            if (text.length() > 32) {
                text = text.substring(0, 32);
            }

            for (String entry : this.scoreboard.getEntries()) {
                if (this.obj.getScore(entry).getScore() == row) {
                    this.scoreboard.resetScores(entry);
                    break;
                }
            }

            this.obj.getScore(ChatColor.translateAlternateColorCodes('&', text)).setScore(row);
        }

    }

    Both classes work without each other. So all I "should" need to do is make them both get the Main Scoreboard and then when the player joins do:
    Code (Text):
    Titles title = new Titles(arguments go here);
    title.setPrefix(title here);
    title.setSuffix(title here);

    Scoreboards scoreboard = new Scoreboards(arguments go here);
    // Add lines to scoreboard...

    player.setScoreboard(scoreboard.getScoreboard() /* Which should be the same as the titles scoreboard? */ );
    Right?
     
  7. I would do this:

    1. onEnable register sidebar and teams (with prefixes) for the main scoreboard.
    2. onJoin set the players scoreboard to the main scoreboard and add them to the team for their rank.

    Get the main scoreboard by doing
    Code (Text):
    Bukkit.getScoreboardManager().getMainScoreboard()
    The code you're currently using is way too complicated and it could be done much easier so I suggest you start from scratch.
     
  8. Alright, well I have this code now. It is kind bugging out now, only setting it for one player.

    Code (Text):
    public class Scoreboards {

        Player player;
        String prefix;
        String suffix;
       
       
        Scoreboard scoreboard;
        Objective obj;
        Team team;

        public Scoreboards(Player player, String title, ArrayList<String> lines) {
            scoreboard = Bukkit.getScoreboardManager().getMainScoreboard();
           
            try {
                obj = scoreboard.registerNewObjective("test", "dummy");
            } catch (Exception e) {
                obj = scoreboard.getObjective("test");
            }
           
            obj.setDisplaySlot(DisplaySlot.SIDEBAR);
            obj.setDisplayName(ChatColor.translateAlternateColorCodes('&', title));

            if (!(lines.size() > 16) || !(lines.size() < 0)) {
                for (int i = lines.size() - 1; i > -1; i--) {
                    Score score = obj.getScore(ChatColor.translateAlternateColorCodes('&', lines.get(i)));
                    score.setScore(lines.size() - i);
                }
            } else {
                throw new IllegalArgumentException();
            }

            try {
                team = scoreboard.registerNewTeam(player.getName());
                System.out.println("Registered Team...");
            } catch (IllegalArgumentException e) {
                team = scoreboard.getTeam(player.getName());
                System.out.println("Team Already Exists..");
            }
           
            this.player = player;
           
            if (!team.hasEntry(player.getDisplayName())) {
                System.out.println("Doesn't have player... adding it to the list.");
                team.addEntry(player.getDisplayName());
                System.out.println(team.getEntries().toString());
            }

            if (scoreboard != null) {
                player.setScoreboard(scoreboard);
                System.out.println("Set scoreboard : " + scoreboard.toString());
            } else {
                System.out.println("Scoreboard = null");
            }
           
           
        }

        public boolean hasScoreboard() {
            if (player != null) {
                if (player.getScoreboard() != null) {
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }

        public static void resetBoard(Player p) {
            Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
            p.setScoreboard(scoreboard);
        }

        public void removeAll() {
            for (String entry : this.scoreboard.getEntries()) {
                this.scoreboard.resetScores(entry);
            }
        }

        public void removeLine(int line) {
            for (String entry : this.scoreboard.getEntries()) {
                if (this.obj.getScore(entry).getScore() == line) {
                    this.scoreboard.resetScores(entry);
                    break;
                }
            }
        }

        public Scoreboard getScoreboard() {
            return scoreboard;
        }

        public String getTitle() {
            return obj.getDisplayName();
        }

        public void setTitle(String name) {
            this.obj.setDisplayName(ChatColor.translateAlternateColorCodes('&', name));
        }

        public void set(int row, String text) {
            Validate.isTrue(16 > row, "Row can't be higher than 16");
            if (text.length() > 32) {
                text = text.substring(0, 32);
            }

            for (String entry : this.scoreboard.getEntries()) {
                if (this.obj.getScore(entry).getScore() == row) {
                    this.scoreboard.resetScores(entry);
                    break;
                }
            }

            this.obj.getScore(ChatColor.translateAlternateColorCodes('&', text)).setScore(row);
        }
       
        public Team getTeam() {
            return team;
        }

        public void setPrefix(String newPrefix) {
            this.prefix = newPrefix;
            team.setPrefix(prefix);
        }

        public void setSuffix(String newSuffix) {
            this.suffix = newSuffix;
            team.setSuffix(suffix);
        }

        public String getPrefix() {
            return this.prefix;
        }

        public String getSuffix() {
            return this.suffix;
        }

    }
     
    It worked until I got the error saying it already had an objective. Although, I tried making a way of getting the objective if it already exists.. Is this the right way of doing it?
     
  9. Thats because
    What info do you want to display on the sidebar? Do you want to show global info or per player info?

    Global info example:
    Welcome to the server

    website:
    website.com

    online:
    13/40


    Per player info:
    Welcome SmokingIsBadMkay

    Rank:
    default

    Coins:
    23

    This is important to know because the way you need to code this really depends on the information you want to show on the sidebar.
     
  10. The scoreboard is per player information.
     
  11. Oh, well in that case you will need to create a new scoreboard for every player. On player join create a new Scoreboards() class for the player and save it in a hashMap. Since you want to have a scoreboard for every player you can't use the main scoreboard so use getNewScoreboard() instead.
     
  12. I had it working with getNewScoreboard before and it worked perfectly fine... Then I added in the Team and title stuff into that class and it stopped working.
     
  13. Okay, so I changed it so none of the Team stuff is being called or set, and the scoreboard works normally now...

    And I think I know why this isn't quite working either.. The titles are being set because there are 2 separate scoreboards for the 2 players online. Since the scoreboards are personal preference... There will be a scoreboard with one title and another with another title. Therefore, the other players cannot see each other titles because they are in separate scoreboards...Anyway to conquer this? xD
     
  14. With titles you mean ranks right? I had the exact same problem when I was coding my core plugin. What you need to do is set the titles of all online players for every scoreboard you create. So if you create the board for player1 you also need to loop through the OnlinePlayers list and set the titles of those players on the scoreboard of player1.

    This is how I update (set) my tablist rank colors:
    Code (Text):
          public static void updateTab(Player p)
            {
                //My core plugin hides players that aren't in the same world as you
                //So thats why I only update the scoreboard for the players in the same world
                //In your case you would use Bukkit.getOnlinePlayers() for the loop
                for (Player online : p.getWorld().getPlayers()) {
                    Rank rank = DataManager.getPlayerData(p.getUniqueId()).getRank();
                    //get(player) returns the players personal scoreboard instance
                    Scoreboard board = get(online);

                    //Tab priority returns a letter which it puts in front of the rank name.
                    //This way I can make the owner be on top of the tablist and moderators below.
                    //Here are 2 examples of what my team names would be:
                    //Owner: aOWNER
                    //Admin: bADMIN
                    Team team = board.getTeam(rank.getTabPriority() + rank.name());
                    if (team != null)
                    {
                        team.addPlayer(p);
                   
                        //rank.getTabColor() returns the ChatColor (prefix) for the player's rank
                        //setPlayerListName doesn't have anything to do with the scoreboard
                        //I set the PlayerListName just in case the player is in a world without a scoreboard
                        p.setPlayerListName(rank.getTabColor() + p.getName());
               
                        //The team option disables collision so you can remove that
                        team.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER);
                    }
           
                    //update scoreboards for all other players
                    online.setScoreboard(board);
                }
                for (Player online : p.getWorld().getPlayers()) {
                    Rank rank = DataManager.getPlayerData(online.getUniqueId()).getRank();
                    Scoreboard board = get(p);
                    Team team = board.getTeam(rank.getTabPriority() + rank.name());
                    if (team != null)
                    {
                        team.addPlayer(online);
                        online.setPlayerListName(rank.getTabColor() + online.getName());
                        team.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER);
                    }
           
                    //update scoreboard for the player you're updating
                    p.setScoreboard(board);
                }
            }
     
    #14 SmokingIsBadMkay, Apr 27, 2017
    Last edited: Apr 27, 2017
  15. Okay, I think I can implement this..
    Would this be called in the onJoinEvent or in the constructor of Scoreboards.java?
    And I am using this in a different aspect as well, I using the RolePlay plugin I have developed and I am trying to set the prefix to the player's roleplay name and then the suffix to the player's role. (And yes I have accounted for strings longer than x amount that will prevent it from breaking.)
     
  16. I call this method whenever I want to update my tablist (for example if someones rank changes). You should probably put it in the same place as where you set the player's SIDEBAR.

    As for the prefix and suffix. The code I showed you only adds people to the right scoreboard team (if it exists). You should setup your teams (with prefix/suffix) when you create a new scoreboard for the player joining.
     
  17. This is when the player join even is called:
    Code (Text):
    final Scoreboards scoreboard = new Scoreboards(p, ChatColor.GOLD + "" + ChatColor.BOLD + "SKRolePlay "
                    + ChatColor.RED + "" + ChatColor.BOLD + "" + Main.vs, board);
           
            new BukkitRunnable() {

                @Override
                public void run() {
                    System.out.println("Scoreboard: " + scoreboard.getScoreboard().getTeams().toString());
                    RolePlayGroup rpg2 = Main.listManager.getRolePlayGroupByMember(p.getUniqueId());
                    if (rpg2 != null) {
                        if (scoreboard.hasScoreboard()) {
                            scoreboard.set(3, ChatColor.AQUA + " " + rpg2.getAllMembers().size());
                            scoreboard.set(6, ChatColor.AQUA + " " + rpg2.getOwner().getName());

                            String roleplayname = rpg2.getName().toString();
                            if (roleplayname.length() >= 11) {
                                roleplayname = roleplayname.substring(0, 6) + "...";
                            }

                            //scoreboard.setPrefix(ChatColor.GOLD + " " + roleplayname + " " + ChatColor.GRAY);

                            if (rpg2.getRoleFromUUID(p.getUniqueId()) != null) {
                                scoreboard.set(9,
                                        ChatColor.AQUA + " " + rpg2.getRoleFromUUID(p.getUniqueId()).getName().toString());
                                String rolename = rpg2.getRoleFromUUID(p.getUniqueId()).getName().toString();
                                if (rolename.length() >= 11) {
                                    rolename = rolename.substring(0, 6) + "...";
                                }

                                //scoreboard.setSuffix(ChatColor.BLUE + " " + rolename);
                            } else {
                                scoreboard.set(9, ChatColor.RED + " Unassigned");
                                //scoreboard.setPrefix(ChatColor.RED + "");
                            }
                            scoreboard.set(12, ChatColor.AQUA + " " + rpg2.getName());
                        }

                        scoreboard.setScoreboard();
                        System.out.println("P Scoreboard: " + p.getScoreboard().getTeams().toString());

                    } else {
                        p.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard());

                    }

                    if (!p.isOnline()) {
                        if (scoreboard.getTeam() != null) {
                            scoreboard.getTeam().unregister();
                        }
                        cancel();

                    }

                    rpg2 = null;
                }

            }.runTaskTimer(plugin, 0L, 100L);
        }
    As you can see I commented out the prefix stuff.
     
  18. Does it work?
     
    • Agree Agree x 1
  19. Yes, except for the titles (which are commented out but weren't before I posted it )
     
  20. What is isn't working? Aren't they showing or are you getting any errors? Try debugging (for example check if the teams are registered and they have the right prefix etc).