From f8b99d44bf8058755db95f926d8c979da2f0851a Mon Sep 17 00:00:00 2001 From: Torrie Fischer Date: Sat, 28 May 2022 16:05:02 +0200 Subject: [PATCH] Implement in-game sidebars --- TODO.md | 14 ++- .../gg/malloc/defense/engine/BombFuse.java | 14 ++- .../gg/malloc/defense/engine/GameRunner.java | 27 ++++-- .../gg/malloc/defense/engine/GameState.java | 43 +++++++++ .../gg/malloc/defense/engine/MobManager.java | 13 ++- .../malloc/defense/engine/PlayerManager.java | 8 +- .../malloc/defense/engine/StaticProgress.java | 21 +++++ .../gg/malloc/defense/engine/WaveManager.java | 9 +- .../gg/malloc/defense/model/Progress.java | 10 +++ .../java/gg/malloc/defense/model/State.java | 12 +++ .../java/gg/malloc/defense/ui/BossBars.java | 49 ++++------- .../java/gg/malloc/defense/ui/Sidebar.java | 87 +++++++++++++++++++ .../java/gg/malloc/defense/ui/Sidebars.java | 35 ++++++++ 13 files changed, 292 insertions(+), 50 deletions(-) create mode 100644 src/main/java/gg/malloc/defense/engine/GameState.java create mode 100644 src/main/java/gg/malloc/defense/engine/StaticProgress.java create mode 100644 src/main/java/gg/malloc/defense/model/Progress.java create mode 100644 src/main/java/gg/malloc/defense/model/State.java create mode 100644 src/main/java/gg/malloc/defense/ui/Sidebar.java create mode 100644 src/main/java/gg/malloc/defense/ui/Sidebars.java diff --git a/TODO.md b/TODO.md index e749fa8..c800b56 100644 --- a/TODO.md +++ b/TODO.md @@ -20,6 +20,8 @@ [X] Mob AI categories [X] Never hungry [X] Mobs don't drop bomb items +[ ] Execute commands on game/wave end +[ ] Player Respawning # QOL @@ -28,6 +30,11 @@ [ ] "Click here to leave" at end of game [ ] Hidden armor stands [ ] Small/nonexistent prop collision boxes +[ ] Leave game when leaving game world +[ ] Bomb and target glow different colors +[ ] Play sound once bomb is close to / at target +[ ] Expose coins under vault API +[ ] Animations framework # Malloc beta map @@ -52,7 +59,7 @@ [X] Clickable /ready in chat [ ] Post-Round summary in chat [X] Clickable join links in /list -[ ] Sidebar +[X] Sidebar [ ] Coin pickup messages in action bar [ ] Target catches on fire more it is lit [ ] Colored titles @@ -69,7 +76,7 @@ [ ] Plan stats [ ] /invite friends to games [ ] /voterestart -[ ] Medals/awards/scoreboards +[ ] Medals/awards/scoreboards/cosmetics # Mechanics @@ -93,6 +100,9 @@ [ ] Scripted batch overlap/timings [ ] Scripted spawn locations [ ] Scripted waypoint paths +[ ] Execute commands on game/wave end +[ ] Coin reward curve +[ ] Mob number curves with player count [ ] Bosses # Mapping diff --git a/src/main/java/gg/malloc/defense/engine/BombFuse.java b/src/main/java/gg/malloc/defense/engine/BombFuse.java index 7ffbd42..df2ef5b 100644 --- a/src/main/java/gg/malloc/defense/engine/BombFuse.java +++ b/src/main/java/gg/malloc/defense/engine/BombFuse.java @@ -1,10 +1,12 @@ package gg.malloc.defense.engine; -public class BombFuse { +import gg.malloc.defense.model.Progress; + +public class BombFuse implements Progress { int m_bombFuseCount = 0; int m_bombFuseTarget = 10; - public double getProgress() { + public double toDouble() { return Math.max(0.0, Math.min(1.0, (double)m_bombFuseCount / (double)m_bombFuseTarget)); } @@ -27,4 +29,12 @@ public class BombFuse { public void tickDecay() { m_bombFuseCount -= 1; } + + public int value() { + return m_bombFuseCount; + } + + public int maximum() { + return m_bombFuseTarget; + } } diff --git a/src/main/java/gg/malloc/defense/engine/GameRunner.java b/src/main/java/gg/malloc/defense/engine/GameRunner.java index a558680..1b2956e 100644 --- a/src/main/java/gg/malloc/defense/engine/GameRunner.java +++ b/src/main/java/gg/malloc/defense/engine/GameRunner.java @@ -10,9 +10,9 @@ import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.ComponentBuilder; -import gg.malloc.defense.ui.BombCarrier; import gg.malloc.defense.ui.BossBars; import gg.malloc.defense.ui.Items; +import gg.malloc.defense.ui.Sidebars; import gg.malloc.defense.Plugin; @@ -24,7 +24,6 @@ import java.util.Collection; import org.bukkit.Bukkit; import org.bukkit.GameRule; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.Particle; import org.bukkit.Sound; import org.bukkit.SoundCategory; @@ -34,15 +33,13 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityTargetEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; -import org.bukkit.attribute.Attribute; -import org.bukkit.attribute.AttributeModifier; import org.bukkit.inventory.ItemStack; public class GameRunner { + GameState m_state; + Arena m_arena; Game m_game; Stage m_stage; @@ -71,6 +68,7 @@ public class GameRunner { TickTask m_bombCrackleTask; BossBars m_bars; + Sidebars m_sidebars; World m_world; @@ -106,13 +104,19 @@ public class GameRunner { m_waves = new WaveManager(m_game); m_players = new PlayerManager(); m_bombFuse = new BombFuse(); - m_bars = new BossBars(this, m_game, m_waves, m_players, m_bombFuse, m_mobs); + + m_state = new GameState(this, m_waves, m_game, m_mobs, m_bombFuse, m_players); + + m_bars = new BossBars(m_state); + m_sidebars = new Sidebars(m_state, m_plugin.getServer().getScoreboardManager()); + m_log = m_plugin.getLogger(); m_fuseTask = new TickTask(m_plugin, () -> { if (m_bombFuse.isLit()) { m_bombFuse.tickDecay(); m_bars.update(); + m_sidebars.update(); } }, 80); @@ -128,6 +132,7 @@ public class GameRunner { m_warmupCountdown--; m_bars.setCountdownProgress((double)m_warmupCountdown / 10.0); m_bars.update(); + m_sidebars.update(); } }, 20); @@ -147,6 +152,7 @@ public class GameRunner { m_gameEndCountdown--; m_bars.setCountdownProgress((double)m_gameEndCountdown / 60.0); m_bars.update(); + m_sidebars.update(); } }, 20); @@ -159,6 +165,8 @@ public class GameRunner { Location targetLoc = getLocation(m_arena.bombTarget()); m_world.playSound(targetLoc, Sound.BLOCK_CAMPFIRE_CRACKLE, SoundCategory.NEUTRAL, 1.0f, 1.0f); }, 35); + + validateGameRules(); } int m_warmupCountdown = 0; @@ -177,6 +185,7 @@ public class GameRunner { m_bombFuse.tickLit(); m_world.playSound(getLocation(m_arena.bombTarget()), Sound.ENTITY_ZOMBIE_ATTACK_IRON_DOOR, 1.5f, 0.9f); m_bars.update(); + m_sidebars.update(); if (m_bombFuse.isExploded()) { m_world.strikeLightningEffect(getLocation(m_arena.bombTarget())); m_world.playSound(getLocation(m_arena.bombTarget()), Sound.ENTITY_GENERIC_EXPLODE, SoundCategory.NEUTRAL, 1.3f, 1.0f); @@ -269,6 +278,7 @@ public class GameRunner { m_players.setReady(p, isReady); } m_bars.update(); + m_sidebars.update(); if (m_players.isEveryoneReady()) { requestTransition(Stage.Countdown); } @@ -314,6 +324,7 @@ public class GameRunner { Spawner spawner = new GameSpawner(m_world, m_arena, m_mobs); m_waves.currentWave().spawnBatch(spawner, m_waves.currentBatchNum()); m_bars.update(); + m_sidebars.update(); } private void handlePlayerDeath(Player player) { @@ -345,6 +356,7 @@ public class GameRunner { m_world.dropItem(entity.getLocation(), coins); } m_bars.update(); + m_sidebars.update(); if (m_mobs.remainingMobs() <= 3) { m_log.info("Starting next batch!"); if (m_waves.isLastBatch()) { @@ -411,6 +423,7 @@ public class GameRunner { m_log.info("Game transition: " + m_stage + " -> " + stage); m_stage = stage; m_bars.update(); + m_sidebars.update(); for(Player p : m_players.getPlayers()) { sendStageTitle(p); } diff --git a/src/main/java/gg/malloc/defense/engine/GameState.java b/src/main/java/gg/malloc/defense/engine/GameState.java new file mode 100644 index 0000000..44d2108 --- /dev/null +++ b/src/main/java/gg/malloc/defense/engine/GameState.java @@ -0,0 +1,43 @@ +package gg.malloc.defense.engine; + +import gg.malloc.defense.model.Game; +import gg.malloc.defense.model.Progress; +import gg.malloc.defense.model.State; + +public class GameState implements State { + GameRunner m_runner; + WaveManager m_waves; + Game m_game; + MobManager m_mobs; + BombFuse m_fuse; + PlayerManager m_players; + + public GameState(GameRunner runner, WaveManager waves, Game game, MobManager mobs, BombFuse fuse, PlayerManager players) { + m_runner = runner; + m_waves = waves; + m_game = game; + m_mobs = mobs; + m_fuse = fuse; + m_players = players; + } + + public GameRunner.Stage getStage() { + return m_runner.getStage(); + } + + public Progress fuseProgress() { + return m_fuse; + } + + public Progress waveProgress() { + return m_waves.asProgress(); + } + + public Progress mobProgress() { + return m_mobs; + } + + public Progress playerReadyProgress() { + return m_players.readyProgress(); + } +} diff --git a/src/main/java/gg/malloc/defense/engine/MobManager.java b/src/main/java/gg/malloc/defense/engine/MobManager.java index 721794d..cccc7e1 100644 --- a/src/main/java/gg/malloc/defense/engine/MobManager.java +++ b/src/main/java/gg/malloc/defense/engine/MobManager.java @@ -17,11 +17,12 @@ import org.bukkit.event.entity.EntityTargetEvent; import org.bukkit.inventory.EntityEquipment; import gg.malloc.defense.model.Game; +import gg.malloc.defense.model.Progress; import gg.malloc.defense.ui.BombCarrier; import gg.malloc.defense.ui.Items; -public class MobManager { +public class MobManager implements Progress { LivingEntity m_bombTarget; HashSet m_livingMobs = new HashSet<>(); HashSet m_bombCarriers = new HashSet<>(); @@ -33,6 +34,16 @@ public class MobManager { PlayerHarassment } + @Override + public int value() { + return m_killedMobs; + } + + @Override + public int maximum() { + return m_createdMobs; + } + int m_createdMobs = 0; int m_killedMobs = 0; diff --git a/src/main/java/gg/malloc/defense/engine/PlayerManager.java b/src/main/java/gg/malloc/defense/engine/PlayerManager.java index 1491354..f58404c 100644 --- a/src/main/java/gg/malloc/defense/engine/PlayerManager.java +++ b/src/main/java/gg/malloc/defense/engine/PlayerManager.java @@ -5,6 +5,10 @@ import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.attribute.Attribute; import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.scoreboard.ScoreboardManager; + +import gg.malloc.defense.ui.Sidebar; +import gg.malloc.defense.model.Progress; import java.util.HashMap; import java.util.Collection; @@ -90,14 +94,14 @@ public class PlayerManager { m_playerReadyStates.put(player, ready); } - public double readyProgress() { + public Progress readyProgress() { int readyNum = 0; for(boolean b : m_playerReadyStates.values()) { if (b) { readyNum += 1; } } - return (double)readyNum / (double)m_playerReadyStates.size(); + return new StaticProgress(readyNum, m_playerReadyStates.size()); } public boolean isEveryoneReady() { diff --git a/src/main/java/gg/malloc/defense/engine/StaticProgress.java b/src/main/java/gg/malloc/defense/engine/StaticProgress.java new file mode 100644 index 0000000..5af58f9 --- /dev/null +++ b/src/main/java/gg/malloc/defense/engine/StaticProgress.java @@ -0,0 +1,21 @@ +package gg.malloc.defense.engine; + +import gg.malloc.defense.model.Progress; + +public class StaticProgress implements Progress { + int m_value; + int m_maximum; + + public StaticProgress(int value, int maximum) { + m_value = value; + m_maximum = maximum; + } + + public int value() { + return m_value; + } + + public int maximum() { + return m_maximum; + } +} diff --git a/src/main/java/gg/malloc/defense/engine/WaveManager.java b/src/main/java/gg/malloc/defense/engine/WaveManager.java index 78d32a0..6e6c57c 100644 --- a/src/main/java/gg/malloc/defense/engine/WaveManager.java +++ b/src/main/java/gg/malloc/defense/engine/WaveManager.java @@ -2,6 +2,7 @@ package gg.malloc.defense.engine; import gg.malloc.defense.model.Wave; import gg.malloc.defense.model.Game; +import gg.malloc.defense.model.Progress; public class WaveManager { int m_currentWaveNum = 0; @@ -9,6 +10,10 @@ public class WaveManager { Wave m_currentWave = null; Game m_game; + public Progress asProgress() { + return new StaticProgress(m_currentWaveNum, m_game.getWaveCount()); + } + public WaveManager(Game game) { m_game = game; } @@ -31,10 +36,6 @@ public class WaveManager { return m_currentBatch; } - public double progress() { - return (double)m_currentWaveNum / (double)m_game.getWaveCount(); - } - public boolean isLastWave() { return m_currentWaveNum >= m_game.getWaveCount(); } diff --git a/src/main/java/gg/malloc/defense/model/Progress.java b/src/main/java/gg/malloc/defense/model/Progress.java new file mode 100644 index 0000000..1879621 --- /dev/null +++ b/src/main/java/gg/malloc/defense/model/Progress.java @@ -0,0 +1,10 @@ +package gg.malloc.defense.model; + +public interface Progress { + + int value(); + int maximum(); + default double toDouble() { + return Math.min(maximum(), Math.max(0.0, value())) / maximum(); + } +} diff --git a/src/main/java/gg/malloc/defense/model/State.java b/src/main/java/gg/malloc/defense/model/State.java new file mode 100644 index 0000000..648196a --- /dev/null +++ b/src/main/java/gg/malloc/defense/model/State.java @@ -0,0 +1,12 @@ +package gg.malloc.defense.model; + +import gg.malloc.defense.engine.GameRunner; + +public interface State { + GameRunner.Stage getStage(); + + Progress fuseProgress(); + Progress waveProgress(); + Progress mobProgress(); + Progress playerReadyProgress(); +} diff --git a/src/main/java/gg/malloc/defense/ui/BossBars.java b/src/main/java/gg/malloc/defense/ui/BossBars.java index 1306009..cacba7e 100644 --- a/src/main/java/gg/malloc/defense/ui/BossBars.java +++ b/src/main/java/gg/malloc/defense/ui/BossBars.java @@ -1,12 +1,7 @@ package gg.malloc.defense.ui; -import gg.malloc.defense.engine.GameRunner; -import gg.malloc.defense.engine.WaveManager; -import gg.malloc.defense.engine.PlayerManager; -import gg.malloc.defense.engine.MobManager; -import gg.malloc.defense.engine.BombFuse; - import gg.malloc.defense.model.Game; +import gg.malloc.defense.model.State; import org.bukkit.boss.BossBar; import org.bukkit.boss.BarStyle; @@ -19,12 +14,7 @@ public class BossBars { BossBar m_waveBar = Bukkit.createBossBar("Malloc Defense", BarColor.PURPLE, BarStyle.SOLID); BossBar m_bombBar = Bukkit.createBossBar("Bomb Fuse", BarColor.RED, BarStyle.SOLID); - GameRunner m_runner; - MobManager m_mobs; - WaveManager m_waves; - PlayerManager m_players; - BombFuse m_fuse; - Game m_game; + State m_gameState; double m_countdownProgress; @@ -32,13 +22,8 @@ public class BossBars { m_countdownProgress = v; } - public BossBars(GameRunner runner, Game game, WaveManager waves, PlayerManager players, BombFuse fuse, MobManager mobs) { - m_runner = runner; - m_game = game; - m_waves = waves; - m_players = players; - m_fuse = fuse; - m_mobs = mobs; + public BossBars(State gameState) { + m_gameState = gameState; m_gameBar.setVisible(true); m_waveBar.setVisible(false); m_bombBar.setVisible(false); @@ -57,7 +42,7 @@ public class BossBars { } public void update() { - switch(m_runner.getStage()) { + switch(m_gameState.getStage()) { case Idle: m_gameBar.setProgress(1.0); m_gameBar.setTitle("Waiting for players..."); @@ -66,18 +51,18 @@ public class BossBars { m_bombBar.setVisible(false); break; case Warmup: - m_gameBar.setProgress(m_waves.progress()); - m_gameBar.setTitle("Wave " + m_waves.currentWaveNum() + " / " + m_game.getWaveCount()); + m_gameBar.setProgress(m_gameState.waveProgress().toDouble()); + m_gameBar.setTitle("Wave " + m_gameState.waveProgress().value() + " / " + m_gameState.waveProgress().maximum()); m_gameBar.setColor(BarColor.PURPLE); m_waveBar.setVisible(true); m_waveBar.setColor(BarColor.BLUE); m_waveBar.setTitle("Warmup - Waiting for players to get ready..."); - m_waveBar.setProgress(m_players.readyProgress()); + m_waveBar.setProgress(m_gameState.playerReadyProgress().toDouble()); m_bombBar.setVisible(false); break; case Countdown: - m_gameBar.setProgress(m_waves.progress()); - m_gameBar.setTitle("Wave " + m_waves.currentWaveNum() + " / " + m_game.getWaveCount()); + m_gameBar.setProgress(m_gameState.waveProgress().toDouble()); + m_gameBar.setTitle("Wave " + m_gameState.waveProgress().value() + " / " + m_gameState.waveProgress().maximum()); m_gameBar.setColor(BarColor.PURPLE); m_waveBar.setVisible(true); m_waveBar.setColor(BarColor.YELLOW); @@ -86,20 +71,20 @@ public class BossBars { m_bombBar.setVisible(false); break; case Playing: - m_gameBar.setProgress(m_waves.progress()); - m_gameBar.setTitle("Wave " + m_waves.currentWaveNum() + " / " + m_game.getWaveCount()); + m_gameBar.setProgress(m_gameState.waveProgress().toDouble()); + m_gameBar.setTitle("Wave " + m_gameState.waveProgress().value() + " / " + m_gameState.waveProgress().maximum()); m_gameBar.setColor(BarColor.PURPLE); - if (m_mobs.createdMobs() > 0) { + if (m_gameState.mobProgress().maximum() > 0) { m_waveBar.setVisible(true); m_waveBar.setColor(BarColor.GREEN); - m_waveBar.setTitle("Mobs remaining: " + m_mobs.remainingMobs()); - m_waveBar.setProgress(m_mobs.progress()); + m_waveBar.setTitle("Mobs remaining: " + (m_gameState.mobProgress().maximum() - m_gameState.mobProgress().value())); + m_waveBar.setProgress(m_gameState.mobProgress().toDouble()); } else { m_waveBar.setVisible(false); } - if (m_fuse.isLit()) { + if (m_gameState.fuseProgress().value() > 0) { m_bombBar.setVisible(true); - m_bombBar.setProgress(1.0 - m_fuse.getProgress()); + m_bombBar.setProgress(1.0 - m_gameState.fuseProgress().toDouble()); } else { m_bombBar.setVisible(false); } diff --git a/src/main/java/gg/malloc/defense/ui/Sidebar.java b/src/main/java/gg/malloc/defense/ui/Sidebar.java new file mode 100644 index 0000000..cae37a9 --- /dev/null +++ b/src/main/java/gg/malloc/defense/ui/Sidebar.java @@ -0,0 +1,87 @@ +package gg.malloc.defense.ui; + +import java.util.Collection; +import java.util.ArrayList; +import java.util.HashMap; + +import gg.malloc.defense.model.State; + +import org.bukkit.ChatColor; +import org.bukkit.scoreboard.Scoreboard; +import org.bukkit.scoreboard.DisplaySlot; +import org.bukkit.scoreboard.Score; +import org.bukkit.scoreboard.Team; +import org.bukkit.scoreboard.Objective; + +public class Sidebar { + Scoreboard m_scoreboard; + Objective m_objective; + ArrayList m_rowKeys; + HashMap m_rows; + ArrayList m_teams; + int m_size; + + State m_state; + + public Sidebar(State state, Scoreboard scoreboard) { + m_state = state; + m_scoreboard = scoreboard; + m_objective = m_scoreboard.registerNewObjective("text", "dummy", ChatColor.LIGHT_PURPLE + "" + ChatColor.BOLD + "Malloc Defense"); + m_objective.setDisplaySlot(DisplaySlot.SIDEBAR); + m_rowKeys = new ArrayList<>(); + m_rows = new HashMap<>(); + m_teams = new ArrayList<>(); + m_rowKeys.add(ChatColor.BLACK + "" + ChatColor.WHITE); + m_rowKeys.add(ChatColor.GOLD+ "" + ChatColor.WHITE); + m_rowKeys.add(ChatColor.WHITE+ "" + ChatColor.WHITE); + for(String key : m_rowKeys) { + Team team = m_scoreboard.registerNewTeam(key); + team.addEntry(key); + m_teams.add(team); + } + } + + public void update() { + switch(m_state.getStage()) { + case Idle: + m_rows.put(0, ChatColor.LIGHT_PURPLE + "Waiting for players..."); + m_size = 1; + break; + case Warmup: + m_rows.put(0, ChatColor.LIGHT_PURPLE + "Wave " + m_state.waveProgress().value() + " / " + m_state.waveProgress().maximum()); + m_rows.put(1, ChatColor.AQUA + "Get ready!"); + m_rows.put(2, ChatColor.AQUA + "Balance: "); + m_size = 3; + break; + case Countdown: + m_rows.put(0, ChatColor.LIGHT_PURPLE + "Wave " + m_state.waveProgress().value() + " / " + m_state.waveProgress().maximum()); + m_rows.put(1, ChatColor.GOLD + "Wave incoming!"); + m_rows.put(2, ChatColor.AQUA + "Balance: "); + m_size = 3; + break; + case Playing: + m_rows.put(0, ChatColor.LIGHT_PURPLE + "Wave " + m_state.waveProgress().value() + " / " + m_state.waveProgress().maximum()); + m_rows.put(1, ChatColor.GREEN + "Mobs remaining: " + (m_state.mobProgress().maximum() - m_state.mobProgress().value())); + m_rows.put(2, ChatColor.AQUA + "Balance: "); + m_size = 3; + break; + case GameOver: + m_rows.put(0, ChatColor.RED + "Game over!"); + m_size = 1; + } + + for(int i = 0; i < Math.min(m_size, m_rowKeys.size()); i++) { + Score rowScore = m_objective.getScore(m_rowKeys.get(i)); + rowScore.setScore(m_rowKeys.size() - i); + if (m_rows.containsKey(i)) { + m_teams.get(i).setPrefix(m_rows.get(i)); + } else { + m_teams.get(i).setPrefix(""); + } + } + } + + public Scoreboard getScoreboard() { + return m_scoreboard; + } +} diff --git a/src/main/java/gg/malloc/defense/ui/Sidebars.java b/src/main/java/gg/malloc/defense/ui/Sidebars.java new file mode 100644 index 0000000..524bfca --- /dev/null +++ b/src/main/java/gg/malloc/defense/ui/Sidebars.java @@ -0,0 +1,35 @@ +package gg.malloc.defense.ui; + +import org.bukkit.entity.Player; +import org.bukkit.scoreboard.ScoreboardManager; + +import java.util.HashMap; + +import gg.malloc.defense.model.State; + +public class Sidebars { + State m_state; + ScoreboardManager m_scoreboards; + HashMap m_sidebars = new HashMap<>(); + + public Sidebars(State state, ScoreboardManager scoreboards) { + m_state = state; + m_scoreboards = scoreboards; + } + + public void addPlayer(Player player) { + m_sidebars.put(player, new Sidebar(m_state, m_scoreboards.getNewScoreboard())); + player.setScoreboard(m_sidebars.get(player).getScoreboard()); + } + + public void removePlayer(Player player) { + m_sidebars.remove(player); + player.setScoreboard(m_scoreboards.getMainScoreboard()); + } + + public void update() { + for(Player p : m_sidebars.keySet()) { + m_sidebars.get(p).update(); + } + } +}