callable) {
+ super(chartId);
+ this.callable = callable;
+ }
+
+ @Override
+ protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
+ int value = callable.call();
+ if (value == 0) {
+ // Null = skip the chart
+ return null;
+ }
+ return new JsonObjectBuilder().appendField("value", value).build();
+ }
+ }
+
+ /**
+ * An extremely simple JSON builder.
+ *
+ * While this class is neither feature-rich nor the most performant one, it's sufficient enough
+ * for its use-case.
+ */
+ public static class JsonObjectBuilder {
+
+ private StringBuilder builder = new StringBuilder();
+
+ private boolean hasAtLeastOneField = false;
+
+ public JsonObjectBuilder() {
+ builder.append("{");
+ }
+
+ /**
+ * Appends a null field to the JSON.
+ *
+ * @param key The key of the field.
+ * @return A reference to this object.
+ */
+ public JsonObjectBuilder appendNull(String key) {
+ appendFieldUnescaped(key, "null");
+ return this;
+ }
+
+ /**
+ * Appends a string field to the JSON.
+ *
+ * @param key The key of the field.
+ * @param value The value of the field.
+ * @return A reference to this object.
+ */
+ public JsonObjectBuilder appendField(String key, String value) {
+ if (value == null) {
+ throw new IllegalArgumentException("JSON value must not be null");
+ }
+ appendFieldUnescaped(key, "\"" + escape(value) + "\"");
+ return this;
+ }
+
+ /**
+ * Appends an integer field to the JSON.
+ *
+ * @param key The key of the field.
+ * @param value The value of the field.
+ * @return A reference to this object.
+ */
+ public JsonObjectBuilder appendField(String key, int value) {
+ appendFieldUnescaped(key, String.valueOf(value));
+ return this;
+ }
+
+ /**
+ * Appends an object to the JSON.
+ *
+ * @param key The key of the field.
+ * @param object The object.
+ * @return A reference to this object.
+ */
+ public JsonObjectBuilder appendField(String key, JsonObject object) {
+ if (object == null) {
+ throw new IllegalArgumentException("JSON object must not be null");
+ }
+ appendFieldUnescaped(key, object.toString());
+ return this;
+ }
+
+ /**
+ * Appends a string array to the JSON.
+ *
+ * @param key The key of the field.
+ * @param values The string array.
+ * @return A reference to this object.
+ */
+ public JsonObjectBuilder appendField(String key, String[] values) {
+ if (values == null) {
+ throw new IllegalArgumentException("JSON values must not be null");
+ }
+ String escapedValues =
+ Arrays.stream(values)
+ .map(value -> "\"" + escape(value) + "\"")
+ .collect(Collectors.joining(","));
+ appendFieldUnescaped(key, "[" + escapedValues + "]");
+ return this;
+ }
+
+ /**
+ * Appends an integer array to the JSON.
+ *
+ * @param key The key of the field.
+ * @param values The integer array.
+ * @return A reference to this object.
+ */
+ public JsonObjectBuilder appendField(String key, int[] values) {
+ if (values == null) {
+ throw new IllegalArgumentException("JSON values must not be null");
+ }
+ String escapedValues =
+ Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(","));
+ appendFieldUnescaped(key, "[" + escapedValues + "]");
+ return this;
+ }
+
+ /**
+ * Appends an object array to the JSON.
+ *
+ * @param key The key of the field.
+ * @param values The integer array.
+ * @return A reference to this object.
+ */
+ public JsonObjectBuilder appendField(String key, JsonObject[] values) {
+ if (values == null) {
+ throw new IllegalArgumentException("JSON values must not be null");
+ }
+ String escapedValues =
+ Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(","));
+ appendFieldUnescaped(key, "[" + escapedValues + "]");
+ return this;
+ }
+
+ /**
+ * Appends a field to the object.
+ *
+ * @param key The key of the field.
+ * @param escapedValue The escaped value of the field.
+ */
+ private void appendFieldUnescaped(String key, String escapedValue) {
+ if (builder == null) {
+ throw new IllegalStateException("JSON has already been built");
+ }
+ if (key == null) {
+ throw new IllegalArgumentException("JSON key must not be null");
+ }
+ if (hasAtLeastOneField) {
+ builder.append(",");
+ }
+ builder.append("\"").append(escape(key)).append("\":").append(escapedValue);
+ hasAtLeastOneField = true;
+ }
+
+ /**
+ * Builds the JSON string and invalidates this builder.
+ *
+ * @return The built JSON string.
+ */
+ public JsonObject build() {
+ if (builder == null) {
+ throw new IllegalStateException("JSON has already been built");
+ }
+ JsonObject object = new JsonObject(builder.append("}").toString());
+ builder = null;
+ return object;
+ }
+
+ /**
+ * Escapes the given string like stated in https://www.ietf.org/rfc/rfc4627.txt.
+ *
+ *
This method escapes only the necessary characters '"', '\'. and '\u0000' - '\u001F'.
+ * Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and not as "\n").
+ *
+ * @param value The value to escape.
+ * @return The escaped value.
+ */
+ private static String escape(String value) {
+ final StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < value.length(); i++) {
+ char c = value.charAt(i);
+ if (c == '"') {
+ builder.append("\\\"");
+ } else if (c == '\\') {
+ builder.append("\\\\");
+ } else if (c <= '\u000F') {
+ builder.append("\\u000").append(Integer.toHexString(c));
+ } else if (c <= '\u001F') {
+ builder.append("\\u00").append(Integer.toHexString(c));
+ } else {
+ builder.append(c);
+ }
+ }
+ return builder.toString();
+ }
+
+ /**
+ * A super simple representation of a JSON object.
+ *
+ *
This class only exists to make methods of the {@link JsonObjectBuilder} type-safe and not
+ * allow a raw string inputs for methods like {@link JsonObjectBuilder#appendField(String,
+ * JsonObject)}.
+ */
+ public static class JsonObject {
+
+ private final String value;
+
+ private JsonObject(String value) {
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/ceraia/modules/ModuleMarriage.kt b/src/main/java/com/ceraia/modules/MarriageModule.kt
similarity index 61%
rename from src/main/java/com/ceraia/modules/ModuleMarriage.kt
rename to src/main/java/com/ceraia/modules/MarriageModule.kt
index 6121c03..70126f7 100644
--- a/src/main/java/com/ceraia/modules/ModuleMarriage.kt
+++ b/src/main/java/com/ceraia/modules/MarriageModule.kt
@@ -15,24 +15,27 @@ import org.bukkit.event.Listener
import org.bukkit.event.player.PlayerInteractEntityEvent
import org.bukkit.event.player.PlayerQuitEvent
import org.bukkit.util.StringUtil
+import kotlin.math.cos
+import kotlin.math.sin
-class ModuleMarriage(private val plugin: Ceraia) : CommandExecutor, TabCompleter, Listener {
+class MarriageModule(private val plugin: Ceraia) : CommandExecutor, TabCompleter, Listener {
- private val invites: MutableMap = mutableMapOf()
+ private val proposals: MutableMap = mutableMapOf()
+ // First is parent of the request, second is the child
+ private val adoptionRequests: MutableMap = mutableMapOf()
init {
plugin.getCommand("marry")?.setExecutor(this)
plugin.getCommand("divorce")?.setExecutor(this)
plugin.getCommand("marry")?.tabCompleter = this
-
Bukkit.getPluginManager().registerEvents(this, plugin)
}
override fun onCommand(sender: CommandSender, cmd: Command, label: String, args: Array): Boolean {
if (sender !is Player) return true
- if (!sender.hasPermission("double.marry")) {
+ if (!sender.hasPermission("ceraia.marry")) {
plugin.noPermission(sender)
return true
}
@@ -51,13 +54,63 @@ class ModuleMarriage(private val plugin: Ceraia) : CommandExecutor, TabCompleter
return true
}
- invite(sender, target)
+ propose(sender, target)
+ }
+ "adopt" -> {
+ if (args.isEmpty() || args.size < 2 || (args[0] != "parent" && args[0] != "kid")) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize("Usage: /adopt "))
+ return true
+ }
+
+ val target = plugin.server.getPlayer(args[1])
+
+ if (target == null) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize("Player not found"))
+ return true
+ }
+
+ if(args[0] == "parent") adopt(sender, target) else adopt(target, sender)
}
}
return true
}
+ private fun adopt(parent: Player, child: Player) {
+ if (adoptionRequests.containsKey(parent)) {
+ if (adoptionRequests[parent] == child) {
+ acceptAdoption(parent, child)
+ return
+ }
+ }
+
+ adoptionRequests[child] = parent
+ plugin.server.sendMessage(MiniMessage.miniMessage().deserialize(
+ "${parent.name} has invited ${child.name} to adopt them!"
+ ))
+ child.sendMessage(MiniMessage.miniMessage().deserialize(
+ "${parent.name} has invited you to adopt them! Click [here] to accept."
+ ))
+ }
+
+ private fun acceptAdoption(parent: Player, child: Player) {
+ val parentCeraiaPlayer = plugin.playerManager.getCeraiaPlayer(parent.uniqueId)
+ val childCeraiaPlayer = plugin.playerManager.getCeraiaPlayer(child.uniqueId)
+
+ if (adoptionRequests[child] != parent) {
+ return
+ }
+
+ plugin.server.sendMessage(MiniMessage.miniMessage().deserialize(
+ "${child.name} has accepted ${parent.name}'s adoption proposal!"
+ ))
+
+ childCeraiaPlayer.addParent(parent.name)
+ parentCeraiaPlayer.addChild(child.name)
+
+ adoptionRequests.remove(child)
+ }
+
override fun onTabComplete(sender: CommandSender, cmd: Command, label: String, args: Array): List {
// Return all online players except the sender
val tabOptions = Bukkit.getServer().onlinePlayers
@@ -71,7 +124,7 @@ class ModuleMarriage(private val plugin: Ceraia) : CommandExecutor, TabCompleter
return returnedOptions
}
- fun invite(sender: Player, target: Player) {
+ private fun propose(sender: Player, target: Player) {
val senderCeraiaPlayer = plugin.playerManager.getCeraiaPlayer(sender.uniqueId)
val targetCeraiaPlayer = plugin.playerManager.getCeraiaPlayer(target.uniqueId)
@@ -84,14 +137,14 @@ class ModuleMarriage(private val plugin: Ceraia) : CommandExecutor, TabCompleter
return
}
- if (invites.containsKey(sender)) {
- if (invites[sender] == target) {
- accept(sender, target)
+ if (proposals.containsKey(sender)) {
+ if (proposals[sender] == target) {
+ acceptProposal(sender, target)
return
}
}
- invites[target] = sender
+ proposals[target] = sender
plugin.server.sendMessage(MiniMessage.miniMessage().deserialize(
"${sender.name} has invited ${target.name} to marry them!"
))
@@ -100,7 +153,7 @@ class ModuleMarriage(private val plugin: Ceraia) : CommandExecutor, TabCompleter
))
}
- fun accept(target: Player, sender: Player) {
+ private fun acceptProposal(target: Player, sender: Player) {
val senderCeraiaPlayer = plugin.playerManager.getCeraiaPlayer(sender.uniqueId)
val targetCeraiaPlayer = plugin.playerManager.getCeraiaPlayer(target.uniqueId)
@@ -114,7 +167,7 @@ class ModuleMarriage(private val plugin: Ceraia) : CommandExecutor, TabCompleter
target.sendMessage(MiniMessage.miniMessage().deserialize("You are already married!"))
return
}
- if (invites[target] != sender) {
+ if (proposals[target] != sender) {
return
}
@@ -124,45 +177,24 @@ class ModuleMarriage(private val plugin: Ceraia) : CommandExecutor, TabCompleter
targetCeraiaPlayer.marry(sender.name)
senderCeraiaPlayer.marry(target.name)
- invites.remove(target)
- }
-
- fun decline(target: Player, sender: Player): Int {
- val senderCeraiaPlayer = plugin.playerManager.getCeraiaPlayer(sender.uniqueId)
- val targetCeraiaPlayer = plugin.playerManager.getCeraiaPlayer(target.uniqueId)
-
- if (senderCeraiaPlayer.isMarried()) {
- return 1
- }
- if (targetCeraiaPlayer.isMarried()) {
- return 2
- }
- if (invites[target] != sender) {
- return 3
- }
-
- plugin.server.sendMessage(MiniMessage.miniMessage().deserialize(
- "${target.name} has declined ${sender.name}'s marriage proposal!"
- ))
- invites.remove(target)
- return 4
+ proposals.remove(target)
}
- fun divorce(player: Player) {
- val doublePlayer = plugin.playerManager.getCeraiaPlayer(player.uniqueId)
- val doublePartner = plugin.playerManager.getCeraiaPlayer(doublePlayer.getPartner() ?: return)
+ private fun divorce(player: Player) {
+ val ceraiaPlayer = plugin.playerManager.getCeraiaPlayer(player.uniqueId)
+ val ceraiaPartner = plugin.playerManager.getCeraiaPlayer(ceraiaPlayer.getPartner() ?: return)
- doublePlayer.divorce()
- doublePartner.divorce()
+ ceraiaPlayer.divorce()
+ ceraiaPartner.divorce()
plugin.server.sendMessage(MiniMessage.miniMessage().deserialize(
- "${player.name} has divorced ${doublePartner.name}."
+ "${player.name} has divorced ${ceraiaPartner.name}."
))
}
@EventHandler
fun onPlayerQuit(event: PlayerQuitEvent) {
- invites.remove(event.player)
+ proposals.remove(event.player)
}
@EventHandler
@@ -170,8 +202,8 @@ class ModuleMarriage(private val plugin: Ceraia) : CommandExecutor, TabCompleter
val rightClicked = event.rightClicked as? Player ?: return
if (event.player.uniqueId == rightClicked.uniqueId || !event.player.isSneaking) return
- val doublePlayer = plugin.playerManager.getCeraiaPlayer(event.player.uniqueId)
- if (doublePlayer.isMarried() && rightClicked.name == doublePlayer.getMarriedName()) {
+ val ceraiaPlayer = plugin.playerManager.getCeraiaPlayer(event.player.uniqueId)
+ if (ceraiaPlayer.isMarried() && rightClicked.name == ceraiaPlayer.getMarriedName()) {
// Spawn a bunch of hearts
spawnHeartsAroundPlayer(rightClicked)
spawnHeartsAroundPlayer(event.player)
@@ -186,16 +218,12 @@ class ModuleMarriage(private val plugin: Ceraia) : CommandExecutor, TabCompleter
repeat(heartsToSpawn) {
val angle = Math.random() * Math.PI * 2
val radius = 0.5
- val x = playerLocation.x + Math.cos(angle) * radius
+ val x = playerLocation.x + cos(angle) * radius
val y = playerLocation.y + (Math.random() * 0.3) + 1.5
- val z = playerLocation.z + Math.sin(angle) * radius
+ val z = playerLocation.z + sin(angle) * radius
val particleLocation = Location(world, x, y, z)
world.spawnParticle(Particle.HEART, particleLocation, 1)
}
}
-
- fun getRequests(player: Player): Collection {
- return invites.filter { it.value == player }.keys.map { it.name }
- }
}
diff --git a/src/main/java/com/ceraia/modules/races/ModuleRaces.kt b/src/main/java/com/ceraia/modules/RaceModule.kt
similarity index 98%
rename from src/main/java/com/ceraia/modules/races/ModuleRaces.kt
rename to src/main/java/com/ceraia/modules/RaceModule.kt
index d216883..5f3c013 100644
--- a/src/main/java/com/ceraia/modules/races/ModuleRaces.kt
+++ b/src/main/java/com/ceraia/modules/RaceModule.kt
@@ -1,4 +1,4 @@
-package com.ceraia.modules.races
+package com.ceraia.modules
import dev.triumphteam.gui.builder.item.ItemBuilder
import dev.triumphteam.gui.guis.Gui
@@ -21,7 +21,7 @@ import org.bukkit.util.StringUtil
import java.io.File
import java.util.*
-class ModuleRaces(private val plugin: com.ceraia.Ceraia) : CommandExecutor, TabCompleter, Listener {
+class RaceModule(private val plugin: com.ceraia.Ceraia) : CommandExecutor, TabCompleter, Listener {
private var races: MutableList = ArrayList()
private var raceFactions: MutableList = ArrayList()
@@ -52,7 +52,7 @@ class ModuleRaces(private val plugin: com.ceraia.Ceraia) : CommandExecutor, TabC
when (args[0]) {
"reload" -> {
- if (!sender.hasPermission("double.races.reload")) {
+ if (!sender.hasPermission("ceraia.races.reload")) {
plugin.noPermission(sender)
return true
}
@@ -62,7 +62,7 @@ class ModuleRaces(private val plugin: com.ceraia.Ceraia) : CommandExecutor, TabC
}
"become" -> {
- if (!sender.hasPermission("double.races.become")) {
+ if (!sender.hasPermission("ceraia.races.become")) {
plugin.noPermission(sender)
return true
}
@@ -89,8 +89,8 @@ class ModuleRaces(private val plugin: com.ceraia.Ceraia) : CommandExecutor, TabC
sender.sendMessage(MiniMessage.miniMessage().deserialize("Race not found!"))
return true
} else {
- if (!sender.hasPermission("double.races.become." + args[1]) &&
- !sender.hasPermission("double.races.become.*")
+ if (!sender.hasPermission("ceraia.races.become." + args[1]) &&
+ !sender.hasPermission("ceraia.races.become.*")
) {
sender.sendMessage(
MiniMessage.miniMessage().deserialize("You do not have permission to become this race")
@@ -109,7 +109,7 @@ class ModuleRaces(private val plugin: com.ceraia.Ceraia) : CommandExecutor, TabC
"gui" -> openFactionGui(sender)
"restore" -> {
- if (!sender.hasPermission("double.races.restore")) {
+ if (!sender.hasPermission("ceraia.races.restore")) {
plugin.noPermission(sender)
return true
}
@@ -543,8 +543,8 @@ class ModuleRaces(private val plugin: com.ceraia.Ceraia) : CommandExecutor, TabC
val selectable: MutableList = ArrayList()
for (race in races) {
- if ((player.hasPermission("double.races.become." + race.name) ||
- player.hasPermission("double.races.become.*")) &&
+ if ((player.hasPermission("ceraia.races.become." + race.name) ||
+ player.hasPermission("ceraia.races.become.*")) &&
(faction.getRaceInhabitants().contains(race.name)
|| faction.getRaceInhabitants().contains("*"))
) selectable.add(race)
diff --git a/src/main/java/com/ceraia/modules/ModuleSeating.kt b/src/main/java/com/ceraia/modules/SeatingModule.kt
similarity index 97%
rename from src/main/java/com/ceraia/modules/ModuleSeating.kt
rename to src/main/java/com/ceraia/modules/SeatingModule.kt
index 1149116..fac3582 100644
--- a/src/main/java/com/ceraia/modules/ModuleSeating.kt
+++ b/src/main/java/com/ceraia/modules/SeatingModule.kt
@@ -18,7 +18,7 @@ import org.bukkit.event.Listener
import org.bukkit.event.player.PlayerInteractEvent
import org.jetbrains.annotations.NotNull
-class ModuleSeating(private val plugin: Ceraia) : CommandExecutor, TabCompleter, Listener {
+class SeatingModule(private val plugin: Ceraia) : CommandExecutor, TabCompleter, Listener {
val chairs: MutableList = mutableListOf()
@@ -76,7 +76,7 @@ class ModuleSeating(private val plugin: Ceraia) : CommandExecutor, TabCompleter,
if (sender !is Player) {
return true
}
- if (!sender.hasPermission("double.sit")) {
+ if (!sender.hasPermission("ceraia.sit")) {
plugin.noPermission(sender)
return true
}
diff --git a/src/main/java/com/ceraia/modules/system/ModuleSystem.kt b/src/main/java/com/ceraia/modules/SystemModule.kt
similarity index 81%
rename from src/main/java/com/ceraia/modules/system/ModuleSystem.kt
rename to src/main/java/com/ceraia/modules/SystemModule.kt
index df0e936..b051ad2 100644
--- a/src/main/java/com/ceraia/modules/system/ModuleSystem.kt
+++ b/src/main/java/com/ceraia/modules/SystemModule.kt
@@ -1,4 +1,4 @@
-package com.ceraia.modules.system
+package com.ceraia.modules
import com.ceraia.Ceraia
import net.kyori.adventure.text.minimessage.MiniMessage
@@ -11,7 +11,7 @@ import org.bukkit.entity.Player
import org.bukkit.event.Listener
import org.bukkit.util.StringUtil
-class ModuleSystem(private val plugin: Ceraia) : CommandExecutor, TabCompleter, Listener {
+class SystemModule(private val plugin: Ceraia) : CommandExecutor, TabCompleter, Listener {
init {
// Register the commands
@@ -39,14 +39,14 @@ class ModuleSystem(private val plugin: Ceraia) : CommandExecutor, TabCompleter,
"version" -> {
sender.sendMessage(
MiniMessage.miniMessage().deserialize(
- "Running Ceraia v${plugin.pluginMeta.version} by Axodouble"
+ "Running Ceraia v${plugin.pluginMeta.version} by Axoceraia"
)
)
return true
}
"day", "noon" -> {
- if (!sender.hasPermission("double.time.day") &&
- !sender.hasPermission("double.time.*")
+ if (!sender.hasPermission("ceraia.time.day") &&
+ !sender.hasPermission("ceraia.time.*")
) {
plugin.noPermission(sender as Player)
return true
@@ -60,8 +60,8 @@ class ModuleSystem(private val plugin: Ceraia) : CommandExecutor, TabCompleter,
return true
}
"night" -> {
- if (!sender.hasPermission("double.time.night") &&
- !sender.hasPermission("double.time.*")
+ if (!sender.hasPermission("ceraia.time.night") &&
+ !sender.hasPermission("ceraia.time.*")
) {
plugin.noPermission(sender as Player)
return true
@@ -72,7 +72,7 @@ class ModuleSystem(private val plugin: Ceraia) : CommandExecutor, TabCompleter,
return true
}
"discord" -> {
- if (!sender.hasPermission("double.discord")) {
+ if (!sender.hasPermission("ceraia.discord")) {
plugin.noPermission(sender as Player)
return true
}
@@ -104,7 +104,7 @@ class ModuleSystem(private val plugin: Ceraia) : CommandExecutor, TabCompleter,
}
private fun jump(player: Player) {
- if (!player.hasPermission("double.jump")) {
+ if (!player.hasPermission("ceraia.jump")) {
plugin.noPermission(player)
return
}
@@ -126,18 +126,4 @@ class ModuleSystem(private val plugin: Ceraia) : CommandExecutor, TabCompleter,
}
}
}
-
- private fun modHelp(sender: CommandSender) {
- sender.sendMessage(
- MiniMessage.miniMessage().deserialize(
- """
- Mod Help
- /mod ban pvp
- /mod ban arenas
- /mod remove pvp
- /mod remove arenas
- """.trimIndent()
- )
- )
- }
}
\ No newline at end of file
diff --git a/src/main/java/com/ceraia/modules/arenas/Arena.kt b/src/main/java/com/ceraia/modules/arenas/Arena.kt
deleted file mode 100644
index 6fb9b73..0000000
--- a/src/main/java/com/ceraia/modules/arenas/Arena.kt
+++ /dev/null
@@ -1,89 +0,0 @@
-package com.ceraia.modules.arenas
-
-import com.ceraia.Ceraia
-import org.bukkit.Location
-import org.bukkit.Material
-import org.bukkit.World
-import org.bukkit.entity.Player
-import java.util.UUID
-
-class Arena private constructor(
- private val plugin: Ceraia,
- private val name: String,
- private val owner: UUID,
- private val breaking: Boolean,
- private val spawnpoints: List,
-) {
- private val players: MutableMap = mutableMapOf()
- private val placedBlocks: MutableList = mutableListOf()
- private val brokenBlocks: MutableList = mutableListOf()
- private val state: ArenaState = ArenaState.READY
- private val world: World = spawnpoints[0].world
-
- fun getPlugin(): Ceraia { return this.plugin }
-
- fun getName(): String { return this.name }
-
- fun getOwner(): UUID { return this.owner }
-
- fun getSpawnpoints(): List { return this.spawnpoints }
-
- fun breakingAllowed(): Boolean { return this.breaking }
-
- fun getPlayers(): MutableMap { return this.players }
-
- fun getPlacedBlocks(): MutableList { return this.placedBlocks }
-
- fun getBrokenBlocks(): MutableList { return this.brokenBlocks }
-
- fun getState(): ArenaState { return this.state }
-
- fun addPlayer(player: Player, location: Location) {
- this.players[player] = location
- }
-
- fun removePlayer(player: Player) {
- this.players.remove(player)
- }
-
- fun addPlacedBlock(location: Location) {
- this.placedBlocks.add(location)
- }
-
- fun removePlacedBlocks() {
- this.placedBlocks.forEach {
- block -> block.block.type = Material.AIR
- }
- this.placedBlocks.clear()
- }
-
- class Builder {
- private lateinit var plugin: Ceraia
- private lateinit var name: String
- private lateinit var owner: UUID
- private var breaking: Boolean = false // Default to false
- private lateinit var spawnpoints: List
-
- fun plugin(plugin: Ceraia) = apply { this.plugin = plugin }
- fun name(name: String) = apply { this.name = name }
- fun owner(owner: UUID) = apply { this.owner = owner }
- fun breaking(breaking: Boolean) = apply { this.breaking = breaking }
- fun spawnpoints(spawnpoints: List) = apply { this.spawnpoints = spawnpoints }
-
- fun loadBuilder(): Arena {
- return Arena(plugin, name, owner, breaking, spawnpoints)
- }
- }
-
- companion object {
- fun builder() = Builder()
- }
-
- enum class ArenaState {
- READY,
- STARTING,
- INGAME,
- ENDING,
- ENDLESS
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/ceraia/modules/arenas/ArenaCommands.kt b/src/main/java/com/ceraia/modules/arenas/ArenaCommands.kt
deleted file mode 100644
index d7286d6..0000000
--- a/src/main/java/com/ceraia/modules/arenas/ArenaCommands.kt
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.ceraia.modules.arenas
-
-import com.ceraia.Ceraia
-import com.mojang.brigadier.CommandDispatcher
-import com.mojang.brigadier.arguments.StringArgumentType
-import com.mojang.brigadier.builder.LiteralArgumentBuilder
-import com.mojang.brigadier.builder.RequiredArgumentBuilder
-import com.mojang.brigadier.context.CommandContext
-import com.mojang.brigadier.exceptions.CommandSyntaxException
-import org.bukkit.command.Command
-import org.bukkit.command.CommandSender
-import org.bukkit.event.Listener
-
-class ArenaCommands(plugin: Ceraia) : Listener {
- private val plugin: Ceraia = plugin
- private val dispatcher: CommandDispatcher = CommandDispatcher()
-
- init {
- registerCommands()
- }
-
- private fun registerCommands() {
- dispatcher.register(
- LiteralArgumentBuilder.literal("arena")
- .then(
- LiteralArgumentBuilder.literal("create")
- .then(
- RequiredArgumentBuilder.argument("name", StringArgumentType.string())
- .executes { context: CommandContext -> createArena(context) }
- )
- )
- .then(
- LiteralArgumentBuilder.literal("delete")
- .then(
- RequiredArgumentBuilder.argument("name", StringArgumentType.string())
- .executes { context: CommandContext -> deleteArena(context) }
- )
- )
- )
- }
-
- private fun createArena(context: CommandContext): Int {
- val sender = context.source
- val name = StringArgumentType.getString(context, "name")
-
- sender.sendMessage("Arena $name created.")
- return 1
- }
-
- private fun deleteArena(context: CommandContext): Int {
- val sender = context.source
- val name = StringArgumentType.getString(context, "name")
-
- sender.sendMessage("Arena $name deleted.")
- return 1
- }
-
- fun onCommand(sender: CommandSender, command: Command, label: String, args: Array?): Boolean {
- try {
- dispatcher.execute(command.name + " " + args?.joinToString(" "), sender)
- } catch (e: CommandSyntaxException) {
- sender.sendMessage("Invalid command syntax.")
- }
- return true
- }
-
- fun onTabComplete(sender: CommandSender, command: Command, alias: String, args: Array?): MutableList? {
-
- return null
- }
-}
\ No newline at end of file
diff --git a/src/main/java/com/ceraia/modules/arenas/ArenaModule.kt b/src/main/java/com/ceraia/modules/arenas/ArenaModule.kt
index b76e157..67896a5 100644
--- a/src/main/java/com/ceraia/modules/arenas/ArenaModule.kt
+++ b/src/main/java/com/ceraia/modules/arenas/ArenaModule.kt
@@ -1,11 +1,79 @@
package com.ceraia.modules.arenas
import com.ceraia.Ceraia
+import com.ceraia.metrics.Metrics
+import com.ceraia.modules.arenas.commands.arena.*
+import com.ceraia.modules.arenas.commands.system.CommandMod
+import com.ceraia.modules.arenas.commands.system.CommandVersion
+import com.ceraia.modules.arenas.listeners.*
+import com.ceraia.modules.arenas.managers.ArenaManager
+import com.ceraia.modules.arenas.managers.EloScoreboardManager
+import com.ceraia.modules.arenas.managers.InviteManager
+import com.ceraia.modules.arenas.types.ArenaSelectGUI
+import com.ceraia.modules.ceraia.managers.PlayerManager
+import java.io.File
+import java.util.*
class ArenaModule(private val plugin: Ceraia) {
+ var arenaManager: ArenaManager? = null
+ private set
+ var inviteManager: InviteManager? = null
+ private set
+ var arenaSelectGUI: ArenaSelectGUI? = null
+ private set
+ var groupManager: CommandGVG? = null
+ private set
+ var playerManager: PlayerManager? = null
+ private set
+ var metrics: Metrics? = null
+ private var eloScoreBoardManager: EloScoreboardManager? = null
init {
- val arenaCommands = ArenaCommands(plugin)
- plugin.getCommand("arena")?.setExecutor(arenaCommands::onCommand)
- plugin.getCommand("arena")?.setTabCompleter(arenaCommands::onTabComplete)
+ File(plugin.dataFolder, "data/arena").mkdirs()
+ File(plugin.dataFolder, "data/arena/arenas").mkdirs()
+ File(plugin.dataFolder, "data/arena/items").mkdirs()
+
+ // Managers
+ this.arenaManager = ArenaManager(plugin)
+ this.playerManager = PlayerManager(plugin)
+ this.eloScoreBoardManager = EloScoreboardManager(plugin)
+ this.inviteManager = InviteManager()
+
+ this.arenaSelectGUI = ArenaSelectGUI(plugin)
+ this.groupManager = CommandGVG(plugin)
+
+ // Command
+ val commandPVP = CommandPVP(plugin)
+ val commandArena = CommandArena(plugin)
+ val commandMod = CommandMod(plugin)
+ val commandTop = CommandTop(plugin)
+ val commandProfile = CommandProfile(plugin)
+ val commandVersion = CommandVersion(plugin)
+
+ // Listeners
+ PlayerEloChangeListener(plugin)
+ ArenaFightListener(plugin)
+ PlayerInventoryListener(plugin)
+ ArenaBlockListener(plugin)
+ ArenaExplodeListener(plugin)
+
+ // PvP Commands
+ Objects.requireNonNull(plugin.getCommand("pvp"))?.setExecutor(commandPVP)
+ Objects.requireNonNull(plugin.getCommand("arena"))?.setExecutor(commandArena)
+ Objects.requireNonNull(plugin.getCommand("gvg"))?.setExecutor(groupManager)
+ Objects.requireNonNull(plugin.getCommand("top"))?.setExecutor(commandTop)
+ Objects.requireNonNull(plugin.getCommand("leaderboard"))?.setExecutor(commandTop)
+ Objects.requireNonNull(plugin.getCommand("profile"))?.setExecutor(commandProfile)
+ Objects.requireNonNull(plugin.getCommand("stats"))?.setExecutor(commandProfile)
+ }
+
+ fun calculateWinChance(player1: UUID, player2: UUID): Double {
+ val elo1 = playerManager?.getPlayer(player1)?.elo
+ val elo2 = playerManager?.getPlayer(player2)?.elo
+
+ if ((elo1 == 0 || elo1 == null) || (elo2 == 0 || elo2 == null)) {
+ return 0.5
+ }
+
+ return 1 / (1 + Math.pow(10.0, (elo2 - elo1) / 400.0))
}
}
\ No newline at end of file
diff --git a/src/main/java/com/ceraia/modules/arenas/Utils.kt b/src/main/java/com/ceraia/modules/arenas/Utils.kt
new file mode 100644
index 0000000..0a254ce
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/Utils.kt
@@ -0,0 +1,66 @@
+package com.ceraia.modules.arenas
+
+import com.ceraia.Ceraia
+import com.ceraia.modules.arenas.types.Arena
+import org.bukkit.Bukkit
+import org.bukkit.Location
+import org.bukkit.configuration.file.FileConfiguration
+import org.bukkit.configuration.file.YamlConfiguration
+import org.bukkit.entity.Player
+import org.bukkit.inventory.ItemStack
+import java.io.File
+import java.util.*
+
+object Utils {
+ @JvmStatic
+ fun revertInventory(plugin: Ceraia, pl: Player, arena: Arena) {
+ try {
+ val file = File(plugin.dataFolder, "data/pinventory_" + arena.name + "_" + pl.name + ".yml")
+
+ val config: FileConfiguration = YamlConfiguration.loadConfiguration(file)
+
+ val content = arrayOfNulls(pl.inventory.contents.size)
+ try {
+ for (s in Objects.requireNonNull(config.getConfigurationSection("items"))?.getKeys(false)!!) {
+ val i = s.toInt()
+ content[i] = config.getItemStack("items.$s")
+ }
+ } catch (e: Exception) {
+ println("Problem loading player inventories.")
+ }
+
+ pl.inventory.contents = content
+
+ file.delete()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ println("Problem loading player inventory")
+ }
+ }
+
+ @JvmStatic
+ fun teleportPlayerToSpawn(plugin: Ceraia, player: Player, arena: Arena) {
+ val useLocation = checkNotNull(plugin.config.getString("spawn_teleport.use"))
+ if (useLocation.equals("command", ignoreCase = true)) {
+ Objects.requireNonNull(plugin.config.getString("spawn_teleport.command"))?.let {
+ Bukkit.dispatchCommand(
+ Bukkit.getConsoleSender(),
+ it
+ .replace("%player%", player.name)
+ )
+ }
+ } else if (useLocation.equals("prior", ignoreCase = true)) {
+ val l = arena.getPlayerPriorLocation(player)
+ player.teleport(l)
+ } else {
+ val l = Location(
+ Objects.requireNonNull(plugin.config.getString("spawn_teleport.location.world"))
+ ?.let { Bukkit.getWorld(it) },
+ plugin.config.getDouble("spawn_teleport.location.x"),
+ plugin.config.getDouble("spawn_teleport.location.y"),
+ plugin.config.getDouble("spawn_teleport.location.z")
+ )
+ player.teleport(l)
+ }
+ }
+}
diff --git a/src/main/java/com/ceraia/modules/arenas/commands/arena/CommandArena.java b/src/main/java/com/ceraia/modules/arenas/commands/arena/CommandArena.java
new file mode 100644
index 0000000..707ddc1
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/commands/arena/CommandArena.java
@@ -0,0 +1,329 @@
+package com.ceraia.modules.arenas.commands.arena;
+
+import com.ceraia.Ceraia;
+import com.ceraia.modules.arenas.types.Arena;
+import com.ceraia.modules.ceraia.types.CeraiaPlayer;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+public class CommandArena implements CommandExecutor, TabCompleter {
+
+ private final Ceraia plugin;
+
+ public CommandArena(Ceraia plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) {
+ if(!sender.hasPermission("xdbl.arena")){
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.no_permission")));
+ return true;
+ }
+
+ if (args.length == 0) {
+ arenaHelp(sender);
+ return true;
+ }
+
+ if (args[0].equalsIgnoreCase("list")) {
+ arenaList(sender);
+ return true;
+ }
+
+ if (args[0].equalsIgnoreCase("scoreboard") || args[0].equalsIgnoreCase("top")) {
+ Player p = (Player) sender;
+
+ // Create and show a string list of the top 10 players with the highest elo
+ List top = new ArrayList<>();
+ AtomicInteger i = new AtomicInteger();
+ i.set(1);
+
+ top.add(MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.scoreboard.top")));
+
+ plugin.getPlayerManager().getCeraiaPlayers().stream().sorted(Comparator.comparingInt(CeraiaPlayer::getElo).reversed()).limit(10).forEach(ap -> {
+ String playerName = Bukkit.getOfflinePlayer(ap.getUUID()).getName();
+ int elo = ap.getElo();
+
+ String medal; // Default medal color for players outside the top 3
+
+ // Check for 1st, 2nd, and 3rd place
+ if (i.get() == 1) {
+ medal = ""; // Gold for 1st place
+ } else if (i.get() == 2) {
+ medal = "<#C0C0C0>"; // Silver for 2nd place
+ } else if (i.get() == 3) {
+ medal = "<#cd7f32>"; // Bronze for 3rd place
+ } else {
+ medal = ""; // Default medal color for players outside the top 3
+ }
+
+ top.add(MiniMessage.miniMessage().deserialize(medal + i + " " + playerName + " - " + elo + " ELO (" + (ap.getWins() + ap.getLosses()) + " games)"));
+ i.getAndIncrement();
+ });
+
+ // Send the top 10 players with the highest elo to the player
+ top.forEach(p::sendMessage);
+
+ return true;
+ }
+
+ if (args[0].equalsIgnoreCase("delete")) {
+ arenaDelete(sender, args);
+ return true;
+ }
+ if (args[0].equalsIgnoreCase("create")) {
+ arenaCreate(sender, args);
+ return true;
+ }
+ if (args[0].equalsIgnoreCase("sp1")) {
+ arenaSP1(sender, args);
+ return true;
+ }
+ if (args[0].equalsIgnoreCase("sp2")) {
+ arenaSP2(sender, args);
+ return true;
+ }
+ if (args[0].equalsIgnoreCase("public")) {
+ arenaPublic(sender, args);
+ return true;
+ }
+ else {
+ badUsage(sender);
+ arenaHelp(sender);
+ return true;
+ }
+ }
+
+ @Override
+ public List onTabComplete(CommandSender sender, Command cmd, String label, String[] args) {
+ List arenas = new ArrayList<>();
+
+ if (args.length == 1) {
+ return Arrays.asList("list", "delete", "public", "create", "sp1", "sp2", "top", "scoreboard");
+ } else if (args.length == 2 && (
+ args[0].equalsIgnoreCase("delete") ||
+ args[0].equalsIgnoreCase("public") ||
+ args[0].equalsIgnoreCase("sp1") ||
+ args[0].equalsIgnoreCase("sp2"))) {
+ plugin.getArenaModule().getArenaManager().getArenas().forEach(a ->{
+ if (a.getOwner().equals(sender.getName())) {
+ arenas.add(a.getName());
+ }
+ });
+ return arenas;
+ } else if (args.length == 2 && args[0].equalsIgnoreCase("create")) {
+ return Arrays.asList("");
+ } else if ((args.length == 3 && args[0].equalsIgnoreCase("public"))) {
+ return Arrays.asList("true", "false");
+ }
+ return new ArrayList<>();
+ }
+
+ private void arenaSP1(CommandSender sender, String[] args) {
+ if (args.length == 1) {
+ badUsage(sender);
+ return;
+ }
+
+ String name = args[1];
+
+ Arena arena = plugin.getArenaModule().getArenaManager().getArena(name);
+ if (arena == null) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.arena.not_found"))
+ );
+ return;
+ }
+ if (!Objects.equals(arena.getOwner(), sender.getName())) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.arena.not_yours"))
+ );
+ return;
+ }
+ arena.setSpawnPoint1(((Player) sender).getLocation());
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.arena.sp1.success"))
+ );
+ }
+
+ private void arenaSP2(CommandSender sender, String[] args) {
+ if (args.length == 1) {
+ badUsage(sender);
+ return;
+ }
+
+ String name = args[1];
+
+ Arena arena = plugin.getArenaModule().getArenaManager().getArena(name);
+ if (arena == null) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.arena.not_found"))
+ );
+ return;
+ }
+
+ if (!Objects.equals(arena.getOwner(), sender.getName())) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.arena.not_yours"))
+ );
+ return;
+ }
+ arena.setSpawnPoint2(((Player) sender).getLocation());
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.arena.sp2.success"))
+ );
+ }
+
+ private void arenaCreate(CommandSender sender, String[] args) {
+ if (args.length == 1) {
+ badUsage(sender);
+ return;
+ }
+
+ String name = args[1];
+
+ // Check if the string is the same as , if so state the user should put a name
+ if (name.equalsIgnoreCase("")) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.arena.create.no_name"))
+ );
+ return;
+ }
+ // Check if the string is alphanumeric
+ if (!name.matches("[a-zA-Z0-9]*")) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.arena.create.alphanumeric"))
+ );
+ return;
+ }
+
+ // Check if the arena already exists
+ if (plugin.getArenaModule().getArenaManager().getArenas().stream().filter(a -> a.getName().equalsIgnoreCase(name)).count() > 0) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.arena.create.exists"))
+ );
+ return;
+ }
+
+ File file = new File(plugin.getDataFolder(), "data/arenas/" + name + ".yml");
+
+ Arena arena = new Arena(plugin, name, sender.getName(), ((Player) sender).getLocation(), ((Player) sender).getLocation(), false, false, file);
+
+ arena.setSpawnPoint1(((Player) sender).getLocation());
+ arena.setSpawnPoint2(((Player) sender).getLocation());
+
+ plugin.getArenaModule().getArenaManager().addArena(arena);
+
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.arena.create.success"))
+ );
+ }
+
+ private void arenaDelete(CommandSender sender, String[] args) {
+ if (args.length == 1) {
+ badUsage(sender);
+ return;
+ }
+
+ String name = args[1];
+ Arena arena = plugin.getArenaModule().getArenaManager().getArena(name);
+ if (arena == null) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.arena.not_found"))
+ );
+ return;
+ }
+ if (!arena.getOwner().equals(sender.getName())) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.arena.not_yours"))
+ );
+ return;
+ }
+ if (arena.getState() != Arena.ArenaState.WAITING) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.arena.delete.running"))
+ );
+ return;
+ }
+
+ arena.delete();
+ plugin.getArenaModule().getArenaManager().removeArena(arena);
+
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.arena.delete.delete"))
+ );
+ }
+
+ private void arenaPublic(CommandSender sender, String[] args) {
+ if (args.length == 1) {
+ badUsage(sender);
+ return;
+ }
+
+ String name = args[1];
+ Arena arena = plugin.getArenaModule().getArenaManager().getArena(name);
+ if (arena == null) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.arena.not_found"))
+ );
+ return;
+ }
+ if (!arena.getOwner().equals(sender.getName())) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.arena.not_yours"))
+ );
+ return;
+ }
+
+ boolean isPublic = arena.isPublic();
+
+ if (isPublic) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.arena.public_command.success_private"))
+ );
+ } else {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.arena.public_command.success_public"))
+ );
+ }
+
+ arena.setPublic(!isPublic);
+ }
+
+ private void badUsage(CommandSender sender) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.bad_usage")));
+ }
+
+ private void arenaList(CommandSender sender) {
+ List arenas = plugin.getArenaModule().getArenaManager().getArenas().stream().filter(arena -> arena.getOwner().equals(sender.getName())).collect(Collectors.toList());
+ plugin.getConfig().getStringList("messages.arena.list").forEach(s -> {
+ if (s.contains("%arenas%")) {
+ arenas.forEach(a -> {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(s.replace("%arenas%", a.getName()) +
+ (a.getSpawnPoint1() != null ? " (" + a.getSpawnPoint1().getBlockX() + ", " + a.getSpawnPoint1().getBlockY() + ", " + a.getSpawnPoint1().getBlockZ() + ")" : "")));
+ });
+ } else {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(s));
+ }
+ });
+ }
+
+ private void arenaHelp(CommandSender sender) {
+ plugin.getConfig().getStringList("messages.arena.help").forEach(s -> {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(s));
+ });
+ }
+}
diff --git a/src/main/java/com/ceraia/modules/arenas/commands/arena/CommandGVG.java b/src/main/java/com/ceraia/modules/arenas/commands/arena/CommandGVG.java
new file mode 100644
index 0000000..736d929
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/commands/arena/CommandGVG.java
@@ -0,0 +1,278 @@
+package com.ceraia.modules.arenas.commands.arena;
+
+import com.ceraia.Ceraia;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class CommandGVG implements CommandExecutor, TabCompleter, Listener {
+
+ private final Ceraia plugin;
+ private final Map> groups = new HashMap<>();
+ private final Map playersByGroup = new HashMap<>();
+
+ private final Map invites = new HashMap<>();
+
+ public CommandGVG(Ceraia plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) {
+ if(!sender.hasPermission("xdbl.gvg")){
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.no_permission"))));
+ return true;
+ }
+
+ if (args.length == 0) {
+ plugin.getConfig().getStringList("messages.gvg.help").forEach(s -> sender.sendMessage(MiniMessage.miniMessage().deserialize(s)));
+ return true;
+ }
+
+ Player player = (Player) sender;
+
+ if (args[0].equalsIgnoreCase("invite")) {
+ if (playersByGroup.containsKey(player) && !groups.containsKey(player)) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.dont_have_group"))));
+ return true;
+ }
+
+ if (args.length == 1) {
+ badUsage(sender);
+ return true;
+ }
+
+ List targets = new ArrayList<>();
+ List notOnline = new ArrayList<>();
+
+ for (int i = 1; i < args.length; i++) {
+ Player target = Bukkit.getPlayer(args[i]);
+ if (target == null) {
+ notOnline.add(args[i]);
+ } else {
+ targets.add(target);
+ }
+
+ if (playersByGroup.containsKey(target)) {
+ assert target != null;
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.invite.already_in_group"))
+ .replace("%player%", target.getName())));
+ return true;
+ }
+ }
+
+ if (targets.contains(player)) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.invite.cant_invite_yourself"))));
+ return true;
+ }
+
+ if (notOnline.size() > 0) {
+ System.out.println(notOnline);
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.player_offline"))
+ .replace("%player%", String.join(", ", notOnline))));
+ return true;
+ }
+
+ for (Player target : targets) {
+ Component message = Objects.requireNonNull(
+ MiniMessage.miniMessage().deserialize(
+ Objects.requireNonNull(
+ plugin.getConfig().getString("messages.gvg.invite.invite_message")
+ ).replace("%inviter%", player.getName()
+ )
+ )
+ );
+ target.sendMessage(message);
+
+ invites.put(target, player);
+ }
+
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.invite.invite_sent"))
+ .replace("%player%", targets.stream().map(Player::getName).collect(Collectors.joining(", ")))));
+ return true;
+ }
+ else if (args[0].equalsIgnoreCase("accept")) {
+ Player inviter = invites.get(player);
+
+ if (inviter == null || !inviter.isOnline()) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.accept.invite_not_found"))));
+ return true;
+ }
+
+ if (playersByGroup.containsKey(inviter) && !groups.containsKey(inviter)) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.accept.invite_not_found"))));
+ return true;
+ }
+
+ if (playersByGroup.containsKey(player)) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.accept.you_already_in_group"))));
+ return true;
+ }
+
+ List group = groups.get(inviter);
+ if (group == null) {
+ group = new ArrayList<>();
+ group.add(inviter);
+ playersByGroup.put(inviter, inviter);
+ }
+ group.add(player);
+ groups.put(inviter, group);
+
+ playersByGroup.put(player, inviter);
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.accept.accepted"))));
+ for (Player pl : group) {
+ pl.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.accept.invite_accepted"))
+ .replace("%player%", player.getName())));
+ }
+ return true;
+ }
+ else if (args[0].equalsIgnoreCase("leave")) {
+ leaveGang(player);
+ }
+ else if (args[0].equalsIgnoreCase("kick")) {
+ if (!groups.containsKey(player)) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.kick.not_in_group"))));
+ return true;
+ }
+
+ if (args.length == 1) {
+ badUsage(sender);
+ return true;
+ }
+
+ Player target = plugin.getServer().getPlayer(args[1]);
+ if (target == null) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.player_offline"))
+ .replace("%player%", args[1])));
+ return true;
+ }
+
+ List group = groups.get(player);
+
+ if (!group.contains(target)) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.kick.player_not_in_group"))));
+ return true;
+ }
+
+ group.remove(target);
+ playersByGroup.remove(target);
+
+ target.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.kick.you_kicked"))));
+
+ if (group.size() <= 1) {
+
+ groups.get(player).forEach(p -> {
+ player.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.you_left"))));
+ playersByGroup.remove(p);
+ groups.remove(player);
+ });
+
+ groups.remove(player);
+ } else {
+ group.forEach(p -> p.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.kicked"))
+ .replace("%player%", target.getName()))));
+ }
+ return true;
+ }
+ else if (args[0].equalsIgnoreCase("fight")) {
+ String playerName = args[1];
+ Player invited = Bukkit.getPlayer(playerName);
+
+ if (invited == null) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.player_offline"))
+ .replace("%player%", playerName)));
+ return true;
+ }
+
+ if (invited == player) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.invite.invite_yourself"))));
+ return true;
+ }
+
+ if (!groups.containsKey(player)) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.not_in_group"))));
+ return true;
+ }
+
+ if (!groups.containsKey(invited) || (groups.get(player).contains(invited) || groups.get(invited).contains(player))) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.player_not_in_group"))));
+ return true;
+ }
+
+ plugin.getArenaModule().getArenaSelectGUI().openArenaList(player, invited);
+ }
+
+ return true;
+ }
+
+ @Override
+ public List onTabComplete(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args){
+ if (args.length == 1) {
+ return Arrays.asList("invite", "accept", "leave", "kick", "fight");
+ }
+ else if (args.length == 2 && args[0].equalsIgnoreCase("kick")) {
+ return getPlayersByGroup((Player) sender).stream().map(Player::getName).collect(Collectors.toList());
+ }
+ else if (args.length == 2 && (args[0].equalsIgnoreCase("invite") ||args[0].equalsIgnoreCase("fight"))) {
+ return Bukkit.getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
+ }
+
+ return new ArrayList<>();
+ }
+
+ private void leaveGang(Player player) {
+ if (!playersByGroup.containsKey(player)) {
+ player.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.not_in_group"))));
+ return;
+ }
+
+ Player owner = playersByGroup.get(player);
+ List group = groups.get(owner);
+
+ if (group != null || group.size() <= 2) {
+ group.forEach(pl -> {
+ pl.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.you_left"))));
+ playersByGroup.remove(pl);
+ });
+
+ groups.remove(owner);
+ } else {
+ group.forEach(p -> player.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.gvg.leave.player_left_group"))
+ .replace("%player%", player.getName()))));
+
+ group.remove(player);
+ groups.put(owner, group);
+
+ playersByGroup.remove(player);
+ }
+ }
+
+ private void badUsage(CommandSender sender) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.bad_usage"))));
+ }
+
+ public List getPlayersByGroup(Player player) {
+ return groups.get(player);
+ }
+
+ @EventHandler
+ public void onQuit(PlayerQuitEvent e) {
+ Player player = e.getPlayer();
+ if (playersByGroup.containsKey(player)) {
+ leaveGang(player);
+ }
+ }
+}
diff --git a/src/main/java/com/ceraia/modules/arenas/commands/arena/CommandPVP.java b/src/main/java/com/ceraia/modules/arenas/commands/arena/CommandPVP.java
new file mode 100644
index 0000000..a06ae8b
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/commands/arena/CommandPVP.java
@@ -0,0 +1,208 @@
+package com.ceraia.modules.arenas.commands.arena;
+
+import com.ceraia.Ceraia;
+import com.ceraia.modules.arenas.managers.InviteManager;
+import com.ceraia.modules.arenas.types.Arena;
+import com.ceraia.modules.ceraia.types.CeraiaPlayer;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+public class CommandPVP implements CommandExecutor, TabCompleter {
+
+ private final Ceraia plugin;
+
+ public CommandPVP(Ceraia plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) {
+ if(!sender.hasPermission("xdbl.pvp")){
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.no_permission"))));
+ return true;
+ }
+
+ if (args.length == 0) {
+ pvpHelp(sender);
+ return true;
+ }
+
+ // Check if the sender is pvpbanned
+ CeraiaPlayer ceraiaPlayer = plugin.getPlayerManager().getCeraiaPlayer(((Player) sender).getUniqueId());
+
+ if (args[0].equalsIgnoreCase("accept")) {
+ Player p = (Player) sender;
+
+ InviteManager.Invite invite = Objects.requireNonNull(plugin.getArenaModule().getInviteManager()).invites.get(p);
+
+ if (invite == null) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.invite_accept.invite_not_found")))
+ );
+ plugin.getArenaModule().getInviteManager().invites.remove(p);
+ return true;
+ }
+
+ if (!invite.invited.isOnline() || !invite.inviter.isOnline()) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.invite_accept.other_player_offline")))
+ );
+ return true;
+ }
+
+ if(invite.accepted){
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.invite_accept.invite_already_accepted")))
+ );
+ return true;
+ }
+
+ if (invite.arena.getState() != Arena.ArenaState.WAITING || plugin.getArenaModule().getArenaManager().getArenas().stream().noneMatch(
+ a -> a.getName().equalsIgnoreCase(invite.arena.getName())
+ )) {
+ for (Player pl : Arrays.asList(invite.invited, invite.inviter)) {
+ pl.sendMessage(
+ MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.invite_accept.arena_not_ready")))
+ );
+ }
+ plugin.getArenaModule().getInviteManager().invites.remove(p);
+ return true;
+ }
+
+ List playersToFight = new ArrayList<>();
+
+ if (invite.group) {
+ List group1 = plugin.getArenaModule().getGroupManager().getPlayersByGroup(invite.inviter);
+ List group2 = plugin.getArenaModule().getGroupManager().getPlayersByGroup(invite.invited);
+
+ if (group1 == null || group2 == null) {
+ for (Player pl : Arrays.asList(invite.invited, invite.inviter)) {
+ pl.sendMessage(
+ MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.invite_accept.group.group_not_found")))
+ );
+ }
+ plugin.getArenaModule().getInviteManager().invites.remove(p);
+ return true;
+ }
+
+ if (group1.size() < 2 || group2.size() < 2) {
+ for (Player pl : Arrays.asList(invite.invited, invite.inviter)) {
+ pl.sendMessage(
+ MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.invite_accept.group.group_too_small")))
+ );
+ }
+ plugin.getArenaModule().getInviteManager().invites.remove(p);
+ return true;
+ }
+
+ boolean allPlayersAreReady = true;
+
+ for (Player pl : group1) {
+ if (plugin.getArenaModule().getArenaManager().getArena(pl) != null) {
+ return true;
+ }
+ }
+
+ for (Player pl : group2) {
+ if (plugin.getArenaModule().getArenaManager().getArena(pl) != null) {
+ return true;
+ }
+ }
+
+ if (!allPlayersAreReady) {
+ for (Player pl : Arrays.asList(invite.invited, invite.inviter)) {
+ pl.sendMessage(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.invite_accept.group.someone_already_in_fight"))
+ );
+ }
+ plugin.getArenaModule().getInviteManager().invites.remove(p);
+ return true;
+ }
+
+ playersToFight.addAll(group1);
+ playersToFight.addAll(group2);
+
+ group1.forEach(pl -> invite.arena.addPlayer(pl, 1));
+ group2.forEach(pl -> invite.arena.addPlayer(pl, 2));
+ } else {
+ playersToFight.add(invite.invited);
+ playersToFight.add(invite.inviter);
+ invite.arena.addPlayer(invite.invited, 1);
+ invite.arena.addPlayer(invite.inviter, 2);
+ }
+
+ // Starting arena
+ invite.accepted = true;
+ invite.arena.start(invite, playersToFight);
+
+ return true;
+ }
+
+ // open gui for invite player
+
+ String playerName = args[0];
+
+ // reload for op
+ if (playerName.equalsIgnoreCase("reload") && sender.isOp()) {
+ plugin.reloadConfig();
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(
+ "Reloaded!")
+ );
+ return true;
+ } // If the player is reload and the sender is op, reload the config
+
+ Player invited = Bukkit.getPlayer(playerName);
+
+ if (invited == null) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.pvp.invite.player_offline")))
+ );
+ return true;
+ } // If the player is offline, return
+
+ Player inviter = (Player) sender;
+
+ if (inviter == invited) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.pvp.invite.invite_self")))
+ );
+ return true;
+ } // If the inviter is the same as the invited, return
+
+ plugin.getArenaModule().getArenaSelectGUI().openArenaList(inviter, invited);
+ return true;
+ }
+
+ @Override
+ public List onTabComplete(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) {
+ if (args.length == 1) {
+ List tabOptions = new ArrayList<>();
+ // If there is an argument, suggest online player names
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ // Exclude the sender's name from the suggestions
+ if (!player.getName().equals(sender.getName())) {
+ tabOptions.add(player.getName());
+ }
+ }
+
+ return tabOptions;
+ }
+ // If there is more than one argument, return an empty list
+ return new ArrayList<>();
+ }
+
+ private void pvpHelp(CommandSender sender) {
+ plugin.getConfig().getStringList("messages.pvp.help").forEach(s -> sender.sendMessage(MiniMessage.miniMessage().deserialize(s)));
+ }
+}
diff --git a/src/main/java/com/ceraia/modules/arenas/commands/arena/CommandProfile.java b/src/main/java/com/ceraia/modules/arenas/commands/arena/CommandProfile.java
new file mode 100644
index 0000000..baed6ba
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/commands/arena/CommandProfile.java
@@ -0,0 +1,70 @@
+package com.ceraia.modules.arenas.commands.arena;
+
+import com.ceraia.Ceraia;
+import com.ceraia.modules.ceraia.types.CeraiaPlayer;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class CommandProfile implements CommandExecutor, TabCompleter {
+
+ private final Ceraia plugin;
+
+ public CommandProfile(Ceraia plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) {
+ if (!sender.hasPermission("xdbl.pvp")) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.no_permission"))));
+ return true;
+ }
+
+ Player player;
+ if (args.length == 1) {
+ player = Bukkit.getPlayer(args[0]);
+ if (player == null) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.bad_usage"))));
+ return true;
+ }
+ } else {
+ player = (Player) sender;
+ }
+
+ // Return the player's profile
+ CeraiaPlayer ceraiaPlayer = plugin.getPlayerManager().getCeraiaPlayer(player.getUniqueId());
+ plugin.getConfig().getStringList("messages.profile").forEach(s -> sender.sendMessage(MiniMessage.miniMessage().deserialize(s
+ .replace("%player%", player.getName())
+ .replace("%elo%", String.valueOf(ceraiaPlayer.getElo()))
+ .replace("%wins%", String.valueOf(ceraiaPlayer.getWins()))
+ .replace("%losses%", String.valueOf(ceraiaPlayer.getLosses()))
+ .replace("%games%", String.valueOf(ceraiaPlayer.getWins() + ceraiaPlayer.getLosses())))));
+
+
+
+ return true;
+ }
+
+ @Override
+ public List onTabComplete(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) {
+ // Return a list of all players
+ if (args.length == 1) {
+ List players = new ArrayList<>();
+ Bukkit.getOnlinePlayers().forEach(p -> players.add(p.getName()));
+ return players;
+ }
+ return new ArrayList<>();
+ }
+
+
+}
diff --git a/src/main/java/com/ceraia/modules/arenas/commands/arena/CommandTop.java b/src/main/java/com/ceraia/modules/arenas/commands/arena/CommandTop.java
new file mode 100644
index 0000000..c64fe25
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/commands/arena/CommandTop.java
@@ -0,0 +1,77 @@
+package com.ceraia.modules.arenas.commands.arena;
+
+import com.ceraia.Ceraia;
+import com.ceraia.modules.ceraia.types.CeraiaPlayer;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class CommandTop implements CommandExecutor, TabCompleter {
+
+ private final Ceraia plugin;
+
+ public CommandTop(Ceraia plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) {
+ if (!sender.hasPermission("xdbl.pvp")) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.no_permission"))));
+ return true;
+ }
+
+ Player p = (Player) sender;
+
+ // Create and show a string list of the top 10 players with the highest elo
+ List top = new ArrayList<>();
+ AtomicInteger i = new AtomicInteger();
+ i.set(1);
+
+ top.add(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.scoreboard.top"))));
+
+ plugin.getPlayerManager().getCeraiaPlayers().stream().sorted(Comparator.comparingInt(CeraiaPlayer::getElo).reversed()).limit(10).forEach(ap -> {
+ String playerName = Bukkit.getOfflinePlayer(ap.getUUID()).getName();
+ int elo = ap.getElo();
+
+ String medal; // Default medal color for players outside the top 3
+
+ // Check for 1st, 2nd, and 3rd place
+ if (i.get() == 1) {
+ medal = ""; // Gold for 1st place
+ } else if (i.get() == 2) {
+ medal = "<#C0C0C0>"; // Silver for 2nd place
+ } else if (i.get() == 3) {
+ medal = "<#cd7f32>"; // Bronze for 3rd place
+ } else {
+ medal = ""; // Default medal color for players outside the top 3
+ }
+
+ top.add(MiniMessage.miniMessage().deserialize(medal + i + " " + playerName + " - " + elo + " ELO (" + (ap.getWins() + ap.getLosses()) + " games)"));
+ i.getAndIncrement();
+ });
+
+ // Send the top 10 players with the highest elo to the player
+ top.forEach(p::sendMessage);
+
+
+ return true;
+ }
+
+ @Override
+ public List onTabComplete(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) {
+ return new ArrayList<>();
+ }
+}
diff --git a/src/main/java/com/ceraia/modules/arenas/commands/system/CommandMod.java b/src/main/java/com/ceraia/modules/arenas/commands/system/CommandMod.java
new file mode 100644
index 0000000..a0adb32
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/commands/system/CommandMod.java
@@ -0,0 +1,97 @@
+package com.ceraia.modules.arenas.commands.system;
+
+import com.ceraia.Ceraia;
+import com.ceraia.modules.ceraia.types.CeraiaPlayer;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class CommandMod implements CommandExecutor, TabCompleter {
+
+ private final Ceraia plugin;
+
+ public CommandMod(Ceraia plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) {
+ if (!sender.hasPermission("xdbl.mod")) {
+ sender.sendMessage(MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.no_permission"))));
+ return true;
+ }
+
+ if (args.length == 0) {
+ ModHelp(sender);
+ return true;
+ }
+
+ if (args.length == 1) {
+ if (args[0].equalsIgnoreCase("ban")) {
+ ModHelp(sender);
+ return true;
+ }
+ }
+
+ if (args.length == 2) {
+ if (args[0].equalsIgnoreCase("ban")) {
+ if (args[1].equalsIgnoreCase("pvp")) {
+ ModHelp(sender);
+ return true;
+ }
+ if (args[1].equalsIgnoreCase("arena")) {
+ ModHelp(sender);
+ return true;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public List onTabComplete(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) {
+ if (args.length == 1) {
+ List tabOptions = new ArrayList<>();
+ tabOptions.add("ban");
+ tabOptions.add("remove");
+ return tabOptions;
+ }
+ if (args.length == 2) {
+ List tabOptions = new ArrayList<>();
+ if (args[1].equalsIgnoreCase("ban")) tabOptions.add("pvp");
+ tabOptions.add("arena");
+ return tabOptions;
+ }
+ if (args.length == 3) {
+ if (args[2].equalsIgnoreCase("pvp")) {
+ List tabOptions = new ArrayList<>();
+ // If there is an argument, suggest online player names
+ for (Player player : Bukkit.getOnlinePlayers()) {
+ tabOptions.add(player.getName());
+ }
+ return tabOptions;
+ }
+ if (args[2].equalsIgnoreCase("arena")) {
+ List tabOptions = new ArrayList<>();
+ // If there is an argument, suggest all arena names
+ Objects.requireNonNull(plugin.getArenaModule().getArenaManager()).getArenas().forEach(arena -> tabOptions.add(arena.getName()));
+ return tabOptions;
+ }
+ }
+ // If there is more than one argument, return an empty list
+ return new ArrayList<>();
+ }
+
+ private void ModHelp(CommandSender sender) {
+ plugin.getConfig().getStringList("messages.mod.help").forEach(s -> sender.sendMessage(MiniMessage.miniMessage().deserialize(s)));
+ }
+}
diff --git a/src/main/java/com/ceraia/modules/arenas/commands/system/CommandVersion.java b/src/main/java/com/ceraia/modules/arenas/commands/system/CommandVersion.java
new file mode 100644
index 0000000..759d2aa
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/commands/system/CommandVersion.java
@@ -0,0 +1,34 @@
+package com.ceraia.modules.arenas.commands.system;
+
+import com.ceraia.Ceraia;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CommandVersion implements CommandExecutor, TabCompleter {
+
+ private final Ceraia plugin;
+
+ public CommandVersion(Ceraia plugin) {
+ this.plugin = plugin;
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) {
+ sender.sendMessage(
+ MiniMessage.miniMessage().deserialize("Running Ceraia v" + plugin.getPluginMeta().getVersion() + " by Axodouble")
+ );
+ return true;
+ }
+
+ @Override
+ public List onTabComplete(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) {
+ return new ArrayList<>();
+ }
+}
diff --git a/src/main/java/com/ceraia/modules/arenas/listeners/ArenaBlockListener.kt b/src/main/java/com/ceraia/modules/arenas/listeners/ArenaBlockListener.kt
new file mode 100644
index 0000000..e2a51c3
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/listeners/ArenaBlockListener.kt
@@ -0,0 +1,33 @@
+package com.ceraia.modules.arenas.listeners
+
+import com.ceraia.Ceraia
+import org.bukkit.Bukkit
+import org.bukkit.event.EventHandler
+import org.bukkit.event.Listener
+import org.bukkit.event.block.BlockBreakEvent
+import org.bukkit.event.block.BlockPlaceEvent
+
+class ArenaBlockListener(private val plugin: Ceraia) : Listener {
+ init {
+ Bukkit.getPluginManager().registerEvents(this, plugin)
+ }
+
+ @EventHandler
+ fun onBlockPlace(e: BlockPlaceEvent) {
+ val arena = plugin.arenaModule.arenaManager!!.getArena(e.player) ?: return
+
+ arena.placeBlock(e.blockPlaced.location)
+ }
+
+ @EventHandler
+ fun onBlockBreak(e: BlockBreakEvent) {
+ val arena = plugin.arenaModule.arenaManager!!.getArena(e.player) ?: return
+
+ if (arena.placedBlocks.contains(e.block.location)) {
+ arena.removeBlock(e.block.location)
+ return
+ }
+
+ e.isCancelled = true
+ }
+}
diff --git a/src/main/java/com/ceraia/modules/arenas/listeners/ArenaExplodeListener.kt b/src/main/java/com/ceraia/modules/arenas/listeners/ArenaExplodeListener.kt
new file mode 100644
index 0000000..804e4b1
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/listeners/ArenaExplodeListener.kt
@@ -0,0 +1,93 @@
+package com.ceraia.modules.arenas.listeners
+
+import com.ceraia.Ceraia
+import org.bukkit.Bukkit
+import org.bukkit.Material
+import org.bukkit.block.data.type.RespawnAnchor
+import org.bukkit.entity.*
+import org.bukkit.event.EventHandler
+import org.bukkit.event.Listener
+import org.bukkit.event.entity.EntityDamageByEntityEvent
+import org.bukkit.event.entity.EntityExplodeEvent
+import org.bukkit.event.player.PlayerInteractEvent
+
+class ArenaExplodeListener(private val plugin: Ceraia) : Listener {
+ init {
+ Bukkit.getPluginManager().registerEvents(this, plugin)
+ }
+
+ private fun isInArena(player: Player): Boolean {
+ return plugin.arenaModule.arenaManager!!.getArena(player) != null
+ }
+
+ // TNT
+ @EventHandler
+ fun onEntityExplode(e: EntityExplodeEvent) {
+ var source: Player? = null
+ if (e.entityType == EntityType.TNT) {
+ val tnt = e.entity as TNTPrimed
+ val entity = tnt.source as? Player ?: return
+ source = entity
+ }
+
+ if (source == null || isInArena(source)) {
+ return
+ }
+ e.blockList().clear()
+ }
+
+ // End crystal
+ @EventHandler
+ fun onHitCrystal(e: EntityDamageByEntityEvent) {
+ val entity = e.entity
+ val damager = e.damager
+
+ val source: Player
+
+ if (entity !is EnderCrystal) return
+
+ if (damager is Player) {
+ source = damager
+ } else if (damager is Arrow) {
+ val entity2 = damager.shooter as Entity? as? Player ?: return
+ source = entity2
+ } else {
+ return
+ }
+
+ if (isInArena(source)) {
+ return
+ }
+
+ e.isCancelled = true
+ if (e.entity.isValid) e.entity.remove()
+ e.entity.world.createExplosion(
+ e.entity.location,
+ 6f,
+ false,
+ false
+ )
+ }
+
+ // Respawn Anchor
+ @EventHandler
+ fun onFillAnchor(e: PlayerInteractEvent) {
+ if (e.clickedBlock == null) return
+ if (e.clickedBlock!!.type != Material.RESPAWN_ANCHOR) return
+
+ val block = e.clickedBlock
+ val data = block!!.blockData as RespawnAnchor
+ if (data.charges < data.maximumCharges) return
+
+ if (isInArena(e.player)) return
+
+ e.isCancelled = true
+ block.type = Material.AIR
+ block.world.createExplosion(
+ block.location,
+ 5f,
+ false,
+ false
+ )
+ }
+}
diff --git a/src/main/java/com/ceraia/modules/arenas/listeners/ArenaFightListener.kt b/src/main/java/com/ceraia/modules/arenas/listeners/ArenaFightListener.kt
new file mode 100644
index 0000000..90f333e
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/listeners/ArenaFightListener.kt
@@ -0,0 +1,184 @@
+package com.ceraia.modules.arenas.listeners
+
+import com.ceraia.Ceraia
+import com.ceraia.modules.arenas.types.Arena
+import net.kyori.adventure.text.minimessage.MiniMessage
+import org.bukkit.Bukkit
+import org.bukkit.Material
+import org.bukkit.entity.*
+import org.bukkit.event.EventHandler
+import org.bukkit.event.Listener
+import org.bukkit.event.entity.EntityDamageByEntityEvent
+import org.bukkit.event.entity.EntityDamageEvent
+import org.bukkit.event.entity.PlayerDeathEvent
+import org.bukkit.event.player.PlayerQuitEvent
+import org.bukkit.scheduler.BukkitRunnable
+import java.util.*
+
+class ArenaFightListener(private val plugin: Ceraia) : Listener {
+ init {
+ Bukkit.getPluginManager().registerEvents(this, plugin)
+ }
+
+ private fun isInArena(player: Player): Boolean {
+ return plugin.arenaModule.arenaManager?.getArena(player) != null
+ }
+
+ @EventHandler
+ fun onHit(e: EntityDamageByEntityEvent) {
+ val damager = e.damager as? Player ?: return
+ val player = e.entity as? Player ?: return
+
+ if (!isInArena(damager) && !isInArena(player)) {
+ return
+ }
+
+ if (((isInArena(damager) && !isInArena(player)) || (!isInArena(damager) && isInArena(player))) || plugin.arenaModule.arenaManager?.getArena(
+ damager
+ )?.name != plugin.arenaModule.arenaManager?.getArena(player)?.name
+ ) {
+ e.isCancelled = true
+ return
+ }
+
+ val arena: Arena = plugin.arenaModule.arenaManager?.getArena(damager) ?: return
+
+ if (arena.state != Arena.ArenaState.RUNNING) {
+ e.isCancelled = true
+ return
+ }
+
+ if (arena.team1.contains(damager) && arena.team1.contains(player)) {
+ e.isCancelled = true
+ return
+ }
+
+ if (arena.team2.contains(damager) && arena.team2.contains(player)) {
+ e.isCancelled = true
+ }
+ }
+
+ @EventHandler
+ fun onDamage(e: EntityDamageEvent) {
+ val player = e.entity as? Player ?: return
+
+ if (!isInArena(player)) {
+ return
+ }
+
+ // Get player that hurt the player
+ var killer: Player? = null
+ if (e is EntityDamageByEntityEvent) {
+ // If the damage is caused by a player
+ if (e.damager is Player) {
+ plugin.logger.info("Player")
+ killer = e.damager as Player
+ } else if (e.damager is Projectile) {
+ plugin.logger.info("Arrow")
+ val projectile = e.damager as Projectile
+ if (projectile.shooter is Player) {
+ killer = projectile.shooter as Player
+ }
+ } else if (e.damager.type == EntityType.TNT) {
+ plugin.logger.info("TNT")
+ if (e.damager.customName() != null) {
+ killer = Bukkit.getPlayer(Objects.requireNonNull(e.damager.customName()).toString())
+ }
+ }
+ }
+
+ val arena: Arena = plugin.arenaModule.arenaManager?.getArena(player) ?: return
+
+ val healthAfter: Double = player.health - e.finalDamage
+ if (healthAfter <= 0) {
+ // Check if during the fight totems are allowed
+
+ var invite = plugin.arenaModule.inviteManager!!.invites[player]
+
+ if (invite == null) invite = plugin.arenaModule.inviteManager!!.selectingInvites[killer]
+
+ if (invite != null) {
+ if (arena.totems) {
+ if (player.inventory.itemInMainHand.type == Material.TOTEM_OF_UNDYING || player.inventory.itemInOffHand.type == Material.TOTEM_OF_UNDYING) {
+ return
+ }
+ }
+ }
+
+ e.isCancelled = true
+ player.health = player.healthScale
+
+ arena.end(player, false)
+ }
+ }
+
+ @EventHandler
+ fun onDeath(e: PlayerDeathEvent) {
+ if (!isInArena(e.entity)) {
+ return
+ }
+ val arena = plugin.arenaModule.arenaManager?.getArena(e.entity) ?: return
+
+ val loc = e.entity.location
+
+ var killer = e.entity.killer
+
+ if (killer == null) {
+ killer = Bukkit.getPlayer(
+ Objects.requireNonNull(Objects.requireNonNull(e.entity.lastDamageCause)?.entity?.customName()).toString()
+ )
+ }
+ if (killer != null) {
+ matchEnd(e.entity, killer)
+ }
+
+ e.entity.spigot().respawn()
+ object : BukkitRunnable() {
+ override fun run() {
+ e.entity.teleport(loc)
+ arena.end(e.entity, false)
+ }
+ }.runTaskLater(plugin, 5L)
+ }
+
+ @EventHandler
+ fun onQuit(e: PlayerQuitEvent) {
+ if (!isInArena(e.player)) {
+ return
+ }
+
+ val arena = plugin.arenaModule.arenaManager?.getArena(e.player) ?: return
+
+ // Check in which team the player is
+ if (arena.team1.contains(e.player)) {
+ matchEnd(e.player, arena.team2[0])
+ } else {
+ matchEnd(e.player, arena.team1[0])
+ }
+
+ arena.end(e.player, true)
+ }
+
+ private fun matchEnd(loser: Player, winner: Player) {
+ val winnerUUID = winner.uniqueId
+ val loserUUID = loser.uniqueId
+
+ // Get the win chance
+ val winChance = plugin.arenaModule.calculateWinChance(winnerUUID, loserUUID).toInt()
+
+ // Announce the winner and the win chance in chat
+ Bukkit.broadcast(
+ MiniMessage.miniMessage().deserialize(
+ plugin.config.getString("messages.fight.end_global")!!
+ .replace("%winner%", winner.name).replace("%loser%", loser.name)
+ .replace("%elo%", plugin.playerManager.getCeraiaPlayer(loserUUID).elo.toString())
+ .replace("%winchance%", winChance.toString())
+ .replace("%arena%", plugin.arenaModule.arenaManager?.getArena(loser)?.name ?: "")
+ )
+ )
+
+ // Handle ELO calculations
+ // #TODO: Re-implement ELO calculations
+ //plugin.getPlayerManager().PlayerKill(winnerUUID, loserUUID);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/ceraia/modules/arenas/listeners/PlayerEloChangeListener.kt b/src/main/java/com/ceraia/modules/arenas/listeners/PlayerEloChangeListener.kt
new file mode 100644
index 0000000..166b3dd
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/listeners/PlayerEloChangeListener.kt
@@ -0,0 +1,25 @@
+package com.ceraia.modules.arenas.listeners
+
+import com.ceraia.Ceraia
+import com.ceraia.modules.arenas.managers.EloScoreboardManager
+import org.bukkit.event.EventHandler
+import org.bukkit.event.Listener
+import org.bukkit.event.player.PlayerJoinEvent
+
+class PlayerEloChangeListener(private val plugin: Ceraia) : Listener {
+ init {
+ plugin.server.pluginManager.registerEvents(this, plugin)
+ }
+
+ @EventHandler // Custom on player Elo change event to update the scoreboard
+ fun onPlayerEloChange(event: PlayerEventListener?) {
+ val eloScoreboardManager = EloScoreboardManager(plugin)
+ eloScoreboardManager.updateScoreboard()
+ }
+
+ @EventHandler // On player join event to update the scoreboard
+ fun onPlayerJoin(event: PlayerJoinEvent?) {
+ val eloScoreboardManager = EloScoreboardManager(plugin)
+ eloScoreboardManager.updateScoreboard()
+ }
+}
diff --git a/src/main/java/com/ceraia/modules/arenas/listeners/PlayerEventListener.kt b/src/main/java/com/ceraia/modules/arenas/listeners/PlayerEventListener.kt
new file mode 100644
index 0000000..842c6ea
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/listeners/PlayerEventListener.kt
@@ -0,0 +1,19 @@
+package com.ceraia.modules.arenas.listeners
+
+import org.bukkit.event.Event
+import org.bukkit.event.HandlerList
+
+class PlayerEventListener : Event() {
+ companion object {
+ private val handlers = HandlerList()
+
+ @JvmStatic
+ fun getHandlerList(): HandlerList {
+ return handlers
+ }
+ }
+
+ override fun getHandlers(): HandlerList {
+ return handlers
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/ceraia/modules/arenas/listeners/PlayerInventoryListener.kt b/src/main/java/com/ceraia/modules/arenas/listeners/PlayerInventoryListener.kt
new file mode 100644
index 0000000..bef7c6e
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/listeners/PlayerInventoryListener.kt
@@ -0,0 +1,45 @@
+package com.ceraia.modules.arenas.listeners
+
+import com.ceraia.Ceraia
+import org.bukkit.Bukkit
+import org.bukkit.entity.Player
+import org.bukkit.event.EventHandler
+import org.bukkit.event.Listener
+import org.bukkit.event.inventory.InventoryClickEvent
+import org.bukkit.event.inventory.InventoryType
+import org.bukkit.event.player.PlayerDropItemEvent
+
+class PlayerInventoryListener(private val plugin: Ceraia) : Listener {
+ init {
+ Bukkit.getPluginManager().registerEvents(this, plugin)
+ }
+
+ private fun isInArena(player: Player): Boolean {
+ return plugin.arenaModule.arenaManager!!.getArena(player) != null
+ }
+
+ @EventHandler
+ fun onDropItem(e: PlayerDropItemEvent) {
+ if (isInArena(e.player)) {
+ e.isCancelled = true
+ }
+ }
+
+ @EventHandler
+ fun onClickInventory(e: InventoryClickEvent) {
+ val p = e.whoClicked as Player
+
+ if (!isInArena(p)) {
+ return
+ }
+
+ if (e.view.topInventory.type == InventoryType.PLAYER
+ || e.view.topInventory.type ==
+ InventoryType.CRAFTING
+ ) {
+ return
+ }
+
+ e.isCancelled = true
+ }
+}
diff --git a/src/main/java/com/ceraia/modules/arenas/managers/ArenaManager.java b/src/main/java/com/ceraia/modules/arenas/managers/ArenaManager.java
new file mode 100644
index 0000000..d3133b6
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/managers/ArenaManager.java
@@ -0,0 +1,84 @@
+package com.ceraia.modules.arenas.managers;
+
+import com.ceraia.Ceraia;
+import com.ceraia.modules.arenas.types.Arena;
+import org.bukkit.Location;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.entity.Player;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ArenaManager {
+
+ private final Ceraia plugin;
+
+ private final List arenas = new ArrayList<>();
+ private final Map playersInArena = new HashMap<>();
+
+ public ArenaManager(Ceraia plugin) {
+ this.plugin = plugin;
+
+ // Load arenas
+ File f = new File(plugin.getDataFolder(), "data/arenas");
+ if (!f.exists()) {
+ f.mkdirs();
+ return;
+ }
+
+ File[] files = f.listFiles();
+ for (File file : files) {
+ FileConfiguration config = YamlConfiguration.loadConfiguration(file);
+
+ String name = config.getString("name");
+ String owner = config.getString("owner");
+ Location spawnPoint1 = config.getLocation("spawnPoint1");
+ Location spawnPoint2 = config.getLocation("spawnPoint2");
+ boolean isPublic = config.getBoolean("public", false);
+ boolean isFFA = config.getBoolean("ffa", false);
+
+ Arena arena = new Arena(plugin, name, owner, spawnPoint1, spawnPoint2, isPublic, isFFA, file);
+ arenas.add(arena);
+ }
+
+ }
+
+ public List getArenas() {
+ return arenas;
+ }
+
+ public Arena getArena(Player player) {
+ return playersInArena.get(player);
+ }
+
+ public Arena getArena(String name) {
+ for (Arena arena : arenas) {
+ if (arena.getName().equalsIgnoreCase(name)) {
+ return arena;
+ }
+ }
+ return null;
+ }
+
+
+ public void addArena(Arena arena) {
+ arenas.add(arena);
+ arena.saveArena();
+ }
+
+ public void removeArena(Arena arena) {
+ arenas.remove(arena);
+ }
+
+ public void addPlayerToArena(Player player, Arena arena) {
+ playersInArena.put(player, arena);
+ }
+
+ public void removePlayerFromArena(Player player) {
+ playersInArena.remove(player);
+ }
+}
diff --git a/src/main/java/com/ceraia/modules/arenas/managers/EloScoreboardManager.java b/src/main/java/com/ceraia/modules/arenas/managers/EloScoreboardManager.java
new file mode 100644
index 0000000..8deeedf
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/managers/EloScoreboardManager.java
@@ -0,0 +1,39 @@
+package com.ceraia.modules.arenas.managers;
+
+import com.ceraia.Ceraia;
+import com.ceraia.modules.ceraia.types.CeraiaPlayer;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.scoreboard.DisplaySlot;
+import org.bukkit.scoreboard.Objective;
+import org.bukkit.scoreboard.Scoreboard;
+import org.bukkit.scoreboard.ScoreboardManager;
+
+public class EloScoreboardManager {
+
+ private final Ceraia plugin;
+
+ public EloScoreboardManager(Ceraia plugin) {
+ this.plugin = plugin;
+ }
+
+ public void updateScoreboard() {
+ ScoreboardManager scoreboardManager = Bukkit.getScoreboardManager();
+ Scoreboard scoreboardDefault = scoreboardManager.getNewScoreboard();
+ Objective objectivePlayerList = scoreboardDefault.registerNewObjective("eloObjectivePlayerList", "dummy", MiniMessage.miniMessage().deserialize("Top Arena Players"));
+ Objective objectiveBelowName = scoreboardDefault.registerNewObjective("eloObjectiveBelowName", "dummy", MiniMessage.miniMessage().deserialize("ELO"));
+
+ // Get all online players and set their score to their Elo rating
+ for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
+ CeraiaPlayer ceraiaPlayer = plugin.getPlayerManager().getCeraiaPlayer(onlinePlayer.getUniqueId());
+
+ objectivePlayerList.getScore(onlinePlayer.getName()).setScore(ceraiaPlayer.getElo());
+ objectiveBelowName.getScore(onlinePlayer.getName()).setScore(ceraiaPlayer.getElo());
+ objectivePlayerList.setDisplaySlot(DisplaySlot.PLAYER_LIST);
+ objectiveBelowName.setDisplaySlot(DisplaySlot.BELOW_NAME);
+
+ onlinePlayer.setScoreboard(scoreboardDefault);
+ }
+ }
+}
diff --git a/src/main/java/com/ceraia/modules/arenas/managers/InviteManager.java b/src/main/java/com/ceraia/modules/arenas/managers/InviteManager.java
new file mode 100644
index 0000000..6737aed
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/managers/InviteManager.java
@@ -0,0 +1,25 @@
+package com.ceraia.modules.arenas.managers;
+
+import com.ceraia.modules.arenas.types.Arena;
+import org.bukkit.entity.Player;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class InviteManager {
+
+ public Map invites = new HashMap<>();
+ public Map selectingInvites = new HashMap<>();
+
+ public static class Invite {
+ public Player inviter, invited;
+ public Arena arena;
+ public boolean accepted = false;
+ public boolean group;
+
+ public Invite(Player inviter, Player invited) {
+ this.inviter = inviter;
+ this.invited = invited;
+ }
+ }
+}
diff --git a/src/main/java/com/ceraia/modules/arenas/types/Arena.java b/src/main/java/com/ceraia/modules/arenas/types/Arena.java
new file mode 100644
index 0000000..ec8e416
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/types/Arena.java
@@ -0,0 +1,436 @@
+package com.ceraia.modules.arenas.types;
+
+import com.ceraia.Ceraia;
+import com.ceraia.modules.arenas.Utils;
+import com.ceraia.modules.arenas.managers.InviteManager;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import net.kyori.adventure.title.Title;
+import org.bukkit.GameMode;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.scheduler.BukkitRunnable;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+public class Arena {
+ private final Ceraia plugin;
+
+ // before ready
+ private final String name;
+ private final String owner;
+ private final List startPlayers = new ArrayList<>();
+ private final List placedBlocks = new ArrayList<>();
+ private final Map priorLocations = new HashMap<>();
+ private boolean isPublic;
+ private File configFile;
+ // after ready
+ private Location spawnPoint1, spawnPoint2;
+ // after start
+ private List team1 = new ArrayList<>();
+ private List team2 = new ArrayList<>();
+ private ArenaState state = ArenaState.WAITING;
+ private int timer;
+ public boolean totems = false;
+ private boolean isFFA = false;
+
+ public Arena(Ceraia plugin, String name, String owner, Location spawnPoint1, Location spawnPoint2, boolean isPublic, boolean isFFA, File configFile) {
+ this.plugin = plugin;
+
+ this.name = name;
+ this.owner = owner;
+ this.spawnPoint1 = spawnPoint1;
+ this.spawnPoint2 = spawnPoint2;
+ this.isPublic = isPublic;
+ this.isFFA = isFFA;
+
+ this.configFile = configFile;
+ }
+
+ public boolean saveArena() {
+ try {
+ configFile = new File(plugin.getDataFolder(), "data/arenas/" + name + ".yml");
+
+ // Check if the file already exists
+ if (!configFile.exists()) {
+ configFile.createNewFile();
+ }
+
+ YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
+
+ // Update or set the values
+ config.set("name", name);
+ config.set("owner", owner);
+
+ config.set("spawnPoint1", spawnPoint1);
+ config.set("spawnPoint2", spawnPoint2);
+ config.set("public", isPublic);
+
+ config.save(configFile);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ public boolean totems() {
+ return totems;
+ }
+
+ public void setTotems(boolean totems) {
+ this.totems = totems;
+ }
+
+ public void setTotems(boolean totems, boolean save) {
+ this.totems = totems;
+ if (save) {
+ saveArena();
+ }
+ }
+ public int getTimer() {
+ return timer;
+ }
+
+ public void setTimer(int timer) {
+ this.timer = timer;
+ }
+
+ public ArenaState getState() {
+ return state;
+ }
+
+ public void setState(ArenaState state) {
+ this.state = state;
+ }
+
+ public void delete() {
+ configFile.delete();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getOwner() {
+ return owner;
+ }
+
+ public Location getSpawnPoint1() {
+ return spawnPoint1;
+ }
+
+ public void setSpawnPoint1(Location loc) {
+ spawnPoint1 = loc;
+ saveArena();
+ }
+
+ public Location getSpawnPoint2() {
+ return spawnPoint2;
+ }
+
+ public void setSpawnPoint2(Location loc) {
+ spawnPoint2 = loc;
+ saveArena();
+ }
+
+ public List getTeam1() {
+ return team1;
+ }
+
+ public void setTeam1(List team1) {
+ this.team1 = team1;
+ }
+
+ public List getTeam2() {
+ return team2;
+ }
+
+ public void setTeam2(List team2) {
+ this.team2 = team2;
+ }
+
+ public void addPlayer(Player player, int team) {
+ plugin.getArenaModule().getArenaManager().addPlayerToArena(player, this);
+ if (team == 1) {
+ team1.add(player);
+ } else {
+ team2.add(player);
+ }
+
+ startPlayers.add(player);
+ }
+
+ public List getStartPlayers() {
+ return startPlayers;
+ }
+
+ public List getOnlinePlayers() {
+ List onlinePlayers = new ArrayList<>();
+ onlinePlayers.addAll(team1);
+ onlinePlayers.addAll(team2);
+
+ return onlinePlayers;
+ }
+
+ public void reset() {
+ team1.clear();
+ team2.clear();
+ startPlayers.clear();
+ placedBlocks.clear();
+ priorLocations.clear();
+ }
+
+ public void end(Player player, boolean quit) {
+ boolean end = false;
+
+
+
+ List winners = new ArrayList<>();
+ List losers = new ArrayList<>();
+
+ if (this.getTeam1().contains(player)) {
+ if (this.getTeam1().size() <= 1) {
+ end = true;
+
+ winners.addAll(this.getTeam2());
+ losers.addAll(this.getTeam1());
+ } else {
+ List team = this.getTeam1();
+ team.remove(player);
+ this.setTeam1(team);
+ }
+ } else {
+ if (this.getTeam2().size() <= 1) {
+ end = true;
+
+ winners.addAll(this.getTeam1());
+ losers.addAll(this.getTeam2());
+ } else {
+ List team = this.getTeam2();
+ team.remove(player);
+ this.setTeam2(team);
+ }
+ }
+
+ if (!end || quit) {
+ Utils.teleportPlayerToSpawn(plugin, player, this);
+ plugin.getArenaModule().getArenaManager().removePlayerFromArena(player);
+
+ player.getInventory().clear();
+ Utils.revertInventory(plugin, player, this);
+ if (!end) {
+ return;
+ }
+ }
+
+ for (Player pl : this.getOnlinePlayers()) {
+ if (pl == player && quit) {
+ continue;
+ }
+
+ pl.sendMessage(
+ MiniMessage.miniMessage().deserialize(
+ plugin.getConfig().getString("messages.fight.end")
+ .replace("%winner%", winners.stream().map(Player::getName).collect(Collectors.joining(", ")))
+ .replace("%time%", String.valueOf(plugin.getConfig().getInt("cooldown.after")))
+ )
+ );
+
+ pl.getInventory().clear();
+
+ pl.setHealth(20);
+ pl.setFireTicks(0);
+ pl.setFoodLevel(20);
+ pl.setSaturation(20);
+ }
+
+ this.setState(ArenaState.ENDING);
+
+ Arena thisArena = this;
+
+ new BukkitRunnable() {
+ public void run() {
+ for (Location loc : placedBlocks) {
+ loc.getBlock().setType(Material.AIR);
+ }
+
+ for (Player pl : getOnlinePlayers()) {
+ if (pl == player && quit) {
+ continue;
+ }
+ Utils.teleportPlayerToSpawn(plugin, pl, thisArena);
+
+ plugin.getArenaModule().getArenaManager().removePlayerFromArena(pl);
+
+ Utils.revertInventory(plugin, pl, thisArena);
+ }
+
+ // Reward
+ for (Player pl : winners) {
+ plugin.getPlayerManager().getCeraiaPlayer(pl.getUniqueId()).addWin();
+ for (String command : plugin.getConfig().getStringList("rewards")) {
+ pl.performCommand(command.replace("%player%", pl.getName()));
+ }
+ }
+
+ // Reward losers
+ for (Player pl : losers) {
+ plugin.getPlayerManager().getCeraiaPlayer(pl.getUniqueId()).addLoss();
+ for (String command : plugin.getConfig().getStringList("rewards_lose")) {
+ pl.performCommand(command.replace("%player%", pl.getName()));
+ }
+ }
+
+ thisArena.setState(ArenaState.WAITING);
+ reset();
+ }
+ }.runTaskLater(plugin, plugin.getConfig().getInt("cooldown.after") * 20L);
+ }
+
+ public void start(InviteManager.Invite invite, List players) {
+ this.setState(ArenaState.STARTING);
+
+ try {
+ for (Player pl : players) {
+ priorLocations.put(pl, pl.getLocation());
+
+ ItemStack[] content = pl.getInventory().getContents();
+
+ File file = new File(plugin.getDataFolder(), "data/pinventory_" + this.getName() + "_" + pl.getName() + ".yml");
+ file.createNewFile();
+
+ FileConfiguration yaml = YamlConfiguration.loadConfiguration(file);
+
+ // list of itemstack from array
+ for (int i = 0; i < content.length; i++) {
+ if (content[i] == null) {
+ yaml.set("items." + i, "null");
+ } else {
+ yaml.set("items." + i, content[i]);
+ }
+ }
+
+ yaml.save(file);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ System.out.println("Problem saving inventories, nothing was deleted!");
+ for (Player pl : Arrays.asList(invite.invited, invite.inviter)) {
+ pl.sendMessage(
+ MiniMessage.miniMessage().deserialize(
+ Objects.requireNonNull(plugin.getConfig().getString("messages.fight.problem_saving_inventories"))
+ )
+ );
+ }
+
+ return;
+ }
+
+ for (Player pl : this.getTeam1()) {
+ pl.teleport(
+ this.getSpawnPoint1()
+ );
+ }
+ for (Player pl : this.getTeam2()) {
+ pl.teleport(
+ this.getSpawnPoint2()
+ );
+ }
+
+ for (Player pl : players) {
+ pl.setHealth(20);
+ pl.setFoodLevel(20);
+ pl.setSaturation(20);
+ pl.setGameMode(GameMode.SURVIVAL);
+ }
+
+ this.setState(ArenaState.STARTING);
+
+ AtomicInteger i = new AtomicInteger(
+ plugin.getConfig().getInt("cooldown.before") + 1
+ );
+
+ Arena thisArena = this;
+ new BukkitRunnable() {
+ public void run() {
+ for (Player pl : players) {
+ if (i.get() == 0) {
+ pl.showTitle(Title.title(Component.empty(), Component.empty()));
+ } else if (i.get() == 1) {
+ Title title = Title.title(
+ MiniMessage.miniMessage().deserialize(plugin.getConfig().getString("messages.fight.started")
+ .replace("%time%", String.valueOf(i.get() - 1))),
+ Component.empty()
+ );
+
+ pl.showTitle(title);
+ } else {
+ pl.showTitle(Title.title(MiniMessage.miniMessage().deserialize(
+ plugin.getConfig().getString("messages.fight.starting")
+ .replace("%time%", String.valueOf(i.get() - 1))
+ ), MiniMessage.miniMessage().deserialize(
+ Objects.requireNonNull(plugin.getArenaModule().getArenaManager().getArena(pl).totems ?
+ plugin.getConfig().getString("messages.fight.totems_enabled")
+ : plugin.getConfig().getString("messages.fight.totems_disabled"))
+ )
+ ));
+ }
+ }
+
+ if (i.get() == 0) {
+ thisArena.setState(ArenaState.RUNNING);
+ cancel();
+ return;
+ }
+
+ i.decrementAndGet();
+
+ }
+ }.runTaskTimer(plugin, 0, 20);
+ }
+
+ public void placeBlock(Location loc) {
+ placedBlocks.add(loc);
+ }
+
+ public void removeBlock(Location loc) {
+ placedBlocks.remove(loc);
+ }
+
+ public List getPlacedBlocks() {
+ return placedBlocks;
+ }
+
+ public boolean isPublic() {
+ return isPublic;
+ }
+
+ public void setPublic(boolean isPublic) {
+ this.isPublic = isPublic;
+
+ try {
+ YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
+ config.set("public", isPublic);
+ config.save(configFile);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public Location getPlayerPriorLocation(Player pl) {
+ return priorLocations.get(pl);
+ }
+
+ public enum ArenaState {
+ WAITING, STARTING, RUNNING, ENDING
+ }
+}
diff --git a/src/main/java/com/ceraia/modules/arenas/types/ArenaSelectGUI.java b/src/main/java/com/ceraia/modules/arenas/types/ArenaSelectGUI.java
new file mode 100644
index 0000000..f619f3f
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/arenas/types/ArenaSelectGUI.java
@@ -0,0 +1,235 @@
+package com.ceraia.modules.arenas.types;
+
+import com.ceraia.Ceraia;
+import com.ceraia.modules.arenas.managers.InviteManager;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+import org.bukkit.Bukkit;
+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.event.inventory.InventoryType;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+
+import java.util.*;
+
+public class ArenaSelectGUI implements Listener {
+ private static Component INVENTORY_NAME_ARENAS;
+ private static Component INVENTORY_NAME_TOTEMS;
+ private final Ceraia plugin;
+ private final Map> selectingArenaCache = new HashMap<>();
+
+ public ArenaSelectGUI(Ceraia plugin) {
+ this.plugin = plugin;
+
+ INVENTORY_NAME_ARENAS = MiniMessage.miniMessage().deserialize("Quick Text Arena Title");
+ INVENTORY_NAME_TOTEMS = MiniMessage.miniMessage().deserialize("Quick Text Totem Title");
+
+ Bukkit.getPluginManager().registerEvents(this, plugin);
+ }
+
+ public void openArenaList(Player inviter, Player invited) { // Let the player select what arena to fight in
+ // Add the player invitee and inviter
+ InviteManager.Invite invite = new InviteManager.Invite(inviter, invited);
+
+ plugin.getArenaModule().getInviteManager().selectingInvites.put(inviter, invite);
+
+ // Get a list of all arenas accessible to the player
+ List arenas = plugin.getArenaModule().getArenaManager().getArenas()
+ .stream().filter(a -> a.isPublic() || a.getOwner().equals(inviter.getName())).toList();
+
+ // Size is from arenas.size() and must be devidable by 9
+ int size = Math.max(9, (arenas.size() + 8) / 9 * 9);
+
+ // Create the inventory
+ Inventory inv = Bukkit.createInventory(null, size, MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.arena_select_gui.inventory_name"))));
+
+ // Create a map of the slot and the arena
+ Map arenasSelectSlots = new HashMap<>();
+
+ int i = 0; // Slot
+ for (Arena a : arenas.stream().filter(a -> a.getState() == Arena.ArenaState.WAITING).toList()) { // Filter out arenas that are not ready
+ ItemStack itemStack = new ItemStack(Objects.requireNonNull(Material.getMaterial(
+ Objects.requireNonNull(plugin.getConfig().getString("messages.arena_select_gui.arena_item.item"))
+ ))); // Create the itemstack
+ ItemMeta meta = itemStack.getItemMeta();
+ meta.displayName(
+ MiniMessage.miniMessage().deserialize(
+ Objects.requireNonNull(plugin.getConfig().getString("messages.arena_select_gui.arena_item.name"))
+ .replace("%arena_name%", a.getName())
+ .replace("%arena_owner%", a.getOwner())
+ )
+ );
+
+ List lore = new ArrayList<>();
+ for (String s : plugin.getConfig().getStringList("messages.arena_select_gui.arena_item.lore")) {
+ lore.add(MiniMessage.miniMessage().deserialize(s.replace("%arena_name%", a.getName())
+ .replace("%arena_owner%", a.getOwner())
+ .replace("%totems%", a.totems ? "enabled" : "disabled")
+ ));
+ }
+
+ meta.lore(lore);
+
+ itemStack.setItemMeta(meta);
+
+ inv.setItem(i, itemStack);
+ arenasSelectSlots.put(i, a);
+
+ i++;
+ }
+
+ // Put the map in the cache
+ selectingArenaCache.put(inviter, arenasSelectSlots);
+
+ // Open the inventory
+ inviter.openInventory(inv);
+ }
+
+ public void openTotemEnabled(Player inviter, Arena arena){ // Let the player select whether to enable or disable totems in the fight
+ int size = 9;
+
+ Inventory inv = Bukkit.createInventory(null, size, MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.totem_select_gui.inventory_name"))));
+
+ ItemStack itemStackEnable = new ItemStack(Objects.requireNonNull(Material.getMaterial(
+ Objects.requireNonNull(plugin.getConfig().getString("messages.totem_select_gui.items.enable.item"))
+ ))); // Create the itemstack
+ ItemMeta metaEnable = itemStackEnable.getItemMeta();
+
+ metaEnable.displayName(
+ MiniMessage.miniMessage().deserialize(
+ Objects.requireNonNull(plugin.getConfig().getString("messages.totem_select_gui.items.enable.name"))
+ )
+ );
+
+ List loreEnable = new ArrayList<>();
+ for (String s : plugin.getConfig().getStringList("messages.totem_select_gui.items.enable.lore")) {
+ loreEnable.add(MiniMessage.miniMessage().deserialize(s));
+ }
+
+ metaEnable.lore(loreEnable);
+
+ itemStackEnable.setItemMeta(metaEnable);
+
+ inv.setItem(1, itemStackEnable);
+
+ ItemStack itemStackDisable = new ItemStack(Objects.requireNonNull(Material.getMaterial(
+ Objects.requireNonNull(plugin.getConfig().getString("messages.totem_select_gui.items.disable.item"))
+ ))); // Create the itemstack
+ ItemMeta metaDisable = itemStackDisable.getItemMeta();
+ metaDisable.displayName(
+ MiniMessage.miniMessage().deserialize(
+ Objects.requireNonNull(plugin.getConfig().getString("messages.totem_select_gui.items.disable.name"))
+ )
+ );
+
+ List loreDisable = new ArrayList<>();
+ for (String s : plugin.getConfig().getStringList("messages.totem_select_gui.items.disable.lore")) {
+ loreDisable.add(MiniMessage.miniMessage().deserialize(s));
+ }
+
+ metaDisable.lore(loreDisable);
+
+ itemStackDisable.setItemMeta(metaDisable);
+
+ inv.setItem(7, itemStackDisable);
+
+ // Set the center slot to the arena that was selected
+ ItemStack itemStackArena = new ItemStack(Objects.requireNonNull(Material.getMaterial(
+ Objects.requireNonNull(plugin.getConfig().getString("messages.arena_select_gui.arena_item.item"))
+ ))); // Create the itemstack
+
+ ItemMeta metaArena = itemStackArena.getItemMeta();
+ metaArena.displayName(
+ MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.arena_select_gui.arena_item.name"))
+ .replace("%arena_name%", arena.getName())
+ .replace("%arena_owner%", arena.getOwner()))
+
+ );
+
+ List loreArena = new ArrayList<>();
+ for (String s : plugin.getConfig().getStringList("messages.arena_select_gui.arena_item.lore")) {
+ loreArena.add(MiniMessage.miniMessage().deserialize(s.replace("%arena_name%", arena.getName())
+ .replace("%arena_owner%", arena.getOwner())
+ ));
+ }
+
+ metaArena.lore(loreArena);
+
+ inviter.openInventory(inv);
+ }
+
+ @EventHandler
+ public void onClick(InventoryClickEvent e) {
+ if (e.getCurrentItem() == null || e.getCurrentItem().getType() == Material.AIR) {
+ return;
+ } // If the item doesn't exist or is air, return
+
+ if (Objects.requireNonNull(e.getInventory()).getType() == InventoryType.PLAYER) {
+ return;
+ } // If the inventory is the player's inventory, return
+
+ Player inviter = (Player) e.getWhoClicked(); // Get the player who clicked
+
+ if (Objects.equals(e.getView().title().toString(), INVENTORY_NAME_ARENAS.toString())) {
+ e.setCancelled(true); // The inventory name is from the plugin, so cancel the event
+
+ int slot = e.getSlot();
+ Arena arena = selectingArenaCache.get(inviter).get(slot); // Get the specific player and then the arena from the cache
+
+ InviteManager.Invite invite = plugin.getArenaModule().getInviteManager().selectingInvites.get(inviter); // Get the invite from the selectingInvites map
+ invite.arena = arena; // Set the arena in the invite
+
+
+ if (arena == null || arena.getState() != Arena.ArenaState.WAITING) { // Somehow arena doesn't work, purely debug
+ inviter.sendMessage(
+ MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.arena_select_gui.arena_not_ready"))))
+ ;
+ return;
+ }
+
+
+ openTotemEnabled(inviter, arena);
+ }
+ if (Objects.equals(e.getView().title().toString(), INVENTORY_NAME_TOTEMS.toString())) {
+ e.setCancelled(true); // The inventory name is from the plugin, so cancel the event
+
+ int slot = e.getSlot();
+
+ // Get the invite from the selectingInvites map
+ InviteManager.Invite invite = plugin.getArenaModule().getInviteManager().selectingInvites.get(inviter);
+
+ // Get the arena from the invite
+ Arena arena = invite.arena;
+
+ // Set the totems in the invite
+ arena.totems = slot == 1;
+
+ inviter.sendMessage(
+ MiniMessage.miniMessage().deserialize(Objects.requireNonNull(plugin.getConfig().getString("messages.pvp.invite.invite_sent"))
+ .replace("%player%", invite.invited.getName())))
+ ; // Send the invite confirmation message
+
+ String invite_message = Objects.requireNonNull(plugin.getConfig().getString("messages.arena_select_gui.invite_message"))
+ .replace("%inviter%", inviter.getName())
+ .replace("%arena_name%", arena.getName())
+ .replace("%winchance%", plugin.getArenaModule().calculateWinChance(inviter.getUniqueId(), invite.invited.getUniqueId()) + "%")
+ .replace("%totems%", arena.totems ? "enabled" : "disabled");
+ // Get the invite message from the config and replace the placeholders
+
+ Objects.requireNonNull(plugin.getServer().getPlayer(invite.invited.getUniqueId())).sendMessage(MiniMessage.miniMessage().deserialize(invite_message));// Send the actual message
+
+
+ invite.arena = arena;
+
+ plugin.getArenaModule().getInviteManager().selectingInvites.remove(inviter); // Remove the invite from the selectingInvites map
+ plugin.getArenaModule().getInviteManager().invites.put(invite.invited, invite); // Put the invite in the invites map
+
+ inviter.closeInventory(); // Close the inventory
+ }
+ }
+}
diff --git a/src/main/java/com/ceraia/modules/ceraia/CeraiaModule.kt b/src/main/java/com/ceraia/modules/ceraia/CeraiaModule.kt
new file mode 100644
index 0000000..4ea682e
--- /dev/null
+++ b/src/main/java/com/ceraia/modules/ceraia/CeraiaModule.kt
@@ -0,0 +1,18 @@
+package com.ceraia.modules.ceraia
+
+import com.ceraia.Ceraia
+import net.kyori.adventure.text.minimessage.MiniMessage
+import org.bukkit.Bukkit
+import org.bukkit.command.Command
+import org.bukkit.command.CommandExecutor
+import org.bukkit.command.CommandSender
+import org.bukkit.command.TabCompleter
+import org.bukkit.entity.Player
+import org.bukkit.event.Listener
+import org.bukkit.util.StringUtil
+
+class CeraiaModule(private val plugin: Ceraia) : Listener {
+ init {
+
+ }
+}
diff --git a/src/main/java/com/ceraia/managers/PlayerManager.kt b/src/main/java/com/ceraia/modules/ceraia/managers/PlayerManager.kt
similarity index 77%
rename from src/main/java/com/ceraia/managers/PlayerManager.kt
rename to src/main/java/com/ceraia/modules/ceraia/managers/PlayerManager.kt
index 2fd7ebd..715b30e 100644
--- a/src/main/java/com/ceraia/managers/PlayerManager.kt
+++ b/src/main/java/com/ceraia/modules/ceraia/managers/PlayerManager.kt
@@ -1,7 +1,7 @@
-package com.ceraia.managers
+package com.ceraia.modules.ceraia.managers
import com.ceraia.Ceraia
-import com.ceraia.types.CeraiaPlayer
+import com.ceraia.modules.ceraia.types.CeraiaPlayer
import org.bukkit.Bukkit
import org.bukkit.configuration.file.FileConfiguration
import org.bukkit.configuration.file.YamlConfiguration
@@ -11,7 +11,7 @@ import java.io.IOException
import java.util.*
class PlayerManager(private val plugin: Ceraia) {
- val doublePlayers: MutableList = mutableListOf()
+ val ceraiaPlayers: MutableList = mutableListOf()
init {
// Load arenaPlayers
@@ -27,7 +27,7 @@ class PlayerManager(private val plugin: Ceraia) {
}
- val doublePlayer = CeraiaPlayer(
+ val ceraiaPlayer = CeraiaPlayer(
plugin,
config.getString("name") ?: throw IllegalArgumentException("Name cannot be null"),
config.getString("race", "human").toString(),
@@ -39,27 +39,29 @@ class PlayerManager(private val plugin: Ceraia) {
config.getBoolean("pvpbanned", false),
config.getInt("wins", 0),
config.getInt("losses", 0),
+ config.getStringList("parents"),
+ config.getStringList("children"),
file
)
- doublePlayers.add(doublePlayer)
+ ceraiaPlayers.add(ceraiaPlayer)
}
}
fun getCeraiaPlayer(playerUUID: UUID): CeraiaPlayer {
- return doublePlayers.find { it.uuid == playerUUID } ?: createNewCeraiaPlayer(playerUUID).also {
- doublePlayers.add(it)
+ return ceraiaPlayers.find { it.uuid == playerUUID } ?: createNewCeraiaPlayer(playerUUID).also {
+ ceraiaPlayers.add(it)
}
}
fun getCeraiaPlayer(playerName: String): CeraiaPlayer {
- return doublePlayers.find { it.name == playerName }
+ return ceraiaPlayers.find { it.name == playerName }
?: createNewCeraiaPlayer(Bukkit.getPlayer(playerName)?.uniqueId ?: throw IllegalArgumentException("Player not found"))
- .also { doublePlayers.add(it) }
+ .also { ceraiaPlayers.add(it) }
}
fun getCeraiaPlayer(player: Player): CeraiaPlayer {
- return doublePlayers.find { it.uuid == player.uniqueId } ?: createNewCeraiaPlayer(player.uniqueId).also {
- doublePlayers.add(it)
+ return ceraiaPlayers.find { it.uuid == player.uniqueId } ?: createNewCeraiaPlayer(player.uniqueId).also {
+ ceraiaPlayers.add(it)
}
}
@@ -84,6 +86,8 @@ class PlayerManager(private val plugin: Ceraia) {
set("wins", 0)
set("losses", 0)
set("logs", mutableListOf())
+ set("parents", mutableListOf())
+ set("children", mutableListOf())
}
config.save(configFile)
@@ -99,6 +103,8 @@ class PlayerManager(private val plugin: Ceraia) {
false,
0,
0,
+ mutableListOf(),
+ mutableListOf(),
configFile
)
} catch (e: IOException) {
@@ -115,21 +121,23 @@ class PlayerManager(private val plugin: Ceraia) {
false,
0,
0,
+ mutableListOf(),
+ mutableListOf(),
configFile
)
}
}
fun getPlayer(uniqueId: UUID): CeraiaPlayer? {
- return doublePlayers.find { it.uuid == uniqueId }
+ return ceraiaPlayers.find { it.uuid == uniqueId }
}
fun getPlayer(name: String): CeraiaPlayer? {
- return doublePlayers.find { it.name.equals(name, ignoreCase = true) }
+ return ceraiaPlayers.find { it.name.equals(name, ignoreCase = true) }
}
fun savePlayers() {
plugin.logger.info("Saving players...")
- doublePlayers.forEach { it.savePlayer() }
+ ceraiaPlayers.forEach { it.savePlayer() }
}
}
diff --git a/src/main/java/com/ceraia/types/DoublePlayer.kt b/src/main/java/com/ceraia/modules/ceraia/types/DoublePlayer.kt
similarity index 73%
rename from src/main/java/com/ceraia/types/DoublePlayer.kt
rename to src/main/java/com/ceraia/modules/ceraia/types/DoublePlayer.kt
index f10a488..64b8d23 100644
--- a/src/main/java/com/ceraia/types/DoublePlayer.kt
+++ b/src/main/java/com/ceraia/modules/ceraia/types/DoublePlayer.kt
@@ -1,4 +1,4 @@
-package com.ceraia.types
+package com.ceraia.modules.ceraia.types
import com.ceraia.Ceraia
import org.bukkit.configuration.file.FileConfiguration
@@ -19,9 +19,10 @@ class CeraiaPlayer(
private var pvpBanned: Boolean,
var wins: Int,
var losses: Int,
- private val configFile: File
+ private val parents: MutableList,
+ private var children: MutableList,
+ private val configFile: File,
) {
-
fun getUUID(): UUID = uuid
fun togglePvpBan(): Boolean {
@@ -47,6 +48,8 @@ class CeraiaPlayer(
config.set("pvpbanned", pvpBanned)
config.set("wins", wins)
config.set("losses", losses)
+ config.set("parents", parents)
+ config.set("children", children)
try {
config.save(configFile)
@@ -60,6 +63,22 @@ class CeraiaPlayer(
savePlayer()
}
+ fun disown(name: String){
+ children.remove(name)
+ parents.remove(name)
+ savePlayer()
+ }
+
+ fun addChild(name: String){
+ children.add(name)
+ savePlayer()
+ }
+
+ fun addParent(name: String){
+ parents.add(name)
+ savePlayer()
+ }
+
fun marry(name: String) {
marriedName = name
savePlayer()
@@ -80,4 +99,14 @@ class CeraiaPlayer(
this.race = race
savePlayer()
}
-}
+
+ fun addWin() {
+ wins++
+ savePlayer()
+ }
+
+ fun addLoss() {
+ losses++
+ savePlayer()
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index 4564b1f..819894f 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -6,6 +6,26 @@ description: Ceraia, the utility plugin.
author: Axodouble
website: https://github.com/Ceraia/Minecraft
commands:
+ pvp:
+ description: All pvp related commands.
+ usage: /pvp
+ arena:
+ description: All arena related commands.
+ usage: /arena
+ gvg:
+ description: All gvg related commands.
+ usage: /gvg
+ leaderboard:
+ description: All leaderboard related commands.
+ usage: /leaderboard
+ aliases:
+ - top
+ profile:
+ description: All profile related commands.
+ usage: /profile
+ stats:
+ description: All stats related commands.
+ usage: /stats
version:
description: Show the version of the plugin.
usage: /version
@@ -38,44 +58,44 @@ commands:
description: A command to change your race
usage: /race
permissions :
- double.discord:
+ ceraia.discord:
description: "Access to the /discord command that is set in the config.yml"
default: true
- double.time:
+ ceraia.time:
description: "Access to the /day and /night commands"
default: op
children:
- double.time.day:
+ ceraia.time.day:
description: "Access to the /day command"
default: op
- double.time.night:
+ ceraia.time.night:
description: "Access to the /night command"
default: op
- double.time.*:
+ ceraia.time.*:
description: "Access to all time commands"
default: op
- double.sit:
+ ceraia.sit:
description: "Access to the /sit command and to sit on blocks"
default: true
- double.marry:
+ ceraia.marry:
description: "Access to the /marry command"
default: true
- double.jump:
+ ceraia.jump:
description: "Access to the /jump command"
default: op
- double.races:
+ ceraia.races:
description: "Access to the /race command"
default: true
children:
- double.races.become:
+ ceraia.races.become:
description: "Access to become a race with /race become "
default: true
- double.races.become.*:
+ ceraia.races.become.*:
description: "Access to specific races"
default: true
- double.races.reload:
+ ceraia.races.reload:
description: "Access to reload the races"
default: op
- double.races.restore:
+ ceraia.races.restore:
description: "Access to restore all races"
default: op
\ No newline at end of file