Creation of Combat Scoreboard Help!

Discussion in 'Plugin Development' started by Comlud, Jun 23, 2018.

Thread Status:
Not open for further replies.
  1. (First thread, so what I write might be completely wrong)
    Hey!
    I'm making a combat scoreboard for my server, but I need help with some things.
    And also, I have 6 variables for players, so only 6 players will be shown on the scoreboard. That's because of lack of knowledge. I tried to use an array, but without success...

    Here's my code:
    Code:
    public class Main extends JavaPlugin implements Listener
    {
        Player noPlayer;
       
        Player player1 = noPlayer;
        Player player2 = noPlayer;
        Player player3 = noPlayer;
        Player player4 = noPlayer;
        Player player5 = noPlayer;
        Player player6 = noPlayer;
       
        Score noScore;
       
        Score kills1 = noScore;
        Score kills2 = noScore;
        Score kills3 = noScore;
        Score kills4 = noScore;
        Score kills5 = noScore;
        Score kills6 = noScore;
        ScoreboardManager manager = Bukkit.getScoreboardManager();
        Scoreboard scoreboard = manager.getNewScoreboard();
        Objective o = scoreboard.registerNewObjective("KillCount", "");
       
        public static Main instance;
       
        @EventHandler
        public void onJoin(PlayerJoinEvent event)
        {
            Player player = event.getPlayer();
            if(kills1 == noScore && player1 == noPlayer)
            {
                player1 = event.getPlayer();
                kills1 = o.getScore(player.getDisplayName() + ": 0");
                kills1.setScore(5);
            }
            else if(kills2 == noScore && player2 == noPlayer)
            {
                player2 = event.getPlayer();
                kills2 = o.getScore(player.getDisplayName() + ": 0");
                kills2.setScore(4);
            }
            else if(kills3 == noScore && player3 == noPlayer)
            {
                player3 = event.getPlayer();
                kills3 = o.getScore(player.getDisplayName() + ": 0");
                kills3.setScore(3);
            }
            else if(kills4 == noScore && player4 == noPlayer)
            {
                player4 = event.getPlayer();
                kills4 = o.getScore(player.getDisplayName() + ": 0");
                kills4.setScore(2);
            }
            else if(kills5 == noScore && player5 == noPlayer)
            {
                player5 = event.getPlayer();
                kills5 = o.getScore(player.getDisplayName() + ": 0");
                kills5.setScore(1);
            }
            else if(kills6 == noScore && player6 == noPlayer)
            {
                player6 = event.getPlayer();
                kills6 = o.getScore(player.getDisplayName() + ": 0");
                kills6.setScore(0);
            }
            player.setScoreboard(scoreboard);
        }
       
        @EventHandler
        public void onLeave(PlayerQuitEvent event)
        {
            if(player1 == event.getPlayer())
            {
                player1 = noPlayer;
                kills1 = noScore;
            }
            else if(player2 == event.getPlayer())
            {
                player2 = noPlayer;
                kills2 = noScore;
            }
            else if(player3 == event.getPlayer())
            {
                player3 = noPlayer;
                kills3 = noScore;
            }
            else if(player4 == event.getPlayer())
            {
                player4 = noPlayer;
                kills4 = noScore;
            }
            else if(player5 == event.getPlayer())
            {
                player5 = noPlayer;
                kills5 = noScore;
            }
            else if(player6 == event.getPlayer())
            {
                player6 = noPlayer;
                kills6 = noScore;
            }
        }
       
        @Override
        public void onEnable()
        {
            getLogger().info("ComludPVP has successfully been enabled!");
           
            getServer().getPluginManager().registerEvents(this, this);
            PluginManager pm = getServer().getPluginManager();
            pm.registerEvents(this, this);
           
            // Scoreboard
            o.setDisplaySlot(DisplaySlot.SIDEBAR);
            o.setDisplayName(ChatColor.GREEN + "Kills In A Row");
           
            new BukkitRunnable()
            {
                @Override
                public void run()
                {
                    for(Player p : Bukkit.getServer().getOnlinePlayers())
                    {
                        p.setScoreboard(scoreboard);
                    }
                }
            }.runTaskTimer(this, 0L, 20L);
        }
       
        @Override
        public void onDisable()
        {
            getLogger().info("ComludPVP has successfully been disabled!");
        }
    }
    The scoreboard shows all players, even when a new joins, but not when he/she leaves.
    So what I mean, is that the scoreboard doesn't update when someone leaves.
    So what's wrong? (Or has to be done?)

    Thanks,
    Comlud
     
  2. Offline

    CommonSenze

    @Comlud
    There are a lot of thing I can tell you to improve your code, however, I'll keep it simple and answer your question. To update when a player leaves you would want to have the string that you set the score being in the Join event saved somewhere and be able to use the player to access it again. Once accessed you will have to go to the scoreboard and activate the Scorboard#resetScore(String string) method.
     
  3. Thanks a lot!
    I know this forum isn't the place for "spoonfeeding", you know, just give the perfect code.
    BUT, it would be nice if you wanna show/tell me how to improve my code.
     
  4. Offline

    CommonSenze

    @Comlud
    Of course, this forum is suppose to help improve your coding skills.

    First thing I would recommend doing is having your players in an Array like so:

    Code:java
    1. Player[] players = new Player[6];
    2. Score[] scores = new Score[6];

    Now, assuming you're new to arrays, Arrays are just a place to put multiple of the same objects, like Scores or Players, in a list so you can save them and use them for later. In Arrays, you must declare how many object you would like to put in the list.

    Once you create the array of objects all the slots/placeholders of the list are set to the default value of the data type, in objects their defaults are null. For more information, click this.

    Side note before we go any further, when you were checking if player1 or any of the variables where equal to noPlayer you were basically checking if they were null. When you declare but don't initialize (ie. Player noPlayer;), you create a variable not set to anything. By not initializing it to anything, it sets to its default value; in this case, null. So it makes no sense to make Player player1 equal to noPlayer because it wouldn't change anything since they will already be null.

    Now in the Join Event you can use the made arrays in a for loop to check if the object in the array is null. If it is null, we set that slot to the object of the player joining like so:
    Code:java
    1. for (int num = 0; num < players.length; num++) {
    2. if (players[num][I] == [/I]null) {
    3. players[num] = event.getPlayer();
    4. scores[num] = o.getScore(players.getName() + "'s Kills: 0");
    5. scores[num].setScore(num);
    6. }
    7. }

    Now, assuming you don't know that much about for loops, this is an incrementing for loop. Now what that means is it has an integer that starts at 0, checks if it the boolean in the middle of the header is true (In this case we see if the integer that we made is less then the size of the array. Also keep in mind the integer we set keeps going up because the last part in the header of the for loop is adding one to it.). If it is true, it does the action at the last part. Now you can do a lot more then just incrementation, however, you can learn that at a later time. Now, in order to access an array, you must give it an integer of what slot you want to access. In java, all arrays, arraylist, sets, etc. starts at 0 and goes all the way up until it reaches the number one less then the actual size itsself. So in this case, 6 is the size so the array will go from 0 to 5, or 6 elements.

    In the for loop, we check if the object in the numbered slot is null or if its occupied by the player, if it is we leave it alone and continue checking. If it is null, however, we set the slot number in the array to the actual player that joined and also get the scores array and set that same number slot to the score that we want while also setting the score to the name number.

    Now that we've finished the Join Event we get to the Quit event to remove the player, this should be fairly easy. All we have to do is check if the players array contains the player that left, if they did leave we set that slot in players and scores to null so it can be used later like so:
    Code:java
    1. for (int num = 0; num < players.length; num++) {
    2. if (players[num] == event.getPlayer()) {
    3. players[num] = null;
    4. scores[num] = null;
    5. }
    6. }

    Once you set it to null, you can keep adding and removing players as you please. But be sure to make a way to update the scoreboard when a player leaves and joins. Now if you would like me to show you how to do that I will be happy to do so. I hope this all made sense, make sure to read over if you didn't understand anything I said and feel free to ask questions.
     
    Comlud likes this.
  5. Thank you so much CommonSenze!
    Really, you've made my day :D

    In fact, I knew the basics about arrays, but not how to implement them in java. (I've done some c++ before)

    Does this work for updating the scoreboard?
    Code:
    BukkitScheduler scheduler = getServer().getScheduler();
    scheduler.scheduleSyncRepeatingTask(this, new Runnable()
    {
        @Override
        public void run()
        {
            for(Player p : Bukkit.getOnlinePlayers())
            {
                scoreboard.resetScores(p);
            }
        }
    }, 0L, 20L);
    (I'd love to see how you would do it)

    It says that "resetScores" is deprecated.
    What does that even mean? People are talking about it like that the code is still working, but it's no good to use
     
  6. Offline

    KarimAKL

    @Comlud Pretty sure you should use "scoreboard.resetScores(string);" but not sure. (String being what's in the line)
     
  7. Offline

    CommonSenze

    @Comlud
    Sure I'll explain how to update a players scoreboard.

    So what we will be doing is just completely clearing the scoreboard and setting all the scores back up that aren't null (because when a player leaves we set them to null so we will have to do a check to avoid a NPE).

    Now I wouldn't recommend updating it every second because that can cause lag to the server. What I do recommend is having a method for updating the scoreboard so you can just call the method every time you need to update it (ie. When a player connects or disconnects.)

    Now in the method you create you would want to first take in the Player that is going to receive the update (unless you want to just have the method always take in all online players. In that case you can just use the for loop of all players and do the following steps). Once you have the player, you would want to get their scoreboard with this method:
    Code:java
    1. Scoreboard playerBoard = player.getScoreboard();

    Now that you have the scoreboard of the player you want to get the Objective of the Side bar by getting the objective of the Display Slot named Side Bar.

    Once you have the objective you are ready to update. With the playerBoard variable we will get all String entries in the scoreboard and remove them (By the way, @KarimAKL was right about the resetScores(string); method). We will do a for loop with all the entries like so:
    Code:java
    1. for (String entry : playerBoard.getEntries()) {
    2. playerBoard.resetScores(entry);
    3. }

    Now that we removed all scores from the scoreboard we can set them back up with the scores variable. We will do another incrementation for loop to check every Score in scores and check if they aren't null like so:
    Code:java
    1. for (int num = 0; num < scores.length; num++) {
    2. if (scores[num] != null) {
    3. scores[num] = o.getScore(scores[num].getEntry());
    4. scores[num].setScore(num+1);
    5. }
    6. }

    Now one thing I forgot to tell you in the previous post I made is that if you want the red numbers on the scoreboard to be 1 - 6 you will have to add one to the num in the for loop like I did above. Now as you see also above, instead of doing what I did last time of doing:
    Code:java
    1. o.getScore(players.getName() + "'s Kills: 0");

    I did:
    Code:java
    1. o.getScore(scores[num].getEntry());

    That's because in the join event I set the string to the first like of code of "player.getName() + ''s Kills: 0'" so it's saved in the score that I saved in the scores array. So all I would have to do is get the Entry which is the string that we set before.

    Once all of that is finished. The last thing you need to do is set the players scoreboard to the playerBoard variable we had.

    Now if you wanted to update by getting the player with the most kills every time, which is what I think you want seeing your code. You will have to make a variable on how many kills every player has and do a check to get the first 6 players with the most kills and set it to that. If you need me to show you how to do that I will be happy to assist. But until then that should it.
     
    Comlud likes this.
  8. So, this is the code I have right now:

    Code:
    public class Main extends JavaPlugin implements Listener
    {
        Score[] scores = new Score[20];
        String[] players = new String[20];
        int[] kills = new int[20];
    
        Scoreboard board;
        Objective o;
    
        @Override
        public void onEnable()
        {
            getLogger().info("ComludCombat has successfully been enabled!");
    
            getServer().getPluginManager().registerEvents(this, this);
            PluginManager pm = getServer().getPluginManager();
            pm.registerEvents(this, this);
    
            board = Bukkit.getScoreboardManager().getNewScoreboard();
            o = board.registerNewObjective("Kills", "");
    
            o.setDisplaySlot(DisplaySlot.SIDEBAR);
            o.setDisplayName(ChatColor.AQUA + "Kills");
    
            for(int i = 0; i < 20; i++)
            {
                kills = 0;
            }
        }
    
        @Override
        public void onDisable() {
            getLogger().info("ComludCombat has successfully been disabled!");
        }
    
        @EventHandler
        public void onEntityDeath(EntityDeathEvent event) {
            event.getDrops().clear();
     
            if(event.getEntity() instanceof Sheep) {
                Entity killer = event.getEntity().getKiller();
                for(int i = 0; i < 20; i++) {
                    if(killer instanceof Player) {
                        if(((Player) killer).getDisplayName() == players) {
                            kills++;
                            if(players != null) {
                                updateScoreboard(players);
                                break;
                            }
                        }
                    }
                }
            }
        }
    
        @EventHandler
        public void onItemDrop(PlayerDropItemEvent event) {
            event.setCancelled(true);
        }
    
        @EventHandler
        public void onJoin(PlayerJoinEvent event) {
            for (int i = 0; i < players.length; i++) {
                if (players == null) {
                    players = event.getPlayer().getDisplayName();
                    kills = 0;
                    scores = o.getScore(players + ": " + kills);
                    scores.setScore(i);
                    event.getPlayer().setScoreboard(board);
                    break;
                }
            }
            updateScoreboard(event.getPlayer().getDisplayName());
        }
    
        @EventHandler
        public void onLeave(PlayerQuitEvent event)
        {
            for (int i = 0; i < players.length; i++) {
                if (players == event.getPlayer().getDisplayName()) {
                    players = null;
                    scores = null;
                    kills = 0;
                }
                if(players != null) {
                    updateScoreboard(players);
                }
            }
        }
    
        public void updateScoreboard(String name) {
            if(name != null) {
                @SuppressWarnings("deprecation")
                Player player = Bukkit.getPlayer(name);
                Scoreboard playerScoreboard = player.getScoreboard();
                Objective objective = playerScoreboard.getObjective(DisplaySlot.SIDEBAR);
         
                for (String entry : playerScoreboard.getEntries()) {
                    playerScoreboard.resetScores(entry);
                }
         
                for (int i = 0; i < scores.length; i++) {
                    if (scores != null) {
                        scores = objective.getScore(scores.getEntry());
                        scores.setScore(i + 1);
                    }
                }
         
                player.setScoreboard(playerScoreboard);
            }
            else {
                getLogger().warning("The method updateScoreboard() got a null name");
            }
        }
    }

    I changed the data type for players to String, because I read somewhere that it would get rid of problems,
    but it did't change anything

    So, first of all, the scoreboard isn't updating...
    And second, for some reason, like when you execute "/give Player minecraft:dirt" it gives the player 2 dirt.
    And when you do "/give Player minecraft:dirt 64" the player gets a stack + 1.
    Also, it looks like one player takes up two slots in the players array. On the scoreboard the red number is 2
    for the first player that joins. Should be one right?
     
  9. Online

    timtower Administrator Administrator Moderator

    @Comlud Don't use Arrays for this.
    Probably best to use a map for uuid, kills
     
  10. @timtower
    Thanks, I will

    But uhm,
    I know how to create a hashmap, but not really anything else.
    How do I compare a value in a hashmap with some other value?
    A link to a good tutorial would be great!
     
    Last edited: Jun 26, 2018
  11. Offline

    CommonSenze

    @Comlud
    HashMaps have a Key and a Value. So its like "Hey Ill give you this in exchange for this." So you define the two objects that will be the Key and the Value (ie. <Boolean, String> The boolean is the key and the String is the value). Now to put things in the HashMap, you use the put(Object key, Object value) method that takes in the key and the value it will be "unlocking" when you need it.

    In order to unlock that specific value you must put in that specific key.

    Here, I'll do an example to reduce confusion. Lets say I started a pvp server, and every player needs to be saved with their amount of kills they've raked up over the time. I would first create the HashMap of UUIDs and Integers like so:
    Code:java
    1. HashMap<UUID, Integers> kills = new HashMap<>();

    Then, in my join event I would save the players uuid with 0 because they just joined the server and have no kills. So my put method would be put(player.getUniqueId(), 0).

    Side note, in this example you see I used UUIDs, this is the best method since the object is light weight on the ram of the server and doesn't cause memory leaks as damaging. It is important use always try to use UUIDs for your list. Never use the Player object itself.

    Now when I use the get method for that players UUID in the HashMap it will give me that number 0. You can also change the number by just putting the players UUID back in with a different number. Hope that made sense.
     
    Comlud and johnny_boy like this.
Thread Status:
Not open for further replies.

Share This Page