├── src └── main │ ├── resources │ ├── arenas │ │ └── spawn.yml │ ├── data │ │ ├── nickname-data.yml │ │ └── settings-data.yml │ ├── regeneration │ │ └── schematics │ │ │ └── - │ ├── spawnitems.yml │ ├── menus │ │ └── settings_menu.yml │ ├── plugin.yml │ └── config.yml │ └── java │ └── dev │ └── darkxx │ └── ffa │ ├── arenas │ ├── Arenas.java │ ├── ArenaManager.java │ └── coolarenas │ │ └── CoolArenaManager.java │ ├── kits │ ├── Kits.java │ └── KitManager.java │ ├── regeneration │ ├── Runnable.java │ └── command │ │ └── RegenerationCommand.java │ ├── commands │ ├── SettingsCommand.java │ ├── settings │ │ ├── ToggleAutoGGCommand.java │ │ ├── ToggleMentionSoundCommand.java │ │ ├── TogglePrivateMessagesCommand.java │ │ ├── ToggleQuickRespawnCommand.java │ │ └── ToggleDirectionalDamageTiltCommand.java │ ├── SitCommand.java │ ├── RulesCommand.java │ ├── SuicideCommand.java │ ├── FlyCommand.java │ ├── ReplyCommand.java │ ├── CoolArenaCommand.java │ ├── PingCommand.java │ ├── HealCommand.java │ ├── StatsCommand.java │ ├── BroadcastCommand.java │ ├── MessageCommand.java │ └── NickCommand.java │ ├── utils │ ├── ActionBarUtil.java │ ├── gui │ │ ├── GuiUpdater.java │ │ ├── InventoryScheme.java │ │ ├── GuiManager.java │ │ ├── ItemBuilderGUI.java │ │ └── GuiBuilder.java │ ├── SitUtil.java │ ├── WorldGuardUtils.java │ └── ItemBuilder.java │ ├── tasks │ ├── ClipboardCleaner.java │ └── UpdateTask.java │ ├── api │ ├── events │ │ ├── NicknameClearEvent.java │ │ ├── NicknameSetEvent.java │ │ ├── PlayerSuicideEvent.java │ │ ├── TeleportToSpawnEvent.java │ │ ├── SpawnItemsGiveEvent.java │ │ ├── CombatEndEvent.java │ │ ├── PlayerWarpEvent.java │ │ ├── KitGiveEvent.java │ │ ├── CombatStartEvent.java │ │ ├── BroadcastEvent.java │ │ └── QuickRespawnEvent.java │ ├── IKits.java │ └── IArenas.java │ ├── lobby │ ├── VoidListener.java │ ├── SpawnCommands.java │ └── SpawnManager.java │ ├── settings │ ├── OldDamageTilt.java │ ├── menu │ │ └── SettingsMenu.java │ └── SettingsManager.java │ ├── stats │ ├── edit │ │ └── EditStats.java │ ├── Stats.java │ └── StatsManager.java │ ├── combat │ ├── Combat.java │ └── CombatTagger.java │ ├── spawnitems │ ├── EventListener.java │ └── Items.java │ ├── DatabaseManager.java │ ├── expansion │ └── Placeholders.java │ └── deathmessages │ └── DeathMessagesManager.java ├── settings.gradle.kts ├── gradle └── wrapper │ └── gradle-wrapper.properties ├── .gitignore ├── gradlew.bat ├── README.md └── gradlew /src/main/resources/arenas/spawn.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/data/nickname-data.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/resources/data/settings-data.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "FFA" 2 | -------------------------------------------------------------------------------- /src/main/resources/regeneration/schematics/-: -------------------------------------------------------------------------------- 1 | you can delete this file while compiling 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-bin.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/arenas/Arenas.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.arenas; 2 | 3 | import org.bukkit.entity.Player; 4 | import java.util.List; 5 | 6 | public class Arenas { 7 | 8 | public static List getArenasList() { 9 | return ArenaManager.listArenas(); 10 | } 11 | 12 | public static String getLastArena(Player player) { 13 | String lastArena = ArenaManager.lastArena.get(player); 14 | return lastArena != null ? lastArena : "none"; 15 | } 16 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | replay_pid* 25 | 26 | /shelf/ 27 | /workspace.xml 28 | .idea 29 | .paper-nms 30 | .gradle 31 | ..gradle 32 | output 33 | src/main/java/dev/darkxx/ffa/guilds -------------------------------------------------------------------------------- /src/main/resources/spawnitems.yml: -------------------------------------------------------------------------------- 1 | # Ensure commands don't include "/", for example: 2 | # - Incorrect: right-click-command: /editkits 3 | # - Correct: right-click-command: editkits 4 | 5 | items: 6 | stats: 7 | item: 'PAPER' 8 | name: '&bStats' 9 | slot: 0 10 | hide-attributes: true 11 | right-click-command: stats 12 | leaderboard: 13 | item: 'NETHER_STAR' 14 | name: '&bLeaderboards' 15 | slot: 4 16 | hide-attributes: true 17 | right-click-command: leaderboards 18 | settings: 19 | item: 'COMPASS' 20 | name: '&bSettings' 21 | slot: 8 22 | hide-attributes: true 23 | right-click-command: settings -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/kits/Kits.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.kits; 2 | 3 | import org.bukkit.entity.Player; 4 | import java.util.List; 5 | 6 | public class Kits { 7 | 8 | public static List getKitNames() { 9 | return KitManager.getKitNames(); 10 | } 11 | 12 | /* 13 | public static String getCurrentKit(Player player) { 14 | String currentKit = KitManager.currentKit.get(player); 15 | return currentKit != null ? currentKit : "none"; 16 | } 17 | */ 18 | 19 | public static String getLastKit(Player player) { 20 | String lastKit = KitManager.lastKit.get(player); 21 | return lastKit != null ? lastKit : "none"; 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/regeneration/Runnable.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.regeneration; 2 | 3 | import com.fastasyncworldedit.core.FaweAPI; 4 | import com.fastasyncworldedit.core.util.TaskManager; 5 | import java.util.Objects; 6 | import org.bukkit.scheduler.BukkitRunnable; 7 | 8 | public class Runnable extends BukkitRunnable { 9 | private final RegenerationImpl arena; 10 | 11 | public Runnable(RegenerationImpl arena) { 12 | this.arena = arena; 13 | } 14 | 15 | public void run() { 16 | TaskManager var10000 = FaweAPI.getTaskManager(); 17 | RegenerationImpl var10001 = this.arena; 18 | Objects.requireNonNull(var10001); 19 | Objects.requireNonNull(var10001); 20 | Objects.requireNonNull(var10001); 21 | var10000.async(var10001::paste); 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/commands/SettingsCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.commands; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.settings.menu.SettingsMenu; 5 | import org.bukkit.command.Command; 6 | import org.bukkit.command.CommandExecutor; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.entity.Player; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class SettingsCommand implements CommandExecutor { 12 | 13 | @Override 14 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 15 | if (!(sender instanceof Player)) { 16 | return true; 17 | } 18 | 19 | Player player = (Player) sender; 20 | 21 | SettingsMenu.menu(player).open(player); 22 | 23 | return true; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/utils/ActionBarUtil.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.utils; 2 | 3 | import net.md_5.bungee.api.ChatMessageType; 4 | import net.md_5.bungee.api.chat.TextComponent; 5 | import org.bukkit.entity.Player; 6 | 7 | import static dev.darkxx.ffa.Main.formatColors; 8 | 9 | /** 10 | * This class provides utility methods for sending action bar messages to players. 11 | */ 12 | public class ActionBarUtil { 13 | 14 | /** 15 | * Sends an action bar message to a player. 16 | * 17 | * @param player the player to send the action bar message to 18 | * @param message the message to be displayed in the action bar 19 | */ 20 | public static void sendActionBar(Player player, String message) { 21 | player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(formatColors(message))); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/tasks/ClipboardCleaner.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.tasks; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.scheduler.BukkitRunnable; 5 | 6 | import java.io.File; 7 | import java.io.IOException; 8 | import java.nio.file.Files; 9 | import java.nio.file.Path; 10 | import java.nio.file.Paths; 11 | 12 | public class ClipboardCleaner extends BukkitRunnable { 13 | private final Path clipboarddir = Paths.get("plugins/FastAsyncWorldEdit/clipboard"); 14 | 15 | public void run() { 16 | try { 17 | delete(clipboarddir); 18 | Bukkit.getLogger().info("Clipboard directory deleted successfully."); 19 | } catch (IOException e) { 20 | Bukkit.getLogger().severe("Failed to delete clipboard directory " + e.getMessage()); 21 | } 22 | } 23 | 24 | private void delete(Path path) throws IOException { 25 | if (Files.exists(path)) { 26 | Files.walk(path) 27 | .sorted((o1, o2) -> o1.compareTo(o2)) 28 | .map(Path::toFile) 29 | .forEach(File::delete); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/api/events/NicknameClearEvent.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.api.events; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.Event; 6 | import org.bukkit.event.HandlerList; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | public class NicknameClearEvent extends Event implements Cancellable { 10 | 11 | private static final HandlerList handlers = new HandlerList(); 12 | private final Player player; 13 | private boolean cancelled = false; 14 | 15 | public NicknameClearEvent(Player player) { 16 | this.player = player; 17 | } 18 | 19 | public Player getPlayer() { 20 | return player; 21 | } 22 | 23 | @Override 24 | public boolean isCancelled() { 25 | return cancelled; 26 | } 27 | 28 | @Override 29 | public void setCancelled(boolean cancelled) { 30 | this.cancelled = cancelled; 31 | } 32 | 33 | public @NotNull HandlerList getHandlers() { 34 | return handlers; 35 | } 36 | 37 | public static HandlerList getHandlerList() { 38 | return handlers; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/commands/settings/ToggleAutoGGCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.commands.settings; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.settings.SettingsManager; 5 | import org.bukkit.command.Command; 6 | import org.bukkit.command.CommandExecutor; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.entity.Player; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class ToggleAutoGGCommand implements CommandExecutor { 12 | 13 | @Override 14 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 15 | if (!(sender instanceof Player player)) { 16 | return true; 17 | } 18 | 19 | SettingsManager.toggleSetting(player, "autoGG"); 20 | 21 | String toggleMessage = Main.getInstance().getConfig().getString("messages.setting_toggle"); 22 | 23 | String status = SettingsManager.getUnformattedSettingStatus(player, "autoGG"); 24 | String msg = toggleMessage 25 | .replace("{setting_name}", "AutoGG") 26 | .replace("{setting_status}", status); 27 | 28 | player.sendMessage(Main.formatColors(msg)); 29 | 30 | return true; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/commands/settings/ToggleMentionSoundCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.commands.settings; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.settings.SettingsManager; 5 | import org.bukkit.command.Command; 6 | import org.bukkit.command.CommandExecutor; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.entity.Player; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class ToggleMentionSoundCommand implements CommandExecutor { 12 | 13 | @Override 14 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 15 | if (!(sender instanceof Player player)) { 16 | return true; 17 | } 18 | 19 | SettingsManager.toggleSetting(player, "mentionSound"); 20 | 21 | String toggleMessage = Main.getInstance().getConfig().getString("messages.setting_toggle"); 22 | 23 | String status = SettingsManager.getUnformattedSettingStatus(player, "mentionSound"); 24 | String msg = toggleMessage 25 | .replace("{setting_name}", "Mention Sound") 26 | .replace("{setting_status}", status); 27 | 28 | player.sendMessage(Main.formatColors(msg)); 29 | 30 | return true; 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/commands/settings/TogglePrivateMessagesCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.commands.settings; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.settings.SettingsManager; 5 | import org.bukkit.command.Command; 6 | import org.bukkit.command.CommandExecutor; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.entity.Player; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class TogglePrivateMessagesCommand implements CommandExecutor { 12 | 13 | @Override 14 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 15 | if (!(sender instanceof Player player)) { 16 | return true; 17 | } 18 | 19 | SettingsManager.toggleSetting(player, "privateMessages"); 20 | 21 | String toggleMessage = Main.getInstance().getConfig().getString("messages.setting_toggle"); 22 | 23 | String status = SettingsManager.getUnformattedSettingStatus(player, "privateMessages"); 24 | String msg = toggleMessage 25 | .replace("{setting_name}", "Private Messages") 26 | .replace("{setting_status}", status); 27 | 28 | player.sendMessage(Main.formatColors(msg)); 29 | 30 | return true; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/lobby/VoidListener.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.lobby; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.entity.Player; 6 | import org.bukkit.event.EventHandler; 7 | import org.bukkit.event.Listener; 8 | import org.bukkit.event.entity.EntityDamageEvent; 9 | 10 | import java.util.HashSet; 11 | import java.util.Set; 12 | 13 | public class VoidListener implements Listener { 14 | 15 | private final Main main; 16 | private final Set teleportedPlayers; 17 | 18 | public VoidListener(Main main) { 19 | this.main = main; 20 | this.teleportedPlayers = new HashSet<>(); 21 | } 22 | 23 | @EventHandler 24 | public void onPlayerDamage(EntityDamageEvent event) { 25 | if (event.getEntity() instanceof Player victim) { 26 | if (event.getCause() == EntityDamageEvent.DamageCause.VOID) { 27 | if (!teleportedPlayers.contains(victim)) { 28 | event.setCancelled(true); 29 | SpawnManager.teleportToSpawn(victim); 30 | teleportedPlayers.add(victim); 31 | Bukkit.getScheduler().runTaskLater(main, () -> teleportedPlayers.remove(victim), 30L); 32 | } 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/commands/settings/ToggleQuickRespawnCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.commands.settings; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.settings.SettingsManager; 5 | import org.bukkit.command.Command; 6 | import org.bukkit.command.CommandExecutor; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.entity.Player; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class ToggleQuickRespawnCommand implements CommandExecutor { 12 | 13 | @Override 14 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 15 | if (!(sender instanceof Player player)) { 16 | return true; 17 | } 18 | 19 | SettingsManager.toggleSetting(player, "toggleQuickRespawn"); 20 | 21 | String toggleMessage = Main.getInstance().getConfig().getString("messages.setting_toggle"); 22 | 23 | String status = SettingsManager.getUnformattedSettingStatus(player, "toggleQuickRespawn"); 24 | String msg = toggleMessage 25 | .replace("{setting_name}", "Quick Respawn") 26 | .replace("{setting_status}", status); 27 | 28 | player.sendMessage(Main.formatColors(msg)); 29 | 30 | return true; 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/api/events/NicknameSetEvent.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.api.events; 2 | 3 | import org.bukkit.event.Cancellable; 4 | import org.bukkit.event.Event; 5 | import org.bukkit.event.HandlerList; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | import java.util.UUID; 9 | 10 | public class NicknameSetEvent extends Event implements Cancellable { 11 | 12 | private static final HandlerList handlers = new HandlerList(); 13 | private final UUID playerId; 14 | private final String nickname; 15 | private boolean cancelled = false; 16 | 17 | public NicknameSetEvent(UUID playerId, String nickname) { 18 | this.playerId = playerId; 19 | this.nickname = nickname; 20 | } 21 | 22 | public UUID getPlayerId() { 23 | return playerId; 24 | } 25 | 26 | public String getNickname() { 27 | return nickname; 28 | } 29 | 30 | @Override 31 | public boolean isCancelled() { 32 | return cancelled; 33 | } 34 | 35 | @Override 36 | public void setCancelled(boolean cancelled) { 37 | this.cancelled = cancelled; 38 | } 39 | 40 | public @NotNull HandlerList getHandlers() { 41 | return handlers; 42 | } 43 | 44 | public static HandlerList getHandlerList() { 45 | return handlers; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/commands/settings/ToggleDirectionalDamageTiltCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.commands.settings; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.settings.SettingsManager; 5 | import org.bukkit.command.Command; 6 | import org.bukkit.command.CommandExecutor; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.entity.Player; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class ToggleDirectionalDamageTiltCommand implements CommandExecutor { 12 | 13 | @Override 14 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 15 | if (!(sender instanceof Player player)) { 16 | return true; 17 | } 18 | 19 | SettingsManager.toggleSetting(player, "OldDamageTilt"); 20 | 21 | String toggleMessage = Main.getInstance().getConfig().getString("messages.setting_toggle"); 22 | 23 | String status = SettingsManager.getUnformattedSettingStatus(player, "OldDamageTilt"); 24 | String msg = toggleMessage 25 | .replace("{setting_name}", "Directional Damage Tilt") 26 | .replace("{setting_status}", status); 27 | 28 | player.sendMessage(Main.formatColors(msg)); 29 | 30 | return true; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/resources/menus/settings_menu.yml: -------------------------------------------------------------------------------- 1 | menu: 2 | title: "Settings" 3 | placeholders: 4 | enabled: "&aEnabled" 5 | disabled: "&cDisabled" 6 | 7 | OldDamageTilt: 8 | name: "&eOld Damage Tilt &7(1.19.4+)" 9 | material: NETHERITE_SWORD 10 | slot: 11 11 | lore: 12 | - "&7Disable the new directional damage tilt that" 13 | - "&7was removed in 1.3.1, but added back in 1.19.4" 14 | - " " 15 | - "&7Status: %status%" 16 | privateMessages: 17 | name: "&ePrivate Messages" 18 | material: WRITABLE_BOOK 19 | slot: 12 20 | lore: 21 | - "&7Toggle your private messages (PM)" 22 | - " " 23 | - "&7Status: %status%" 24 | autoGG: 25 | name: "&eAuto GG" 26 | material: SKELETON_SKULL 27 | slot: 13 28 | lore: 29 | - "&7Send a message 'gg' automatically when killed someone" 30 | - " " 31 | - "&7Status: %status%" 32 | mentionSound: 33 | name: "&eMention Sound" 34 | material: ENDER_PEARL 35 | slot: 14 36 | lore: 37 | - "&7Toggle the sound when you are mentioned in the chat" 38 | - " " 39 | - "&7Status: %status%" 40 | toggleQuickRespawn: 41 | name: "&eQuick Respawn Item" 42 | material: FEATHER 43 | slot: 15 44 | lore: 45 | - "&7Toggle to get a quick respawn item on death" 46 | - " " 47 | - "&7Status: %status%" 48 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/settings/OldDamageTilt.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.settings; 2 | 3 | import com.comphenix.protocol.PacketType; 4 | import com.comphenix.protocol.events.ListenerPriority; 5 | import com.comphenix.protocol.events.PacketAdapter; 6 | import com.comphenix.protocol.events.PacketContainer; 7 | import com.comphenix.protocol.events.PacketEvent; 8 | import dev.darkxx.ffa.Main; 9 | import net.minecraft.network.protocol.game.ClientboundHurtAnimationPacket; 10 | import org.bukkit.entity.Player; 11 | 12 | public class OldDamageTilt extends PacketAdapter { 13 | 14 | public OldDamageTilt(Main main) { 15 | super(main, ListenerPriority.NORMAL, PacketType.Play.Server.HURT_ANIMATION); 16 | } 17 | 18 | @Override 19 | public void onPacketReceiving(PacketEvent event) {} 20 | 21 | @Override 22 | public void onPacketSending(PacketEvent event) { 23 | if (!(event.getPacket().getType() == PacketType.Play.Server.HURT_ANIMATION)) { 24 | return; 25 | } 26 | 27 | Player player = event.getPlayer(); 28 | if (!SettingsManager.hasEnabledSetting(player, "OldDamageTilt")) { 29 | return; 30 | } 31 | 32 | float modifiedYaw = -180.0f; 33 | ClientboundHurtAnimationPacket modifiedPacket = new ClientboundHurtAnimationPacket(0, modifiedYaw); 34 | event.setPacket(PacketContainer.fromPacket(modifiedPacket)); 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/commands/SitCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.commands; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.utils.SitUtil; 5 | import org.bukkit.command.Command; 6 | import org.bukkit.command.CommandExecutor; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.entity.Player; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import static dev.darkxx.ffa.Main.formatColors; 12 | 13 | public class SitCommand implements CommandExecutor { 14 | 15 | @Override 16 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 17 | if (!(sender instanceof Player player)) { 18 | return true; 19 | } 20 | 21 | if (!player.hasPermission("ffa.commands.sit")) { 22 | String noPermission = Main.getInstance().getConfig().getString("messages.no-permission", "&cNo Permission."); 23 | sender.sendMessage(formatColors(noPermission)); 24 | return true; 25 | } 26 | 27 | if (SitUtil.isSitting(player)) { 28 | String alreadySitting = Main.getInstance().getConfig().getString("messages.already-sitting" , "&cYou are already sitting."); 29 | player.sendMessage(formatColors(alreadySitting)); 30 | return true; 31 | } 32 | 33 | SitUtil.sit(player, player.getLocation().add(0, -0.7, 0)); 34 | String sitting = Main.getInstance().getConfig().getString("messages.now-sitting" , "&aYou are now sitting."); 35 | player.sendMessage(formatColors(sitting)); 36 | 37 | return true; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/commands/RulesCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.commands; 2 | 3 | import me.clip.placeholderapi.PlaceholderAPI; 4 | import org.bukkit.command.Command; 5 | import org.bukkit.command.CommandExecutor; 6 | import org.bukkit.command.CommandSender; 7 | import org.bukkit.configuration.file.FileConfiguration; 8 | import org.bukkit.entity.Player; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.List; 12 | 13 | import static dev.darkxx.ffa.Main.formatColors; 14 | 15 | public class RulesCommand implements CommandExecutor { 16 | 17 | private final FileConfiguration config; 18 | 19 | public RulesCommand(FileConfiguration config) { 20 | this.config = config; 21 | } 22 | 23 | @Override 24 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 25 | if (!(sender instanceof Player)) { 26 | return true; 27 | } 28 | Player player = (Player) sender; 29 | 30 | if (!config.contains("messages.rules.format")) { 31 | player.sendMessage(formatColors("&cNo rules are configured.")); 32 | return true; 33 | } 34 | 35 | List rules = config.getStringList("messages.rules.format"); 36 | if (rules.isEmpty()) { 37 | player.sendMessage(formatColors("&cNo rules are configured.")); 38 | return true; 39 | } 40 | 41 | for (String rule : rules) { 42 | player.sendMessage(formatColors(PlaceholderAPI.setPlaceholders(player, (rule)))); 43 | } 44 | return true; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/stats/edit/EditStats.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.stats.edit; 2 | 3 | import dev.darkxx.ffa.stats.StatsManager; 4 | import org.bukkit.command.CommandSender; 5 | import org.bukkit.entity.Player; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | import static dev.darkxx.ffa.Main.formatColors; 9 | 10 | public class EditStats { 11 | 12 | public static void editKills(Player player, int newKills) { 13 | StatsManager.editKills(player.getUniqueId(), newKills); 14 | } 15 | 16 | public static void editDeaths(Player player, int newDeaths) { 17 | StatsManager.editDeaths(player.getUniqueId(), newDeaths); 18 | } 19 | 20 | public static void editStreak(Player player, int newStreak) { 21 | StatsManager.editStreak(player.getUniqueId(), newStreak); 22 | } 23 | 24 | public static void editHighestStreak(Player player, int newHighestStreak) { 25 | StatsManager.editHighestStreak(player.getUniqueId(), newHighestStreak); 26 | } 27 | 28 | public static void sendInvalidCommandMessage(@NotNull CommandSender sender) { 29 | sender.sendMessage(formatColors("\n")); 30 | sender.sendMessage(formatColors("&b&lFFA &8| &7Invalid Command")); 31 | sender.sendMessage(formatColors("\n")); 32 | sender.sendMessage(formatColors("&b• &7/ffa editstats ")); 33 | sender.sendMessage(formatColors("\n")); 34 | sender.sendMessage(formatColors("&b&lExample")); 35 | sender.sendMessage(formatColors("&b• &7/ffa editstats Darkxx kills 10")); 36 | sender.sendMessage(formatColors("\n")); 37 | } 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/commands/SuicideCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.commands; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.api.events.PlayerSuicideEvent; 5 | import me.clip.placeholderapi.PlaceholderAPI; 6 | import org.bukkit.Bukkit; 7 | import org.bukkit.command.Command; 8 | import org.bukkit.command.CommandExecutor; 9 | import org.bukkit.command.CommandSender; 10 | import org.bukkit.entity.Player; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import static dev.darkxx.ffa.Main.formatColors; 14 | 15 | public class SuicideCommand implements CommandExecutor { 16 | 17 | @Override 18 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 19 | if (!sender.hasPermission("ffa.commands.suicide")) { 20 | String noPermission = Main.getInstance().getConfig().getString("messages.no-permission", "&cNo Permission."); 21 | sender.sendMessage(formatColors(noPermission)); 22 | return true; 23 | } 24 | 25 | if (!(sender instanceof Player player)) { 26 | return true; 27 | } 28 | 29 | PlayerSuicideEvent suicideEvent = new PlayerSuicideEvent(player); 30 | Bukkit.getServer().getPluginManager().callEvent(suicideEvent); 31 | if (suicideEvent.isCancelled()) { 32 | return true; 33 | } 34 | player.setHealth(0); 35 | String iWantToSuicide = Main.getInstance().getConfig().getString("messages.i-want-to-die", "&cYou have committed suicide."); 36 | sender.sendMessage(formatColors(PlaceholderAPI.setPlaceholders(player, iWantToSuicide))); 37 | return true; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/commands/FlyCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.commands; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import org.bukkit.command.Command; 5 | import org.bukkit.command.CommandExecutor; 6 | import org.bukkit.command.CommandSender; 7 | import org.bukkit.entity.Player; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | import static dev.darkxx.ffa.Main.formatColors; 11 | 12 | public class FlyCommand implements CommandExecutor { 13 | 14 | @Override 15 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 16 | if (!(sender instanceof Player)) { 17 | return true; 18 | } 19 | 20 | Player player = (Player) sender; 21 | 22 | if (!player.hasPermission("ffa.commands.fly")) { 23 | String noPermission = Main.getInstance().getConfig().getString("messages.no-permission", "&cNo Permission."); 24 | sender.sendMessage(formatColors(noPermission)); 25 | return true; 26 | } 27 | 28 | toggleFlight(player); 29 | 30 | return true; 31 | } 32 | 33 | private void toggleFlight(Player player) { 34 | player.setAllowFlight(!player.getAllowFlight()); 35 | 36 | if (player.getAllowFlight()) { 37 | String flyEnabled = Main.getInstance().getConfig().getString("flightEnabled", "&aYour fly has been enabled."); 38 | player.sendMessage(formatColors(flyEnabled)); 39 | } else { 40 | String flyDisabled = Main.getInstance().getConfig().getString("flightDisabled", "&cYour fly has been disabled."); 41 | player.sendMessage(formatColors(flyDisabled)); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/lobby/SpawnCommands.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.lobby; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import org.bukkit.command.Command; 5 | import org.bukkit.command.CommandExecutor; 6 | import org.bukkit.command.CommandSender; 7 | import org.bukkit.entity.Player; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | import static dev.darkxx.ffa.Main.formatColors; 11 | 12 | 13 | public class SpawnCommands implements CommandExecutor { 14 | 15 | private final SpawnManager spawnManager; 16 | private final Main main; 17 | 18 | public SpawnCommands(SpawnManager spawnManager, Main main) { 19 | this.spawnManager = spawnManager; 20 | this.main = main; 21 | } 22 | 23 | @Override 24 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 25 | if (!(sender instanceof Player player)) { 26 | return true; 27 | } 28 | if (label.equalsIgnoreCase("setspawn") || label.equalsIgnoreCase("ffa:setspawn")){ 29 | if (!player.isOp()) { 30 | player.sendMessage(formatColors("&cYou don't have permission to use this command.")); 31 | return true; 32 | } 33 | spawnManager.setSpawn(player); 34 | return true; 35 | } else if (label.equalsIgnoreCase("spawn") || label.equalsIgnoreCase("ffa:spawn")) { 36 | SpawnManager.teleportToSpawn(player); 37 | String message = Main.getInstance().getConfig().getString("messages.teleported-to-spawn", "&7Teleported you to the spawn!"); 38 | player.sendMessage(formatColors(message)); 39 | return true; 40 | } 41 | return false; 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/commands/ReplyCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.commands; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import org.bukkit.command.Command; 5 | import org.bukkit.command.CommandExecutor; 6 | import org.bukkit.command.CommandSender; 7 | import org.bukkit.entity.Player; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | import static dev.darkxx.ffa.Main.formatColors; 11 | 12 | public class ReplyCommand implements CommandExecutor { 13 | 14 | private final MessageCommand messageCommand; 15 | 16 | public ReplyCommand(MessageCommand messageCommand) { 17 | this.messageCommand = messageCommand; 18 | } 19 | 20 | @Override 21 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 22 | if (!(sender instanceof Player)) { 23 | return true; 24 | } 25 | 26 | Player player = (Player) sender; 27 | 28 | if (!messageCommand.lastMessaged.containsKey(player)) { 29 | String noRecentMessage = Main.getInstance().getConfig().getString("messages.no-resent-message" , "&cYou have not messaged anyone recently."); 30 | 31 | player.sendMessage(formatColors(noRecentMessage)); 32 | return true; 33 | } 34 | 35 | Player recipient = messageCommand.lastMessaged.get(player); 36 | 37 | if (args.length < 1) { 38 | String usageReply = Main.getInstance().getConfig().getString("usage.reply", "&c/reply "); 39 | player.sendMessage(formatColors(usageReply)); 40 | return true; 41 | } 42 | 43 | String message = String.join(" ", args); 44 | 45 | messageCommand.sendMessage(player, recipient, message); 46 | return true; 47 | } 48 | } -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/combat/Combat.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.combat; 2 | 3 | import com.google.common.collect.ImmutableSet; 4 | import org.bukkit.entity.Player; 5 | 6 | import java.util.List; 7 | import java.util.Set; 8 | 9 | public class Combat { 10 | 11 | private final Player attacker; 12 | private final Player victim; 13 | private long endTime; 14 | private static int durationSeconds; 15 | 16 | public Combat(Player attacker, Player victim, int durationSeconds) { 17 | this.attacker = attacker; 18 | this.victim = victim; 19 | this.durationSeconds = durationSeconds; 20 | reset(durationSeconds); 21 | } 22 | 23 | public Player getAttacker() { 24 | return attacker; 25 | } 26 | 27 | public Player getVictim() { 28 | return victim; 29 | } 30 | 31 | public Set getPlayers() { 32 | return ImmutableSet.of(attacker, victim); 33 | } 34 | 35 | public boolean isExpired() { 36 | return getTimeLeftMillis() <= 0; 37 | } 38 | 39 | public long getTimeLeftMillis() { 40 | return Math.max(0, endTime - System.currentTimeMillis()); 41 | } 42 | 43 | public int getTimeLeftSeconds() { 44 | return (int) Math.max(0, getTimeLeftMillis() / 1000); 45 | } 46 | 47 | public static int getDurationSeconds(){ 48 | return durationSeconds; 49 | } 50 | 51 | public static int getPlayerCombatTimer(Player player, List combatLogs) { 52 | for (Combat combatLog : combatLogs) { 53 | if (combatLog.getPlayers().contains(player)) { 54 | return combatLog.getTimeLeftSeconds(); 55 | } 56 | } 57 | return 0; 58 | } 59 | 60 | public void reset(int durationSeconds) { 61 | endTime = System.currentTimeMillis() + (durationSeconds * 1000L); 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: FFA 2 | version: '1.0.4' 3 | main: dev.darkxx.ffa.Main 4 | api-version: '1.19' 5 | softdepend: 6 | - PlaceholderAPI 7 | - ProtocolLib 8 | - FastAsyncWorldEdit 9 | - XyrisKits 10 | authors: 11 | - Darkxx 12 | - XyrisPlugins 13 | description: A Next Gen 1.19 FFA Core. 14 | 15 | commands: 16 | ffa: 17 | permission: ffa.admin 18 | regeneration: 19 | permission: ffa.admin 20 | spawn: 21 | setspawn: 22 | permission: ffa.admin 23 | suicide: 24 | permission: ffa.commands.suicide 25 | aliases: 26 | - kms 27 | - iwanttodie 28 | - killme 29 | broadcast: 30 | permission: ffa.commands.broadcast 31 | rules: 32 | sit: 33 | permission: ffa.commands.sit 34 | stats: 35 | heal: 36 | permission: ffa.commands.heal 37 | message: 38 | aliases: 39 | - msg 40 | reply: 41 | aliases: 42 | - r 43 | fly: 44 | permission: ffa.commands.fly 45 | ping: 46 | nickname: 47 | permission: ffa.commands.nickname 48 | aliases: 49 | - nick 50 | settings: 51 | coolarena: 52 | permission: ffa.coolarena.use 53 | aliases: 54 | - ca 55 | 56 | toggleautogg: 57 | permission: ffa.settings.toggleautogg 58 | toggledirectionaldamagetilt: 59 | permission: ffa.settings.toggledirectionaldamagetilt 60 | togglementionsound: 61 | permission: ffa.settings.togglementionsound 62 | toggleprivatemessages: 63 | permission: ffa.settings.toggleprivatemessages 64 | togglequickrespawn: 65 | permission: ffa.settings.togglequickrespawn 66 | 67 | permissions: 68 | ffa.admin: 69 | default: op 70 | ffa.commands.suicide: 71 | default: true 72 | ffa.commands.broadcast: 73 | default: op 74 | ffa.commands.sit: 75 | default: true 76 | ffa.commands.heal: 77 | default: op 78 | ffa.commands.fly: 79 | default: op 80 | ffa.commands.nickname: 81 | default: true 82 | ffa.coolarena.use: 83 | default: true 84 | 85 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/spawnitems/EventListener.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.spawnitems; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.NamespacedKey; 6 | import org.bukkit.event.EventHandler; 7 | import org.bukkit.event.Listener; 8 | import org.bukkit.event.player.PlayerInteractEvent; 9 | import org.bukkit.event.player.PlayerDropItemEvent; 10 | import org.bukkit.inventory.ItemStack; 11 | import org.bukkit.inventory.meta.ItemMeta; 12 | import org.bukkit.persistence.PersistentDataType; 13 | 14 | public class EventListener implements Listener { 15 | private Main main; 16 | 17 | public EventListener(Main main) { 18 | this.main = main; 19 | } 20 | 21 | @EventHandler 22 | public void onPlayerInteract(PlayerInteractEvent event) { 23 | if (!event.getAction().name().contains("RIGHT")) { return; 24 | } 25 | 26 | ItemStack item = event.getItem(); 27 | if (item == null || !item.hasItemMeta()) { return; 28 | } 29 | 30 | ItemMeta meta = item.getItemMeta(); 31 | assert meta != null; 32 | if (!meta.getPersistentDataContainer().has(new NamespacedKey(main, "right-click-command"), PersistentDataType.STRING)) { return; 33 | } 34 | 35 | String command = meta.getPersistentDataContainer().get(new NamespacedKey(main, "right-click-command"), PersistentDataType.STRING); 36 | assert command != null; 37 | Bukkit.dispatchCommand(event.getPlayer(), command); 38 | event.setCancelled(true); 39 | } 40 | 41 | @EventHandler 42 | public void onPlayerDropItem(PlayerDropItemEvent event) { 43 | ItemStack item = event.getItemDrop().getItemStack(); 44 | if (item.hasItemMeta()) { 45 | ItemMeta meta = item.getItemMeta(); 46 | assert meta != null; 47 | if (meta.getPersistentDataContainer().has(new NamespacedKey(main, "right-click-command"), PersistentDataType.STRING)) { 48 | event.setCancelled(true); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/commands/CoolArenaCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.commands; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.arenas.coolarenas.CoolArenaManager; 5 | import org.bukkit.command.Command; 6 | import org.bukkit.command.CommandExecutor; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.command.TabCompleter; 9 | import org.bukkit.entity.Player; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | import static dev.darkxx.ffa.Main.formatColors; 16 | 17 | public class CoolArenaCommand implements CommandExecutor, TabCompleter { 18 | 19 | @Override 20 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 21 | if (!(sender instanceof Player)) { 22 | return true; 23 | } 24 | 25 | Player player = (Player) sender; 26 | 27 | if (!player.hasPermission("ffa.coolarena.use")) { 28 | String noPermission = Main.getInstance().getConfig().getString("messages.no-permission", "&cNo Permission."); 29 | sender.sendMessage(formatColors(noPermission)); 30 | return true; 31 | } 32 | 33 | if (args.length != 1) { 34 | String usageCoolArena = Main.getInstance().getConfig().getString("usage.coolarena", "&cUsage, /coolarena "); 35 | player.sendMessage(formatColors(usageCoolArena)); 36 | return true; 37 | } 38 | 39 | String arenaName = args[0]; 40 | 41 | CoolArenaManager.warp(sender, player.getName(), arenaName); 42 | 43 | return true; 44 | } 45 | 46 | @Override 47 | public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) { 48 | List completions = new ArrayList<>(); 49 | 50 | if (args.length == 1) { 51 | completions.addAll(CoolArenaManager.listCa()); 52 | } 53 | 54 | return completions; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/api/events/PlayerSuicideEvent.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.api.events; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.Event; 6 | import org.bukkit.event.HandlerList; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * Represents an event that occurs when a player commits suicide. 11 | */ 12 | public class PlayerSuicideEvent extends Event implements Cancellable { 13 | private static final HandlerList handlers = new HandlerList(); 14 | private final Player player; 15 | private boolean cancelled; 16 | 17 | /** 18 | * Constructs a new PlayerSuicideEvent with the specified player. 19 | * 20 | * @param player The player who committed suicide. 21 | */ 22 | public PlayerSuicideEvent(Player player) { 23 | this.player = player; 24 | } 25 | 26 | /** 27 | * Gets the player who committed suicide. 28 | * 29 | * @return The player who committed suicide. 30 | */ 31 | public Player getPlayer() { 32 | return player; 33 | } 34 | 35 | /** 36 | * Gets the handler list for this event. 37 | * 38 | * @return The handler list for this event. 39 | */ 40 | public @NotNull HandlerList getHandlers() { 41 | return handlers; 42 | } 43 | 44 | /** 45 | * Gets the handler list for this event. 46 | * 47 | * @return The handler list for this event. 48 | */ 49 | public static HandlerList getHandlerList() { 50 | return handlers; 51 | } 52 | 53 | /** 54 | * Gets whether this event is cancelled. 55 | * 56 | * @return true if this event is cancelled, false otherwise. 57 | */ 58 | @Override 59 | public boolean isCancelled() { 60 | return cancelled; 61 | } 62 | 63 | /** 64 | * Sets whether this event is cancelled. 65 | * 66 | * @param cancelled true to cancel this event, false otherwise. 67 | */ 68 | @Override 69 | public void setCancelled(boolean cancelled) { 70 | this.cancelled = cancelled; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/api/events/TeleportToSpawnEvent.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.api.events; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.entity.Player; 5 | import org.bukkit.event.Cancellable; 6 | import org.bukkit.event.HandlerList; 7 | import org.bukkit.event.player.PlayerEvent; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | /** 11 | * Represents an event that occurs when a player teleports to the spawn location. 12 | */ 13 | public class TeleportToSpawnEvent extends PlayerEvent implements Cancellable { 14 | private static final HandlerList handlers = new HandlerList(); 15 | private boolean cancelled; 16 | private final Location tspawnLocation; 17 | 18 | /** 19 | * Constructs a new PlayerTeleportToSpawnEvent with the specified player and spawn location. 20 | * 21 | * @param player The player who is teleporting to the spawn location. 22 | * @param tspawnLocation The location of the spawn. 23 | */ 24 | public TeleportToSpawnEvent(Player player, Location tspawnLocation) { 25 | super(player); 26 | this.tspawnLocation = tspawnLocation; 27 | } 28 | 29 | /** 30 | * Gets the player who is teleporting to the spawn location. 31 | * 32 | * @return The player who is teleporting to the spawn location. 33 | */ 34 | public Player getTeleportedPlayer() { 35 | return getPlayer(); 36 | } 37 | 38 | /** 39 | * Gets the spawn location associated with this event. 40 | * 41 | * @return The spawn location associated with this event. 42 | */ 43 | public Location getSpawnLocation() { 44 | return tspawnLocation; 45 | } 46 | 47 | @Override 48 | public boolean isCancelled() { 49 | return cancelled; 50 | } 51 | 52 | @Override 53 | public void setCancelled(boolean cancelled) { 54 | this.cancelled = cancelled; 55 | } 56 | 57 | @Override 58 | public @NotNull HandlerList getHandlers() { 59 | return handlers; 60 | } 61 | 62 | public static HandlerList getHandlerList() { 63 | return handlers; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/api/events/SpawnItemsGiveEvent.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.api.events; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.Event; 6 | import org.bukkit.event.HandlerList; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * Represents an event that occurs when spawn items are given to a player. 11 | */ 12 | public class SpawnItemsGiveEvent extends Event implements Cancellable { 13 | 14 | private static final HandlerList handlers = new HandlerList(); 15 | private final Player player; 16 | private boolean cancelled = false; 17 | 18 | /** 19 | * Constructs a new SpawnItemsGiveEvent with the specified player. 20 | * 21 | * @param player The player who receives the spawn items. 22 | */ 23 | public SpawnItemsGiveEvent(Player player) { 24 | this.player = player; 25 | } 26 | 27 | /** 28 | * Gets the player who receives the spawn items. 29 | * 30 | * @return The player who receives the spawn items. 31 | */ 32 | public Player getPlayer() { 33 | return player; 34 | } 35 | 36 | /** 37 | * Gets the handler list for this event. 38 | * 39 | * @return The handler list for this event. 40 | */ 41 | public @NotNull HandlerList getHandlers() { 42 | return handlers; 43 | } 44 | 45 | /** 46 | * Gets the handler list for this event. 47 | * 48 | * @return The handler list for this event. 49 | */ 50 | public static HandlerList getHandlerList() { 51 | return handlers; 52 | } 53 | 54 | /** 55 | * Checks if the event is cancelled. 56 | * 57 | * @return true if the event is cancelled, false otherwise. 58 | */ 59 | @Override 60 | public boolean isCancelled() { 61 | return cancelled; 62 | } 63 | 64 | /** 65 | * Sets whether the event is cancelled. 66 | * 67 | * @param cancelled true to cancel the event, false to allow it. 68 | */ 69 | @Override 70 | public void setCancelled(boolean cancelled) { 71 | this.cancelled = cancelled; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/api/events/CombatEndEvent.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.api.events; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.Event; 6 | import org.bukkit.event.HandlerList; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | import java.util.Set; 10 | 11 | /** 12 | * Represents an event that occurs when combat ends for a set of players. 13 | */ 14 | public class CombatEndEvent extends Event implements Cancellable { 15 | 16 | private static final HandlerList handlers = new HandlerList(); 17 | private final Set players; 18 | private boolean cancelled; 19 | 20 | /** 21 | * Constructs a new CombatEndEvent with the specified set of players. 22 | * 23 | * @param players The set of players for which combat has ended. 24 | */ 25 | public CombatEndEvent(Set players) { 26 | this.players = players; 27 | } 28 | 29 | /** 30 | * Gets the set of players for which combat has ended. 31 | * 32 | * @return The set of players for which combat has ended. 33 | */ 34 | public Set getPlayers() { 35 | return players; 36 | } 37 | 38 | /** 39 | * Gets the handler list for this event. 40 | * 41 | * @return The handler list for this event. 42 | */ 43 | public @NotNull HandlerList getHandlers() { 44 | return handlers; 45 | } 46 | 47 | /** 48 | * Gets the handler list for this event. 49 | * 50 | * @return The handler list for this event. 51 | */ 52 | public static HandlerList getHandlerList() { 53 | return handlers; 54 | } 55 | 56 | /** 57 | * Gets whether this event is cancelled. 58 | * 59 | * @return true if this event is cancelled, false otherwise. 60 | */ 61 | @Override 62 | public boolean isCancelled() { 63 | return cancelled; 64 | } 65 | 66 | /** 67 | * Sets whether this event is cancelled. 68 | * 69 | * @param cancelled true to cancel this event, false otherwise. 70 | */ 71 | @Override 72 | public void setCancelled(boolean cancelled) { 73 | this.cancelled = cancelled; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/commands/PingCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.commands; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.ChatColor; 6 | import org.bukkit.command.Command; 7 | import org.bukkit.command.CommandExecutor; 8 | import org.bukkit.command.CommandSender; 9 | import org.bukkit.entity.Player; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import java.util.List; 13 | 14 | import static dev.darkxx.ffa.Main.formatColors; 15 | 16 | public class PingCommand implements CommandExecutor { 17 | 18 | @Override 19 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 20 | if (!(sender instanceof Player player)) { 21 | return true; 22 | } 23 | 24 | if (args.length == 0) { 25 | sendPingInfo(player, player); 26 | return true; 27 | } 28 | if (args.length == 1) { 29 | Player targetPlayer = Bukkit.getPlayer(args[0]); 30 | if (targetPlayer == null || !targetPlayer.isOnline()) { 31 | player.sendMessage(ChatColor.RED + "Player " + args[0] + " is not online."); 32 | return true; 33 | } 34 | sendPingInfo(player, targetPlayer); 35 | return true; 36 | } 37 | String usagePing = Main.getInstance().getConfig().getString("usage.ping", "&cUsage, /ping [playerName]"); 38 | player.sendMessage(formatColors(usagePing)); 39 | return true; 40 | } 41 | 42 | private void sendPingInfo(Player sender, Player target) { 43 | int ping = getPing(target); 44 | 45 | List messages = Main.getInstance().getConfig().getStringList("messages.ping.format"); 46 | String otherPlayer = target.getName(); 47 | 48 | for (String message : messages) { 49 | message = message.replace("%player%", sender.equals(target) ? "Your" : otherPlayer + "'s"); 50 | message = message.replace("%ping%", Integer.toString(ping)); 51 | 52 | sender.sendMessage(formatColors(message)); 53 | } 54 | } 55 | 56 | public static int getPing(Player player) { 57 | return player.getPing(); 58 | } 59 | } -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/api/IKits.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.api; 2 | 3 | import dev.darkxx.ffa.kits.KitManager; 4 | import org.bukkit.command.CommandSender; 5 | import org.bukkit.entity.Player; 6 | 7 | import java.util.List; 8 | 9 | public class IKits { 10 | 11 | /** 12 | * Sends an invalid command message to the sender. 13 | * 14 | * @param sender The command sender to whom the message will be sent. 15 | */ 16 | public static void sendInvalidCommandMessage(CommandSender sender) { 17 | KitManager.sendInvalidCommandMessage(sender); 18 | } 19 | 20 | /** 21 | * Saves a kit with the specified name. 22 | * 23 | * @param sender The command sender saving the kit. 24 | * @param kitName The name of the kit to save. 25 | */ 26 | public static void saveKit(CommandSender sender, String kitName) { 27 | KitManager.saveKit(sender, kitName); 28 | } 29 | 30 | /** 31 | * Deletes the kit with the specified name. 32 | * 33 | * @param kitName The name of the kit to delete. 34 | */ 35 | public static void deleteKit(String kitName) { 36 | KitManager.deleteKit(kitName); 37 | } 38 | 39 | /** 40 | * Lists all available kits to the sender. 41 | * 42 | * @param sender The command sender to whom the kit list will be sent. 43 | */ 44 | public static void listKits(CommandSender sender) { 45 | KitManager.listKits(sender); 46 | } 47 | 48 | /** 49 | * Gives a kit to the specified player. 50 | * 51 | * @param player The player receiving the kit. 52 | * @param kitName The name of the kit to give. 53 | */ 54 | public static void giveKit(Player player, String kitName) { 55 | KitManager.giveKit(player, kitName); 56 | } 57 | 58 | /** 59 | * Retrieves a list of all kit names. 60 | * 61 | * @return A list containing the names of all available kits. 62 | */ 63 | public static List getKitNames() { 64 | return KitManager.getKitNames(); 65 | } 66 | 67 | /** 68 | * Checks if a kit with the specified name exists. 69 | * 70 | * @param kitName The name of the kit to check. 71 | * @return {@code true} if the kit exists, {@code false} otherwise. 72 | */ 73 | public static boolean isKitExists(String kitName) { 74 | return KitManager.isKitExisting(kitName); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/api/IArenas.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.api; 2 | 3 | import dev.darkxx.ffa.arenas.ArenaManager; 4 | import org.bukkit.command.CommandSender; 5 | import org.bukkit.entity.Player; 6 | 7 | import java.util.List; 8 | 9 | public class IArenas { 10 | 11 | /** 12 | * Sends an invalid command message to the sender. 13 | * 14 | * @param sender The command sender to whom the message will be sent. 15 | */ 16 | public static void sendInvalidCommandMessage(CommandSender sender) { 17 | ArenaManager.sendInvalidCommandMessage(sender); 18 | } 19 | 20 | /** 21 | * Creates a new arena with the specified name. 22 | * 23 | * @param sender The command sender creating the arena. 24 | * @param player The player executing the command. 25 | * @param arenaName The name of the arena to create. 26 | */ 27 | public static void createArena(CommandSender sender, Player player, String arenaName) { 28 | ArenaManager.createArena(sender, player, arenaName); 29 | } 30 | 31 | /** 32 | * Deletes the arena with the specified name. 33 | * 34 | * @param sender The command sender deleting the arena. 35 | * @param arenaName The name of the arena to delete. 36 | */ 37 | public static void deleteArena(CommandSender sender, String arenaName) { 38 | ArenaManager.deleteArena(sender, arenaName); 39 | } 40 | 41 | /** 42 | * Retrieves a list of all arena names. 43 | * 44 | * @return A list containing the names of all available arenas. 45 | */ 46 | public static List listArenas() { 47 | return ArenaManager.listArenas(); 48 | } 49 | 50 | /** 51 | * Lists all available arenas to the sender. 52 | * 53 | * @param sender The command sender to whom the arena list will be sent. 54 | */ 55 | public static void arenasList(CommandSender sender) { 56 | ArenaManager.arenasList(sender); 57 | } 58 | 59 | /** 60 | * Warps the specified player to the specified arena. 61 | * 62 | * @param sender The command sender initiating the warp. 63 | * @param player The name of the player to warp. 64 | * @param arenaName The name of the arena to warp to. 65 | */ 66 | public static void warp(CommandSender sender, Player player, String arenaName) { 67 | ArenaManager.warp(sender, player, arenaName); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/api/events/PlayerWarpEvent.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.api.events; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.command.CommandSender; 5 | import org.bukkit.entity.Player; 6 | import org.bukkit.event.Cancellable; 7 | import org.bukkit.event.Event; 8 | import org.bukkit.event.HandlerList; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | /** 12 | * Represents an event that occurs when a player is warped to a specific location. 13 | */ 14 | public class PlayerWarpEvent extends Event implements Cancellable { 15 | private static final HandlerList handlers = new HandlerList(); 16 | private boolean cancelled; 17 | private final Player targetPlayer; 18 | private final Location destination; 19 | private final CommandSender sender; 20 | 21 | /** 22 | * Constructs a new PlayerWarpEvent with the specified parameters. 23 | * 24 | * @param sender The command sender who initiated the warp. 25 | * @param targetPlayer The player being warped. 26 | * @param destination The destination location. 27 | */ 28 | public PlayerWarpEvent(CommandSender sender, Player targetPlayer, Location destination) { 29 | this.sender = sender; 30 | this.targetPlayer = targetPlayer; 31 | this.destination = destination; 32 | } 33 | 34 | /** 35 | * Gets the command sender who initiated the warp. 36 | * 37 | * @return The command sender who initiated the warp. 38 | */ 39 | public CommandSender getSender() { 40 | return sender; 41 | } 42 | 43 | /** 44 | * Gets the player being warped. 45 | * 46 | * @return The player being warped. 47 | */ 48 | public Player getTargetPlayer() { 49 | return targetPlayer; 50 | } 51 | 52 | /** 53 | * Gets the destination location. 54 | * 55 | * @return The destination location. 56 | */ 57 | public Location getDestination() { 58 | return destination; 59 | } 60 | 61 | @Override 62 | public boolean isCancelled() { 63 | return cancelled; 64 | } 65 | 66 | @Override 67 | public void setCancelled(boolean cancelled) { 68 | this.cancelled = cancelled; 69 | } 70 | 71 | @Override 72 | public @NotNull HandlerList getHandlers() { 73 | return handlers; 74 | } 75 | 76 | public static HandlerList getHandlerList() { 77 | return handlers; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/api/events/KitGiveEvent.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.api.events; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.Event; 6 | import org.bukkit.event.HandlerList; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * Represents an event that occurs when a kit is given to a player. 11 | */ 12 | public class KitGiveEvent extends Event implements Cancellable { 13 | 14 | private static final HandlerList handlers = new HandlerList(); 15 | private final Player player; 16 | private final String kitName; 17 | private boolean cancelled; 18 | 19 | /** 20 | * Constructs a new KitGiveEvent with the specified player and kit name. 21 | * 22 | * @param player The player who receives the kit. 23 | * @param kitName The name of the kit given to the player. 24 | */ 25 | public KitGiveEvent(Player player, String kitName) { 26 | this.player = player; 27 | this.kitName = kitName; 28 | } 29 | 30 | /** 31 | * Gets the player who receives the kit. 32 | * 33 | * @return The player who receives the kit. 34 | */ 35 | public Player getPlayer() { 36 | return player; 37 | } 38 | 39 | /** 40 | * Gets the name of the kit given to the player. 41 | * 42 | * @return The name of the kit given to the player. 43 | */ 44 | public String getKitName() { 45 | return kitName; 46 | } 47 | 48 | /** 49 | * Gets the handler list for this event. 50 | * 51 | * @return The handler list for this event. 52 | */ 53 | public @NotNull HandlerList getHandlers() { 54 | return handlers; 55 | } 56 | 57 | /** 58 | * Gets the handler list for this event. 59 | * 60 | * @return The handler list for this event. 61 | */ 62 | public static HandlerList getHandlerList() { 63 | return handlers; 64 | } 65 | 66 | /** 67 | * Gets whether this event is cancelled. 68 | * 69 | * @return true if this event is cancelled, false otherwise. 70 | */ 71 | @Override 72 | public boolean isCancelled() { 73 | return cancelled; 74 | } 75 | 76 | /** 77 | * Sets whether this event is cancelled. 78 | * 79 | * @param cancelled true to cancel this event, false otherwise. 80 | */ 81 | @Override 82 | public void setCancelled(boolean cancelled) { 83 | this.cancelled = cancelled; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/api/events/CombatStartEvent.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.api.events; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.Event; 6 | import org.bukkit.event.HandlerList; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * Represents an event that occurs when combat starts between two players. 11 | */ 12 | public class CombatStartEvent extends Event implements Cancellable { 13 | 14 | private static final HandlerList handlers = new HandlerList(); 15 | private final Player attacker; 16 | private final Player victim; 17 | private boolean cancelled; 18 | 19 | /** 20 | * Constructs a new CombatStartEvent with the specified attacker and victim. 21 | * 22 | * @param attacker The player who initiated the combat. 23 | * @param victim The player who became the victim of the attack. 24 | */ 25 | public CombatStartEvent(Player attacker, Player victim) { 26 | this.attacker = attacker; 27 | this.victim = victim; 28 | } 29 | 30 | /** 31 | * Gets the attacker in this combat event. 32 | * 33 | * @return The attacker in this combat event. 34 | */ 35 | public Player getAttacker() { 36 | return attacker; 37 | } 38 | 39 | /** 40 | * Gets the victim in this combat event. 41 | * 42 | * @return The victim in this combat event. 43 | */ 44 | public Player getVictim() { 45 | return victim; 46 | } 47 | 48 | /** 49 | * Gets the handler list for this event. 50 | * 51 | * @return The handler list for this event. 52 | */ 53 | public @NotNull HandlerList getHandlers() { 54 | return handlers; 55 | } 56 | 57 | /** 58 | * Gets the handler list for this event. 59 | * 60 | * @return The handler list for this event. 61 | */ 62 | public static HandlerList getHandlerList() { 63 | return handlers; 64 | } 65 | 66 | /** 67 | * Gets whether this event is cancelled. 68 | * 69 | * @return true if this event is cancelled, false otherwise. 70 | */ 71 | @Override 72 | public boolean isCancelled() { 73 | return cancelled; 74 | } 75 | 76 | /** 77 | * Sets whether this event is cancelled. 78 | * 79 | * @param cancelled true to cancel this event, false otherwise. 80 | */ 81 | @Override 82 | public void setCancelled(boolean cancelled) { 83 | this.cancelled = cancelled; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/api/events/BroadcastEvent.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.api.events; 2 | 3 | import org.bukkit.command.CommandSender; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.Event; 6 | import org.bukkit.event.HandlerList; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * Represents an event that occurs when a broadcast message is sent. 11 | */ 12 | public class BroadcastEvent extends Event implements Cancellable { 13 | private static final HandlerList handlers = new HandlerList(); 14 | private CommandSender sender; 15 | private String message; 16 | private boolean cancelled = false; 17 | 18 | /** 19 | * Constructs a new BroadcastEvent with the specified sender and message. 20 | * 21 | * @param sender The command sender who initiated the broadcast. 22 | * @param message The message to be broadcasted. 23 | */ 24 | public BroadcastEvent(CommandSender sender, String message) { 25 | this.sender = sender; 26 | this.message = message; 27 | } 28 | 29 | /** 30 | * Gets the command sender who initiated the broadcast. 31 | * 32 | * @return The command sender who initiated the broadcast. 33 | */ 34 | public CommandSender getSender() { 35 | return sender; 36 | } 37 | 38 | /** 39 | * Gets the message to be broadcasted. 40 | * 41 | * @return The message to be broadcasted. 42 | */ 43 | public String getMessage() { 44 | return message; 45 | } 46 | 47 | /** 48 | * Checks if the event is cancelled. 49 | * 50 | * @return true if the event is cancelled, false otherwise. 51 | */ 52 | @Override 53 | public boolean isCancelled() { 54 | return cancelled; 55 | } 56 | 57 | /** 58 | * Sets whether the event is cancelled. 59 | * 60 | * @param cancelled true to cancel the event, false to allow it. 61 | */ 62 | @Override 63 | public void setCancelled(boolean cancelled) { 64 | this.cancelled = cancelled; 65 | } 66 | 67 | /** 68 | * Gets the handler list for this event. 69 | * 70 | * @return The handler list for this event. 71 | */ 72 | public @NotNull HandlerList getHandlers() { 73 | return handlers; 74 | } 75 | 76 | /** 77 | * Gets the handler list for this event. 78 | * 79 | * @return The handler list for this event. 80 | */ 81 | public static HandlerList getHandlerList() { 82 | return handlers; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/commands/HealCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.commands; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.command.Command; 6 | import org.bukkit.command.CommandExecutor; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.entity.Player; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import static dev.darkxx.ffa.Main.formatColors; 12 | 13 | public class HealCommand implements CommandExecutor { 14 | 15 | @Override 16 | public boolean onCommand(CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 17 | if (!sender.hasPermission("ffa.commands.heal")) { 18 | String noPermission = Main.getInstance().getConfig().getString("messages.no-permission", "&cNo Permission."); 19 | sender.sendMessage(formatColors(noPermission)); 20 | return true; 21 | } 22 | 23 | if (sender instanceof Player) { 24 | Player player = (Player) sender; 25 | 26 | if (args.length == 0) { 27 | player.setHealth(player.getMaxHealth()); 28 | player.setFoodLevel(20); 29 | player.setSaturation(0); 30 | return true; 31 | } 32 | 33 | Player targetPlayer = Bukkit.getPlayer(args[0]); 34 | if (targetPlayer == null || !targetPlayer.isOnline()) { 35 | player.sendMessage(formatColors("&cPlayer not found or not online.")); 36 | return true; 37 | } 38 | 39 | targetPlayer.setHealth(targetPlayer.getMaxHealth()); 40 | targetPlayer.setFoodLevel(20); 41 | player.setSaturation(0); 42 | return true; 43 | } else { 44 | if (args.length == 0) { 45 | String usageHeal = Main.getInstance().getConfig().getString("usage.heal", "&cUsage, /heal "); 46 | sender.sendMessage(formatColors(usageHeal)); 47 | return true; 48 | } 49 | 50 | Player targetPlayer = Bukkit.getPlayer(args[0]); 51 | if (targetPlayer == null || !targetPlayer.isOnline()) { 52 | sender.sendMessage((formatColors("&cPlayer not found or not online."))); 53 | return true; 54 | } 55 | 56 | targetPlayer.setHealth(targetPlayer.getMaxHealth()); 57 | targetPlayer.setFoodLevel(20); 58 | targetPlayer.setSaturation(0); 59 | return true; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/tasks/UpdateTask.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.tasks; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import org.apache.http.HttpResponse; 5 | import org.apache.http.client.methods.HttpGet; 6 | import org.apache.http.impl.client.CloseableHttpClient; 7 | import org.apache.http.impl.client.HttpClientBuilder; 8 | import org.apache.http.protocol.BasicHttpContext; 9 | import org.bukkit.Bukkit; 10 | 11 | import java.io.BufferedReader; 12 | import java.io.IOException; 13 | import java.io.InputStreamReader; 14 | import java.net.URI; 15 | import java.net.URISyntaxException; 16 | 17 | import static dev.darkxx.ffa.Main.formatColors; 18 | import static dev.darkxx.ffa.Main.prefix; 19 | 20 | public class UpdateTask { 21 | 22 | public static boolean isOutdated; 23 | public static int latestVersion; 24 | 25 | public static void run() { 26 | try { 27 | String remoteVersion = fetchRemoteVersion(); 28 | if (remoteVersion != null) { 29 | latestVersion = Integer.parseInt(remoteVersion.replaceAll("[^0-9]", "")); 30 | String pluginVersion = Main.getInstance().getDescription().getVersion(); 31 | if (!remoteVersion.equals(pluginVersion)) { 32 | Bukkit.getConsoleSender().sendMessage(formatColors(prefix + "&cThe plugin is not up to date, please update to the latest version, v" + remoteVersion)); 33 | isOutdated = true; 34 | } else { 35 | Bukkit.getConsoleSender().sendMessage(formatColors(prefix + "&aThe plugin is up to date.")); 36 | isOutdated = false; 37 | } 38 | } else { 39 | Bukkit.getConsoleSender().sendMessage(formatColors(prefix + "&cFailed to fetch remote version. Please check your internet connection.")); 40 | } 41 | } catch (IOException | URISyntaxException ex) { 42 | ex.printStackTrace(); 43 | } 44 | } 45 | 46 | private static String fetchRemoteVersion() throws IOException, URISyntaxException { 47 | try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { 48 | HttpGet httpGet = new HttpGet(); 49 | httpGet.setURI(new URI("https://darkxx.xyz/minecraft/ffa/version.txt")); 50 | HttpResponse httpResponse = httpClient.execute(httpGet, new BasicHttpContext()); 51 | BufferedReader reader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent())); 52 | return reader.readLine(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/utils/gui/GuiUpdater.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.utils.gui; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.event.inventory.InventoryClickEvent; 5 | import org.bukkit.inventory.ItemStack; 6 | import org.bukkit.plugin.java.JavaPlugin; 7 | import org.bukkit.scheduler.BukkitTask; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | import java.util.function.Consumer; 12 | import java.util.function.Supplier; 13 | 14 | public class GuiUpdater { 15 | 16 | private BukkitTask task = null; 17 | 18 | private long refreshInterval = 10; 19 | private final Map> suppliers = new HashMap<>(); 20 | private final Map> handlers = new HashMap<>(); 21 | 22 | public GuiUpdater refreshInterval(long interval) { 23 | this.refreshInterval = interval; 24 | return this; 25 | } 26 | 27 | public GuiUpdater updateItem(Integer slot, Supplier supplier, Consumer handler) { 28 | this.suppliers.put(slot, supplier); 29 | this.handlers.put(slot, handler); 30 | return this; 31 | } 32 | 33 | public GuiUpdater updateItem(Integer slot, Supplier supplier) { 34 | return updateItem(slot, supplier, null); 35 | } 36 | 37 | public GuiUpdater updateItems(Integer from, Integer to, Supplier supplier, Consumer handler) { 38 | for(int i = from; i <= to; i++) { 39 | updateItem(i, supplier, handler); 40 | } 41 | return this; 42 | } 43 | 44 | public void startUpdating(GuiBuilder guiBuilder) { 45 | 46 | stopUpdating(); 47 | 48 | for(Map.Entry> entry : suppliers.entrySet()) { 49 | guiBuilder.setItem(entry.getKey(), entry.getValue().get(), handlers.getOrDefault(entry.getKey(), null)); 50 | } 51 | 52 | this.task = Bukkit.getScheduler().runTaskTimer( 53 | JavaPlugin.getProvidingPlugin(GuiUpdater.class), 54 | () -> { 55 | 56 | for(Map.Entry> entry : suppliers.entrySet()) { 57 | guiBuilder.getInventory().setItem(entry.getKey(), entry.getValue().get()); 58 | } 59 | 60 | }, 61 | refreshInterval, // delay 62 | refreshInterval // period 63 | ); 64 | } 65 | 66 | public void stopUpdating() { 67 | if(task != null) { 68 | task.cancel(); 69 | task = null; 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/commands/StatsCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.commands; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.stats.StatsManager; 5 | import org.bukkit.Bukkit; 6 | import org.bukkit.command.Command; 7 | import org.bukkit.command.CommandExecutor; 8 | import org.bukkit.command.CommandSender; 9 | import org.bukkit.configuration.file.FileConfiguration; 10 | import org.bukkit.entity.Player; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import java.util.UUID; 16 | 17 | import static dev.darkxx.ffa.Main.formatColors; 18 | 19 | public class StatsCommand implements CommandExecutor { 20 | 21 | @Override 22 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 23 | if (!(sender instanceof Player)) { 24 | return true; 25 | } 26 | Player player = (Player) sender; 27 | if (args.length > 0) { 28 | UUID targetUUID = Bukkit.getOfflinePlayer(args[0]).getUniqueId(); 29 | displayStats(player, targetUUID); 30 | } else { 31 | displayStats(player, player.getUniqueId()); 32 | } 33 | return true; 34 | } 35 | 36 | private String getPlayerName(UUID playerUUID) { 37 | return Bukkit.getOfflinePlayer(playerUUID).getName(); 38 | } 39 | 40 | private List getFormattedStats(UUID targetUUID) { 41 | List formattedStats = new ArrayList<>(); 42 | FileConfiguration config = Main.getInstance().getConfig(); 43 | String playerName = getPlayerName(targetUUID); 44 | 45 | for (String format : config.getStringList("messages.stats.format")) { 46 | format = format.replace("%player%", playerName) 47 | .replace("%kills%", String.valueOf(StatsManager.getCurrentKills(targetUUID))) 48 | .replace("%deaths%", String.valueOf(StatsManager.getCurrentDeaths(targetUUID))) 49 | .replace("%kdr%", String.valueOf(StatsManager.calculateKDR(targetUUID))) 50 | .replace("%streak%", String.valueOf(StatsManager.getCurrentStreak(targetUUID))) 51 | .replace("%maxstreak%", String.valueOf(StatsManager.getHighestStreak(targetUUID))); 52 | formattedStats.add(formatColors(format)); 53 | } 54 | return formattedStats; 55 | } 56 | 57 | private void displayStats(Player player, UUID targetUUID) { 58 | List formattedStats = getFormattedStats(targetUUID); 59 | formattedStats.forEach(player::sendMessage); 60 | } 61 | } -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/DatabaseManager.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa; 2 | 3 | import com.zaxxer.hikari.HikariConfig; 4 | import com.zaxxer.hikari.HikariDataSource; 5 | import org.bukkit.Bukkit; 6 | 7 | import java.io.File; 8 | import java.sql.Connection; 9 | import java.sql.SQLException; 10 | 11 | import static dev.darkxx.ffa.Main.formatColors; 12 | import static dev.darkxx.ffa.Main.prefix; 13 | 14 | public class DatabaseManager { 15 | 16 | private static HikariDataSource dataSource; 17 | 18 | public static void connect() { 19 | try { 20 | File dataFolder = Main.getInstance().getDataFolder(); 21 | if (!dataFolder.exists()) { 22 | dataFolder.mkdirs(); 23 | } 24 | 25 | Bukkit.getConsoleSender().sendMessage(formatColors(prefix + "&7Establishing connection to the Database...")); 26 | 27 | HikariConfig config = new HikariConfig(); 28 | config.setJdbcUrl("jdbc:sqlite:" + dataFolder.getAbsolutePath() + "/playerdata.db"); 29 | 30 | dataSource = new HikariDataSource(config); 31 | 32 | Bukkit.getConsoleSender().sendMessage(formatColors(prefix + "&7Successfully connected to the Database.")); 33 | createTables(); 34 | } catch (Exception e) { 35 | Bukkit.getLogger().severe("Failed to establish connection to the database: " + e.getMessage()); 36 | } 37 | } 38 | 39 | public static void disconnect() { 40 | try { 41 | if (dataSource != null) { 42 | Bukkit.getConsoleSender().sendMessage(formatColors(prefix + "&7Closing the Database connection...")); 43 | dataSource.close(); 44 | Bukkit.getConsoleSender().sendMessage(formatColors(prefix + "&7Database connection closed successfully.")); 45 | } 46 | } catch (Exception e) { 47 | Bukkit.getLogger().severe("Failed to close the database connection: " + e.getMessage()); 48 | } 49 | } 50 | 51 | private static void createTables() { 52 | try (Connection connection = dataSource.getConnection()) { 53 | try (var statement = connection.createStatement()) { 54 | statement.executeUpdate("CREATE TABLE IF NOT EXISTS player_stats (" + 55 | "uuid VARCHAR(36) PRIMARY KEY," + 56 | "kills INT DEFAULT 0," + 57 | "deaths INT DEFAULT 0," + 58 | "kill_streak INT DEFAULT 0," + 59 | "max_kill_streak INT DEFAULT 0)"); 60 | } 61 | } catch (SQLException e) { 62 | Bukkit.getLogger().severe("Failed to create tables " + e.getMessage()); 63 | } 64 | } 65 | 66 | public static Connection getConnection() { 67 | if (dataSource == null) { 68 | throw new IllegalStateException("Data source is not initialized."); 69 | } 70 | try { 71 | return dataSource.getConnection(); 72 | } catch (SQLException e) { 73 | throw new RuntimeException("Failed to obtain a connection from the data source.", e); 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/commands/BroadcastCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.commands; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.api.events.BroadcastEvent; 5 | import me.clip.placeholderapi.PlaceholderAPI; 6 | import org.bukkit.Bukkit; 7 | import org.bukkit.command.Command; 8 | import org.bukkit.command.CommandExecutor; 9 | import org.bukkit.command.CommandSender; 10 | import org.bukkit.configuration.file.FileConfiguration; 11 | import org.bukkit.entity.Player; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | import java.util.List; 15 | 16 | import static dev.darkxx.ffa.Main.formatColors; 17 | 18 | public class BroadcastCommand implements CommandExecutor { 19 | 20 | private final FileConfiguration config; 21 | 22 | public BroadcastCommand(FileConfiguration config) { 23 | this.config = config; 24 | } 25 | 26 | @Override 27 | public boolean onCommand(CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 28 | if (!sender.hasPermission("ffa.commands.broadcast")) { 29 | String noPermission = config.getString("messages.no-permission", "&cNo Permission."); 30 | sender.sendMessage(formatColors(noPermission)); 31 | return true; 32 | } 33 | 34 | String message = String.join(" ", args); 35 | BroadcastEvent broadcastEvent = new BroadcastEvent(sender, message); 36 | Bukkit.getServer().getPluginManager().callEvent(broadcastEvent); 37 | 38 | if (broadcastEvent.isCancelled()) { 39 | return true; 40 | } 41 | 42 | if (args.length == 0) { 43 | String usageBcast = Main.getInstance().getConfig().getString("usage.broadcast", "&cUsage, /broadcast "); 44 | sender.sendMessage(formatColors(usageBcast)); 45 | return true; 46 | } 47 | 48 | if (!config.contains("messages.broadcast.format")) { 49 | sender.sendMessage(formatColors("&cThe broadcast message is not configured.")); 50 | return true; 51 | } 52 | 53 | List broadcastMessageList = config.getStringList("messages.broadcast.format"); 54 | if (broadcastMessageList.isEmpty()) { 55 | sender.sendMessage(formatColors("&cThe broadcast message is empty.")); 56 | return true; 57 | } 58 | 59 | StringBuilder broadcastMessage = new StringBuilder(); 60 | int size = broadcastMessageList.size(); 61 | for (int i = 0; i < size; i++) { 62 | String line = broadcastMessageList.get(i); 63 | if (!line.isEmpty()) { 64 | line = line.replace("%player%", sender instanceof Player ? ((Player) sender).getDisplayName() : "Server"); 65 | line = line.replace("%message%", String.join(" ", args)); 66 | broadcastMessage.append(line); 67 | if (i < size - 1) { 68 | broadcastMessage.append("\n"); 69 | } 70 | } 71 | } 72 | sender.getServer().broadcastMessage(formatColors(PlaceholderAPI.setPlaceholders((Player) sender, broadcastMessage.toString()))); 73 | return true; 74 | } 75 | } -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/utils/SitUtil.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.utils; 2 | 3 | import org.bukkit.Location; 4 | import org.bukkit.World; 5 | import org.bukkit.entity.Bat; 6 | import org.bukkit.entity.EntityType; 7 | import org.bukkit.entity.LivingEntity; 8 | import org.bukkit.entity.Player; 9 | import org.bukkit.potion.PotionEffect; 10 | import org.bukkit.potion.PotionEffectType; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | import java.util.UUID; 15 | 16 | /** 17 | * This class provides utility methods for handling player sitting functionality. 18 | */ 19 | public class SitUtil { 20 | 21 | private static final Map chair = new HashMap<>(); 22 | 23 | /** 24 | * Checks if a player is currently sitting. 25 | * 26 | * @param player the player to check 27 | * @return true if the player is sitting, false otherwise 28 | */ 29 | public static boolean isSitting(Player player) { 30 | return chair.containsKey(player.getUniqueId()); 31 | } 32 | 33 | /** 34 | * Gets the entity that the player is sitting on. 35 | * 36 | * @param player the player whose chair is to be retrieved 37 | * @return the entity that the player is sitting on, or null if the player is not sitting 38 | */ 39 | public static LivingEntity getChair(Player player) { 40 | return chair.get(player.getUniqueId()); 41 | } 42 | 43 | /** 44 | * Makes a player sit on a specified location. 45 | * 46 | * @param player the player to make sit 47 | * @param pos the location where the player will sit 48 | */ 49 | public static void sit(Player player, Location pos) { 50 | standup(player); 51 | 52 | World world = player.getWorld(); 53 | 54 | Bat entity = (Bat) world.spawnEntity(pos, EntityType.BAT); 55 | 56 | entity.setAwake(true); 57 | entity.setAI(false); 58 | entity.setInvulnerable(true); 59 | entity.setCollidable(false); 60 | entity.setSilent(true); 61 | entity.setGravity(false); 62 | entity.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, 63 | 9999999, 1, false, false, false)); 64 | entity.addPassenger(player); 65 | entity.setRotation(player.getLocation().getYaw(), player.getLocation().getPitch()); 66 | 67 | chair.put(player.getUniqueId(), entity); 68 | } 69 | 70 | /** 71 | * Makes a player stand up from their chair. 72 | * 73 | * @param player the player to make stand up 74 | */ 75 | public static void standup(Player player) { 76 | if (!isSitting(player)) { 77 | return; 78 | } 79 | 80 | LivingEntity chairEntity = getChair(player); 81 | 82 | chair.remove(player.getUniqueId()); 83 | 84 | chairEntity.setInvulnerable(false); 85 | chairEntity.setHealth(0); 86 | } 87 | } 88 | 89 | /* 90 | public static void closeAllChairs() { 91 | for (LivingEntity chair : chairs.values()) { 92 | if (!chair.isDead()) { 93 | chair.setInvulnerable(false); 94 | chair.setHealth(0); 95 | } 96 | } 97 | chairs.clear(); 98 | } 99 | */ -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/stats/Stats.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.stats; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.configuration.file.FileConfiguration; 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.event.EventHandler; 8 | import org.bukkit.event.Listener; 9 | import org.bukkit.event.entity.PlayerDeathEvent; 10 | 11 | import java.util.List; 12 | import java.util.concurrent.CompletableFuture; 13 | 14 | import static dev.darkxx.ffa.Main.formatColors; 15 | 16 | public class Stats implements Listener { 17 | 18 | private final int killStreakThreshold; 19 | private final int deathStreakThreshold; 20 | private final FileConfiguration config; 21 | 22 | public Stats(FileConfiguration config) { 23 | this.config = config; 24 | this.killStreakThreshold = config.getInt("StreakThreshold"); 25 | this.deathStreakThreshold = config.getInt("StreakLoseThreshold"); 26 | } 27 | 28 | @EventHandler 29 | public void onPlayerDeath(PlayerDeathEvent event) { 30 | Player victim = event.getEntity(); 31 | CompletableFuture.runAsync(() -> { 32 | if (victim.getKiller() != null && !victim.getKiller().equals(victim)) { 33 | Player attacker = victim.getKiller(); 34 | int currentStreak = StatsManager.getCurrentStreak(attacker.getUniqueId()); 35 | currentStreak++; 36 | StatsManager.updateKillStreak(attacker, currentStreak); 37 | StatsManager.updateMaxKillStreak(attacker, Math.max(currentStreak, StatsManager.getHighestStreak(attacker.getUniqueId()))); 38 | if (currentStreak % this.killStreakThreshold == 0) { 39 | String playerName = attacker.getName(); 40 | int finalCurrentStreak = currentStreak; 41 | Bukkit.getScheduler().runTaskLater(Main.getInstance(), () -> { 42 | broadcastStreakMessage(playerName, finalCurrentStreak, "StreakMessage"); 43 | }, 3); 44 | } 45 | StatsManager.addKills(attacker, 1); 46 | } 47 | 48 | int currentStreak = StatsManager.getCurrentStreak(victim.getUniqueId()); 49 | StatsManager.updateKillStreak(victim, 0); 50 | StatsManager.updateMaxKillStreak(victim, StatsManager.getHighestStreak(victim.getUniqueId())); 51 | StatsManager.addDeaths(victim, 1); 52 | 53 | if (currentStreak >= this.deathStreakThreshold) { 54 | String playerName = victim.getName(); 55 | Bukkit.getScheduler().runTaskLater(Main.getInstance(), () -> { 56 | broadcastStreakMessage(playerName, currentStreak, "StreakLose"); 57 | }, 3); 58 | } 59 | }); 60 | } 61 | 62 | private void broadcastStreakMessage(String playerName, int streak, String configPath) { 63 | List messages = config.getStringList(configPath); 64 | for (String message : messages) { 65 | message = message.replace("%player%", playerName).replace("%streak%", String.valueOf(streak)); 66 | Bukkit.broadcastMessage(formatColors(message)); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/commands/MessageCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.commands; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.settings.SettingsManager; 5 | import org.bukkit.Bukkit; 6 | import org.bukkit.command.Command; 7 | import org.bukkit.command.CommandExecutor; 8 | import org.bukkit.command.CommandSender; 9 | import org.bukkit.configuration.file.FileConfiguration; 10 | import org.bukkit.entity.Player; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | import static dev.darkxx.ffa.Main.formatColors; 17 | 18 | public class MessageCommand implements CommandExecutor { 19 | private final FileConfiguration config; 20 | final Map lastMessaged = new HashMap<>(); 21 | 22 | public MessageCommand(FileConfiguration config) { 23 | this.config = config; 24 | } 25 | 26 | @Override 27 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 28 | if (!(sender instanceof Player)) { 29 | return true; 30 | } 31 | 32 | Player player = (Player) sender; 33 | 34 | if (args.length < 2) { 35 | String usageMessage = Main.getInstance().getConfig().getString("usage.message", "&c/message "); 36 | player.sendMessage(formatColors(usageMessage)); 37 | return true; 38 | } 39 | 40 | Player targetPlayer = Bukkit.getPlayer(args[0]); 41 | if (targetPlayer == null || !targetPlayer.isOnline()) { 42 | player.sendMessage(formatColors("&cPlayer not found or not online.")); 43 | return true; 44 | } 45 | 46 | String message = String.join(" ", args).substring(args[0].length() + 1); 47 | sendMessage(player, targetPlayer, message); 48 | return true; 49 | } 50 | 51 | private String formatMessage(String format, Player sender, Player recipient, String message) { 52 | format = format.replace("%sender%", sender.getName()) 53 | .replace("%recipient%", recipient.getName()) 54 | .replace("%message%", message); 55 | return format; 56 | } 57 | 58 | void sendMessage(Player sender, Player recipient, String message) { 59 | if (!SettingsManager.hasEnabledSetting(recipient, "privateMessages")) { 60 | String msgsDisabled = Main.getInstance().getConfig().getString("messages.private-messages-disabled", "&c%player% has their Private Messages disabled.") 61 | .replace("%player%", recipient.getName()); 62 | sender.sendMessage(formatColors(msgsDisabled)); 63 | return; 64 | } 65 | 66 | String senderFormat = config.getString("messages.message_format.sender", "&7[To %recipient%] &b%message%").trim(); 67 | String recipientFormat = config.getString("messages.message_format.recipient", "&7[From %sender%] &b%message%").trim(); 68 | 69 | String formattedSenderMessage = formatMessage(senderFormat, sender, recipient, message); 70 | String formattedRecipientMessage = formatMessage(recipientFormat, sender, recipient, message); 71 | 72 | sender.sendMessage(formatColors(formattedSenderMessage)); 73 | recipient.sendMessage(formatColors(formattedRecipientMessage)); 74 | 75 | lastMessaged.put(sender, recipient); 76 | lastMessaged.put(recipient, sender); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/api/events/QuickRespawnEvent.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.api.events; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.bukkit.event.Cancellable; 5 | import org.bukkit.event.Event; 6 | import org.bukkit.event.HandlerList; 7 | import org.bukkit.inventory.ItemStack; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | /** 11 | * Represents an event that occurs when a player quick respawns. 12 | */ 13 | public class QuickRespawnEvent extends Event implements Cancellable { 14 | 15 | private static final HandlerList handlers = new HandlerList(); 16 | private final Player player; 17 | private final ItemStack item; 18 | private String lastArena; 19 | private String lastKit; 20 | private boolean cancelled; 21 | 22 | /** 23 | * Constructs a new QuickRespawnEvent. 24 | * 25 | * @param player The player who quick respawns. 26 | * @param item The item used for quick respawn. 27 | * @param lastArena The last arena the player was in before quick respawning. 28 | * @param lastKit The last kit the player had before quick respawning. 29 | */ 30 | public QuickRespawnEvent(@NotNull Player player, @NotNull ItemStack item, String lastArena, String lastKit) { 31 | this.player = player; 32 | this.item = item; 33 | this.lastArena = lastArena; 34 | this.lastKit = lastKit; 35 | this.cancelled = false; 36 | } 37 | 38 | /** 39 | * Gets the player who quick respawns. 40 | * 41 | * @return The player who quick respawns. 42 | */ 43 | public Player getPlayer() { 44 | return player; 45 | } 46 | 47 | /** 48 | * Gets the item used for quick respawn. 49 | * 50 | * @return The item used for quick respawn. 51 | */ 52 | public ItemStack getItem() { 53 | return item; 54 | } 55 | 56 | /** 57 | * Gets the last arena the player was in before quick respawning. 58 | * 59 | * @return The last arena the player was in before quick respawning. 60 | */ 61 | public String getLastArena() { 62 | return lastArena; 63 | } 64 | 65 | /** 66 | * Gets the last kit the player had before quick respawning. 67 | * 68 | * @return The last kit the player had before quick respawning. 69 | */ 70 | public String getLastKit() { 71 | return lastKit; 72 | } 73 | 74 | /** 75 | * Checks if the event is cancelled. 76 | * 77 | * @return True if the event is cancelled, otherwise false. 78 | */ 79 | public boolean isCancelled() { 80 | return cancelled; 81 | } 82 | 83 | /** 84 | * Sets the cancellation state of the event. 85 | * 86 | * @param cancelled True to cancel the event, otherwise false. 87 | */ 88 | public void setCancelled(boolean cancelled) { 89 | this.cancelled = cancelled; 90 | } 91 | 92 | /** 93 | * Gets the handler list for this event. 94 | * 95 | * @return The handler list for this event. 96 | */ 97 | public @NotNull HandlerList getHandlers() { 98 | return handlers; 99 | } 100 | 101 | /** 102 | * Gets the handler list for this event. 103 | * 104 | * @return The handler list for this event. 105 | */ 106 | public static HandlerList getHandlerList() { 107 | return handlers; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/expansion/Placeholders.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.expansion; 2 | 3 | import dev.darkxx.ffa.combat.Combat; 4 | import dev.darkxx.ffa.combat.CombatTagger; 5 | import dev.darkxx.ffa.arenas.Arenas; 6 | import dev.darkxx.ffa.commands.NickCommand; 7 | import dev.darkxx.ffa.kits.Kits; 8 | import dev.darkxx.ffa.settings.SettingsManager; 9 | import dev.darkxx.ffa.stats.StatsManager; 10 | import dev.darkxx.ffa.utils.WorldGuardUtils; 11 | import me.clip.placeholderapi.expansion.PlaceholderExpansion; 12 | import org.bukkit.Bukkit; 13 | import org.bukkit.entity.Player; 14 | import org.jetbrains.annotations.NotNull; 15 | 16 | import java.util.List; 17 | 18 | public class Placeholders extends PlaceholderExpansion { 19 | 20 | @Override 21 | public @NotNull String getIdentifier() { 22 | return "ffa"; 23 | } 24 | 25 | @Override 26 | public @NotNull String getAuthor() { 27 | return "Darkxx"; 28 | } 29 | 30 | @Override 31 | public @NotNull String getVersion() { 32 | return "1.0"; 33 | } 34 | 35 | @Override 36 | public boolean persist() { 37 | return true; 38 | } 39 | 40 | @Override 41 | public String onPlaceholderRequest(Player player, @NotNull String identifier) { 42 | if (player == null) { 43 | return ""; 44 | } 45 | 46 | if (Bukkit.getPluginManager().isPluginEnabled("WorldGuard")) { 47 | if (identifier.startsWith("players_")) { 48 | String regionName = identifier.replace("players_", ""); 49 | int playerCount = WorldGuardUtils.getPlayerCountInRegion(regionName); 50 | return String.valueOf(playerCount); 51 | } else if (identifier.startsWith("isbusy_")) { 52 | String regionName = identifier.replace("isbusy_", ""); 53 | return WorldGuardUtils.checkArenaStatus(regionName); 54 | } 55 | } else if (identifier.startsWith("players_") || identifier.startsWith("isbusy_")) { 56 | return ""; 57 | } 58 | 59 | return switch (identifier.toLowerCase()) { 60 | case "kills" -> String.valueOf(StatsManager.getCurrentKills(player.getUniqueId())); 61 | case "deaths" -> String.valueOf(StatsManager.getCurrentDeaths(player.getUniqueId())); 62 | case "kdr" -> String.valueOf(StatsManager.calculateKDR(player.getUniqueId())); 63 | case "streak" -> String.valueOf(StatsManager.getCurrentStreak(player.getUniqueId())); 64 | case "maxstreak" -> String.valueOf(StatsManager.getHighestStreak(player.getUniqueId())); 65 | case "lastkit" -> Kits.getLastKit(player); 66 | case "lastarena" -> Arenas.getLastArena(player); 67 | case "combat_timer" -> { 68 | List combatLogs = CombatTagger.getCombatLogs(player); 69 | yield String.valueOf(Combat.getPlayerCombatTimer(player, combatLogs)); 70 | } 71 | case "nickname" -> NickCommand.getNickname(player); 72 | case "settings_olddamagetilt" -> SettingsManager.getSettingStatus(player, "OldDamageTilt"); 73 | case "settings_privatemessages" -> SettingsManager.getSettingStatus(player, "privateMessages"); 74 | case "settings_autogg" -> SettingsManager.getSettingStatus(player, "autoGG"); 75 | case "settings_mentionsound" -> SettingsManager.getSettingStatus(player, "mentionSound"); 76 | case "settings_quickrespawn" -> SettingsManager.getSettingStatus(player, "toggleQuickRespawn"); 77 | default -> null; 78 | }; 79 | } 80 | } -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/utils/gui/InventoryScheme.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of FastInv, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 MrMicky 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package dev.darkxx.ffa.utils.gui; 26 | 27 | import org.bukkit.event.inventory.InventoryClickEvent; 28 | import org.bukkit.inventory.ItemStack; 29 | 30 | import java.util.ArrayList; 31 | import java.util.HashMap; 32 | import java.util.List; 33 | import java.util.Map; 34 | import java.util.Objects; 35 | import java.util.function.Consumer; 36 | 37 | public class InventoryScheme { 38 | 39 | private final List masks = new ArrayList<>(); 40 | private final Map items = new HashMap<>(); 41 | private final Map> handlers = new HashMap<>(); 42 | 43 | public InventoryScheme mask(String mask) { 44 | Objects.requireNonNull(mask); 45 | this.masks.add(mask.length() > 9 ? mask.substring(0, 10) : mask); 46 | 47 | return this; 48 | } 49 | 50 | public InventoryScheme masks(String... masks) { 51 | for (String mask : Objects.requireNonNull(masks)) { 52 | mask(mask); 53 | } 54 | return this; 55 | } 56 | 57 | public InventoryScheme bindItem(char character, ItemStack item, Consumer handler) { 58 | this.items.put(character, Objects.requireNonNull(item)); 59 | 60 | if (handler != null) { 61 | this.handlers.put(character, handler); 62 | } 63 | return this; 64 | } 65 | 66 | public InventoryScheme bindItem(char character, ItemStack item) { 67 | return this.bindItem(character, item, null); 68 | } 69 | 70 | public InventoryScheme unbindItem(char character) { 71 | this.items.remove(character); 72 | this.handlers.remove(character); 73 | return this; 74 | } 75 | 76 | public void apply(GuiBuilder inv) { 77 | for (int line = 0; line < this.masks.size(); line++) { 78 | String mask = this.masks.get(line); 79 | 80 | for (int slot = 0; slot < mask.length(); slot++) { 81 | char c = mask.charAt(slot); 82 | ItemStack item = this.items.get(c); 83 | Consumer handler = this.handlers.get(c); 84 | 85 | if (item != null) { 86 | inv.setItem(9 * line + slot, item, handler); 87 | } 88 | } 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/utils/WorldGuardUtils.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.utils; 2 | 3 | import com.sk89q.worldedit.bukkit.BukkitAdapter; 4 | import com.sk89q.worldguard.WorldGuard; 5 | import com.sk89q.worldguard.protection.regions.ProtectedRegion; 6 | import com.sk89q.worldguard.protection.regions.RegionContainer; 7 | import com.sk89q.worldguard.protection.regions.RegionQuery; 8 | import org.bukkit.Bukkit; 9 | import org.bukkit.entity.Player; 10 | 11 | /** 12 | * This class provides utility methods for interacting with WorldGuard regions. 13 | */ 14 | public class WorldGuardUtils { 15 | 16 | /** 17 | * Retrieves the count of players currently inside a specified WorldGuard region. 18 | * 19 | * @param regionName the name of the WorldGuard region 20 | * @return the count of players inside the specified region 21 | */ 22 | public static int getPlayerCountInRegion(String regionName) { 23 | RegionContainer regionContainer = WorldGuard.getInstance().getPlatform().getRegionContainer(); 24 | RegionQuery query = regionContainer.createQuery(); 25 | int playerCount = 0; 26 | 27 | for (Player player : Bukkit.getOnlinePlayers()) { 28 | if (isInRegion(player, regionName, query)) { 29 | playerCount++; 30 | } 31 | } 32 | return playerCount; 33 | } 34 | 35 | /** 36 | * Checks if a player is inside a specified WorldGuard region. 37 | * 38 | * @param player the player to check 39 | * @param regionName the name of the WorldGuard region 40 | * @param query the region query object 41 | * @return true if the player is inside the specified region, false otherwise 42 | */ 43 | private static boolean isInRegion(Player player, String regionName, RegionQuery query) { 44 | com.sk89q.worldedit.util.Location playerLocation = BukkitAdapter.adapt(player.getLocation()); 45 | for (ProtectedRegion region : query.getApplicableRegions(playerLocation).getRegions()) { 46 | if (region.getId().equalsIgnoreCase(regionName)) { 47 | return true; 48 | } 49 | } 50 | return false; 51 | } 52 | 53 | /** 54 | * Checks if a player is inside a specified WorldGuard region. 55 | * 56 | * @param player the player to check 57 | * @param regionName the name of the WorldGuard region 58 | * @return true if the player is inside the specified region, false otherwise 59 | */ 60 | public static boolean isinRegion(Player player, String regionName) { 61 | RegionContainer regionContainer = WorldGuard.getInstance().getPlatform().getRegionContainer(); 62 | RegionQuery query = regionContainer.createQuery(); 63 | com.sk89q.worldedit.util.Location playerLocation = BukkitAdapter.adapt(player.getLocation()); 64 | for (ProtectedRegion region : query.getApplicableRegions(playerLocation).getRegions()) { 65 | if (region.getId().equalsIgnoreCase(regionName)) { 66 | return true; 67 | } 68 | } 69 | return false; 70 | } 71 | 72 | /** 73 | * Checks if a given arena is considered busy based on the number of players inside. 74 | * 75 | * @param regionName the name of the WorldGuard region representing the arena 76 | * @return a String indicating whether the arena is busy or empty 77 | */ 78 | public static String checkArenaStatus(String regionName) { 79 | int playerCount = getPlayerCountInRegion(regionName); 80 | 81 | if (playerCount >= 8) { 82 | return " &7(Busy)"; 83 | } else { 84 | return ""; 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/deathmessages/DeathMessagesManager.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.deathmessages; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import org.bukkit.Bukkit; 5 | import org.bukkit.configuration.file.FileConfiguration; 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.event.EventHandler; 8 | import org.bukkit.event.Listener; 9 | import org.bukkit.event.entity.PlayerDeathEvent; 10 | import org.bukkit.plugin.java.JavaPlugin; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | import java.util.Random; 15 | 16 | import static dev.darkxx.ffa.Main.formatColors; 17 | 18 | public class DeathMessagesManager implements Listener { 19 | private List deathMessages; 20 | private List disabledWorlds; 21 | private boolean disabled; 22 | private FileConfiguration config; 23 | private Main main; 24 | 25 | public DeathMessagesManager(Main main) { 26 | this.main = main; 27 | deathMessages = new ArrayList<>(); 28 | disabledWorlds = new ArrayList<>(); 29 | disabled = false; 30 | loadConfig(main); 31 | Bukkit.getPluginManager().registerEvents(this, main); 32 | } 33 | 34 | private void loadConfig(JavaPlugin plugin) { 35 | config = plugin.getConfig(); 36 | disabled = config.getBoolean("deathMessages.disabled") 37 | if (config.isList("deathMessages.messages")) { 38 | deathMessages = config.getStringList("deathMessages.messages"); 39 | } else { 40 | deathMessages.add("&c%victim% &7was defeated by &a%attacker% &8(%attacker_health% ❤)"); 41 | deathMessages.add("&7You can add more here!"); 42 | config.set("deathMessages.messages", deathMessages); 43 | } 44 | 45 | if (config.isList("deathMessages.disabledWorlds")) { 46 | disabledWorlds = config.getStringList("deathMessages.disabledWorlds"); 47 | } else { 48 | disabledWorlds.add("example_world"); 49 | config.set("deathMessages.disabledWorlds", disabledWorlds); 50 | } 51 | 52 | plugin.saveConfig(); 53 | } 54 | 55 | @EventHandler 56 | public void onPlayerDeath(PlayerDeathEvent event) { 57 | Player victim = event.getEntity(); 58 | String worldName = victim.getWorld().getName(); 59 | 60 | if (disabled) { 61 | return; 62 | } 63 | 64 | if (disabledWorlds.contains(worldName)) { 65 | return; 66 | } 67 | 68 | Player attacker = event.getEntity().getKiller(); 69 | String attackerName = (attacker != null) ? attacker.getName() : "Unknown"; 70 | String victimName = (victim != null) ? victim.getName() : "Unknown"; 71 | double attackerHealth = (attacker != null) ? attacker.getHealth() : 0.00; 72 | double victimHealth = (victim != null) ? victim.getHealth() : 0.00; 73 | Bukkit.getScheduler().runTaskAsynchronously(Main.getInstance(), () -> { 74 | Bukkit.broadcastMessage(formatColors(Placeholders(attackerName, victimName, attackerHealth, victimHealth))); 75 | }); 76 | } 77 | 78 | private String Placeholders(String attackerName, String victimName, double attackerHealth, double victimHealth) { 79 | String deathMessage = getRandomDeathMessage(); 80 | deathMessage = deathMessage.replace("%attacker%", attackerName); 81 | deathMessage = deathMessage.replace("%victim%", victimName); 82 | deathMessage = deathMessage.replace("%attacker_health%", String.format("%.2f", attackerHealth)); 83 | deathMessage = deathMessage.replace("%victim_health%", String.format("%.2f", victimHealth)); 84 | return deathMessage; 85 | } 86 | 87 | private String getRandomDeathMessage() { 88 | Random random = new Random(); 89 | int index = random.nextInt(deathMessages.size()); 90 | return deathMessages.get(index); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

FFA

2 |

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

13 | 14 | ## Overview 15 | 16 | FFA is a next-generation plugin designed for PvP/FFA servers, offering a robust API and a bunch of features. 17 | 18 | ## Requirements 19 | To use the FFA plugin, you need to use Minecraft version 1.19 or higher, Java version 17 or above, Spigot or any of its forks, and You need PlaceholderAPI to use this plugin. 20 | 21 | # Features 22 | * Arenas System, Includes cool arenas for ranked users. 23 | 24 | * Next Gen Combat Log System 25 | * Customizable Death Messages 26 | * PlaceholderAPI Support 27 | * Guilds (TODO) 28 | * Arena Regeneration 29 | ___ 30 | **How to use this?** 31 | 32 | 1. Make sure to have FastAsyncWorldEdit installed on your server. 33 | 2. Use the command `/regeneration create MyArena`. 34 | 3. Set the corners of the arena via `/regeneration corner1` and `/regeneration corner2`. 35 | 4. Finally, use the command `/regeneration start MyArena`. 36 | 5. You're done! You can now use `/regeneration regenerate MyArena`. 37 | ___ 38 | * Multi Worlds (TODO) 39 | * Advanced Kit System 40 | * Next Generation Settings Menu 41 | * Spawn/Lobby Items 42 | * Advance Stats System, with a feature where adminstrators can edit player's stats 43 | * WorldGuard Integration 44 | * Health Indicators 45 | * Quick Respawn 46 | * LaunchPads, And More 47 | 48 | ## Addon(s) 49 | * Kit Layouts - Let your server's players save a custom kit layout for a kit (recommended for practice servers). **$2.99** 50 | ____ 51 | 52 | ### Necessary Commands 53 | - Broadcast 54 | - Fly 55 | - Heal 56 | - Message 57 | - Reply 58 | - Nickname 59 | - Ping 60 | - Rules 61 | - Settings, Yes there are even more which are not listed here. 62 | ___ 63 | 64 | Everything is editable via the `config.yml` file. 65 | 66 | ## Placeholders 67 | - %ffa_kills% | Returns the kills of a player. 68 | - %ffa_deaths% | Returns the deaths of a player. 69 | - %ffa_kdr% | Returns the KDR of a player. 70 | - %ffa_streak% | Returns the kill streak of a player. 71 | - %ffa_maxstreak% | Returns the max kill streak of a player. 72 | - %ffa_combat_timer% | Returns the combat timer of a player. 73 | - %ffa_nickname% | Returns the nickname of a player. 74 | 75 | ### Utility Placeholders 76 | - %ffa_lastkit% | Returns the name of the last kit the player had. 77 | - %ffa_lastarena% | Returns the name of the last arena the player was in. 78 | - %ffa_player_RegionName% | Returns the player count of the specified WorldGuard region. 79 | - %ffa_isbusy_RegionName% | Checks if the specified WorldGuard region has 8+ players; if yes, return "[Busy]". 80 | - %ffa_settings_olddamagetilt% | Returns the OldDamageTilt setting status of a player. 81 | - %ffa_settings_privatemessages% | Returns the PrivateMessages setting status of a player. 82 | - %ffa_settings_autogg% | Returns the AutoGG setting status of a player. 83 | - %ffa_settings_mentionsound% | Returns the MentionSound setting status of a player. 84 | - %ffa_settings_quickrespawn% | Returns the QuickRespawn setting status of a player. 85 | 86 | ## Reporting Issues 87 | Please feel free to report any glitches or bugs via our [Discord server](https://discord.gg/XBmrFsg5eR). 88 | 89 | ## Download 90 | To get the FFA plugin, Purchase it from our [BuiltByBit](https://builtbybit.com/resources/xyris-ffa.44950/) page. Alternatively, compile it yourself. 91 | 92 | ### License 93 | The FFA plugin is licensed under [GNU General Public License](https://github.com/Darkxx14/FFA?tab=GPL-3.0-1-ov-file) (GPL). 94 | -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | prefix: "&b&lFFA &7|&r " 2 | 3 | # Streak settings 4 | StreakThreshold: 5 5 | StreakLoseThreshold: 5 6 | StreakMessage: 7 | - " " 8 | - "&a%player% &7reached a kill streak of &a%streak%&7!" 9 | - " " 10 | StreakLose: 11 | - " " 12 | - "&c%player% &7just lost their kill streak of &c%streak%&7!" 13 | - " " 14 | 15 | # Gameplay settings 16 | chat-formatter: 17 | enabled: true 18 | format: "&7%player%: &f%message%" 19 | armorStandBlocking: true 20 | heal_on_kill: true 21 | disableDeathDrops: true 22 | smoothSpawnTeleport: true 23 | show-ping-on-right-click: 24 | enabled: true 25 | message: "&b%clicked_player% &7has &b%ping%&7ms" 26 | join-message: "&7%player_name% joined." 27 | quit-message: "&7%player_name% left." 28 | launchpad: 29 | force: 1.8 30 | deathMessages: 31 | disabled: false 32 | messages: 33 | - "&c%victim% &7was defeated by &a%attacker% &7(&c%attacker_health%❤&7)" 34 | - "&7You can add more here!" 35 | disabledWorlds: 36 | - "example_world" 37 | 38 | # Quick Respawn settings 39 | quick-respawn: 40 | enabled: true 41 | material: FEATHER 42 | item-name: "&aQuick Respawn" 43 | lore: 44 | - "&7Click to respawn!" 45 | click-action: BOTH 46 | slot: 1 47 | message-type: action bar 48 | message: "&aTeleported to your last location" 49 | 50 | # Healthbar settings 51 | healthbar: 52 | enabled: false 53 | display-name-format: "&#FF7A7A❤" 54 | disabled-worlds: 55 | - spawn 56 | 57 | # Combat Tag settings 58 | combat-tagger: 59 | combat-timer: 10 60 | message-type: action bar 61 | damage-to-enemy: "&7You attacked &b%victim%&7. Do not log out." 62 | damage-from-enemy: "&7You got attacked by &b%attacker%&7. Do not log out." 63 | combat-end: "&7You are no longer in combat." 64 | action-bar: "&7You're in combat for &b%seconds% &7seconds." 65 | disable-commands-message: "&7You cannot use commands while in combat!" 66 | whitelisted_commands: 67 | - msg 68 | - r 69 | 70 | # Blacklisted nicknames 71 | blacklisted-nicknames: 72 | - Fuck 73 | - Dick 74 | - DarkxxIsBad 75 | - XyrisPluginsBad 76 | 77 | # Messages 78 | messages: 79 | no-permission: "&cNo Permission." 80 | teleported-to-spawn: "&7Teleported you to the spawn!" 81 | i-want-to-die: "&cYou have committed suicide." 82 | now-sitting: "&aYou are now sitting." 83 | already-sitting: "&cYou are already sitting." 84 | private-messages-disabled: "&c%player% has their Private Messages disabled." 85 | no-recent-message: "&cYou have not messaged anyone recently." 86 | flightEnabled: "&aYour fly has been enabled." 87 | flightDisabled: "&cYour fly has been disabled." 88 | nick-blacklisted: "&cThis nickname contains blacklisted words." 89 | nick-changed: "&aYour nickname has been set to %nickname%" 90 | nick-cleared: "&aYour nickname has been cleared." 91 | setting_toggle: "&a{setting_name} is now {setting_status}" 92 | kit_gave: "NONE" 93 | warped_to_arena: "NONE" 94 | message_format: 95 | sender: "&7[To %recipient%] &b%message%" 96 | recipient: "&7[From %sender%] &b%message%" 97 | stats: 98 | format: 99 | - " " 100 | - "&b&l%player% &bStats" 101 | - " " 102 | - "&fKills: &b%kills%" 103 | - "&fDeaths: &b%deaths%" 104 | - "&fKDR: &b%kdr%" 105 | - "&fStreak: &b%streak%" 106 | - "&fMax Streak: &b%maxstreak%" 107 | - " " 108 | ping: 109 | format: 110 | - " " 111 | - "&7%player%'s ping is %ping%ms!" 112 | - "&7The ping becomes reliable after being in-game for at least 3 minutes." 113 | - " " 114 | rules: 115 | format: 116 | - " " 117 | - "&b&lServer Rules" 118 | - " " 119 | - "1. Respect other players." 120 | - "2. No cheating or exploiting bugs." 121 | - "3. No spamming or excessive swearing." 122 | - " " 123 | broadcast: 124 | format: 125 | - " " 126 | - "&b&l%player% &bis Broadcasting" 127 | - "&7%message%" 128 | - " " 129 | # Usage Messages 130 | usage: 131 | broadcast: "&cUsage, /broadcast " 132 | heal: "&cUsage, /heal " 133 | message: "&c/message " 134 | nickname: "&cUsage, /nick | /nick clear" 135 | ping: "&cUsage, /ping [playerName]" 136 | reply: "&c/reply " 137 | coolarena: "&cUsage, /coolarena " 138 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/utils/gui/GuiManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of FastInv, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 MrMicky 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package dev.darkxx.ffa.utils.gui; 26 | 27 | import org.bukkit.Bukkit; 28 | import org.bukkit.entity.Player; 29 | import org.bukkit.event.EventHandler; 30 | import org.bukkit.event.Listener; 31 | import org.bukkit.event.inventory.InventoryClickEvent; 32 | import org.bukkit.event.inventory.InventoryCloseEvent; 33 | import org.bukkit.event.inventory.InventoryOpenEvent; 34 | import org.bukkit.event.server.PluginDisableEvent; 35 | import org.bukkit.plugin.Plugin; 36 | 37 | import java.util.Objects; 38 | import java.util.concurrent.atomic.AtomicBoolean; 39 | 40 | public final class GuiManager { 41 | 42 | private static final AtomicBoolean REGISTERED = new AtomicBoolean(false); 43 | 44 | private GuiManager() { 45 | throw new UnsupportedOperationException(); 46 | } 47 | 48 | public static void register(Plugin plugin) { 49 | Objects.requireNonNull(plugin, "plugin"); 50 | 51 | if (REGISTERED.getAndSet(true)) { 52 | throw new IllegalStateException("FFA is already registered"); 53 | } 54 | 55 | Bukkit.getPluginManager().registerEvents(new InventoryListener(plugin), plugin); 56 | } 57 | 58 | public static void closeAll() { 59 | Bukkit.getOnlinePlayers().stream() 60 | .filter(p -> p.getOpenInventory().getTopInventory().getHolder() instanceof GuiBuilder) 61 | .forEach(Player::closeInventory); 62 | } 63 | 64 | public static final class InventoryListener implements Listener { 65 | 66 | private final Plugin plugin; 67 | 68 | public InventoryListener(Plugin plugin) { 69 | this.plugin = plugin; 70 | } 71 | 72 | @EventHandler 73 | public void onInventoryClick(InventoryClickEvent e) { 74 | if (e.getInventory().getHolder() instanceof GuiBuilder && e.getClickedInventory() != null) { 75 | GuiBuilder inv = (GuiBuilder) e.getInventory().getHolder(); 76 | 77 | boolean wasCancelled = e.isCancelled(); 78 | e.setCancelled(true); 79 | 80 | inv.handleClick(e); 81 | 82 | if (!wasCancelled && !e.isCancelled()) { 83 | e.setCancelled(false); 84 | } 85 | } 86 | } 87 | 88 | @EventHandler 89 | public void onInventoryOpen(InventoryOpenEvent e) { 90 | if (e.getInventory().getHolder() instanceof GuiBuilder) { 91 | GuiBuilder inv = (GuiBuilder) e.getInventory().getHolder(); 92 | 93 | inv.handleOpen(e); 94 | } 95 | } 96 | 97 | @EventHandler 98 | public void onInventoryClose(InventoryCloseEvent e) { 99 | if (e.getInventory().getHolder() instanceof GuiBuilder) { 100 | GuiBuilder inv = (GuiBuilder) e.getInventory().getHolder(); 101 | 102 | if (inv.handleClose(e)) { 103 | Bukkit.getScheduler().runTask(this.plugin, () -> inv.open((Player) e.getPlayer())); 104 | } 105 | } 106 | } 107 | 108 | @EventHandler 109 | public void onPluginDisable(PluginDisableEvent e) { 110 | if (e.getPlugin() == this.plugin) { 111 | closeAll(); 112 | 113 | REGISTERED.set(false); 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/spawnitems/Items.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.spawnitems; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.api.events.SpawnItemsGiveEvent; 5 | import net.md_5.bungee.api.ChatColor; 6 | import org.bukkit.Bukkit; 7 | import org.bukkit.Material; 8 | import org.bukkit.NamespacedKey; 9 | import org.bukkit.command.CommandSender; 10 | import org.bukkit.configuration.ConfigurationSection; 11 | import org.bukkit.configuration.file.FileConfiguration; 12 | import org.bukkit.configuration.file.YamlConfiguration; 13 | import org.bukkit.entity.Player; 14 | import org.bukkit.inventory.ItemFlag; 15 | import org.bukkit.inventory.ItemStack; 16 | import org.bukkit.inventory.meta.ItemMeta; 17 | import org.bukkit.persistence.PersistentDataType; 18 | import org.jetbrains.annotations.NotNull; 19 | 20 | import java.io.File; 21 | import java.util.Set; 22 | 23 | import static dev.darkxx.ffa.Main.formatColors; 24 | import static dev.darkxx.ffa.Main.prefix; 25 | import static org.bukkit.Bukkit.getServer; 26 | 27 | public class Items { 28 | private static Main main; 29 | 30 | private static FileConfiguration spawnItemsConfig; 31 | 32 | public Items(Main plugin) { 33 | this.main = plugin; 34 | getServer().getPluginManager().registerEvents(new EventListener(main), main); 35 | loadSpawnItemsConfig(); 36 | } 37 | 38 | public static void giveSpawnItems(Player player) { 39 | ConfigurationSection itemsSection = getSpawnItemsConfig().getConfigurationSection("items"); 40 | if (itemsSection == null || itemsSection.getKeys(false).isEmpty()) { 41 | // no items configured, disable spawn items 42 | return; 43 | } 44 | 45 | Set itemList = itemsSection.getKeys(false); 46 | SpawnItemsGiveEvent spawnItemGevent = new SpawnItemsGiveEvent(player); 47 | Bukkit.getServer().getPluginManager().callEvent(spawnItemGevent); 48 | 49 | if (spawnItemGevent.isCancelled()) { 50 | return; 51 | } 52 | 53 | player.getInventory().clear(); 54 | 55 | for (String itemKey : itemList) { 56 | String path = "items." + itemKey; 57 | String materialName = getSpawnItemsConfig().getString(path + ".item"); 58 | String name = getSpawnItemsConfig().getString(path + ".name"); 59 | int slot = getSpawnItemsConfig().getInt(path + ".slot"); 60 | boolean hideAttributes = getSpawnItemsConfig().getBoolean(path + ".hide-attributes"); 61 | String rightClickCommand = getSpawnItemsConfig().getString(path + ".right-click-command"); 62 | assert materialName != null; 63 | Material material = Material.matchMaterial(materialName); 64 | if (material == null) { 65 | main.getLogger().warning("Invalid material for item " + itemKey + ": " + materialName); 66 | continue; 67 | } 68 | ItemStack itemStack = new ItemStack(material); 69 | ItemMeta meta = itemStack.getItemMeta(); 70 | String formattedName = formatColors(name); 71 | meta.setDisplayName(formattedName); 72 | if (hideAttributes) { 73 | meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES); 74 | } 75 | if (rightClickCommand != null) { 76 | meta.getPersistentDataContainer().set(new NamespacedKey(main, "right-click-command"), PersistentDataType.STRING, rightClickCommand); 77 | } 78 | Bukkit.getScheduler().runTaskLater(main, () -> { 79 | itemStack.setItemMeta(meta); 80 | player.getInventory().setItem(slot, itemStack); 81 | }, 1); 82 | } 83 | } 84 | 85 | public static void sendInvalidCommandMessage(@NotNull CommandSender sender) { 86 | sender.sendMessage(formatColors("\n")); 87 | sender.sendMessage(formatColors("&b&lFFA &8| &7Invalid Command")); 88 | sender.sendMessage(formatColors("\n")); 89 | sender.sendMessage(formatColors("&b• &7/spawnitems reload")); 90 | sender.sendMessage(formatColors("&b• &7/spawnitems give \n")); 91 | sender.sendMessage(formatColors("\n")); 92 | } 93 | 94 | public static void loadSpawnItemsConfig() { 95 | File configFile = new File(main.getDataFolder(), "spawnitems.yml"); 96 | if (!configFile.exists()) { 97 | main.saveResource("spawnitems.yml", false); 98 | } 99 | spawnItemsConfig = YamlConfiguration.loadConfiguration(configFile); 100 | } 101 | 102 | public static FileConfiguration getSpawnItemsConfig() { 103 | return spawnItemsConfig; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/settings/menu/SettingsMenu.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.settings.menu; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.settings.SettingsManager; 5 | import dev.darkxx.ffa.utils.gui.GuiBuilder; 6 | import dev.darkxx.ffa.utils.gui.ItemBuilderGUI; 7 | import org.bukkit.Bukkit; 8 | import org.bukkit.Material; 9 | import org.bukkit.Sound; 10 | import org.bukkit.configuration.file.FileConfiguration; 11 | import org.bukkit.configuration.file.YamlConfiguration; 12 | import org.bukkit.entity.Player; 13 | import org.bukkit.inventory.ItemFlag; 14 | import org.bukkit.inventory.ItemStack; 15 | import org.bukkit.inventory.meta.ItemMeta; 16 | 17 | import java.io.File; 18 | import java.util.List; 19 | import java.util.stream.Collectors; 20 | 21 | import static dev.darkxx.ffa.Main.formatColors; 22 | 23 | public class SettingsMenu extends GuiBuilder { 24 | 25 | public static FileConfiguration settingsConfig; 26 | 27 | static { 28 | try { 29 | File configFile = new File(Main.getInstance().getDataFolder(), "menus/settings_menu.yml"); 30 | if (!configFile.exists()) { 31 | configFile.getParentFile().mkdirs(); 32 | Main.getInstance().saveResource("menus/settings_menu.yml", false); 33 | } 34 | settingsConfig = YamlConfiguration.loadConfiguration(configFile); 35 | } catch (Exception e) { 36 | e.printStackTrace(); 37 | } 38 | } 39 | 40 | public SettingsMenu() { 41 | super(27); 42 | } 43 | 44 | public static GuiBuilder menu(Player player) { 45 | if (settingsConfig == null) { 46 | Bukkit.getLogger().warning("Settings config is not loaded properly."); 47 | return new GuiBuilder(3 * 9, formatColors(settingsConfig.getString("menu.title"))); 48 | } 49 | 50 | GuiBuilder inventory = new GuiBuilder(3 * 9, formatColors(settingsConfig.getString("menu.title"))); 51 | 52 | settingsConfig.getConfigurationSection("menu").getKeys(false).forEach(settingKey -> { 53 | String name = settingsConfig.getString("menu." + settingKey + ".name"); 54 | String material = settingsConfig.getString("menu." + settingKey + ".material"); 55 | int slot = settingsConfig.getInt("menu." + settingKey + ".slot"); 56 | List lore = settingsConfig.getStringList("menu." + settingKey + ".lore"); 57 | 58 | if (material == null) { 59 | return; 60 | } 61 | 62 | try { 63 | Material mat = Material.valueOf(material); 64 | settingItem(inventory, player, settingKey, mat, slot, name, lore); 65 | } catch (IllegalArgumentException e) { 66 | Bukkit.getLogger().warning("Invalid Material value: " + material + " for setting: " + settingKey); 67 | } 68 | }); 69 | 70 | return inventory; 71 | } 72 | 73 | private static void settingItem(GuiBuilder inventory, Player player, String settingKey, Material material, int slot, String name, List lore) { 74 | if (settingsConfig == null) { 75 | Bukkit.getLogger().warning("Settings config is not loaded properly."); 76 | return; 77 | } 78 | 79 | String status = SettingsManager.getSettingStatus(player, settingKey); 80 | List formattedLore = lore.stream() 81 | .map(line -> formatColors(line.replace("%status%", status))) 82 | .collect(Collectors.toList()); 83 | 84 | ItemStack item = new ItemBuilderGUI(material) 85 | .name(formatColors(name)) 86 | .lore(formattedLore.toArray(new String[0])) 87 | .flags(ItemFlag.HIDE_ATTRIBUTES, ItemFlag.HIDE_ENCHANTS) 88 | .build(); 89 | 90 | inventory.setItem(slot, item, p -> { 91 | Bukkit.getScheduler().runTaskAsynchronously(Main.getInstance(), () -> { 92 | SettingsManager.toggleSetting(player, settingKey); 93 | String updatedStatus = SettingsManager.getSettingStatus(player, settingKey); 94 | List updatedLore = lore.stream() 95 | .map(line -> formatColors(line.replace("%status%", updatedStatus))) 96 | .collect(Collectors.toList()); 97 | ItemMeta meta = item.getItemMeta(); 98 | meta.setLore(updatedLore); 99 | item.setItemMeta(meta); 100 | player.getOpenInventory().setItem(slot, item); 101 | player.playSound(player.getLocation(), Sound.UI_LOOM_TAKE_RESULT, 1.0f, 1.0f); 102 | }); 103 | }); 104 | } 105 | 106 | public static FileConfiguration getSettingsConfig() { 107 | return settingsConfig; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/utils/ItemBuilder.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.utils; 2 | 3 | import org.bukkit.Material; 4 | import org.bukkit.enchantments.Enchantment; 5 | import org.bukkit.inventory.ItemFlag; 6 | import org.bukkit.inventory.ItemStack; 7 | import org.bukkit.inventory.meta.ItemMeta; 8 | 9 | import java.util.Arrays; 10 | import java.util.HashMap; 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | /** 15 | * This class provides a builder pattern for creating ItemStacks with specific attributes. 16 | */ 17 | public class ItemBuilder { 18 | 19 | private Material material; 20 | private int amount = 1; 21 | private short data = -1; 22 | private String name; 23 | private List lore; 24 | private Map enchantments; 25 | private ItemFlag[] itemflags; 26 | private Integer customModelData; 27 | 28 | /** 29 | * Constructs a new ItemBuilder instance. 30 | */ 31 | public ItemBuilder() { 32 | } 33 | 34 | /** 35 | * Constructs a new ItemBuilder instance with the specified material. 36 | * 37 | * @param material the material of the item 38 | */ 39 | public ItemBuilder(Material material) { 40 | this.material = material; 41 | } 42 | 43 | /** 44 | * Sets the material of the item. 45 | * 46 | * @param material the material of the item 47 | * @return the ItemBuilder instance 48 | */ 49 | public ItemBuilder setMaterial(Material material) { 50 | this.material = material; 51 | return this; 52 | } 53 | 54 | /** 55 | * Sets the amount of the item. 56 | * 57 | * @param amount the amount of the item 58 | * @return the ItemBuilder instance 59 | */ 60 | public ItemBuilder setAmount(int amount) { 61 | this.amount = amount; 62 | return this; 63 | } 64 | 65 | /** 66 | * Sets the data value of the item. 67 | * 68 | * @param data the data value of the item 69 | * @return the ItemBuilder instance 70 | */ 71 | public ItemBuilder setData(short data) { 72 | this.data = data; 73 | return this; 74 | } 75 | 76 | /** 77 | * Sets the display name of the item. 78 | * 79 | * @param name the display name of the item 80 | * @return the ItemBuilder instance 81 | */ 82 | public ItemBuilder setName(String name) { 83 | this.name = name; 84 | return this; 85 | } 86 | 87 | /** 88 | * Sets the lore of the item. 89 | * 90 | * @param lore the lore of the item 91 | * @return the ItemBuilder instance 92 | */ 93 | public ItemBuilder setLore(String... lore) { 94 | this.lore = Arrays.asList(lore); 95 | return this; 96 | } 97 | 98 | /** 99 | * Adds an enchantment to the item. 100 | * 101 | * @param enchantment the enchantment to add 102 | * @param level the level of the enchantment 103 | * @return the ItemBuilder instance 104 | */ 105 | public ItemBuilder addEnchant(Enchantment enchantment, int level) { 106 | if (enchantments == null) 107 | enchantments = new HashMap<>(); 108 | enchantments.put(enchantment, level); 109 | return this; 110 | } 111 | 112 | /** 113 | * Sets the item flags of the item. 114 | * 115 | * @param flags the item flags to set 116 | * @return the ItemBuilder instance 117 | */ 118 | public ItemBuilder setFlags(ItemFlag... flags) { 119 | itemflags = flags; 120 | return this; 121 | } 122 | 123 | /** 124 | * Sets the custom model data of the item. 125 | * 126 | * @param customModelData the custom model data of the item 127 | * @return the ItemBuilder instance 128 | */ 129 | public ItemBuilder setCustomModelData(Integer customModelData) { 130 | this.customModelData = customModelData; 131 | return this; 132 | } 133 | 134 | /** 135 | * Sets minimal attributes for the item (empty name, lore, and all item flags). 136 | * 137 | * @return the ItemBuilder instance 138 | */ 139 | public ItemBuilder minimal() { 140 | setName(""); 141 | setLore(""); 142 | setFlags(ItemFlag.values()); 143 | return this; 144 | } 145 | 146 | /** 147 | * Builds the ItemStack with the specified attributes. 148 | * 149 | * @return the constructed ItemStack 150 | */ 151 | public ItemStack build() { 152 | ItemStack is = new ItemStack(material, amount); 153 | if (data != -1) 154 | is.setDurability(data); 155 | ItemMeta meta = is.getItemMeta(); 156 | if (name != null) 157 | meta.setDisplayName(name); 158 | if (lore != null) 159 | meta.setLore(lore); 160 | if (enchantments != null) 161 | enchantments.forEach((enchantment, level) -> meta.addEnchant(enchantment, level, true)); 162 | if (itemflags != null) 163 | meta.addItemFlags(itemflags); 164 | if (customModelData != null) 165 | meta.setCustomModelData(customModelData); 166 | is.setItemMeta(meta); 167 | return is; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/commands/NickCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.commands; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.api.events.NicknameClearEvent; 5 | import dev.darkxx.ffa.api.events.NicknameSetEvent; 6 | import org.bukkit.Bukkit; 7 | import org.bukkit.command.Command; 8 | import org.bukkit.command.CommandExecutor; 9 | import org.bukkit.command.CommandSender; 10 | import org.bukkit.configuration.file.FileConfiguration; 11 | import org.bukkit.configuration.file.YamlConfiguration; 12 | import org.bukkit.entity.Player; 13 | import org.bukkit.scheduler.BukkitRunnable; 14 | import org.jetbrains.annotations.NotNull; 15 | 16 | import java.io.File; 17 | import java.io.IOException; 18 | import java.util.List; 19 | import java.util.UUID; 20 | 21 | import static dev.darkxx.ffa.Main.formatColors; 22 | 23 | public class NickCommand implements CommandExecutor { 24 | 25 | private final Main main; 26 | private final File configFile; 27 | private static FileConfiguration dataConfig; 28 | private final List blacklist; 29 | 30 | public NickCommand(Main main) { 31 | this.main = main; 32 | this.configFile = new File(main.getDataFolder(), "/data/nickname-data.yml"); 33 | dataConfig = YamlConfiguration.loadConfiguration(configFile); 34 | this.blacklist = main.getConfig().getStringList("blacklisted-nicknames"); 35 | } 36 | 37 | @Override 38 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, String[] args) { 39 | if (!(sender instanceof Player)) { 40 | return true; 41 | } 42 | 43 | Player player = (Player) sender; 44 | 45 | if (!player.hasPermission("ffa.commands.nickname")) { 46 | String noPermission = Main.getInstance().getConfig().getString("messages.no-permission", "&cNo Permission."); 47 | sender.sendMessage(formatColors(noPermission)); 48 | return true; 49 | } 50 | 51 | if (args.length == 0) { 52 | String nickCmdUsage = Main.getInstance().getConfig().getString("usage.nickname", "&cUsage, /nick | /nick clear"); 53 | player.sendMessage(formatColors(nickCmdUsage)); 54 | return true; 55 | } 56 | 57 | if (args[0].equalsIgnoreCase("clear")) { 58 | clearNickname(player); 59 | return true; 60 | } 61 | 62 | String nickname = args[0]; 63 | if (isBlacklisted(nickname)) { 64 | String nickBlacklisted = Main.getInstance().getConfig().getString("messages.nick-blacklisted", "&cThis nickname contains blacklisted words."); 65 | player.sendMessage(formatColors(nickBlacklisted)); 66 | return true; 67 | } 68 | String nickChanged = Main.getInstance().getConfig().getString("messages.nick-changed", "&aYour nickname has been set to %nickname%").replace("%nickname%", nickname); 69 | player.sendMessage(formatColors(nickChanged)); 70 | saveNickname(player.getUniqueId(), nickname); 71 | 72 | return true; 73 | } 74 | 75 | private void saveNickname(UUID playerId, String nickname) { 76 | NicknameSetEvent setEvent = new NicknameSetEvent(playerId, nickname); 77 | Bukkit.getServer().getPluginManager().callEvent(setEvent); 78 | if (setEvent.isCancelled()) { 79 | return; 80 | } 81 | dataConfig.set(playerId.toString(), nickname); 82 | try { 83 | dataConfig.save(configFile); 84 | } catch (IOException e) { 85 | main.getLogger().warning("Could not save nickname data to nickname-data.yml " + e.getMessage()); 86 | } 87 | } 88 | 89 | public static String getNickname(Player player) { 90 | String nickname = dataConfig.getString(player.getUniqueId().toString()); 91 | return nickname != null ? nickname : player.getName(); 92 | } 93 | 94 | private void clearNickname(Player player) { 95 | NicknameClearEvent clearEvent = new NicknameClearEvent(player); 96 | Bukkit.getServer().getPluginManager().callEvent(clearEvent); 97 | if (clearEvent.isCancelled()) { 98 | return; 99 | } 100 | player.setDisplayName(player.getName()); 101 | String nickCleared = Main.getInstance().getConfig().getString("messages.nick-cleared", "&aYour nickname has been cleared."); 102 | player.sendMessage(formatColors(nickCleared)); 103 | dataConfig.set(player.getUniqueId().toString(), null); 104 | try { 105 | dataConfig.save(configFile); 106 | } catch (IOException e) { 107 | main.getLogger().warning("Could not save nickname data to nickname-data.yml " + e.getMessage()); 108 | } 109 | } 110 | 111 | private boolean isBlacklisted(String nickname) { 112 | for (String word : blacklist) { 113 | if (nickname.toLowerCase().contains(word.toLowerCase())) { 114 | return true; 115 | } 116 | } 117 | return false; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/lobby/SpawnManager.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.lobby; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.api.events.TeleportToSpawnEvent; 5 | import dev.darkxx.ffa.settings.SettingsManager; 6 | import dev.darkxx.ffa.spawnitems.Items; 7 | import dev.darkxx.ffa.utils.MiscListener; 8 | import org.bukkit.Bukkit; 9 | import org.bukkit.Location; 10 | import org.bukkit.World; 11 | import org.bukkit.configuration.file.FileConfiguration; 12 | import org.bukkit.configuration.file.YamlConfiguration; 13 | import org.bukkit.entity.Player; 14 | import org.bukkit.event.EventHandler; 15 | import org.bukkit.event.Listener; 16 | import org.bukkit.event.entity.PlayerDeathEvent; 17 | import org.bukkit.event.player.PlayerJoinEvent; 18 | import org.bukkit.inventory.ItemStack; 19 | import org.bukkit.potion.PotionEffect; 20 | import org.bukkit.potion.PotionEffectType; 21 | 22 | import java.io.File; 23 | import java.io.IOException; 24 | 25 | import static dev.darkxx.ffa.Main.formatColors; 26 | import static dev.darkxx.ffa.Main.prefix; 27 | import static dev.darkxx.ffa.utils.MiscListener.createQuickRespawnItem; 28 | 29 | public class SpawnManager implements Listener { 30 | 31 | private static final Main main = Main.getInstance(); 32 | private static final FileConfiguration spawnConfig = YamlConfiguration.loadConfiguration(new File(main.getDataFolder(), "arenas/spawn.yml")); 33 | 34 | public SpawnManager() { 35 | main.getServer().getPluginManager().registerEvents(this, main); 36 | File spawnFile = new File(main.getDataFolder(), "arenas/spawn.yml"); 37 | if (!spawnFile.exists()) { 38 | main.saveResource("arenas/spawn.yml", false); 39 | } 40 | } 41 | 42 | public void setSpawn(Player player) { 43 | Location location = player.getLocation(); 44 | spawnConfig.set("spawn.world", location.getWorld().getName()); 45 | spawnConfig.set("spawn.x", location.getX()); 46 | spawnConfig.set("spawn.y", location.getY()); 47 | spawnConfig.set("spawn.z", location.getZ()); 48 | spawnConfig.set("spawn.yaw", location.getYaw()); 49 | spawnConfig.set("spawn.pitch", location.getPitch()); 50 | saveSpawnConfig(); 51 | player.sendMessage(formatColors(prefix + "&7Spawn point has been successfully set.")); 52 | } 53 | 54 | public static void teleportToSpawn(Player p) { 55 | String worldName = spawnConfig.getString("spawn.world"); 56 | if (worldName != null) { 57 | World world = p.getServer().getWorld(worldName); 58 | double x = spawnConfig.getDouble("spawn.x"); 59 | double y = spawnConfig.getDouble("spawn.y"); 60 | double z = spawnConfig.getDouble("spawn.z"); 61 | float yaw = (float) spawnConfig.getDouble("spawn.yaw"); 62 | float pitch = (float) spawnConfig.getDouble("spawn.pitch"); 63 | Location tspawnLocation = new Location(world, x, y, z, yaw, pitch); 64 | TeleportToSpawnEvent spawnTpEvent = new TeleportToSpawnEvent(p, tspawnLocation); 65 | Bukkit.getServer().getPluginManager().callEvent(spawnTpEvent); 66 | if (spawnTpEvent.isCancelled()) { 67 | return; 68 | } 69 | p.teleport(tspawnLocation); 70 | MiscListener.heal(p); 71 | Items.giveSpawnItems(p); 72 | if (main.getConfig().getBoolean("smoothSpawnTeleport")) { 73 | Bukkit.getScheduler().runTaskLater(main, () -> { 74 | p.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 8, 255, false, false)); 75 | p.addPotionEffect(new PotionEffect(PotionEffectType.DARKNESS, 8, 255, false, false)); 76 | }, 2); 77 | } 78 | } 79 | } 80 | 81 | @EventHandler 82 | public void onPlayerJoin(PlayerJoinEvent event) { 83 | Player player = event.getPlayer(); 84 | MiscListener.heal(player); 85 | teleportToSpawn(player); 86 | Items.giveSpawnItems(player); 87 | } 88 | 89 | @EventHandler 90 | public void onPlayerDeath(PlayerDeathEvent event) { 91 | Player player = event.getEntity(); 92 | ItemStack quickRespawnItem = createQuickRespawnItem(); 93 | MiscListener.heal(player); 94 | teleportToSpawn(player); 95 | Items.giveSpawnItems(player); 96 | boolean quickRespawnEnabled = main.getConfig().getBoolean("quick-respawn.enabled"); 97 | int quickRespawnSlot = main.getConfig().getInt("quick-respawn.slot"); 98 | if (SettingsManager.hasEnabledSetting(player, "toggleQuickRespawn")) { 99 | if (quickRespawnEnabled) { 100 | if (quickRespawnItem != null) { 101 | Bukkit.getScheduler().runTaskLater(main, () -> { 102 | MiscListener.giveQuickRespawn(player, quickRespawnItem, quickRespawnSlot); 103 | }, 2); 104 | } else { 105 | player.sendMessage(formatColors("&cFailed to create quick respawn item. Please check your configuration.")); 106 | } 107 | } 108 | } 109 | } 110 | 111 | private void saveSpawnConfig() { 112 | try { 113 | spawnConfig.save(new File(main.getDataFolder(), "arenas/spawn.yml")); 114 | } catch (IOException e) { 115 | main.getLogger().warning("Could not save spawn config to file."); 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/settings/SettingsManager.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.settings; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.settings.menu.SettingsMenu; 5 | import org.bukkit.configuration.ConfigurationSection; 6 | import org.bukkit.configuration.file.FileConfiguration; 7 | import org.bukkit.configuration.file.YamlConfiguration; 8 | import org.bukkit.entity.Player; 9 | 10 | import java.io.File; 11 | import java.io.IOException; 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | public class SettingsManager { 16 | 17 | private static final Main main; 18 | private static File configFile; 19 | private static FileConfiguration config; 20 | 21 | static { 22 | main = Main.getInstance(); 23 | configFile = new File(main.getDataFolder(), "data/settings-data.yml"); 24 | if (!configFile.getParentFile().exists()) { 25 | configFile.getParentFile().mkdirs(); 26 | } 27 | if (!configFile.exists()) { 28 | try { 29 | configFile.createNewFile(); 30 | main.saveResource("data/settings-data.yml", false); 31 | } catch (IOException e) { 32 | e.printStackTrace(); 33 | } 34 | } 35 | config = YamlConfiguration.loadConfiguration(configFile); 36 | } 37 | 38 | public static boolean hasEnabledSetting(Player player, String settingName) { 39 | ConfigurationSection playerSettings = config.getConfigurationSection("players." + player.getUniqueId()); 40 | if (playerSettings == null) { 41 | return false; 42 | } 43 | return playerSettings.getBoolean(settingName, false); 44 | } 45 | 46 | public static void toggleSetting(Player player, String settingName) { 47 | String playerUUID = player.getUniqueId().toString(); 48 | ConfigurationSection playerSettings = config.getConfigurationSection("players." + playerUUID); 49 | if (playerSettings == null) { 50 | playerSettings = config.createSection("players." + playerUUID); 51 | } 52 | boolean currentValue = playerSettings.getBoolean(settingName, false); 53 | playerSettings.set(settingName, !currentValue); 54 | saveConfig(); 55 | } 56 | 57 | public static void setSettingValue(Player player, String settingName, boolean value) { 58 | String playerUUID = player.getUniqueId().toString(); 59 | ConfigurationSection playerSettings = config.getConfigurationSection("players." + playerUUID); 60 | if (playerSettings == null) { 61 | playerSettings = config.createSection("players." + playerUUID); 62 | } 63 | playerSettings.set(settingName, value); 64 | saveConfig(); 65 | } 66 | 67 | public static void ensurePlayerSettings(Player player) { 68 | String playerUUID = player.getUniqueId().toString(); 69 | ConfigurationSection playerSettings = config.getConfigurationSection("players." + playerUUID); 70 | if (playerSettings == null) { 71 | playerSettings = config.createSection("players." + playerUUID); 72 | addDefaultSettings(playerSettings); 73 | saveConfig(); 74 | } else { 75 | addMissingSettings(playerSettings); 76 | } 77 | } 78 | 79 | private static void addDefaultSettings(ConfigurationSection playerSettings) { 80 | List settingsToAdd = Arrays.asList("OldDamageTilt", "privateMessages", "autoGG", "mentionSound", "toggleQuickRespawn"); 81 | for (String setting : settingsToAdd) { 82 | if (setting.equals("autoGG") || setting.equals("mentionSound")) { 83 | playerSettings.set(setting, false); 84 | } else { 85 | playerSettings.set(setting, true); 86 | } 87 | } 88 | } 89 | 90 | private static void addMissingSettings(ConfigurationSection playerSettings) { 91 | List settingsToAdd = Arrays.asList("OldDamageTilt", "privateMessages", "autoGG", "mentionSound", "toggleQuickRespawn"); 92 | for (String setting : settingsToAdd) { 93 | if (!playerSettings.contains(setting)) { 94 | if (setting.equals("autoGG") || setting.equals("mentionSound")) { 95 | playerSettings.set(setting, false); 96 | } else { 97 | playerSettings.set(setting, true); 98 | } 99 | } 100 | } 101 | saveConfig(); 102 | } 103 | 104 | public static String getSettingStatus(Player player, String settingName) { 105 | boolean isEnabled = hasEnabledSetting(player, settingName); 106 | String enabled = SettingsMenu.getSettingsConfig().getString("menu.placeholders.enabled"); 107 | String disabled = SettingsMenu.getSettingsConfig().getString("menu.placeholders.disabled"); 108 | 109 | return isEnabled ? Main.formatColors(enabled) : Main.formatColors(disabled); 110 | } 111 | 112 | public static String getUnformattedSettingStatus(Player player, String settingName) { 113 | boolean isEnabled = hasEnabledSetting(player, settingName); 114 | return isEnabled ? "Enabled" : "Disabled"; 115 | } 116 | 117 | private static void saveConfig() { 118 | try { 119 | config.save(configFile); 120 | } catch (IOException e) { 121 | main.getLogger().warning("Could not save settings data file " + e.getMessage()); 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/regeneration/command/RegenerationCommand.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.regeneration.command; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.regeneration.RegenerationImpl; 5 | import org.bukkit.Location; 6 | import org.bukkit.command.Command; 7 | import org.bukkit.command.CommandExecutor; 8 | import org.bukkit.command.CommandSender; 9 | import org.bukkit.command.TabCompleter; 10 | import org.bukkit.entity.Player; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.jetbrains.annotations.Nullable; 13 | 14 | import java.util.Arrays; 15 | import java.util.List; 16 | import java.util.stream.Collectors; 17 | 18 | import static dev.darkxx.ffa.Main.formatColors; 19 | import static dev.darkxx.ffa.Main.prefix; 20 | 21 | public class RegenerationCommand implements CommandExecutor, TabCompleter { 22 | private static final List ACTIONS = Arrays.asList("create", "delete", "start", "corner1", "corner2", "regenerate"); 23 | 24 | @Override 25 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, @NotNull String[] args) { 26 | if (!(sender instanceof Player) && !sender.hasPermission("ffa.admin")) { 27 | String noPermission = Main.getInstance().getConfig().getString("messages.no-permission", "&cNo Permission."); 28 | sender.sendMessage(formatColors(noPermission)); 29 | return true; 30 | } 31 | 32 | if (args.length == 0) { 33 | RegenerationImpl.sendInvalidCommandMessage(sender); 34 | return true; 35 | } 36 | 37 | String action = args[0].toLowerCase(); 38 | String arenaName = args.length > 1 ? args[1] : null; 39 | 40 | if (!ACTIONS.contains(action)) { 41 | RegenerationImpl.sendInvalidCommandMessage(sender); 42 | return true; 43 | } 44 | 45 | RegenerationImpl arena = RegenerationImpl.arena(arenaName); 46 | 47 | switch (action) { 48 | case "create": 49 | if (arena != null) { 50 | sender.sendMessage(Main.formatColors(prefix + "&7An arena with that name already exists.")); 51 | return true; 52 | } 53 | arena = new RegenerationImpl(arenaName, null, null); 54 | arena.save(); 55 | RegenerationImpl.saveAll(); 56 | RegenerationImpl.loadAll(); 57 | RegenerationImpl.arenas().add(arena); 58 | sender.sendMessage(Main.formatColors(prefix + "&7Arena " + arenaName + " has been successfully created.")); 59 | break; 60 | case "delete": 61 | if (arena == null) { 62 | sender.sendMessage(Main.formatColors(prefix + "&7Arena not found.")); 63 | return true; 64 | } 65 | 66 | arena.delete(); 67 | sender.sendMessage(Main.formatColors(prefix + "&7Arena " + arenaName + " deleted.")); 68 | break; 69 | case "corner1": 70 | case "corner2": 71 | if (!(sender instanceof Player)) { 72 | sender.sendMessage(Main.formatColors(prefix + "&7This command can only be executed by players.")); 73 | return true; 74 | } 75 | 76 | Player player = (Player) sender; 77 | Location playerLocation = player.getLocation(); 78 | 79 | if (arena == null) { 80 | sender.sendMessage(Main.formatColors(prefix + "&7Arena not found.")); 81 | return true; 82 | } 83 | 84 | if (action.equals("corner1")) { 85 | arena.corner1(playerLocation); 86 | } else { 87 | arena.corner2(playerLocation); 88 | } 89 | 90 | arena.save(); 91 | sender.sendMessage(Main.formatColors(prefix + "&7Corner " + action.substring(6) + " set successfully.")); 92 | break; 93 | case "start": 94 | if (arena == null) { 95 | sender.sendMessage(Main.formatColors(prefix + "&7Arena not found.")); 96 | return true; 97 | } 98 | 99 | arena.load(); 100 | if (arena.corner1() != null && arena.corner2() != null) { 101 | arena.saveSchematic(); 102 | arena.start(); 103 | sender.sendMessage(Main.formatColors(prefix + "&7Regeneration started.")); 104 | } else { 105 | sender.sendMessage(Main.formatColors(prefix + "&7Regeneration failed to start. You need to have both corner1 and corner2 set.")); 106 | } 107 | break; 108 | case "regenerate": 109 | if (arena == null) { 110 | sender.sendMessage(Main.formatColors(prefix + "&7Arena not found.")); 111 | return true; 112 | } 113 | 114 | arena.load(); 115 | arena.regenerate(); 116 | sender.sendMessage(Main.formatColors(prefix + "&7Arena " + arenaName + " has been regenerated.")); 117 | break; 118 | } 119 | return true; 120 | } 121 | 122 | @Nullable 123 | @Override 124 | public List onTabComplete(@NotNull CommandSender sender, @NotNull Command cmd, @NotNull String label, @NotNull String[] args) { 125 | if (args.length == 1) { 126 | return ACTIONS; 127 | } else if (args.length == 2) { 128 | return RegenerationImpl.arenas().stream().map(RegenerationImpl::name).collect(Collectors.toList()); 129 | } else { 130 | return null; 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/stats/StatsManager.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.stats; 2 | 3 | import dev.darkxx.ffa.DatabaseManager; 4 | import java.sql.Connection; 5 | import java.sql.PreparedStatement; 6 | import java.sql.ResultSet; 7 | import java.sql.SQLException; 8 | import java.util.UUID; 9 | import java.util.concurrent.ConcurrentHashMap; 10 | import java.util.concurrent.ConcurrentMap; 11 | import org.bukkit.Bukkit; 12 | import org.bukkit.entity.Player; 13 | 14 | public class StatsManager { 15 | private static final Connection connection = DatabaseManager.getConnection(); 16 | private static final ConcurrentMap cache = new ConcurrentHashMap<>(); 17 | 18 | public static void addKills(Player player, int killsToAdd) { 19 | UUID uuid = player.getUniqueId(); 20 | StatsManager.PlayerStats stats = cache.computeIfAbsent(uuid, StatsManager::load); 21 | stats.kills += killsToAdd; 22 | } 23 | 24 | public static void addDeaths(Player player, int deathsToAdd) { 25 | UUID uuid = player.getUniqueId(); 26 | StatsManager.PlayerStats stats = cache.computeIfAbsent(uuid, StatsManager::load); 27 | stats.deaths += deathsToAdd; 28 | } 29 | 30 | public static void updateKillStreak(Player player, int newKillStreak) { 31 | UUID uuid = player.getUniqueId(); 32 | StatsManager.PlayerStats stats = cache.computeIfAbsent(uuid, StatsManager::load); 33 | stats.killStreak = newKillStreak; 34 | if (newKillStreak > stats.maxKillStreak) { 35 | stats.maxKillStreak = newKillStreak; 36 | } 37 | } 38 | 39 | public static void updateMaxKillStreak(Player player, int newMaxKillStreak) { 40 | UUID uuid = player.getUniqueId(); 41 | cache.computeIfAbsent(uuid, StatsManager::load).maxKillStreak = newMaxKillStreak; 42 | } 43 | 44 | public static int getCurrentKills(UUID playerUUID) { 45 | return cache.computeIfAbsent(playerUUID, StatsManager::load).kills; 46 | } 47 | 48 | public static int getCurrentDeaths(UUID playerUUID) { 49 | return cache.computeIfAbsent(playerUUID, StatsManager::load).deaths; 50 | } 51 | 52 | public static double calculateKDR(UUID playerUUID) { 53 | StatsManager.PlayerStats stats = cache.computeIfAbsent(playerUUID, StatsManager::load); 54 | return stats.deaths == 0 ? (double) stats.kills : Double.parseDouble(String.format("%.2f", (double) stats.kills / (double) stats.deaths)); 55 | } 56 | 57 | public static int getCurrentStreak(UUID playerUUID) { 58 | return cache.computeIfAbsent(playerUUID, StatsManager::load).killStreak; 59 | } 60 | 61 | public static int getHighestStreak(UUID playerUUID) { 62 | return cache.computeIfAbsent(playerUUID, StatsManager::load).maxKillStreak; 63 | } 64 | 65 | public static void editKills(UUID playerUUID, int newKills) { 66 | cache.computeIfAbsent(playerUUID, StatsManager::load).kills = newKills; 67 | } 68 | 69 | public static void editDeaths(UUID playerUUID, int newDeaths) { 70 | cache.computeIfAbsent(playerUUID, StatsManager::load).deaths = newDeaths; 71 | } 72 | 73 | public static void editStreak(UUID playerUUID, int newStreak) { 74 | cache.computeIfAbsent(playerUUID, StatsManager::load).killStreak = newStreak; 75 | } 76 | 77 | public static void editHighestStreak(UUID playerUUID, int newHighestStreak) { 78 | cache.computeIfAbsent(playerUUID, StatsManager::load).maxKillStreak = newHighestStreak; 79 | } 80 | 81 | public static void save(UUID playerUUID) { 82 | StatsManager.PlayerStats stats = cache.get(playerUUID); 83 | if (stats == null) return; 84 | 85 | try { 86 | PreparedStatement statement = connection.prepareStatement( 87 | "INSERT INTO player_stats (uuid, kills, deaths, kill_streak, max_kill_streak) VALUES (?, ?, ?, ?, ?) " + 88 | "ON CONFLICT(uuid) DO UPDATE SET kills = ?, deaths = ?, kill_streak = ?, max_kill_streak = ?"); 89 | 90 | statement.setString(1, playerUUID.toString()); 91 | statement.setInt(2, stats.kills); 92 | statement.setInt(3, stats.deaths); 93 | statement.setInt(4, stats.killStreak); 94 | statement.setInt(5, stats.maxKillStreak); 95 | statement.setInt(6, stats.kills); 96 | statement.setInt(7, stats.deaths); 97 | statement.setInt(8, stats.killStreak); 98 | statement.setInt(9, stats.maxKillStreak); 99 | statement.executeUpdate(); 100 | statement.close(); 101 | } catch (SQLException e) { 102 | handleSQLException("Failed to save stats for player " + playerUUID, e); 103 | } 104 | } 105 | 106 | public static void saveAll() { 107 | cache.forEach((uuid, stats) -> save(uuid)); 108 | } 109 | 110 | public static StatsManager.PlayerStats load(UUID playerUUID) { 111 | StatsManager.PlayerStats stats = new StatsManager.PlayerStats(); 112 | 113 | try { 114 | PreparedStatement statement = connection.prepareStatement( 115 | "SELECT kills, deaths, kill_streak, max_kill_streak FROM player_stats WHERE uuid = ?"); 116 | 117 | statement.setString(1, playerUUID.toString()); 118 | ResultSet resultSet = statement.executeQuery(); 119 | 120 | if (resultSet.next()) { 121 | stats.kills = resultSet.getInt("kills"); 122 | stats.deaths = resultSet.getInt("deaths"); 123 | stats.killStreak = resultSet.getInt("kill_streak"); 124 | stats.maxKillStreak = resultSet.getInt("max_kill_streak"); 125 | } 126 | 127 | resultSet.close(); 128 | statement.close(); 129 | } catch (SQLException e) { 130 | handleSQLException("Failed to load stats for player " + playerUUID, e); 131 | } 132 | 133 | return stats; 134 | } 135 | 136 | private static void handleSQLException(String message, SQLException e) { 137 | Bukkit.getLogger().severe(message + " " + e.getMessage()); 138 | } 139 | 140 | public static class PlayerStats { 141 | int kills = 0; 142 | int deaths = 0; 143 | int killStreak = 0; 144 | int maxKillStreak = 0; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/utils/gui/ItemBuilderGUI.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of FastInv, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 MrMicky 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package dev.darkxx.ffa.utils.gui; 26 | 27 | import org.bukkit.Color; 28 | import org.bukkit.Material; 29 | import org.bukkit.enchantments.Enchantment; 30 | import org.bukkit.inventory.ItemFlag; 31 | import org.bukkit.inventory.ItemStack; 32 | import org.bukkit.inventory.meta.ItemMeta; 33 | import org.bukkit.inventory.meta.LeatherArmorMeta; 34 | 35 | import java.util.Arrays; 36 | import java.util.Collections; 37 | import java.util.List; 38 | import java.util.Objects; 39 | import java.util.function.Consumer; 40 | 41 | public class ItemBuilderGUI { 42 | 43 | private final ItemStack item; 44 | 45 | public static ItemBuilderGUI copyOf(ItemStack item) { 46 | return new ItemBuilderGUI(item.clone()); 47 | } 48 | 49 | public ItemBuilderGUI(Material material) { 50 | this(new ItemStack(material)); 51 | } 52 | 53 | public ItemBuilderGUI(ItemStack item) { 54 | this.item = Objects.requireNonNull(item, "item"); 55 | } 56 | 57 | public ItemBuilderGUI edit(Consumer function) { 58 | function.accept(this.item); 59 | return this; 60 | } 61 | 62 | public ItemBuilderGUI meta(Consumer metaConsumer) { 63 | return edit(item -> { 64 | ItemMeta meta = item.getItemMeta(); 65 | 66 | if (meta != null) { 67 | metaConsumer.accept(meta); 68 | item.setItemMeta(meta); 69 | } 70 | }); 71 | } 72 | 73 | public ItemBuilderGUI meta(Class metaClass, Consumer metaConsumer) { 74 | return meta(meta -> { 75 | if (metaClass.isInstance(meta)) { 76 | metaConsumer.accept(metaClass.cast(meta)); 77 | } 78 | }); 79 | } 80 | 81 | public ItemBuilderGUI type(Material material) { 82 | return edit(item -> item.setType(material)); 83 | } 84 | 85 | public ItemBuilderGUI data(int data) { 86 | return durability((short) data); 87 | } 88 | 89 | @SuppressWarnings("deprecation") 90 | public ItemBuilderGUI durability(short durability) { 91 | return edit(item -> item.setDurability(durability)); 92 | } 93 | 94 | public ItemBuilderGUI amount(int amount) { 95 | return edit(item -> item.setAmount(amount)); 96 | } 97 | 98 | public ItemBuilderGUI enchant(Enchantment enchantment) { 99 | return enchant(enchantment, 1); 100 | } 101 | 102 | public ItemBuilderGUI enchant(Enchantment enchantment, int level) { 103 | return meta(meta -> meta.addEnchant(enchantment, level, true)); 104 | } 105 | 106 | public ItemBuilderGUI removeEnchant(Enchantment enchantment) { 107 | return meta(meta -> meta.removeEnchant(enchantment)); 108 | } 109 | 110 | public ItemBuilderGUI removeEnchants() { 111 | return meta(m -> m.getEnchants().keySet().forEach(m::removeEnchant)); 112 | } 113 | 114 | public ItemBuilderGUI name(String name) { 115 | return meta(meta -> meta.setDisplayName(name)); 116 | } 117 | 118 | public ItemBuilderGUI lore(String lore) { 119 | return lore(Collections.singletonList(lore)); 120 | } 121 | 122 | public ItemBuilderGUI lore(String... lore) { 123 | return lore(Arrays.asList(lore)); 124 | } 125 | 126 | public ItemBuilderGUI lore(List lore) { 127 | return meta(meta -> meta.setLore(lore)); 128 | } 129 | 130 | public ItemBuilderGUI addLore(String line) { 131 | return meta(meta -> { 132 | List lore = meta.getLore(); 133 | 134 | if (lore == null) { 135 | meta.setLore(Collections.singletonList(line)); 136 | return; 137 | } 138 | 139 | lore.add(line); 140 | meta.setLore(lore); 141 | }); 142 | } 143 | 144 | public ItemBuilderGUI addLore(String... lines) { 145 | return addLore(Arrays.asList(lines)); 146 | } 147 | 148 | public ItemBuilderGUI addLore(List lines) { 149 | return meta(meta -> { 150 | List lore = meta.getLore(); 151 | 152 | if (lore == null) { 153 | meta.setLore(lines); 154 | return; 155 | } 156 | 157 | lore.addAll(lines); 158 | meta.setLore(lore); 159 | }); 160 | } 161 | 162 | public ItemBuilderGUI flags(ItemFlag... flags) { 163 | return meta(meta -> meta.addItemFlags(flags)); 164 | } 165 | 166 | public ItemBuilderGUI flags() { 167 | return flags(ItemFlag.values()); 168 | } 169 | 170 | public ItemBuilderGUI removeFlags(ItemFlag... flags) { 171 | return meta(meta -> meta.removeItemFlags(flags)); 172 | } 173 | 174 | public ItemBuilderGUI removeFlags() { 175 | return removeFlags(ItemFlag.values()); 176 | } 177 | 178 | public ItemBuilderGUI armorColor(Color color) { 179 | return meta(LeatherArmorMeta.class, meta -> meta.setColor(color)); 180 | } 181 | 182 | public ItemStack build() { 183 | return this.item; 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/arenas/ArenaManager.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.arenas; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.api.events.PlayerWarpEvent; 5 | import org.bukkit.Bukkit; 6 | import org.bukkit.Location; 7 | import org.bukkit.World; 8 | import org.bukkit.command.CommandSender; 9 | import org.bukkit.configuration.file.YamlConfiguration; 10 | import org.bukkit.entity.Player; 11 | 12 | import java.io.File; 13 | import java.io.IOException; 14 | import java.util.ArrayList; 15 | import java.util.HashMap; 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | import static dev.darkxx.ffa.Main.formatColors; 20 | import static dev.darkxx.ffa.Main.prefix; 21 | 22 | public class ArenaManager { 23 | public static Map lastArena = new HashMap<>(); 24 | private static final Main main; 25 | public static final File arenasFolder; 26 | 27 | static { 28 | main = Main.getInstance(); 29 | arenasFolder = new File(main.getDataFolder(), "arenas"); 30 | 31 | if (!arenasFolder.exists()) { 32 | arenasFolder.mkdirs(); 33 | } 34 | } 35 | 36 | public static void sendInvalidCommandMessage(CommandSender sender) { 37 | sender.sendMessage("\n"); 38 | sender.sendMessage(formatColors("&b&lFFA &8| &7Invalid Command")); 39 | sender.sendMessage("\n"); 40 | sender.sendMessage(formatColors("&b• &7/ffa arenas create ")); 41 | sender.sendMessage(formatColors("&b• &7/ffa arenas delete ")); 42 | sender.sendMessage(formatColors("&b• &7/ffa arenas warp ")); 43 | sender.sendMessage(formatColors("&b• &7/ffa arenas list")); 44 | sender.sendMessage("\n"); 45 | } 46 | 47 | public static void createArena(CommandSender sender, Player player, String arenaName) { 48 | Location location = player.getLocation(); 49 | File arenaFile = new File(arenasFolder, arenaName + ".yml"); 50 | 51 | if (arenaFile.exists()) { 52 | player.sendMessage(formatColors(prefix + "&7An arena already exists with the name " + arenaName)); 53 | return; 54 | } 55 | 56 | YamlConfiguration config = new YamlConfiguration(); 57 | config.set("location.world", location.getWorld().getName()); 58 | config.set("location.x", location.getX()); 59 | config.set("location.y", location.getY()); 60 | config.set("location.z", location.getZ()); 61 | config.set("location.pitch", location.getPitch()); 62 | config.set("location.yaw", location.getYaw()); 63 | 64 | try { 65 | config.save(arenaFile); 66 | sender.sendMessage(formatColors(prefix + "&7Arena " + arenaName + " created successfully!")); 67 | } catch (IOException e) { 68 | e.printStackTrace(); 69 | } 70 | } 71 | 72 | public static void deleteArena(CommandSender sender, String arenaName) { 73 | File arenaFile = new File(arenasFolder, arenaName + ".yml"); 74 | if (arenaFile.exists()) { 75 | arenaFile.delete(); 76 | sender.sendMessage(formatColors(prefix + "&7Arena " + arenaName + " deleted successfully!")); 77 | } else { 78 | sender.sendMessage(formatColors(prefix + "&7Arena not found " + arenaName)); 79 | } 80 | } 81 | 82 | public static List listArenas() { 83 | List arenaNames = new ArrayList<>(); 84 | File[] files = arenasFolder.listFiles(); 85 | if (files != null) { 86 | for (File file : files) { 87 | String fileName = file.getName(); 88 | if (fileName.endsWith(".yml") && !fileName.equalsIgnoreCase("spawn.yml")) { 89 | arenaNames.add(fileName.replace(".yml", "")); 90 | } 91 | } 92 | } 93 | return arenaNames; 94 | } 95 | 96 | public static void arenasList(CommandSender sender) { 97 | sender.sendMessage(formatColors("\n")); 98 | sender.sendMessage(formatColors("&b&lFFA &8| &7Arenas")); 99 | sender.sendMessage(formatColors("\n")); 100 | 101 | List arenaNames = listArenas(); 102 | for (String arenaName : arenaNames) { 103 | sender.sendMessage(formatColors("&b• &7" + arenaName)); 104 | sender.sendMessage(formatColors("\n")); 105 | } 106 | } 107 | 108 | public static void warp(CommandSender sender, Player playerName, String arenaName) { 109 | if (playerName != null) { 110 | File arenaFile = new File(arenasFolder, arenaName + ".yml"); 111 | if (arenaFile.exists()) { 112 | YamlConfiguration config = YamlConfiguration.loadConfiguration(arenaFile); 113 | String worldName = config.getString("location.world"); 114 | World world = Bukkit.getWorld(worldName); 115 | if (world != null) { 116 | double x = config.getDouble("location.x"); 117 | double y = config.getDouble("location.y"); 118 | double z = config.getDouble("location.z"); 119 | float pitch = (float) config.getDouble("location.pitch"); 120 | float yaw = (float) config.getDouble("location.yaw"); 121 | Location location = new Location(world, x, y, z, yaw, pitch); 122 | PlayerWarpEvent warpevent = new PlayerWarpEvent(sender, playerName, location); 123 | Bukkit.getServer().getPluginManager().callEvent(warpevent); 124 | if (!warpevent.isCancelled()) { 125 | playerName.teleport(location); 126 | lastArena.put(playerName, arenaName); 127 | String warped = main.getConfig().getString("messages.warped_to_arena"); 128 | if (sender != null && !"NONE".equals(warped)) { 129 | assert warped != null; 130 | sender.sendMessage(formatColors(prefix + warped.replace("%player%", playerName.getName()).replace("%arena%", arenaName))); 131 | } 132 | } 133 | } else if (sender != null) { 134 | sender.sendMessage(formatColors(prefix + "&7Arena not found " + arenaName)); 135 | } 136 | } else if (sender != null) { 137 | sender.sendMessage(formatColors(prefix + "&7Arena file not found: " + arenaName)); 138 | } 139 | } else if (sender != null) { 140 | sender.sendMessage(formatColors(prefix + "&7Player not found: " + playerName)); 141 | } 142 | } 143 | } -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/arenas/coolarenas/CoolArenaManager.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.arenas.coolarenas; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.kits.KitManager; 5 | import dev.darkxx.xyriskits.api.XyrisKitsAPI; 6 | import org.bukkit.Bukkit; 7 | import org.bukkit.Location; 8 | import org.bukkit.World; 9 | import org.bukkit.command.CommandSender; 10 | import org.bukkit.configuration.file.YamlConfiguration; 11 | import org.bukkit.entity.Player; 12 | 13 | import java.io.File; 14 | import java.io.IOException; 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | 18 | import static dev.darkxx.ffa.Main.formatColors; 19 | import static dev.darkxx.ffa.Main.prefix; 20 | import static dev.darkxx.ffa.arenas.ArenaManager.lastArena; 21 | import static dev.darkxx.ffa.kits.Kits.getLastKit; 22 | 23 | public class CoolArenaManager { 24 | private static final Main main; 25 | public static final File coolArenasFolder; 26 | 27 | static { 28 | main = Main.getInstance(); 29 | coolArenasFolder = new File(main.getDataFolder(), "arenas/coolarenas"); 30 | 31 | if (!coolArenasFolder.exists()) { 32 | coolArenasFolder.mkdirs(); 33 | } 34 | } 35 | 36 | public static void sendInvalidCommandMessage(CommandSender sender) { 37 | sender.sendMessage("\n"); 38 | sender.sendMessage(formatColors("&b&lFFA &8| &7Invalid Command")); 39 | sender.sendMessage("\n"); 40 | sender.sendMessage(formatColors("&b• &7/ffa coolarenas create ")); 41 | sender.sendMessage(formatColors("&b• &7/ffa coolarenas delete ")); 42 | sender.sendMessage(formatColors("&b• &7/ffa coolarenas warp ")); 43 | sender.sendMessage(formatColors("&b• &7/ffa coolarenas list")); 44 | sender.sendMessage("\n"); 45 | } 46 | 47 | public static void createCa(CommandSender sender, Player player, String arenaName, String kitName) { 48 | Location location = player.getLocation(); 49 | File arenaFile = new File(coolArenasFolder, arenaName + ".yml"); 50 | 51 | if (arenaFile.exists()) { 52 | player.sendMessage(formatColors(prefix + "&7A cool arena already exists with the name " + arenaName)); 53 | return; 54 | } 55 | 56 | YamlConfiguration config = new YamlConfiguration(); 57 | config.set("location.world", location.getWorld().getName()); 58 | config.set("location.x", location.getX()); 59 | config.set("location.y", location.getY()); 60 | config.set("location.z", location.getZ()); 61 | config.set("location.pitch", location.getPitch()); 62 | config.set("location.yaw", location.getYaw()); 63 | config.set("kit", kitName); 64 | try { 65 | config.save(arenaFile); 66 | sender.sendMessage(formatColors(prefix + "&7Cool Arena " + arenaName + " created successfully!")); 67 | } catch (IOException e) { 68 | e.printStackTrace(); 69 | } 70 | } 71 | 72 | public static void deleteCa(CommandSender sender, String arenaName) { 73 | File arenaFile = new File(coolArenasFolder, arenaName + ".yml"); 74 | if (arenaFile.exists()) { 75 | arenaFile.delete(); 76 | sender.sendMessage(formatColors(prefix + "&7Cool Arena " + arenaName + " deleted successfully!")); 77 | } else { 78 | sender.sendMessage(formatColors(prefix + "&7Cool Arena not found " + arenaName)); 79 | } 80 | } 81 | 82 | public static List listCa() { 83 | List arenaNames = new ArrayList<>(); 84 | File[] files = coolArenasFolder.listFiles(); 85 | if (files != null) { 86 | for (File file : files) { 87 | String fileName = file.getName(); 88 | if (fileName.endsWith(".yml") && !fileName.equalsIgnoreCase("spawn.yml")) { 89 | arenaNames.add(fileName.replace(".yml", "")); 90 | } 91 | } 92 | } 93 | return arenaNames; 94 | } 95 | 96 | public static void caArenasList(CommandSender sender) { 97 | sender.sendMessage(formatColors("\n")); 98 | sender.sendMessage(formatColors("&b&lFFA &8| &7CoolArenas")); 99 | sender.sendMessage(formatColors("\n")); 100 | 101 | List arenaNames = listCa(); 102 | for (String arenaName : arenaNames) { 103 | sender.sendMessage(formatColors("&b• &7" + arenaName)); 104 | sender.sendMessage(formatColors("\n")); 105 | } 106 | } 107 | 108 | public static void warp(CommandSender sender, String playerName, String arenaName) { 109 | Player targetPlayer = Bukkit.getPlayerExact(playerName); 110 | File kitsFolder = Main.getKitsFolder(); 111 | if (targetPlayer != null) { 112 | File arenaFile = new File(coolArenasFolder, arenaName + ".yml"); 113 | if (arenaFile.exists()) { 114 | YamlConfiguration config = YamlConfiguration.loadConfiguration(arenaFile); 115 | String worldName = config.getString("location.world"); 116 | World world = Bukkit.getWorld(worldName); 117 | if (world != null) { 118 | double x = config.getDouble("location.x"); 119 | double y = config.getDouble("location.y"); 120 | double z = config.getDouble("location.z"); 121 | float pitch = (float) config.getDouble("location.pitch"); 122 | float yaw = (float) config.getDouble("location.yaw"); 123 | Location location = new Location(world, x, y, z, yaw, pitch); 124 | targetPlayer.teleport(location); 125 | lastArena.put(targetPlayer, arenaName); 126 | if (config.contains("kit")) { 127 | String kitName = config.getString("kit"); 128 | 129 | if (Bukkit.getServer().getPluginManager().isPluginEnabled("XyrisKits")) { 130 | assert kitName != null; 131 | XyrisKitsAPI.getKitsAPI().giveKit(targetPlayer, kitName); 132 | } else { 133 | KitManager.giveKit(targetPlayer, kitName); 134 | } 135 | 136 | } 137 | sender.sendMessage(formatColors(prefix + "&7Warped " + targetPlayer.getName() + " to cool arena " + arenaName)); 138 | } 139 | } else { 140 | sender.sendMessage(formatColors(prefix + "&7Cool Arena not found " + arenaName)); 141 | } 142 | } else { 143 | sender.sendMessage(formatColors(prefix + "&7Player not found " + playerName)); 144 | } 145 | } 146 | } -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/kits/KitManager.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.kits; 2 | 3 | import dev.darkxx.ffa.api.events.KitGiveEvent; 4 | import org.bukkit.Bukkit; 5 | import dev.darkxx.ffa.Main; 6 | import org.bukkit.command.CommandSender; 7 | import org.bukkit.configuration.file.FileConfiguration; 8 | import org.bukkit.configuration.file.YamlConfiguration; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.inventory.ItemStack; 11 | import org.bukkit.potion.PotionEffect; 12 | import org.bukkit.potion.PotionEffectType; 13 | 14 | import java.io.File; 15 | import java.io.IOException; 16 | import java.util.*; 17 | 18 | import static dev.darkxx.ffa.Main.formatColors; 19 | 20 | public class KitManager { 21 | 22 | public static Map lastKit = new HashMap<>(); 23 | 24 | public static void sendInvalidCommandMessage(CommandSender sender) { 25 | sender.sendMessage("\n"); 26 | sender.sendMessage(formatColors("&b&lFFA &8| &7Invalid Command")); 27 | sender.sendMessage("\n"); 28 | sender.sendMessage(formatColors("&b• &7/ffa kits create ")); 29 | sender.sendMessage(formatColors("&b• &7/ffa kits delete ")); 30 | sender.sendMessage(formatColors("&b• &7/ffa kits give ")); 31 | sender.sendMessage(formatColors("&b• &7/ffa kits list")); 32 | sender.sendMessage("\n"); 33 | } 34 | 35 | public static File createKitsFolder() { 36 | File folder = new File(Main.getInstance().getDataFolder(), "kits"); 37 | if (!folder.exists()) { 38 | folder.mkdirs(); 39 | } 40 | return folder; 41 | } 42 | 43 | public static void saveKit(CommandSender sender, String kitName) { 44 | File kitsFolder = createKitsFolder(); 45 | File kitFile = new File(kitsFolder, kitName + ".yml"); 46 | try { 47 | kitFile.createNewFile(); 48 | FileConfiguration kits = YamlConfiguration.loadConfiguration(kitFile); 49 | if (sender instanceof Player) { 50 | Player player = (Player) sender; 51 | 52 | kits.set("inventory", player.getInventory().getContents()); 53 | kits.set("armor", player.getInventory().getArmorContents()); 54 | kits.set("offhand", player.getInventory().getItemInOffHand()); 55 | 56 | Collection activeEffects = player.getActivePotionEffects(); 57 | for (PotionEffect effect : activeEffects) { 58 | kits.set("effects." + effect.getType().getName() + ".duration", effect.getDuration()); 59 | kits.set("effects." + effect.getType().getName() + ".amplifier", effect.getAmplifier()); 60 | } 61 | } 62 | kits.save(kitFile); 63 | } catch (IOException e) { 64 | e.printStackTrace(); 65 | } 66 | } 67 | 68 | public static void deleteKit(String kitName) { 69 | File kitFile = new File(Main.getInstance().getKitsFolder(), kitName + ".yml"); 70 | if (kitFile.exists()) { 71 | kitFile.delete(); 72 | } 73 | } 74 | 75 | public static void giveKit(Player player, String kitName) { 76 | KitGiveEvent kitGiveEvent = new KitGiveEvent(player, kitName); 77 | Bukkit.getServer().getPluginManager().callEvent(kitGiveEvent); 78 | if (kitGiveEvent.isCancelled()) { 79 | return; 80 | } 81 | File kitsFolder = createKitsFolder(); 82 | File kitFile = new File(kitsFolder, kitName + ".yml"); 83 | if (kitFile.exists()) { 84 | try { 85 | FileConfiguration kitConfig = YamlConfiguration.loadConfiguration(kitFile); 86 | List inventory = kitConfig.getList("inventory"); 87 | List armor = kitConfig.getList("armor"); 88 | ItemStack offhand = kitConfig.getItemStack("offhand"); 89 | 90 | if (inventory != null && armor != null) { 91 | 92 | player.getInventory().setContents(((List) inventory).toArray(new ItemStack[0])); 93 | player.getInventory().setArmorContents(((List) armor).toArray(new ItemStack[0])); 94 | player.getInventory().setItemInOffHand(offhand); 95 | player.getActivePotionEffects().clear(); 96 | 97 | if (kitConfig.contains("effects")) { 98 | for (String effectName : kitConfig.getConfigurationSection("effects").getKeys(false)) { 99 | PotionEffectType type = PotionEffectType.getByName(effectName); 100 | if (type != null) { 101 | int duration = kitConfig.getInt("effects." + effectName + ".duration"); 102 | int amplifier = kitConfig.getInt("effects." + effectName + ".amplifier"); 103 | player.addPotionEffect(new PotionEffect(type, duration, amplifier)); 104 | } 105 | } 106 | } 107 | lastKit.put(player, kitName); 108 | } 109 | } catch (Exception e) { 110 | e.printStackTrace(); 111 | player.sendMessage(formatColors("&cAn error occurred while giving the kit.")); 112 | } 113 | } else { 114 | player.sendMessage(formatColors("&cNo kit found.")); 115 | } 116 | } 117 | 118 | public static void listKits(CommandSender sender) { 119 | File kitsFolder = Main.getInstance().getKitsFolder(); 120 | File[] kitFiles = kitsFolder.listFiles(); 121 | if (kitFiles != null) { 122 | sender.sendMessage(formatColors("\n")); 123 | sender.sendMessage(formatColors("&b&lFFA &8| &7Kits")); 124 | sender.sendMessage(formatColors("\n")); 125 | for (File kitFile : kitFiles) { 126 | if (kitFile.isFile()) { 127 | String kitName = kitFile.getName().replace(".yml", ""); 128 | sender.sendMessage(formatColors("&b• &7" + kitName)); 129 | sender.sendMessage(formatColors("\n")); 130 | } 131 | } 132 | } 133 | } 134 | 135 | public static List getKitNames() { 136 | List kitNames = new ArrayList<>(); 137 | File[] kitFiles = Main.getInstance().getKitsFolder().listFiles(); 138 | if (kitFiles != null) { 139 | for (File kitFile : kitFiles) { 140 | if (kitFile.isFile()) { 141 | String kitName = kitFile.getName().replace(".yml", ""); 142 | kitNames.add(kitName); 143 | } 144 | } 145 | } 146 | return kitNames; 147 | } 148 | 149 | public static boolean isKitExisting(String kitName) { 150 | File kitFile = new File(Main.getKitsFolder(), kitName + ".yml"); 151 | return kitFile.exists(); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/utils/gui/GuiBuilder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of FastInv, licensed under the MIT License. 3 | * 4 | * Copyright (c) 2018-2021 MrMicky 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package dev.darkxx.ffa.utils.gui; 26 | 27 | import org.bukkit.Bukkit; 28 | import org.bukkit.Material; 29 | import org.bukkit.entity.Player; 30 | import org.bukkit.event.inventory.InventoryClickEvent; 31 | import org.bukkit.event.inventory.InventoryCloseEvent; 32 | import org.bukkit.event.inventory.InventoryOpenEvent; 33 | import org.bukkit.event.inventory.InventoryType; 34 | import org.bukkit.inventory.Inventory; 35 | import org.bukkit.inventory.InventoryHolder; 36 | import org.bukkit.inventory.ItemStack; 37 | 38 | import java.util.ArrayList; 39 | import java.util.HashMap; 40 | import java.util.List; 41 | import java.util.Map; 42 | import java.util.Objects; 43 | import java.util.function.Consumer; 44 | import java.util.function.Function; 45 | import java.util.function.Predicate; 46 | import java.util.stream.IntStream; 47 | 48 | public class GuiBuilder implements InventoryHolder { 49 | 50 | private final Map> itemHandlers = new HashMap<>(); 51 | private final List> openHandlers = new ArrayList<>(); 52 | private final List> closeHandlers = new ArrayList<>(); 53 | private final List> clickHandlers = new ArrayList<>(); 54 | 55 | private final Inventory inventory; 56 | 57 | private Predicate closeFilter; 58 | 59 | public GuiBuilder(int size) { 60 | this(owner -> Bukkit.createInventory(owner, size)); 61 | } 62 | 63 | public GuiBuilder(int size, String title) { 64 | this(owner -> Bukkit.createInventory(owner, size, title)); 65 | } 66 | 67 | public GuiBuilder(InventoryType type) { 68 | this(owner -> Bukkit.createInventory(owner, type)); 69 | } 70 | 71 | public GuiBuilder(InventoryType type, String title) { 72 | this(owner -> Bukkit.createInventory(owner, type, title)); 73 | } 74 | 75 | public GuiBuilder(Function inventoryFunction) { 76 | Objects.requireNonNull(inventoryFunction, "inventoryFunction"); 77 | Inventory inv = inventoryFunction.apply(this); 78 | 79 | inv.getHolder(); 80 | 81 | this.inventory = inv; 82 | } 83 | 84 | protected void onOpen(InventoryOpenEvent event) { 85 | } 86 | 87 | protected void onClick(InventoryClickEvent event) { 88 | } 89 | 90 | protected void onClose(InventoryCloseEvent event) { 91 | } 92 | 93 | public void addItem(ItemStack item) { 94 | addItem(item, null); 95 | } 96 | 97 | public void addItem(ItemStack item, Consumer handler) { 98 | int slot = this.inventory.firstEmpty(); 99 | if (slot >= 0) { 100 | setItem(slot, item, handler); 101 | } 102 | } 103 | 104 | public void setItem(int slot, ItemStack item) { 105 | setItem(slot, item, null); 106 | } 107 | 108 | public void setItem(int slot, ItemStack item, Consumer handler) { 109 | this.inventory.setItem(slot, item); 110 | 111 | if (handler != null) { 112 | this.itemHandlers.put(slot, handler); 113 | } else { 114 | this.itemHandlers.remove(slot); 115 | } 116 | } 117 | 118 | public void setItems(int slotFrom, int slotTo, ItemStack item) { 119 | setItems(slotFrom, slotTo, item, null); 120 | } 121 | 122 | public void setItems(int slotFrom, int slotTo, ItemStack item, Consumer handler) { 123 | for (int i = slotFrom; i <= slotTo; i++) { 124 | setItem(i, item, handler); 125 | } 126 | } 127 | 128 | public void fillEmptySlots(ItemStack fillerItem) { 129 | for (int i = 0; i < this.inventory.getSize(); i++) { 130 | if (this.inventory.getItem(i) == null || this.inventory.getItem(i).getType() == Material.AIR) { 131 | setItem(i, fillerItem); 132 | } 133 | } 134 | } 135 | 136 | public void setItems(int[] slots, ItemStack item) { 137 | setItems(slots, item, null); 138 | } 139 | 140 | public void setItems(int[] slots, ItemStack item, Consumer handler) { 141 | for (int slot : slots) { 142 | setItem(slot, item, handler); 143 | } 144 | } 145 | 146 | public void removeItem(int slot) { 147 | this.inventory.clear(slot); 148 | this.itemHandlers.remove(slot); 149 | } 150 | 151 | public void removeItems(int... slots) { 152 | for (int slot : slots) { 153 | removeItem(slot); 154 | } 155 | } 156 | 157 | public void setCloseFilter(Predicate closeFilter) { 158 | this.closeFilter = closeFilter; 159 | } 160 | 161 | public void addOpenHandler(Consumer openHandler) { 162 | this.openHandlers.add(openHandler); 163 | } 164 | 165 | 166 | public void addCloseHandler(Consumer closeHandler) { 167 | this.closeHandlers.add(closeHandler); 168 | } 169 | 170 | public void addClickHandler(Consumer clickHandler) { 171 | this.clickHandlers.add(clickHandler); 172 | } 173 | 174 | public void open(Player player) { 175 | player.openInventory(this.inventory); 176 | } 177 | 178 | public int[] getBorders() { 179 | int size = this.inventory.getSize(); 180 | return IntStream.range(0, size).filter(i -> size < 27 || i < 9 181 | || i % 9 == 0 || (i - 8) % 9 == 0 || i > size - 9).toArray(); 182 | } 183 | 184 | public int[] getCorners() { 185 | int size = this.inventory.getSize(); 186 | return IntStream.range(0, size).filter(i -> i < 2 || (i > 6 && i < 10) 187 | || i == 17 || i == size - 18 188 | || (i > size - 11 && i < size - 7) || i > size - 3).toArray(); 189 | } 190 | 191 | @Override 192 | public Inventory getInventory() { 193 | return this.inventory; 194 | } 195 | 196 | void handleOpen(InventoryOpenEvent e) { 197 | onOpen(e); 198 | 199 | this.openHandlers.forEach(c -> c.accept(e)); 200 | } 201 | 202 | boolean handleClose(InventoryCloseEvent e) { 203 | onClose(e); 204 | 205 | this.closeHandlers.forEach(c -> c.accept(e)); 206 | 207 | return this.closeFilter != null && this.closeFilter.test((Player) e.getPlayer()); 208 | } 209 | 210 | void handleClick(InventoryClickEvent e) { 211 | onClick(e); 212 | 213 | this.clickHandlers.forEach(c -> c.accept(e)); 214 | 215 | Consumer clickConsumer = this.itemHandlers.get(e.getRawSlot()); 216 | 217 | if (clickConsumer != null) { 218 | clickConsumer.accept(e); 219 | } 220 | } 221 | } -------------------------------------------------------------------------------- /src/main/java/dev/darkxx/ffa/combat/CombatTagger.java: -------------------------------------------------------------------------------- 1 | package dev.darkxx.ffa.combat; 2 | 3 | import dev.darkxx.ffa.Main; 4 | import dev.darkxx.ffa.api.events.CombatEndEvent; 5 | import dev.darkxx.ffa.api.events.CombatStartEvent; 6 | import dev.darkxx.ffa.utils.ActionBarUtil; 7 | import org.bukkit.Bukkit; 8 | import org.bukkit.configuration.file.FileConfiguration; 9 | import org.bukkit.entity.Player; 10 | import org.bukkit.event.EventHandler; 11 | import org.bukkit.event.EventPriority; 12 | import org.bukkit.event.Listener; 13 | import org.bukkit.event.entity.EntityDamageByEntityEvent; 14 | import org.bukkit.event.entity.PlayerDeathEvent; 15 | import org.bukkit.event.player.PlayerCommandPreprocessEvent; 16 | import org.bukkit.event.player.PlayerQuitEvent; 17 | import org.bukkit.scheduler.BukkitTask; 18 | 19 | import java.util.ArrayList; 20 | import java.util.Iterator; 21 | import java.util.List; 22 | import java.util.Set; 23 | 24 | import static dev.darkxx.ffa.Main.formatColors; 25 | 26 | public class CombatTagger implements Listener { 27 | 28 | private final Main main; 29 | private static final List combatLogs = new ArrayList<>(); 30 | private final int combatLogDurationInSeconds; 31 | private BukkitTask task; 32 | 33 | public CombatTagger(Main main, int combatLogDurationInSeconds) { 34 | this.main = main; 35 | this.combatLogDurationInSeconds = combatLogDurationInSeconds; 36 | this.task = Bukkit.getScheduler().runTaskTimerAsynchronously(main, this::updateCombatLogs, 4L, 8L); 37 | } 38 | 39 | private void updateCombatLogs() { 40 | String actionBarMessage = Main.getInstance().getConfig().getString("combat-tagger.action-bar", "&7You're in combat for &b%seconds% &7seconds."); 41 | for (Iterator iterator = combatLogs.iterator(); iterator.hasNext(); ) { 42 | Combat combatLog = iterator.next(); 43 | 44 | if (combatLog.isExpired()) { 45 | iterator.remove(); 46 | endCombat(combatLog); 47 | continue; 48 | } 49 | int secondsLeft = combatLog.getTimeLeftSeconds() + 1; 50 | String actionBarMessageFormatted = formatColors(actionBarMessage.replace("%seconds%", String.valueOf(secondsLeft))); 51 | combatLog.getPlayers().forEach(player -> { 52 | ActionBarUtil.sendActionBar(player, actionBarMessageFormatted); 53 | player.setExp(Math.min(1.0f, Math.max(0.0f, secondsLeft / (float) combatLog.getDurationSeconds()))); 54 | }); 55 | } 56 | } 57 | 58 | @EventHandler(priority = EventPriority.MONITOR) 59 | public void onPlayerDamage(EntityDamageByEntityEvent event) { 60 | if (event.isCancelled()) return; 61 | if (event.getEntity() instanceof Player && event.getDamager() instanceof Player) { 62 | Player attacker = (Player) event.getDamager(); 63 | Player victim = (Player) event.getEntity(); 64 | startCombat(attacker, victim); 65 | } 66 | } 67 | 68 | @EventHandler 69 | public void onPlayerDeath(PlayerDeathEvent event) { 70 | event.setDroppedExp(0); 71 | getCombatLogs(event.getEntity()).forEach(this::endCombat); 72 | } 73 | 74 | @EventHandler 75 | public void onPlayerQuit(PlayerQuitEvent event) { 76 | Player player = event.getPlayer(); 77 | Combat combatLog = getLastCombatLog(player); 78 | if (combatLog != null) { 79 | Player other = combatLog.getAttacker().equals(player) ? combatLog.getVictim() : combatLog.getAttacker(); 80 | player.setHealth(0); 81 | } 82 | getCombatLogs(player).forEach(this::endCombat); 83 | } 84 | 85 | public void startCombat(Player attacker, Player victim) { 86 | CombatStartEvent combatStartEvent = new CombatStartEvent(attacker, victim); 87 | Bukkit.getServer().getPluginManager().callEvent(combatStartEvent); 88 | if (combatStartEvent.isCancelled()) { 89 | return; 90 | } 91 | Combat combatLog = getCombatLog(attacker, victim); 92 | if (combatLog == null) { 93 | if (getCombatLogs(attacker).isEmpty()) 94 | attacker.sendMessage(formatColors(Main.getInstance().getConfig().getString("combat-tagger.damage-to-enemy", "&7You attacked &b%victim%&7. Do not log out.").replace("%victim%", victim.getName()))); 95 | if (getCombatLogs(victim).isEmpty()) 96 | victim.sendMessage(formatColors(Main.getInstance().getConfig().getString("combat-tagger.damage-from-enemy", "&7You got attacked by &b%attacker%&7. Do not log out.").replace("%attacker%", attacker.getName()))); 97 | combatLogs.add(new Combat(attacker, victim, combatLogDurationInSeconds)); 98 | } else 99 | combatLog.reset(combatLogDurationInSeconds); 100 | } 101 | 102 | public void endCombat(Combat combatLog) { 103 | Set players = combatLog.getPlayers(); 104 | CombatEndEvent combatEndEvent = new CombatEndEvent(players); 105 | Bukkit.getScheduler().runTask(Main.getInstance(), () -> { 106 | Bukkit.getServer().getPluginManager().callEvent(combatEndEvent); 107 | if (combatEndEvent.isCancelled()) { 108 | return; 109 | } 110 | combatLogs.remove(combatLog); 111 | String messageType = Main.getInstance().getConfig().getString("combat-tagger.message-type", "action bar"); 112 | String notInCombatMessage = Main.getInstance().getConfig().getString("combat-tagger.combat-end", "&7You are no longer in combat."); 113 | 114 | combatLog.getPlayers().forEach(player -> { 115 | player.setLevel(0); 116 | player.setExp(0); 117 | 118 | if (messageType.equalsIgnoreCase("action bar")) { 119 | String actionBarMessage = formatColors(notInCombatMessage); 120 | ActionBarUtil.sendActionBar(player, actionBarMessage); 121 | } else { 122 | String chatMessage = formatColors(notInCombatMessage); 123 | player.sendMessage(chatMessage); 124 | } 125 | 126 | Bukkit.getScheduler().runTaskLater(main, () -> { 127 | if (!messageType.equalsIgnoreCase("action bar")) { 128 | String chatMessage = formatColors(notInCombatMessage); 129 | player.sendMessage(chatMessage); 130 | } 131 | }, 3L); 132 | }); 133 | }); 134 | } 135 | 136 | public boolean isInCombat(Player player) { 137 | return !getCombatLogs(player).isEmpty(); 138 | } 139 | 140 | @EventHandler 141 | public void onPlayerCommand(PlayerCommandPreprocessEvent event) { 142 | Player player = event.getPlayer(); 143 | if (isInCombat(player)) { 144 | String command = event.getMessage().split(" ")[0].substring(1); 145 | FileConfiguration config = Main.getInstance().getConfig(); 146 | List whitelistedCommands = config.getStringList("combat-tagger.whitelisted_commands"); 147 | 148 | if (!whitelistedCommands.contains(command)) { 149 | String disableCommands = config.getString("combat-tagger.disable-commands-message", "&7You cannot use commands while in combat!"); 150 | player.sendMessage(formatColors(disableCommands)); 151 | event.setCancelled(true); 152 | } 153 | } 154 | } 155 | 156 | public static List getCombatLogs(Player player) { 157 | return combatLogs.stream().filter(c -> c.getPlayers().contains(player)).toList(); 158 | } 159 | 160 | public Combat getLastCombatLog(Player player) { 161 | List list = getCombatLogs(player); 162 | return list.isEmpty() ? null : list.get(list.size() - 1); 163 | } 164 | 165 | public Combat getCombatLog(Player player1, Player player2) { 166 | return combatLogs.stream().filter(c -> c.getPlayers().contains(player1) && c.getPlayers().contains(player2)).findAny().orElse(null); 167 | } 168 | 169 | public void cancelTask() { 170 | if (task != null) { 171 | task.cancel(); 172 | task = null; 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | # Collect all arguments for the java command; 201 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 202 | # shell script including quotes and variable substitutions, so put them in 203 | # double quotes to make sure that they get re-expanded; and 204 | # * put everything else in single quotes, so that it's not re-expanded. 205 | 206 | set -- \ 207 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 208 | -classpath "$CLASSPATH" \ 209 | org.gradle.wrapper.GradleWrapperMain \ 210 | "$@" 211 | 212 | # Stop when "xargs" is not available. 213 | if ! command -v xargs >/dev/null 2>&1 214 | then 215 | die "xargs is not available" 216 | fi 217 | 218 | # Use "xargs" to parse quoted args. 219 | # 220 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 221 | # 222 | # In Bash we could simply go: 223 | # 224 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 225 | # set -- "${ARGS[@]}" "$@" 226 | # 227 | # but POSIX shell has neither arrays nor command substitution, so instead we 228 | # post-process each arg (as a line of input to sed) to backslash-escape any 229 | # character that might be a shell metacharacter, then use eval to reverse 230 | # that process (while maintaining the separation between arguments), and wrap 231 | # the whole thing up as a single "set" statement. 232 | # 233 | # This will of course break if any of these variables contains a newline or 234 | # an unmatched quote. 235 | # 236 | 237 | eval "set -- $( 238 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 239 | xargs -n1 | 240 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 241 | tr '\n' ' ' 242 | )" '"$@"' 243 | 244 | exec "$JAVACMD" "$@" 245 | --------------------------------------------------------------------------------