[1.5.1] Custom Scoreboards

Discussion in 'Resources' started by Tzeentchful, Mar 16, 2013.

Thread Status:
Not open for further replies.
  1. Offline

    Tzeentchful

    Scoreboards are a cool feature that was added in the 1.5 update. At the moment there isn't any official bukkit API to create scoreboards and send them to players. So after a bit of tinkering i found how to do it using NMS code.

    For this to be able to work you need to be building against the 1.5.1 dev build of craftbukkit.
    First off you will want to create a new scoreboard and create a new objective. This is going to hold all our scoreboard's data.
    Code:java
    1.  
    2. Scoreboard sb = new Scoreboard();//Create new scoreboard
    3. sb.registerObjective(name, new ScoreboardBaseCriteria("Test"));//Create new objective in the scoreboard called "Test"
    4.  


    We will then want to create a new item in our objective and give it a value.
    Code:java
    1.  
    2. ScoreboardScore scoreItem = sb.getPlayerScoreForObjective("Answer to life", sb.getObjective("Test"));
    3. scoreItem.setScore(42);//Set it's value to 42
    4.  


    All we have to do now it to create the packets and send them to the player.
    Code:java
    1.  
    2. Packet206SetScoreboardObjective packet = new Packet206SetScoreboardObjective(sb.getObjective("Test"), 0);//Create Scoreboard create packet
    3. Packet208SetScoreboardDisplayObjective display = new Packet208SetScoreboardDisplayObjective(1, sb.getObjective("Test"));//Create display packet set to sidebar mode(0 = list, 1 = sidebar, 2 = belowName)
    4.  
    5. Packet207SetScoreboardScore scoreItemP = new Packet207SetScoreboardScore(scoreItem, 0);//Create scoreboard item packet
    6.  
    7. ((CraftPlayer) player).getHandle().playerConnection.sendPacket(scoreboardP);
    8. ((CraftPlayer) player).getHandle().playerConnection.sendPacket(displayP);
    9. ((CraftPlayer) player).getHandle().playerConnection.sendPacket(scoreItemP);
    10.  

    And the list should now show up to the player.

    If you want to change an item in the list.
    Code:java
    1.  
    2. scoreItem.setScore(69);//Set it's value to 69
    3. Packet207SetScoreboardScore scoreItemP = new Packet207SetScoreboardScore(scoreItem, 0);//Create scoreboard item packet
    4.  
    5. ((CraftPlayer) player).getHandle().playerConnection.sendPacket(scoreItemP);
    6.  


    And to remove an item set the update/remove flag to 1.
    Code:java
    1.  
    2. Packet207SetScoreboardScore scoreItemP = new Packet207SetScoreboardScore(scoreItem, 1);//Create scoreboard item packet with flag to to 1
    3.  
    4. ((CraftPlayer) player).getHandle().playerConnection.sendPacket(scoreItemP);
    5.  


    To add more items to the objective simply create another ScoreboardScore and send another SetScoreboardScore packet.
    Code:java
    1.  
    2. ScoreboardScore scoreItem1 = sb.sb.getPlayerScoreForObjective("Stuff n stuff", sb.b("Test"));//Create a new item in the "Test" objective
    3. scoreItem1.setScore(1337);//Set it's value to 42
    4.  
    5. ScoreboardScore scoreItem2 = sb.sb.getPlayerScoreForObjective("Some port", sb.b("Test"));//Create a new item in the "Test" objective
    6. scoreItem2.setScore(25565);//Set it's value to 25565
    7.  
    8. Packet207SetScoreboardScore scoreItemP1 = new Packet207SetScoreboardScore(scoreItem1, 0);//create item 1
    9. Packet207SetScoreboardScore scoreItemP2 = new Packet207SetScoreboardScore(scoreItem2, 0);//create item 2
    10.  
    11. ((CraftPlayer) player).getHandle().playerConnection.sendPacket(scoreItemP1);//send item 1
    12. ((CraftPlayer) player).getHandle().playerConnection.sendPacket(scoreItemP2);//send item 2
    13.  


    Here is a full example.
    Code:java
    1.  
    2. public void test(final Player player) {
    3. getServer().getScheduler().runTask(this, new Runnable() {
    4. @Override
    5. public void run() {
    6. String name = "Test";
    7.  
    8. Scoreboard sb = new Scoreboard();//Create new scoreboard
    9. sb.registerObjective(name, new ScoreboardBaseCriteria(name));//Create new objective in the scoreboard
    10.  
    11. Packet206SetScoreboardObjective packet = new Packet206SetScoreboardObjective(sb.getObjective(name), 0);//Create Scoreboard create packet
    12. Packet208SetScoreboardDisplayObjective display = new Packet208SetScoreboardDisplayObjective(1, sb.getObjective(name));//Create display packet set to sidebar mode
    13.  
    14. sendPacket(player, packet);//Send Scoreboard create packet
    15. sendPacket(player, display);//Send the display packet
    16.  
    17. ScoreboardScore scoreItem1 = sb.getPlayerScoreForObjective("Answer to life", sb.getObjective(name));//Create a new item
    18. ScoreboardScore scoreItem2 = sb.getPlayerScoreForObjective("4 * 4", sb.getObjective(name));//Create a new item
    19. scoreItem1.setScore(42);//Set it's value to 42
    20. scoreItem2.setScore(12);//Set it's value to 12
    21.  
    22. Packet207SetScoreboardScore pScoreItem1 = new Packet207SetScoreboardScore(scoreItem1, 0);//Create score packet 1
    23. Packet207SetScoreboardScore pScoreItem2 = new Packet207SetScoreboardScore(scoreItem2, 0);//Create score packet 2
    24. sendPacket(player, pScoreItem1);//Send score update packet
    25. sendPacket(player, pScoreItem2);//Send score update packet
    26.  
    27. }
    28.  
    29. });
    30. }
    31.  
    32. public static void sendPacket(Player player, Packet packet) {
    33. ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
    34. }
    35.  
     
  2. Offline

    CreeperShift

    This should be interesting. Thanks for posting this, I'll have to get some ideas going soon.

    Just imagine what you could do with custom per player scoreboards :O You could basically give them any information they currently have to get via chat :O.
     
  3. Offline

    stuntguy3000

    Cool stuff :)
     
  4. Offline

    bobacadodl

    Hmm well scoreboard values can only be integers :/
     
  5. Offline

    CreeperShift

    What about adding fake playernames? :p But still, something like a wallet or mana display is possible even without it.
     
  6. Offline

    KeybordPiano459

    Am I the only one that gets an error with the client and crashes if I use this code?
     
  7. Offline

    Tzeentchful

    Are you sending the Packet206SetScoreboardObjective more than once?
    I find that the client crashes if you send the create packet more than once.
     
  8. Offline

    KeybordPiano459

    I'm actually sending Packet207SetScoreboardScore more than once- is there something else I'm supposed to do for multiple items on the scoreboard?
     
  9. Offline

    MCForger

    I am also trying to figure this out.
     
  10. Offline

    Tzeentchful

    You want to use the Packet207SetScoreboardScore packet. And send it multiple times.
    Code:java
    1.  
    2. ScoreboardScore scoreItem1 = sb.a("Answer to life", sb.b("Test"));//Create a new item in the "Test" objective
    3. scoreItem1.c(42);//Set it's value to 42
    4.  
    5. ScoreboardScore scoreItem2 = sb.a("Some value", sb.b("Test"));//Create a new item in the "Test" objective
    6. scoreItem2.c(25565);//Set it's value to 25565
    7.  
    8. Packet207SetScoreboardScore scoreItemP1 = new Packet207SetScoreboardScore(scoreItem1, 0);//create item 1 packet
    9. Packet207SetScoreboardScore scoreItemP2 = new Packet207SetScoreboardScore(scoreItem2, 0);//create item 2 packet
    10.  
    11. //then send the packets
    12.  

    I'll add this to the main post.
     
  11. Offline

    MCForger

    Tzeentchful
    May you write a full example of this in a sync scheduler?
     
  12. Offline

    Tzeentchful

    I reformatted my laptop so i dont have eclipse on here atm. But i will do something when i get home.
     
  13. Offline

    KeybordPiano459

    Tzeentchful
    That's exactly what I did, here's all of my code (by the way this is PlayerJoinEvent):
    Code:java
    1. Scoreboard sb = new Scoreboard();
    2. sb.a("Captures", new ScoreboardBaseObjective("Captures"));
    3. ScoreboardScore scoreItemBlue = sb.a("Blue", sb.b("Captures"));
    4. ScoreboardScore scoreItemRed = sb.a("Red", sb.b("Captures"));
    5. scoreItemBlue.c(1);
    6. scoreItemRed.c(1);
    7. Packet206SetScoreboardObjective scoreboardP = new Packet206SetScoreboardObjective(sb.b("Captures"), 1);
    8. Packet208SetScoreboardDisplayObjective displayP = new Packet208SetScoreboardDisplayObjective(1, sb.b("Captures"));
    9. Packet207SetScoreboardScore scoreItemBlueP = new Packet207SetScoreboardScore(scoreItemBlue, 1);
    10. Packet207SetScoreboardScore scoreItemRedP = new Packet207SetScoreboardScore(scoreItemRed, 1);
    11. PlayerConnection pc = ((CraftPlayer) event.getPlayer()).getHandle().playerConnection;
    12. pc.sendPacket(scoreboardP);
    13. pc.sendPacket(displayP);
    14. pc.sendPacket(scoreItemBlueP);
    15. pc.sendPacket(scoreItemRedP);
     
  14. Offline

    Tzeentchful

    You have your packet's add/remove flag set to 1. So it's trying to remove an item that isn't there.
    Code:java
    1.  
    2. //From
    3. Packet207SetScoreboardScore scoreItemBlueP = new Packet207SetScoreboardScore(scoreItemBlue, 1);
    4. Packet207SetScoreboardScore scoreItemRedP = new Packet207SetScoreboardScore(scoreItemRed, 1);
    5.  
    6. //To
    7. Packet207SetScoreboardScore scoreItemBlueP = new Packet207SetScoreboardScore(scoreItemBlue, 0);
    8. Packet207SetScoreboardScore scoreItemRedP = new Packet207SetScoreboardScore(scoreItemRed, 0);
    9.  
     
  15. Offline

    KeybordPiano459

    Tzeentchful
    It still crashes with a "Ticking screen"
     
  16. Offline

    Tzeentchful

    Ah you also have your SetScoreboardObjective set to remove instead of create.
    Code:java
    1.  
    2. //From
    3. Packet206SetScoreboardObjective scoreboardP = new Packet206SetScoreboardObjective(sb.b("Captures"), 1);
    4. //To
    5. Packet206SetScoreboardObjective scoreboardP = new Packet206SetScoreboardObjective(sb.b("Captures"), 0);
    6.  
     
  17. Offline

    KeybordPiano459

  18. Offline

    XDemonic25

    Does this also change the name color to the teams color?

    And also is there a way to do like

    Code
    Code:
    If(Player.IsScoreBoardTeam("Team Name"){
    //CODE
    }
    
     
  19. Offline

    Tzeentchful

    No this wont change the player name colour. Refer to this if you want to change the colour/team of a player.
     
  20. Offline

    wacossusca34

    Hey!

    Just wanted to say thanks for this, it was a huge help. I was going to dive into the obfuscation myself, buy you saved me of some work. I now have a score system working in my plugin that is specific to certain players within certain games!
     
  21. Offline

    Rprrr

    Not really. It's horrible. I tried to make an announcement plugin, but you can only display 16 characters per line..

    Also, you can barely influence the order of strings, they're sorted alphabetically.
     
  22. Offline

    CreeperShift

    Well an announcement plugin wasn't something I had in mind. I was thinking of a wallet showing you your current cash, a mana display showing you how much mana you have left etc, small things that currently need a command that to see.
     
  23. Offline

    Rprrr

  24. Offline

    CreeperShift

  25. Offline

    Cybermaxke

    jjacobson likes this.
  26. Offline

    CreeperShift

    Cybermaxke likes this.
  27. Offline

    Tzeentchful

    Ok guys i have created a nifty little class for handling scoreboards. I haven't tested it much so expect it to have bugs, you can have a look at it here.
    And you can use it like so.
    PHP:
        ScoreboardManager sm;
     
        @
    Override
        
    public void onEnable() {
            
    sm = new ScoreboardManager();
         
            
    sm.createScoreboard("Test");
            
    sm.createObjective("Test""Test");
            
    sm.setObjectiveItem("Test""Test""alive"69);
            
    sm.setObjectiveItem("Test""Test""woo"32);
         
            
    sm.createObjective("Test""Lol");
            
    sm.setObjectiveItem("Test""Lol""cool"44);
            
    sm.setObjectiveItem("Test""Lol""stuff"88);
        }
    PHP:
        @Override
        
    public boolean onCommand(CommandSender senderCommand commandString labelString[] args) {
            if(
    sender instanceof Player){
                
    Player player = (Playersender;
                
    Scoreboard sb;
                if(
    command.getName().equalsIgnoreCase("test")){
                    
    sm.sendScoreboardData(player"Test");
                }else if(
    command.getName().equalsIgnoreCase("test2")){
                    if(
    args.length && args[0].equalsIgnoreCase("lol")){
                    
    sm.displayObjective(player"Test""Lol");
                    }else{
                        
    sm.displayObjective(player"Test""Test");
                    }
                     
                }
            }
            return 
    true;
        }
    I'll work on it a bit and I'll add it to the main post when I'm happy with it.
     
  28. Offline

    Barinade

    I've ran into a few issues while fondling this myself, first being client crash "obective x already exists" when sending the scoreboard a second time, another would be the scoreboard only showing to one person, as in the first person to see the scoreboard is the only person to see it. Another is if a player relogs, he won't get the scoreboard, even if the packets are sent.

    My fix includes saving the scoreboards in memory and accessing them when needing to refresh. If one doesn't exist in memory, it creates one. The problem with methods/voids etc is that everything instantiated in them gets cleared when the method is complete, so you've lost your scoreboard. There is a CraftPlayer.getScoreboard() function but it didn't seem to work for me.

    You can see my scoreboard, fully made by myself after 5 hours of working out obfuscation, at us1.mchavoc.com
    Players are lacking due to the time, we usually keep around ~50.

    If anyone is having any of these issues and would like some help feel free to add me to Skype and I'll try to help you.
    ira.sancti
     
  29. Offline

    CreeperShift

    Barinade

    Wow I really like what you did. I just got on and went on a killing spree in one of the arenas xD Your use of the scoreboard is really neat! :)
     
  30. Offline

    Barinade

    Thanks, I'm glad you like it :p
     
Thread Status:
Not open for further replies.

Share This Page