aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com')
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/Main.java38
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/commands/Config.java35
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/commands/ForceStart.java48
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/commands/ForceStop.java48
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/commands/Join.java103
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/commands/Leave.java53
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/commands/Reload.java26
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/commands/SetAutoStart.java94
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/commands/SetWinnerLoc.java110
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/commands/SetWorldConfig.java74
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/commands/StartGame.java85
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/game/Arena.java26
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/game/EventListener.java204
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/game/Game.java652
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/game/Generator.java135
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/plugin/ConfigManager.java152
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/plugin/Constants.java25
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/plugin/EventListener.java222
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/plugin/GameState.java7
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/plugin/GameType.java11
-rw-r--r--src/main/java/com/MylesAndMore/Tumble/plugin/Result.java8
21 files changed, 1113 insertions, 1043 deletions
diff --git a/src/main/java/com/MylesAndMore/Tumble/Main.java b/src/main/java/com/MylesAndMore/Tumble/Main.java
index a9a07ee..f3ea52e 100644
--- a/src/main/java/com/MylesAndMore/Tumble/Main.java
+++ b/src/main/java/com/MylesAndMore/Tumble/Main.java
@@ -1,39 +1,33 @@
package com.MylesAndMore.Tumble;
import com.MylesAndMore.Tumble.commands.*;
-import com.MylesAndMore.Tumble.plugin.Constants;
-import com.MylesAndMore.Tumble.plugin.EventListener;
-
-import com.jeff_media.updatechecker.UpdateCheckSource;
-import com.jeff_media.updatechecker.UpdateChecker;
+import com.MylesAndMore.Tumble.plugin.ConfigManager;
import org.bstats.bukkit.Metrics;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
+import java.util.Objects;
+
public class Main extends JavaPlugin{
+ public static Main plugin;
+
@Override
public void onEnable() {
- // Register setup items
- getServer().getPluginManager().registerEvents(new EventListener(), this);
- this.getCommand("reload").setExecutor(new Reload());
- this.getCommand("link").setExecutor(new SetWorldConfig());
- this.getCommand("start").setExecutor(new StartGame());
- this.getCommand("winlocation").setExecutor(new SetWinnerLoc());
- this.getCommand("autostart").setExecutor(new SetAutoStart());
+ plugin = this;
+
+ Objects.requireNonNull(this.getCommand("reload")).setExecutor(new Reload());
+ Objects.requireNonNull(this.getCommand("config")).setExecutor(new Config());
+ Objects.requireNonNull(this.getCommand("forcestart")).setExecutor(new ForceStart());
+ Objects.requireNonNull(this.getCommand("join")).setExecutor(new Join());
+ Objects.requireNonNull(this.getCommand("leave")).setExecutor(new Leave());
+ Objects.requireNonNull(this.getCommand("forcestop")).setExecutor(new ForceStop());
new Metrics(this, 16940);
- this.saveDefaultConfig(); // Saves the default config file (packaged in the JAR) if we haven't already
+ // TODO: change command format
- // Check if worlds are null in config and throw warnings if so
- if (Constants.getGameWorld() == null) {
- Bukkit.getServer().getLogger().warning("[Tumble] It appears you have not configured a game world for Tumble.");
- Bukkit.getServer().getLogger().info("[Tumble] If this is your first time running the plugin, you may disregard this message.");
- }
- if (Constants.getLobbyWorld() == null) {
- Bukkit.getServer().getLogger().warning("[Tumble] It appears you have not configured a lobby world for Tumble.");
- Bukkit.getServer().getLogger().info("[Tumble] If this is your first time running the plugin, you may disregard this message.");
- }
+ this.saveDefaultConfig(); // Saves the default config file (packaged in the JAR) if we haven't already
+ ConfigManager.readConfig();
Bukkit.getServer().getLogger().info("[Tumble] Tumble successfully enabled!");
}
diff --git a/src/main/java/com/MylesAndMore/Tumble/commands/Config.java b/src/main/java/com/MylesAndMore/Tumble/commands/Config.java
new file mode 100644
index 0000000..d91a5b5
--- /dev/null
+++ b/src/main/java/com/MylesAndMore/Tumble/commands/Config.java
@@ -0,0 +1,35 @@
+package com.MylesAndMore.Tumble.commands;
+
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Config implements CommandExecutor, TabCompleter {
+ @Override
+ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
+ if (!(sender instanceof Player)) {
+ sender.sendMessage(ChatColor.RED + "This cannot be run by the console");
+ return false;
+ }
+
+ if (!sender.hasPermission("tumble.config")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to perform this command!");
+ return false;
+ }
+
+ sender.sendMessage(ChatColor.RED + "Not implemented yet"); // TODO
+ return true;
+ }
+
+ @Override
+ public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
+ return new ArrayList<>();
+ }
+}
diff --git a/src/main/java/com/MylesAndMore/Tumble/commands/ForceStart.java b/src/main/java/com/MylesAndMore/Tumble/commands/ForceStart.java
new file mode 100644
index 0000000..78ff183
--- /dev/null
+++ b/src/main/java/com/MylesAndMore/Tumble/commands/ForceStart.java
@@ -0,0 +1,48 @@
+package com.MylesAndMore.Tumble.commands;
+
+import com.MylesAndMore.Tumble.game.Game;
+import com.MylesAndMore.Tumble.plugin.ConfigManager;
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ForceStart implements CommandExecutor, TabCompleter {
+ @Override
+ public boolean onCommand(CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
+
+ if (!sender.hasPermission("tumble.forcestart")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to perform this command!");
+ return false;
+ }
+
+ Game game;
+ if (args.length < 1 || args[0] == null) {
+ game = ConfigManager.findGamePlayerIsIn((Player)sender);
+ if (game == null) {
+ sender.sendMessage(ChatColor.RED + "Missing arena name");
+ return false;
+ }
+ }
+ else {
+ game = ConfigManager.arenas.get(args[0]).game;
+ }
+
+ game.startGame();
+ return true;
+ }
+
+ @Override
+ public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
+ if (args.length == 1) {
+ return ConfigManager.arenas.keySet().stream().toList();
+ }
+ return new ArrayList<>();
+ }
+}
diff --git a/src/main/java/com/MylesAndMore/Tumble/commands/ForceStop.java b/src/main/java/com/MylesAndMore/Tumble/commands/ForceStop.java
new file mode 100644
index 0000000..7f266d7
--- /dev/null
+++ b/src/main/java/com/MylesAndMore/Tumble/commands/ForceStop.java
@@ -0,0 +1,48 @@
+package com.MylesAndMore.Tumble.commands;
+
+import com.MylesAndMore.Tumble.game.Game;
+import com.MylesAndMore.Tumble.plugin.ConfigManager;
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ForceStop implements CommandExecutor, TabCompleter {
+ @Override
+ public boolean onCommand(CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
+
+ if (!sender.hasPermission("tumble.forcestop")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to perform this command!");
+ return false;
+ }
+
+ Game game;
+ if (args.length < 1 || args[0] == null) {
+ game = ConfigManager.findGamePlayerIsIn((Player)sender);
+ if (game == null) {
+ sender.sendMessage(ChatColor.RED + "Missing arena name");
+ return false;
+ }
+ }
+ else {
+ game = ConfigManager.arenas.get(args[0]).game;
+ }
+
+ game.killGame();
+ return true;
+ }
+
+ @Override
+ public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
+ if (args.length == 1) {
+ return ConfigManager.arenas.keySet().stream().toList();
+ }
+ return new ArrayList<>();
+ }
+}
diff --git a/src/main/java/com/MylesAndMore/Tumble/commands/Join.java b/src/main/java/com/MylesAndMore/Tumble/commands/Join.java
new file mode 100644
index 0000000..4dd4ef8
--- /dev/null
+++ b/src/main/java/com/MylesAndMore/Tumble/commands/Join.java
@@ -0,0 +1,103 @@
+package com.MylesAndMore.Tumble.commands;
+
+import com.MylesAndMore.Tumble.game.Arena;
+import com.MylesAndMore.Tumble.plugin.ConfigManager;
+import com.MylesAndMore.Tumble.game.Game;
+import com.MylesAndMore.Tumble.plugin.GameState;
+import com.MylesAndMore.Tumble.plugin.GameType;
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+public class Join implements CommandExecutor, TabCompleter {
+ @Override
+ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
+
+ if (!(sender instanceof Player)) {
+ sender.sendMessage(ChatColor.RED + "This cannot be run by the console");
+ return false;
+ }
+
+ if (!sender.hasPermission("tumble.join")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to perform this command!");
+ return false;
+ }
+
+ if (ConfigManager.findGamePlayerIsIn((Player)sender) != null) {
+ sender.sendMessage(ChatColor.RED + "You are already in a game! Leave it to join another one");
+ }
+
+ if (args.length < 1 || args[0] == null) {
+ sender.sendMessage(ChatColor.RED + "Missing arena name");
+ return false;
+ }
+ String arenaName = args[0];
+ if (!ConfigManager.arenas.containsKey(arenaName))
+ {
+ sender.sendMessage(ChatColor.RED + "This arena does not exist");
+ return false;
+ }
+ Arena arena = ConfigManager.arenas.get(arenaName);
+
+ Game game;
+ if (args.length < 2 || args[1] == null) {
+ if (arena.game == null) {
+ sender.sendMessage(ChatColor.RED + "no game is currently taking place in this arena, specify the game type to start one");
+ return false;
+ }
+ else {
+ game = arena.game;
+ }
+ }
+ else {
+ GameType type;
+ switch (args[1]) {
+ case "shovels", "shovel" -> type = GameType.SHOVELS;
+ case "snowballs", "snowball" -> type = GameType.SNOWBALLS;
+ case "mix", "mixed" -> type = GameType.MIXED;
+ default -> {
+ sender.sendMessage(ChatColor.RED + "Invalid game type");
+ return false;
+ }
+ }
+
+ if (arena.game == null) {
+ game = arena.game = new Game(arena, type);
+ }
+ else {
+ sender.sendMessage(ChatColor.RED + "A game of "+type+" is currently taking place in this arena, choose another arena or join it with /tumble:join "+arena.name+" "+type);
+ return false;
+ }
+ }
+
+ if (game.gameState != GameState.WAITING) {
+ sender.sendMessage(ChatColor.RED + "This game is still in progress, wait until it finishes or join another game");
+ return false;
+ }
+
+ game.addPlayer((Player)sender);
+ sender.sendMessage(ChatColor.GREEN + "Joined game " + arena.name + " - " + game.type);
+ return true;
+ }
+
+ @Override
+ public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
+ if (args.length == 1) {
+ return ConfigManager.arenas.keySet().stream().toList();
+ }
+ if (args.length == 2) {
+ return Arrays.stream(GameType.values()).map(Objects::toString).collect(Collectors.toList());
+ }
+ return new ArrayList<>();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/MylesAndMore/Tumble/commands/Leave.java b/src/main/java/com/MylesAndMore/Tumble/commands/Leave.java
new file mode 100644
index 0000000..94255a4
--- /dev/null
+++ b/src/main/java/com/MylesAndMore/Tumble/commands/Leave.java
@@ -0,0 +1,53 @@
+package com.MylesAndMore.Tumble.commands;
+
+import com.MylesAndMore.Tumble.game.Game;
+import com.MylesAndMore.Tumble.plugin.ConfigManager;
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Leave implements CommandExecutor, TabCompleter {
+ @Override
+ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
+
+ if (!(sender instanceof Player)) {
+ sender.sendMessage(ChatColor.RED + "This cannot be run by the console");
+ return false;
+ }
+
+ if (!sender.hasPermission("tumble.leave")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to perform this command!");
+ return false;
+ }
+
+ Game game;
+ if (args.length < 1 || args[0] == null) {
+ game = ConfigManager.findGamePlayerIsIn((Player)sender);
+ if (game == null) {
+ sender.sendMessage(ChatColor.RED + "Missing arena name");
+ return false;
+ }
+ }
+ else {
+ game = ConfigManager.arenas.get(args[0]).game;
+ }
+
+ game.removePlayer((Player) sender);
+ return true;
+ }
+
+ @Override
+ public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
+ if (args.length == 1) {
+ return ConfigManager.arenas.keySet().stream().toList();
+ }
+ return new ArrayList<>();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/MylesAndMore/Tumble/commands/Reload.java b/src/main/java/com/MylesAndMore/Tumble/commands/Reload.java
index ffc6dd8..5d35a03 100644
--- a/src/main/java/com/MylesAndMore/Tumble/commands/Reload.java
+++ b/src/main/java/com/MylesAndMore/Tumble/commands/Reload.java
@@ -1,22 +1,32 @@
package com.MylesAndMore.Tumble.commands;
-import com.MylesAndMore.Tumble.plugin.Constants;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
import org.jetbrains.annotations.NotNull;
-public class Reload implements CommandExecutor {
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.MylesAndMore.Tumble.Main.plugin;
+
+public class Reload implements CommandExecutor, TabCompleter {
+
@Override
public boolean onCommand(CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
- if (sender.hasPermission("tumble.reload")) {
- Constants.getPlugin().reloadConfig();
- sender.sendMessage(ChatColor.GREEN + "Tumble configuration reloaded successfully.");
- }
- else {
- sender.sendMessage(ChatColor.RED + Constants.getPermissionMessage());
+ if (!sender.hasPermission("tumble.reload")) {
+ sender.sendMessage(ChatColor.RED + "You do not have permission to perform this command!");
+ return false;
}
+ plugin.onEnable();
+ sender.sendMessage(ChatColor.GREEN + "Tumble configuration reloaded successfully.");
return true;
}
+
+ @Override
+ public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
+ return new ArrayList<>();
+ }
}
diff --git a/src/main/java/com/MylesAndMore/Tumble/commands/SetAutoStart.java b/src/main/java/com/MylesAndMore/Tumble/commands/SetAutoStart.java
deleted file mode 100644
index b3da74e..0000000
--- a/src/main/java/com/MylesAndMore/Tumble/commands/SetAutoStart.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package com.MylesAndMore.Tumble.commands;
-
-import com.MylesAndMore.Tumble.plugin.Constants;
-import org.bukkit.ChatColor;
-import org.bukkit.command.Command;
-import org.bukkit.command.CommandExecutor;
-import org.bukkit.command.CommandSender;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Objects;
-
-public class SetAutoStart implements CommandExecutor{
- @Override
- public boolean onCommand(CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
- if (sender.hasPermission("tumble.autostart")) {
- if (Constants.getGameWorld() != null) {
- if (Constants.getLobbyWorld() != null) {
- if (args.length == 2) {
- // Check the player # argument and parse it into an int
- int args0;
- try {
- args0 = Integer.parseInt(args[0]);
- } catch (NumberFormatException nfe){
- sender.sendMessage(ChatColor.RED + "Player amount must be a valid number.");
- return true;
- } catch (Exception e){
- sender.sendMessage(ChatColor.RED + "Invalid player amount.");
- return true;
- }
- // PlayerAmount & enable/disable were entered
- if ((args0 >= 2) && (args0 <= 8)) {
- if (Objects.equals(args[1], "enable")) {
- // Write values to the config
- Constants.getPlugin().getConfig().set("autoStart.players", args0);
- Constants.getPlugin().getConfig().set("autoStart.enabled", true);
- Constants.getPlugin().saveConfig();
- sender.sendMessage(ChatColor.GREEN + "Configuration saved!");
- sender.sendMessage(ChatColor.GREEN + "Run " + ChatColor.GRAY + "/tumble:reload " + ChatColor.GREEN + "the changes to take effect.");
- }
- else if (Objects.equals(args[1], "disable")) {
- Constants.getPlugin().getConfig().set("autoStart.players", args0);
- Constants.getPlugin().getConfig().set("autoStart.enabled", false);
- Constants.getPlugin().saveConfig();
- sender.sendMessage(ChatColor.GREEN + "Configuration saved!");
- sender.sendMessage(ChatColor.GREEN + "Run " + ChatColor.GRAY + "/tumble:reload " + ChatColor.GREEN + "the changes to take effect.");
- }
- else {
- return false;
- }
- }
- else {
- sender.sendMessage(ChatColor.RED + "Please enter a player amount between two and eight!");
- }
- }
- else if (args.length == 1) {
- // Only PlayerAmount was entered
- int args0;
- try {
- args0 = Integer.parseInt(args[0]);
- } catch (NumberFormatException nfe){
- sender.sendMessage(ChatColor.RED + "Player amount must be a valid number.");
- return true;
- } catch (Exception e){
- sender.sendMessage(ChatColor.RED + "Invalid player amount.");
- return true;
- }
- if ((args0 >= 2) && (args0 <= 8)) {
- Constants.getPlugin().getConfig().set("autoStart.players", args0);
- Constants.getPlugin().saveConfig();
- sender.sendMessage(ChatColor.GREEN + "Configuration saved!");
- sender.sendMessage(ChatColor.GREEN + "Run " + ChatColor.GRAY + "/tumble:reload " + ChatColor.GREEN + "the changes to take effect.");
- }
- else {
- sender.sendMessage(ChatColor.RED + "Please enter a player amount between two and eight!");
- }
- }
- else {
- return false;
- }
- }
- else {
- sender.sendMessage(ChatColor.RED + "Please link a lobby world first!");
- }
- }
- else {
- sender.sendMessage(ChatColor.RED + "Please link a game world first!");
- }
- }
- else {
- sender.sendMessage(ChatColor.RED + Constants.getPermissionMessage());
- }
- return true;
- }
-}
diff --git a/src/main/java/com/MylesAndMore/Tumble/commands/SetWinnerLoc.java b/src/main/java/com/MylesAndMore/Tumble/commands/SetWinnerLoc.java
deleted file mode 100644
index 38e6444..0000000
--- a/src/main/java/com/MylesAndMore/Tumble/commands/SetWinnerLoc.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package com.MylesAndMore.Tumble.commands;
-
-import com.MylesAndMore.Tumble.plugin.Constants;
-import org.bukkit.ChatColor;
-import org.bukkit.Location;
-import org.bukkit.command.Command;
-import org.bukkit.command.CommandExecutor;
-import org.bukkit.command.CommandSender;
-import org.bukkit.command.ConsoleCommandSender;
-import org.bukkit.entity.Player;
-import org.jetbrains.annotations.NotNull;
-
-public class SetWinnerLoc implements CommandExecutor {
- @Override
- public boolean onCommand(CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
- if (sender.hasPermission("tumble.winlocation")) {
- if (Constants.getLobbyWorld() != null) {
- if (sender instanceof Player) {
- // Check the sender entered the correct number of args
- if (args.length == 3) {
- double args0 = 0;
- double args1 = 0;
- double args2 = 0;
- try {
- args0 = Double.parseDouble(args[0]);
- args1 = Double.parseDouble(args[1]);
- args2 = Double.parseDouble(args[2]);
- } catch (NumberFormatException nfe){
- sender.sendMessage(ChatColor.RED + "Input arguments must be valid numbers.");
- } catch (Exception e){
- sender.sendMessage(ChatColor.RED + "Invalid input arguments.");
- }
- // Check if any of the args were 0 (this will cause future problems, so we prevent it here)
- if (!((args0 == 0) || (args1 == 0) || (args2 == 0))) {
- Constants.getPlugin().getConfig().set("winnerTeleport.x", args0);
- Constants.getPlugin().getConfig().set("winnerTeleport.y", args1);
- Constants.getPlugin().getConfig().set("winnerTeleport.z", args2);
- Constants.getPlugin().saveConfig();
- sender.sendMessage(ChatColor.GREEN + "Win location successfully set!");
- sender.sendMessage(ChatColor.GREEN + "Run " + ChatColor.GRAY + "/tumble:reload " + ChatColor.GREEN + "the changes to take effect.");
- }
- else {
- sender.sendMessage(ChatColor.RED + "Your coordinates cannot be zero!");
- sender.sendMessage(ChatColor.RED + "Use something like 0.5 (the middle of the block) instead.");
- }
- }
- // If the sender entered no args, use their current location
- else if (args.length == 0) {
- Location senderPos = ((Player) sender).getLocation();
- // if so, check if any of their locations are zero
- if (!((senderPos.getX() == 0) || (senderPos.getY() == 0) || (senderPos.getZ() == 0))) {
- // set the config values to their current pos
- Constants.getPlugin().getConfig().set("winnerTeleport.x", senderPos.getX());
- Constants.getPlugin().getConfig().set("winnerTeleport.y", senderPos.getY());
- Constants.getPlugin().getConfig().set("winnerTeleport.z", senderPos.getZ());
- Constants.getPlugin().saveConfig();
- sender.sendMessage(ChatColor.GREEN + "Win location successfully set!");
- sender.sendMessage(ChatColor.GREEN + "Run " + ChatColor.GRAY + "/tumble:reload " + ChatColor.GREEN + "the changes to take effect.");
- }
- else {
- sender.sendMessage(ChatColor.RED + "Your coordinates cannot be zero!");
- sender.sendMessage(ChatColor.RED + "Use something like 0.5 (the middle of the block) instead.");
- }
- }
- else {
- return false;
- }
- }
- else if (sender instanceof ConsoleCommandSender) {
- if (args.length == 3) {
- double args0 = 0;
- double args1 = 0;
- double args2 = 0;
- try {
- args0 = Double.parseDouble(args[0]);
- args1 = Double.parseDouble(args[1]);
- args2 = Double.parseDouble(args[2]);
- } catch (NumberFormatException nfe){
- sender.sendMessage(ChatColor.RED + "Input arguments must be valid numbers.");
- } catch (Exception e){
- sender.sendMessage(ChatColor.RED + "Invalid input arguments.");
- }
- if (!((args0 == 0) || (args1 == 0) || (args2 == 0))) {
- Constants.getPlugin().getConfig().set("winnerTeleport.x", args0);
- Constants.getPlugin().getConfig().set("winnerTeleport.y", args1);
- Constants.getPlugin().getConfig().set("winnerTeleport.z", args2);
- Constants.getPlugin().saveConfig();
- sender.sendMessage(ChatColor.GREEN + "Win location successfully set!");
- sender.sendMessage(ChatColor.GREEN + "Run " + ChatColor.GRAY + "/tumble:reload " + ChatColor.GREEN + "the changes to take effect.");
- }
- else {
- sender.sendMessage(ChatColor.RED + "Your coordinates cannot be zero!");
- sender.sendMessage(ChatColor.RED + "Use something like 0.5 (the middle of the block) instead.");
- }
- }
- else {
- return false;
- }
- }
- }
- else {
- sender.sendMessage(ChatColor.RED + "Please link a lobby world first!");
- }
- }
- else {
- sender.sendMessage(ChatColor.RED + Constants.getPermissionMessage());
- }
- return true;
- }
-}
diff --git a/src/main/java/com/MylesAndMore/Tumble/commands/SetWorldConfig.java b/src/main/java/com/MylesAndMore/Tumble/commands/SetWorldConfig.java
deleted file mode 100644
index 90e0a96..0000000
--- a/src/main/java/com/MylesAndMore/Tumble/commands/SetWorldConfig.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package com.MylesAndMore.Tumble.commands;
-
-import com.MylesAndMore.Tumble.plugin.Constants;
-import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
-import org.bukkit.GameRule;
-import org.bukkit.command.Command;
-import org.bukkit.command.CommandExecutor;
-import org.bukkit.command.CommandSender;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Objects;
-
-public class SetWorldConfig implements CommandExecutor {
- @Override
- public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
- // Catch for null arguments
- if (args.length == 2) {
- if (sender.hasPermission("tumble.link")){
- // Initialize vars for their respective command arguments
- String world = args[0];
- String worldType = args[1];
- if (Objects.equals(worldType, "lobby")) {
- // Check if the world is actually a world on the server
- if (Bukkit.getWorld(world) != null) {
- // Check if the world has already been configured
- if (!Objects.equals(Constants.getGameWorld(), world)) {
- // Set the specified value of the world in the config under lobbyWorld
- Constants.getPlugin().getConfig().set("lobbyWorld", world);
- Constants.getPlugin().saveConfig();
- sender.sendMessage(ChatColor.GREEN + "Lobby world successfully linked: " + ChatColor.GRAY + world);
- sender.sendMessage(ChatColor.GREEN + "Please restart your server for the changes to take effect; " + ChatColor.RED + "reloading the plugin is insufficient!");
- }
- else {
- sender.sendMessage(ChatColor.RED + "That world has already been linked, please choose/create another world!");
- }
- }
- else {
- sender.sendMessage(ChatColor.RED + "Failed to find a world named " + ChatColor.GRAY + world);
- }
- }
- else if (Objects.equals(args[1], "game")) {
- if (Bukkit.getWorld(world) != null) {
- if (!Objects.equals(Constants.getLobbyWorld(), world)) {
- Constants.getPlugin().getConfig().set("gameWorld", world);
- Constants.getPlugin().saveConfig();
- // Set the gamerule of doImmediateRespawn in the gameWorld for later
- Objects.requireNonNull(Bukkit.getWorld(world)).setGameRule(GameRule.DO_IMMEDIATE_RESPAWN, true);
- Objects.requireNonNull(Bukkit.getWorld(world)).setGameRule(GameRule.KEEP_INVENTORY, true);
- sender.sendMessage(ChatColor.GREEN + "Game world successfully linked: " + ChatColor.GRAY + world);
- sender.sendMessage(ChatColor.GREEN + "Please restart your server for the changes to take effect; " + ChatColor.RED + "reloading the plugin is insufficient!");
- }
- else {
- sender.sendMessage(ChatColor.RED + "That world has already been linked, please choose/create another world!");
- }
- }
- else {
- sender.sendMessage(ChatColor.RED + "Failed to find a world named " + ChatColor.GRAY + world);
- }
- }
- else {
- sender.sendMessage(ChatColor.RED + "Allowed world types are " + ChatColor.GRAY + "lobby " + ChatColor.RED + "and " + ChatColor.GRAY + "game" + ChatColor.RED + ".");
- }
- }
- else {
- sender.sendMessage(ChatColor.RED + Constants.getPermissionMessage());
- }
- }
- else {
- return false;
- }
- return true;
- }
-}
diff --git a/src/main/java/com/MylesAndMore/Tumble/commands/StartGame.java b/src/main/java/com/MylesAndMore/Tumble/commands/StartGame.java
deleted file mode 100644
index 706b33a..0000000
--- a/src/main/java/com/MylesAndMore/Tumble/commands/StartGame.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package com.MylesAndMore.Tumble.commands;
-
-import com.MylesAndMore.Tumble.game.Game;
-import com.MylesAndMore.Tumble.plugin.Constants;
-import org.bukkit.ChatColor;
-import org.bukkit.command.Command;
-import org.bukkit.command.CommandExecutor;
-import org.bukkit.command.CommandSender;
-import org.jetbrains.annotations.NotNull;
-
-import java.util.Objects;
-
-public class StartGame implements CommandExecutor {
- @Override
- public boolean onCommand(CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
- if (sender.hasPermission("tumble.start")) {
- if (Constants.getLobbyWorld() != null) {
- if (Constants.getPlayersInLobby().size() > 1) {
- if (Constants.getGameWorld() != null) {
- if (!Objects.equals(Game.getGame().getGameState(), "waiting")) {
- sender.sendMessage(ChatColor.BLUE + "Generating layers, please wait.");
- // Use multiverse to load game world--if the load was successful, start game
- if (Constants.getMVWorldManager().loadWorld(Constants.getGameWorld())) {
- // If there is no starting argument,
- if (args.length == 0) {
- // pull which gamemode to initiate from the config file
- if (!Game.getGame().startGame(Constants.getGameType())) {
- // Sender feedback for if the game failed to start
- if (Objects.equals(Game.getGame().getGameState(), "starting")) {
- sender.sendMessage(ChatColor.RED + "A game is already starting!");
- }
- else if (Objects.equals(Game.getGame().getGameState(), "running")) {
- sender.sendMessage(ChatColor.RED + "A game is already running!");
- }
- else {
- sender.sendMessage(ChatColor.RED + "Failed to recognize game of type " + ChatColor.GRAY + Constants.getPlugin().getConfig().getString("gameMode"));
- }
- }
- }
- // If there was an argument for gameType, pass that instead
- else {
- if (!Game.getGame().startGame(args[0])) {
- // Sender feedback for if the game failed to start
- if (Objects.equals(Game.getGame().getGameState(), "starting")) {
- sender.sendMessage(ChatColor.RED + "A game is already starting!");
- }
- else if (Objects.equals(Game.getGame().getGameState(), "running")) {
- sender.sendMessage(ChatColor.RED + "A game is already running!");
- }
- else {
- sender.sendMessage(ChatColor.RED + "Failed to recognize game of type " + ChatColor.GRAY + args[0]);
- }
- }
- }
- }
- // If load was unsuccessful, give feedback
- // Note: this should not occur unless the config file was edited externally,
- // because the plugin prevents adding "worlds" that are not actually present to the config.
- else {
- sender.sendMessage(ChatColor.RED + "Failed to find a world named " + ChatColor.GRAY + Constants.getGameWorld());
- sender.sendMessage(ChatColor.RED + "Is the configuration file correct?");
- }
- }
- else {
- sender.sendMessage(ChatColor.RED + "A game is already queued to begin!");
- }
- }
- else {
- sender.sendMessage(ChatColor.RED + "Please link a game world first!");
- }
- }
- else {
- sender.sendMessage(ChatColor.RED + "You can't start a game with yourself!");
- }
- }
- else {
- sender.sendMessage(ChatColor.RED + "Please link a lobby world first!");
- }
- }
- else {
- sender.sendMessage(ChatColor.RED + Constants.getPermissionMessage());
- }
- return true;
- }
-}
diff --git a/src/main/java/com/MylesAndMore/Tumble/game/Arena.java b/src/main/java/com/MylesAndMore/Tumble/game/Arena.java
new file mode 100644
index 0000000..ef477d2
--- /dev/null
+++ b/src/main/java/com/MylesAndMore/Tumble/game/Arena.java
@@ -0,0 +1,26 @@
+package com.MylesAndMore.Tumble.game;
+
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * An arena is the world and spawn location where a game can take place. An arena can only host one game at a time.
+ */
+public class Arena {
+ public Game game = null;
+ public final World world;
+ public final Location location;
+ public final String name;
+
+ /**
+ * Creates a new Arena
+ * @param name Name of the arena
+ * @param location Center point / spawn point.
+ */
+ public Arena(@NotNull String name, @NotNull Location location) {
+ this.location = location;
+ this.world = location.getWorld();
+ this.name = name;
+ }
+}
diff --git a/src/main/java/com/MylesAndMore/Tumble/game/EventListener.java b/src/main/java/com/MylesAndMore/Tumble/game/EventListener.java
new file mode 100644
index 0000000..16698f4
--- /dev/null
+++ b/src/main/java/com/MylesAndMore/Tumble/game/EventListener.java
@@ -0,0 +1,204 @@
+package com.MylesAndMore.Tumble.game;
+
+import java.util.Objects;
+
+import com.MylesAndMore.Tumble.plugin.ConfigManager;
+import com.MylesAndMore.Tumble.plugin.GameState;
+import org.bukkit.*;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.Snowball;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.event.block.BlockDropItemEvent;
+import org.bukkit.event.entity.*;
+import org.bukkit.event.inventory.InventoryDragEvent;
+import org.bukkit.event.player.*;
+import org.bukkit.util.Vector;
+
+import org.bukkit.inventory.ItemStack;
+
+import static com.MylesAndMore.Tumble.Main.plugin;
+
+/**
+ * Tumble event listener for all plugin and game-related events.
+ */
+public class EventListener implements Listener {
+
+ World gameWorld;
+ Game game;
+ public EventListener(Game game) {
+ this.game = game;
+ this.gameWorld = game.gameWorld;
+ }
+
+ @EventHandler
+ public void PlayerJoinEvent(PlayerJoinEvent event) {
+ // Hide/show join message accordingly
+ if (ConfigManager.HideLeaveJoin) {
+ event.setJoinMessage(null);
+ }
+ if (event.getPlayer().getWorld() == gameWorld) {
+ // Send the player back to the lobby if they try to join in the middle of a game
+ event.getPlayer().teleport(Objects.requireNonNull(ConfigManager.lobby));
+ }
+ }
+
+ @EventHandler
+ public void PlayerQuitEvent(PlayerQuitEvent event) {
+ // Hide/show leave message accordingly
+ if (ConfigManager.HideLeaveJoin) {
+ event.setQuitMessage(null);
+ }
+ if (event.getPlayer().getWorld() == gameWorld) {
+ game.removePlayer(event.getPlayer());
+ }
+ }
+
+ @EventHandler
+ public void PlayerDeathEvent(PlayerDeathEvent event) {
+ if (event.getEntity().getWorld() == gameWorld) {
+ game.playerDeath(event.getEntity());
+ }
+ }
+
+ @EventHandler
+ public void PlayerItemDamageEvent(PlayerItemDamageEvent event) {
+ // Remove item damage within games
+ if (event.getPlayer().getWorld() == gameWorld) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void ProjectileLaunchEvent(ProjectileLaunchEvent event) {
+ if (event.getEntity().getWorld() == gameWorld
+ && event.getEntity() instanceof Snowball
+ && event.getEntity().getShooter() instanceof Player player) {
+
+ // Prevent projectiles (snowballs) from being thrown before the game starts
+ if (Objects.equals(game.gameState, GameState.STARTING)) {
+ event.setCancelled(true);
+ }
+ else {
+ // Give players a snowball when they've used one (infinite snowballs)
+ Bukkit.getServer().getScheduler().runTask(plugin, () -> player.getInventory().addItem(new ItemStack(Material.SNOWBALL, 1)));
+ }
+ }
+ }
+
+ @EventHandler
+ public void ProjectileHitEvent(ProjectileHitEvent event) {
+ if (event.getHitBlock() == null) { return; }
+ // Removes blocks that snowballs thrown by players have hit in the game world
+ if (event.getHitBlock().getWorld() == gameWorld) {
+ if (event.getEntity() instanceof Snowball) {
+ if (event.getEntity().getShooter() instanceof Player p) {
+ if (event.getHitBlock() != null) {
+ if (event.getHitBlock().getLocation().distanceSquared(Objects.requireNonNull(game.arena.location)) < 579) {
+ p.playEffect(
+ event.getHitBlock().getLocation(),
+ Effect.STEP_SOUND,
+ event.getHitBlock().getType());
+ event.getHitBlock().setType(Material.AIR);
+ }
+ }
+ else if (event.getHitEntity() != null) {
+ if (event.getHitEntity() instanceof Player hitPlayer) {
+ // Also cancel any knockback
+ Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> hitPlayer.setVelocity(new Vector()));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @EventHandler
+ public void PlayerDropItemEvent(PlayerDropItemEvent event) {
+ // Don't allow items to drop in the game world
+ if (event.getPlayer().getWorld() == gameWorld) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void PlayerMoveEvent(PlayerMoveEvent event) {
+ // Cancel movement if the game is starting (so players can't move before the game starts)
+ if (Objects.equals(game.gameState, GameState.STARTING)
+ && event.getPlayer().getWorld().equals(gameWorld)) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void BlockDropItemEvent(BlockDropItemEvent event) {
+ // If a block was going to drop an item (ex. snow dropping snowballs) in the game world, cancel it
+ if (event.getBlock().getWorld() == gameWorld) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void PlayerInteractEvent(PlayerInteractEvent event) {
+ // Remove blocks when clicked in the game world (all gamemodes require this functionality)
+ if (event.getAction() == Action.LEFT_CLICK_BLOCK
+ && Objects.requireNonNull(event.getClickedBlock()).getWorld() == gameWorld) {
+ event.getPlayer().playEffect(
+ event.getClickedBlock().getLocation(),
+ Effect.STEP_SOUND,
+ event.getClickedBlock().getType()
+ );
+ event.getClickedBlock().setType(Material.AIR);
+ }
+ }
+
+ @EventHandler
+ public void BlockBreakEvent(BlockBreakEvent event) {
+ // This just doesn't allow blocks to break in the gameWorld; the PlayerInteractEvent will take care of everything
+ // This prevents any weird client-server desync
+ if (event.getBlock().getWorld() == gameWorld) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void FoodLevelChangeEvent(FoodLevelChangeEvent event) {
+ // INFINITE FOOD (YAY!!!!)
+ if (event.getEntity().getWorld() == gameWorld) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void EntityDamageEvent(EntityDamageEvent event) {
+ // Check to see if a player got damaged by another entity (player, snowball, etc) in the gameWorld, if so, cancel it
+ if (event.getEntity().getWorld() == gameWorld) {
+ if (event.getEntity() instanceof Player) {
+ if (event.getCause() == EntityDamageEvent.DamageCause.ENTITY_ATTACK
+ && event.getCause() == EntityDamageEvent.DamageCause.ENTITY_SWEEP_ATTACK
+ && event.getCause() == EntityDamageEvent.DamageCause.FALL) {
+ event.setCancelled(true);
+ }
+ }
+ }
+ }
+
+ @EventHandler
+ public void InventoryDragEvent(InventoryDragEvent event) {
+ if (event.getWhoClicked().getWorld() == gameWorld) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void PlayerRespwanEvent(PlayerRespawnEvent event) {
+ // Make sure players respawn in the correct location
+ if (game.gamePlayers.contains(event.getPlayer())) {
+ event.setRespawnLocation(game.arena.location);
+ }
+ }
+
+ // TODO: stop tile drops for pistons
+}
diff --git a/src/main/java/com/MylesAndMore/Tumble/game/Game.java b/src/main/java/com/MylesAndMore/Tumble/game/Game.java
index cdaede9..8fa9289 100644
--- a/src/main/java/com/MylesAndMore/Tumble/game/Game.java
+++ b/src/main/java/com/MylesAndMore/Tumble/game/Game.java
@@ -1,113 +1,222 @@
package com.MylesAndMore.Tumble.game;
-import com.MylesAndMore.Tumble.plugin.Constants;
-
+import com.MylesAndMore.Tumble.plugin.ConfigManager;
+import com.MylesAndMore.Tumble.plugin.GameState;
+import com.MylesAndMore.Tumble.plugin.GameType;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.*;
import org.bukkit.enchantments.Enchantment;
-import org.bukkit.entity.Entity;
-import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
+import org.bukkit.event.HandlerList;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
+import static com.MylesAndMore.Tumble.Main.plugin;
+
/**
* Everything relating to the Tumble game
*/
public class Game {
- // Singleton class logic
- private static Game gameInstance;
- private Game() {
- gameWorld = Bukkit.getWorld(Constants.getGameWorld());
- gameSpawn = Objects.requireNonNull(gameWorld).getSpawnLocation();
- }
- public static Game getGame() {
- if (gameInstance == null) {
- gameInstance = new Game();
- }
- return gameInstance;
- }
- // Define local game vars
- private String gameState;
- private String gameType;
+ public final GameType type;
+ public final Arena arena;
+ public final World gameWorld;
+ public final List<Player> gamePlayers = new ArrayList<>();
+ private final Location gameSpawn;
+ private final HashMap<Player, Integer> gameWins = new HashMap<>();
+ public GameState gameState = GameState.WAITING;
+ public GameType roundType;
private int gameID = -1;
private int autoStartID = -1;
- private final World gameWorld;
- private final Location gameSpawn;
- private List<Player> gamePlayers;
- private List<Player> roundPlayers;
- private List<Integer> gameWins;
+ private List<Player> playersAlive;
+ private EventListener eventListener;
+
+ public Game(@NotNull Arena arena, @NotNull GameType type) {
+ this.arena = arena;
+ this.type = type;
+ this.gameWorld = arena.world;
+ this.gameSpawn = arena.location;
- private final Random Random = new Random();
+ }
/**
* Creates a new Game
- * @param type The type of game
- * @return true if the game succeeds creation, and false if not
*/
- public boolean startGame(@NotNull String type) {
+ public void startGame() {
+
// Check if the game is starting or running
- if (Objects.equals(gameState, "starting")) { return false; }
- else if (Objects.equals(gameState, "running")) { return false; }
+ if (gameState != GameState.WAITING) {
+ return;
+ }
+
+ Bukkit.getServer().getScheduler().cancelTask(autoStartID);
+ autoStartID = -1;
+// if (waitingPlayers.size() < 2) {
+// return false;
+// }
+
+ eventListener = new EventListener(this);
+ Bukkit.getServer().getPluginManager().registerEvents(eventListener, plugin);
+
+ // clear area in case it did not get properly cleared
+ roundStart();
+ }
+
+ /**
+ * Starts a new round
+ */
+ private void roundStart() {
+ gameState = GameState.STARTING;
+ playersAlive = new ArrayList<>(gamePlayers);
+ // Put all players in spectator to prevent them from getting kicked for flying
+ setGamemode(gamePlayers, GameMode.SPECTATOR);
+ scatterPlayers(gamePlayers);
+ clearInventories(gamePlayers);
+ clearArena();
+ prepareGameType(type);
+ Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
+ // Begin the countdown sequence
+ countdown(() -> {
+ setGamemode(gamePlayers, GameMode.SURVIVAL);
+ gameState = GameState.RUNNING;
+ });
+ }, 100);
+ }
+
+ /**
+ * Type specific setup: Generating layers and giving items
+ * @param type can be either "shovels", "snowballs", or "mixed"
+ */
+ private void prepareGameType(GameType type) {
+ roundType = type; // note: may need deepcopy this for it to work properly
+ if (roundType.equals(GameType.MIXED)) {
+ // Randomly select either shovels or snowballs and re-run the method
+ Random random = new Random();
+ switch (random.nextInt(2)) {
+ case 0 -> roundType = GameType.SHOVELS;
+ case 1 -> roundType = GameType.SNOWBALLS;
+ }
+ }
+
+ switch (roundType) {
+ case SHOVELS -> {
+ Generator.generateLayersShovels(gameSpawn.clone());
+ ItemStack shovel = new ItemStack(Material.IRON_SHOVEL);
+ shovel.addEnchantment(Enchantment.SILK_TOUCH, 1);
+ giveItems(gamePlayers, shovel);
+ // Schedule a process to give snowballs after 2m30s (so people can't island, the OG game had this); add 160t because of the countdown
+ gameID = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
+ clearInventories(gamePlayers);
+ giveItems(gamePlayers, new ItemStack(Material.SNOWBALL));
+ displayActionbar(gamePlayers, ChatColor.DARK_RED + "Showdown!");
+ playSound(gamePlayers, Sound.ENTITY_ELDER_GUARDIAN_CURSE, SoundCategory.HOSTILE, 1, 1);
+ // End the round in another 2m30s
+ gameID = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, this::roundEnd, 3000);
+ }, 3160);
+ }
+ case SNOWBALLS -> {
+ Generator.generateLayersSnowballs(gameSpawn.clone());
+ giveItems(gamePlayers, new ItemStack(Material.SNOWBALL));
+
+ // End the round in 5m
+ gameID = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, this::roundEnd, 6160);
+ }
+ }
+ }
+
+ /**
+ * Round end stuff: Finds and displays winner, starts next round if necessary
+ */
+ private void roundEnd() {
+ // Cancel the tasks that auto-end the round
+ Bukkit.getServer().getScheduler().cancelTask(gameID);
+ // Clear old layers (as a fill command, this would be /fill ~-20 ~-20 ~-20 ~20 ~ ~20 relative to spawn)
+ playSound(gamePlayers, Sound.BLOCK_NOTE_BLOCK_PLING, SoundCategory.BLOCKS, 5, 0);
+ // Check if there was a definite winner or not
+ if (!playersAlive.isEmpty()) {
+ Player winner = playersAlive.get(0);
+ // Set the wins of the player to their current # of wins + 1
+ if (!gameWins.containsKey(winner)) {
+ gameWins.put(winner, 0);
+ }
+ gameWins.put(winner, gameWins.get(winner)+1);
+ if (gameWins.get(winner) == 3) {
+ gameEnd();
+ }
+ // If that player doesn't have three wins, nobody else does, so we need another round
+ else {
+ displayTitles(gamePlayers, ChatColor.RED + "Round over!", ChatColor.GOLD + winner.getName() + " has won the round!", 5, 60, 5);
+ Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, this::roundStart, 100);
+ }
+ }
else {
- // Define the gameType
- switch (type) {
- case "shovels", "snowballs", "mixed" -> {
- gameState = "starting";
- // Set the type to gameType since it won't change for this mode
- gameType = type;
- // Clear the players' inventories so they can't bring any items into the game
- clearInventories(Constants.getPlayersInLobby());
- // Generate the correct layers for a Shovels game
- // The else statement is just in case the generator fails; this command will fail
- if (generateLayers(type)) {
- // Send all players from lobby to the game
- scatterPlayers(Constants.getPlayersInLobby());
- } else {
- return false;
- }
+ displayTitles(gamePlayers, ChatColor.RED + "Round over!", ChatColor.GOLD + "Draw!", 5, 60, 5);
+ Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, this::roundStart, 100);
+ }
+ }
+
+ /**
+ * Game end stuff: Displays overall winner and teleports players to lobby
+ */
+ private void gameEnd() {
+ if (!gamePlayers.isEmpty()) {
+ Player winner = getPlayerWithMostWins(gameWins);
+ setGamemode(gamePlayers, GameMode.SPECTATOR);
+ clearInventories(gamePlayers);
+ if (winner != null) {
+ displayTitles(gamePlayers, ChatColor.RED + "Game over!", ChatColor.GOLD + winner.getName() + " has won the game!", 5, 60, 5);
+ }
+ displayActionbar(gamePlayers, ChatColor.BLUE + "Returning to lobby in ten seconds...");
+ // Wait 10s (200t), then
+ Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
+ // First, check to see if there is a separate location to tp the winner to
+ if (ConfigManager.winnerLobby != null && winner != null) {
+ winner.teleport(ConfigManager.winnerLobby);
+ // Remove the winner from the game so they don't get double-tp'd
+ gamePlayers.remove(winner);
}
- default -> {
- // The game type in the config did not match a specified game type
- return false;
+ // Send all players back to lobby (spawn)
+ for (Player aPlayer : gamePlayers) {
+ aPlayer.teleport(Objects.requireNonNull(ConfigManager.lobby));
}
- }
- // Update the game/round players for later
- gamePlayers = new ArrayList<>(Constants.getPlayersInGame());
- roundPlayers = new ArrayList<>(Constants.getPlayersInGame());
- // Create a list that will later keep track of each player's wins
- gameWins = new ArrayList<>();
- gameWins.addAll(List.of(0,0,0,0,0,0,0,0));
- // Put all players in spectator to prevent them from getting kicked for flying (this needs a delay bc servers are slow)
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> setGamemode(gamePlayers, GameMode.SPECTATOR), 25);
- // Wait 5s (100t) for the clients to load in
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> {
- // Begin the countdown sequence
- playSound(gamePlayers, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.NEUTRAL, 5, 1);
- displayTitles(gamePlayers, ChatColor.DARK_GREEN + "3", null, 3, 10, 7);
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> {
- playSound(gamePlayers, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.NEUTRAL, 5, 1);
- displayTitles(gamePlayers, ChatColor.YELLOW + "2", null, 3, 10, 7);
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> {
- playSound(gamePlayers, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.NEUTRAL, 5, 1);
- displayTitles(gamePlayers, ChatColor.DARK_RED + "1", null, 3, 10, 7);
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> {
- playSound(gamePlayers, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.NEUTRAL, 5, 2);
- displayTitles(gamePlayers, ChatColor.GREEN + "Go!", null, 1, 5, 1);
- setGamemode(gamePlayers, GameMode.SURVIVAL);
- gameState = "running";
- }, 20);
- }, 20);
- }, 20);
- }, 100);
+ }, 200);
+ }
+ HandlerList.unregisterAll(eventListener);
+ arena.game = null;
+ }
+
+ /**
+ * Force stops a game
+ */
+ public void killGame() {
+ Bukkit.getServer().getScheduler().cancelTask(gameID);
+ HandlerList.unregisterAll(eventListener);
+ arena.game = null;
+ }
+
+ /**
+ * Removes a player from the game
+ * Called when a player leaves the server, or if they issue the leave command
+ * @param p Player to remove
+ */
+ public void removePlayer(Player p) {
+ gamePlayers.remove(p);
+ if (gamePlayers.size() < 2) {
+ gameEnd();
+ }
+ p.teleport(ConfigManager.lobby);
+ }
+
+ public void addPlayer(Player p) {
+ gamePlayers.add(p);
+ if (gamePlayers.size() >= 2 && gameState == GameState.WAITING) {
+ autoStart();
}
- return true;
}
/**
@@ -115,217 +224,92 @@ public class Game {
*/
public void autoStart() {
// Wait for the player to load in
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> {
- gameState = "waiting";
- displayActionbar(Constants.getPlayersInLobby(), ChatColor.GREEN + "Game will begin in 15 seconds!");
- playSound(Constants.getPlayersInLobby(), Sound.BLOCK_NOTE_BLOCK_CHIME, SoundCategory.BLOCKS, 1, 1);
- Constants.getMVWorldManager().loadWorld(Constants.getGameWorld());
+ Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
+ displayActionbar(gamePlayers, ChatColor.GREEN + "Game will begin in 15 seconds!");
+ playSound(gamePlayers, Sound.BLOCK_NOTE_BLOCK_CHIME, SoundCategory.BLOCKS, 1, 1);
// Schedule a process to start the game in 300t (15s) and save the PID so we can cancel it later if needed
- autoStartID = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> startGame(Constants.getGameType()), 300);
+ autoStartID = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, this::startGame, 300);
}, 50);
}
/**
- * Cancels a "waiting" automatic start
- */
- public void cancelStart() {
- Bukkit.getServer().getScheduler().cancelTask(Game.getGame().getAutoStartID());
- displayActionbar(Constants.getPlayersInLobby(), ChatColor.RED + "Game start cancelled!");
- playSound(Constants.getPlayersInLobby(), Sound.BLOCK_NOTE_BLOCK_BASS, SoundCategory.BLOCKS, 1, 1);
- gameState = null;
- autoStartID = -1;
- }
-
- /**
* This method should be called on the death of one of the Game's players
* @param player The player who died
*/
public void playerDeath(Player player) {
player.setGameMode(GameMode.SPECTATOR);
- // Add a delay to tp them to the gameWorld just in case they have a bed in another world (yes you Jacob)
- // Delay is needed because instant respawn is a lie (it's not actually instant)
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> {
- player.teleport(gameSpawn);
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> player.setGameMode(GameMode.SPECTATOR), 5);
- }, 5);
// remove that player (who just died) from the roundPlayersArray, effectively eliminating them,
- roundPlayers.remove(player);
+ playersAlive.remove(player);
// If there are less than 2 players in the game (1 just died),
- if (roundPlayers.size() < 2) {
- roundEnd(roundPlayers.get(0));
+ if (playersAlive.size() < 2) {
+ roundEnd();
}
}
- // Methods to get the game type and game state for other classes outside the Game
+ // utility functions
/**
- * @return The game's current state as a String ("waiting", "starting", "running", "complete")
- * Can also be null if not initialized.
+ * Teleports a list of players to the specified scatter locations in the gameWorld
+ * @param players a List of Players to teleport
*/
- public String getGameState() { return gameState; }
+ private void scatterPlayers(List<Player> players) {
+ double x = gameSpawn.getX();
+ double y = gameSpawn.getY();
+ double z = gameSpawn.getZ();
+ // Create the scatter locations based off the game's spawn
+ List<Location> scatterLocations = new ArrayList<>(List.of(
+ new Location(gameWorld, (x - 14.5), y, (z + 0.5), -90, 0),
+ new Location(gameWorld, (x + 0.5), y, (z - 14.5), 0, 0),
+ new Location(gameWorld, (x + 15.5), y, (z + 0.5), 90, 0),
+ new Location(gameWorld, (x + 0.5), y, (z + 15.5), 180, 0),
+ new Location(gameWorld, (x - 10.5), y, (z - 10.5), -45, 0),
+ new Location(gameWorld, (x - 10.5), y, (z + 11.5), -135, 0),
+ new Location(gameWorld, (x + 11.5), y, (z - 10.5), 45, 0),
+ new Location(gameWorld, (x + 11.5), y, (z + 11.5), 135, 0)));
+ Collections.shuffle(scatterLocations);
+ for (Player aPlayer : players) {
+ if (!aPlayer.teleport(scatterLocations.get(0))) {
+ plugin.getLogger().info("dbg: FAILED TELEPORT");
+ }
+ scatterLocations.remove(0); // Remove that location so multiple players won't get the same one
+ }
+ }
/**
- * @return The Bukkit process ID of the autostart process, if applicable
- * Can also be null if not initialized, or -1 if the process failed to schedule.
+ * Displays the 3, 2, 1 countdown
+ * @param doAfter Will be executed after the countdown
*/
- public int getAutoStartID() { return autoStartID; }
-
+ private void countdown(Runnable doAfter) {
+ playSound(gamePlayers, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.NEUTRAL, 5, 1);
+ displayTitles(gamePlayers, ChatColor.DARK_GREEN + "3", null, 3, 10, 7);
+ Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
+ playSound(gamePlayers, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.NEUTRAL, 5, 1);
+ displayTitles(gamePlayers, ChatColor.YELLOW + "2", null, 3, 10, 7);
+ Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
+ playSound(gamePlayers, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.NEUTRAL, 5, 1);
+ displayTitles(gamePlayers, ChatColor.DARK_RED + "1", null, 3, 10, 7);
+ Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
+ playSound(gamePlayers, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.NEUTRAL, 5, 2);
+ displayTitles(gamePlayers, ChatColor.GREEN + "Go!", null, 1, 5, 1);
+ doAfter.run();
+ }, 20);
+ }, 20);
+ }, 20);
+ }
- private final Layers layers = new Layers();
/**
- * Generates the layers in the gameWorld for a certain gameType
- * @param type can be either "shovels", "snowballs", or "mixed", anything else will fail generation
- * @return true if gameType was recognized and layers were (hopefully) generated, false if unrecognized
+ * Finds the player with the most wins
+ * @param list List of players and their number of wins
+ * @return Player with the most wins
*/
- private boolean generateLayers(String type) {
- // Create a new Location for the layers to work with--this is so that we don't modify the actual gameSpawn var
- Location layer = new Location(gameSpawn.getWorld(), gameSpawn.getX(), gameSpawn.getY(), gameSpawn.getZ(), gameSpawn.getYaw(), gameSpawn.getPitch());
- if (Objects.equals(type, "shovels")) {
- layer.setY(layer.getY() - 1);
- // Choose a random type of generation; a circular layer, a square layer, or a multi-tiered layer of either variety
- if (Random.nextInt(4) == 0) {
- // Circular layer
- Generator.generateClumps(Generator.generateLayer(layer, 17, 1, Material.SNOW_BLOCK), layers.getSafeMaterialList());
- }
- else if (Random.nextInt(4) == 1) {
- // Square layer
- Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 17, layer.getY(), layer.getZ() - 17), new Location(layer.getWorld(), layer.getX() + 17, layer.getY(), layer.getZ() + 17), Material.SNOW_BLOCK), layers.getSafeMaterialList());
+ private Player getPlayerWithMostWins(HashMap<Player, Integer> list) {
+ Player largest = null;
+ for (Player p: list.keySet()) {
+ if (largest == null || list.get(p) > list.get(largest)) {
+ largest = p;
}
- else if (Random.nextInt(4) == 2) {
- // Multi-tiered circle
- Generator.generateClumps(Generator.generateLayer(layer, 17, 1, Material.SNOW_BLOCK), layers.getSafeMaterialList());
- Generator.generateLayer(layer, 13, 1, Material.AIR);
- layer.setY(layer.getY() - 1);
- Generator.generateClumps(Generator.generateLayer(layer, 13, 1, Material.GRASS_BLOCK), layers.getMaterialList());
- Generator.generateLayer(layer, 4, 1, Material.AIR);
- layer.setY(layer.getY() - 1);
- Generator.generateClumps(Generator.generateLayer(layer, 4, 1, Material.PODZOL), layers.getMaterialList());
- }
- else {
- // Multi-tiered square
- Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 17, layer.getY(), layer.getZ() - 17), new Location(layer.getWorld(), layer.getX() + 17, layer.getY(), layer.getZ() + 17), Material.SNOW_BLOCK), layers.getSafeMaterialList());
- Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 13, layer.getY(), layer.getZ() - 13), new Location(layer.getWorld(), layer.getX() + 13, layer.getY(), layer.getZ() + 13), Material.AIR);
- layer.setY(layer.getY() - 1);
- Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 13, layer.getY(), layer.getZ() - 13), new Location(layer.getWorld(), layer.getX() + 13, layer.getY(), layer.getZ() + 13), Material.GRASS_BLOCK), layers.getMaterialList());
- Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 7, layer.getY(), layer.getZ() - 7), new Location(layer.getWorld(), layer.getX() + 7, layer.getY(), layer.getZ() + 7), Material.AIR);
- layer.setY(layer.getY() - 1);
- Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 7, layer.getY(), layer.getZ() - 7), new Location(layer.getWorld(), layer.getX() + 7, layer.getY(), layer.getZ() + 7), Material.PODZOL), layers.getMaterialList());
- }
- ItemStack shovel = new ItemStack(Material.IRON_SHOVEL);
- shovel.addEnchantment(Enchantment.SILK_TOUCH, 1);
- if (Objects.equals(gameState, "running")) {
- giveItems(Constants.getPlayersInGame(), shovel);
- }
- else if (Objects.equals(gameState, "starting")) {
- giveItems(Constants.getPlayersInLobby(), shovel);
- }
- // Schedule a process to give snowballs after 2m30s (so people can't island, the OG game had this); add 160t because of the countdown
- gameID = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> {
- clearInventories(gamePlayers);
- giveItems(gamePlayers, new ItemStack(Material.SNOWBALL));
- displayActionbar(gamePlayers, ChatColor.DARK_RED + "Showdown!");
- playSound(gamePlayers, Sound.ENTITY_ELDER_GUARDIAN_CURSE, SoundCategory.HOSTILE, 1, 1);
- // End the round in another 2m30s
- gameID = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> roundEnd(null), 3000);
- }, 3160);
}
- else if (Objects.equals(type, "snowballs")) {
- layer.setY(layer.getY() - 1);
- // Similar generation to shovels, except there are three layers
- if (Random.nextInt(4) == 0) {
- // Circular layer
- Generator.generateClumps(Generator.generateLayer(layer, 17, 1, Material.STONE), layers.getSafeMaterialList());
- layer.setY(layer.getY() - 6);
- Generator.generateClumps(Generator.generateLayer(layer, 17, 1, Material.STONE), layers.getMaterialList());
- layer.setY(layer.getY() - 6);
- Generator.generateClumps(Generator.generateLayer(layer, 17, 1, Material.STONE), layers.getMaterialList());
- }
- else if (Random.nextInt(4) == 1) {
- // Square layer
- Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 17, layer.getY(), layer.getZ() - 17), new Location(layer.getWorld(), layer.getX() + 17, layer.getY(), layer.getZ() + 17), Material.STONE), layers.getSafeMaterialList());
- layer.setY(layer.getY() - 6);
- Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 17, layer.getY(), layer.getZ() - 17), new Location(layer.getWorld(), layer.getX() + 17, layer.getY(), layer.getZ() + 17), Material.STONE), layers.getMaterialList());
- layer.setY(layer.getY() - 6);
- Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 17, layer.getY(), layer.getZ() - 17), new Location(layer.getWorld(), layer.getX() + 17, layer.getY(), layer.getZ() + 17), Material.STONE), layers.getMaterialList());
- }
- else if (Random.nextInt(4) == 2) {
- // Multi-tiered circle
- Generator.generateClumps(Generator.generateLayer(layer, 17, 1, Material.STONE), layers.getSafeMaterialList());
- Generator.generateLayer(layer, 13, 1, Material.AIR);
- layer.setY(layer.getY() - 1);
- Generator.generateClumps(Generator.generateLayer(layer, 13, 1, Material.GRANITE), layers.getMaterialList());
- Generator.generateLayer(layer, 4, 1, Material.AIR);
- layer.setY(layer.getY() - 1);
- Generator.generateClumps(Generator.generateLayer(layer, 4, 1, Material.LIME_GLAZED_TERRACOTTA), layers.getMaterialList());
- layer.setY(layer.getY() - 6);
-
- Generator.generateClumps(Generator.generateLayer(layer, 17, 1, Material.STONE), layers.getSafeMaterialList());
- Generator.generateLayer(layer, 13, 1, Material.AIR);
- layer.setY(layer.getY() - 1);
- Generator.generateClumps(Generator.generateLayer(layer, 13, 1, Material.GRANITE), layers.getMaterialList());
- Generator.generateLayer(layer, 4, 1, Material.AIR);
- layer.setY(layer.getY() - 1);
- Generator.generateClumps(Generator.generateLayer(layer, 4, 1, Material.LIME_GLAZED_TERRACOTTA), layers.getMaterialList());
- layer.setY(layer.getY() - 6);
-
- Generator.generateClumps(Generator.generateLayer(layer, 17, 1, Material.STONE), layers.getSafeMaterialList());
- Generator.generateLayer(layer, 13, 1, Material.AIR);
- layer.setY(layer.getY() - 1);
- Generator.generateClumps(Generator.generateLayer(layer, 13, 1, Material.GRANITE), layers.getMaterialList());
- Generator.generateLayer(layer, 4, 1, Material.AIR);
- layer.setY(layer.getY() - 1);
- Generator.generateClumps(Generator.generateLayer(layer, 4, 1, Material.LIME_GLAZED_TERRACOTTA), layers.getMaterialList());
- }
- else {
- // Multi-tiered square
- Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 17, layer.getY(), layer.getZ() - 17), new Location(layer.getWorld(), layer.getX() + 17, layer.getY(), layer.getZ() + 17), Material.STONE), layers.getSafeMaterialList());
- Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 13, layer.getY(), layer.getZ() - 13), new Location(layer.getWorld(), layer.getX() + 13, layer.getY(), layer.getZ() + 13), Material.AIR);
- layer.setY(layer.getY() - 1);
- Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 13, layer.getY(), layer.getZ() - 13), new Location(layer.getWorld(), layer.getX() + 13, layer.getY(), layer.getZ() + 13), Material.GRANITE), layers.getMaterialList());
- Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 7, layer.getY(), layer.getZ() - 7), new Location(layer.getWorld(), layer.getX() + 7, layer.getY(), layer.getZ() + 7), Material.AIR);
- layer.setY(layer.getY() - 1);
- Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 7, layer.getY(), layer.getZ() - 7), new Location(layer.getWorld(), layer.getX() + 7, layer.getY(), layer.getZ() + 7), Material.LIME_GLAZED_TERRACOTTA), layers.getMaterialList());
- layer.setY(layer.getY() - 6);
-
- Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 17, layer.getY(), layer.getZ() - 17), new Location(layer.getWorld(), layer.getX() + 17, layer.getY(), layer.getZ() + 17), Material.STONE), layers.getSafeMaterialList());
- Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 13, layer.getY(), layer.getZ() - 13), new Location(layer.getWorld(), layer.getX() + 13, layer.getY(), layer.getZ() + 13), Material.AIR);
- layer.setY(layer.getY() - 1);
- Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 13, layer.getY(), layer.getZ() - 13), new Location(layer.getWorld(), layer.getX() + 13, layer.getY(), layer.getZ() + 13), Material.GRANITE), layers.getMaterialList());
- Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 7, layer.getY(), layer.getZ() - 7), new Location(layer.getWorld(), layer.getX() + 7, layer.getY(), layer.getZ() + 7), Material.AIR);
- layer.setY(layer.getY() - 1);
- Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 7, layer.getY(), layer.getZ() - 7), new Location(layer.getWorld(), layer.getX() + 7, layer.getY(), layer.getZ() + 7), Material.LIME_GLAZED_TERRACOTTA), layers.getMaterialList());
- layer.setY(layer.getY() - 6);
-
- Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 17, layer.getY(), layer.getZ() - 17), new Location(layer.getWorld(), layer.getX() + 17, layer.getY(), layer.getZ() + 17), Material.STONE), layers.getSafeMaterialList());
- Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 13, layer.getY(), layer.getZ() - 13), new Location(layer.getWorld(), layer.getX() + 13, layer.getY(), layer.getZ() + 13), Material.AIR);
- layer.setY(layer.getY() - 1);
- Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 13, layer.getY(), layer.getZ() - 13), new Location(layer.getWorld(), layer.getX() + 13, layer.getY(), layer.getZ() + 13), Material.GRANITE), layers.getMaterialList());
- Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 7, layer.getY(), layer.getZ() - 7), new Location(layer.getWorld(), layer.getX() + 7, layer.getY(), layer.getZ() + 7), Material.AIR);
- layer.setY(layer.getY() - 1);
- Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 7, layer.getY(), layer.getZ() - 7), new Location(layer.getWorld(), layer.getX() + 7, layer.getY(), layer.getZ() + 7), Material.LIME_GLAZED_TERRACOTTA), layers.getMaterialList());
- }
- if (Objects.equals(gameState, "running")) {
- giveItems(Constants.getPlayersInGame(), new ItemStack(Material.SNOWBALL));
- }
- else if (Objects.equals(gameState, "starting")) {
- giveItems(Constants.getPlayersInLobby(), new ItemStack(Material.SNOWBALL));
- }
- // End the round in 5m
- gameID = Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> roundEnd(null), 6160);
- }
- else if (Objects.equals(type, "mixed")) {
- // Randomly select either shovels or snowballs and re-run the method
- if (Random.nextInt(2) == 0) {
- generateLayers("shovels");
- } else {
- generateLayers("snowballs");
- }
- }
- // Game type was invalid
- else {
- return false;
- }
- return true;
+ return largest;
}
/**
@@ -401,139 +385,13 @@ public class Game {
}
/**
- * Teleports a list of players to the specified scatter locations in the gameWorld
- * @param players a List of Players to teleport
+ * Clears old layers
+ * (as a fill command, this would be /fill ~-20 ~-20 ~-20 ~20 ~ ~20 relative to spawn)
*/
- private void scatterPlayers(List<Player> players) {
- double x = gameSpawn.getX();
- double y = gameSpawn.getY();
- double z = gameSpawn.getZ();
- // Create the scatter locations based off the game's spawn
- List<Location> scatterLocations = new ArrayList<>(List.of(
- new Location(gameWorld, (x - 14.5), y, (z + 0.5), -90, 0),
- new Location(gameWorld, (x + 0.5), y, (z - 14.5), 0, 0),
- new Location(gameWorld, (x + 15.5), y, (z + 0.5), 90, 0),
- new Location(gameWorld, (x + 0.5), y, (z + 15.5), 180, 0),
- new Location(gameWorld, (x - 10.5), y, (z - 10.5), -45, 0),
- new Location(gameWorld, (x - 10.5), y, (z + 11.5), -135, 0),
- new Location(gameWorld, (x + 11.5), y, (z - 10.5), 45, 0),
- new Location(gameWorld, (x + 11.5), y, (z + 11.5), 135, 0)));
- Collections.shuffle(scatterLocations);
- for (Player aPlayer : players) {
- aPlayer.teleport(scatterLocations.get(0));
- scatterLocations.remove(0); // Remove that location so multiple players won't get the same one
- }
- }
-
- private void roundEnd(@Nullable Player winner) {
- // Cancel the tasks that auto-end the round
- Bukkit.getServer().getScheduler().cancelTask(gameID);
- // Clear old layers (as a fill command, this would be /fill ~-20 ~-20 ~-20 ~20 ~ ~20 relative to spawn)
- Generator.generateCuboid(new Location(gameSpawn.getWorld(), gameSpawn.getX() - 20, gameSpawn.getY() - 20, gameSpawn.getZ() - 20), new Location(gameSpawn.getWorld(), gameSpawn.getX() + 20, gameSpawn.getY(), gameSpawn.getZ() + 20), Material.AIR);
- playSound(gamePlayers, Sound.BLOCK_NOTE_BLOCK_PLING, SoundCategory.BLOCKS, 5, 0);
- // Check if there was a definite winner or not
- if (winner != null) {
- // Set the wins of the player to their current # of wins + 1
- gameWins.set(gamePlayers.indexOf(winner), (gameWins.get(gamePlayers.indexOf(winner)) + 1));
- // If the player has three wins, they won the game, so initiate the gameEnd
- if (gameWins.get(gamePlayers.indexOf(winner)) == 3) {
- gameEnd(winner);
- }
- // If that player doesn't have three wins, nobody else does, so we need another round
- else {
- roundPlayers.get(0).setGameMode(GameMode.SPECTATOR);
- roundPlayers.remove(0);
- roundPlayers.addAll(gamePlayers);
- clearInventories(gamePlayers);
- displayTitles(gamePlayers, ChatColor.RED + "Round over!", ChatColor.GOLD + winner.getName() + " has won the round!", 5, 60, 5);
- // Wait for the player to respawn before completely lagging the server ._.
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> {
- generateLayers(gameType);
- // Wait 5s (100t) for tp method
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> {
- // Kill all items (pistons are weird)
- for (Entity entity : gameWorld.getEntities()) {
- if (entity instanceof Item) {
- entity.remove();
- }
- }
- gameState = "starting";
- scatterPlayers(gamePlayers);
- playSound(gamePlayers, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.NEUTRAL, 5, 1);
- displayTitles(gamePlayers, ChatColor.DARK_GREEN + "3", null, 3, 10, 7);
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> {
- playSound(gamePlayers, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.NEUTRAL, 5, 1);
- displayTitles(gamePlayers, ChatColor.YELLOW + "2", null, 3, 10, 7);
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> {
- playSound(gamePlayers, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.NEUTRAL, 5, 1);
- displayTitles(gamePlayers, ChatColor.DARK_RED + "1", null, 3, 10, 7);
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> {
- playSound(gamePlayers, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.NEUTRAL, 5, 2);
- displayTitles(gamePlayers, ChatColor.GREEN + "Go!", null, 1, 5, 1);
- setGamemode(gamePlayers, GameMode.SURVIVAL);
- gameState = "running";
- }, 20);
- }, 20);
- }, 20);
- }, 100);
- }, 1);
- }
- }
- else {
- setGamemode(gamePlayers, GameMode.SPECTATOR);
- roundPlayers.clear();
- roundPlayers.addAll(gamePlayers);
- clearInventories(gamePlayers);
- displayTitles(gamePlayers, ChatColor.RED + "Round over!", ChatColor.GOLD + "Draw!", 5, 60, 5);
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> {
- generateLayers(gameType);
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> {
- for (Entity entity : gameWorld.getEntities()) {
- if (entity instanceof Item) {
- entity.remove();
- }
- }
- gameState = "starting";
- scatterPlayers(gamePlayers);
- playSound(gamePlayers, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.NEUTRAL, 5, 1);
- displayTitles(gamePlayers, ChatColor.DARK_GREEN + "3", null, 3, 10, 7);
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> {
- playSound(gamePlayers, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.NEUTRAL, 5, 1);
- displayTitles(gamePlayers, ChatColor.YELLOW + "2", null, 3, 10, 7);
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> {
- playSound(gamePlayers, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.NEUTRAL, 5, 1);
- displayTitles(gamePlayers, ChatColor.DARK_RED + "1", null, 3, 10, 7);
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> {
- playSound(gamePlayers, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, SoundCategory.NEUTRAL, 5, 2);
- displayTitles(gamePlayers, ChatColor.GREEN + "Go!", null, 1, 5, 1);
- setGamemode(gamePlayers, GameMode.SURVIVAL);
- gameState = "running";
- }, 20);
- }, 20);
- }, 20);
- }, 100);
- }, 1);
- }
- }
-
- private void gameEnd(Player winner) {
- winner.setGameMode(GameMode.SPECTATOR);
- clearInventories(gamePlayers);
- displayTitles(gamePlayers, ChatColor.RED + "Game over!", ChatColor.GOLD + winner.getName() + " has won the game!", 5, 60, 5);
- displayActionbar(gamePlayers, ChatColor.BLUE + "Returning to lobby in ten seconds...");
- // Wait 10s (200t), then
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> {
- // First, check to see if there is a separate location to tp the winner to
- if ((Constants.getPlugin().getConfig().getDouble("winnerTeleport.x") != 0) && (Constants.getPlugin().getConfig().getDouble("winnerTeleport.y") != 0) && (Constants.getPlugin().getConfig().getDouble("winnerTeleport.z") != 0)) {
- winner.teleport(new Location(Bukkit.getWorld(Constants.getLobbyWorld()), Constants.getPlugin().getConfig().getDouble("winnerTeleport.x"), Constants.getPlugin().getConfig().getDouble("winnerTeleport.y"), Constants.getPlugin().getConfig().getDouble("winnerTeleport.z")));
- // Remove the winner from the gamePlayers so they don't get double-tp'd
- gamePlayers.remove(winner);
- }
- // Send all players back to lobby (spawn)
- for (Player aPlayer : gamePlayers) {
- aPlayer.teleport(Objects.requireNonNull(Bukkit.getWorld(Constants.getLobbyWorld())).getSpawnLocation());
- }
- }, 200);
- gameState = "complete";
+ private void clearArena() {
+ Generator.generateCuboid(
+ new Location(gameSpawn.getWorld(), gameSpawn.getX() - 20, gameSpawn.getY() - 20, gameSpawn.getZ() - 20),
+ new Location(gameSpawn.getWorld(), gameSpawn.getX() + 20, gameSpawn.getY(), gameSpawn.getZ() + 20),
+ Material.AIR);
}
}
diff --git a/src/main/java/com/MylesAndMore/Tumble/game/Generator.java b/src/main/java/com/MylesAndMore/Tumble/game/Generator.java
index ecaa1b7..c8ecb06 100644
--- a/src/main/java/com/MylesAndMore/Tumble/game/Generator.java
+++ b/src/main/java/com/MylesAndMore/Tumble/game/Generator.java
@@ -1,8 +1,6 @@
package com.MylesAndMore.Tumble.game;
-import org.bukkit.Location;
-import org.bukkit.Material;
-import org.bukkit.World;
+import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
@@ -12,6 +10,131 @@ import java.util.*;
* Holds the methods that generate blocks in-game such as cylinders, cuboids, and block clumps.
*/
public class Generator {
+
+ /**
+ * Generates layers for a round of type shovels
+ * @param layer Location where the layers should start
+ */
+ public static void generateLayersShovels(Location layer) {
+ Random random = new Random();
+ Layers layers = new Layers();
+
+ layer.setY(layer.getY() - 1);
+ // Choose a random type of generation; a circular layer, a square layer, or a multi-tiered layer of either variety
+ if (random.nextInt(4) == 0) {
+ // Circular layer
+ Generator.generateClumps(Generator.generateLayer(layer, 17, 1, Material.SNOW_BLOCK), layers.getSafeMaterialList());
+ }
+ else if (random.nextInt(4) == 1) {
+ // Square layer
+ Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 17, layer.getY(), layer.getZ() - 17), new Location(layer.getWorld(), layer.getX() + 17, layer.getY(), layer.getZ() + 17), Material.SNOW_BLOCK), layers.getSafeMaterialList());
+ }
+ else if (random.nextInt(4) == 2) {
+ // Multi-tiered circle
+ Generator.generateClumps(Generator.generateLayer(layer, 17, 1, Material.SNOW_BLOCK), layers.getSafeMaterialList());
+ Generator.generateLayer(layer, 13, 1, Material.AIR);
+ layer.setY(layer.getY() - 1);
+ Generator.generateClumps(Generator.generateLayer(layer, 13, 1, Material.GRASS_BLOCK), layers.getMaterialList());
+ Generator.generateLayer(layer, 4, 1, Material.AIR);
+ layer.setY(layer.getY() - 1);
+ Generator.generateClumps(Generator.generateLayer(layer, 4, 1, Material.PODZOL), layers.getMaterialList());
+ }
+ else {
+ // Multi-tiered square
+ Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 17, layer.getY(), layer.getZ() - 17), new Location(layer.getWorld(), layer.getX() + 17, layer.getY(), layer.getZ() + 17), Material.SNOW_BLOCK), layers.getSafeMaterialList());
+ Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 13, layer.getY(), layer.getZ() - 13), new Location(layer.getWorld(), layer.getX() + 13, layer.getY(), layer.getZ() + 13), Material.AIR);
+ layer.setY(layer.getY() - 1);
+ Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 13, layer.getY(), layer.getZ() - 13), new Location(layer.getWorld(), layer.getX() + 13, layer.getY(), layer.getZ() + 13), Material.GRASS_BLOCK), layers.getMaterialList());
+ Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 7, layer.getY(), layer.getZ() - 7), new Location(layer.getWorld(), layer.getX() + 7, layer.getY(), layer.getZ() + 7), Material.AIR);
+ layer.setY(layer.getY() - 1);
+ Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 7, layer.getY(), layer.getZ() - 7), new Location(layer.getWorld(), layer.getX() + 7, layer.getY(), layer.getZ() + 7), Material.PODZOL), layers.getMaterialList());
+ }
+ }
+
+ /**
+ * Generates layers for round of type snowballs
+ * @param layer Location where the layers should start
+ */
+ public static void generateLayersSnowballs(Location layer) {
+ Random random = new Random();
+ Layers layers = new Layers();
+
+ layer.setY(layer.getY() - 1);
+ // Similar generation to shovels, except there are three layers
+ if (random.nextInt(4) == 0) {
+ // Circular layer
+ Generator.generateClumps(Generator.generateLayer(layer, 17, 1, Material.STONE), layers.getSafeMaterialList());
+ layer.setY(layer.getY() - 6);
+ Generator.generateClumps(Generator.generateLayer(layer, 17, 1, Material.STONE), layers.getMaterialList());
+ layer.setY(layer.getY() - 6);
+ Generator.generateClumps(Generator.generateLayer(layer, 17, 1, Material.STONE), layers.getMaterialList());
+ }
+ else if (random.nextInt(4) == 1) {
+ // Square layer
+ Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 17, layer.getY(), layer.getZ() - 17), new Location(layer.getWorld(), layer.getX() + 17, layer.getY(), layer.getZ() + 17), Material.STONE), layers.getSafeMaterialList());
+ layer.setY(layer.getY() - 6);
+ Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 17, layer.getY(), layer.getZ() - 17), new Location(layer.getWorld(), layer.getX() + 17, layer.getY(), layer.getZ() + 17), Material.STONE), layers.getMaterialList());
+ layer.setY(layer.getY() - 6);
+ Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 17, layer.getY(), layer.getZ() - 17), new Location(layer.getWorld(), layer.getX() + 17, layer.getY(), layer.getZ() + 17), Material.STONE), layers.getMaterialList());
+ }
+ else if (random.nextInt(4) == 2) {
+ // Multi-tiered circle
+ Generator.generateClumps(Generator.generateLayer(layer, 17, 1, Material.STONE), layers.getSafeMaterialList());
+ Generator.generateLayer(layer, 13, 1, Material.AIR);
+ layer.setY(layer.getY() - 1);
+ Generator.generateClumps(Generator.generateLayer(layer, 13, 1, Material.GRANITE), layers.getMaterialList());
+ Generator.generateLayer(layer, 4, 1, Material.AIR);
+ layer.setY(layer.getY() - 1);
+ Generator.generateClumps(Generator.generateLayer(layer, 4, 1, Material.LIME_GLAZED_TERRACOTTA), layers.getMaterialList());
+ layer.setY(layer.getY() - 6);
+
+ Generator.generateClumps(Generator.generateLayer(layer, 17, 1, Material.STONE), layers.getSafeMaterialList());
+ Generator.generateLayer(layer, 13, 1, Material.AIR);
+ layer.setY(layer.getY() - 1);
+ Generator.generateClumps(Generator.generateLayer(layer, 13, 1, Material.GRANITE), layers.getMaterialList());
+ Generator.generateLayer(layer, 4, 1, Material.AIR);
+ layer.setY(layer.getY() - 1);
+ Generator.generateClumps(Generator.generateLayer(layer, 4, 1, Material.LIME_GLAZED_TERRACOTTA), layers.getMaterialList());
+ layer.setY(layer.getY() - 6);
+
+ Generator.generateClumps(Generator.generateLayer(layer, 17, 1, Material.STONE), layers.getSafeMaterialList());
+ Generator.generateLayer(layer, 13, 1, Material.AIR);
+ layer.setY(layer.getY() - 1);
+ Generator.generateClumps(Generator.generateLayer(layer, 13, 1, Material.GRANITE), layers.getMaterialList());
+ Generator.generateLayer(layer, 4, 1, Material.AIR);
+ layer.setY(layer.getY() - 1);
+ Generator.generateClumps(Generator.generateLayer(layer, 4, 1, Material.LIME_GLAZED_TERRACOTTA), layers.getMaterialList());
+ }
+ else {
+ // Multi-tiered square
+ Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 17, layer.getY(), layer.getZ() - 17), new Location(layer.getWorld(), layer.getX() + 17, layer.getY(), layer.getZ() + 17), Material.STONE), layers.getSafeMaterialList());
+ Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 13, layer.getY(), layer.getZ() - 13), new Location(layer.getWorld(), layer.getX() + 13, layer.getY(), layer.getZ() + 13), Material.AIR);
+ layer.setY(layer.getY() - 1);
+ Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 13, layer.getY(), layer.getZ() - 13), new Location(layer.getWorld(), layer.getX() + 13, layer.getY(), layer.getZ() + 13), Material.GRANITE), layers.getMaterialList());
+ Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 7, layer.getY(), layer.getZ() - 7), new Location(layer.getWorld(), layer.getX() + 7, layer.getY(), layer.getZ() + 7), Material.AIR);
+ layer.setY(layer.getY() - 1);
+ Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 7, layer.getY(), layer.getZ() - 7), new Location(layer.getWorld(), layer.getX() + 7, layer.getY(), layer.getZ() + 7), Material.LIME_GLAZED_TERRACOTTA), layers.getMaterialList());
+ layer.setY(layer.getY() - 6);
+
+ Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 17, layer.getY(), layer.getZ() - 17), new Location(layer.getWorld(), layer.getX() + 17, layer.getY(), layer.getZ() + 17), Material.STONE), layers.getSafeMaterialList());
+ Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 13, layer.getY(), layer.getZ() - 13), new Location(layer.getWorld(), layer.getX() + 13, layer.getY(), layer.getZ() + 13), Material.AIR);
+ layer.setY(layer.getY() - 1);
+ Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 13, layer.getY(), layer.getZ() - 13), new Location(layer.getWorld(), layer.getX() + 13, layer.getY(), layer.getZ() + 13), Material.GRANITE), layers.getMaterialList());
+ Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 7, layer.getY(), layer.getZ() - 7), new Location(layer.getWorld(), layer.getX() + 7, layer.getY(), layer.getZ() + 7), Material.AIR);
+ layer.setY(layer.getY() - 1);
+ Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 7, layer.getY(), layer.getZ() - 7), new Location(layer.getWorld(), layer.getX() + 7, layer.getY(), layer.getZ() + 7), Material.LIME_GLAZED_TERRACOTTA), layers.getMaterialList());
+ layer.setY(layer.getY() - 6);
+
+ Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 17, layer.getY(), layer.getZ() - 17), new Location(layer.getWorld(), layer.getX() + 17, layer.getY(), layer.getZ() + 17), Material.STONE), layers.getSafeMaterialList());
+ Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 13, layer.getY(), layer.getZ() - 13), new Location(layer.getWorld(), layer.getX() + 13, layer.getY(), layer.getZ() + 13), Material.AIR);
+ layer.setY(layer.getY() - 1);
+ Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 13, layer.getY(), layer.getZ() - 13), new Location(layer.getWorld(), layer.getX() + 13, layer.getY(), layer.getZ() + 13), Material.GRANITE), layers.getMaterialList());
+ Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 7, layer.getY(), layer.getZ() - 7), new Location(layer.getWorld(), layer.getX() + 7, layer.getY(), layer.getZ() + 7), Material.AIR);
+ layer.setY(layer.getY() - 1);
+ Generator.generateClumps(Generator.generateCuboid(new Location(layer.getWorld(), layer.getX() - 7, layer.getY(), layer.getZ() - 7), new Location(layer.getWorld(), layer.getX() + 7, layer.getY(), layer.getZ() + 7), Material.LIME_GLAZED_TERRACOTTA), layers.getMaterialList());
+ }
+ }
+
/**
* Generates a layer (basically just a cylinder) as good as possible with blocks
* @param center The center of the layer (Location)
@@ -21,7 +144,7 @@ public class Generator {
*
* @return A list of Blocks containing all the blocks it just changed
*/
- public static List<Block> generateLayer(Location center, int radius, int height, Material material) {
+ private static List<Block> generateLayer(Location center, int radius, int height, Material material) {
int Cx = center.getBlockX();
int Cy = center.getBlockY();
int Cz = center.getBlockZ();
@@ -77,13 +200,13 @@ public class Generator {
* Keep in mind that not all Materials may be used, the amount used depends on the size of the layer.
* More Materials = more randomization
*/
- public static void generateClumps(List<Block> blockList, List<Material> materialList) {
+ private static void generateClumps(List<Block> blockList, List<Material> materialList) {
Random random = new Random();
// Make new lists so we can manipulate them
List<Block> blocks = new ArrayList<>(blockList);
List<Material> materials = new ArrayList<>(materialList);
Collections.shuffle(materials);
- while (blocks.size() > 0) {
+ while (!blocks.isEmpty()) {
Material randomMaterial = materials.get(random.nextInt(materials.size()));
Block aBlock = blocks.get(0);
aBlock.setType(randomMaterial);
diff --git a/src/main/java/com/MylesAndMore/Tumble/plugin/ConfigManager.java b/src/main/java/com/MylesAndMore/Tumble/plugin/ConfigManager.java
new file mode 100644
index 0000000..dae6dd5
--- /dev/null
+++ b/src/main/java/com/MylesAndMore/Tumble/plugin/ConfigManager.java
@@ -0,0 +1,152 @@
+package com.MylesAndMore.Tumble.plugin;
+
+import com.MylesAndMore.Tumble.game.Arena;
+import com.MylesAndMore.Tumble.game.Game;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashMap;
+import java.util.Objects;
+
+import static com.MylesAndMore.Tumble.Main.plugin;
+
+public class ConfigManager {
+ public static HashMap<String, Arena> arenas;
+ public static Location lobby;
+ public static Location winnerLobby;
+ public static Location waitArea;
+ public static boolean HideLeaveJoin;
+ public static int waitDuration;
+
+ /**
+ * Reads config file and populates values above
+ */
+ public static void readConfig() {
+ FileConfiguration config = plugin.getConfig();
+
+ // arenas
+ if (config.getConfigurationSection("arenas") == null) {
+ plugin.getLogger().warning("Section arenas is missing from config");
+ return;
+ }
+ arenas = new HashMap<>();
+ for (String arenaName: Objects.requireNonNull(config.getConfigurationSection("arenas")).getKeys(false)) {
+ ConfigurationSection section = Objects.requireNonNull(config.getConfigurationSection("arenas")).getConfigurationSection(arenaName);
+
+ Result<Location> res = readWorld(section);
+ if (!res.success) {
+ plugin.getLogger().warning("Failed to load arena "+arenaName+": "+res.error);
+ continue;
+ }
+
+ arenas.put(arenaName, new Arena(arenaName, res.value));
+ }
+
+ // lobby
+ {
+ Result<Location>res = readWorld(config.getConfigurationSection("lobby-spawn"));
+ if (!res.success) {
+ plugin.getLogger().warning("Failed to load lobby: "+res.error);
+ plugin.getLogger().severe("^ THIS IS REQUIRED, PLEASE FIX TO AVOID UNDEFINED BEHAVIOR");
+ }
+
+ lobby = res.value;
+ }
+
+ // winner lobby
+ if (config.getBoolean("enable-winner-lobby-spawn")) {
+ Result<Location>res = readWorld(config.getConfigurationSection("winner-lobby-spawn"));
+ if (!res.success) {
+ plugin.getLogger().warning("Failed to load winner lobby: "+res.error);
+ }
+
+ winnerLobby = res.value;
+ }
+
+ // wait area
+ if (config.getBoolean("enable-wait-area")) {
+ Result<Location>res = readWorld(config.getConfigurationSection("wait-area"));
+ if (!res.success) {
+ plugin.getLogger().warning("Failed to load winner lobby: "+res.error);
+ }
+
+ waitArea = res.value;
+ }
+
+ // other
+ HideLeaveJoin = config.getBoolean("hideJoinLeaveMessages");
+ waitDuration = config.getInt("wait-duration", 15);
+ }
+
+ /**
+ * tries to convert a config section in the following format to a world
+ * section:
+ * x:
+ * y:
+ * z:
+ * world:
+ * @param section the section in the yaml with x, y, z, and world as its children
+ * @return result of either:
+ * success = true and a world
+ * success = false and an error string
+ */
+ private static Result<Location> readWorld(@Nullable ConfigurationSection section) {
+
+ if (section == null) {
+ Result<Location> res = new Result<>();
+ res.success = false;
+ res.error = "Section missing from config";
+ return res;
+ }
+
+ double x = section.getDouble("x");
+ double y = section.getDouble("y");
+ double z = section.getDouble("x");
+ if (x==0 || y == 0 || z == 0) {
+ Result<Location> res = new Result<>();
+ res.success = false;
+ res.error = "Arena coordinates are missing or are zero. Coordinates cannot be zero.";
+ return res;
+ }
+
+ String worldName = section.getString("world");
+ if (worldName == null) {
+ Result<Location> res = new Result<>();
+ res.success = false;
+ res.error = "World name is missing";
+ return res;
+ }
+
+ World world = Bukkit.getWorld(worldName);
+ if (world == null) {
+ Result<Location> res = new Result<>();
+ res.success = false;
+ res.error = "Failed to load world " + worldName;
+ return res;
+ }
+
+ Result<Location> res = new Result<>();
+ res.success = true;
+ res.value = new Location(world,x,y,z);
+ return res;
+ }
+
+ /**
+ * Searches all arenas for a game that player p is in
+ * @param p Player to search for
+ * @return the game the player is in, or null if not found
+ */
+ public static Game findGamePlayerIsIn(Player p) {
+ for (Arena a : arenas.values()) {
+ if (a.game != null && a.game.gamePlayers.contains(p)) {
+ return a.game;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/com/MylesAndMore/Tumble/plugin/Constants.java b/src/main/java/com/MylesAndMore/Tumble/plugin/Constants.java
deleted file mode 100644
index 118af23..0000000
--- a/src/main/java/com/MylesAndMore/Tumble/plugin/Constants.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.MylesAndMore.Tumble.plugin;
-
-import com.onarandombox.MultiverseCore.MultiverseCore;
-import com.onarandombox.MultiverseCore.api.MVWorldManager;
-import org.bukkit.Bukkit;
-import org.bukkit.entity.Player;
-import org.bukkit.plugin.Plugin;
-
-import java.util.List;
-import java.util.Objects;
-
-public class Constants {
- public static Plugin getPlugin() {
- return Bukkit.getServer().getPluginManager().getPlugin("tumble");
- }
- public static String getPermissionMessage() { return Constants.getPlugin().getConfig().getString("permissionMessage"); }
- public static String getGameWorld() { return Constants.getPlugin().getConfig().getString("gameWorld"); }
- public static String getLobbyWorld() { return Constants.getPlugin().getConfig().getString("lobbyWorld"); }
- public static String getGameType() { return Constants.getPlugin().getConfig().getString("gameMode"); }
- public static List<Player> getPlayersInGame() { return Objects.requireNonNull(Bukkit.getServer().getWorld(Constants.getGameWorld())).getPlayers(); }
- public static List<Player> getPlayersInLobby() { return Objects.requireNonNull(Bukkit.getServer().getWorld(Constants.getLobbyWorld())).getPlayers(); }
-
- public static MultiverseCore getMV() { return (MultiverseCore) Bukkit.getServer().getPluginManager().getPlugin("Multiverse-Core"); }
- public static MVWorldManager getMVWorldManager() { return getMV().getMVWorldManager(); }
-}
diff --git a/src/main/java/com/MylesAndMore/Tumble/plugin/EventListener.java b/src/main/java/com/MylesAndMore/Tumble/plugin/EventListener.java
deleted file mode 100644
index 9a4dd62..0000000
--- a/src/main/java/com/MylesAndMore/Tumble/plugin/EventListener.java
+++ /dev/null
@@ -1,222 +0,0 @@
-package com.MylesAndMore.Tumble.plugin;
-
-import java.util.Objects;
-
-import com.MylesAndMore.Tumble.game.Game;
-import org.bukkit.Bukkit;
-import org.bukkit.Material;
-import org.bukkit.entity.Player;
-import org.bukkit.entity.Snowball;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.Listener;
-import org.bukkit.event.block.Action;
-import org.bukkit.event.block.BlockBreakEvent;
-import org.bukkit.event.block.BlockDropItemEvent;
-import org.bukkit.event.entity.*;
-import org.bukkit.event.inventory.InventoryDragEvent;
-import org.bukkit.event.player.*;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.util.Vector;
-
-/**
- * Tumble event listener for all plugin and game-related events.
- */
-public class EventListener implements Listener {
- @EventHandler
- public void PlayerJoinEvent(PlayerJoinEvent event) {
- // Hide/show join message accordingly
- if (Constants.getPlugin().getConfig().getBoolean("hideJoinLeaveMessages")) {
- event.setJoinMessage(null);
- }
- // Check if either of the worlds are not defined in config, if so, end to avoid any NPEs later on
- if (Constants.getGameWorld() == null || Constants.getLobbyWorld() == null) { return; }
- if (event.getPlayer().getWorld() == Bukkit.getWorld(Constants.getGameWorld())) {
- // Send the player back to the lobby if they try to join in the middle of a game
- event.getPlayer().teleport(Objects.requireNonNull(Bukkit.getWorld(Constants.getLobbyWorld())).getSpawnLocation());
- }
- if (Constants.getPlugin().getConfig().getBoolean("autoStart.enabled")) {
- if (Constants.getPlayersInLobby().size() == Constants.getPlugin().getConfig().getInt("autoStart.players")) {
- // The autoStart should begin if it is already enabled and the amount of players is correct; pass this to the Game
- Game.getGame().autoStart();
- }
- }
- }
-
- @EventHandler
- public void PlayerChangedWorldEvent(PlayerChangedWorldEvent event) {
- if (Constants.getGameWorld() == null || Constants.getLobbyWorld() == null) {
- return;
- }
- if (event.getPlayer().getWorld() == Bukkit.getWorld(Constants.getLobbyWorld())) {
- // Another event on which autostart could be triggered
- if (Constants.getPlugin().getConfig().getBoolean("autoStart.enabled")) {
- if (Constants.getPlayersInLobby().size() == Constants.getPlugin().getConfig().getInt("autoStart.players")) {
- Game.getGame().autoStart();
- }
- }
- }
- // Also check if the player left to another world and cancel autostart
- else if (event.getFrom() == Bukkit.getWorld(Constants.getLobbyWorld())) {
- if (Objects.equals(Game.getGame().getGameState(), "waiting")) {
- Game.getGame().cancelStart();
- }
- }
- }
-
- @EventHandler
- public void PlayerQuitEvent(PlayerQuitEvent event) {
- // Hide/show leave message accordingly
- if (Constants.getPlugin().getConfig().getBoolean("hideJoinLeaveMessages")) {
- event.setQuitMessage(null);
- }
- if (Constants.getLobbyWorld() == null) { return; }
- if (event.getPlayer().getWorld() == Bukkit.getWorld(Constants.getLobbyWorld())) {
- // Check if the game is in the process of autostarting, if so cancel
- if (Objects.equals(Game.getGame().getGameState(), "waiting")) {
- Game.getGame().cancelStart();
- }
- }
- }
-
- @EventHandler
- public void PlayerDeathEvent(PlayerDeathEvent event) {
- if (Constants.getGameWorld() == null) { return; }
- // Pass game deaths to the Game
- if (event.getEntity().getWorld() == Bukkit.getWorld(Constants.getGameWorld())) {
- Game.getGame().playerDeath(event.getEntity());
- }
- }
-
- @EventHandler
- public void PlayerItemDamageEvent(PlayerItemDamageEvent event) {
- if (Constants.getGameWorld() == null) { return; }
- // Remove item damage within games
- if (event.getPlayer().getWorld() == Bukkit.getWorld(Constants.getGameWorld())) {
- event.setCancelled(true);
- }
- }
-
- @EventHandler
- public void ProjectileLaunchEvent(ProjectileLaunchEvent event) {
- if (Constants.getGameWorld() == null) {
- return;
- }
- if (event.getEntity().getWorld() == Bukkit.getWorld(Constants.getGameWorld())) {
- if (event.getEntity() instanceof Snowball) {
- if (event.getEntity().getShooter() instanceof Player player) {
- // Prevent projectiles (snowballs) from being thrown before the game starts
- if (Objects.equals(Game.getGame().getGameState(), "starting")) {
- event.setCancelled(true);
- }
- else {
- // Give players a snowball when they've used one (infinite snowballs)
- Bukkit.getServer().getScheduler().runTask(Constants.getPlugin(), () -> player.getInventory().addItem(new ItemStack(Material.SNOWBALL, 1)));
- }
- }
- }
- }
- }
-
- @EventHandler
- public void ProjectileHitEvent(ProjectileHitEvent event) {
- if (Constants.getGameWorld() == null) { return; }
- else if (event.getHitBlock() == null) { return; }
- // Removes blocks that snowballs thrown by players have hit in the game world
- if (event.getHitBlock().getWorld() == Bukkit.getWorld(Constants.getGameWorld())) {
- if (event.getEntity() instanceof Snowball) {
- if (event.getEntity().getShooter() instanceof Player) {
- if (event.getHitBlock() != null) {
- if (event.getHitBlock().getLocation().distanceSquared(Objects.requireNonNull(Bukkit.getWorld(Constants.getGameWorld())).getSpawnLocation()) < 579) {
- event.getHitBlock().setType(Material.AIR);
- }
- }
- else if (event.getHitEntity() != null) {
- if (event.getHitEntity() instanceof Player hitPlayer) {
- // Also cancel any knockback
- Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(Constants.getPlugin(), () -> hitPlayer.setVelocity(new Vector()));
- }
- }
- }
- }
- }
- }
-
- @EventHandler
- public void PlayerDropItemEvent(PlayerDropItemEvent event) {
- if (Constants.getGameWorld() == null) { return; }
- // Don't allow items to drop in the game world
- if (event.getPlayer().getWorld() == Bukkit.getWorld((Constants.getGameWorld()))) {
- event.setCancelled(true);
- }
- }
-
- @EventHandler
- public void PlayerMoveEvent(PlayerMoveEvent event) {
- if (Constants.getGameWorld() == null) { return; }
- // Cancel movement if the game is starting (so players can't move before the game starts)
- if (Objects.equals(Game.getGame().getGameState(), "starting")) {
- event.setCancelled(true);
- }
- }
-
- @EventHandler
- public void BlockDropItemEvent(BlockDropItemEvent event) {
- if (Constants.getGameWorld() == null) { return; }
- // If a block was going to drop an item (ex. snow dropping snowballs) in the game world, cancel it
- if (event.getBlock().getWorld() == Bukkit.getWorld(Constants.getGameWorld())) {
- event.setCancelled(true);
- }
- }
-
- @EventHandler
- public void PlayerInteractEvent(PlayerInteractEvent event) {
- if (Constants.getGameWorld() == null) { return; }
- // Remove blocks when clicked in the game world (all gamemodes require this functionality)
- if (event.getAction() == Action.LEFT_CLICK_BLOCK) {
- if (Objects.requireNonNull(event.getClickedBlock()).getWorld() == Bukkit.getWorld(Constants.getGameWorld())) {
- event.getClickedBlock().setType(Material.AIR);
- }
- }
- }
-
- @EventHandler
- public void BlockBreakEvent(BlockBreakEvent event) {
- if (Constants.getGameWorld() == null) { return; }
- // This just doesn't allow blocks to break in the gameWorld; the PlayerInteractEvent will take care of everything
- // This prevents any weird client-server desync
- if (event.getBlock().getWorld() == Bukkit.getWorld(Constants.getGameWorld())) {
- event.setCancelled(true);
- }
- }
-
- @EventHandler
- public void FoodLevelChangeEvent(FoodLevelChangeEvent event) {
- if (Constants.getGameWorld() == null) { return; }
- // INFINITE FOOD (YAY!!!!)
- if (event.getEntity().getWorld() == Bukkit.getWorld(Constants.getGameWorld())) {
- event.setCancelled(true);
- }
- }
-
- @EventHandler
- public void EntityDamageEvent(EntityDamageEvent event) {
- if (Constants.getGameWorld() == null) { return; }
- // Check to see if a player got damaged by another entity (player, snowball, etc) in the gameWorld, if so, cancel it
- if (event.getEntity().getWorld() == Bukkit.getWorld(Constants.getGameWorld())) {
- if (event.getEntity() instanceof Player) {
- if (event.getCause() == EntityDamageEvent.DamageCause.ENTITY_ATTACK || event.getCause() == EntityDamageEvent.DamageCause.ENTITY_SWEEP_ATTACK || event.getCause() == EntityDamageEvent.DamageCause.FALL) {
- event.setCancelled(true);
- }
- }
- }
- }
-
- @EventHandler
- public void InventoryDragEvent(InventoryDragEvent event) {
- if (Constants.getGameWorld() == null) { return; }
- if (event.getWhoClicked().getWorld() == Bukkit.getWorld((Constants.getGameWorld()))) {
- event.setCancelled(true);
- }
- }
-
-}
diff --git a/src/main/java/com/MylesAndMore/Tumble/plugin/GameState.java b/src/main/java/com/MylesAndMore/Tumble/plugin/GameState.java
new file mode 100644
index 0000000..879a1f5
--- /dev/null
+++ b/src/main/java/com/MylesAndMore/Tumble/plugin/GameState.java
@@ -0,0 +1,7 @@
+package com.MylesAndMore.Tumble.plugin;
+
+public enum GameState {
+ WAITING,
+ STARTING,
+ RUNNING,
+}
diff --git a/src/main/java/com/MylesAndMore/Tumble/plugin/GameType.java b/src/main/java/com/MylesAndMore/Tumble/plugin/GameType.java
new file mode 100644
index 0000000..cf01c88
--- /dev/null
+++ b/src/main/java/com/MylesAndMore/Tumble/plugin/GameType.java
@@ -0,0 +1,11 @@
+package com.MylesAndMore.Tumble.plugin;
+
+public enum GameType {
+ SHOVELS,
+ SNOWBALLS,
+ MIXED;
+
+ public String toString() {
+ return this.name().toLowerCase();
+ }
+}
diff --git a/src/main/java/com/MylesAndMore/Tumble/plugin/Result.java b/src/main/java/com/MylesAndMore/Tumble/plugin/Result.java
new file mode 100644
index 0000000..68e1133
--- /dev/null
+++ b/src/main/java/com/MylesAndMore/Tumble/plugin/Result.java
@@ -0,0 +1,8 @@
+package com.MylesAndMore.Tumble.plugin;
+
+// java does not have result types (i miss rust </3) so i did this
+public class Result<T> {
+ public boolean success;
+ public T value;
+ public String error;
+}