reorganize engine bits into engine package, same with commands, reimplement player state as FSM
This commit is contained in:
		| @@ -1,5 +1,7 @@ | |||||||
| package gg.malloc.defense; | package gg.malloc.defense; | ||||||
|  |  | ||||||
|  | import gg.malloc.defense.engine.GameRunner; | ||||||
|  |  | ||||||
| import org.bukkit.event.EventHandler; | import org.bukkit.event.EventHandler; | ||||||
| import org.bukkit.event.Listener; | import org.bukkit.event.Listener; | ||||||
| import org.bukkit.event.entity.EntityDeathEvent; | import org.bukkit.event.entity.EntityDeathEvent; | ||||||
|   | |||||||
| @@ -1,381 +0,0 @@ | |||||||
| package gg.malloc.defense; |  | ||||||
|  |  | ||||||
| import gg.malloc.defense.model.Game; |  | ||||||
| import gg.malloc.defense.model.Arena; |  | ||||||
| import gg.malloc.defense.model.Spawnpoint; |  | ||||||
| import gg.malloc.defense.model.Spawner; |  | ||||||
| import gg.malloc.defense.model.Wave; |  | ||||||
|  |  | ||||||
| import java.util.ArrayList; |  | ||||||
| import java.util.HashSet; |  | ||||||
| import java.util.logging.Logger; |  | ||||||
|  |  | ||||||
| import org.bukkit.Bukkit; |  | ||||||
| import org.bukkit.World; |  | ||||||
| import org.bukkit.GameMode; |  | ||||||
| import org.bukkit.attribute.Attribute; |  | ||||||
| import org.bukkit.boss.BarColor; |  | ||||||
| import org.bukkit.boss.BarStyle; |  | ||||||
| import org.bukkit.boss.BossBar; |  | ||||||
| import org.bukkit.event.player.PlayerTeleportEvent; |  | ||||||
| import org.bukkit.event.entity.EntityDamageEvent; |  | ||||||
| import org.bukkit.entity.Entity; |  | ||||||
| import org.bukkit.entity.LivingEntity; |  | ||||||
| import org.bukkit.entity.EntityType; |  | ||||||
| import org.bukkit.entity.Player; |  | ||||||
| import org.bukkit.scheduler.BukkitTask; |  | ||||||
|  |  | ||||||
| public class GameRunner { |  | ||||||
|   HashSet<Entity> m_livingMobs = new HashSet<>(); |  | ||||||
|   int m_createdMobs = 0; |  | ||||||
|   int m_killedMobs = 0; |  | ||||||
|   Arena m_arena; |  | ||||||
|   Game m_game; |  | ||||||
|   State m_state; |  | ||||||
|   HashSet<Player> m_players = new HashSet<>(); |  | ||||||
|   HashSet<Player> m_livingPlayers = new HashSet<>(); |  | ||||||
|   Plugin m_plugin; |  | ||||||
|  |  | ||||||
|   BossBar m_gameBar = Bukkit.createBossBar("Malloc Defense", BarColor.PURPLE, BarStyle.SOLID); |  | ||||||
|   BossBar m_waveBar = Bukkit.createBossBar("Malloc Defense", BarColor.PURPLE, BarStyle.SOLID); |  | ||||||
|   BukkitTask m_countdownTask; |  | ||||||
|  |  | ||||||
|   int m_currentWaveNum = 0; |  | ||||||
|   int m_currentBatch = 0; |  | ||||||
|   Wave m_currentWave = null; |  | ||||||
|  |  | ||||||
|   Logger m_log; |  | ||||||
|  |  | ||||||
|   enum State { |  | ||||||
|     Idle, |  | ||||||
|     Warmup, |  | ||||||
|     Playing, |  | ||||||
|     GameOver |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   public GameRunner(Plugin plugin, Game game, Arena arena) { |  | ||||||
|     m_plugin = plugin; |  | ||||||
|     m_game = game; |  | ||||||
|     m_arena = arena; |  | ||||||
|     m_state = State.Idle; |  | ||||||
|     m_gameBar.setVisible(true); |  | ||||||
|     m_waveBar.setVisible(false); |  | ||||||
|     m_log = m_plugin.getLogger(); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   int m_warmupCountdown = 0; |  | ||||||
|  |  | ||||||
|   public void handleEntityDamage(EntityDamageEvent evt) { |  | ||||||
|     Entity entity = evt.getEntity(); |  | ||||||
|     m_log.info("Damage " + entity); |  | ||||||
|     m_log.info("Living Mobs " + m_livingMobs); |  | ||||||
|     if (m_livingMobs.contains(entity)) { |  | ||||||
|       m_game.onMobDamaged(entity); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   private void countdownTick() { |  | ||||||
|     if (m_warmupCountdown == 0) { |  | ||||||
|       requestTransition(State.Playing); |  | ||||||
|     } else { |  | ||||||
|       updateMobBars(); |  | ||||||
|       broadcastMessage("Starting game in " + m_warmupCountdown); |  | ||||||
|       m_warmupCountdown--; |  | ||||||
|       m_countdownTask = m_plugin.getServer().getScheduler().runTaskLater(m_plugin, () -> { |  | ||||||
|         countdownTick(); |  | ||||||
|       }, 20); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   private void clearMobs() { |  | ||||||
|     for(Entity e : m_livingMobs) { |  | ||||||
|       e.remove(); |  | ||||||
|     } |  | ||||||
|     m_livingMobs.clear(); |  | ||||||
|     m_createdMobs = 0; |  | ||||||
|     m_killedMobs = 0; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   private boolean enterIdle() { |  | ||||||
|     broadcastMessage("Game state: Idle"); |  | ||||||
|     m_currentWaveNum = 0; |  | ||||||
|     m_livingPlayers.clear(); |  | ||||||
|     for(Player p : m_players) { |  | ||||||
|       m_livingPlayers.add(p); |  | ||||||
|     } |  | ||||||
|     if (m_countdownTask != null) { |  | ||||||
|       m_countdownTask.cancel(); |  | ||||||
|       m_countdownTask = null; |  | ||||||
|     } |  | ||||||
|     clearMobs(); |  | ||||||
|     return true; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   private boolean enterWarmup() { |  | ||||||
|     m_log.info("Game state: Warmup"); |  | ||||||
|     m_currentWaveNum += 1; |  | ||||||
|     m_currentWave = m_game.getWave(m_currentWaveNum); |  | ||||||
|     m_warmupCountdown = 10; |  | ||||||
|     for(Player p : m_players) { |  | ||||||
|       m_livingPlayers.add(p); |  | ||||||
|     } |  | ||||||
|     broadcastTitle("Warmup", "Prepare yourself for wave " + m_currentWaveNum); |  | ||||||
|     clearMobs(); |  | ||||||
|     countdownTick(); |  | ||||||
|     return true; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   private boolean enterPlaying() { |  | ||||||
|     m_log.info("Game state: Playing"); |  | ||||||
|     m_log.info("Starting wave " + m_currentWaveNum); |  | ||||||
|     m_currentBatch = 1; |  | ||||||
|     spawnNextBatch(); |  | ||||||
|     broadcastTitle("Wave " + m_currentWaveNum); |  | ||||||
|     return true; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   private boolean enterGameOver() { |  | ||||||
|     broadcastTitle("Game Over!"); |  | ||||||
|     if (m_countdownTask != null) { |  | ||||||
|       m_countdownTask.cancel(); |  | ||||||
|       m_countdownTask = null; |  | ||||||
|     } |  | ||||||
|     clearMobs(); |  | ||||||
|     for(Player p : m_players) { |  | ||||||
|       removePlayer(p); |  | ||||||
|     } |  | ||||||
|     return true; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   private void updateMobBars() { |  | ||||||
|     m_gameBar.setVisible(true); |  | ||||||
|     switch(m_state) { |  | ||||||
|       case Idle: |  | ||||||
|         m_gameBar.setProgress(1.0); |  | ||||||
|         m_gameBar.setTitle("Waiting for playres..."); |  | ||||||
|         m_gameBar.setColor(BarColor.PURPLE); |  | ||||||
|         m_waveBar.setVisible(false); |  | ||||||
|         break; |  | ||||||
|       case Warmup: |  | ||||||
|         m_gameBar.setProgress((double)m_currentWaveNum / (double)m_game.getWaveCount()); |  | ||||||
|         m_gameBar.setTitle("Wave " + m_currentWaveNum + " / " + m_game.getWaveCount()); |  | ||||||
|         m_gameBar.setColor(BarColor.PURPLE); |  | ||||||
|         m_waveBar.setVisible(true); |  | ||||||
|         m_waveBar.setColor(BarColor.YELLOW); |  | ||||||
|         m_waveBar.setTitle("Warmup"); |  | ||||||
|         m_waveBar.setProgress((double)m_warmupCountdown / (double)10); |  | ||||||
|         break; |  | ||||||
|       case Playing: |  | ||||||
|         m_gameBar.setProgress((double)m_currentWaveNum / (double)m_game.getWaveCount()); |  | ||||||
|         m_gameBar.setTitle("Wave " + m_currentWaveNum + " / " + m_game.getWaveCount()); |  | ||||||
|         m_gameBar.setColor(BarColor.PURPLE); |  | ||||||
|         if (m_createdMobs > 0) { |  | ||||||
|           m_waveBar.setVisible(true); |  | ||||||
|           m_waveBar.setColor(BarColor.GREEN); |  | ||||||
|           m_waveBar.setTitle("Mobs remaining: " + (m_createdMobs - m_killedMobs)); |  | ||||||
|           m_waveBar.setProgress((double)m_killedMobs / (double)m_createdMobs); |  | ||||||
|         } else { |  | ||||||
|           m_waveBar.setVisible(false); |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|       case GameOver: |  | ||||||
|         m_gameBar.setColor(BarColor.RED); |  | ||||||
|         m_gameBar.setProgress(1.0); |  | ||||||
|         m_gameBar.setTitle("Game Over!"); |  | ||||||
|         m_waveBar.setVisible(false); |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   private void spawnNextBatch() { |  | ||||||
|     broadcastMessage("Spawning batch " + m_currentBatch); |  | ||||||
|     Spawner spawner = new GameSpawner(m_arena.spawnpoints()); |  | ||||||
|     m_currentWave.spawnBatch(spawner, m_currentBatch); |  | ||||||
|     updateMobBars(); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   public void handlePlayerDeath(Player player) { |  | ||||||
|     if (m_livingPlayers.contains(player)) { |  | ||||||
|       m_log.info("Player has died in game" + player); |  | ||||||
|       m_livingPlayers.remove(player); |  | ||||||
|       m_arena.getWorld().strikeLightningEffect(player.getLocation()); |  | ||||||
|       player.setGameMode(GameMode.SPECTATOR); |  | ||||||
|       if (m_livingPlayers.size() == 0) { |  | ||||||
|         broadcastMessage("Everyone is dead :("); |  | ||||||
|         requestTransition(State.GameOver); |  | ||||||
|       } else { |  | ||||||
|         m_log.info("Remaining players " + m_livingPlayers.size()); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   public void handleEntityDeath(Entity entity) { |  | ||||||
|     if (m_livingMobs.contains(entity)) { |  | ||||||
|       broadcastMessage("Killed game entity " + entity); |  | ||||||
|       m_livingMobs.remove(entity); |  | ||||||
|       m_killedMobs += 1; |  | ||||||
|       updateMobBars(); |  | ||||||
|       if (m_livingMobs.size() <= 3) { |  | ||||||
|         m_log.info("Starting next batch!"); |  | ||||||
|         if (m_currentBatch >= m_currentWave.batchCount()) { |  | ||||||
|           if (m_currentWaveNum >= m_game.getWaveCount()) { |  | ||||||
|             requestTransition(State.GameOver); |  | ||||||
|           } else if (m_livingMobs.size() == 0) { |  | ||||||
|             requestTransition(State.Warmup); |  | ||||||
|           } |  | ||||||
|         } else { |  | ||||||
|           m_currentBatch += 1; |  | ||||||
|           spawnNextBatch(); |  | ||||||
|         } |  | ||||||
|       } else { |  | ||||||
|         m_log.fine("Living mobs remaining: " + m_livingMobs.size()); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   private boolean syncPlayer(Player player) { |  | ||||||
|     m_log.fine("Synchronizing player " + player); |  | ||||||
|     World playerWorld = player.getLocation().getWorld(); |  | ||||||
|     World gameWorld = m_arena.getWorld(); |  | ||||||
|     m_gameBar.addPlayer(player); |  | ||||||
|     m_waveBar.addPlayer(player); |  | ||||||
|     if (m_livingPlayers.contains(player)) { |  | ||||||
|       m_log.fine("Player is alive, turning into adventure mode " + player); |  | ||||||
|       if (player.getGameMode() != Bukkit.getDefaultGameMode()) { |  | ||||||
|         player.setGameMode(Bukkit.getDefaultGameMode()); |  | ||||||
|         player.teleport(gameWorld.getSpawnLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN); |  | ||||||
|       } |  | ||||||
|       player.setHealth(player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()); |  | ||||||
|       player.setFoodLevel(10); |  | ||||||
|     } else { |  | ||||||
|       m_log.fine("Player is dead, turning into spectator " + player); |  | ||||||
|       player.setGameMode(GameMode.SPECTATOR); |  | ||||||
|     } |  | ||||||
|     if (playerWorld != gameWorld) { |  | ||||||
|       m_log.info("Teleporting player " + player); |  | ||||||
|       return player.teleport(gameWorld.getSpawnLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN); |  | ||||||
|     } else { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   private boolean attemptTransition(State state) { |  | ||||||
|     if (m_state == state) { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
|     switch(state) { |  | ||||||
|       case Idle: |  | ||||||
|         return enterIdle(); |  | ||||||
|       case Warmup: |  | ||||||
|         return enterWarmup(); |  | ||||||
|       case Playing: |  | ||||||
|         return enterPlaying(); |  | ||||||
|       case GameOver: |  | ||||||
|         return enterGameOver(); |  | ||||||
|     } |  | ||||||
|     return false; |  | ||||||
|   } |  | ||||||
|    |  | ||||||
|   private boolean validateTransition(State from, State to) { |  | ||||||
|     switch(from) { |  | ||||||
|       case Idle: |  | ||||||
|         return to == State.Warmup; |  | ||||||
|       case Warmup: |  | ||||||
|         return to == State.Playing || to == State.Idle || to == State.GameOver; |  | ||||||
|       case Playing: |  | ||||||
|         return to == State.Warmup || to == State.GameOver || to == State.Idle; |  | ||||||
|       case GameOver: |  | ||||||
|         return to == State.Idle; |  | ||||||
|     } |  | ||||||
|     return false; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   public boolean requestTransition(State state) { |  | ||||||
|     if (!validateTransition(m_state, state)) { |  | ||||||
|       m_log.warning("Attemped illegal transition: " + m_state + " -> " + state); |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
|     if (attemptTransition(state)) { |  | ||||||
|       updateMobBars(); |  | ||||||
|       m_log.info("Game transition: " + m_state + " -> " + state); |  | ||||||
|       m_state = state; |  | ||||||
|       for(Player p : m_players) { |  | ||||||
|         syncPlayer(p); |  | ||||||
|       } |  | ||||||
|       return true; |  | ||||||
|     } |  | ||||||
|     m_log.severe("Failed to complete transition: " + m_state + " -> " + state); |  | ||||||
|     return false; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   public boolean addPlayer(Player p) { |  | ||||||
|     if (m_state == State.Idle || m_state == State.Warmup) { |  | ||||||
|       m_log.info("Adding player " + p); |  | ||||||
|       m_players.add(p); |  | ||||||
|       broadcastMessage(p.getName() + " has joined the game"); |  | ||||||
|       syncPlayer(p); |  | ||||||
|       if (m_state == State.Idle) { |  | ||||||
|         requestTransition(State.Warmup); |  | ||||||
|       } |  | ||||||
|       return true; |  | ||||||
|     } else { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   public void removePlayer(Player p) { |  | ||||||
|     m_log.info("Removing player " + p);  |  | ||||||
|     m_gameBar.removePlayer(p); |  | ||||||
|     m_waveBar.removePlayer(p); |  | ||||||
|     m_players.remove(p); |  | ||||||
|     m_livingPlayers.remove(p); |  | ||||||
|     p.setGameMode(Bukkit.getDefaultGameMode()); |  | ||||||
|     if (m_players.size() == 0) { |  | ||||||
|       requestTransition(State.Idle); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   void broadcastTitle(String title) { |  | ||||||
|     broadcastTitle(title, ""); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   void broadcastTitle(String title, String subtitle) { |  | ||||||
|     for(Player p : m_players) { |  | ||||||
|       p.sendTitle(title, subtitle, 10, 70, 20); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   void broadcastMessage(String string) { |  | ||||||
|     World world = m_arena.getWorld(); |  | ||||||
|     for(Player p : world.getPlayers()) { |  | ||||||
|       p.sendMessage(string); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   void registerSpawnedMob(Entity entity) { |  | ||||||
|     m_log.fine("Registered new mob " + entity);  |  | ||||||
|     m_livingMobs.add(entity); |  | ||||||
|     m_createdMobs += 1; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   private class GameSpawner implements Spawner { |  | ||||||
|     Spawnpoint[] m_spawnpoints; |  | ||||||
|     int m_spawnIdx = 0; |  | ||||||
|   |  | ||||||
|     public GameSpawner(Spawnpoint[] spawnpoints) { |  | ||||||
|       m_spawnpoints = spawnpoints; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @Override |  | ||||||
|     public Entity spawnMob(EntityType type) { |  | ||||||
|       m_log.fine("Spawning " + type + " at " + m_spawnpoints[m_spawnIdx]); |  | ||||||
|       Entity newMob = m_arena.getWorld().spawnEntity(m_spawnpoints[m_spawnIdx].getLocation(), type); |  | ||||||
|       LivingEntity livingMob = (LivingEntity)newMob; |  | ||||||
|       livingMob.setRemoveWhenFarAway(false); |  | ||||||
|       registerSpawnedMob(newMob); |  | ||||||
|       m_spawnIdx += 1; |  | ||||||
|       m_spawnIdx %= m_spawnpoints.length; |  | ||||||
|       return newMob; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @@ -20,6 +20,11 @@ import gg.malloc.defense.model.Game; | |||||||
| import gg.malloc.defense.games.LinearGame; | import gg.malloc.defense.games.LinearGame; | ||||||
| import gg.malloc.defense.games.ScaledWaves; | import gg.malloc.defense.games.ScaledWaves; | ||||||
|  |  | ||||||
|  | import gg.malloc.defense.engine.GameRunner; | ||||||
|  |  | ||||||
|  | import gg.malloc.defense.commands.AddPlayerCommand; | ||||||
|  | import gg.malloc.defense.commands.SetStageCommand; | ||||||
|  |  | ||||||
| public class Plugin extends JavaPlugin { | public class Plugin extends JavaPlugin { | ||||||
|   ArrayList<Arena> m_arenas = new ArrayList<>(); |   ArrayList<Arena> m_arenas = new ArrayList<>(); | ||||||
|   ArrayList<Game> m_games = new ArrayList<>(); |   ArrayList<Game> m_games = new ArrayList<>(); | ||||||
| @@ -58,7 +63,7 @@ public class Plugin extends JavaPlugin { | |||||||
|     getLogger().setLevel(Level.FINEST); |     getLogger().setLevel(Level.FINEST); | ||||||
|     setupDemoGame(); |     setupDemoGame(); | ||||||
|     getCommand("setstage").setExecutor(new SetStageCommand(this)); |     getCommand("setstage").setExecutor(new SetStageCommand(this)); | ||||||
|     getCommand("initgame").setExecutor(new InitGameCommand(this)); |     getCommand("addplayer").setExecutor(new AddPlayerCommand(this)); | ||||||
|     getCommand("debuginfo").setExecutor(new DebuginfoCommand(this)); |     getCommand("debuginfo").setExecutor(new DebuginfoCommand(this)); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,14 +1,18 @@ | |||||||
| package gg.malloc.defense; | package gg.malloc.defense.commands; | ||||||
| 
 | 
 | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
| import org.bukkit.command.CommandExecutor; | import org.bukkit.command.CommandExecutor; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
| import org.bukkit.entity.Player; | import org.bukkit.entity.Player; | ||||||
| 
 | 
 | ||||||
| public class InitGameCommand implements CommandExecutor { | import gg.malloc.defense.engine.GameRunner; | ||||||
|  | 
 | ||||||
|  | import gg.malloc.defense.Plugin; | ||||||
|  | 
 | ||||||
|  | public class AddPlayerCommand implements CommandExecutor { | ||||||
|   Plugin m_plugin; |   Plugin m_plugin; | ||||||
| 
 | 
 | ||||||
|   public InitGameCommand(Plugin plugin) { |   public AddPlayerCommand(Plugin plugin) { | ||||||
|     m_plugin = plugin; |     m_plugin = plugin; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @@ -1,10 +1,14 @@ | |||||||
| package gg.malloc.defense; | package gg.malloc.defense.commands; | ||||||
| 
 | 
 | ||||||
| import org.bukkit.command.Command; | import org.bukkit.command.Command; | ||||||
| import org.bukkit.command.CommandExecutor; | import org.bukkit.command.CommandExecutor; | ||||||
| import org.bukkit.command.CommandSender; | import org.bukkit.command.CommandSender; | ||||||
| import org.bukkit.World; | import org.bukkit.World; | ||||||
| 
 | 
 | ||||||
|  | import gg.malloc.defense.engine.GameRunner; | ||||||
|  | 
 | ||||||
|  | import gg.malloc.defense.Plugin; | ||||||
|  | 
 | ||||||
| public class SetStageCommand implements CommandExecutor { | public class SetStageCommand implements CommandExecutor { | ||||||
|   Plugin m_plugin; |   Plugin m_plugin; | ||||||
| 
 | 
 | ||||||
| @@ -19,13 +23,13 @@ public class SetStageCommand implements CommandExecutor { | |||||||
|     String stateName = args[0].toLowerCase(); |     String stateName = args[0].toLowerCase(); | ||||||
|     boolean ret = false; |     boolean ret = false; | ||||||
|     if (stateName.equals("idle")) { |     if (stateName.equals("idle")) { | ||||||
|       ret = runner.requestTransition(GameRunner.State.Idle); |       ret = runner.requestTransition(GameRunner.Stage.Idle); | ||||||
|     } else if (stateName.equals("warmup")) { |     } else if (stateName.equals("warmup")) { | ||||||
|       ret = runner.requestTransition(GameRunner.State.Warmup); |       ret = runner.requestTransition(GameRunner.Stage.Warmup); | ||||||
|     } else if (stateName.equals("playing")) { |     } else if (stateName.equals("playing")) { | ||||||
|       ret = runner.requestTransition(GameRunner.State.Playing); |       ret = runner.requestTransition(GameRunner.Stage.Playing); | ||||||
|     } else if (stateName.equals("gameover")) { |     } else if (stateName.equals("gameover")) { | ||||||
|       ret = runner.requestTransition(GameRunner.State.GameOver); |       ret = runner.requestTransition(GameRunner.Stage.GameOver); | ||||||
|     } else { |     } else { | ||||||
|       sender.sendMessage("Unknown state " + stateName); |       sender.sendMessage("Unknown state " + stateName); | ||||||
|       return false; |       return false; | ||||||
							
								
								
									
										350
									
								
								src/main/java/gg/malloc/defense/engine/GameRunner.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										350
									
								
								src/main/java/gg/malloc/defense/engine/GameRunner.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,350 @@ | |||||||
|  | package gg.malloc.defense.engine; | ||||||
|  |  | ||||||
|  | import gg.malloc.defense.model.Game; | ||||||
|  | import gg.malloc.defense.model.Arena; | ||||||
|  | import gg.malloc.defense.model.Spawner; | ||||||
|  | import gg.malloc.defense.model.Wave; | ||||||
|  |  | ||||||
|  | import gg.malloc.defense.Plugin; | ||||||
|  |  | ||||||
|  | import java.util.logging.Logger; | ||||||
|  |  | ||||||
|  | import org.bukkit.Bukkit; | ||||||
|  | import org.bukkit.World; | ||||||
|  | import org.bukkit.boss.BarColor; | ||||||
|  | import org.bukkit.boss.BarStyle; | ||||||
|  | import org.bukkit.boss.BossBar; | ||||||
|  | import org.bukkit.event.player.PlayerTeleportEvent; | ||||||
|  | import org.bukkit.event.entity.EntityDamageEvent; | ||||||
|  | import org.bukkit.entity.Entity; | ||||||
|  | import org.bukkit.entity.LivingEntity; | ||||||
|  | import org.bukkit.entity.EntityType; | ||||||
|  | import org.bukkit.entity.Player; | ||||||
|  | import org.bukkit.scheduler.BukkitTask; | ||||||
|  |  | ||||||
|  | public class GameRunner { | ||||||
|  |   Arena m_arena; | ||||||
|  |   Game m_game; | ||||||
|  |   Stage m_stage; | ||||||
|  |   Plugin m_plugin; | ||||||
|  |  | ||||||
|  |   BossBar m_gameBar = Bukkit.createBossBar("Malloc Defense", BarColor.PURPLE, BarStyle.SOLID); | ||||||
|  |   BossBar m_waveBar = Bukkit.createBossBar("Malloc Defense", BarColor.PURPLE, BarStyle.SOLID); | ||||||
|  |   BukkitTask m_countdownTask; | ||||||
|  |  | ||||||
|  |   MobManager m_mobs; | ||||||
|  |   WaveManager m_waves; | ||||||
|  |   PlayerManager m_players; | ||||||
|  |  | ||||||
|  |   Logger m_log; | ||||||
|  |  | ||||||
|  |   public enum Stage { | ||||||
|  |     Idle, | ||||||
|  |     Warmup, | ||||||
|  |     Playing, | ||||||
|  |     GameOver | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   class WaveManager { | ||||||
|  |     int m_currentWaveNum = 0; | ||||||
|  |     int m_currentBatch = 0; | ||||||
|  |     Wave m_currentWave = null; | ||||||
|  |     Game m_game; | ||||||
|  |  | ||||||
|  |     WaveManager(Game game) { | ||||||
|  |       m_game = game; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void reset() { | ||||||
|  |       m_currentWaveNum = 0; | ||||||
|  |       m_currentBatch = 0; | ||||||
|  |       m_currentWave = null; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Wave currentWave() { | ||||||
|  |       return m_currentWave; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int currentWaveNum() { | ||||||
|  |       return m_currentWaveNum; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int currentBatchNum() { | ||||||
|  |       return m_currentBatch; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     double progress() { | ||||||
|  |       return (double)m_currentWaveNum / (double)m_game.getWaveCount(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     boolean isLastWave() { | ||||||
|  |       return m_currentWaveNum >= m_game.getWaveCount(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     boolean isLastBatch() { | ||||||
|  |       return m_currentBatch >= m_currentWave.batchCount(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void nextBatch() { | ||||||
|  |       m_currentBatch += 1; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     void next() { | ||||||
|  |       m_currentWaveNum += 1; | ||||||
|  |       m_currentBatch = 0; | ||||||
|  |       m_currentWave = m_game.getWave(m_currentWaveNum); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   public GameRunner(Plugin plugin, Game game, Arena arena) { | ||||||
|  |     m_plugin = plugin; | ||||||
|  |     m_game = game; | ||||||
|  |     m_arena = arena; | ||||||
|  |     m_stage = Stage.Idle; | ||||||
|  |     m_gameBar.setVisible(true); | ||||||
|  |     m_waveBar.setVisible(false); | ||||||
|  |     m_mobs = new MobManager(m_game); | ||||||
|  |     m_waves = new WaveManager(m_game); | ||||||
|  |     m_players = new PlayerManager(); | ||||||
|  |     m_log = m_plugin.getLogger(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   int m_warmupCountdown = 0; | ||||||
|  |  | ||||||
|  |   public void handleEntityDamage(EntityDamageEvent evt) { | ||||||
|  |     m_mobs.handleEntityDamage(evt); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private void countdownTick() { | ||||||
|  |     if (m_warmupCountdown == 0) { | ||||||
|  |       requestTransition(Stage.Playing); | ||||||
|  |     } else { | ||||||
|  |       updateMobBars(); | ||||||
|  |       broadcastMessage("Starting game in " + m_warmupCountdown); | ||||||
|  |       m_warmupCountdown--; | ||||||
|  |       m_countdownTask = m_plugin.getServer().getScheduler().runTaskLater(m_plugin, () -> { | ||||||
|  |         countdownTick(); | ||||||
|  |       }, 20); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private boolean enterIdle() { | ||||||
|  |     m_waves.reset(); | ||||||
|  |     m_mobs.clear(); | ||||||
|  |     m_players.requestTransitionForAll(PlayerManager.State.Idle); | ||||||
|  |     if (m_countdownTask != null) { | ||||||
|  |       m_countdownTask.cancel(); | ||||||
|  |       m_countdownTask = null; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private boolean enterWarmup() { | ||||||
|  |     m_waves.next(); | ||||||
|  |     m_warmupCountdown = 10; | ||||||
|  |     for(Player p : m_players.getPlayers()) { | ||||||
|  |         if (m_players.requestTransition(p, PlayerManager.State.Playing)) { | ||||||
|  |           p.teleport(m_arena.getWorld().getSpawnLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     broadcastTitle("Warmup", "Prepare yourself for wave " + m_waves.currentWaveNum()); | ||||||
|  |     m_mobs.clear(); | ||||||
|  |     countdownTick(); | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private boolean enterPlaying() { | ||||||
|  |     m_log.info("Starting wave " + m_waves.currentWaveNum()); | ||||||
|  |     spawnNextBatch(); | ||||||
|  |     broadcastTitle("Wave " + m_waves.currentWaveNum()); | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private boolean enterGameOver() { | ||||||
|  |     broadcastTitle("Game Over!"); | ||||||
|  |     if (m_countdownTask != null) { | ||||||
|  |       m_countdownTask.cancel(); | ||||||
|  |       m_countdownTask = null; | ||||||
|  |     } | ||||||
|  |     m_mobs.clear(); | ||||||
|  |     for(Player p : m_players.getPlayers()) { | ||||||
|  |       removePlayer(p); | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private void updateMobBars() { | ||||||
|  |     m_gameBar.setVisible(true); | ||||||
|  |     switch(m_stage) { | ||||||
|  |       case Idle: | ||||||
|  |         m_gameBar.setProgress(1.0); | ||||||
|  |         m_gameBar.setTitle("Waiting for playres..."); | ||||||
|  |         m_gameBar.setColor(BarColor.PURPLE); | ||||||
|  |         m_waveBar.setVisible(false); | ||||||
|  |         break; | ||||||
|  |       case Warmup: | ||||||
|  |         m_gameBar.setProgress(m_waves.progress()); | ||||||
|  |         m_gameBar.setTitle("Wave " + m_waves.currentWaveNum() + " / " + m_game.getWaveCount()); | ||||||
|  |         m_gameBar.setColor(BarColor.PURPLE); | ||||||
|  |         m_waveBar.setVisible(true); | ||||||
|  |         m_waveBar.setColor(BarColor.YELLOW); | ||||||
|  |         m_waveBar.setTitle("Warmup"); | ||||||
|  |         m_waveBar.setProgress((double)m_warmupCountdown / (double)10); | ||||||
|  |         break; | ||||||
|  |       case Playing: | ||||||
|  |         m_gameBar.setProgress(m_waves.progress()); | ||||||
|  |         m_gameBar.setTitle("Wave " + m_waves.currentWaveNum() + " / " + m_game.getWaveCount()); | ||||||
|  |         m_gameBar.setColor(BarColor.PURPLE); | ||||||
|  |         if (m_mobs.createdMobs() > 0) { | ||||||
|  |           m_waveBar.setVisible(true); | ||||||
|  |           m_waveBar.setColor(BarColor.GREEN); | ||||||
|  |           m_waveBar.setTitle("Mobs remaining: " + m_mobs.remainingMobs()); | ||||||
|  |           m_waveBar.setProgress(m_mobs.progress()); | ||||||
|  |         } else { | ||||||
|  |           m_waveBar.setVisible(false); | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |       case GameOver: | ||||||
|  |         m_gameBar.setColor(BarColor.RED); | ||||||
|  |         m_gameBar.setProgress(1.0); | ||||||
|  |         m_gameBar.setTitle("Game Over!"); | ||||||
|  |         m_waveBar.setVisible(false); | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private void spawnNextBatch() { | ||||||
|  |     broadcastMessage("Spawning batch " + m_waves.currentBatchNum()); | ||||||
|  |     Spawner spawner = new GameSpawner(m_arena, m_mobs); | ||||||
|  |     m_waves.currentWave().spawnBatch(spawner, m_waves.currentBatchNum()); | ||||||
|  |     updateMobBars(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void handlePlayerDeath(Player player) { | ||||||
|  |     if (m_players.requestTransition(player, PlayerManager.State.Dead)) { | ||||||
|  |       m_arena.getWorld().strikeLightningEffect(player.getLocation()); | ||||||
|  |       if (!m_players.isAnyoneAlive()) { | ||||||
|  |         broadcastMessage("Everyone is dead :("); | ||||||
|  |         requestTransition(Stage.GameOver); | ||||||
|  |       } else { | ||||||
|  |         m_log.info("Remaining players " + m_players.remainingPlayers()); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void handleEntityDeath(Entity entity) { | ||||||
|  |     if (m_mobs.killMob(entity)) { | ||||||
|  |       broadcastMessage("Killed game entity " + entity); | ||||||
|  |       updateMobBars(); | ||||||
|  |       if (m_mobs.remainingMobs() <= 3) { | ||||||
|  |         m_log.info("Starting next batch!"); | ||||||
|  |         if (m_waves.isLastBatch()) { | ||||||
|  |           if (m_waves.isLastWave()) { | ||||||
|  |             requestTransition(Stage.GameOver); | ||||||
|  |           } else if (m_mobs.empty()) { | ||||||
|  |             requestTransition(Stage.Warmup); | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           m_waves.nextBatch(); | ||||||
|  |           spawnNextBatch(); | ||||||
|  |         } | ||||||
|  |       } else { | ||||||
|  |         m_log.fine("Living mobs remaining: " + m_mobs.remainingMobs()); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private boolean attemptTransition(Stage stage) { | ||||||
|  |     if (m_stage == stage) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     m_log.info("Game state: " + stage); | ||||||
|  |     switch(stage) { | ||||||
|  |       case Idle: | ||||||
|  |         return enterIdle(); | ||||||
|  |       case Warmup: | ||||||
|  |         return enterWarmup(); | ||||||
|  |       case Playing: | ||||||
|  |         return enterPlaying(); | ||||||
|  |       case GameOver: | ||||||
|  |         return enterGameOver(); | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   private boolean validateTransition(Stage from, Stage to) { | ||||||
|  |     switch(from) { | ||||||
|  |       case Idle: | ||||||
|  |         return to == Stage.Warmup; | ||||||
|  |       case Warmup: | ||||||
|  |         return to == Stage.Playing || to == Stage.Idle || to == Stage.GameOver; | ||||||
|  |       case Playing: | ||||||
|  |         return to == Stage.Warmup || to == Stage.GameOver || to == Stage.Idle; | ||||||
|  |       case GameOver: | ||||||
|  |         return to == Stage.Idle; | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public boolean requestTransition(Stage stage) { | ||||||
|  |     if (!validateTransition(m_stage, stage)) { | ||||||
|  |       m_log.warning("Attemped illegal transition: " + m_stage + " -> " + stage); | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     if (attemptTransition(stage)) { | ||||||
|  |       m_log.info("Game transition: " + m_stage + " -> " + stage); | ||||||
|  |       m_stage = stage; | ||||||
|  |       updateMobBars(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     m_log.severe("Failed to complete transition: " + m_stage + " -> " + stage); | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void addPlayer(Player p) { | ||||||
|  |     m_players.addPlayer(p); | ||||||
|  |     m_gameBar.addPlayer(p); | ||||||
|  |     m_waveBar.addPlayer(p); | ||||||
|  |     if (m_stage == Stage.Idle || m_stage == Stage.Warmup) { | ||||||
|  |       if (m_players.requestTransition(p, PlayerManager.State.Playing)) { | ||||||
|  |         p.teleport(m_arena.getWorld().getSpawnLocation(), PlayerTeleportEvent.TeleportCause.PLUGIN); | ||||||
|  |       } | ||||||
|  |       broadcastMessage(p.getName() + " has joined the game"); | ||||||
|  |       if (m_stage == Stage.Idle) { | ||||||
|  |         requestTransition(Stage.Warmup); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void removePlayer(Player p) { | ||||||
|  |     m_gameBar.removePlayer(p); | ||||||
|  |     m_waveBar.removePlayer(p); | ||||||
|  |     m_players.removePlayer(p); | ||||||
|  |     if (m_players.isEmpty()) { | ||||||
|  |       requestTransition(Stage.Idle); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void broadcastTitle(String title) { | ||||||
|  |     broadcastTitle(title, ""); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void broadcastTitle(String title, String subtitle) { | ||||||
|  |     for(Player p : m_players.getPlayers()) { | ||||||
|  |       p.sendTitle(title, subtitle, 10, 70, 20); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void broadcastMessage(String string) { | ||||||
|  |     World world = m_arena.getWorld(); | ||||||
|  |     for(Player p : world.getPlayers()) { | ||||||
|  |       p.sendMessage(string); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void registerSpawnedMob(Entity entity) { | ||||||
|  |     m_mobs.addEntity(entity); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										33
									
								
								src/main/java/gg/malloc/defense/engine/GameSpawner.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/main/java/gg/malloc/defense/engine/GameSpawner.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | package gg.malloc.defense.engine; | ||||||
|  |  | ||||||
|  | import gg.malloc.defense.model.Spawner; | ||||||
|  | import gg.malloc.defense.model.Spawnpoint; | ||||||
|  | import gg.malloc.defense.model.Arena; | ||||||
|  |  | ||||||
|  | import org.bukkit.entity.Entity; | ||||||
|  | import org.bukkit.entity.LivingEntity; | ||||||
|  | import org.bukkit.entity.EntityType; | ||||||
|  |  | ||||||
|  | public class GameSpawner implements Spawner { | ||||||
|  |   Arena m_arena; | ||||||
|  |   MobManager m_manager; | ||||||
|  |   int m_spawnIdx = 0; | ||||||
|  |  | ||||||
|  |   public GameSpawner(Arena arena, MobManager manager) { | ||||||
|  |     m_arena = arena; | ||||||
|  |     m_manager = manager; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @Override | ||||||
|  |   public Entity spawnMob(EntityType type) { | ||||||
|  |     Spawnpoint[] spawnpoints = m_arena.spawnpoints(); | ||||||
|  |     m_spawnIdx %= spawnpoints.length; | ||||||
|  |     //m_log.fine("Spawning " + type + " at " + spawnpoints[m_spawnIdx]); | ||||||
|  |     Entity newMob = m_arena.getWorld().spawnEntity(spawnpoints[m_spawnIdx].getLocation(), type); | ||||||
|  |     LivingEntity livingMob = (LivingEntity)newMob; | ||||||
|  |     livingMob.setRemoveWhenFarAway(false); | ||||||
|  |     m_manager.addEntity(newMob); | ||||||
|  |     m_spawnIdx += 1; | ||||||
|  |     return newMob; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								src/main/java/gg/malloc/defense/engine/GameStage.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/main/java/gg/malloc/defense/engine/GameStage.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | package gg.malloc.defense.engine; | ||||||
|  |  | ||||||
|  | public interface GameStage { | ||||||
|  |   String name(); | ||||||
|  |   default void onEnter() {} | ||||||
|  |   default void onExit() {} | ||||||
|  | } | ||||||
							
								
								
									
										72
									
								
								src/main/java/gg/malloc/defense/engine/MobManager.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/main/java/gg/malloc/defense/engine/MobManager.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | package gg.malloc.defense.engine; | ||||||
|  |  | ||||||
|  | import java.util.HashSet; | ||||||
|  |  | ||||||
|  | import org.bukkit.entity.Entity; | ||||||
|  | import org.bukkit.event.entity.EntityDamageEvent; | ||||||
|  |  | ||||||
|  | import gg.malloc.defense.model.Game; | ||||||
|  |  | ||||||
|  | public class MobManager { | ||||||
|  |   HashSet<Entity> m_livingMobs = new HashSet<>(); | ||||||
|  |   int m_createdMobs = 0; | ||||||
|  |   int m_killedMobs = 0; | ||||||
|  |  | ||||||
|  |   Game m_game; | ||||||
|  |  | ||||||
|  |   MobManager(Game game) { | ||||||
|  |     m_game = game; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void handleEntityDamage(EntityDamageEvent evt) { | ||||||
|  |     Entity entity = evt.getEntity(); | ||||||
|  |     //m_log.info("Damage " + entity); | ||||||
|  |     //m_log.info("Living Mobs " + m_livingMobs); | ||||||
|  |     if (m_livingMobs.contains(entity)) { | ||||||
|  |       m_game.onMobDamaged(entity); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public boolean killMob(Entity entity) { | ||||||
|  |     if (m_livingMobs.contains(entity)) { | ||||||
|  |       m_killedMobs += 1; | ||||||
|  |       return m_livingMobs.remove(entity); | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void clear() { | ||||||
|  |     for(Entity e : m_livingMobs) { | ||||||
|  |       e.remove(); | ||||||
|  |     } | ||||||
|  |     m_livingMobs.clear(); | ||||||
|  |     m_createdMobs = 0; | ||||||
|  |     m_killedMobs = 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public int createdMobs() { | ||||||
|  |     return m_createdMobs; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public int killedMobs() { | ||||||
|  |     return m_killedMobs; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public int remainingMobs() { | ||||||
|  |     return m_createdMobs - m_killedMobs; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public double progress() { | ||||||
|  |     return (double)m_killedMobs / (double)m_createdMobs; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void addEntity(Entity entity) { | ||||||
|  |     //m_log.fine("Registered new mob " + entity);  | ||||||
|  |     m_livingMobs.add(entity); | ||||||
|  |     m_createdMobs += 1; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public boolean empty() { | ||||||
|  |     return m_livingMobs.size() == 0; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										113
									
								
								src/main/java/gg/malloc/defense/engine/PlayerManager.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								src/main/java/gg/malloc/defense/engine/PlayerManager.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,113 @@ | |||||||
|  | package gg.malloc.defense.engine; | ||||||
|  |  | ||||||
|  | import org.bukkit.entity.Player; | ||||||
|  | import org.bukkit.Bukkit; | ||||||
|  | import org.bukkit.GameMode; | ||||||
|  | import org.bukkit.attribute.Attribute; | ||||||
|  | import org.bukkit.event.player.PlayerTeleportEvent; | ||||||
|  |  | ||||||
|  | import java.util.HashMap; | ||||||
|  | import java.util.Collection; | ||||||
|  |  | ||||||
|  | public class PlayerManager { | ||||||
|  |   HashMap<Player, State> m_playerStates = new HashMap<>(); | ||||||
|  |  | ||||||
|  |   public enum State { | ||||||
|  |     Idle, | ||||||
|  |     Playing, | ||||||
|  |     Dead | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public boolean requestTransitionForAll(State toState) { | ||||||
|  |     boolean allSuccess = true; | ||||||
|  |     for (Player p : getPlayers()) { | ||||||
|  |       allSuccess = allSuccess && requestTransition(p, toState); | ||||||
|  |     } | ||||||
|  |     return allSuccess; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public boolean requestTransition(Player player, State toState) { | ||||||
|  |     State currentState = m_playerStates.get(player); | ||||||
|  |     if (currentState == toState) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     boolean ret = false; | ||||||
|  |     switch(toState) { | ||||||
|  |       case Idle: | ||||||
|  |         ret = enterIdle(player);break; | ||||||
|  |       case Playing: | ||||||
|  |         ret = enterPlaying(player);break; | ||||||
|  |       case Dead: | ||||||
|  |         ret = enterDead(player);break; | ||||||
|  |     } | ||||||
|  |     if (ret) { | ||||||
|  |       m_playerStates.put(player, toState); | ||||||
|  |     } | ||||||
|  |     return ret; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public boolean enterIdle(Player player) { | ||||||
|  |     // Reset player to non-game state, return control back to Minecraft | ||||||
|  |     player.setGameMode(Bukkit.getDefaultGameMode()); | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Respawn player | ||||||
|  |   public boolean enterPlaying(Player player) { | ||||||
|  |     //m_log.fine("Respawning player " + player); | ||||||
|  |     player.setGameMode(Bukkit.getDefaultGameMode()); | ||||||
|  |     player.setHealth(player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()); | ||||||
|  |     player.setFoodLevel(10); | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public boolean enterDead(Player player) { | ||||||
|  |     //m_log.info("Player has died in game" + player); | ||||||
|  |     player.setGameMode(GameMode.SPECTATOR); | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public void addPlayer(Player player) { | ||||||
|  |     //m_log.info("Adding player " + player);  | ||||||
|  |     m_playerStates.put(player, State.Idle); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public boolean removePlayer(Player player) { | ||||||
|  |     //m_log.info("Removing player " + player);  | ||||||
|  |     requestTransition(player, State.Idle); | ||||||
|  |     m_playerStates.remove(player); | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public boolean isEmpty() { | ||||||
|  |     return m_playerStates.size() == 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public boolean isAlive(Player player) { | ||||||
|  |     return m_playerStates.get(player) == State.Playing; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public boolean isAnyoneAlive() { | ||||||
|  |     for(Player p : m_playerStates.keySet()) { | ||||||
|  |       if (m_playerStates.get(p) == State.Playing) { | ||||||
|  |         return true; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public int remainingPlayers() { | ||||||
|  |     int aliveCount = 0; | ||||||
|  |     for(State s : m_playerStates.values()) { | ||||||
|  |       if (s == State.Playing) { | ||||||
|  |         aliveCount += 1; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return aliveCount; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Collection<Player> getPlayers() { | ||||||
|  |     return m_playerStates.keySet(); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| @@ -6,7 +6,7 @@ depend:  [] | |||||||
| commands: | commands: | ||||||
|   setstage: |   setstage: | ||||||
|     description: Sets a game stage |     description: Sets a game stage | ||||||
|   initgame: |   addplayer: | ||||||
|     description: Adds a player to a game |     description: Adds a player to a game | ||||||
|   debuginfo: |   debuginfo: | ||||||
|     description: Unknowable powers |     description: Unknowable powers | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user