diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 717208cb..0d2ea9cd 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -59,31 +59,6 @@ jobs: name: StationofdoomPlugin path: build/libs - publishToRegistry: - runs-on: ubuntu-latest - needs: [build, paths-filter] - if: ${{ github.ref == 'refs/heads/master' && needs.paths-filter.outputs.output1 == 'true' }} - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Set up JDK 21 - uses: actions/setup-java@v4.7.1 - with: - java-version: 21 - distribution: 'adopt' - cache: gradle - - name: Validate Gradle wrapper - uses: gradle/actions/wrapper-validation@v4.4.0 - - name: Set env variables - run: | - echo "REPOSILITE_USER=${{ secrets.REPOSILITE_USER }}" >> $GITHUB_ENV - echo "REPOSILITE_PW=${{ secrets.REPOSILITE_PW }}" >> $GITHUB_ENV - - name: Publish - run: | - ./gradlew publish -PtargetRepo=snapshots - env: - MAVEN_USERNAME: ${{ secrets.REPOSILITE_USER }} - MAVEN_PASSWORD: ${{ secrets.REPOSILITE_PW }} - releaseJar: runs-on: ubuntu-latest needs: [createJar, paths-filter] diff --git a/.github/workflows/repo.yml b/.github/workflows/repo.yml deleted file mode 100644 index cf9dba53..00000000 --- a/.github/workflows/repo.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Repo - -on: - release: - types: [published, edited, released] - -jobs: - createRepo: - runs-on: ubuntu-latest - if: ${{ github.event.release.prerelease == false }} - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - name: Set up JDK 21 - uses: actions/setup-java@v4.7.1 - with: - java-version: 21 - distribution: 'adopt' - cache: gradle - - name: Validate Gradle wrapper - uses: gradle/actions/wrapper-validation@v4.4.0 - - name: Set env variables - run: | - echo "REPOSILITE_USER=${{ secrets.REPOSILITE_USER }}" >> $GITHUB_ENV - echo "REPOSILITE_PW=${{ secrets.REPOSILITE_PW }}" >> $GITHUB_ENV - - name: Publish - run: | - ./gradlew publish - env: - MAVEN_USERNAME: ${{ secrets.REPOSILITE_USER }} - MAVEN_PASSWORD: ${{ secrets.REPOSILITE_PW }} diff --git a/README.md b/README.md index 2daf3d45..30da53bc 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,19 @@ A minecraft paper survival plugin for private servers 3. finished +-
+ Team System + + - Another feature of this plugin is its team system, which lets players create teams, to access it enter the command `/teams`. The teams are saved in the database if one is connected + - **List of Features** + 1. create Teams + 2. change appearance of the team (color & name) + 3. rank system inside the teams to lock important settings of it + 4. team enderchest + 5. shortcut command to the players team menu (`/team`) + 6. protect a location from interactions of players outside the team (the radius of the location can be configured in game settings or via the config file) +
+ **Support and Project Discussion:** - [Discord](https://discord.gg/uYwAKpRyak) @@ -152,7 +165,7 @@ dependencies { reposilite-repository Jonas Franke Repository - https://repo.jonasfranke.xyz/ + https://repo.jonasfranke.xyz/ diff --git a/docker-compose.yml b/docker-compose.yml index aa34b79c..b406eb13 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,10 +2,12 @@ services: postgres: image: postgres:17-alpine ports: - - 9667:5432 + - 5432:5432 volumes: - ./apps/postgres:/var/lib/postgresql/data environment: - POSTGRES_PASSWORD=65465 - POSTGRES_USER=mc - - POSTGRES_DB=stationofdoom \ No newline at end of file + - POSTGRES_DB=stationofdoom + - POSTGRES_APPLICATION_NAME=stationofdoom + - POSTGRES_SCHEMA=public \ No newline at end of file diff --git a/src/main/java/de/j/deathMinigames/database/DBTeamMember.java b/src/main/java/de/j/deathMinigames/database/DBTeamMember.java new file mode 100644 index 00000000..31301163 --- /dev/null +++ b/src/main/java/de/j/deathMinigames/database/DBTeamMember.java @@ -0,0 +1,15 @@ +package de.j.deathMinigames.database; + +import java.util.UUID; + +public class DBTeamMember { + public boolean isInTeam; + public UUID uuid; + public boolean isTeamOperator; + + public DBTeamMember(boolean isInTeam, String uuid, boolean isTeamOperator) { + this.isInTeam = isInTeam; + this.uuid = UUID.fromString(uuid); + this.isTeamOperator = isTeamOperator; + } +} diff --git a/src/main/java/de/j/deathMinigames/database/Database.java b/src/main/java/de/j/deathMinigames/database/Database.java index 0017445a..384a1ad3 100644 --- a/src/main/java/de/j/deathMinigames/database/Database.java +++ b/src/main/java/de/j/deathMinigames/database/Database.java @@ -77,6 +77,8 @@ public void initDatabase(){ isConnected = true; configureDefaultQuery(); PlayerDataDatabase.getInstance().createTable(); + TeamsDatabase.getInstance().createTable(); + TeamEnderchestsDatabase.getInstance().createTable(); Main.getMainLogger().info("Database initialized"); } catch(Exception e) { diff --git a/src/main/java/de/j/deathMinigames/database/PlayerDataDatabase.java b/src/main/java/de/j/deathMinigames/database/PlayerDataDatabase.java index cbf5ac04..b05e4f7d 100644 --- a/src/main/java/de/j/deathMinigames/database/PlayerDataDatabase.java +++ b/src/main/java/de/j/deathMinigames/database/PlayerDataDatabase.java @@ -6,14 +6,11 @@ import de.j.deathMinigames.main.HandlePlayers; import de.j.deathMinigames.main.PlayerData; import de.j.stationofdoom.main.Main; +import de.j.stationofdoom.teams.HandleTeams; +import de.j.stationofdoom.teams.Team; import org.bukkit.Bukkit; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.UUID; +import java.util.*; public class PlayerDataDatabase { private static volatile PlayerDataDatabase instance; @@ -50,7 +47,7 @@ public static PlayerDataDatabase getInstance() { */ public void createTable() { if(!Database.getInstance().isConnected) return; - Query.query("CREATE TABLE IF NOT EXISTS playerData (name VARCHAR(255), UUID VARCHAR(255), introduction BOOLEAN, usesPlugin BOOLEAN, difficulty INT, bestParkourTime FLOAT);") + Query.query("CREATE TABLE IF NOT EXISTS playerData (name VARCHAR(255), UUID VARCHAR(255), introduction BOOLEAN, usesPlugin BOOLEAN, difficulty INT, bestParkourTime FLOAT, isInTeam BOOLEAN, uuidOfTeam VARCHAR(255), isTeamOperator BOOLEAN);") .single() .insert(); } @@ -65,8 +62,9 @@ public void createTable() { * * @return A list of PlayerData objects representing all players in the database. */ - public List getAllPlayerDatas() { + public List getAllPlayerDataFromDB() { if(!Database.getInstance().isConnected) return new ArrayList<>(); + updatePlayerDataDatabase(HandlePlayers.getKnownPlayers().values()); return Query.query("SELECT * FROM playerdata;") .single() .map(row -> new PlayerData(row.getString("name"), @@ -74,10 +72,37 @@ public List getAllPlayerDatas() { row.getBoolean("introduction"), row.getBoolean("usesPlugin"), row.getInt("difficulty"), - row.getFloat("bestParkourTime"))) + row.getFloat("bestParkourTime"), + row.getBoolean("isInTeam"), + row.getString("uuidOfTeam"), + row.getBoolean("isTeamOperator"))) .all(); } + public PlayerData getPlayerDataFromDB(UUID uuid) { + if(!Database.getInstance().isConnected) return null; + try { + return Query.query("SELECT * FROM playerdata WHERE uuid = ?;") + .single(Call.of() + .bind(uuid, UUIDAdapter.AS_STRING)) + .map(row -> new PlayerData(row.getString("name"), + row.getString("uuid"), + row.getBoolean("introduction"), + row.getBoolean("usesPlugin"), + row.getInt("difficulty"), + row.getFloat("bestParkourTime"), + row.getBoolean("isInTeam"), + row.getString("uuidOfTeam"), + row.getBoolean("isTeamOperator"))) + .all() + .getFirst(); + } + catch (NoSuchElementException e) { + Main.getMainLogger().warning("No player data found for uuid: " + uuid); + return null; + } + } + /** * Updates the playerData database with the given player data collection. * @@ -88,20 +113,39 @@ public List getAllPlayerDatas() { * @param playerDatas The collection of player data to update the database with. */ public void updatePlayerDataDatabase(Collection playerDatas) { + if(playerDatas.isEmpty()) return; int newlyAddedPlayers = 0; int updatedPlayers = 0; if(!Database.getInstance().isConnected) return; for (PlayerData playerData : playerDatas) { if(checkIfPlayerIsInDatabase(playerData)) { - Query.query("UPDATE playerData SET name = :name, introduction = :introduction, usesPlugin = :usesPlugin, difficulty = :difficulty, bestParkourTime = :bestParkourTime WHERE uuid = :uuid;") - .single(Call.of() - .bind("name", playerData.getName()) - .bind("introduction", playerData.getIntroduction()) - .bind("usesPlugin", playerData.getUsesPlugin()) - .bind("difficulty", playerData.getDifficulty()) - .bind("bestParkourTime", playerData.getBestParkourTime()) - .bind("uuid", playerData.getUUID(), UUIDAdapter.AS_STRING)) - .update(); + Team team = HandleTeams.getTeam(playerData); + if(team == null || !playerData.isInTeam()) { + Query.query("UPDATE playerData SET name = :name, introduction = :introduction, usesPlugin = :usesPlugin, difficulty = :difficulty, bestParkourTime = :bestParkourTime, isInTeam = :isInTeam WHERE uuid = :uuid;") + .single(Call.of() + .bind("name", playerData.getName()) + .bind("introduction", playerData.getIntroduction()) + .bind("usesPlugin", playerData.getUsesPlugin()) + .bind("difficulty", playerData.getDifficulty()) + .bind("bestParkourTime", playerData.getBestParkourTime()) + .bind("isInTeam", false) + .bind("uuid", playerData.getUniqueId(), UUIDAdapter.AS_STRING)) + .update(); + } + else { + Query.query("UPDATE playerData SET name = :name, introduction = :introduction, usesPlugin = :usesPlugin, difficulty = :difficulty, bestParkourTime = :bestParkourTime, isInTeam = :isInTeam, uuidOfTeam = :uuidOfTeam, isTeamOperator = :isTeamOperator WHERE uuid = :uuid;") + .single(Call.of() + .bind("name", playerData.getName()) + .bind("introduction", playerData.getIntroduction()) + .bind("usesPlugin", playerData.getUsesPlugin()) + .bind("difficulty", playerData.getDifficulty()) + .bind("bestParkourTime", playerData.getBestParkourTime()) + .bind("isInTeam", true) + .bind("uuidOfTeam", playerData.getUuidOfTeam(), UUIDAdapter.AS_STRING) + .bind("isTeamOperator", team.isTeamOperator(playerData)) + .bind("uuid", playerData.getUniqueId(), UUIDAdapter.AS_STRING)) + .update(); + } updatedPlayers++; } else { @@ -122,14 +166,17 @@ public void updatePlayerDataDatabase(Collection playerDatas) { */ public void addPlayerToDatabase(PlayerData playerData) { if(!Database.getInstance().isConnected) return; - Query.query("INSERT INTO playerData (name, UUID, introduction, usesPlugin, difficulty, bestParkourTime) VALUES (:name, :uuid, :introduction, :usesPlugin, :difficulty, :bestParkourTime);") + Query.query("INSERT INTO playerData (name, UUID, introduction, usesPlugin, difficulty, bestParkourTime, isInTeam, uuidOfTeam, isTeamOperator) VALUES (:name, :uuid, :introduction, :usesPlugin, :difficulty, :bestParkourTime, :isInTeam, :uuidOfTeam, :isTeamOperator);") .single(Call.of() .bind("name", playerData.getName()) - .bind("uuid", playerData.getUUID(), UUIDAdapter.AS_STRING) + .bind("uuid", playerData.getUniqueId(), UUIDAdapter.AS_STRING) .bind("introduction", playerData.getIntroduction()) .bind("usesPlugin", playerData.getUsesPlugin()) .bind("difficulty", playerData.getDifficulty()) - .bind("bestParkourTime", playerData.getBestParkourTime())) + .bind("bestParkourTime", playerData.getBestParkourTime()) + .bind("isInTeam", playerData.isInTeam()) + .bind("uuidOfTeam", playerData.getUuidOfTeam(), UUIDAdapter.AS_STRING) + .bind("isTeamOperator", playerData.isTeamOperator())) .insert(); } @@ -139,19 +186,22 @@ public void addPlayerToDatabase(PlayerData playerData) { *

This method fetches all player data records from the database and checks * if the player with the given UUID is present in the list. * - * @param playerDataPlayerToCheck The player data to check. + * @param playerDataToCheck The player data to check. * @return true if the player is in the database, false otherwise. */ - public boolean checkIfPlayerIsInDatabase(PlayerData playerDataPlayerToCheck) { - if(!Database.getInstance().isConnected) return HandlePlayers.getKnownPlayers().containsKey(playerDataPlayerToCheck.getUUID()); // does not return false or true to prevent unpredictable behavior - List playerDatas = getAllPlayerDatas(); - boolean isInDatabase = false; - if(playerDatas.isEmpty()) return false; - for (PlayerData playerDataToCompare : playerDatas) { - if(playerDataToCompare.getUUID().equals(playerDataPlayerToCheck.getUUID())) { - isInDatabase = true; - } - } - return isInDatabase; + public boolean checkIfPlayerIsInDatabase(PlayerData playerDataToCheck) { + return checkIfPlayerIsInDatabase(playerDataToCheck.getUniqueId()); + } + + public boolean checkIfPlayerIsInDatabase(UUID uuidOfPlayerToCheck) { + if(!Database.getInstance().isConnected) return HandlePlayers.getKnownPlayers().containsKey(uuidOfPlayerToCheck); // does not return false or true to prevent unpredictable behavior + List data = Query.query("SELECT UUID FROM playerData WHERE UUID = :UUID;") + .single(Call.of() + .bind("UUID", uuidOfPlayerToCheck, UUIDAdapter.AS_STRING)) + .map(row -> UUID.fromString(row.getString("UUID"))) + .all(); + + Main.getMainLogger().warning("CheckIfPlayerIsInDatabase for: " + Bukkit.getOfflinePlayer(uuidOfPlayerToCheck).getName() + ", found " + !data.isEmpty()); + return !data.isEmpty(); } } diff --git a/src/main/java/de/j/deathMinigames/database/TeamEnderchestsDatabase.java b/src/main/java/de/j/deathMinigames/database/TeamEnderchestsDatabase.java new file mode 100644 index 00000000..1eac5c30 --- /dev/null +++ b/src/main/java/de/j/deathMinigames/database/TeamEnderchestsDatabase.java @@ -0,0 +1,88 @@ +package de.j.deathMinigames.database; + +import de.chojo.sadu.queries.api.call.Call; +import de.chojo.sadu.queries.api.query.Query; +import de.chojo.sadu.queries.call.adapter.UUIDAdapter; +import de.j.stationofdoom.main.Main; +import de.j.stationofdoom.teams.Team; +import de.j.stationofdoom.teams.TeamsMainMenuGUI; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.UUID; + +public class TeamEnderchestsDatabase { + private static volatile TeamEnderchestsDatabase instance; + + public TeamEnderchestsDatabase() {} + + public static TeamEnderchestsDatabase getInstance() { + if (instance == null) { + synchronized (TeamEnderchestsDatabase.class) { + if (instance == null) { + instance = new TeamEnderchestsDatabase(); + } + } + } + return instance; + } + + public void createTable() { + if(!Database.getInstance().isConnected) return; + Query.query("CREATE TABLE IF NOT EXISTS teamEnderchests (uuidOfTeam VARCHAR(255), name VARCHAR(255), amount INTEGER, material VARCHAR(255));") + .single() + .insert(); + } + + public Inventory getTeamEnderchest(UUID uuidOfTeam) { + Inventory inv = Bukkit.createInventory(null, 27, "Team Enderchest"); + if(!Database.getInstance().isConnected) return inv; + Query.query("SELECT * FROM teamEnderchests WHERE uuidOfTeam = ?;") + .single(Call.of() + .bind(uuidOfTeam, UUIDAdapter.AS_STRING)) + .map(row -> { + ItemStack itemStack; + try { + itemStack = new ItemStack(Material.valueOf(row.getString("material")), row.getInt("amount")); + ItemMeta itemMeta = itemStack.getItemMeta(); + if(row.getString("name") != null && !row.getString("name").isEmpty()) itemMeta.displayName(Component.text(row.getString("name"))); + itemStack.setItemMeta(itemMeta); + } + catch (NullPointerException e) { + Main.getMainLogger().warning("Could not find material of " + row.getString("material") + " in team enderchests of team " + uuidOfTeam); + itemStack = new ItemStack(Material.STONE, 1); + itemStack.getItemMeta().displayName(Component.text("Could not find material of " + row.getString("material"))); + } + inv.addItem(itemStack); + return itemStack; + }) + .all(); + return inv; + } + + public void updateTeamEnderchestsOfAllTeams() { + if(!Database.getInstance().isConnected) return; + for (Team team : TeamsMainMenuGUI.teams) { + UUID uuidOfTeam = team.getUuid(); + Query.query("DELETE FROM teamEnderchests WHERE uuidOfTeam = ?;") + .single(Call.of() + .bind(uuidOfTeam, UUIDAdapter.AS_STRING)) + .delete(); + if(team.inventory == null) continue; + for (ItemStack itemStack : team.inventory.getContents()) { + if(itemStack == null) continue; + Query.query("INSERT INTO teamEnderchests (uuidOfTeam, name, amount, material) VALUES (?, ?, ?, ?);") + .single(Call.of() + .bind(uuidOfTeam, UUIDAdapter.AS_STRING) + .bind(itemStack.getItemMeta().displayName() != null ? itemStack.getItemMeta().getDisplayName() : null) + .bind(itemStack.getAmount()) + .bind(itemStack.getType().toString())) + .insert(); + } + } + } +} diff --git a/src/main/java/de/j/deathMinigames/database/TeamsDatabase.java b/src/main/java/de/j/deathMinigames/database/TeamsDatabase.java new file mode 100644 index 00000000..a9861bdc --- /dev/null +++ b/src/main/java/de/j/deathMinigames/database/TeamsDatabase.java @@ -0,0 +1,166 @@ +package de.j.deathMinigames.database; + + +import de.chojo.sadu.queries.api.call.Call; +import de.chojo.sadu.queries.api.query.Query; +import de.chojo.sadu.queries.call.adapter.UUIDAdapter; +import de.j.deathMinigames.main.HandlePlayers; +import de.j.deathMinigames.main.PlayerData; +import de.j.stationofdoom.main.Main; +import de.j.stationofdoom.teams.HandleTeams; +import de.j.stationofdoom.teams.Team; + +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; + +public class TeamsDatabase { + private static volatile TeamsDatabase instance; + + public TeamsDatabase() {} + + public static TeamsDatabase getInstance() { + if (instance == null) { + synchronized (TeamsDatabase.class) { + if (instance == null) { + instance = new TeamsDatabase(); + } + } + } + return instance; + } + + public void createTable() { + if(!Database.getInstance().isConnected) return; + Query.query("CREATE TABLE IF NOT EXISTS teams (name VARCHAR(255), color VARCHAR(255), locked BOOLEAN, uuid VARCHAR(255), world VARCHAR(255), protectedLocationX INT, protectedLocationY INT, protectedLocationZ INT);") + .single() + .insert(); + } + + public List getTeams() { + if(!Database.getInstance().isConnected) return new ArrayList<>(); + List teams = new ArrayList<>(); + Query.query("SELECT * FROM teams;") + .single() + .map(row -> new Team(row.getString("name"), + row.getString("color"), + row.getBoolean("locked"), + row.getString("uuid"), + row.getString("world"), + row.getInt("protectedLocationX"), + row.getInt("protectedLocationY"), + row.getInt("protectedLocationZ"))) + .all() + .forEach(team -> teams.add(team)); + Main.getMainLogger().info("Found " + teams.size() + " team(s):"); + for (Team team : teams) { + Main.getMainLogger().info(team.getName()); + try { + Query.query("SELECT isInTeam, uuid, isTeamOperator FROM playerData WHERE uuidOfTeam = ?;") + .single(Call.of() + .bind(team.getUuid(), UUIDAdapter.AS_STRING) + ) + .map(row -> new DBTeamMember( + row.getBoolean("isInTeam"), + row.getString("uuid"), + row.getBoolean("isTeamOperator"))) + .all() + .forEach(team::addMember); + } + catch (Exception e) { + e.printStackTrace(); + Main.getMainLogger().warning("Could not get players from team " + team.getName()); + } + } + return teams; + } + + public void insertTeam(Team team) { + if(!Database.getInstance().isConnected) return; + if(team.getProtectedLocation() != null) { + Query.query("INSERT INTO teams (name, color, locked, uuid, world, protectedLocationX, protectedLocationY, protectedLocationZ) VALUES (?, ?, ?, ?, ?, ?, ?, ?);") + .single(Call.of() + .bind(team.getName()) + .bind(team.getColorAsMaterial().name()) + .bind(team.getLocked()) + .bind(team.getUuid(), UUIDAdapter.AS_STRING) + .bind(team.getProtectedLocation().getWorld().getName()) + .bind(team.getProtectedLocation().getBlockX()) + .bind(team.getProtectedLocation().getBlockY()) + .bind(team.getProtectedLocation().getBlockZ()) + ) + .insert(); + } + else { + Query.query("INSERT INTO teams (name, color, locked, uuid) VALUES (?, ?, ?, ?);") + .single(Call.of() + .bind(team.getName()) + .bind(team.getColorAsMaterial().name()) + .bind(team.getLocked()) + .bind(team.getUuid(), UUIDAdapter.AS_STRING)) + .insert(); + } + for(UUID uuid : team.getAllPlayers()) { + PlayerData playerData = HandlePlayers.getInstance().getPlayerData(uuid); + updatePlayerInDB(playerData); + } + } + + public void updatePlayerInDB(PlayerData playerData) { + if(!Database.getInstance().isConnected) return; + Team team = HandleTeams.getTeam(playerData); + if(team == null || !playerData.isInTeam()) { + Main.getMainLogger().warning("Player is not in team, isInTeam = " + playerData.isInTeam()); + Query.query("UPDATE playerData SET isInTeam = ? WHERE uuid = ?;") + .single(Call.of() + .bind(false) + .bind(playerData.getUniqueId(), UUIDAdapter.AS_STRING)) + .insert(); + } + else { + Main.getMainLogger().warning("Player is in team, isInTeam = " + playerData.isInTeam()); + Query.query("UPDATE playerData SET uuidOfTeam = ?, isTeamOperator = ? WHERE uuid = ?;") + .single(Call.of() + .bind(team.getUuid().toString()) + .bind(team.isTeamOperator(playerData)) + .bind(playerData.getUniqueId(), UUIDAdapter.AS_STRING)) + .insert(); + } + } + + public void updateTeamsDatabase() { + if(!Database.getInstance().isConnected) return; + List teams = HandleTeams.getInstance().getAllTeams(); + wipeDatabase(); + for (Team team : teams) { + if(team.getAllPlayers().isEmpty()) { + Main.getMainLogger().info("Team " + team.getName() + " has no players, removing it"); + } + else { + insertTeam(team); + } + } + Main.getMainLogger().info("Updated teams database"); + } + + private void wipeDatabase() { + if(!Database.getInstance().isConnected) return; + Query.query("DELETE FROM teams;") + .single() + .delete(); + } + + public void removeTeam(Team team) { + if(!Database.getInstance().isConnected) return; + Query.query("DELETE FROM teams WHERE uuid = ?;") + .single(Call.of() + .bind(team.getUuid(), UUIDAdapter.AS_STRING)) + .delete(); + for(UUID uuid : team.getAllPlayers()) { + PlayerData playerData = HandlePlayers.getInstance().getPlayerData(uuid); + updatePlayerInDB(playerData); + } + } +} diff --git a/src/main/java/de/j/deathMinigames/listeners/AnvilListener.java b/src/main/java/de/j/deathMinigames/listeners/AnvilListener.java index 7218257b..af5931b1 100644 --- a/src/main/java/de/j/deathMinigames/listeners/AnvilListener.java +++ b/src/main/java/de/j/deathMinigames/listeners/AnvilListener.java @@ -1,8 +1,13 @@ package de.j.deathMinigames.listeners; import de.j.deathMinigames.dmUtil.DmUtil; +import de.j.deathMinigames.main.HandlePlayers; import de.j.deathMinigames.settings.MainMenu; import de.j.stationofdoom.main.Main; +import de.j.stationofdoom.teams.HandleTeams; +import de.j.stationofdoom.teams.Team; +import de.j.stationofdoom.teams.TeamSettingsGUI; +import de.j.stationofdoom.teams.chunkClaimSystem.ChunkClaimSystem; import de.j.stationofdoom.util.Tablist; import de.j.stationofdoom.util.translations.TranslationFactory; import net.kyori.adventure.text.Component; @@ -22,9 +27,13 @@ import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.view.AnvilView; +import static io.papermc.paper.registry.keys.SoundEventKeys.*; + public class AnvilListener implements Listener { private String serverName; private String hostName; + private String teamName; + private int claimingRadius; private TranslationFactory tf = new TranslationFactory(); @EventHandler @@ -54,6 +63,26 @@ else if(MainMenu.getSetServerName().compareLocIDTo(loc)) { if(renameText == null) return; serverName = renameText; } + else if(TeamSettingsGUI.renameTeam.compareLocIDTo(loc)) { + finishAnvilInvAfterOpening(event, player); + if(renameText == null) return; + teamName = renameText; + } + else if(MainMenu.getSetClaimingRadius().compareLocIDTo(loc)) { + finishAnvilInvAfterOpening(event, player); + if(renameText == null) return; + try { + claimingRadius = Integer.parseInt(renameText); + } + catch(NumberFormatException e) { + player.sendMessage(Component.text(tf.getTranslation(player, "invalidAnvilInputClaimingRadius"))); + return; + } + if(claimingRadius <= 0 || claimingRadius > 256) { + player.sendMessage(Component.text(tf.getTranslation(player, "invalidAnvilInputClaimingRadius"))); + return; + } + } } @EventHandler @@ -69,17 +98,43 @@ public void onAnvilClick(InventoryClickEvent event) { if (hostName == null) return; Tablist.setHostedBy(hostName); event.getView().close(); - DmUtil.getInstance().playSoundAtLocation(player.getLocation(), 0.5f, Sound.BLOCK_ANVIL_USE); + player.playSound(net.kyori.adventure.sound.Sound.sound(BLOCK_CHISELED_BOOKSHELF_INSERT_ENCHANTED, net.kyori.adventure.sound.Sound.Source.PLAYER, 3F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); player.sendMessage(Component.text("Host name: " + hostName).color(NamedTextColor.GOLD)); } else if (MainMenu.getSetServerName().compareLocIDTo(loc)) { event.setCancelled(true); if (serverName == null) return; Tablist.setServerName(serverName); event.getView().close(); - DmUtil.getInstance().playSoundAtLocation(player.getLocation(), 0.5f, Sound.BLOCK_ANVIL_USE); + player.playSound(net.kyori.adventure.sound.Sound.sound(BLOCK_CHISELED_BOOKSHELF_INSERT_ENCHANTED, net.kyori.adventure.sound.Sound.Source.PLAYER, 3F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); player.sendMessage(Component.text("Server name: " + serverName).color(NamedTextColor.GOLD)); } - + else if(TeamSettingsGUI.renameTeam.compareLocIDTo(loc)) { + event.setCancelled(true); + if(teamName == null) { + Main.getMainLogger().info("teamName is null"); + return; + } + Team team = HandleTeams.getTeam(HandlePlayers.getInstance().getPlayerData(player.getUniqueId())); + if(team == null) { + Main.getMainLogger().warning("Team is null in onAnvilClick"); + player.sendMessage(Component.text(tf.getTranslation(player, "noTeam"))); + return; + } + Main.getMainLogger().info("set name of team " + team.getName() + " to: " + teamName); + team.setName(teamName); + new TeamSettingsGUI(team).showPage(1, player); + player.playSound(net.kyori.adventure.sound.Sound.sound(BLOCK_CHISELED_BOOKSHELF_INSERT_ENCHANTED, net.kyori.adventure.sound.Sound.Source.PLAYER, 3F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + } + else if(MainMenu.getSetClaimingRadius().compareLocIDTo(loc)) { + event.setCancelled(true); + if(claimingRadius <= 0 || claimingRadius > 256) { + player.sendMessage(Component.text(tf.getTranslation(player, "invalidAnvilInputClaimingRadius"))); + return; + } + ChunkClaimSystem.getInstance().setProtectedLocationSizeInBlocks(claimingRadius); + event.getView().close(); + player.sendMessage(Component.text(tf.getTranslation(player, "setClaimingRadius", ChunkClaimSystem.getInstance().getProtectedLocationSizeInBlocks())).color(NamedTextColor.GOLD)); + } } } @@ -95,6 +150,12 @@ public void onAnvilClose(InventoryCloseEvent event) { else if(MainMenu.getSetServerName().compareLocIDTo(loc)) { anvilInventory.clear(); } + else if(TeamSettingsGUI.renameTeam.compareLocIDTo(loc)) { + anvilInventory.clear(); + } + else if(MainMenu.getSetClaimingRadius().compareLocIDTo(loc)) { + anvilInventory.clear(); + } } } diff --git a/src/main/java/de/j/deathMinigames/listeners/InventoryListener.java b/src/main/java/de/j/deathMinigames/listeners/InventoryListener.java index f0168023..15f58db1 100755 --- a/src/main/java/de/j/deathMinigames/listeners/InventoryListener.java +++ b/src/main/java/de/j/deathMinigames/listeners/InventoryListener.java @@ -256,6 +256,9 @@ private void handleMainMenuGUI(InventoryClickEvent event, Player player, MainMen case 5: MainMenu.getSetServerName().showInventory(player); break; + case 6: + MainMenu.getSetClaimingRadius().showInventory(player); + break; } } diff --git a/src/main/java/de/j/deathMinigames/listeners/JoinListener.java b/src/main/java/de/j/deathMinigames/listeners/JoinListener.java index 5ac67ffd..a5725310 100755 --- a/src/main/java/de/j/deathMinigames/listeners/JoinListener.java +++ b/src/main/java/de/j/deathMinigames/listeners/JoinListener.java @@ -3,6 +3,7 @@ import de.j.deathMinigames.main.HandlePlayers; import de.j.deathMinigames.main.PlayerData; import de.j.deathMinigames.main.PlayerMinigameStatus; +import de.j.stationofdoom.main.Main; import de.j.stationofdoom.util.translations.TranslationFactory; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -32,13 +33,12 @@ public void onJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); TranslationFactory tf = new TranslationFactory(); HandlePlayers handlePlayers = HandlePlayers.getInstance(); - if(!handlePlayers.checkIfPlayerIsKnown(player.getUniqueId())) { handlePlayers.addNewPlayer(player); player.sendMessage(Component.text(tf.getTranslation(player,"addedToPlayerList")).color(NamedTextColor.GOLD) .append(Component.text(HandlePlayers.getKnownPlayers().get(player.getUniqueId()).getDifficulty()).color(NamedTextColor.RED))); } - PlayerData playerData = HandlePlayers.getKnownPlayers().get(player.getUniqueId()); + PlayerData playerData = HandlePlayers.getInstance().getPlayerData(player.getUniqueId()); if(playerData.getStatus().equals(PlayerMinigameStatus.DECIDING)) { respawnListener.handleTimerWhilePlayerDecides(player); } diff --git a/src/main/java/de/j/deathMinigames/main/Config.java b/src/main/java/de/j/deathMinigames/main/Config.java index 564cdc2d..3768d63a 100644 --- a/src/main/java/de/j/deathMinigames/main/Config.java +++ b/src/main/java/de/j/deathMinigames/main/Config.java @@ -1,9 +1,9 @@ package de.j.deathMinigames.main; import de.j.stationofdoom.enchants.CustomEnchantsEnum; +import de.j.stationofdoom.teams.chunkClaimSystem.ChunkClaimSystem; import de.j.stationofdoom.util.Tablist; import org.bukkit.Location; - import de.j.stationofdoom.main.Main; import org.bukkit.World; import org.bukkit.configuration.file.FileConfiguration; @@ -140,6 +140,9 @@ private void handleCloneTablist(FileConfiguration config) { Tablist.setHostedBy(config.getString("Tablist.HostedBy")); } } + if(config.contains("ProtectedLocationRadius")) { + ChunkClaimSystem.getInstance().setProtectedLocationSizeInBlocks(config.getInt("ProtectedLocationRadius")); + } } private void handleCloneCustomEnchants(FileConfiguration config) { @@ -177,7 +180,6 @@ public void cloneWaitingListLocationToPlugin(World world) { int y = Main.getPlugin().getConfig().getInt("WaitingListPosition.y"); int z = Main.getPlugin().getConfig().getInt("WaitingListPosition.z"); configWaitingListPosition = new Location(world, x, y, z); - Main.getMainLogger().info("set WaitingListPosition from config to: " + configWaitingListPosition.getBlockX() + ", " + configWaitingListPosition.getBlockY() + ", " + configWaitingListPosition.getBlockZ()); } else { Main.getMainLogger().warning("WaitingListPosition not found in config!"); @@ -259,6 +261,13 @@ public synchronized void setWaitingListPosition(Location location) { Main.getMainLogger().info("set WaitingListPosition to: " + configWaitingListPosition); } + public synchronized void setProtectedLocationSizeInBlocksInConfig(int size) { + if(size == 0 || size == Main.getPlugin().getConfig().getInt("ProtectedLocationRadius")) return; + Main.getPlugin().getConfig().set("ProtectedLocationRadius", size); + Main.getPlugin().saveConfig(); + Main.getMainLogger().info("set ProtectedLocationSizeInBlocksInConfig to: " + size); + } + /** * Checks if the plugin is set up. * diff --git a/src/main/java/de/j/deathMinigames/main/HandlePlayers.java b/src/main/java/de/j/deathMinigames/main/HandlePlayers.java index 15ae6362..76e7bac3 100644 --- a/src/main/java/de/j/deathMinigames/main/HandlePlayers.java +++ b/src/main/java/de/j/deathMinigames/main/HandlePlayers.java @@ -1,11 +1,10 @@ package de.j.deathMinigames.main; +import de.j.deathMinigames.database.Database; import de.j.deathMinigames.database.PlayerDataDatabase; import de.j.deathMinigames.minigames.Minigame; import de.j.stationofdoom.main.Main; -import de.j.stationofdoom.util.translations.TranslationFactory; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; import java.util.*; @@ -58,10 +57,10 @@ public static HashMap getKnownPlayers() { */ public static void initKnownPlayersPlayerData() { PlayerDataDatabase playerDataDatabase = PlayerDataDatabase.getInstance(); - for(PlayerData playerData : playerDataDatabase.getAllPlayerDatas()) { - knownPlayers.put(playerData.getUUID(), playerData); + for(PlayerData playerData : playerDataDatabase.getAllPlayerDataFromDB()) { + HandlePlayers.knownPlayers.put(playerData.getUniqueId(), playerData); } - Main.getMainLogger().info("Loaded " + knownPlayers.size() + " known players and their data"); + Main.getMainLogger().info("Loaded " + HandlePlayers.knownPlayers.size() + " known players and their data"); } /** @@ -71,7 +70,7 @@ public static void initKnownPlayersPlayerData() { * @return true if the player is known, false otherwise. */ public boolean checkIfPlayerIsKnown(UUID uuid) { - return knownPlayers.containsKey(uuid); + return HandlePlayers.knownPlayers.containsKey(uuid); } /** @@ -82,14 +81,14 @@ public boolean checkIfPlayerIsKnown(UUID uuid) { * @param player The player to add. */ public synchronized void addNewPlayer(Player player) { - PlayerData playerData = new PlayerData(player); UUID playerUUID = player.getUniqueId(); if(checkIfPlayerIsKnown(playerUUID)) { Main.getMainLogger().warning("Player " + playerUUID + " was tried to add, but is already known!"); return; } - knownPlayers.put(playerUUID, playerData); - Main.getMainLogger().info("Added new player " + playerData.getName()); + PlayerData playerData = new PlayerData(player); + HandlePlayers.knownPlayers.put(playerUUID, playerData); + PlayerDataDatabase.getInstance().addPlayerToDatabase(playerData); } @@ -101,7 +100,7 @@ public synchronized void addNewPlayer(Player player) { */ public static void copyAllPlayerDataIntoDatabase() { PlayerDataDatabase playerDataDatabase = PlayerDataDatabase.getInstance(); - playerDataDatabase.updatePlayerDataDatabase(knownPlayers.values()); + playerDataDatabase.updatePlayerDataDatabase(HandlePlayers.knownPlayers.values()); } /** @@ -114,7 +113,7 @@ public static void copyAllPlayerDataIntoDatabase() { public List getLeaderBoard() { float defaultTime = 1000f; List leaderboard = new ArrayList<>(); - for (PlayerData playerData : knownPlayers.values()) { + for (PlayerData playerData : HandlePlayers.knownPlayers.values()) { if(playerData.getBestParkourTime() == defaultTime) continue; leaderboard.add(playerData); } @@ -124,7 +123,7 @@ public List getLeaderBoard() { } public void resetLeaderboardAndTimesOfPlayers() { - for (PlayerData playerData : knownPlayers.values()) { + for (PlayerData playerData : HandlePlayers.knownPlayers.values()) { playerData.setBestParkourTime(1000f); } } @@ -145,4 +144,11 @@ public void handlePlayerLeftWhileProcessing(Player player) { playerData.setLeftWhileProcessing(false); } } + + public PlayerData getPlayerData(UUID uuidOfPlayer) { + if(!this.checkIfPlayerIsKnown(uuidOfPlayer)) { + addNewPlayer(Bukkit.getPlayer(uuidOfPlayer)); + } + return HandlePlayers.knownPlayers.get(uuidOfPlayer); + } } diff --git a/src/main/java/de/j/deathMinigames/main/PlayerData.java b/src/main/java/de/j/deathMinigames/main/PlayerData.java index 3bb062ad..bbbd1069 100644 --- a/src/main/java/de/j/deathMinigames/main/PlayerData.java +++ b/src/main/java/de/j/deathMinigames/main/PlayerData.java @@ -1,7 +1,9 @@ package de.j.deathMinigames.main; import de.j.stationofdoom.main.Main; +import de.j.stationofdoom.teams.HandleTeams; import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; @@ -18,16 +20,23 @@ public synchronized void setName(String name) { this.name = name; } - public synchronized UUID getUUID() { + public synchronized UUID getUniqueId() { return uuid; } - public synchronized void setUUID(UUID uuid) { + public synchronized void setUniqueID(UUID uuid) { this.uuid = uuid; } public synchronized Player getPlayer() { - return player; + if(this.player == null) { + this.player = Bukkit.getPlayer(this.uuid); + } + return this.player; + } + + public synchronized OfflinePlayer getOfflinePlayer() { + return Bukkit.getOfflinePlayer(this.uuid); } public synchronized PlayerMinigameStatus getStatus() { @@ -62,6 +71,16 @@ public synchronized void setLastDeathLocation(Location lastDeathLocation) { this.lastDeathLocation = lastDeathLocation; } + public synchronized Location getLocation() { + try { + return getPlayer().getLocation(); + } + catch (NullPointerException e) { + Main.getMainLogger().warning("Tried accessing location of " + this.name + " but player is not online!"); + return Bukkit.getOfflinePlayer(this.uuid).getLocation(); + } + } + public synchronized int getDecisionTimer() { return decisionTimer; } @@ -102,9 +121,18 @@ public synchronized void setUsesPlugin(boolean usesPlugin) { this.usesPlugin = usesPlugin; } + public boolean isOnline() { + try { + return getPlayer().isConnected(); + } + catch (NullPointerException e) { + return false; + } + } + private volatile String name; // in database private volatile UUID uuid; // in database - private final Player player; + private volatile Player player; private volatile PlayerMinigameStatus status; private volatile Inventory lastDeathInventory = Bukkit.createInventory(null, 9*6); private volatile Location lastDeathLocation; @@ -113,6 +141,33 @@ public synchronized void setUsesPlugin(boolean usesPlugin) { private volatile int difficulty; // in database private volatile int decisionTimer; private volatile float bestParkourTime; // in database + private volatile boolean isInTeam; // in database + private volatile UUID uuidOfTeam; // in database + private volatile boolean teamOperator; // in database + + public boolean isInTeam() { + return this.isInTeam; + } + + public void setInTeam(boolean isInTeam) { + this.isInTeam = isInTeam; + } + + public UUID getUuidOfTeam() { + return this.uuidOfTeam; + } + + public void setUuidOfTeam(UUID uuidOfTeam) { + this.uuidOfTeam = uuidOfTeam; + } + + public boolean isTeamOperator() { + return teamOperator; + } + + public void setTeamOperator(boolean teamOperator) { + this.teamOperator = teamOperator; + } public boolean getLeftWhileProcessing() { return leftWhileProcessing; @@ -139,7 +194,7 @@ public PlayerData(Player player) { this.leftWhileProcessing = false; } - public PlayerData(String name, String uuid, boolean introduction, boolean usesPlugin, int difficulty, float bestParkourTime) { + public PlayerData(String name, String uuid, boolean introduction, boolean usesPlugin, int difficulty, float bestParkourTime, boolean isInTeam, String uuidOfTeam, boolean teamOperator) { Config config = Config.getInstance(); this.name = name; this.uuid = UUID.fromString(uuid); @@ -152,14 +207,10 @@ public PlayerData(String name, String uuid, boolean introduction, boolean usesPl this.introduction = introduction; this.usesPlugin = usesPlugin; this.leftWhileProcessing = false; - } - - /** - * Updates the player's name to the current name of the player entity. - * This method synchronizes the stored name with the live player's name. - */ - public void updateName() { - this.name = player.getName(); + if(isInTeam) { + this.uuidOfTeam = UUID.fromString(uuidOfTeam); + this.teamOperator = teamOperator; + } } /** diff --git a/src/main/java/de/j/deathMinigames/settings/AnvilUI.java b/src/main/java/de/j/deathMinigames/settings/AnvilUI.java index a3e5ef2c..91241e72 100644 --- a/src/main/java/de/j/deathMinigames/settings/AnvilUI.java +++ b/src/main/java/de/j/deathMinigames/settings/AnvilUI.java @@ -1,5 +1,10 @@ package de.j.deathMinigames.settings; +import de.j.deathMinigames.main.HandlePlayers; +import de.j.stationofdoom.main.Main; +import de.j.stationofdoom.teams.HandleTeams; +import de.j.stationofdoom.teams.Team; +import de.j.stationofdoom.teams.chunkClaimSystem.ChunkClaimSystem; import de.j.stationofdoom.util.Tablist; import de.j.stationofdoom.util.translations.TranslationFactory; import net.kyori.adventure.text.Component; @@ -66,9 +71,30 @@ private void setInputMeta(Player player) { } else { switch (title) { - case SET_HOST_NAME -> inputItemName = Tablist.getHostedBy(); - case SET_SERVER_NAME -> inputItemName = Tablist.getServerName(); - default -> throw new IllegalArgumentException("Title: " + title + " is not supported"); + case SET_HOST_NAME: + inputItemName = Tablist.getHostedBy(); + break; + case SET_SERVER_NAME: + inputItemName = Tablist.getServerName(); + break; + case TEAM_RENAME: + Team team = HandleTeams.getTeam(HandlePlayers.getInstance().getPlayerData(player.getUniqueId())); + if(team == null) { + Main.getMainLogger().warning("Team is null in setInputMeta"); + return; + } + if(team.getName() != null) { + inputItemName = team.getName(); + } + else { + inputItemName = ""; + } + break; + case SET_CLAIMING_RADIUS: + inputItemName = String.valueOf(ChunkClaimSystem.getInstance().getProtectedLocationSizeInBlocks()); + break; + default: + throw new IllegalArgumentException("Title: " + title + " is not supported!"); } if(inputItemName == null) { inputMeta.displayName(Component.text(new TranslationFactory().getTranslation(player, "noNameSet"))); diff --git a/src/main/java/de/j/deathMinigames/settings/GUI.java b/src/main/java/de/j/deathMinigames/settings/GUI.java index f0a6908c..62ff55c4 100755 --- a/src/main/java/de/j/deathMinigames/settings/GUI.java +++ b/src/main/java/de/j/deathMinigames/settings/GUI.java @@ -7,17 +7,12 @@ import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.Material; -import org.bukkit.OfflinePlayer; -import org.bukkit.Server; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; -import de.j.deathMinigames.main.Config; -import de.j.deathMinigames.listeners.InventoryListener; import org.bukkit.inventory.meta.SkullMeta; -import org.bukkit.profile.PlayerProfile; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -26,8 +21,13 @@ import java.util.UUID; public class GUI implements InventoryHolder { - private final Inventory inventory; - private final UUID uuid = UUID.randomUUID(); + protected Inventory inventory; + protected final UUID uuid = UUID.randomUUID(); + + public GUI() { + int inventorySize = 54; + inventory = Bukkit.createInventory(this, inventorySize); + } public GUI(String title, boolean addAllPlayers, boolean addAsPlayerHeads) { if(title == null) { @@ -46,6 +46,22 @@ public GUI(String title, boolean addAllPlayers, boolean addAsPlayerHeads) { } } + public GUI(String title, boolean addAllPlayers, boolean addAsPlayerHeads, int size) { + if(title == null) { + throw new NullPointerException("Title is null!"); + } + inventory = Bukkit.createInventory(this, size, title); + if(addAllPlayers) { + HashMap knownPlayers = HandlePlayers.getKnownPlayers(); + if(addAsPlayerHeads) { + addPlayerHeads(knownPlayers); + } + else { + addBooleanBased(knownPlayers, title); + } + } + } + public void addPlayerHeads(HashMap knownPlayers) { int maxSlots = inventory.getSize() - 1; List playerKeys = new ArrayList<>(knownPlayers.keySet()); @@ -55,10 +71,10 @@ public void addPlayerHeads(HashMap knownPlayers) { break; } PlayerData playerData = knownPlayers.get(playerKeys.get(i)); - if(playerData == null || playerData.getUUID() == null) continue; + if(playerData == null || playerData.getUniqueId() == null) continue; ItemStack head = new ItemStack(Material.PLAYER_HEAD, 1); SkullMeta skullMeta = (SkullMeta) head.getItemMeta(); - skullMeta.setOwnerProfile(Bukkit.createProfile(playerData.getUUID())); + skullMeta.setOwnerProfile(Bukkit.createProfile(playerData.getUniqueId())); skullMeta.displayName(Component.text(playerData.getName())); head.setItemMeta(skullMeta); @@ -66,6 +82,17 @@ public void addPlayerHeads(HashMap knownPlayers) { } } + public void addPlayerHead(PlayerData playerData, int slot, List lore) { + ItemStack head = new ItemStack(Material.PLAYER_HEAD, 1); + SkullMeta skullMeta = (SkullMeta) head.getItemMeta(); + skullMeta.setOwnerProfile(Bukkit.createProfile(playerData.getUniqueId())); + skullMeta.displayName(Component.text(playerData.getName())); + skullMeta.setLore(lore); + head.setItemMeta(skullMeta); + + inventory.setItem(slot, head); + } + private void addBooleanBased(HashMap knownPlayers, String title) { List playerKeys = new ArrayList<>(knownPlayers.keySet()); for(int i = 0; i < knownPlayers.size(); i++) { @@ -118,21 +145,7 @@ public void addClickableItemStack(String name, Material material, int amount, in } itemStack.setItemMeta(itemMeta); - inventory.setItem(slotWhereToPutTheItem, itemStack); - } - - /** - * Adds contents to the inventory using an array of ItemStacks. - * If the array is larger than the inventory size, an exception is thrown. - * - * @param itemStackList An array of ItemStacks to be added to the inventory. - * @throws IllegalArgumentException if the itemS tackList size exceeds the inventory size. - */ - public void addClickableContentsViaItemStackList(ItemStack[] itemStackList) { - if(itemStackList.length > inventory.getSize()) { - throw new IllegalArgumentException("The StackList is bigger then the size of the inventory!"); - } - inventory.setContents(itemStackList); + this.inventory.setItem(slotWhereToPutTheItem, itemStack); } /** diff --git a/src/main/java/de/j/deathMinigames/settings/MainMenu.java b/src/main/java/de/j/deathMinigames/settings/MainMenu.java index 74bf6e73..da9ecff7 100755 --- a/src/main/java/de/j/deathMinigames/settings/MainMenu.java +++ b/src/main/java/de/j/deathMinigames/settings/MainMenu.java @@ -27,13 +27,13 @@ public enum InventoryMenus { PARKOUR_LENGTH, COST_TO_LOWER_THE_DIFFICULTY, TIME_TO_DECIDE_WHEN_RESPAWNING, - SET_HOST, - SET_SERVER_NAME } public enum AnvilUIs { SET_SERVER_NAME, SET_HOST_NAME, + TEAM_RENAME, + SET_CLAIMING_RADIUS, DEFAULT // usage when the input slot item should have no name } @@ -85,6 +85,10 @@ public synchronized static AnvilUI getSetServerName() { return setServerName; } + public static AnvilUI getSetClaimingRadius() { + return setClaimingRadius; + } + private static final GUI introduction = new GUI("Introduction", true, false); private static final GUI difficulty = new GUI("Difficulty", true, true); private static final GUI usesPlugin = new GUI("UsesPlugin", true, false); @@ -96,6 +100,7 @@ public synchronized static AnvilUI getSetServerName() { private static final GUI timeToDecideWhenRespawning = new GUI("TimeToDecideWhenRespawning", false, false); private static final AnvilUI setHost = new AnvilUI(AnvilUIs.SET_HOST_NAME); private static final AnvilUI setServerName = new AnvilUI(AnvilUIs.SET_SERVER_NAME); + private static final AnvilUI setClaimingRadius = new AnvilUI(AnvilUIs.SET_CLAIMING_RADIUS); /** * Opens the main menu for the given player, where the player can @@ -129,6 +134,7 @@ private void addSubmenus() { addClickableItemStack("Difficulty", Material.RED_CONCRETE, 1, 3); addClickableItemStack("SetHost", Material.BOOK, 1, 4); addClickableItemStack("SetServerName", Material.BOOK, 1, 5); + addClickableItemStack("SetClaimingRadius", Material.MAP, 1, 6); } /** diff --git a/src/main/java/de/j/stationofdoom/main/Main.java b/src/main/java/de/j/stationofdoom/main/Main.java index 29cc38c1..20f84d11 100755 --- a/src/main/java/de/j/stationofdoom/main/Main.java +++ b/src/main/java/de/j/stationofdoom/main/Main.java @@ -2,6 +2,11 @@ import de.j.deathMinigames.commands.GameCMD; import de.j.deathMinigames.commands.LeaderboardCMD; +import de.j.stationofdoom.teams.TeamCMD; +import de.j.stationofdoom.teams.chunkClaimSystem.BlockBreakAndUseCancelListener; +import de.j.stationofdoom.teams.enderchest.TeamEnderchestPreventEnchantedItemsInputListener; +import de.j.deathMinigames.database.TeamEnderchestsDatabase; +import de.j.deathMinigames.database.TeamsDatabase; import de.j.deathMinigames.listeners.*; import de.j.deathMinigames.main.Config; import de.j.deathMinigames.database.Database; @@ -12,6 +17,9 @@ import de.j.stationofdoom.enchants.FurnaceEvents; import de.j.stationofdoom.enchants.TelepathyEvents; import de.j.stationofdoom.listener.*; +import de.j.stationofdoom.teams.TeamInventoryReload; +import de.j.stationofdoom.teams.TeamsCMD; +import de.j.stationofdoom.teams.TeamSettingsInventoryListener; import de.j.stationofdoom.util.EntityManager; import de.j.stationofdoom.util.translations.ChangeLanguageGUI; import de.j.stationofdoom.util.translations.LanguageChanger; @@ -87,6 +95,8 @@ public void onEnable() { COMMANDS.register("sit", new PlayerSitListener()); COMMANDS.register("game", "game related commands", new GameCMD()); COMMANDS.register("leaderboard", "showing the leaderboard of the minigame", new LeaderboardCMD()); + COMMANDS.register("teams", "showing the Main teams menu settings", new TeamsCMD()); + COMMANDS.register("team", "showing your team's settings", new TeamCMD()); }); PluginManager pluginManager = Bukkit.getPluginManager(); @@ -112,6 +122,10 @@ public void onEnable() { pluginManager.registerEvents(new InitWaitingListLocationOnJoin(), this); pluginManager.registerEvents(new LeaveListener(), this); pluginManager.registerEvents(new AnvilListener(), this); + pluginManager.registerEvents(new TeamSettingsInventoryListener(), this); + pluginManager.registerEvents(new TeamInventoryReload(), this); + pluginManager.registerEvents(new TeamEnderchestPreventEnchantedItemsInputListener(), this); + pluginManager.registerEvents(new BlockBreakAndUseCancelListener(), this); //CustomEnchants.register(); -> see custom enchants class for more info @@ -126,6 +140,8 @@ public void onDisable() { EntityManager.removeOldEntities(); WhoIsOnline.shutdown(); HandlePlayers.copyAllPlayerDataIntoDatabase(); + TeamsDatabase.getInstance().updateTeamsDatabase(); + TeamEnderchestsDatabase.getInstance().updateTeamEnderchestsOfAllTeams(); } public static Main getPlugin(){ diff --git a/src/main/java/de/j/stationofdoom/teams/HandleTeams.java b/src/main/java/de/j/stationofdoom/teams/HandleTeams.java new file mode 100644 index 00000000..c0c92a99 --- /dev/null +++ b/src/main/java/de/j/stationofdoom/teams/HandleTeams.java @@ -0,0 +1,90 @@ +package de.j.stationofdoom.teams; + +import de.j.deathMinigames.database.TeamsDatabase; +import de.j.deathMinigames.main.PlayerData; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CopyOnWriteArrayList; + +public class HandleTeams { + private static volatile HandleTeams instance; + + private static List teams = new CopyOnWriteArrayList<>(); + + private HandleTeams() { + teams = TeamsDatabase.getInstance().getTeams(); + } + + public static HandleTeams getInstance() { + if (instance == null) { + synchronized (HandleTeams.class) { + if (instance == null) { + instance = new HandleTeams(); + } + } + } + return instance; + } + + /** returns null when no them is found */ + @Nullable + public static Team getTeam(PlayerData playerData) { + for(Team team : teams) { + if(team.isDeleted()) continue; + if(team.isMember(playerData.getUniqueId())) { + return team; + } + } + return null; + } + + public static Team getTeamFromPlayerUUID(UUID uuid) { + for(Team team : teams) { + if(team.isDeleted()) continue; + if(team.isMember(uuid)) { + return team; + } + } + return new Team(); + } + + public static Team getTeam(UUID uuidOfTeam) { + for(Team team : teams) { + if(team.getUuid().equals(uuidOfTeam)) return team; + } + return null; + } + + public static boolean teamExists(UUID uuidOfTeam) { + for(Team team : teams) { + if(team.getUuid().equals(uuidOfTeam)) return true; + } + return false; + } + + public static void removePlayerFromEveryTeam(PlayerData playerData) { + List teamToRemoveOrAddPlayer = new ArrayList<>(); + for(Team team : teams) { + if(team == null) continue; + if(team.isMember(playerData.getUniqueId())) { + teamToRemoveOrAddPlayer.add(team); + } + } + for(Team team : teamToRemoveOrAddPlayer) { + team.removeMember(playerData); + } + } + + public static void addTeam(Team team) { + if(!teams.contains(team) && team.getName() != null && team.getUuid() != null && !team.getAllPlayers().isEmpty()) { + teams.add(team); + } + } + + public List getAllTeams() { + return teams; + } +} diff --git a/src/main/java/de/j/stationofdoom/teams/Team.java b/src/main/java/de/j/stationofdoom/teams/Team.java new file mode 100644 index 00000000..92e3b882 --- /dev/null +++ b/src/main/java/de/j/stationofdoom/teams/Team.java @@ -0,0 +1,307 @@ +package de.j.stationofdoom.teams; + +import de.j.deathMinigames.database.DBTeamMember; +import de.j.deathMinigames.database.TeamEnderchestsDatabase; +import de.j.deathMinigames.database.TeamsDatabase; +import de.j.deathMinigames.main.HandlePlayers; +import de.j.deathMinigames.main.PlayerData; +import de.j.stationofdoom.main.Main; +import de.j.stationofdoom.teams.enderchest.EnderchestInvHolder; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; + + +public class Team { + private String name; + private Material colorAsMaterial; + private String colorAsString; + private boolean locked; + public volatile Inventory inventory; + private final EnderchestInvHolder enderchestInvHolder = new EnderchestInvHolder(); + private final HashMap members = new HashMap<>(); + private UUID uuid; + private Location protectedLocation; + + public void addToMembers(UUID uuid, boolean isOperator) { + Main.getMainLogger().info("Adding member: " + uuid + " " + isOperator); + this.members.put(uuid, isOperator); + } + + public void removeFromMembers(UUID uuid) { + Main.getMainLogger().info("Removing member: " + uuid); + this.members.remove(uuid); + } + + public boolean isDeleted() { + return deleted; + } + + private volatile boolean deleted = false; + + public Team(String name, String colorAsString, boolean locked, String uuid, Location protectedLocation) { + init(name, UUID.fromString(uuid), Material.valueOf(colorAsString)); + convertMaterialToString(this.colorAsMaterial); + this.locked = locked; + this.inventory.setContents(TeamEnderchestsDatabase.getInstance().getTeamEnderchest(this.getUuid()).getContents()); + if (protectedLocation != null && protectedLocation.getWorld() != null) { + this.protectedLocation = protectedLocation; + } + } + + public Team(String name, String colorAsString, boolean locked, String uuid, String world, int x, int y, int z) { + init(name, UUID.fromString(uuid), Material.valueOf(colorAsString)); + convertMaterialToString(this.colorAsMaterial); + this.locked = locked; + this.inventory.setContents(TeamEnderchestsDatabase.getInstance().getTeamEnderchest(this.getUuid()).getContents()); + if(world != null) { + this.protectedLocation = new Location(Bukkit.getWorld(world), x, y, z); + } + } + + public Team(String name, String colorAsString, boolean locked, String uuid) { + init(name, UUID.fromString(uuid), Material.valueOf(colorAsString)); + convertMaterialToString(this.colorAsMaterial); + this.locked = locked; + this.inventory.setContents(TeamEnderchestsDatabase.getInstance().getTeamEnderchest(this.getUuid()).getContents()); + } + + // used to create a new team without any operators + public Team() { + uuid = UUID.randomUUID(); + addToList(); + } + + public Team(PlayerData playerData) { + init(playerData.getName() + "'s Team", UUID.randomUUID(), getRandomConcreteMaterial()); + this.inventory.setContents(TeamEnderchestsDatabase.getInstance().getTeamEnderchest(this.getUuid()).getContents()); + handlePlayerLeaveOrJoin(playerData); + setTeamOperator(HandlePlayers.getInstance().getPlayerData(playerData.getUniqueId()), true); + } + + public Team(Player player) { + init(player.getName() + "'s Team", UUID.randomUUID(), getRandomConcreteMaterial()); + this.inventory.setContents(TeamEnderchestsDatabase.getInstance().getTeamEnderchest(this.getUuid()).getContents()); + handlePlayerLeaveOrJoin(HandlePlayers.getInstance().getPlayerData(player.getUniqueId())); + setTeamOperator(HandlePlayers.getInstance().getPlayerData(player.getUniqueId()), true); + } + + private void init(String name, UUID uuid, Material colorAsMaterial) { + this.name = name; + this.uuid = uuid; + this.colorAsMaterial = colorAsMaterial; + this.inventory = Bukkit.createInventory(this.enderchestInvHolder, 27, name); + addToList(); + } + + public List getMembers() { + List members = new ArrayList<>(); + for (UUID uuid : this.members.keySet()) { + PlayerData playerData = HandlePlayers.getInstance().getPlayerData(uuid); + if(isTeamOperator(playerData)) continue; + members.add(playerData); + } + return members; + } + + public void addMember(DBTeamMember member) { + if(member.isInTeam) this.members.put(member.uuid, member.isTeamOperator); + } + + public List getTeamOperators() { + List teamOperators = new ArrayList<>(); + for (UUID uuid : this.members.keySet()) { + PlayerData playerData = HandlePlayers.getInstance().getPlayerData(uuid); + if(this.members.get(uuid)) teamOperators.add(playerData); + } + return teamOperators; + } + + public List getAllPlayers() { + return members.keySet().stream().toList(); + } + + public boolean getLocked() { + return locked; + } + + public void setLocked(boolean locked) { + if(getTeamOperators().isEmpty()) { + Main.getMainLogger().info("Team is not locked because there are no operators"); + return; + } + this.locked = locked; + } + + public Material getColorAsMaterial() { + return colorAsMaterial; + } + + public void setColorAsMaterial(Material colorAsMaterial) { + this.colorAsMaterial = colorAsMaterial; + convertMaterialToString(colorAsMaterial); + } + + private void convertMaterialToString(Material material) { + String color = material.toString(); + color = color.replace("_CONCRETE", ""); + this.colorAsString = color; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + private Material getRandomConcreteMaterial() { + List materials = new ArrayList<>(); + for (Material material : Material.values()) { + if (material.name().contains("CONCRETE") && !material.name().contains("POWDER")) { + materials.add(material); + } + } + return materials.get(ThreadLocalRandom.current().nextInt(0, materials.size())); + } + + public UUID getUuid() { + return uuid; + } + + public void handlePlayerLeaveOrJoin(PlayerData playerData) { + if(this.members.containsKey(playerData.getUniqueId())) { + if(getAllPlayers().size() <= 1) { + this.remove(); + } + else { + removeMember(playerData); + } + } + else { + HandleTeams.removePlayerFromEveryTeam(playerData); + this.members.put(playerData.getUniqueId(), false); + playerData.setUuidOfTeam(this.getUuid()); + playerData.setInTeam(true); + } + } + + public void removeMember(PlayerData playerData) { + if(this.members.containsKey(playerData.getUniqueId())) { + if(getTeamOperators().contains(playerData) && getTeamOperators().size() == 1) { + setLocked(false); + } + this.members.remove(playerData.getUniqueId()); + playerData.setUuidOfTeam(null); + playerData.setInTeam(false); + Main.getMainLogger().warning("Removed player " + playerData.getName()); + if(this.members.isEmpty()) { + TeamsMainMenuGUI.teams.remove(this); + } + } + } + + public void remove() { + Main.getMainLogger().info("Removing team " + this.name); + TeamsDatabase.getInstance().removeTeam(this); + this.deleted = true; + if (this.inventory != null && !this.inventory.isEmpty()) { + Location loc; + Main.getMainLogger().warning("Team " + this.name + " is being removed but has items in its ender chest, dropping items to first operator"); + if (!getTeamOperators().isEmpty()) { + loc = getTeamOperators().getFirst().getLocation(); + try { + for (ItemStack itemStack : this.inventory.getContents()) { + if (itemStack == null) continue; + loc.getWorld().dropItem(loc, itemStack); + } + } + catch (Exception e) { + Main.getMainLogger().severe("Could not drop enderchest items for team " + this.name); + e.printStackTrace(); + } + } else { + Main.getMainLogger().warning("Team has no operators, dropping items to first member"); + if (!getAllPlayers().isEmpty()) { + loc = HandlePlayers.getInstance().getPlayerData(getAllPlayers().getFirst()).getLocation(); + try { + for (ItemStack itemStack : this.inventory.getContents()) { + if (itemStack == null) continue; + loc.getWorld().dropItem(loc, itemStack); + } + } + catch (Exception e) { + Main.getMainLogger().severe("Could not drop enderchest items for team " + this.name); + e.printStackTrace(); + } + } + else Main.getMainLogger().warning("Team has no members, can not drop items"); + } + } + this.members.clear(); + TeamsMainMenuGUI.teams.remove(this); + if(this.inventory != null && !this.inventory.isEmpty()) { + this.inventory.clear(); + } + + Main.getMainLogger().info("Removed team " + this.name); + } + + public void setTeamOperator(PlayerData playerData, boolean value) { + if(this.members.containsKey(playerData.getUniqueId())) { + this.members.put(playerData.getUniqueId(), value); + } + if(getTeamOperators().isEmpty()) this.locked = false; + } + + public boolean isTeamOperator(PlayerData playerData) { + if(!this.members.containsKey(playerData.getUniqueId())) return false; + return this.members.containsKey(playerData.getUniqueId()) && this.members.get(playerData.getUniqueId()); + } + + public void accessEnderChest(Player player) { + if(!this.members.containsKey(player.getUniqueId())) return; + player.openInventory(this.inventory); + } + + public boolean isMember(UUID uuidOfPlayerToCheck) { + if (uuidOfPlayerToCheck == null) { + return false; + } + for (UUID uuid : this.members.keySet()) { + if(uuid.equals(uuidOfPlayerToCheck)) { + return true; + } + } + return false; + } + + public void setProtectedLocation(Location location) { + this.protectedLocation = location; + } + + public Location getProtectedLocation() { + return this.protectedLocation; + } + + private void addToList() { + HandleTeams.addTeam(this); + } + + public String getColorAsString() { + if(colorAsString == null) { + convertMaterialToString(this.colorAsMaterial); + } + return colorAsString; + } +} diff --git a/src/main/java/de/j/stationofdoom/teams/TeamCMD.java b/src/main/java/de/j/stationofdoom/teams/TeamCMD.java new file mode 100644 index 00000000..30dd668d --- /dev/null +++ b/src/main/java/de/j/stationofdoom/teams/TeamCMD.java @@ -0,0 +1,25 @@ +package de.j.stationofdoom.teams; + +import de.j.stationofdoom.util.translations.TranslationFactory; +import io.papermc.paper.command.brigadier.BasicCommand; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; + + +public class TeamCMD implements BasicCommand { + @Override + public void execute(CommandSourceStack stack, String[] args) { + if (!(stack.getSender() instanceof Player player)) { + return; + } + Team team = HandleTeams.getTeamFromPlayerUUID(player.getUniqueId()); + if (!team.isMember(player.getUniqueId())) { + player.sendMessage(Component.text(new TranslationFactory().getTranslation(player, "TeamCMDNoTeam")) + .color(NamedTextColor.RED)); + return; + } + new TeamSettingsGUI(team).showPage(1, player); + } +} diff --git a/src/main/java/de/j/stationofdoom/teams/TeamInventoryReload.java b/src/main/java/de/j/stationofdoom/teams/TeamInventoryReload.java new file mode 100644 index 00000000..37c2349b --- /dev/null +++ b/src/main/java/de/j/stationofdoom/teams/TeamInventoryReload.java @@ -0,0 +1,45 @@ +package de.j.stationofdoom.teams; + +import de.j.deathMinigames.settings.GUI; +import de.j.stationofdoom.main.Main; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryOpenEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.scheduler.BukkitRunnable; + +public class TeamInventoryReload implements Listener { + private static final int secondsBetweenReloads = 3; + + @EventHandler + public void onInventoryOpen(InventoryOpenEvent event) { + if(event.getInventory().getHolder() instanceof TeamsMainMenuGUI || event.getInventory().getHolder() instanceof TeamSettingsGUI) { + GUI gui = (GUI) event.getInventory().getHolder(); + Player viewer = (Player) event.getPlayer(); + Inventory inv = event.getInventory(); + startTimer(inv, gui, viewer); + } + } + + private void startTimer(Inventory inv, GUI gui, Player viewer) { + new BukkitRunnable() { + @Override + public void run() { + if(!inv.getViewers().contains(viewer)) { + cancel(); + } + else { + int currentPage = inv.getItem(53).getAmount() - 1; + if(gui instanceof TeamsMainMenuGUI teamsMainMenuGUI) { + teamsMainMenuGUI.showPage(currentPage, viewer); + } + else if(gui instanceof TeamSettingsGUI teamSettingsGUI) { + teamSettingsGUI.showPage(currentPage, viewer); + } + cancel(); + } + } + }.runTaskTimer(Main.getPlugin(), 10, secondsBetweenReloads * 20); + } +} \ No newline at end of file diff --git a/src/main/java/de/j/stationofdoom/teams/TeamPlayerSettingsGUI.java b/src/main/java/de/j/stationofdoom/teams/TeamPlayerSettingsGUI.java new file mode 100644 index 00000000..bc57e568 --- /dev/null +++ b/src/main/java/de/j/stationofdoom/teams/TeamPlayerSettingsGUI.java @@ -0,0 +1,65 @@ +package de.j.stationofdoom.teams; + +import de.j.deathMinigames.main.PlayerData; +import de.j.deathMinigames.settings.GUI; +import de.j.stationofdoom.main.Main; +import de.j.stationofdoom.util.translations.TranslationFactory; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryHolder; + +import java.util.ArrayList; + +public class TeamPlayerSettingsGUI extends GUI { + private TranslationFactory tf = new TranslationFactory(); + private volatile PlayerData playerData; + private volatile Team team; + + public TeamPlayerSettingsGUI() { + + } + + public void showInventory(Player playerToShowTheInvTo, PlayerData playerDataBasedOnSlot) { + this.playerData = playerDataBasedOnSlot; + fillInv(playerToShowTheInvTo, playerDataBasedOnSlot); + playerToShowTheInvTo.openInventory(inventory); + } + + private void fillInv(Player playerToShowTheInvTo,PlayerData playerDataBasedOnSlot) { + this.inventory = Bukkit.createInventory(this, 18, playerDataBasedOnSlot.getName()); + Team team = HandleTeams.getTeam(playerDataBasedOnSlot); + if(team == null) { + Main.getMainLogger().warning("Team is null in fillInv"); + return; + } + this.team = team; + boolean isOperator = team.isTeamOperator(playerDataBasedOnSlot); + this.inventory.clear(); + for (int i = 0; i < 9; i++) { + if (i == 4) continue; + if (isOperator) { + addClickableItemStack("", Material.GREEN_STAINED_GLASS_PANE, 1, i); + } else { + addClickableItemStack("", Material.WHITE_STAINED_GLASS_PANE, 1, i); + } + } + addPlayerHead(playerDataBasedOnSlot, 4, new ArrayList<>()); + if(isOperator) { + addClickableItemStack(tf.getTranslation(playerToShowTheInvTo, "teamPlayerSettingsDemoteToMember"), Material.ENDER_EYE, 1, 9); + } + else { + addClickableItemStack(tf.getTranslation(playerToShowTheInvTo, "teamPlayerSettingsPromoteToOperator"), Material.ENDER_PEARL, 1, 9); + } + addClickableItemStack(tf.getTranslation(playerToShowTheInvTo, "teamPlayerSettingsKickPlayer"), Material.BARRIER, 1, 10); + addClickableItemStack(tf.getTranslation(playerToShowTheInvTo, "backButton"), Material.RED_CONCRETE, 1, 17); + } + + public PlayerData getPlayerData() { + return playerData; + } + + public Team getTeam() { + return team; + } +} diff --git a/src/main/java/de/j/stationofdoom/teams/TeamSettingsGUI.java b/src/main/java/de/j/stationofdoom/teams/TeamSettingsGUI.java new file mode 100644 index 00000000..44ba603d --- /dev/null +++ b/src/main/java/de/j/stationofdoom/teams/TeamSettingsGUI.java @@ -0,0 +1,141 @@ +package de.j.stationofdoom.teams; + +import de.j.deathMinigames.main.HandlePlayers; +import de.j.deathMinigames.main.PlayerData; +import de.j.deathMinigames.settings.AnvilUI; +import de.j.deathMinigames.settings.GUI; +import de.j.deathMinigames.settings.MainMenu; +import de.j.stationofdoom.util.translations.TranslationFactory; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +public class TeamSettingsGUI extends GUI { + private final TranslationFactory tf = new TranslationFactory(); + private final Team team; + private final int inventorySize = 54; + private final int maxSlotsPerPage = 27; + private volatile ConcurrentHashMap invSlots = new ConcurrentHashMap<>(); + private int pagesBasedOnMemberQuantity; + private volatile List members; + private volatile float memberQuantity; + private final int startSlotToFill = 18; + public static AnvilUI renameTeam = new AnvilUI(MainMenu.AnvilUIs.TEAM_RENAME); + public static GUI colorChanger = new GUI("Color changer", false, false, 2 * 9); + + public TeamSettingsGUI(Team team) { + this.team = team; + } + + public void showPage(int page, Player playerToShowTheInvTo) { + this.inventory = null; + this.inventory = Bukkit.createInventory(this, inventorySize, team.getName() +" - " + tf.getTranslation(playerToShowTheInvTo, "page") + " " + page ); + if(this.team.isDeleted()) { + playerToShowTheInvTo.sendMessage(Component.text(tf.getTranslation(playerToShowTheInvTo, "teamDeleted", team.getName())).color(NamedTextColor.RED)); + new TeamsMainMenuGUI().showPage(1, playerToShowTheInvTo); + return; + } + members = team.getAllPlayers(); + if(!members.isEmpty()) { + memberQuantity = team.getAllPlayers().size(); + pagesBasedOnMemberQuantity = (int) Math.ceil(memberQuantity / maxSlotsPerPage); + fillPage(page); + } + if(members.contains(playerToShowTheInvTo.getUniqueId())) { + addClickableItemStack(tf.getTranslation(playerToShowTheInvTo, "leaveTeam"), Material.BARRIER, 1, 45); + } + else { + addClickableItemStack(tf.getTranslation(playerToShowTheInvTo, "joinTeam"), Material.END_CRYSTAL, 1, 45); + } + if(page == 1) { + addClickableItemStack(tf.getTranslation(playerToShowTheInvTo, "alreadyFirstPage"), Material.BARRIER, 1, 52); + } + else { + addClickableItemStack(tf.getTranslation(playerToShowTheInvTo, "lastPage"), Material.COPPER_BULB, page - 1, 52); + } + addClickableItemStack(tf.getTranslation(playerToShowTheInvTo, "nextPage"), Material.OXIDIZED_COPPER_BULB, page + 1, 53); + addTopBarToInventory(); + addFunctionsToInventory(playerToShowTheInvTo); + playerToShowTheInvTo.openInventory(this.inventory); + } + + private void fillPage(int page) { + float intToStartFrom = (page * maxSlotsPerPage) - maxSlotsPerPage; + addPlayersToInventory((int) intToStartFrom); + } + + private void addPlayersToInventory(int intToStartFrom) { + invSlots.clear(); + for(int playersAdded = 0; playersAdded < maxSlotsPerPage; playersAdded++) { + if(playersAdded >= memberQuantity || playersAdded >= maxSlotsPerPage || intToStartFrom + playersAdded >= memberQuantity) return; + PlayerData currentPlayerData = HandlePlayers.getInstance().getPlayerData(members.get(intToStartFrom + playersAdded)); + ArrayList lore = new ArrayList<>(); + lore.add("Operator: " + team.isTeamOperator(currentPlayerData)); + if(!currentPlayerData.isOnline()) { + lore.add("Offline"); + } + else { + lore.add("Online"); + } + addPlayerHead(currentPlayerData, playersAdded + startSlotToFill, lore); + invSlots.put(playersAdded + startSlotToFill, currentPlayerData); + } + } + + public int getPagesQuantity() { + return pagesBasedOnMemberQuantity; + } + + public Team getTeam() { + return team; + } + + public PlayerData getMemberBasedOnSlot(int slot) { + PlayerData playerBasedOnSlot = invSlots.get(slot); + if(playerBasedOnSlot == null) { + return null; + } + return playerBasedOnSlot; + } + + private void addTopBarToInventory() { + String colorAsGlassPane = team.getColorAsMaterial().toString().replace("_CONCRETE", "_STAINED_GLASS_PANE"); + Material material = Material.getMaterial(colorAsGlassPane); + if(material == null) material = Material.WHITE_STAINED_GLASS_PANE; + for (int i = 0; i < 9; i++) { + addClickableItemStack(team.getName(), material, 1, i); + } + addClickableItemStack(team.getName(), team.getColorAsMaterial(), 1, 4); + } + + private void addFunctionsToInventory(Player player) { + addClickableItemStack(tf.getTranslation(player, "renameTeam"), Material.NAME_TAG, 1, 9); + addClickableItemStack(tf.getTranslation(player, "changeColor"), Material.ORANGE_GLAZED_TERRACOTTA, 1, 10); + ArrayList lockedTeamSettingsLore = new ArrayList<>(); + lockedTeamSettingsLore.add(tf.getTranslation(player, "lockedTeamSettingsLore")); + if(team.getLocked()) { + addClickableItemStack(tf.getTranslation(player, "lockTeamSettings"), Material.OMINOUS_TRIAL_KEY, 1, 11, lockedTeamSettingsLore); + } + else { + addClickableItemStack(tf.getTranslation(player, "lockTeamSettings"), Material.TRIAL_KEY, 1, 11, lockedTeamSettingsLore); + } + ArrayList teamEnderChestLore = new ArrayList<>(); + teamEnderChestLore.add(tf.getTranslation(player, "teamEnderChestLore")); + addClickableItemStack(tf.getTranslation(player, "teamEnderChest"), Material.ENDER_CHEST, 1, 12, teamEnderChestLore); + ArrayList teamClaimChunksLore = new ArrayList<>(); + teamClaimChunksLore.add(tf.getTranslation(player, "teamClaimChunksLore")); + if(team.getProtectedLocation() != null) { + addClickableItemStack(tf.getTranslation(player, "teamClaimChunksProtectedLocation", team.getProtectedLocation().getBlockX(), team.getProtectedLocation().getBlockY(), team.getProtectedLocation().getBlockZ()), Material.FILLED_MAP, 1, 13, teamClaimChunksLore); + } + else { + addClickableItemStack(tf.getTranslation(player, "teamClaimChunks"), Material.MAP, 1, 13, teamClaimChunksLore); + } + addClickableItemStack(tf.getTranslation(player, "deleteTeam"), Material.COMPOSTER, 1, 17); + } +} diff --git a/src/main/java/de/j/stationofdoom/teams/TeamSettingsInventoryListener.java b/src/main/java/de/j/stationofdoom/teams/TeamSettingsInventoryListener.java new file mode 100644 index 00000000..c3245e25 --- /dev/null +++ b/src/main/java/de/j/stationofdoom/teams/TeamSettingsInventoryListener.java @@ -0,0 +1,308 @@ +package de.j.stationofdoom.teams; + +import de.j.deathMinigames.main.HandlePlayers; +import de.j.deathMinigames.main.PlayerData; +import de.j.deathMinigames.settings.GUI; +import de.j.stationofdoom.main.Main; +import de.j.stationofdoom.teams.chunkClaimSystem.ChunkClaimSystem; +import de.j.stationofdoom.util.translations.TranslationFactory; +import net.kyori.adventure.sound.Sound; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; +import org.bukkit.Effect; +import org.bukkit.EntityEffect; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; + +import static io.papermc.paper.registry.keys.SoundEventKeys.*; + +public class TeamSettingsInventoryListener implements Listener { + TranslationFactory tf = new TranslationFactory(); + + @EventHandler + public void onInventoryClick(InventoryClickEvent event) { + if (event.getClickedInventory() == null) return; + InventoryHolder invHolder = event.getClickedInventory().getHolder(); + if (invHolder instanceof TeamSettingsGUI || invHolder instanceof TeamsMainMenuGUI) { + event.setCancelled(true); + int slot = event.getSlot(); + Inventory inv = event.getClickedInventory(); + Player player = (Player) event.getWhoClicked(); + if (player == null) return; + PlayerData playerData = HandlePlayers.getInstance().getPlayerData(player.getUniqueId()); + if (event.getClickedInventory().getItem(53) == null) return; + int currentPage = event.getClickedInventory().getItem(53).getAmount() - 1; + int lastPage = currentPage - 1; + int nextPage = currentPage + 1; + if (invHolder instanceof TeamsMainMenuGUI) { + handleTeamsMainMenuGUI(slot, inv, invHolder, player, currentPage, lastPage, nextPage); + } + else { + handleTeamSettingsGUI(slot, inv, invHolder, player, playerData, currentPage, lastPage, nextPage); + } + } + else if (invHolder instanceof GUI) { + GUI colorChanger = (GUI) invHolder; + event.setCancelled(true); + int slot = event.getSlot(); + Inventory inv = event.getClickedInventory(); + Player player = (Player) event.getWhoClicked(); + if (player == null) return; + if(colorChanger.getUUID() == TeamSettingsGUI.colorChanger.getUUID()) { + if(slot < 0 || slot > 15) return; + handleColorChanger(slot, inv, player); + } + if(invHolder instanceof TeamPlayerSettingsGUI) { + handleTeamPlayerSettingsGUI(slot, invHolder, player); + } + } + } + + private void handleTeamsMainMenuGUI(int slot, Inventory inv, InventoryHolder invHolder, Player player, int currentPage, int lastPage, int nextPage) { + TeamsMainMenuGUI teamsMainMenuGUI = (TeamsMainMenuGUI) invHolder; + switch (slot) { + case -999: + return; + case 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44: + if (inv.getItem(slot) == null) { + player.playSound(Sound.sound(BLOCK_COPPER_BULB_PLACE, Sound.Source.PLAYER, 0.5F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + return; + } + Team currentTeam = teamsMainMenuGUI.getTeamBasedOnSlot(slot); + if (currentTeam == null) return; + TeamSettingsGUI teamSettingsGUI = new TeamSettingsGUI(currentTeam); + teamSettingsGUI.showPage(1, player); + player.playSound(Sound.sound(BLOCK_COPPER_BULB_PLACE, Sound.Source.PLAYER, 0.5F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + break; + case 45: + teamsMainMenuGUI.addTeam(player); + teamsMainMenuGUI.showPage(teamsMainMenuGUI.getPagesQuantity(), player); + player.playSound(Sound.sound(BLOCK_AMETHYST_BLOCK_PLACE, Sound.Source.PLAYER, 1F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + break; + case 52: + if (currentPage == 1) { + return; + } else { + teamsMainMenuGUI.showPage(lastPage, player); + player.playSound(Sound.sound(BLOCK_COPPER_BULB_TURN_ON, Sound.Source.PLAYER, 2F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); } + break; + case 53: + if (currentPage == teamsMainMenuGUI.getPagesQuantity() || teamsMainMenuGUI.getPagesQuantity() == 1 || teamsMainMenuGUI.getPagesQuantity() == 0) { + return; + } + else { + teamsMainMenuGUI.showPage(nextPage, player); + player.playSound(Sound.sound(BLOCK_COPPER_BULB_TURN_ON, Sound.Source.PLAYER, 2F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); } + break; + default: + if (inv.getItem(slot) == null) player.playSound(Sound.sound(BLOCK_COPPER_BULB_PLACE, Sound.Source.PLAYER, 0.5F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + } + } + + private void handleTeamSettingsGUI(int slot, Inventory inv, InventoryHolder invHolder, Player player, PlayerData playerData, int currentPage, int lastPage, int nextPage) { + TeamSettingsGUI teamSettingsGUI = (TeamSettingsGUI) invHolder; + Team team = teamSettingsGUI.getTeam(); + handleTeamSettingsGUIChecking(slot, player, team, teamSettingsGUI, currentPage, inv); + switch (slot) { + case -999: + return; + case 0, 1, 2, 3, 4, 5, 6, 7, 8, 14, 15, 16, 46, 47, 48, 49, 50, 51: + player.playSound(Sound.sound(BLOCK_COPPER_BULB_PLACE, Sound.Source.PLAYER, 0.5F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + break; + case 9: + TeamSettingsGUI.renameTeam.showInventory(player); + player.playSound(Sound.sound(BLOCK_COPPER_BULB_TURN_ON, Sound.Source.PLAYER, 2F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + break; + case 10: + addColorsToColorChanger(TeamSettingsGUI.colorChanger.getInventory()); + TeamSettingsGUI.colorChanger.showInventory(player); + player.playSound(Sound.sound(BLOCK_COPPER_BULB_TURN_ON, Sound.Source.PLAYER, 2F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + break; + case 11: + handleTeamSettingsGUICase11(team, player, teamSettingsGUI, currentPage); + break; + case 12: + team.accessEnderChest(player); + player.playSound(Sound.sound(BLOCK_CHEST_OPEN, Sound.Source.PLAYER, 0.5F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + break; + case 13: + ChunkClaimSystem.getInstance().playerClaim(player, team, player.getLocation()); + player.playSound(Sound.sound(BLOCK_AMETHYST_BLOCK_RESONATE, Sound.Source.PLAYER, 1F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + break; + case 17: + team.remove(); + new TeamsMainMenuGUI().showPage(1, player); + player.playSound(Sound.sound(BLOCK_AMETHYST_BLOCK_BREAK, Sound.Source.PLAYER, 1F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + break; + case 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44: + handleTeamSettingsGUICase18To44(inv, slot, player, teamSettingsGUI); + break; + case 45: + handleTeamSettingsGUICase45(team, player, teamSettingsGUI, currentPage, playerData); + break; + case 52: + handleTeamSettingsGUICase52(currentPage, player, teamSettingsGUI, lastPage); + break; + case 53: + if (currentPage == teamSettingsGUI.getPagesQuantity() || teamSettingsGUI.getPagesQuantity() == 1 || teamSettingsGUI.getPagesQuantity() == 0) { + return; + } else { + teamSettingsGUI.showPage(nextPage, player); + player.playSound(Sound.sound(BLOCK_COPPER_BULB_TURN_ON, Sound.Source.PLAYER, 2F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); } + break; + default: + } + } + + private void handleTeamSettingsGUIChecking(int slot, Player player, Team team, TeamSettingsGUI teamSettingsGUI, int currentPage, Inventory inv) { + if(slot != 45) { + if(player.getUniqueId() == null) { + Main.getMainLogger().info("Player is null in TeamSettingsInventoryListener"); + return; + } + if(!team.isMember(player.getUniqueId())) { + player.sendMessage(Component.text(tf.getTranslation(player, "teamNotAMember")).color(NamedTextColor.RED)); + player.playSound(Sound.sound(BLOCK_AMETHYST_CLUSTER_BREAK, Sound.Source.PLAYER, 0.5F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + return; + } + } + if(slot >= 9 && slot <=13 || slot == 17 || slot >= 18 && slot <= 44 && inv.getItem(slot) != null) { + if(team.getLocked() && !team.isTeamOperator(HandlePlayers.getInstance().getPlayerData(player.getUniqueId()))) { + player.sendMessage(Component.text(tf.getTranslation(player, "teamLockedAndNotOperator")).color(NamedTextColor.RED)); + player.playSound(Sound.sound(BLOCK_AMETHYST_CLUSTER_BREAK, Sound.Source.PLAYER, 0.5F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + teamSettingsGUI.showPage(currentPage, player); + } + } + } + + private void handleTeamSettingsGUICase11(Team team, Player player, TeamSettingsGUI teamSettingsGUI, int currentPage) { + team.setLocked(!team.getLocked()); + teamSettingsGUI.showPage(currentPage, player); + if(team.getLocked()) { + player.playSound(Sound.sound(BLOCK_IRON_DOOR_CLOSE, Sound.Source.PLAYER, 0.5F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + } + else { + player.playSound(Sound.sound(BLOCK_IRON_DOOR_OPEN, Sound.Source.PLAYER, 0.5F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + } + } + + private void handleTeamSettingsGUICase18To44(Inventory inv, int slot, Player player, TeamSettingsGUI teamSettingsGUI) { + if (inv.getItem(slot) == null) { + player.playSound(Sound.sound(BLOCK_COPPER_BULB_PLACE, Sound.Source.PLAYER, 0.5F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + return; + } + PlayerData playerBasedOnSlot = teamSettingsGUI.getMemberBasedOnSlot(slot); + if(playerBasedOnSlot == null) return; + new TeamPlayerSettingsGUI().showInventory(player, playerBasedOnSlot); + player.playSound(Sound.sound(BLOCK_ENDER_CHEST_OPEN, Sound.Source.PLAYER, 0.5F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + } + + private void handleTeamSettingsGUICase45(Team team, Player player, TeamSettingsGUI teamSettingsGUI, int currentPage, PlayerData playerData) { + if(team.getLocked() && !team.isMember(player.getUniqueId())) { + player.sendMessage(Component.text(tf.getTranslation(player, "teamLocked")).color(NamedTextColor.RED)); + return; + } + if(team.isMember(player.getUniqueId())) player.playSound(Sound.sound(BLOCK_AMETHYST_BLOCK_BREAK, Sound.Source.PLAYER, 1F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + else player.playSound(net.kyori.adventure.sound.Sound.sound(BLOCK_CHISELED_BOOKSHELF_INSERT_ENCHANTED, net.kyori.adventure.sound.Sound.Source.PLAYER, 3F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + team.handlePlayerLeaveOrJoin(playerData); + if(!team.getAllPlayers().isEmpty()) { + teamSettingsGUI.showPage(currentPage, player); + } + else { + new TeamsMainMenuGUI().showPage(1, player); + } + } + + private void handleTeamSettingsGUICase52(int currentPage, Player player, TeamSettingsGUI teamSettingsGUI, int lastPage) { + if (currentPage != 1) { + teamSettingsGUI.showPage(lastPage, player); + player.playSound(Sound.sound(BLOCK_COPPER_BULB_TURN_ON, Sound.Source.PLAYER, 2F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + } + } + + private void handleColorChanger(int slot, Inventory inv, Player player) { + Material clickedColor = inv.getItem(slot).getType(); + Team teamToChangeColor = HandleTeams.getTeam(HandlePlayers.getInstance().getPlayerData(player.getUniqueId())); + if(teamToChangeColor == null) return; + teamToChangeColor.setColorAsMaterial(clickedColor); + new TeamSettingsGUI(teamToChangeColor).showPage(1, player); + player.playSound(net.kyori.adventure.sound.Sound.sound(BLOCK_CHISELED_BOOKSHELF_INSERT_ENCHANTED, net.kyori.adventure.sound.Sound.Source.PLAYER, 3F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + player.playSound(Sound.sound(ITEM_BOOK_PAGE_TURN, Sound.Source.PLAYER, 1F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + } + + private void addColorsToColorChanger(Inventory colorChanger) { + int count = 0; + for (Material material : Material.values()) { + if (material.name().contains("CONCRETE") && !material.name().contains("POWDER")) { + ItemStack color = new ItemStack(material); + colorChanger.setItem(count, color); + count++; + } + } + } + + private void handleTeamPlayerSettingsGUI(int slot, InventoryHolder invHolder, Player player) { + if(slot != 9 && slot != 10 && slot != 17) { + player.playSound(Sound.sound(BLOCK_COPPER_BULB_PLACE, Sound.Source.PLAYER, 0.5F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + return; + } + TeamPlayerSettingsGUI teamPlayerSettingsGUI = (TeamPlayerSettingsGUI) invHolder; + Team team = teamPlayerSettingsGUI.getTeam(); + PlayerData playerData = HandlePlayers.getInstance().getPlayerData(player.getUniqueId()); + PlayerData clickedOnPlayerData = teamPlayerSettingsGUI.getPlayerData(); + if(team == null) return; + if(slot == 9 || slot == 10) { + if(!team.isTeamOperator(playerData) && team.getLocked()) { + player.sendMessage(Component.text(tf.getTranslation(player, "teamLockedAndNotOperator")).color(NamedTextColor.RED)); + return; + } + } + switch (slot) { + case 9: + handleTeamPlayerSettingsGUICase9(team, player, clickedOnPlayerData); + break; + case 10: + handleTeamPlayerSettingsGUICase10(team, player, clickedOnPlayerData); + break; + case 17: + handleTeamPlayerSettingsGUICase17(team, player); + return; + } + if(!team.getAllPlayers().isEmpty()) { + teamPlayerSettingsGUI.showInventory(player, clickedOnPlayerData); + } + } + + private void handleTeamPlayerSettingsGUICase9(Team team, Player player, PlayerData clickedOnPlayerData) { + player.playSound(Sound.sound(BLOCK_PISTON_CONTRACT, Sound.Source.PLAYER, 0.5F, 1), Sound.Emitter.self()); + team.setTeamOperator(clickedOnPlayerData, !team.isTeamOperator(clickedOnPlayerData)); + } + + private void handleTeamPlayerSettingsGUICase10(Team team, Player player, PlayerData clickedOnPlayerData) { + team.removeMember(clickedOnPlayerData); + if(clickedOnPlayerData.isOnline()) { + clickedOnPlayerData.getPlayer().sendMessage(Component.text(tf.getTranslation(clickedOnPlayerData.getPlayer(), "kickedFromTeam", player.getName())).color(NamedTextColor.RED)); + Bukkit.getPlayer(clickedOnPlayerData.getUniqueId()).playSound(Sound.sound(BLOCK_AMETHYST_BLOCK_RESONATE, Sound.Source.PLAYER, 1F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + } + player.playSound(Sound.sound(BLOCK_COPPER_BULB_TURN_ON, Sound.Source.PLAYER, 2F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + } + + private void handleTeamPlayerSettingsGUICase17(Team team, Player player) { + if(!team.getAllPlayers().isEmpty()) { + new TeamSettingsGUI(team).showPage(1, player); + } + else { + new TeamsMainMenuGUI().showPage(1, player); + } + player.playSound(Sound.sound(ITEM_BOOK_PAGE_TURN, Sound.Source.PLAYER, 1F, 1), net.kyori.adventure.sound.Sound.Emitter.self()); + } +} diff --git a/src/main/java/de/j/stationofdoom/teams/TeamsCMD.java b/src/main/java/de/j/stationofdoom/teams/TeamsCMD.java new file mode 100644 index 00000000..d12550f9 --- /dev/null +++ b/src/main/java/de/j/stationofdoom/teams/TeamsCMD.java @@ -0,0 +1,30 @@ +package de.j.stationofdoom.teams; + +import de.j.deathMinigames.main.HandlePlayers; +import io.papermc.paper.command.brigadier.BasicCommand; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class TeamsCMD implements BasicCommand { + public TeamsMainMenuGUI teamsMainMenuGUI = new TeamsMainMenuGUI(); + + @Override + public boolean canUse(@NotNull CommandSender sender) { + return sender instanceof Player; + } + + @Override + public void execute(CommandSourceStack stack, String[] args) { + Player player = (Player) stack.getSender(); + if(args.length == 0) { + teamsMainMenuGUI.showPage(1, player); + } + else if(args.length == 1 && (args[0].equalsIgnoreCase("e") || args[0].equalsIgnoreCase("enderchest"))) { + Team team = HandleTeams.getTeam(HandlePlayers.getInstance().getPlayerData(player.getUniqueId())); + if(team == null || !team.isMember(player.getUniqueId())) return; + team.accessEnderChest(player); + } + } +} diff --git a/src/main/java/de/j/stationofdoom/teams/TeamsMainMenuGUI.java b/src/main/java/de/j/stationofdoom/teams/TeamsMainMenuGUI.java new file mode 100644 index 00000000..3ef1068e --- /dev/null +++ b/src/main/java/de/j/stationofdoom/teams/TeamsMainMenuGUI.java @@ -0,0 +1,111 @@ +package de.j.stationofdoom.teams; + +import de.j.deathMinigames.database.Database; +import de.j.deathMinigames.main.PlayerData; +import de.j.deathMinigames.settings.GUI; +import de.j.stationofdoom.main.Main; +import de.j.stationofdoom.util.translations.TranslationFactory; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class TeamsMainMenuGUI extends GUI { + public static volatile List teams = new ArrayList<>(); + private final HashMap invSlots = new HashMap<>(); // for checking which team settings to open based on clicked slot + private float teamQuantity; + private final float maxSlotsPerPage = 45; + private int pagesBasedOnTeamsQuantity; // has to be greater than 0 + private final int inventorySize = 54; + private final TranslationFactory tf = new TranslationFactory(); + + public TeamsMainMenuGUI() { + if(Database.getInstance().isConnected) { + teams = HandleTeams.getInstance().getAllTeams(); + } + } + + public List getTeams() { + return teams; + } + + public void showPage(int page, Player player) { + this.inventory = null; + this.inventory = Bukkit.createInventory(this, inventorySize, "Teams - " + tf.getTranslation(player, "page") + " " + page ); + if(!TeamsMainMenuGUI.teams.isEmpty()) { + teamQuantity = TeamsMainMenuGUI.teams.size(); + pagesBasedOnTeamsQuantity = (int) Math.ceil(teamQuantity / maxSlotsPerPage); + fillPage(page); + } + addClickableItemStack(tf.getTranslation(player, "createTeam"), Material.CRAFTING_TABLE, 1, 45); + if(page == 1) { + addClickableItemStack(tf.getTranslation(player, "alreadyFirstPage"), Material.BARRIER, 1, 52); + } + else { + addClickableItemStack(tf.getTranslation(player, "lastPage"), Material.COPPER_BULB, page - 1, 52); + } + addClickableItemStack(tf.getTranslation(player, "nextPage"), Material.OXIDIZED_COPPER_BULB, page + 1, 53); + player.openInventory(this.inventory); + } + + private void fillPage(int page) { + float intToStartFrom = (page * maxSlotsPerPage) - maxSlotsPerPage; + addTeamsToInventory((int) intToStartFrom); + } + + private void addTeamsToInventory(int intToStartFrom) { + invSlots.clear(); + for(int teamsAdded = 0; teamsAdded < maxSlotsPerPage; teamsAdded++) { + if(teamsAdded >= teamQuantity || teamsAdded >= maxSlotsPerPage || intToStartFrom + teamsAdded >= teamQuantity) return; + Team currentTeam = TeamsMainMenuGUI.teams.get(intToStartFrom + teamsAdded); + ArrayList lore = getTeamInformation(currentTeam); + addClickableItemStack(currentTeam.getName(), currentTeam.getColorAsMaterial(), 1, teamsAdded, lore); + invSlots.put(teamsAdded, currentTeam); + } + } + + private ArrayList getTeamInformation(Team currentTeam) { + ArrayList lore = new ArrayList<>(); + if(!currentTeam.getTeamOperators().isEmpty()) { + lore.add("Team Operators:"); + for (PlayerData playerData : currentTeam.getTeamOperators()) { + lore.add(" " + playerData.getName()); + } + } + if(!currentTeam.getMembers().isEmpty()) { + lore.add("Team Members:"); + for (PlayerData playerData : currentTeam.getMembers()) { + lore.add(" " + playerData.getName()); + } + } + if(currentTeam.getProtectedLocation() == null) { + lore.add("No Claimed Location"); + } + else { + lore.add("Claimed Location:"); + lore.add(" X: " + currentTeam.getProtectedLocation().getBlockX() + " Z: " + currentTeam.getProtectedLocation().getBlockZ()); + } + return lore; + } + + public void addTeam(Player creatorOfTeam) { + new Team(creatorOfTeam); + } + + public int getPagesQuantity() { + if(pagesBasedOnTeamsQuantity == 0) return 1; + else return pagesBasedOnTeamsQuantity; + } + + public Team getTeamBasedOnSlot(int slot) { + Team teamBasedOnSlot = invSlots.get(slot); + if(teamBasedOnSlot == null) { + return null; + } + return teamBasedOnSlot; + } + +} diff --git a/src/main/java/de/j/stationofdoom/teams/chunkClaimSystem/BlockBreakAndUseCancelListener.java b/src/main/java/de/j/stationofdoom/teams/chunkClaimSystem/BlockBreakAndUseCancelListener.java new file mode 100644 index 00000000..58e6319f --- /dev/null +++ b/src/main/java/de/j/stationofdoom/teams/chunkClaimSystem/BlockBreakAndUseCancelListener.java @@ -0,0 +1,30 @@ +package de.j.stationofdoom.teams.chunkClaimSystem; + +import de.j.stationofdoom.main.Main; +import de.j.stationofdoom.teams.Team; +import de.j.stationofdoom.util.translations.TranslationFactory; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerInteractEvent; + +public class BlockBreakAndUseCancelListener implements Listener { + @EventHandler + public void onPlayerInteract(PlayerInteractEvent event) { + Player player = event.getPlayer(); + if(player == null || event.getClickedBlock() == null) return; + ChunkClaimSystem chunkClaimSystem = ChunkClaimSystem.getInstance(); + if(chunkClaimSystem.checkIfLocationProtectedFromPlayer(event.getClickedBlock().getX(), event.getClickedBlock().getZ(), player)) { + Team team = ChunkClaimSystem.getInstance().getTeam(event.getClickedBlock().getLocation()); + if(team == null) { + Main.getMainLogger().warning("Team is null when checking if location is protected"); + return; + } + player.sendMessage(Component.text(new TranslationFactory().getTranslation(player, "chunkClaimedByDifferentTeam", team.getName())).color(NamedTextColor.RED)); + event.setCancelled(true); + ChunkClaimSystem.getInstance().showPlayerProtectedLocationViaParticles(player, team.getProtectedLocation()); + } + } +} diff --git a/src/main/java/de/j/stationofdoom/teams/chunkClaimSystem/ChunkClaimSystem.java b/src/main/java/de/j/stationofdoom/teams/chunkClaimSystem/ChunkClaimSystem.java new file mode 100644 index 00000000..069167e8 --- /dev/null +++ b/src/main/java/de/j/stationofdoom/teams/chunkClaimSystem/ChunkClaimSystem.java @@ -0,0 +1,194 @@ +package de.j.stationofdoom.teams.chunkClaimSystem; + +import de.j.deathMinigames.main.Config; +import de.j.deathMinigames.main.HandlePlayers; +import de.j.stationofdoom.main.Main; +import de.j.stationofdoom.teams.HandleTeams; +import de.j.stationofdoom.teams.Team; +import de.j.stationofdoom.util.translations.TranslationFactory; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.*; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; + +import java.util.*; + +public class ChunkClaimSystem { + private final TranslationFactory tf = new TranslationFactory(); + private int protectedLocationSizeInBlocks = 32; + private final int heightOfCube = 20; + private final int period = 1; + private final Material material = Material.BARRIER; + private static volatile ChunkClaimSystem instance; + + private ChunkClaimSystem(){} + + public static ChunkClaimSystem getInstance() { + if (instance == null) { + synchronized (ChunkClaimSystem.class) { + if (instance == null) { + instance = new ChunkClaimSystem(); + } + } + } + return instance; + } + + public int getProtectedLocationSizeInBlocks() { + return protectedLocationSizeInBlocks; + } + + public void setProtectedLocationSizeInBlocks(int protectedLocationSizeInBlocks) { + this.protectedLocationSizeInBlocks = protectedLocationSizeInBlocks; + Config.getInstance().setProtectedLocationSizeInBlocksInConfig(protectedLocationSizeInBlocks); + } + + public boolean checkIfLocationProtectedFromPlayer(int locationX, int locationZ, Player player) { + HashMap locationsOfTeamsMap = getAllProtectedLocations(); + for (Location loc : locationsOfTeamsMap.keySet()) { + if(loc == null) continue; + int minX = loc.getBlockX() - protectedLocationSizeInBlocks; + int maxX = loc.getBlockX() + protectedLocationSizeInBlocks; + int minZ = loc.getBlockZ() - protectedLocationSizeInBlocks; + int maxZ = loc.getBlockZ() + protectedLocationSizeInBlocks; + if((locationX >= minX && locationX <= maxX) && (locationZ >= minZ && locationZ <= maxZ)){ + if(!locationsOfTeamsMap.get(loc).isMember(player.getUniqueId())) { + return true; + } + } + } + return false; + } + + public boolean checkIfAreaLocationIsProtectedFromPlayer(int locationX, int locationZ, Player player) { + return checkIfLocationProtectedFromPlayer(locationX + protectedLocationSizeInBlocks, locationZ + protectedLocationSizeInBlocks, player) || + checkIfLocationProtectedFromPlayer(locationX - protectedLocationSizeInBlocks, locationZ - protectedLocationSizeInBlocks, player) || + checkIfLocationProtectedFromPlayer(locationX + protectedLocationSizeInBlocks, locationZ - protectedLocationSizeInBlocks, player) || + checkIfLocationProtectedFromPlayer(locationX - protectedLocationSizeInBlocks, locationZ + protectedLocationSizeInBlocks, player); + } + + public Team getTeam(Location location) { + return getTeamFromLocation(location.getBlockX(), location.getBlockZ()); + } + + private Team getTeamFromLocation(int locationX, int locationZ) { + HashMap locationsOfTeamsMap = getAllProtectedLocations(); + for (Location loc : locationsOfTeamsMap.keySet()) { + int minX = loc.getBlockX() - protectedLocationSizeInBlocks; + int maxX = loc.getBlockX() + protectedLocationSizeInBlocks; + int minZ = loc.getBlockZ() - protectedLocationSizeInBlocks; + int maxZ = loc.getBlockZ() + protectedLocationSizeInBlocks; + if((locationX >= minX && locationX <= maxX) && (locationZ >= minZ && locationZ <= maxZ)){ + return locationsOfTeamsMap.get(loc); + } + } + return null; + } + + private HashMap getAllProtectedLocations() { + HashMap locationsOfTeamsMap = new HashMap<>(); + int i = 0; + for (Team team : HandleTeams.getInstance().getAllTeams()){ + Location location = team.getProtectedLocation(); + if(location != null) { + locationsOfTeamsMap.put(team.getProtectedLocation(), team); + i++; + } + } + return locationsOfTeamsMap; + } + + public void playerClaim(Player player, Team team, Location location) { + if(!checkIfAreaLocationIsProtectedFromPlayer(location.getBlockX(), location.getBlockZ(), player)) { + team.setProtectedLocation(location); + messageTeamMembersAboutNewProtectedLocation(team, player); + showPlayerProtectedLocationViaParticles(player, team.getProtectedLocation()); + } + else { + player.sendMessage(Component.text(tf.getTranslation(player, "teamLocationAlreadyProtected")).color(NamedTextColor.RED)); + } + } + + private void messageTeamMembersAboutNewProtectedLocation(Team team, Player claimingPlayer) { + for (UUID uuid : team.getAllPlayers()) { + if(HandlePlayers.getInstance().getPlayerData(uuid).isOnline()) { + Player player = Bukkit.getPlayer(uuid); + if(player == null) continue; + Location location = team.getProtectedLocation(); + if(uuid.equals(claimingPlayer.getUniqueId())) { + player.sendMessage(Component.text(tf.getTranslation(player, "teamSetProtectedLocation", location.getBlockX(), location.getBlockZ())).color(NamedTextColor.GREEN)); + } + else { + player.sendMessage(Component.text(tf.getTranslation(player, "teamMembersNewProtectedLocation", location.getBlockX(), location.getBlockZ())).color(NamedTextColor.GREEN)); + } + } + } + } + + public void showPlayerProtectedLocationViaParticles(Player player, Location location1) { + List corners = new ArrayList<>(); + Location playerLocation = player.getLocation(); + Location location = location1.clone(); + location.setY(playerLocation.getY()); + location = location.getBlock().getLocation(); + corners.add(location.clone().add(protectedLocationSizeInBlocks, heightOfCube, protectedLocationSizeInBlocks)); + corners.add(location.clone().add(-protectedLocationSizeInBlocks, heightOfCube, -protectedLocationSizeInBlocks)); + corners.add(location.clone().add(protectedLocationSizeInBlocks, heightOfCube, -protectedLocationSizeInBlocks)); + corners.add(location.clone().add(-protectedLocationSizeInBlocks, heightOfCube, protectedLocationSizeInBlocks)); + spawnEdgeParticles(location.getBlockX() + protectedLocationSizeInBlocks, location.getBlockZ() + protectedLocationSizeInBlocks, player, playerLocation, corners); + spawnEdgeParticles(location.getBlockX() - protectedLocationSizeInBlocks, location.getBlockZ() - protectedLocationSizeInBlocks, player, playerLocation, corners); + spawnEdgeParticles(location.getBlockX() + protectedLocationSizeInBlocks, location.getBlockZ() - protectedLocationSizeInBlocks, player, playerLocation, corners); + spawnEdgeParticles(location.getBlockX() - protectedLocationSizeInBlocks, location.getBlockZ() + protectedLocationSizeInBlocks, player, playerLocation, corners); + } + + private void spawnEdgeParticles(int locationX, int locationZ, Player player, Location playerLocation, List corners) { + BlockData blockData = Bukkit.createBlockData(material); + final int[] y = {playerLocation.getBlockY() - 30}; + Location thisCorner = new Location(player.getWorld(), locationX, playerLocation.getBlockY() + heightOfCube, locationZ); + + BukkitRunnable runnable = new BukkitRunnable() { + public void run() { + int i = 1; + if(y[0] >= playerLocation.getBlockY() + heightOfCube) { + for(Location corner : corners) { + Vector connectionVector = corner.clone().toVector().subtract(thisCorner.toVector()); + if(Math.round(connectionVector.length()) == (long) protectedLocationSizeInBlocks * 2) { + spawnBlockMarkerFromPointToAnother(thisCorner.clone(), thisCorner.clone().add(connectionVector.clone().multiply(0.5)), player); + } + i++; + } + this.cancel(); + } + player.spawnParticle(Particle.BLOCK_MARKER, locationX, y[0], locationZ, 1, 0, 0, 0, blockData); + y[0]++; + } + }; + runnable.runTaskTimer(Main.getPlugin(), 0, period); + } + + private void spawnBlockMarkerFromPointToAnother(Location locationFromWhereToDraw, Location locationToWhereToDraw, Player player) { + Vector vector = locationToWhereToDraw.toVector().subtract(locationFromWhereToDraw.toVector()); + Vector changeVector = vector.clone().multiply(1 / vector.length()); + Location location = locationFromWhereToDraw.clone(); + BlockData blockData = Bukkit.createBlockData(material); + final int[] y = {0}; + + BukkitRunnable runnable = new BukkitRunnable() { + public void run() { + if (y[0] >= vector.length()) { + this.cancel(); + } + player.spawnParticle(Particle.BLOCK_MARKER, location.add(changeVector), 1, 0, 0, 0, blockData); + y[0]++; + if(vector.length() > 16) { + player.spawnParticle(Particle.BLOCK_MARKER, location.add(changeVector), 1, 0, 0, 0, blockData); + y[0]++; + } + } + }; + runnable.runTaskTimerAsynchronously(Main.getPlugin(), 0, period); + } +} diff --git a/src/main/java/de/j/stationofdoom/teams/enderchest/EnderchestInvHolder.java b/src/main/java/de/j/stationofdoom/teams/enderchest/EnderchestInvHolder.java new file mode 100644 index 00000000..45e93869 --- /dev/null +++ b/src/main/java/de/j/stationofdoom/teams/enderchest/EnderchestInvHolder.java @@ -0,0 +1,13 @@ +package de.j.stationofdoom.teams.enderchest; + +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; + +public class EnderchestInvHolder implements InventoryHolder { + + /** returns null, don't use*/ + @Override + public Inventory getInventory() { + return null; + } +} diff --git a/src/main/java/de/j/stationofdoom/teams/enderchest/TeamEnderchestPreventEnchantedItemsInputListener.java b/src/main/java/de/j/stationofdoom/teams/enderchest/TeamEnderchestPreventEnchantedItemsInputListener.java new file mode 100644 index 00000000..1f8f9343 --- /dev/null +++ b/src/main/java/de/j/stationofdoom/teams/enderchest/TeamEnderchestPreventEnchantedItemsInputListener.java @@ -0,0 +1,32 @@ +package de.j.stationofdoom.teams.enderchest; + +import de.j.deathMinigames.dmUtil.DmUtil; +import de.j.stationofdoom.main.Main; +import de.j.stationofdoom.util.translations.TranslationFactory; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Sound; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; + +public class TeamEnderchestPreventEnchantedItemsInputListener implements Listener { + @EventHandler + public void onEnderchestInput(InventoryClickEvent event) { + try { + if(event.getView().getTopInventory().getHolder() instanceof EnderchestInvHolder && !event.getCurrentItem().getEnchantments().isEmpty()) { + event.setCancelled(true); + Player player = (Player) event.getView().getPlayer(); + if(player == null) return; + player.sendMessage(Component.text(new TranslationFactory().getTranslation(player, "teamEnderchestPreventEnchantedItemsInput")).color(NamedTextColor.RED)); + DmUtil.getInstance().playSoundAtLocation(player.getLocation(), 1F, Sound.BLOCK_ANVIL_PLACE); + } + } + catch (NullPointerException e) { + Main.getMainLogger().warning(e.getMessage()); + return; + } + } + +} diff --git a/src/main/java/de/j/stationofdoom/util/Tablist.java b/src/main/java/de/j/stationofdoom/util/Tablist.java index b6ff7e11..9093317e 100644 --- a/src/main/java/de/j/stationofdoom/util/Tablist.java +++ b/src/main/java/de/j/stationofdoom/util/Tablist.java @@ -2,133 +2,292 @@ import de.j.deathMinigames.main.Config; import de.j.stationofdoom.main.Main; +import de.j.stationofdoom.teams.HandleTeams; +import de.j.stationofdoom.teams.Team; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextDecoration; -import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; +import org.bukkit.*; import org.bukkit.entity.Player; import org.bukkit.scoreboard.Scoreboard; -import java.util.HashMap; +import java.util.*; import java.util.stream.Stream; public class Tablist { private volatile static String serverName = Bukkit.getServer().getName(); private volatile static String hostedBy = null; + private static final HashMap playerRanks = new HashMap<>(); + private static final List afkPlayers = new ArrayList<>(); private static Scoreboard scoreboard; - public static HashMap rank; //Map that contains the player as key and the header and footer as array private final HashMap playerListMap = new HashMap<>(); + private static final Map colors = new HashMap<>(); + + private static final int secondsBetweenReloads = 10; + private static int n = 0; + private static boolean autoReloadRunning = false; + private static int autoReloadTaskId; + + private enum Ranks { + HOST, + ADMIN, + DEVELOPER + } + public void setScoreboard() { assert !Main.isFolia(); + putColorsInMap(); + scoreboard = Bukkit.getScoreboardManager().getNewScoreboard(); - rank = new HashMap<>(); - scoreboard.registerNewTeam("0Host"); - scoreboard.registerNewTeam("1Admin"); - scoreboard.registerNewTeam("2Developer"); - scoreboard.registerNewTeam("4Spieler"); - scoreboard.registerNewTeam("5AFK"); + createScoreboardTeamsWithoutTeamName(); + for (Team team : HandleTeams.getInstance().getAllTeams()) { + createScoreboardTeamsFromTeam(team); + } - MiniMessage mm = MiniMessage.miniMessage(); + setAllPlayerRanks(); + for (Player on : Bukkit.getOnlinePlayers()){ + setTeam(on); + reloadScoreboard(on); + } + if(!autoReloadRunning) { + startAutoReload(); + } + } + + private void putColorsInMap() { + colors.put("WHITE", "#FFFFFF"); + colors.put("ORANGE", "#FFA500"); + colors.put("MAGENTA", "#ff00ff"); + colors.put("LIGHT_BLUE", "#ADD8E6"); + colors.put("YELLOW", "#FFFF00"); + colors.put("LIME", "#00FF00"); + colors.put("PINK", "#FFC0CB"); + colors.put("GRAY", "#808080"); + colors.put("LIGHT_GRAY", "#D3D3D3"); + colors.put("CYAN", "#E0FFFF"); + colors.put("PURPLE", "#800080"); + colors.put("BLUE", "#0000FF"); + colors.put("BROWN", "#964B00"); + colors.put("GREEN", "#008000"); + colors.put("RED", "#FF0000"); + colors.put("BLACK", "#000000"); + } + + // teams without any team name in it only once + private void createScoreboardTeamsWithoutTeamName() { + scoreboard.registerNewTeam("0Host"); scoreboard.getTeam("0Host").prefix(Component.text("Host ") .color(NamedTextColor.DARK_RED).decoration(TextDecoration.BOLD, true) - .append(Component.text("| ").color(NamedTextColor.DARK_GRAY))); - //scoreboard.getTeam("0Host") - // .prefix(mm.deserialize("Host | ")); + .append(Component.text("| ").color(NamedTextColor.WHITE))); + + scoreboard.registerNewTeam("0AFK_Host"); + scoreboard.getTeam("0AFK_Host").prefix(Component.text("AFK ") + .color(NamedTextColor.DARK_RED).decoration(TextDecoration.BOLD, true) + .append(Component.text("Host ") + .color(NamedTextColor.DARK_RED).decoration(TextDecoration.BOLD, true) + .append(Component.text("| ").color(NamedTextColor.WHITE)))); + + scoreboard.registerNewTeam("1Admin"); scoreboard.getTeam("1Admin").prefix(Component.text("Admin ") .color(NamedTextColor.RED) - .append(Component.text("| ").color(NamedTextColor.DARK_GRAY))); + .append(Component.text("| ").color(NamedTextColor.WHITE))); + + scoreboard.registerNewTeam("1AFK_Admin"); + scoreboard.getTeam("1AFK_Admin").prefix(Component.text("AFK ") + .color(NamedTextColor.DARK_RED).decoration(TextDecoration.BOLD, true) + .append(Component.text("Admin ") + .color(NamedTextColor.RED) + .append(Component.text("| ").color(NamedTextColor.WHITE)))); + + scoreboard.registerNewTeam("2Developer"); scoreboard.getTeam("2Developer").prefix(Component.text("Dev ") .color(NamedTextColor.GOLD) - .append(Component.text("| ").color(NamedTextColor.DARK_GRAY))); - scoreboard.getTeam("4Spieler").prefix(Component.text("")); - scoreboard.getTeam("5AFK").prefix(Component.text("[") - .color(NamedTextColor.DARK_BLUE) - .append(Component.text("AFK") - .color(NamedTextColor.DARK_AQUA) - .append(Component.text("] ") - .color(NamedTextColor.DARK_BLUE) - .append(Component.text("| ").color(NamedTextColor.DARK_GRAY))))); + .append(Component.text("| ").color(NamedTextColor.WHITE))); + scoreboard.registerNewTeam("2AFK_Developer"); + scoreboard.getTeam("2AFK_Developer").prefix(Component.text("AFK ") + .color(NamedTextColor.DARK_RED).decoration(TextDecoration.BOLD, true) + .append(Component.text("Dev ") + .color(NamedTextColor.GOLD) + .append(Component.text("| ").color(NamedTextColor.WHITE)))); + + scoreboard.registerNewTeam("3AFK_"); + scoreboard.getTeam("3AFK_").prefix(Component.text("AFK ") + .color(NamedTextColor.DARK_RED).decoration(TextDecoration.BOLD, true) + .append(Component.text("| ").color(NamedTextColor.WHITE))); - for (Player on : Bukkit.getOnlinePlayers()){ - setTeam(on); - } } - public void setScoreboard(Player player, boolean afk) { - assert !Main.isFolia(); - scoreboard.getTeam("0Host").prefix(Component.text("Host ") + private void createScoreboardTeamsFromTeam(Team team) { + TextColor teamColor; + if(team.getColorAsString() == null || colors.get(team.getColorAsString()) == null) { + Main.getMainLogger().warning("Could not find color for " + team.getName()); + teamColor = NamedTextColor.WHITE; + } + else { + teamColor = TextColor.fromHexString(colors.get(team.getColorAsString())); + } + + scoreboard.registerNewTeam("0Host_" + team.getUuid()); + scoreboard.getTeam("0Host_" + team.getUuid()).prefix(Component.text("Host ") + .color(NamedTextColor.DARK_RED).decoration(TextDecoration.BOLD, true) + .append(Component.text("| ").color(NamedTextColor.WHITE) + .append(Component.text(team.getName() + " ").color(teamColor) + .append(Component.text("| ").color(NamedTextColor.WHITE))))); + scoreboard.registerNewTeam("0AFK_Host_" + team.getUuid()); + scoreboard.getTeam("0AFK_Host_" + team.getUuid()).prefix(Component.text("AFK ") .color(NamedTextColor.DARK_RED).decoration(TextDecoration.BOLD, true) - .append(Component.text("| ").color(NamedTextColor.DARK_GRAY))); - scoreboard.getTeam("1Admin").prefix(Component.text("Admin ") + .append(Component.text("Host ") + .color(NamedTextColor.DARK_RED).decoration(TextDecoration.BOLD, true) + .append(Component.text("| ").color(NamedTextColor.WHITE) + .append(Component.text(team.getName() + " ").color(teamColor) + .append(Component.text("| ").color(NamedTextColor.WHITE)))))); + + scoreboard.registerNewTeam("1Admin_" + team.getUuid()); + scoreboard.getTeam("1Admin_" + team.getUuid()).prefix(Component.text("Admin ") .color(NamedTextColor.RED) - .append(Component.text("| ").color(NamedTextColor.DARK_GRAY))); - scoreboard.getTeam("2Developer").prefix(Component.text("Dev ") + .append(Component.text("| ").color(NamedTextColor.WHITE) + .append(Component.text(team.getName() + " ").color(teamColor) + .append(Component.text("| ").color(NamedTextColor.WHITE))))); + scoreboard.registerNewTeam("1AFK_Admin_" + team.getUuid()); + scoreboard.getTeam("1AFK_Admin_" + team.getUuid()).prefix(Component.text("AFK ") + .color(NamedTextColor.DARK_RED).decoration(TextDecoration.BOLD, true) + .append(Component.text("Admin ") + .color(NamedTextColor.RED) + .append(Component.text("| ").color(NamedTextColor.WHITE) + .append(Component.text(team.getName() + " ").color(teamColor) + .append(Component.text("| ").color(NamedTextColor.WHITE)))))); + + scoreboard.registerNewTeam("2Developer_" + team.getUuid()); + scoreboard.getTeam("2Developer_" + team.getUuid()).prefix(Component.text("Dev ") .color(NamedTextColor.GOLD) - .append(Component.text("| ").color(NamedTextColor.DARK_GRAY))); - scoreboard.getTeam("4Spieler").prefix(Component.text("")); - scoreboard.getTeam("5AFK").prefix(Component.text("[") - .color(NamedTextColor.DARK_BLUE) - .append(Component.text("AFK") - .color(NamedTextColor.DARK_AQUA) - .append(Component.text("] ") - .color(NamedTextColor.DARK_BLUE) - .append(Component.text("| ").color(NamedTextColor.DARK_GRAY))))); + .append(Component.text("| ").color(NamedTextColor.WHITE) + .append(Component.text(team.getName() + " ").color(teamColor) + .append(Component.text("| ").color(NamedTextColor.WHITE))))); + scoreboard.registerNewTeam("2AFK_Developer_" + team.getUuid()); + scoreboard.getTeam("2AFK_Developer_" + team.getUuid()).prefix(Component.text("AFK ") + .color(NamedTextColor.DARK_RED).decoration(TextDecoration.BOLD, true) + .append(Component.text("Dev ") + .color(NamedTextColor.GOLD) + .append(Component.text("| ").color(NamedTextColor.WHITE) + .append(Component.text(team.getName() + " ").color(teamColor) + .append(Component.text("| ").color(NamedTextColor.WHITE)))))); - setTeam(player, afk); + scoreboard.registerNewTeam("3AFK_" + team.getUuid()); + scoreboard.getTeam("3AFK_" + team.getUuid()).prefix(Component.text("AFK ") + .color(NamedTextColor.DARK_RED).decoration(TextDecoration.BOLD, true) + .append(Component.text("| ").color(NamedTextColor.WHITE) + .append(Component.text(team.getName() + " ").color(teamColor) + .append(Component.text("| ").color(NamedTextColor.WHITE))))); + scoreboard.registerNewTeam("3_" + team.getUuid()); + scoreboard.getTeam("3_" + team.getUuid()).prefix(Component.text(team.getName() + " ").color(teamColor) + .append(Component.text("| ").color(NamedTextColor.WHITE))); + } + private void setAllPlayerRanks() { + playerRanks.put(UUID.fromString("46cd27ba-df0c-49ef-9f33-6cfa884e339b"), Ranks.DEVELOPER); + playerRanks.put(UUID.fromString("050fee27-a1cc-4e78-953a-7cefaf0849a1"), Ranks.DEVELOPER); } private void setTeam(Player player) { assert !Main.isFolia(); - String team = null; - switch (player.getUniqueId().toString()) { - case "050fee27-a1cc-4e78-953a-7cefaf0849a1" -> {//LP - team = "0Host"; - rank.put(player, ChatColor.RED + "" + ChatColor.BOLD + "[Host]" + ChatColor.RESET + " "); + UUID playerUUID = player.getUniqueId(); + if(playerRanks.containsKey(player.getUniqueId())) { + switch (playerRanks.get(player.getUniqueId())) { + case Ranks.HOST: + if(afkPlayers.contains(player.getUniqueId())) { + if(HandleTeams.getTeamFromPlayerUUID(playerUUID).isMember(player.getUniqueId())) { + scoreboard.getTeam("0AFK_Host_" + HandleTeams.getTeamFromPlayerUUID(playerUUID).getUuid()).addPlayer(player); + } + else { + scoreboard.getTeam("0AFK_Host").addPlayer(player); + } + } + else { + if(HandleTeams.getTeamFromPlayerUUID(playerUUID).isMember(player.getUniqueId())) { + scoreboard.getTeam("0Host_" + HandleTeams.getTeamFromPlayerUUID(playerUUID).getUuid()).addPlayer(player); + } + else { + scoreboard.getTeam("0Host").addPlayer(player); + } + } + break; + case Ranks.ADMIN: + if(afkPlayers.contains(player.getUniqueId())) { + if(HandleTeams.getTeamFromPlayerUUID(playerUUID).isMember(player.getUniqueId())) { + scoreboard.getTeam("1AFK_Admin_" + HandleTeams.getTeamFromPlayerUUID(playerUUID).getUuid()).addPlayer(player); + } + else { + scoreboard.getTeam("1AFK_Admin").addPlayer(player); + } + } + else { + if(HandleTeams.getTeamFromPlayerUUID(playerUUID).isMember(player.getUniqueId())) { + scoreboard.getTeam("1Admin_" + HandleTeams.getTeamFromPlayerUUID(playerUUID).getUuid()).addPlayer(player); + } + else { + scoreboard.getTeam("1Admin").addPlayer(player); + } + } + break; + case Ranks.DEVELOPER: + if(afkPlayers.contains(player.getUniqueId())) { + if(HandleTeams.getTeamFromPlayerUUID(playerUUID).isMember(player.getUniqueId())) { + scoreboard.getTeam("2AFK_Developer_" + HandleTeams.getTeamFromPlayerUUID(playerUUID).getUuid()).addPlayer(player); + } + else { + scoreboard.getTeam("2AFK_Developer").addPlayer(player); + } + } + else { + if(HandleTeams.getTeamFromPlayerUUID(playerUUID).isMember(player.getUniqueId())) { + scoreboard.getTeam("2Developer_" + HandleTeams.getTeamFromPlayerUUID(playerUUID).getUuid()).addPlayer(player); + } + else { + scoreboard.getTeam("2Developer").addPlayer(player); + } + } + break; } - case "0565369c-ec68-4e7e-a90f-3492eb7002d8" -> {//MDHD - team = "1Admin"; - rank.put(player, ChatColor.BLUE + "" + ChatColor.BOLD + "[Admin]" + ChatColor.RESET + " "); - } - //case "" -> { - // team = "2Developer"; - // rank.put(player, ChatColor.GRAY + "[Dev]" + ChatColor.RESET + " "); - //} } - - if (team == null) { - team = "4Spieler"; - rank.put(player, ""); + else { + if(afkPlayers.contains(player.getUniqueId())) { + if(HandleTeams.getTeamFromPlayerUUID(playerUUID).isMember(player.getUniqueId())) { + scoreboard.getTeam("3AFK_" + HandleTeams.getTeamFromPlayerUUID(playerUUID).getUuid()).addPlayer(player); + } + else { + scoreboard.getTeam("3AFK_").addPlayer(player); + } + } + else { + if(HandleTeams.getTeamFromPlayerUUID(playerUUID).isMember(player.getUniqueId())) { + scoreboard.getTeam("3_" + HandleTeams.getTeamFromPlayerUUID(playerUUID).getUuid()).addPlayer(player); + } + } } + } - scoreboard.getTeam(team).addPlayer(player); + private void reloadScoreboard(Player player) { player.setScoreboard(scoreboard); } - private void setTeam(Player player, boolean afk) { + public void setAFK(Player player, boolean afk) { assert !Main.isFolia(); - String team; - if (afk) { - team = "5AFK"; - rank.put(player, ChatColor.DARK_BLUE + "[" + ChatColor.DARK_AQUA + "AFK" + ChatColor.DARK_BLUE + "]"); - - scoreboard.getTeam(team).addPlayer(player); - player.setScoreboard(scoreboard); - } else - setTeam(player); - } - public void tab(Audience player, Component header, Component footer) { - player.sendPlayerListHeaderAndFooter(header, footer); + if(afk && !afkPlayers.contains(player.getUniqueId())) { + afkPlayers.add(player.getUniqueId()); + } + else if(!afk && afkPlayers.contains(player.getUniqueId())) { + afkPlayers.remove(player.getUniqueId()); + } + setScoreboard(); } public void tabTPS(Audience player, Component header, Component footer) { @@ -147,15 +306,6 @@ public void tabTPS(Audience player, Component header, Component footer) { playerListMap.put(player, Stream.of(header, footer).toArray(Component[]::new)); } - public void setAFK(Player player, boolean afk) { - assert !Main.isFolia(); - if (afk) { - setScoreboard(player, afk); - } else - setScoreboard(player, false); - - } - public Component getTimeComponent(Player player) { double time = (player.getWorld().getFullTime() / 1000.0 + 6) % 24; String formattedTime = String.format("%02d:%02d", (int) time, (int) ((time % 1) * 60)); @@ -188,4 +338,26 @@ public static void setHostedBy(String hostedBy) { public static String getHostedBy() { return hostedBy; } + + private static void startAutoReload() { + autoReloadRunning = true; + autoReloadTaskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(Main.getPlugin(), new Runnable() { + public void run() { + if(Bukkit.getOnlinePlayers().isEmpty()) { + stopAutoReload(); + } + if (n >= secondsBetweenReloads){ + Tablist tablist = new Tablist(); + tablist.setScoreboard(); + n = 0; + } + n++; + } + }, 20, 20); + } + + private static void stopAutoReload() { + autoReloadRunning = false; + Bukkit.getScheduler().cancelTask(autoReloadTaskId); + } } diff --git a/src/main/resources/translations.json b/src/main/resources/translations.json index 2448d3f2..59b0315f 100755 --- a/src/main/resources/translations.json +++ b/src/main/resources/translations.json @@ -65,7 +65,7 @@ "ignoreMinigame": "nicht um deine Items spielen", "maxDiffAlreadyReached": "Du hast schon die maximale Schwierigkeit erreicht. Hast du super gemacht", "introParkour": "Du musst diesen Parkour bestehen, um deine Items wieder zu bekommen", - "loseMessage": "Du hast verloren. Dein Inventar wird an deinem Todesort gedroppt\n Todesort: %s\n Wenn du deine Schwierigkeit verringern möchtest musst du etwas opfern. Clicke dafür hier oder gib /game lowerDifficulty ein", + "loseMessage": "Du hast verloren. Dein Inventar wird an deinem Todesort gedroppt\n Todesort: %s\n Wenn du deine Schwierigkeit verringern möchtest musst du etwas opfern. Clicke dafür hier oder gib /game lowerDifficulty ein", "winMessage": "Du hast gewonnen, du bekommst jetzt deine Items", "winInv": "Deine Items", "backButton": "Zurück", @@ -84,7 +84,42 @@ "invalidDifficulty": "Die Schwierigkeit muss zwischen 0 und 10 sein", "anvilOutput": "Klicke hier um zu bestätigen", "noNameSet": "Kein Name gesetzt", - "enchantNotEnabled": "Diese Verzauberung ist auf diesem Server nicht aktiviert." + "createTeam": "Erstelle eine Team", + "alreadyFirstPage": "Du bist bereits auf der ersten Seite", + "lastPage": "Zurück", + "nextPage": "Weiter", + "page": "Seite", + "leaveTeam": "Team verlassen", + "joinTeam": "Team beitreten", + "renameTeam": "Team umbenennen", + "deleteTeam": "Team löschen", + "changeColor": "Farbe ändern", + "lockTeamSettings": "Team Einstellungen sperren", + "lockedTeamSettingsLore": "Wenn die Einstellungen gesperrt sind, können diese nur die Team Operatoren bearbeiten", + "teamEnderChest": "Team Enderchest", + "teamEnderChestLore": "Klicke hier um die Team-Enderchest zu öffnen", + "teamLockedAndNotOperator": "Die Team Einstellung sind gesperrt und du bis kein Operator von diesem Team", + "teamNotAMember": "Du bist kein Mitglied dieses Teams", + "teamPlayerSettingsDemoteToMember": "Zu Mitglied herunterstufen", + "teamPlayerSettingsPromoteToOperator": "Zu Operator hochstufen", + "teamPlayerSettingsKickPlayer": "Spieler kicken", + "kickedFromTeam": "Du wurdest von %s vom Team gekickt", + "teamDeleted": "Das Team, %s, ist gelöscht und du kannst es nicht mehr öffnen", + "playerIsOffline": "Der Spieler ist offline", + "teamClaimChunks": "Chunks beanspruchen", + "teamClaimChunksProtectedLocation": "Chunks beanspruchen (gerade: x: %s y: %s z: %S)", + "teamClaimChunksLore": "Klicke hier, um Anspruch auf die drei umgebenden Chunks zu erheben", + "chunkClaimedByDifferentTeam": "Dieser Chunk ist von dem Team: %s beansprucht", + "teamEnderchestPreventEnchantedItemsInput": "Du kannst keine verzauberten Items in die Enderchest legen", + "teamSetProtectedLocation": "Du hast den Bereich um die Location x: %s z: %S geschützt", + "teamLocationAlreadyProtected": "Dieser Bereich ist bereits beschützt", + "teamMembersNewProtectedLocation": "Dein Team hat einen neuen Bereich geschützt: x: %s z: %s", + "setClaimingRadius": "Du hast den Radius des beschützen Bereichs jedes Team auf: %s gesetzt", + "TeamCMDNoTeam": "Du bist in keinem Team", + "teamLocked": "Das Team ist gesperrt", + "enchantNotEnabled": "Diese Verzauberung ist auf diesem Server nicht aktiviert", + "noTeam": "Es wurde für dich kein Team gefunden", + "invalidAnvilInputClaimingRadius": "Deine Eingabe war invalide, bitte gebe nur positive Zahlen bis 256 ein" } ], "en-US": [ @@ -153,7 +188,7 @@ "ignoreMinigame": "not play for your items", "maxDiffAlreadyReached": "You already reached the maximum difficulty.", "introParkour": "You have to get to the end of this parkour to get your items back", - "loseMessage": "You lost. Your inventory will be dropped at your point of death \n Deathpoint: %s \n If this difficulty is to hard for you, you can lower it by sacrificing something. Click here or type /game lowerDifficulty in chat.", + "loseMessage": "You lost. Your inventory will be dropped at your point of death \n Deathpoint: %s \n If this difficulty is to hard for you, you can lower it by sacrificing something. Click here or type /game lowerDifficulty in chat.", "winMessage": "You won, you will get your items back", "winInv": "Your items", "backButton": "Back", @@ -172,7 +207,42 @@ "invalidDifficulty": "The difficulty has to be between 0 and 10", "anvilOutput": "Click here to accept", "noNameSet": "No name set", - "enchantNotEnabled": "This enchantment is currently not activated." + "createTeam": "Create a team", + "alreadyFirstPage": "You are already on the first page", + "lastPage": "Back", + "nextPage": "Next", + "page": "Page", + "leaveTeam": "Leave team", + "joinTeam": "Join team", + "renameTeam": "Rename team", + "deleteTeam": "Delete team", + "changeColor": "Change color", + "lockTeamSettings": "Lock team settings", + "lockedTeamSettingsLore": "When locked, only team operators can change team settings", + "teamEnderChest": "Team enderchest", + "teamEnderChestLore": "Click here to open the team enderchest", + "teamLockedAndNotOperator": "The team settings are locked and you are not an operator of this team", + "teamNotAMember": "You are not a member of this team", + "teamPlayerSettingsDemoteToMember": "Demote to member", + "teamPlayerSettingsPromoteToOperator": "Promote to operator", + "teamPlayerSettingsKickPlayer": "Kick player", + "kickedFromTeam": "You got kicked from the team by %s", + "teamDeleted": "The team, %s, is deleted and you can not open it anymore", + "playerIsOffline": "This player is offline", + "teamClaimChunks": "Claim chunks", + "teamClaimChunksProtectedLocation": "Claim chunks (at the moment: x: %s y: %s z: %S)", + "teamClaimChunksLore": "Click here to claim the three surrounding chunks for your team", + "chunkClaimedByDifferentTeam": "This chunk is claimed by the team: %s", + "teamEnderchestPreventEnchantedItemsInput": "You can not put enchanted items into the team enderchest", + "teamSetProtectedLocation": "You claimed the location around x: %s z: %s", + "teamLocationAlreadyProtected": "This location is already claimed", + "teamMembersNewProtectedLocation": "Your team has claimed a new location: x: %s z: %s", + "setClaimingRadius": "You set the claiming radius to: %s", + "TeamCMDNoTeam": "You are not in any team", + "teamLocked": "This team is locked", + "enchantNotEnabled": "This enchantment is currently not activated.", + "noTeam": "There was no team found for you", + "invalidAnvilInputClaimingRadius": "Your input is invalid, please only use positive numbers which are smaller than 256" } ] } \ No newline at end of file