summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXander <xander@biltopia.org>2023-10-08 21:37:35 +0200
committerXander <xander@biltopia.org>2023-10-08 21:37:35 +0200
commita5a1daa80b386c6ca43b651a2c2dae2f53db6afd (patch)
tree83b34631828761256116ab7c0eab43b1f9149590
downloadteams-speedrun-master.tar.xz
teams-speedrun-master.zip
First commitHEADmaster
-rw-r--r--.gitignore38
-rw-r--r--.idea/.gitignore3
-rw-r--r--.idea/encodings.xml7
-rw-r--r--.idea/misc.xml13
-rw-r--r--.idea/uiDesigner.xml124
-rw-r--r--pom.xml33
-rw-r--r--src/main/java/org/biltopia/Main.java370
-rw-r--r--src/main/java/org/biltopia/SaveTask.java18
-rw-r--r--src/main/resources/plugin.yml33
9 files changed, 639 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5ff6309
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,38 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store \ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..aa00ffa
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="Encoding">
+ <file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
+ <file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
+ </component>
+</project> \ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..c3f3b0a
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,13 @@
+<project version="4">
+ <component name="ExternalStorageConfigurationManager" enabled="true" />
+ <component name="MavenProjectsManager">
+ <option name="originalFiles">
+ <list>
+ <option value="$PROJECT_DIR$/pom.xml" />
+ </list>
+ </option>
+ </component>
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
+ <output url="file://$PROJECT_DIR$/out" />
+ </component>
+</project> \ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 0000000..2b63946
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="Palette2">
+ <group name="Swing">
+ <item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
+ </item>
+ <item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
+ </item>
+ <item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
+ <default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
+ <initial-values>
+ <property name="text" value="Button" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="RadioButton" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="CheckBox" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
+ <initial-values>
+ <property name="text" value="Label" />
+ </initial-values>
+ </item>
+ <item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
+ <preferred-size width="150" height="-1" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
+ <preferred-size width="150" height="50" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+ <preferred-size width="200" height="200" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
+ <preferred-size width="200" height="200" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
+ </item>
+ <item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
+ </item>
+ <item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
+ </item>
+ <item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
+ <preferred-size width="-1" height="20" />
+ </default-constraints>
+ </item>
+ <item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
+ <default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
+ </item>
+ <item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
+ <default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
+ </item>
+ </group>
+ </component>
+</project> \ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..16118b5
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.biltopia</groupId>
+ <artifactId>speedrun</artifactId>
+ <version>1.0-SNAPSHOT</version>
+
+ <properties>
+ <maven.compiler.source>17</maven.compiler.source>
+ <maven.compiler.target>17</maven.compiler.target>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <repositories>
+ <repository>
+ <id>spigot-repo</id>
+ <url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
+ </repository>
+ </repositories>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.spigotmc</groupId>
+ <artifactId>spigot-api</artifactId>
+ <version>1.20.1-R0.1-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+</project> \ No newline at end of file
diff --git a/src/main/java/org/biltopia/Main.java b/src/main/java/org/biltopia/Main.java
new file mode 100644
index 0000000..4dff9ec
--- /dev/null
+++ b/src/main/java/org/biltopia/Main.java
@@ -0,0 +1,370 @@
+package org.biltopia;
+
+import org.bukkit.*;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.event.entity.PlayerDeathEvent;
+import org.bukkit.event.player.*;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.bukkit.scoreboard.Scoreboard;
+import org.bukkit.scoreboard.ScoreboardManager;
+import org.bukkit.scoreboard.Team;
+import org.bukkit.util.io.BukkitObjectInputStream;
+import org.bukkit.util.io.BukkitObjectOutputStream;
+
+import javax.annotation.Nullable;
+import java.io.*;
+import java.util.*;
+
+record Data(Map<UUID, Integer> playerGroups, Map<Integer, ArrayList<UUID>> uuidMap) implements Serializable {
+}
+
+
+public class Main extends JavaPlugin implements Listener {
+
+ private final Map<UUID, Integer> playerGroups = new HashMap<>();
+ private static final double MAX_DISTANCE_SQUARED = 200.0;
+ private static final String FILEPATH = "dump";
+
+ private final Map<Integer, ArrayList<UUID>> uuidMap = new HashMap<>();
+ private final List<ChatColor> colors = List.of(
+ ChatColor.BLUE,
+ ChatColor.RED,
+ ChatColor.DARK_BLUE,
+ ChatColor.DARK_PURPLE,
+ ChatColor.DARK_AQUA,
+ ChatColor.DARK_GRAY,
+ ChatColor.DARK_GREEN,
+ ChatColor.WHITE,
+ ChatColor.AQUA,
+ ChatColor.BLACK,
+ ChatColor.GOLD,
+ ChatColor.YELLOW,
+ ChatColor.LIGHT_PURPLE
+ );
+
+ private static ScoreboardManager sm;
+ private static Scoreboard scoreboard;
+
+
+ @Override
+ public void onEnable() {
+ getLogger().info("onEnable is called!");
+ getServer().getPluginManager().registerEvents(this, this);
+ Objects.requireNonNull(getCommand("groupAdd")).setExecutor(this::addToGroupCommand);
+ Objects.requireNonNull(getCommand("groupRemove")).setExecutor(this::removeFromGroupCommand);
+ Objects.requireNonNull(getCommand("groupList")).setExecutor(this::groupListCommand);
+ Objects.requireNonNull(getCommand("groupsSave")).setExecutor(this::groupsSaveCommand);
+ Objects.requireNonNull(getCommand("groupsLoad")).setExecutor(this::groupsLoadCommand);
+ Objects.requireNonNull(getCommand("startSaving")).setExecutor(this::startSavingCommand);
+ sm = Bukkit.getScoreboardManager();
+ scoreboard = sm.getMainScoreboard();
+ scoreboard.getTeams().forEach(Team::unregister);
+ loadData();
+ }
+
+ @Override
+ public void onDisable() {
+ getLogger().info("onDisable is called!");
+ saveData();
+ }
+
+ public boolean saveData() {
+ try {
+ BukkitObjectOutputStream out = new BukkitObjectOutputStream(new FileOutputStream(FILEPATH));
+ Data data = new Data(playerGroups, uuidMap);
+ out.writeObject(data);
+ out.close();
+ getLogger().info("Saved groups!");
+ return true;
+ } catch (IOException e) {
+ System.out.println(e.toString());
+ return false;
+ }
+ }
+
+ public boolean loadData() {
+ try {
+ BukkitObjectInputStream in = new BukkitObjectInputStream(new FileInputStream(FILEPATH));
+ Data data = (Data) in.readObject();
+ in.close();
+ for (Map.Entry<UUID, Integer> entry : data.playerGroups().entrySet()) {
+ Player player = Bukkit.getPlayer(entry.getKey());
+ if (player != null) {
+ addPlayer(player, entry.getValue());
+ } else {
+ OfflinePlayer offline = Bukkit.getOfflinePlayer(entry.getKey());
+ addPlayer(offline,entry.getValue());
+ }
+ }
+ return true;
+ } catch (ClassNotFoundException | IOException e) {
+ System.out.println(e);
+ return false;
+ }
+ }
+
+ private double getDistanceSquared(Location loc, Location loc2) {
+ return Math.pow(loc.getX() - loc2.getX(), 2) + Math.pow(loc.getZ() - loc2.getZ(), 2);
+ }
+
+ @Nullable
+ private Location getGroupCenter(Player player) {
+ if (playerGroups.containsKey(player.getUniqueId())) {
+ // Calculate center of locations
+ double x = 0.0;
+ double y = 0.0;
+ double z = 0.0;
+
+ ArrayList<UUID> list = uuidMap.get(playerGroups.get(player.getUniqueId()));
+ int size = 0;
+ for (UUID id : list) {
+ Player p = Bukkit.getPlayer(id);
+ if (p != null) {
+ size++;
+ x += p.getLocation().getX();
+ y += p.getLocation().getY();
+ z += p.getLocation().getZ();
+ }
+ }
+
+ x /= size;
+ y /= size;
+ z /= size;
+
+ return new Location(player.getWorld(), x, y, z);
+ }
+ return null;
+ }
+
+ @EventHandler
+ public void onPlayerMove(PlayerMoveEvent event) {
+ if (event.getFrom().getX() != event.getTo().getX() || event.getFrom().getZ() != event.getTo().getZ() || event.getFrom().getY() != event.getTo().getY()) {
+ Player player = event.getPlayer();
+ Location center = getGroupCenter(player);
+ if (center != null) {
+ double distanceFrom = getDistanceSquared(event.getFrom(), center);
+ double distanceTo = getDistanceSquared(event.getTo(), center);
+ if (distanceTo > MAX_DISTANCE_SQUARED && distanceTo > distanceFrom) {
+ event.setCancelled(true);
+ player.sendMessage(ChatColor.RED + "You're too far from your group!!");
+ }
+ }
+ }
+ }
+
+ @EventHandler
+ void onRightClick(PlayerInteractEvent event) {
+ if ((event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) && event.getMaterial() == Material.COMPASS && playerGroups.containsKey(event.getPlayer().getUniqueId())) {
+ event.getPlayer().setCompassTarget(Objects.requireNonNull(getGroupCenter(event.getPlayer())));
+ event.getPlayer().sendMessage(ChatColor.BLUE + "Updated compass direction to group center.");
+ }
+ }
+
+ @EventHandler
+ public void onPlayerJoin(PlayerJoinEvent event) {
+ Player player = event.getPlayer();
+ player.setGlowing(true);
+ if (playerGroups.containsKey(player.getUniqueId())) {
+ for (UUID id : uuidMap.get(playerGroups.get(player.getUniqueId()))) {
+ Player p = Bukkit.getPlayer(id);
+ if (p != null && p.getUniqueId() != player.getUniqueId()) {
+ player.teleport(p);
+ return;
+ }
+ }
+ }
+ }
+
+ @EventHandler
+ public void onPlayerTeleport(PlayerTeleportEvent event) {
+ UUID uuid = event.getPlayer().getUniqueId();
+ if (event.getCause() != PlayerTeleportEvent.TeleportCause.PLUGIN && playerGroups.containsKey(uuid) && event.getTo() != null) {
+ for (UUID id : uuidMap.get(playerGroups.get(uuid))) {
+ Player p = Bukkit.getPlayer(id);
+ if (p != null &&
+ p.getUniqueId() != uuid &&
+ event.getTo().getWorld() != null &&
+ (p.getWorld().getEnvironment() != event.getTo().getWorld().getEnvironment() ||
+ getDistanceSquared(p.getLocation(), event.getTo()) > MAX_DISTANCE_SQUARED)) {
+ p.teleport(event.getTo());
+ }
+ }
+ }
+ }
+
+ @EventHandler
+ public void onSpawnChange(PlayerSpawnChangeEvent event) {
+ if (event.getCause() == PlayerSpawnChangeEvent.Cause.RESPAWN_ANCHOR) {
+ event.getPlayer().sendMessage(ChatColor.RED + "Not supported, sorry...");
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ public void onSpawnBed(PlayerBedEnterEvent event) {
+ Player player = event.getPlayer();
+ if (playerGroups.containsKey(player.getUniqueId())) {
+ for (UUID id : uuidMap.get(playerGroups.get(player.getUniqueId()))) {
+ Player p = Bukkit.getPlayer(id);
+ if (p != null) {
+ p.setBedSpawnLocation(event.getBed().getLocation());
+ }
+ }
+ }
+ }
+
+ @EventHandler
+ public void onPlayerDeath(PlayerDeathEvent event) {
+ Player player = event.getEntity();
+ EntityDamageEvent damageEvent = player.getLastDamageCause();
+ if (damageEvent != null && damageEvent.getCause() == EntityDamageEvent.DamageCause.CUSTOM) {
+ event.setKeepInventory(true);
+ event.getDrops().clear();
+ } else if (playerGroups.containsKey(player.getUniqueId())) {
+ uuidMap.get(playerGroups.get(player.getUniqueId())).forEach(uuid -> {
+ Player target = Bukkit.getPlayer(uuid);
+ if (target != null && target.getUniqueId() != player.getUniqueId()) {
+ target.setLastDamageCause(new EntityDamageEvent(target, EntityDamageEvent.DamageCause.CUSTOM, 0));
+ target.setHealth(0);
+ }
+ });
+ }
+ }
+
+ @EventHandler
+ public void onPlayerRespawn(PlayerRespawnEvent event) {
+ Player player = event.getPlayer();
+ if (playerGroups.containsKey(player.getUniqueId()) && !player.getInventory().contains(Material.COMPASS)) {
+ player.getInventory().addItem(new ItemStack(Material.COMPASS, 1));
+ }
+ }
+
+ private void addPlayer(OfflinePlayer player, Integer index) {
+ if (player.getName() == null) {
+ getLogger().warning("Player name not found");
+ return;
+ };
+
+ ArrayList<UUID> list = uuidMap.getOrDefault(index, new ArrayList<>());
+
+ playerGroups.put(player.getUniqueId(), index);
+ list.add(player.getUniqueId());
+
+ if (!uuidMap.containsKey(index)) {
+ uuidMap.put(index, list);
+ Team team = scoreboard.registerNewTeam(index.toString());
+ if (index == 69) {
+ team.setColor(ChatColor.MAGIC);
+ } else {
+ team.setColor(colors.get(index % colors.size()));
+ }
+ team.setPrefix("Team " + index.toString() + " ");
+ team.setAllowFriendlyFire(false);
+ team.addEntry(player.getName());
+ } else {
+ Team team = scoreboard.getTeam(index.toString());
+ if (team != null) {
+ team.addEntry(player.getName());
+ }
+ }
+
+
+ if (player instanceof Player onlinePlayer) {
+ onlinePlayer.sendMessage(ChatColor.GREEN + "You have been added to team " + index.toString());
+
+ if (!onlinePlayer.getInventory().contains(Material.COMPASS)) {
+ onlinePlayer.getInventory().addItem(new ItemStack(Material.COMPASS, 1));
+ }
+ }
+
+ }
+
+ public boolean addToGroupCommand(CommandSender sender, Command cmd, String label, String[] args) {
+ try {
+ if (args.length == 2) {
+ Player player = Bukkit.getPlayerExact(args[0]);
+ if (player != null && !playerGroups.containsKey(player.getUniqueId())) {
+ Integer index = Integer.parseInt(args[1]);
+ addPlayer(player, index);
+ } else {
+ sender.sendMessage("Player " + args[0] + " does not exist.");
+ }
+ } else {
+ sender.sendMessage("groupAdd usage: /groupAdd <player> <index>");
+ return false;
+ }
+ } catch (NumberFormatException ex) {
+ sender.sendMessage(ChatColor.RED + "usage: /groupAdd <player> <NUMBER>");
+ return false;
+ }
+
+ return true;
+ }
+
+ public boolean removeFromGroupCommand(CommandSender sender, Command cmd, String label, String[] args) {
+ if (args.length > 0) {
+ Player player = Bukkit.getPlayerExact(args[0]);
+ if (player != null) {
+
+ if (playerGroups.containsKey(player.getUniqueId())) {
+ Integer index = playerGroups.get(player.getUniqueId());
+ ArrayList<UUID> list = uuidMap.get(index);
+ list.remove(player.getUniqueId());
+ playerGroups.remove(player.getUniqueId());
+ player.sendMessage(ChatColor.RED + "You have been removed from your team");
+ Team team = scoreboard.getTeam(index.toString());
+ if (team != null) {
+ team.removeEntry(player.getName());
+ }
+ } else {
+ getLogger().warning("Player not in group!");
+ }
+
+ } else {
+ getLogger().warning("Player " + args[0] + " does not exist.");
+ }
+ } else {
+ getLogger().warning("groupAdd usage: /groupAdd <player>");
+ return false;
+ }
+
+ return true;
+ }
+
+ public boolean groupListCommand(CommandSender sender, Command cmd, String label, String[] args) {
+ if (sender instanceof Player player) {
+ uuidMap.forEach((num, list) -> {
+ player.sendMessage(ChatColor.BLUE + "Group: " + num);
+ list.forEach(item -> {
+ OfflinePlayer p = Bukkit.getPlayer(item);
+ if (p == null) {
+ p = Bukkit.getOfflinePlayer(item);
+ }
+ player.sendMessage((p.isOnline() ? ChatColor.GREEN : ChatColor.RED) + " " + p.getName());
+ });
+ });
+ return true;
+ }
+ return false;
+ }
+
+ public boolean groupsSaveCommand(CommandSender sender, Command cmd, String label, String[] args) {
+ return this.saveData();
+ }
+
+ public boolean groupsLoadCommand(CommandSender sender, Command cmd, String label, String[] args) {
+ return this.loadData();
+ }
+
+ public boolean startSavingCommand(CommandSender sender, Command cmd, String label, String[] args) {
+ new SaveTask(this).runTaskTimer(this, 0, 400);
+ return true;
+ }
+}
diff --git a/src/main/java/org/biltopia/SaveTask.java b/src/main/java/org/biltopia/SaveTask.java
new file mode 100644
index 0000000..4fff4f8
--- /dev/null
+++ b/src/main/java/org/biltopia/SaveTask.java
@@ -0,0 +1,18 @@
+package org.biltopia;
+
+import org.bukkit.scheduler.BukkitRunnable;
+
+public class SaveTask extends BukkitRunnable {
+
+ private final Main owner;
+
+ public SaveTask(Main owner) {
+ this.owner = owner;
+ }
+
+ @Override
+ public void run() {
+ owner.saveData();
+ }
+
+}
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
new file mode 100644
index 0000000..ad0d849
--- /dev/null
+++ b/src/main/resources/plugin.yml
@@ -0,0 +1,33 @@
+name: SpeedrunPlugin
+version: 1.0
+main: org.biltopia.Main
+api-version: 1.20
+commands:
+ groupAdd:
+ description: Add player to group
+ permission: speedrun.manage
+ usage: /<command> <player>
+ groupRemove:
+ description: Remove player from group
+ permission: speedrun.manage
+ usage: /<command> <player>
+ groupList:
+ description: Show the groups with all it's players
+ permission: speedrun.manage
+ usage: /<command>
+ groupsSave:
+ description: Save the current group configuration to make it persistent.
+ permission: speedrun.manage
+ usage: /<command>
+ groupsLoad:
+ description: Load the current group configuration from persistent storage.
+ permission: speedrun.manage
+ usage: /<command>
+ startSaving:
+ description: Begins the saving tasks that executes groupsSave repeatedly.
+ permission: speedrun.manage
+ usage: /<command>
+
+permissions:
+ speedrun.manage:
+ description: Allow managing speedrun plugin commands. \ No newline at end of file