From ca157335f9473f9d945faa5f19934b7bc0bae580 Mon Sep 17 00:00:00 2001 From: derrickmehaffy Date: Mon, 6 Apr 2026 17:56:27 -0700 Subject: [PATCH 1/2] feat: add cancellable events, expanded API, and PlaceholderAPI/WiFlow support EventBus Infrastructure: - Add Cancellable interface with cancel reason support - Upgrade EventBus with publishCancellable() for pre-event interception Events (58 classes across 7 modules): - homes: set, delete, teleport, share, unshare, setDefault - warps: set, delete, teleport - spawns: set, delete, teleport - kits: claim, create, delete - moderation: ban, unban, mute, unmute, kick, warn - teleport: TPA send/accept/deny, back, RTP - utility: fly, god, AFK toggle All with cancellable PreEvent + immutable PostEvent record pairs. Public API expanded from 12 to 80+ methods: - Home, Kit, Moderation, Utility sections added - Warp, Spawn, Back, TPA sections expanded - EventBus access: registerEventListener/unregisterEventListener - Manager accessors for advanced plugin use PlaceholderAPI integration (~37 placeholders): - HyperEssentialsExpansion for PAPI (%%essentials_*%%) - WiFlowExpansion for WiFlow ({essentials_*}) - Bridge classes with runtime detection and reflection - Conditional WiFlow compilation in build.gradle --- build.gradle | 17 + .../com/hyperessentials/HyperEssentials.java | 29 + .../api/HyperEssentialsAPI.java | 805 +++++++++++++++++- .../api/events/Cancellable.java | 23 + .../hyperessentials/api/events/EventBus.java | 69 +- .../api/events/homes/HomeDefaultSetEvent.java | 10 + .../events/homes/HomeDefaultSetPreEvent.java | 28 + .../api/events/homes/HomeDeleteEvent.java | 10 + .../api/events/homes/HomeDeletePreEvent.java | 28 + .../api/events/homes/HomeSetEvent.java | 14 + .../api/events/homes/HomeSetPreEvent.java | 41 + .../api/events/homes/HomeShareEvent.java | 11 + .../api/events/homes/HomeSharePreEvent.java | 32 + .../api/events/homes/HomeTeleportEvent.java | 11 + .../events/homes/HomeTeleportPreEvent.java | 32 + .../api/events/homes/HomeUnshareEvent.java | 11 + .../api/events/homes/HomeUnsharePreEvent.java | 32 + .../api/events/kits/KitClaimEvent.java | 10 + .../api/events/kits/KitClaimPreEvent.java | 55 ++ .../api/events/kits/KitCreateEvent.java | 10 + .../api/events/kits/KitCreatePreEvent.java | 55 ++ .../api/events/kits/KitDeleteEvent.java | 10 + .../api/events/kits/KitDeletePreEvent.java | 55 ++ .../api/events/moderation/PlayerBanEvent.java | 12 + .../events/moderation/PlayerBanPreEvent.java | 73 ++ .../events/moderation/PlayerKickEvent.java | 11 + .../events/moderation/PlayerKickPreEvent.java | 63 ++ .../events/moderation/PlayerMuteEvent.java | 12 + .../events/moderation/PlayerMutePreEvent.java | 73 ++ .../events/moderation/PlayerUnbanEvent.java | 10 + .../moderation/PlayerUnbanPreEvent.java | 55 ++ .../events/moderation/PlayerUnmuteEvent.java | 10 + .../moderation/PlayerUnmutePreEvent.java | 55 ++ .../events/moderation/PlayerWarnEvent.java | 11 + .../events/moderation/PlayerWarnPreEvent.java | 63 ++ .../api/events/spawns/SpawnDeleteEvent.java | 10 + .../events/spawns/SpawnDeletePreEvent.java | 28 + .../api/events/spawns/SpawnSetEvent.java | 10 + .../api/events/spawns/SpawnSetPreEvent.java | 28 + .../api/events/spawns/SpawnTeleportEvent.java | 10 + .../events/spawns/SpawnTeleportPreEvent.java | 28 + .../events/teleport/BackTeleportEvent.java | 11 + .../events/teleport/BackTeleportPreEvent.java | 82 ++ .../api/events/teleport/RtpEvent.java | 11 + .../api/events/teleport/RtpPreEvent.java | 55 ++ .../api/events/teleport/TpaAcceptEvent.java | 10 + .../events/teleport/TpaAcceptPreEvent.java | 55 ++ .../api/events/teleport/TpaDenyEvent.java | 10 + .../api/events/teleport/TpaDenyPreEvent.java | 55 ++ .../api/events/teleport/TpaSendEvent.java | 10 + .../api/events/teleport/TpaSendPreEvent.java | 62 ++ .../api/events/utility/AfkToggleEvent.java | 10 + .../api/events/utility/AfkTogglePreEvent.java | 55 ++ .../api/events/utility/FlyToggleEvent.java | 10 + .../api/events/utility/FlyTogglePreEvent.java | 55 ++ .../api/events/utility/GodToggleEvent.java | 10 + .../api/events/utility/GodTogglePreEvent.java | 55 ++ .../api/events/warps/WarpDeleteEvent.java | 10 + .../api/events/warps/WarpDeletePreEvent.java | 28 + .../api/events/warps/WarpSetEvent.java | 10 + .../api/events/warps/WarpSetPreEvent.java | 28 + .../api/events/warps/WarpTeleportEvent.java | 10 + .../events/warps/WarpTeleportPreEvent.java | 28 + .../placeholder/HyperEssentialsExpansion.java | 481 +++++++++++ .../PlaceholderAPIIntegration.java | 83 ++ .../placeholder/WiFlowExpansion.java | 507 +++++++++++ .../WiFlowPlaceholderIntegration.java | 106 +++ .../module/homes/HomeManager.java | 35 + .../module/kits/KitManager.java | 23 + .../module/moderation/ModerationManager.java | 70 +- .../module/spawns/SpawnManager.java | 37 + .../module/teleport/TpaManager.java | 26 +- .../module/utility/UtilityManager.java | 53 +- .../module/warps/WarpManager.java | 37 + src/main/resources/manifest.json | 4 + 75 files changed, 4017 insertions(+), 75 deletions(-) create mode 100644 src/main/java/com/hyperessentials/api/events/Cancellable.java create mode 100644 src/main/java/com/hyperessentials/api/events/homes/HomeDefaultSetEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/homes/HomeDefaultSetPreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/homes/HomeDeleteEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/homes/HomeDeletePreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/homes/HomeSetEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/homes/HomeSetPreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/homes/HomeShareEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/homes/HomeSharePreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/homes/HomeTeleportEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/homes/HomeTeleportPreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/homes/HomeUnshareEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/homes/HomeUnsharePreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/kits/KitClaimEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/kits/KitClaimPreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/kits/KitCreateEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/kits/KitCreatePreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/kits/KitDeleteEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/kits/KitDeletePreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/moderation/PlayerBanEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/moderation/PlayerBanPreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/moderation/PlayerKickEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/moderation/PlayerKickPreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/moderation/PlayerMuteEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/moderation/PlayerMutePreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/moderation/PlayerUnbanEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/moderation/PlayerUnbanPreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/moderation/PlayerUnmuteEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/moderation/PlayerUnmutePreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/moderation/PlayerWarnEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/moderation/PlayerWarnPreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/spawns/SpawnDeleteEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/spawns/SpawnDeletePreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/spawns/SpawnSetEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/spawns/SpawnSetPreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/spawns/SpawnTeleportEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/spawns/SpawnTeleportPreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/teleport/BackTeleportEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/teleport/BackTeleportPreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/teleport/RtpEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/teleport/RtpPreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/teleport/TpaAcceptEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/teleport/TpaAcceptPreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/teleport/TpaDenyEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/teleport/TpaDenyPreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/teleport/TpaSendEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/teleport/TpaSendPreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/utility/AfkToggleEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/utility/AfkTogglePreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/utility/FlyToggleEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/utility/FlyTogglePreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/utility/GodToggleEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/utility/GodTogglePreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/warps/WarpDeleteEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/warps/WarpDeletePreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/warps/WarpSetEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/warps/WarpSetPreEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/warps/WarpTeleportEvent.java create mode 100644 src/main/java/com/hyperessentials/api/events/warps/WarpTeleportPreEvent.java create mode 100644 src/main/java/com/hyperessentials/integration/placeholder/HyperEssentialsExpansion.java create mode 100644 src/main/java/com/hyperessentials/integration/placeholder/PlaceholderAPIIntegration.java create mode 100644 src/main/java/com/hyperessentials/integration/placeholder/WiFlowExpansion.java create mode 100644 src/main/java/com/hyperessentials/integration/placeholder/WiFlowPlaceholderIntegration.java diff --git a/build.gradle b/build.gradle index 883c16b..6a7bf66 100644 --- a/build.gradle +++ b/build.gradle @@ -28,12 +28,16 @@ java { } } +// WiFlow PlaceholderAPI lib detection (conditional compilation) +def hasWiFlowLib = file('libs').listFiles()?.any { it.name.contains('WiFlow') } ?: false + repositories { mavenCentral() maven { name = 'hytale' url = "https://maven.hytale.com/${hytaleChannel}" } + maven { url = 'https://repo.helpch.at/releases/' } } dependencies { @@ -52,6 +56,12 @@ dependencies { // Sentry error tracking (bundled in shadow JAR) implementation 'io.sentry:sentry:8.33.0' + // PlaceholderAPI Hytale (soft dependency - compileOnly) + compileOnly 'at.helpch:placeholderapi-hytale:1.0.4' + + // Optional local soft dependencies (WiFlowPlaceholderAPI) + compileOnly fileTree('libs') { include '*.jar' } + // Null safety annotations compileOnly 'org.jetbrains:annotations:24.1.0' @@ -114,6 +124,13 @@ build { finalizedBy tasks.matching { it.name == 'sentryUploadSourceBundleJava' } } +// WiFlowExpansion extends PlaceholderExpansion (from WiFlowPlaceholderAPI) directly. +// When WiFlow isn't on the classpath (JitPack / CI), exclude it from compilation. +// The bridge class (WiFlowPlaceholderIntegration) loads it reflectively at runtime. +if (!hasWiFlowLib) { + sourceSets.main.java.exclude '**/WiFlowExpansion.java' +} + tasks.named('compileJava') { dependsOn 'generateBuildInfo' dependsOn ':HyperPerms:shadowJar' diff --git a/src/main/java/com/hyperessentials/HyperEssentials.java b/src/main/java/com/hyperessentials/HyperEssentials.java index 82d6542..068864f 100644 --- a/src/main/java/com/hyperessentials/HyperEssentials.java +++ b/src/main/java/com/hyperessentials/HyperEssentials.java @@ -168,6 +168,17 @@ public void enable() { // Register GUI pages (post-init, modules + managers must be ready) registerPages(); + // Initialize PlaceholderAPI integration (after all managers are ready) + com.hyperessentials.integration.placeholder.PlaceholderAPIIntegration.init(this); + + // Initialize WiFlow PlaceholderAPI integration (guard before class loading) + try { + Class.forName("com.wiflow.placeholderapi.WiFlowPlaceholderAPI"); + com.hyperessentials.integration.placeholder.WiFlowPlaceholderIntegration.init(this); + } catch (ClassNotFoundException e) { + Logger.debug("WiFlow PlaceholderAPI not found — WiFlow placeholders disabled"); + } + Logger.info("HyperEssentials enabled with %d modules", moduleRegistry.getEnabledModules().size()); } @@ -175,6 +186,16 @@ public void enable() { * Disables HyperEssentials - disables modules, shuts down storage, saves config. */ public void disable() { + // Unregister PlaceholderAPI expansions + try { + Class.forName("com.wiflow.placeholderapi.WiFlowPlaceholderAPI"); + com.hyperessentials.integration.placeholder.WiFlowPlaceholderIntegration.shutdown(); + } catch (ClassNotFoundException ignored) {} + com.hyperessentials.integration.placeholder.PlaceholderAPIIntegration.shutdown(); + + // Clear event bus listeners + com.hyperessentials.api.events.EventBus.clearAll(); + // Disable modules in reverse order if (moduleRegistry != null) { moduleRegistry.disableAll(); @@ -506,6 +527,14 @@ private void ensureDirectories() { public HomesModule getHomesModule() { return moduleRegistry.getModule(HomesModule.class); } @Nullable public TeleportModule getTeleportModule() { return moduleRegistry.getModule(TeleportModule.class); } + @Nullable + public KitsModule getKitsModule() { return moduleRegistry.getModule(KitsModule.class); } + @Nullable + public ModerationModule getModerationModule() { return moduleRegistry.getModule(ModerationModule.class); } + @Nullable + public UtilityModule getUtilityModule() { return moduleRegistry.getModule(UtilityModule.class); } + @Nullable + public AnnouncementsModule getAnnouncementsModule() { return moduleRegistry.getModule(AnnouncementsModule.class); } // Getters diff --git a/src/main/java/com/hyperessentials/api/HyperEssentialsAPI.java b/src/main/java/com/hyperessentials/api/HyperEssentialsAPI.java index 1bd2bcc..44a4e42 100644 --- a/src/main/java/com/hyperessentials/api/HyperEssentialsAPI.java +++ b/src/main/java/com/hyperessentials/api/HyperEssentialsAPI.java @@ -1,27 +1,51 @@ package com.hyperessentials.api; import com.hyperessentials.HyperEssentials; +import com.hyperessentials.api.events.EventBus; +import com.hyperessentials.data.Home; import com.hyperessentials.data.Location; import com.hyperessentials.data.Spawn; import com.hyperessentials.data.Warp; +import com.hyperessentials.module.homes.HomeManager; +import com.hyperessentials.module.homes.HomesModule; +import com.hyperessentials.module.kits.KitManager; +import com.hyperessentials.module.kits.KitsModule; +import com.hyperessentials.module.kits.data.Kit; +import com.hyperessentials.module.moderation.ModerationManager; +import com.hyperessentials.module.moderation.ModerationModule; +import com.hyperessentials.module.moderation.data.Punishment; import com.hyperessentials.module.spawns.SpawnManager; import com.hyperessentials.module.spawns.SpawnsModule; import com.hyperessentials.module.teleport.BackManager; import com.hyperessentials.module.teleport.TeleportModule; import com.hyperessentials.module.teleport.TpaManager; +import com.hyperessentials.module.utility.UtilityManager; +import com.hyperessentials.module.utility.UtilityModule; import com.hyperessentials.module.warps.WarpManager; import com.hyperessentials.module.warps.WarpsModule; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.time.Instant; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.UUID; +import java.util.function.Consumer; /** * Public API for HyperEssentials. - * Other plugins can use this to interact with HyperEssentials modules. + * External plugins can use this to query and modify essentials data + * without depending on internal module implementations. + * + *

All query methods that return collections return empty collections (never null) + * when the backing module is unavailable or disabled. Nullable return types indicate + * that the data may not exist. Mutating methods return {@code boolean} where + * {@code false} means the module was unavailable or the operation failed.

+ * + *

For advanced use cases, the manager accessor methods at the bottom of this class + * expose the underlying managers directly.

*/ public final class HyperEssentialsAPI { @@ -29,107 +53,828 @@ public final class HyperEssentialsAPI { private HyperEssentialsAPI() {} + /** + * Sets the backing HyperEssentials instance. Called internally on plugin enable/disable. + */ public static void setInstance(@Nullable HyperEssentials instance) { HyperEssentialsAPI.instance = instance; } - @Nullable + /** + * Returns the backing HyperEssentials instance. + * + * @throws IllegalStateException if HyperEssentials is not initialized + */ + @NotNull public static HyperEssentials getInstance() { + if (instance == null) throw new IllegalStateException("HyperEssentials is not initialized"); return instance; } + /** + * Returns whether HyperEssentials is initialized and available. + */ public static boolean isAvailable() { return instance != null; } - // ========== Warp API ========== + // ======================================================================== + // Home API + // ======================================================================== + + /** + * Gets all homes for a player. + * + * @param uuid the player UUID + * @return the player's homes, or an empty collection if the module is unavailable + */ + @NotNull + public static Collection getHomes(@NotNull UUID uuid) { + HomeManager hm = homeManager(); + return hm != null ? hm.getHomes(uuid) : Collections.emptyList(); + } + + /** + * Gets a specific home by name. + * + * @param uuid the player UUID + * @param name the home name + * @return the home, or null if not found or module unavailable + */ + @Nullable + public static Home getHome(@NotNull UUID uuid, @NotNull String name) { + HomeManager hm = homeManager(); + return hm != null ? hm.getHome(uuid, name) : null; + } + + /** + * Sets (creates or overwrites) a home for a player. + * + * @param uuid the player UUID + * @param home the home to set + * @return true if the home was set, false if the module is unavailable or the player is at their limit + */ + public static boolean setHome(@NotNull UUID uuid, @NotNull Home home) { + HomeManager hm = homeManager(); + return hm != null && hm.setHome(uuid, home); + } + + /** + * Deletes a home by name. + * + * @param uuid the player UUID + * @param name the home name + * @return true if the home was deleted, false if not found or module unavailable + */ + public static boolean deleteHome(@NotNull UUID uuid, @NotNull String name) { + HomeManager hm = homeManager(); + return hm != null && hm.deleteHome(uuid, name); + } + + /** + * Gets the number of homes a player has. + * + * @param uuid the player UUID + * @return the home count, or 0 if the module is unavailable + */ + public static int getHomeCount(@NotNull UUID uuid) { + HomeManager hm = homeManager(); + return hm != null ? hm.getHomeCount(uuid) : 0; + } + + /** + * Gets the home limit for a player (based on permissions and config). + * + * @param uuid the player UUID + * @return the home limit (-1 = unlimited), or 0 if the module is unavailable + */ + public static int getHomeLimit(@NotNull UUID uuid) { + HomeManager hm = homeManager(); + return hm != null ? hm.getHomeLimit(uuid) : 0; + } + + /** + * Checks whether a player is at their home limit. + * + * @param uuid the player UUID + * @return true if the player cannot create more homes, false if unlimited or module unavailable + */ + public static boolean isAtHomeLimit(@NotNull UUID uuid) { + HomeManager hm = homeManager(); + return hm != null && hm.isAtLimit(uuid); + } + /** + * Gets the name of a player's default home. + * + * @param uuid the player UUID + * @return the default home name, or null if none set or module unavailable + */ + @Nullable + public static String getDefaultHome(@NotNull UUID uuid) { + HomeManager hm = homeManager(); + return hm != null ? hm.getDefaultHome(uuid) : null; + } + + /** + * Sets a player's default home. + * + * @param uuid the player UUID + * @param name the home name to set as default (null to clear) + * @return true if set, false if the module is unavailable + */ + public static boolean setDefaultHome(@NotNull UUID uuid, @Nullable String name) { + HomeManager hm = homeManager(); + if (hm == null) return false; + hm.setDefaultHome(uuid, name); + return true; + } + + /** + * Shares a home with another player. + * + * @param ownerUuid the home owner's UUID + * @param homeName the home name + * @param targetUuid the player to share with + * @return true if shared, false if the module is unavailable + */ + public static boolean shareHome(@NotNull UUID ownerUuid, @NotNull String homeName, @NotNull UUID targetUuid) { + HomeManager hm = homeManager(); + if (hm == null) return false; + hm.shareHome(ownerUuid, homeName, targetUuid); + return true; + } + + /** + * Revokes a home share from another player. + * + * @param ownerUuid the home owner's UUID + * @param homeName the home name + * @param targetUuid the player to unshare from + * @return true if unshared, false if the module is unavailable + */ + public static boolean unshareHome(@NotNull UUID ownerUuid, @NotNull String homeName, @NotNull UUID targetUuid) { + HomeManager hm = homeManager(); + if (hm == null) return false; + hm.unshareHome(ownerUuid, homeName, targetUuid); + return true; + } + + /** + * Gets the set of player UUIDs a home is shared with. + * + * @param ownerUuid the home owner's UUID + * @param homeName the home name + * @return the set of shared player UUIDs, or an empty set if unavailable + */ + @NotNull + public static Set getSharedWith(@NotNull UUID ownerUuid, @NotNull String homeName) { + HomeManager hm = homeManager(); + return hm != null ? hm.getSharedWith(ownerUuid, homeName) : Set.of(); + } + + /** + * Gets all homes shared TO a player (from other players). + * + * @param uuid the viewer's UUID + * @return list of shared homes, or an empty list if unavailable + */ + @NotNull + public static List getSharedHomes(@NotNull UUID uuid) { + HomeManager hm = homeManager(); + return hm != null ? hm.getSharedHomes(uuid) : List.of(); + } + + // ======================================================================== + // Warp API + // ======================================================================== + + /** + * Gets a warp by name. + * + * @param name the warp name (case-insensitive) + * @return the warp, or null if not found or module unavailable + */ @Nullable public static Warp getWarp(@NotNull String name) { - WarpManager wm = getWarpManager(); + WarpManager wm = warpManager(); return wm != null ? wm.getWarp(name) : null; } + /** + * Gets all warps. + * + * @return all warps, or an empty collection if unavailable + */ @NotNull public static Collection getAllWarps() { - WarpManager wm = getWarpManager(); + WarpManager wm = warpManager(); return wm != null ? wm.getAllWarps() : Collections.emptyList(); } + /** + * Gets warps accessible to a player (respecting per-warp permissions). + * + * @param uuid the player UUID + * @return accessible warps, or an empty list if unavailable + */ @NotNull public static List getAccessibleWarps(@NotNull UUID uuid) { - WarpManager wm = getWarpManager(); + WarpManager wm = warpManager(); return wm != null ? wm.getAccessibleWarps(uuid) : Collections.emptyList(); } - // ========== Spawn API ========== + /** + * Creates or updates a warp. + * + * @param warp the warp to set + * @return true if set, false if the module is unavailable + */ + public static boolean setWarp(@NotNull Warp warp) { + WarpManager wm = warpManager(); + if (wm == null) return false; + wm.setWarp(warp); + return true; + } + + /** + * Deletes a warp by name. + * + * @param name the warp name + * @return true if the warp was deleted, false if not found or module unavailable + */ + public static boolean deleteWarp(@NotNull String name) { + WarpManager wm = warpManager(); + return wm != null && wm.deleteWarp(name); + } + + /** + * Gets the total number of warps. + * + * @return the warp count, or 0 if the module is unavailable + */ + public static int getWarpCount() { + WarpManager wm = warpManager(); + return wm != null ? wm.getWarpCount() : 0; + } + + /** + * Gets all warp categories. + * + * @return category names, or an empty set if unavailable + */ + @NotNull + public static Set getWarpCategories() { + WarpManager wm = warpManager(); + return wm != null ? wm.getCategories() : Set.of(); + } + // ======================================================================== + // Spawn API + // ======================================================================== + + /** + * Gets the spawn for a specific world by UUID. + * + * @param worldUuid the world UUID string + * @return the spawn, or null if not found or module unavailable + */ @Nullable public static Spawn getSpawnForWorld(@NotNull String worldUuid) { - SpawnManager sm = getSpawnManager(); + SpawnManager sm = spawnManager(); return sm != null ? sm.getSpawnForWorld(worldUuid) : null; } + /** + * Gets the global spawn point. + * + * @return the global spawn, or null if none configured or module unavailable + */ @Nullable public static Spawn getGlobalSpawn() { - SpawnManager sm = getSpawnManager(); + SpawnManager sm = spawnManager(); return sm != null ? sm.getGlobalSpawn() : null; } + /** + * Gets all configured spawns. + * + * @return all spawns, or an empty collection if unavailable + */ @NotNull public static Collection getAllSpawns() { - SpawnManager sm = getSpawnManager(); + SpawnManager sm = spawnManager(); return sm != null ? sm.getAllSpawns() : Collections.emptyList(); } - // ========== Back API ========== + /** + * Sets (creates or updates) a spawn for a world. + * If the spawn is marked as global, any previous global spawn is demoted. + * + * @param spawn the spawn to set + * @return true if set, false if the module is unavailable + */ + public static boolean setSpawn(@NotNull Spawn spawn) { + SpawnManager sm = spawnManager(); + if (sm == null) return false; + sm.setSpawn(spawn); + return true; + } + + /** + * Deletes the spawn for a world. + * + * @param worldUuid the world UUID string + * @return true if deleted, false if not found or module unavailable + */ + public static boolean deleteSpawn(@NotNull String worldUuid) { + SpawnManager sm = spawnManager(); + return sm != null && sm.deleteSpawn(worldUuid); + } + + /** + * Gets the total number of configured spawns. + * + * @return the spawn count, or 0 if the module is unavailable + */ + public static int getSpawnCount() { + SpawnManager sm = spawnManager(); + return sm != null ? sm.getSpawnCount() : 0; + } + + // ======================================================================== + // Kit API + // ======================================================================== + /** + * Gets a kit by name. + * + * @param name the kit name (case-insensitive) + * @return the kit, or null if not found or module unavailable + */ + @Nullable + public static Kit getKit(@NotNull String name) { + KitManager km = kitManager(); + return km != null ? km.getKit(name) : null; + } + + /** + * Gets all defined kits. + * + * @return all kits, or an empty collection if unavailable + */ + @NotNull + public static Collection getAllKits() { + KitManager km = kitManager(); + return km != null ? km.getAllKits() : Collections.emptyList(); + } + + /** + * Gets kits available to a player (based on permission checks). + * + * @param uuid the player UUID + * @return available kits, or an empty list if unavailable + */ + @NotNull + public static List getAvailableKits(@NotNull UUID uuid) { + KitManager km = kitManager(); + return km != null ? km.getAvailableKits(uuid) : Collections.emptyList(); + } + + /** + * Checks whether a player is on cooldown for a kit. + * + * @param uuid the player UUID + * @param kitName the kit name + * @return true if on cooldown, false if not or module unavailable + */ + public static boolean isOnKitCooldown(@NotNull UUID uuid, @NotNull String kitName) { + KitManager km = kitManager(); + return km != null && km.isOnCooldown(uuid, kitName); + } + + /** + * Gets the remaining cooldown for a kit in milliseconds. + * + * @param uuid the player UUID + * @param kitName the kit name + * @return remaining cooldown in ms, or 0 if no cooldown or module unavailable + */ + public static long getRemainingKitCooldown(@NotNull UUID uuid, @NotNull String kitName) { + KitManager km = kitManager(); + return km != null ? km.getRemainingCooldown(uuid, kitName) : 0L; + } + + /** + * Checks whether a player has already claimed a one-time kit. + * + * @param uuid the player UUID + * @param kitName the kit name + * @return true if already claimed, false if not or module unavailable + */ + public static boolean hasClaimedOneTimeKit(@NotNull UUID uuid, @NotNull String kitName) { + KitManager km = kitManager(); + return km != null && km.hasClaimedOneTimeKit(uuid, kitName); + } + + /** + * Deletes a kit by name. + * + * @param name the kit name + * @return true if deleted, false if not found or module unavailable + */ + public static boolean deleteKit(@NotNull String name) { + KitManager km = kitManager(); + return km != null && km.deleteKit(name); + } + + // ======================================================================== + // Moderation API + // ======================================================================== + + /** + * Checks whether a player is currently banned. + * + * @param uuid the player UUID + * @return true if banned, false if not or module unavailable + */ + public static boolean isBanned(@NotNull UUID uuid) { + ModerationManager mm = moderationManager(); + return mm != null && mm.isBanned(uuid); + } + + /** + * Checks whether a player is currently muted. + * + * @param uuid the player UUID + * @return true if muted, false if not or module unavailable + */ + public static boolean isMuted(@NotNull UUID uuid) { + ModerationManager mm = moderationManager(); + return mm != null && mm.isMuted(uuid); + } + + /** + * Gets the active ban for a player. + * + * @param uuid the player UUID + * @return the active ban punishment, or null if not banned or module unavailable + */ + @Nullable + public static Punishment getActiveBan(@NotNull UUID uuid) { + ModerationManager mm = moderationManager(); + return mm != null ? mm.getActiveBan(uuid) : null; + } + + /** + * Gets the full punishment history for a player. + * + * @param uuid the player UUID + * @return the punishment history, or an empty list if unavailable + */ + @NotNull + public static List getPunishmentHistory(@NotNull UUID uuid) { + ModerationManager mm = moderationManager(); + return mm != null ? mm.getHistory(uuid) : List.of(); + } + + /** + * Gets all punishments across all players. + * This is an expensive operation that scans all player data files. + * + * @param activeOnly if true, only returns currently effective punishments + * @return all punishments, or an empty list if unavailable + */ + @NotNull + public static List getAllPunishments(boolean activeOnly) { + ModerationManager mm = moderationManager(); + return mm != null ? mm.getAllPunishments(activeOnly) : List.of(); + } + + /** + * Checks whether an IP address is banned. + * + * @param ip the IP address + * @return true if IP-banned, false if not or module unavailable + */ + public static boolean isIpBanned(@NotNull String ip) { + ModerationManager mm = moderationManager(); + return mm != null && mm.isIpBanned(ip); + } + + // ======================================================================== + // Utility API + // ======================================================================== + + /** + * Checks whether a player has fly mode enabled. + * + * @param uuid the player UUID + * @return true if flying, false if not or module unavailable + */ + public static boolean isFlying(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + return um != null && um.isFlying(uuid); + } + + /** + * Checks whether a player has god mode enabled. + * + * @param uuid the player UUID + * @return true if in god mode, false if not or module unavailable + */ + public static boolean isGod(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + return um != null && um.isGod(uuid); + } + + /** + * Checks whether a player is AFK. + * + * @param uuid the player UUID + * @return true if AFK, false if not or module unavailable + */ + public static boolean isAfk(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + return um != null && um.isAfk(uuid); + } + + /** + * Checks whether a player has infinite stamina enabled. + * + * @param uuid the player UUID + * @return true if infinite stamina is active, false if not or module unavailable + */ + public static boolean isInfiniteStamina(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + return um != null && um.isInfiniteStamina(uuid); + } + + /** + * Gets the first join time for a player. + * + * @param uuid the player UUID + * @return the first join instant, or null if unknown or module unavailable + */ + @Nullable + public static Instant getFirstJoin(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + return um != null ? um.getFirstJoin(uuid) : null; + } + + /** + * Gets the total playtime for a player, including the current session. + * + * @param uuid the player UUID + * @return total playtime in milliseconds, or 0 if module unavailable + */ + public static long getTotalPlaytimeMs(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + return um != null ? um.getTotalPlaytimeMs(uuid) : 0L; + } + + /** + * Gets the current session start time for a player. + * + * @param uuid the player UUID + * @return the session start instant, or null if not online or module unavailable + */ + @Nullable + public static Instant getSessionStart(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + return um != null ? um.getSessionStart(uuid) : null; + } + + // ======================================================================== + // TPA / Back API + // ======================================================================== + + /** + * Checks whether a player is accepting TPA requests. + * + * @param uuid the player UUID + * @return true if accepting (or if the module is unavailable — fail-open) + */ + public static boolean isAcceptingTpa(@NotNull UUID uuid) { + TpaManager tm = tpaManager(); + return tm == null || tm.isAcceptingRequests(uuid); + } + + /** + * Saves a back location for a player (used by external teleport systems). + * + * @param uuid the player UUID + * @param location the location to save + * @param source a source identifier (e.g., "warp", "home", "tpa") + */ public static void saveBackLocation(@NotNull UUID uuid, @NotNull Location location, @NotNull String source) { - BackManager bm = getBackManager(); + BackManager bm = backManager(); if (bm != null) { bm.saveBackLocation(uuid, location, source); } } + /** + * Checks whether a player has any back history entries. + * + * @param uuid the player UUID + * @return true if back history exists, false if empty or module unavailable + */ public static boolean hasBackHistory(@NotNull UUID uuid) { - BackManager bm = getBackManager(); + BackManager bm = backManager(); return bm != null && bm.hasBackHistory(uuid); } - // ========== TPA API ========== + /** + * Gets the number of entries in a player's back history. + * + * @param uuid the player UUID + * @return the back history size, or 0 if the module is unavailable + */ + public static int getBackHistorySize(@NotNull UUID uuid) { + BackManager bm = backManager(); + return bm != null ? bm.getHistorySize(uuid) : 0; + } - public static boolean isAcceptingTpa(@NotNull UUID uuid) { - TpaManager tm = getTpaManager(); - return tm == null || tm.isAcceptingRequests(uuid); + /** + * Clears a player's entire back history. + * + * @param uuid the player UUID + */ + public static void clearBackHistory(@NotNull UUID uuid) { + BackManager bm = backManager(); + if (bm != null) { + bm.clearHistory(uuid); + } } - // ========== Internal helpers ========== + // ======================================================================== + // Event System + // ======================================================================== + + /** + * Registers an event listener for HyperEssentials events. + * + * @param eventClass the event class to listen for + * @param listener the listener callback + * @param the event type + */ + public static void registerEventListener(@NotNull Class eventClass, @NotNull Consumer listener) { + EventBus.register(eventClass, listener); + } + + /** + * Unregisters an event listener. + * + * @param eventClass the event class + * @param listener the listener callback to remove + * @param the event type + */ + public static void unregisterEventListener(@NotNull Class eventClass, @NotNull Consumer listener) { + EventBus.unregister(eventClass, listener); + } + + // ======================================================================== + // Manager Accessors (for advanced use) + // ======================================================================== + + /** + * Gets the HomeManager for direct access to home operations. + * + * @return the HomeManager, or null if the homes module is unavailable + */ + @Nullable + public static HomeManager getHomeManager() { + return homeManager(); + } + + /** + * Gets the WarpManager for direct access to warp operations. + * + * @return the WarpManager, or null if the warps module is unavailable + */ + @Nullable + public static WarpManager getWarpManager() { + return warpManager(); + } + + /** + * Gets the SpawnManager for direct access to spawn operations. + * + * @return the SpawnManager, or null if the spawns module is unavailable + */ + @Nullable + public static SpawnManager getSpawnManager() { + return spawnManager(); + } + + /** + * Gets the KitManager for direct access to kit operations. + * + * @return the KitManager, or null if the kits module is unavailable + */ + @Nullable + public static KitManager getKitManager() { + return kitManager(); + } + + /** + * Gets the ModerationManager for direct access to moderation operations. + * + * @return the ModerationManager, or null if the moderation module is unavailable + */ + @Nullable + public static ModerationManager getModerationManager() { + return moderationManager(); + } + + /** + * Gets the UtilityManager for direct access to utility state operations. + * + * @return the UtilityManager, or null if the utility module is unavailable + */ + @Nullable + public static UtilityManager getUtilityManager() { + return utilityManager(); + } + + /** + * Gets the TpaManager for direct access to TPA request operations. + * + * @return the TpaManager, or null if the teleport module is unavailable + */ + @Nullable + public static TpaManager getTpaManager() { + return tpaManager(); + } + + /** + * Gets the BackManager for direct access to back history operations. + * + * @return the BackManager, or null if the teleport module is unavailable + */ + @Nullable + public static BackManager getBackManager() { + return backManager(); + } + + // ======================================================================== + // Private Helpers + // ======================================================================== + + @Nullable + private static HomeManager homeManager() { + if (!isAvailable()) return null; + HomesModule m = instance.getHomesModule(); + return (m != null && m.isEnabled()) ? m.getHomeManager() : null; + } + + @Nullable + private static WarpManager warpManager() { + if (!isAvailable()) return null; + WarpsModule m = instance.getWarpsModule(); + return (m != null && m.isEnabled()) ? m.getWarpManager() : null; + } + + @Nullable + private static SpawnManager spawnManager() { + if (!isAvailable()) return null; + SpawnsModule m = instance.getSpawnsModule(); + return (m != null && m.isEnabled()) ? m.getSpawnManager() : null; + } + + @Nullable + private static KitManager kitManager() { + if (!isAvailable()) return null; + KitsModule m = instance.getKitsModule(); + return (m != null && m.isEnabled()) ? m.getKitManager() : null; + } @Nullable - private static WarpManager getWarpManager() { + private static ModerationManager moderationManager() { if (!isAvailable()) return null; - WarpsModule module = instance.getWarpsModule(); - return (module != null && module.isEnabled()) ? module.getWarpManager() : null; + ModerationModule m = instance.getModerationModule(); + return (m != null && m.isEnabled()) ? m.getModerationManager() : null; } @Nullable - private static SpawnManager getSpawnManager() { + private static UtilityManager utilityManager() { if (!isAvailable()) return null; - SpawnsModule module = instance.getSpawnsModule(); - return (module != null && module.isEnabled()) ? module.getSpawnManager() : null; + UtilityModule m = instance.getUtilityModule(); + return (m != null && m.isEnabled()) ? m.getUtilityManager() : null; } @Nullable - private static BackManager getBackManager() { + private static TpaManager tpaManager() { if (!isAvailable()) return null; - TeleportModule module = instance.getTeleportModule(); - return (module != null && module.isEnabled()) ? module.getBackManager() : null; + TeleportModule m = instance.getTeleportModule(); + return (m != null && m.isEnabled()) ? m.getTpaManager() : null; } @Nullable - private static TpaManager getTpaManager() { + private static BackManager backManager() { if (!isAvailable()) return null; - TeleportModule module = instance.getTeleportModule(); - return (module != null && module.isEnabled()) ? module.getTpaManager() : null; + TeleportModule m = instance.getTeleportModule(); + return (m != null && m.isEnabled()) ? m.getBackManager() : null; } } diff --git a/src/main/java/com/hyperessentials/api/events/Cancellable.java b/src/main/java/com/hyperessentials/api/events/Cancellable.java new file mode 100644 index 0000000..9615c63 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/Cancellable.java @@ -0,0 +1,23 @@ +package com.hyperessentials.api.events; + +import org.jetbrains.annotations.Nullable; + +/** + * Interface for events that can be cancelled by listeners. + * When a pre-event is cancelled, the corresponding action is aborted. + * + *

Listeners can optionally provide a cancellation reason via + * {@link #setCancelReason(String)}, which will be sent to the player + * instead of the default denial message. + */ +public interface Cancellable { + + boolean isCancelled(); + + void setCancelled(boolean cancelled); + + @Nullable + String getCancelReason(); + + void setCancelReason(@Nullable String reason); +} diff --git a/src/main/java/com/hyperessentials/api/events/EventBus.java b/src/main/java/com/hyperessentials/api/events/EventBus.java index 98b7d16..fce3522 100644 --- a/src/main/java/com/hyperessentials/api/events/EventBus.java +++ b/src/main/java/com/hyperessentials/api/events/EventBus.java @@ -1,48 +1,81 @@ package com.hyperessentials.api.events; -import org.jetbrains.annotations.NotNull; - -import java.util.List; -import java.util.Map; +import com.hyperessentials.util.ErrorHandler; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; +import org.jetbrains.annotations.NotNull; /** * Simple event bus for HyperEssentials events. */ public final class EventBus { - private static final Map, List>> handlers = new ConcurrentHashMap<>(); + private static final Map, List>> listeners = new ConcurrentHashMap<>(); private EventBus() {} - public static void register(@NotNull Class eventClass, @NotNull Consumer handler) { - handlers.computeIfAbsent(eventClass, k -> new CopyOnWriteArrayList<>()).add(handler); + /** + * Registers a listener for an event type. + */ + public static void register(@NotNull Class eventClass, @NotNull Consumer listener) { + listeners.computeIfAbsent(eventClass, k -> Collections.synchronizedList(new ArrayList<>())) + .add(listener); + } + + /** + * Unregisters a listener for an event type. + */ + public static void unregister(@NotNull Class eventClass, @NotNull Consumer listener) { + List> list = listeners.get(eventClass); + if (list != null) { + list.remove(listener); + } } - public static void unregister(@NotNull Class eventClass, @NotNull Consumer handler) { - List> list = handlers.get(eventClass); + /** + * Publishes an event to all registered listeners. + */ + @SuppressWarnings("unchecked") + public static void publish(@NotNull T event) { + List> list = listeners.get(event.getClass()); if (list != null) { - list.remove(handler); + for (Consumer listener : list) { + try { + ((Consumer) listener).accept(event); + } catch (Exception e) { + ErrorHandler.report("Event bus listener error", e); + } + } } } + /** + * Publishes a cancellable event to all registered listeners. + * Returns true if the event was cancelled by any listener. + */ @SuppressWarnings("unchecked") - public static void fire(@NotNull T event) { - List> list = handlers.get(event.getClass()); + public static boolean publishCancellable(@NotNull T event) { + List> list = listeners.get(event.getClass()); if (list != null) { - for (Consumer handler : list) { + for (Consumer listener : list) { try { - ((Consumer) handler).accept(event); + ((Consumer) listener).accept(event); + if (event.isCancelled()) { + return true; + } } catch (Exception e) { - e.printStackTrace(); + ErrorHandler.report("Event bus listener error", e); } } } + return event.isCancelled(); } - public static void clear() { - handlers.clear(); + /** + * Clears all listeners. + */ + public static void clearAll() { + listeners.clear(); } } diff --git a/src/main/java/com/hyperessentials/api/events/homes/HomeDefaultSetEvent.java b/src/main/java/com/hyperessentials/api/events/homes/HomeDefaultSetEvent.java new file mode 100644 index 0000000..c2ad1bf --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/homes/HomeDefaultSetEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.homes; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public record HomeDefaultSetEvent( + @NotNull UUID playerUuid, + @NotNull String homeName +) {} diff --git a/src/main/java/com/hyperessentials/api/events/homes/HomeDefaultSetPreEvent.java b/src/main/java/com/hyperessentials/api/events/homes/HomeDefaultSetPreEvent.java new file mode 100644 index 0000000..5cc0a2a --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/homes/HomeDefaultSetPreEvent.java @@ -0,0 +1,28 @@ +package com.hyperessentials.api.events.homes; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public final class HomeDefaultSetPreEvent implements Cancellable { + + private final UUID playerUuid; + private final String homeName; + private boolean cancelled; + private String cancelReason; + + public HomeDefaultSetPreEvent(@NotNull UUID playerUuid, @NotNull String homeName) { + this.playerUuid = playerUuid; + this.homeName = homeName; + } + + @NotNull public UUID playerUuid() { return playerUuid; } + @NotNull public String homeName() { return homeName; } + + @Override public boolean isCancelled() { return cancelled; } + @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } + @Override @Nullable public String getCancelReason() { return cancelReason; } + @Override public void setCancelReason(@Nullable String reason) { this.cancelReason = reason; } +} diff --git a/src/main/java/com/hyperessentials/api/events/homes/HomeDeleteEvent.java b/src/main/java/com/hyperessentials/api/events/homes/HomeDeleteEvent.java new file mode 100644 index 0000000..2fee018 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/homes/HomeDeleteEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.homes; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public record HomeDeleteEvent( + @NotNull UUID playerUuid, + @NotNull String homeName +) {} diff --git a/src/main/java/com/hyperessentials/api/events/homes/HomeDeletePreEvent.java b/src/main/java/com/hyperessentials/api/events/homes/HomeDeletePreEvent.java new file mode 100644 index 0000000..e12ee01 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/homes/HomeDeletePreEvent.java @@ -0,0 +1,28 @@ +package com.hyperessentials.api.events.homes; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public final class HomeDeletePreEvent implements Cancellable { + + private final UUID playerUuid; + private final String homeName; + private boolean cancelled; + private String cancelReason; + + public HomeDeletePreEvent(@NotNull UUID playerUuid, @NotNull String homeName) { + this.playerUuid = playerUuid; + this.homeName = homeName; + } + + @NotNull public UUID playerUuid() { return playerUuid; } + @NotNull public String homeName() { return homeName; } + + @Override public boolean isCancelled() { return cancelled; } + @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } + @Override @Nullable public String getCancelReason() { return cancelReason; } + @Override public void setCancelReason(@Nullable String reason) { this.cancelReason = reason; } +} diff --git a/src/main/java/com/hyperessentials/api/events/homes/HomeSetEvent.java b/src/main/java/com/hyperessentials/api/events/homes/HomeSetEvent.java new file mode 100644 index 0000000..9b6d6b1 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/homes/HomeSetEvent.java @@ -0,0 +1,14 @@ +package com.hyperessentials.api.events.homes; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public record HomeSetEvent( + @NotNull UUID playerUuid, + @NotNull String homeName, + @NotNull String world, + double x, + double y, + double z +) {} diff --git a/src/main/java/com/hyperessentials/api/events/homes/HomeSetPreEvent.java b/src/main/java/com/hyperessentials/api/events/homes/HomeSetPreEvent.java new file mode 100644 index 0000000..de4ba23 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/homes/HomeSetPreEvent.java @@ -0,0 +1,41 @@ +package com.hyperessentials.api.events.homes; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public final class HomeSetPreEvent implements Cancellable { + + private final UUID playerUuid; + private final String homeName; + private final String world; + private final double x; + private final double y; + private final double z; + private boolean cancelled; + private String cancelReason; + + public HomeSetPreEvent(@NotNull UUID playerUuid, @NotNull String homeName, + @NotNull String world, double x, double y, double z) { + this.playerUuid = playerUuid; + this.homeName = homeName; + this.world = world; + this.x = x; + this.y = y; + this.z = z; + } + + @NotNull public UUID playerUuid() { return playerUuid; } + @NotNull public String homeName() { return homeName; } + @NotNull public String world() { return world; } + public double x() { return x; } + public double y() { return y; } + public double z() { return z; } + + @Override public boolean isCancelled() { return cancelled; } + @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } + @Override @Nullable public String getCancelReason() { return cancelReason; } + @Override public void setCancelReason(@Nullable String reason) { this.cancelReason = reason; } +} diff --git a/src/main/java/com/hyperessentials/api/events/homes/HomeShareEvent.java b/src/main/java/com/hyperessentials/api/events/homes/HomeShareEvent.java new file mode 100644 index 0000000..2f41958 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/homes/HomeShareEvent.java @@ -0,0 +1,11 @@ +package com.hyperessentials.api.events.homes; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public record HomeShareEvent( + @NotNull UUID ownerUuid, + @NotNull String homeName, + @NotNull UUID targetUuid +) {} diff --git a/src/main/java/com/hyperessentials/api/events/homes/HomeSharePreEvent.java b/src/main/java/com/hyperessentials/api/events/homes/HomeSharePreEvent.java new file mode 100644 index 0000000..87658e6 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/homes/HomeSharePreEvent.java @@ -0,0 +1,32 @@ +package com.hyperessentials.api.events.homes; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public final class HomeSharePreEvent implements Cancellable { + + private final UUID ownerUuid; + private final String homeName; + private final UUID targetUuid; + private boolean cancelled; + private String cancelReason; + + public HomeSharePreEvent(@NotNull UUID ownerUuid, @NotNull String homeName, + @NotNull UUID targetUuid) { + this.ownerUuid = ownerUuid; + this.homeName = homeName; + this.targetUuid = targetUuid; + } + + @NotNull public UUID ownerUuid() { return ownerUuid; } + @NotNull public String homeName() { return homeName; } + @NotNull public UUID targetUuid() { return targetUuid; } + + @Override public boolean isCancelled() { return cancelled; } + @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } + @Override @Nullable public String getCancelReason() { return cancelReason; } + @Override public void setCancelReason(@Nullable String reason) { this.cancelReason = reason; } +} diff --git a/src/main/java/com/hyperessentials/api/events/homes/HomeTeleportEvent.java b/src/main/java/com/hyperessentials/api/events/homes/HomeTeleportEvent.java new file mode 100644 index 0000000..a64abff --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/homes/HomeTeleportEvent.java @@ -0,0 +1,11 @@ +package com.hyperessentials.api.events.homes; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public record HomeTeleportEvent( + @NotNull UUID playerUuid, + @NotNull String homeName, + @NotNull String world +) {} diff --git a/src/main/java/com/hyperessentials/api/events/homes/HomeTeleportPreEvent.java b/src/main/java/com/hyperessentials/api/events/homes/HomeTeleportPreEvent.java new file mode 100644 index 0000000..41251b2 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/homes/HomeTeleportPreEvent.java @@ -0,0 +1,32 @@ +package com.hyperessentials.api.events.homes; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public final class HomeTeleportPreEvent implements Cancellable { + + private final UUID playerUuid; + private final String homeName; + private final String world; + private boolean cancelled; + private String cancelReason; + + public HomeTeleportPreEvent(@NotNull UUID playerUuid, @NotNull String homeName, + @NotNull String world) { + this.playerUuid = playerUuid; + this.homeName = homeName; + this.world = world; + } + + @NotNull public UUID playerUuid() { return playerUuid; } + @NotNull public String homeName() { return homeName; } + @NotNull public String world() { return world; } + + @Override public boolean isCancelled() { return cancelled; } + @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } + @Override @Nullable public String getCancelReason() { return cancelReason; } + @Override public void setCancelReason(@Nullable String reason) { this.cancelReason = reason; } +} diff --git a/src/main/java/com/hyperessentials/api/events/homes/HomeUnshareEvent.java b/src/main/java/com/hyperessentials/api/events/homes/HomeUnshareEvent.java new file mode 100644 index 0000000..bab61f2 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/homes/HomeUnshareEvent.java @@ -0,0 +1,11 @@ +package com.hyperessentials.api.events.homes; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public record HomeUnshareEvent( + @NotNull UUID ownerUuid, + @NotNull String homeName, + @NotNull UUID targetUuid +) {} diff --git a/src/main/java/com/hyperessentials/api/events/homes/HomeUnsharePreEvent.java b/src/main/java/com/hyperessentials/api/events/homes/HomeUnsharePreEvent.java new file mode 100644 index 0000000..37d40b1 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/homes/HomeUnsharePreEvent.java @@ -0,0 +1,32 @@ +package com.hyperessentials.api.events.homes; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public final class HomeUnsharePreEvent implements Cancellable { + + private final UUID ownerUuid; + private final String homeName; + private final UUID targetUuid; + private boolean cancelled; + private String cancelReason; + + public HomeUnsharePreEvent(@NotNull UUID ownerUuid, @NotNull String homeName, + @NotNull UUID targetUuid) { + this.ownerUuid = ownerUuid; + this.homeName = homeName; + this.targetUuid = targetUuid; + } + + @NotNull public UUID ownerUuid() { return ownerUuid; } + @NotNull public String homeName() { return homeName; } + @NotNull public UUID targetUuid() { return targetUuid; } + + @Override public boolean isCancelled() { return cancelled; } + @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } + @Override @Nullable public String getCancelReason() { return cancelReason; } + @Override public void setCancelReason(@Nullable String reason) { this.cancelReason = reason; } +} diff --git a/src/main/java/com/hyperessentials/api/events/kits/KitClaimEvent.java b/src/main/java/com/hyperessentials/api/events/kits/KitClaimEvent.java new file mode 100644 index 0000000..0b054a0 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/kits/KitClaimEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.kits; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +/** + * Fired after a player successfully claims a kit. + */ +public record KitClaimEvent(@NotNull UUID playerUuid, @NotNull String kitName) {} diff --git a/src/main/java/com/hyperessentials/api/events/kits/KitClaimPreEvent.java b/src/main/java/com/hyperessentials/api/events/kits/KitClaimPreEvent.java new file mode 100644 index 0000000..37281d2 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/kits/KitClaimPreEvent.java @@ -0,0 +1,55 @@ +package com.hyperessentials.api.events.kits; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired before a player claims a kit. + * Cancel to prevent the kit from being given. + */ +public final class KitClaimPreEvent implements Cancellable { + + private final UUID playerUuid; + private final String kitName; + private boolean cancelled; + private String cancelReason; + + public KitClaimPreEvent(@NotNull UUID playerUuid, @NotNull String kitName) { + this.playerUuid = playerUuid; + this.kitName = kitName; + } + + @NotNull + public UUID playerUuid() { + return playerUuid; + } + + @NotNull + public String kitName() { + return kitName; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @Override + @Nullable + public String getCancelReason() { + return cancelReason; + } + + @Override + public void setCancelReason(@Nullable String reason) { + this.cancelReason = reason; + } +} diff --git a/src/main/java/com/hyperessentials/api/events/kits/KitCreateEvent.java b/src/main/java/com/hyperessentials/api/events/kits/KitCreateEvent.java new file mode 100644 index 0000000..c8ef6d2 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/kits/KitCreateEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.kits; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +/** + * Fired after a new kit is successfully created. + */ +public record KitCreateEvent(@NotNull String kitName, @NotNull UUID actorUuid) {} diff --git a/src/main/java/com/hyperessentials/api/events/kits/KitCreatePreEvent.java b/src/main/java/com/hyperessentials/api/events/kits/KitCreatePreEvent.java new file mode 100644 index 0000000..046c63c --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/kits/KitCreatePreEvent.java @@ -0,0 +1,55 @@ +package com.hyperessentials.api.events.kits; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired before a new kit is created. + * Cancel to prevent the kit from being created. + */ +public final class KitCreatePreEvent implements Cancellable { + + private final String kitName; + private final UUID actorUuid; + private boolean cancelled; + private String cancelReason; + + public KitCreatePreEvent(@NotNull String kitName, @NotNull UUID actorUuid) { + this.kitName = kitName; + this.actorUuid = actorUuid; + } + + @NotNull + public String kitName() { + return kitName; + } + + @NotNull + public UUID actorUuid() { + return actorUuid; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @Override + @Nullable + public String getCancelReason() { + return cancelReason; + } + + @Override + public void setCancelReason(@Nullable String reason) { + this.cancelReason = reason; + } +} diff --git a/src/main/java/com/hyperessentials/api/events/kits/KitDeleteEvent.java b/src/main/java/com/hyperessentials/api/events/kits/KitDeleteEvent.java new file mode 100644 index 0000000..6f374f0 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/kits/KitDeleteEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.kits; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +/** + * Fired after a kit is successfully deleted. + */ +public record KitDeleteEvent(@NotNull String kitName, @NotNull UUID actorUuid) {} diff --git a/src/main/java/com/hyperessentials/api/events/kits/KitDeletePreEvent.java b/src/main/java/com/hyperessentials/api/events/kits/KitDeletePreEvent.java new file mode 100644 index 0000000..ebc7bdb --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/kits/KitDeletePreEvent.java @@ -0,0 +1,55 @@ +package com.hyperessentials.api.events.kits; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired before a kit is deleted. + * Cancel to prevent the kit from being deleted. + */ +public final class KitDeletePreEvent implements Cancellable { + + private final String kitName; + private final UUID actorUuid; + private boolean cancelled; + private String cancelReason; + + public KitDeletePreEvent(@NotNull String kitName, @NotNull UUID actorUuid) { + this.kitName = kitName; + this.actorUuid = actorUuid; + } + + @NotNull + public String kitName() { + return kitName; + } + + @NotNull + public UUID actorUuid() { + return actorUuid; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @Override + @Nullable + public String getCancelReason() { + return cancelReason; + } + + @Override + public void setCancelReason(@Nullable String reason) { + this.cancelReason = reason; + } +} diff --git a/src/main/java/com/hyperessentials/api/events/moderation/PlayerBanEvent.java b/src/main/java/com/hyperessentials/api/events/moderation/PlayerBanEvent.java new file mode 100644 index 0000000..998a3c1 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/moderation/PlayerBanEvent.java @@ -0,0 +1,12 @@ +package com.hyperessentials.api.events.moderation; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired after a player is successfully banned. + */ +public record PlayerBanEvent(@NotNull UUID targetUuid, @NotNull UUID actorUuid, + @NotNull String reason, @Nullable Long durationMs) {} diff --git a/src/main/java/com/hyperessentials/api/events/moderation/PlayerBanPreEvent.java b/src/main/java/com/hyperessentials/api/events/moderation/PlayerBanPreEvent.java new file mode 100644 index 0000000..224e323 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/moderation/PlayerBanPreEvent.java @@ -0,0 +1,73 @@ +package com.hyperessentials.api.events.moderation; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired before a player is banned. + * Cancel to prevent the ban. + */ +public final class PlayerBanPreEvent implements Cancellable { + + private final UUID targetUuid; + private final UUID actorUuid; + private final String reason; + private final Long durationMs; + private boolean cancelled; + private String cancelReason; + + public PlayerBanPreEvent(@NotNull UUID targetUuid, @NotNull UUID actorUuid, + @NotNull String reason, @Nullable Long durationMs) { + this.targetUuid = targetUuid; + this.actorUuid = actorUuid; + this.reason = reason; + this.durationMs = durationMs; + } + + @NotNull + public UUID targetUuid() { + return targetUuid; + } + + @NotNull + public UUID actorUuid() { + return actorUuid; + } + + @NotNull + public String reason() { + return reason; + } + + /** + * Duration in milliseconds, or {@code null} for a permanent ban. + */ + @Nullable + public Long durationMs() { + return durationMs; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @Override + @Nullable + public String getCancelReason() { + return cancelReason; + } + + @Override + public void setCancelReason(@Nullable String reason) { + this.cancelReason = reason; + } +} diff --git a/src/main/java/com/hyperessentials/api/events/moderation/PlayerKickEvent.java b/src/main/java/com/hyperessentials/api/events/moderation/PlayerKickEvent.java new file mode 100644 index 0000000..a7fd3d7 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/moderation/PlayerKickEvent.java @@ -0,0 +1,11 @@ +package com.hyperessentials.api.events.moderation; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +/** + * Fired after a player is successfully kicked. + */ +public record PlayerKickEvent(@NotNull UUID targetUuid, @NotNull UUID actorUuid, + @NotNull String reason) {} diff --git a/src/main/java/com/hyperessentials/api/events/moderation/PlayerKickPreEvent.java b/src/main/java/com/hyperessentials/api/events/moderation/PlayerKickPreEvent.java new file mode 100644 index 0000000..c32432e --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/moderation/PlayerKickPreEvent.java @@ -0,0 +1,63 @@ +package com.hyperessentials.api.events.moderation; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired before a player is kicked. + * Cancel to prevent the kick. + */ +public final class PlayerKickPreEvent implements Cancellable { + + private final UUID targetUuid; + private final UUID actorUuid; + private final String reason; + private boolean cancelled; + private String cancelReason; + + public PlayerKickPreEvent(@NotNull UUID targetUuid, @NotNull UUID actorUuid, + @NotNull String reason) { + this.targetUuid = targetUuid; + this.actorUuid = actorUuid; + this.reason = reason; + } + + @NotNull + public UUID targetUuid() { + return targetUuid; + } + + @NotNull + public UUID actorUuid() { + return actorUuid; + } + + @NotNull + public String reason() { + return reason; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @Override + @Nullable + public String getCancelReason() { + return cancelReason; + } + + @Override + public void setCancelReason(@Nullable String reason) { + this.cancelReason = reason; + } +} diff --git a/src/main/java/com/hyperessentials/api/events/moderation/PlayerMuteEvent.java b/src/main/java/com/hyperessentials/api/events/moderation/PlayerMuteEvent.java new file mode 100644 index 0000000..0cb8627 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/moderation/PlayerMuteEvent.java @@ -0,0 +1,12 @@ +package com.hyperessentials.api.events.moderation; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired after a player is successfully muted. + */ +public record PlayerMuteEvent(@NotNull UUID targetUuid, @NotNull UUID actorUuid, + @NotNull String reason, @Nullable Long durationMs) {} diff --git a/src/main/java/com/hyperessentials/api/events/moderation/PlayerMutePreEvent.java b/src/main/java/com/hyperessentials/api/events/moderation/PlayerMutePreEvent.java new file mode 100644 index 0000000..87a956a --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/moderation/PlayerMutePreEvent.java @@ -0,0 +1,73 @@ +package com.hyperessentials.api.events.moderation; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired before a player is muted. + * Cancel to prevent the mute. + */ +public final class PlayerMutePreEvent implements Cancellable { + + private final UUID targetUuid; + private final UUID actorUuid; + private final String reason; + private final Long durationMs; + private boolean cancelled; + private String cancelReason; + + public PlayerMutePreEvent(@NotNull UUID targetUuid, @NotNull UUID actorUuid, + @NotNull String reason, @Nullable Long durationMs) { + this.targetUuid = targetUuid; + this.actorUuid = actorUuid; + this.reason = reason; + this.durationMs = durationMs; + } + + @NotNull + public UUID targetUuid() { + return targetUuid; + } + + @NotNull + public UUID actorUuid() { + return actorUuid; + } + + @NotNull + public String reason() { + return reason; + } + + /** + * Duration in milliseconds, or {@code null} for a permanent mute. + */ + @Nullable + public Long durationMs() { + return durationMs; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @Override + @Nullable + public String getCancelReason() { + return cancelReason; + } + + @Override + public void setCancelReason(@Nullable String reason) { + this.cancelReason = reason; + } +} diff --git a/src/main/java/com/hyperessentials/api/events/moderation/PlayerUnbanEvent.java b/src/main/java/com/hyperessentials/api/events/moderation/PlayerUnbanEvent.java new file mode 100644 index 0000000..8162352 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/moderation/PlayerUnbanEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.moderation; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +/** + * Fired after a player is successfully unbanned. + */ +public record PlayerUnbanEvent(@NotNull UUID targetUuid, @NotNull UUID actorUuid) {} diff --git a/src/main/java/com/hyperessentials/api/events/moderation/PlayerUnbanPreEvent.java b/src/main/java/com/hyperessentials/api/events/moderation/PlayerUnbanPreEvent.java new file mode 100644 index 0000000..2ff2e0c --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/moderation/PlayerUnbanPreEvent.java @@ -0,0 +1,55 @@ +package com.hyperessentials.api.events.moderation; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired before a player is unbanned. + * Cancel to prevent the unban. + */ +public final class PlayerUnbanPreEvent implements Cancellable { + + private final UUID targetUuid; + private final UUID actorUuid; + private boolean cancelled; + private String cancelReason; + + public PlayerUnbanPreEvent(@NotNull UUID targetUuid, @NotNull UUID actorUuid) { + this.targetUuid = targetUuid; + this.actorUuid = actorUuid; + } + + @NotNull + public UUID targetUuid() { + return targetUuid; + } + + @NotNull + public UUID actorUuid() { + return actorUuid; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @Override + @Nullable + public String getCancelReason() { + return cancelReason; + } + + @Override + public void setCancelReason(@Nullable String reason) { + this.cancelReason = reason; + } +} diff --git a/src/main/java/com/hyperessentials/api/events/moderation/PlayerUnmuteEvent.java b/src/main/java/com/hyperessentials/api/events/moderation/PlayerUnmuteEvent.java new file mode 100644 index 0000000..676f44b --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/moderation/PlayerUnmuteEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.moderation; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +/** + * Fired after a player is successfully unmuted. + */ +public record PlayerUnmuteEvent(@NotNull UUID targetUuid, @NotNull UUID actorUuid) {} diff --git a/src/main/java/com/hyperessentials/api/events/moderation/PlayerUnmutePreEvent.java b/src/main/java/com/hyperessentials/api/events/moderation/PlayerUnmutePreEvent.java new file mode 100644 index 0000000..fd57205 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/moderation/PlayerUnmutePreEvent.java @@ -0,0 +1,55 @@ +package com.hyperessentials.api.events.moderation; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired before a player is unmuted. + * Cancel to prevent the unmute. + */ +public final class PlayerUnmutePreEvent implements Cancellable { + + private final UUID targetUuid; + private final UUID actorUuid; + private boolean cancelled; + private String cancelReason; + + public PlayerUnmutePreEvent(@NotNull UUID targetUuid, @NotNull UUID actorUuid) { + this.targetUuid = targetUuid; + this.actorUuid = actorUuid; + } + + @NotNull + public UUID targetUuid() { + return targetUuid; + } + + @NotNull + public UUID actorUuid() { + return actorUuid; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @Override + @Nullable + public String getCancelReason() { + return cancelReason; + } + + @Override + public void setCancelReason(@Nullable String reason) { + this.cancelReason = reason; + } +} diff --git a/src/main/java/com/hyperessentials/api/events/moderation/PlayerWarnEvent.java b/src/main/java/com/hyperessentials/api/events/moderation/PlayerWarnEvent.java new file mode 100644 index 0000000..3df4489 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/moderation/PlayerWarnEvent.java @@ -0,0 +1,11 @@ +package com.hyperessentials.api.events.moderation; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +/** + * Fired after a player is successfully warned. + */ +public record PlayerWarnEvent(@NotNull UUID targetUuid, @NotNull UUID actorUuid, + @NotNull String reason) {} diff --git a/src/main/java/com/hyperessentials/api/events/moderation/PlayerWarnPreEvent.java b/src/main/java/com/hyperessentials/api/events/moderation/PlayerWarnPreEvent.java new file mode 100644 index 0000000..2971e6e --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/moderation/PlayerWarnPreEvent.java @@ -0,0 +1,63 @@ +package com.hyperessentials.api.events.moderation; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired before a player is warned. + * Cancel to prevent the warning. + */ +public final class PlayerWarnPreEvent implements Cancellable { + + private final UUID targetUuid; + private final UUID actorUuid; + private final String reason; + private boolean cancelled; + private String cancelReason; + + public PlayerWarnPreEvent(@NotNull UUID targetUuid, @NotNull UUID actorUuid, + @NotNull String reason) { + this.targetUuid = targetUuid; + this.actorUuid = actorUuid; + this.reason = reason; + } + + @NotNull + public UUID targetUuid() { + return targetUuid; + } + + @NotNull + public UUID actorUuid() { + return actorUuid; + } + + @NotNull + public String reason() { + return reason; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @Override + @Nullable + public String getCancelReason() { + return cancelReason; + } + + @Override + public void setCancelReason(@Nullable String reason) { + this.cancelReason = reason; + } +} diff --git a/src/main/java/com/hyperessentials/api/events/spawns/SpawnDeleteEvent.java b/src/main/java/com/hyperessentials/api/events/spawns/SpawnDeleteEvent.java new file mode 100644 index 0000000..b0762f6 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/spawns/SpawnDeleteEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.spawns; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public record SpawnDeleteEvent( + @NotNull String worldUuid, + @NotNull UUID actorUuid +) {} diff --git a/src/main/java/com/hyperessentials/api/events/spawns/SpawnDeletePreEvent.java b/src/main/java/com/hyperessentials/api/events/spawns/SpawnDeletePreEvent.java new file mode 100644 index 0000000..c46a441 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/spawns/SpawnDeletePreEvent.java @@ -0,0 +1,28 @@ +package com.hyperessentials.api.events.spawns; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public final class SpawnDeletePreEvent implements Cancellable { + + private final String worldUuid; + private final UUID actorUuid; + private boolean cancelled; + private String cancelReason; + + public SpawnDeletePreEvent(@NotNull String worldUuid, @NotNull UUID actorUuid) { + this.worldUuid = worldUuid; + this.actorUuid = actorUuid; + } + + @NotNull public String worldUuid() { return worldUuid; } + @NotNull public UUID actorUuid() { return actorUuid; } + + @Override public boolean isCancelled() { return cancelled; } + @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } + @Override @Nullable public String getCancelReason() { return cancelReason; } + @Override public void setCancelReason(@Nullable String reason) { this.cancelReason = reason; } +} diff --git a/src/main/java/com/hyperessentials/api/events/spawns/SpawnSetEvent.java b/src/main/java/com/hyperessentials/api/events/spawns/SpawnSetEvent.java new file mode 100644 index 0000000..a1f8ca8 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/spawns/SpawnSetEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.spawns; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public record SpawnSetEvent( + @NotNull String worldUuid, + @NotNull UUID actorUuid +) {} diff --git a/src/main/java/com/hyperessentials/api/events/spawns/SpawnSetPreEvent.java b/src/main/java/com/hyperessentials/api/events/spawns/SpawnSetPreEvent.java new file mode 100644 index 0000000..b9e349d --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/spawns/SpawnSetPreEvent.java @@ -0,0 +1,28 @@ +package com.hyperessentials.api.events.spawns; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public final class SpawnSetPreEvent implements Cancellable { + + private final String worldUuid; + private final UUID actorUuid; + private boolean cancelled; + private String cancelReason; + + public SpawnSetPreEvent(@NotNull String worldUuid, @NotNull UUID actorUuid) { + this.worldUuid = worldUuid; + this.actorUuid = actorUuid; + } + + @NotNull public String worldUuid() { return worldUuid; } + @NotNull public UUID actorUuid() { return actorUuid; } + + @Override public boolean isCancelled() { return cancelled; } + @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } + @Override @Nullable public String getCancelReason() { return cancelReason; } + @Override public void setCancelReason(@Nullable String reason) { this.cancelReason = reason; } +} diff --git a/src/main/java/com/hyperessentials/api/events/spawns/SpawnTeleportEvent.java b/src/main/java/com/hyperessentials/api/events/spawns/SpawnTeleportEvent.java new file mode 100644 index 0000000..1534c02 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/spawns/SpawnTeleportEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.spawns; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public record SpawnTeleportEvent( + @NotNull UUID playerUuid, + @NotNull String worldUuid +) {} diff --git a/src/main/java/com/hyperessentials/api/events/spawns/SpawnTeleportPreEvent.java b/src/main/java/com/hyperessentials/api/events/spawns/SpawnTeleportPreEvent.java new file mode 100644 index 0000000..e882a24 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/spawns/SpawnTeleportPreEvent.java @@ -0,0 +1,28 @@ +package com.hyperessentials.api.events.spawns; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public final class SpawnTeleportPreEvent implements Cancellable { + + private final UUID playerUuid; + private final String worldUuid; + private boolean cancelled; + private String cancelReason; + + public SpawnTeleportPreEvent(@NotNull UUID playerUuid, @NotNull String worldUuid) { + this.playerUuid = playerUuid; + this.worldUuid = worldUuid; + } + + @NotNull public UUID playerUuid() { return playerUuid; } + @NotNull public String worldUuid() { return worldUuid; } + + @Override public boolean isCancelled() { return cancelled; } + @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } + @Override @Nullable public String getCancelReason() { return cancelReason; } + @Override public void setCancelReason(@Nullable String reason) { this.cancelReason = reason; } +} diff --git a/src/main/java/com/hyperessentials/api/events/teleport/BackTeleportEvent.java b/src/main/java/com/hyperessentials/api/events/teleport/BackTeleportEvent.java new file mode 100644 index 0000000..cf1f8aa --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/teleport/BackTeleportEvent.java @@ -0,0 +1,11 @@ +package com.hyperessentials.api.events.teleport; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +/** + * Fired after a player has teleported back to their previous location. + */ +public record BackTeleportEvent(@NotNull UUID playerUuid, @NotNull String world, + double x, double y, double z, @NotNull String source) {} diff --git a/src/main/java/com/hyperessentials/api/events/teleport/BackTeleportPreEvent.java b/src/main/java/com/hyperessentials/api/events/teleport/BackTeleportPreEvent.java new file mode 100644 index 0000000..ad74ba9 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/teleport/BackTeleportPreEvent.java @@ -0,0 +1,82 @@ +package com.hyperessentials.api.events.teleport; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired before a player teleports back to their previous location. + * Cancel to prevent the back-teleport. + */ +public final class BackTeleportPreEvent implements Cancellable { + + private final UUID playerUuid; + private final String world; + private final double x; + private final double y; + private final double z; + private final String source; + private boolean cancelled; + private String cancelReason; + + public BackTeleportPreEvent(@NotNull UUID playerUuid, @NotNull String world, + double x, double y, double z, @NotNull String source) { + this.playerUuid = playerUuid; + this.world = world; + this.x = x; + this.y = y; + this.z = z; + this.source = source; + } + + @NotNull + public UUID playerUuid() { + return playerUuid; + } + + @NotNull + public String world() { + return world; + } + + public double x() { + return x; + } + + public double y() { + return y; + } + + public double z() { + return z; + } + + /** The source that recorded this back location (e.g. "tpa", "warp", "home", "death"). */ + @NotNull + public String source() { + return source; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @Override + @Nullable + public String getCancelReason() { + return cancelReason; + } + + @Override + public void setCancelReason(@Nullable String reason) { + this.cancelReason = reason; + } +} diff --git a/src/main/java/com/hyperessentials/api/events/teleport/RtpEvent.java b/src/main/java/com/hyperessentials/api/events/teleport/RtpEvent.java new file mode 100644 index 0000000..d197b26 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/teleport/RtpEvent.java @@ -0,0 +1,11 @@ +package com.hyperessentials.api.events.teleport; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +/** + * Fired after a random teleport has completed successfully. + */ +public record RtpEvent(@NotNull UUID playerUuid, @NotNull String world, + double x, double y, double z) {} diff --git a/src/main/java/com/hyperessentials/api/events/teleport/RtpPreEvent.java b/src/main/java/com/hyperessentials/api/events/teleport/RtpPreEvent.java new file mode 100644 index 0000000..3998fda --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/teleport/RtpPreEvent.java @@ -0,0 +1,55 @@ +package com.hyperessentials.api.events.teleport; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired before a random teleport is initiated. + * Cancel to prevent the random teleport. + */ +public final class RtpPreEvent implements Cancellable { + + private final UUID playerUuid; + private final String world; + private boolean cancelled; + private String cancelReason; + + public RtpPreEvent(@NotNull UUID playerUuid, @NotNull String world) { + this.playerUuid = playerUuid; + this.world = world; + } + + @NotNull + public UUID playerUuid() { + return playerUuid; + } + + @NotNull + public String world() { + return world; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @Override + @Nullable + public String getCancelReason() { + return cancelReason; + } + + @Override + public void setCancelReason(@Nullable String reason) { + this.cancelReason = reason; + } +} diff --git a/src/main/java/com/hyperessentials/api/events/teleport/TpaAcceptEvent.java b/src/main/java/com/hyperessentials/api/events/teleport/TpaAcceptEvent.java new file mode 100644 index 0000000..dbb1b2b --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/teleport/TpaAcceptEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.teleport; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +/** + * Fired after a TPA request has been accepted successfully. + */ +public record TpaAcceptEvent(@NotNull UUID accepterUuid, @NotNull UUID requesterUuid) {} diff --git a/src/main/java/com/hyperessentials/api/events/teleport/TpaAcceptPreEvent.java b/src/main/java/com/hyperessentials/api/events/teleport/TpaAcceptPreEvent.java new file mode 100644 index 0000000..afe20b5 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/teleport/TpaAcceptPreEvent.java @@ -0,0 +1,55 @@ +package com.hyperessentials.api.events.teleport; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired before a TPA request is accepted. + * Cancel to prevent the acceptance. + */ +public final class TpaAcceptPreEvent implements Cancellable { + + private final UUID accepterUuid; + private final UUID requesterUuid; + private boolean cancelled; + private String cancelReason; + + public TpaAcceptPreEvent(@NotNull UUID accepterUuid, @NotNull UUID requesterUuid) { + this.accepterUuid = accepterUuid; + this.requesterUuid = requesterUuid; + } + + @NotNull + public UUID accepterUuid() { + return accepterUuid; + } + + @NotNull + public UUID requesterUuid() { + return requesterUuid; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @Override + @Nullable + public String getCancelReason() { + return cancelReason; + } + + @Override + public void setCancelReason(@Nullable String reason) { + this.cancelReason = reason; + } +} diff --git a/src/main/java/com/hyperessentials/api/events/teleport/TpaDenyEvent.java b/src/main/java/com/hyperessentials/api/events/teleport/TpaDenyEvent.java new file mode 100644 index 0000000..b3a77c7 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/teleport/TpaDenyEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.teleport; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +/** + * Fired after a TPA request has been denied. + */ +public record TpaDenyEvent(@NotNull UUID denierUuid, @NotNull UUID requesterUuid) {} diff --git a/src/main/java/com/hyperessentials/api/events/teleport/TpaDenyPreEvent.java b/src/main/java/com/hyperessentials/api/events/teleport/TpaDenyPreEvent.java new file mode 100644 index 0000000..c6b56e9 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/teleport/TpaDenyPreEvent.java @@ -0,0 +1,55 @@ +package com.hyperessentials.api.events.teleport; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired before a TPA request is denied. + * Cancel to prevent the denial. + */ +public final class TpaDenyPreEvent implements Cancellable { + + private final UUID denierUuid; + private final UUID requesterUuid; + private boolean cancelled; + private String cancelReason; + + public TpaDenyPreEvent(@NotNull UUID denierUuid, @NotNull UUID requesterUuid) { + this.denierUuid = denierUuid; + this.requesterUuid = requesterUuid; + } + + @NotNull + public UUID denierUuid() { + return denierUuid; + } + + @NotNull + public UUID requesterUuid() { + return requesterUuid; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @Override + @Nullable + public String getCancelReason() { + return cancelReason; + } + + @Override + public void setCancelReason(@Nullable String reason) { + this.cancelReason = reason; + } +} diff --git a/src/main/java/com/hyperessentials/api/events/teleport/TpaSendEvent.java b/src/main/java/com/hyperessentials/api/events/teleport/TpaSendEvent.java new file mode 100644 index 0000000..0c96a76 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/teleport/TpaSendEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.teleport; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +/** + * Fired after a TPA or TPAHere request has been sent successfully. + */ +public record TpaSendEvent(@NotNull UUID senderUuid, @NotNull UUID targetUuid, boolean here) {} diff --git a/src/main/java/com/hyperessentials/api/events/teleport/TpaSendPreEvent.java b/src/main/java/com/hyperessentials/api/events/teleport/TpaSendPreEvent.java new file mode 100644 index 0000000..7154073 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/teleport/TpaSendPreEvent.java @@ -0,0 +1,62 @@ +package com.hyperessentials.api.events.teleport; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired before a TPA or TPAHere request is sent. + * Cancel to prevent the request from being sent. + */ +public final class TpaSendPreEvent implements Cancellable { + + private final UUID senderUuid; + private final UUID targetUuid; + private final boolean here; + private boolean cancelled; + private String cancelReason; + + public TpaSendPreEvent(@NotNull UUID senderUuid, @NotNull UUID targetUuid, boolean here) { + this.senderUuid = senderUuid; + this.targetUuid = targetUuid; + this.here = here; + } + + @NotNull + public UUID senderUuid() { + return senderUuid; + } + + @NotNull + public UUID targetUuid() { + return targetUuid; + } + + /** Whether this is a TPAHere request (true) or a regular TPA request (false). */ + public boolean here() { + return here; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @Override + @Nullable + public String getCancelReason() { + return cancelReason; + } + + @Override + public void setCancelReason(@Nullable String reason) { + this.cancelReason = reason; + } +} diff --git a/src/main/java/com/hyperessentials/api/events/utility/AfkToggleEvent.java b/src/main/java/com/hyperessentials/api/events/utility/AfkToggleEvent.java new file mode 100644 index 0000000..9e9fe1b --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/utility/AfkToggleEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.utility; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +/** + * Fired after a player's AFK state has been toggled. + */ +public record AfkToggleEvent(@NotNull UUID playerUuid, boolean newState) {} diff --git a/src/main/java/com/hyperessentials/api/events/utility/AfkTogglePreEvent.java b/src/main/java/com/hyperessentials/api/events/utility/AfkTogglePreEvent.java new file mode 100644 index 0000000..e457c0b --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/utility/AfkTogglePreEvent.java @@ -0,0 +1,55 @@ +package com.hyperessentials.api.events.utility; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired before a player's AFK state is toggled. + * Cancel to prevent the toggle. + */ +public final class AfkTogglePreEvent implements Cancellable { + + private final UUID playerUuid; + private final boolean newState; + private boolean cancelled; + private String cancelReason; + + public AfkTogglePreEvent(@NotNull UUID playerUuid, boolean newState) { + this.playerUuid = playerUuid; + this.newState = newState; + } + + @NotNull + public UUID playerUuid() { + return playerUuid; + } + + /** The AFK state that will be set (true = going AFK, false = returning from AFK). */ + public boolean newState() { + return newState; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @Override + @Nullable + public String getCancelReason() { + return cancelReason; + } + + @Override + public void setCancelReason(@Nullable String reason) { + this.cancelReason = reason; + } +} diff --git a/src/main/java/com/hyperessentials/api/events/utility/FlyToggleEvent.java b/src/main/java/com/hyperessentials/api/events/utility/FlyToggleEvent.java new file mode 100644 index 0000000..714555b --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/utility/FlyToggleEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.utility; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +/** + * Fired after a player's fly mode has been toggled. + */ +public record FlyToggleEvent(@NotNull UUID playerUuid, boolean newState) {} diff --git a/src/main/java/com/hyperessentials/api/events/utility/FlyTogglePreEvent.java b/src/main/java/com/hyperessentials/api/events/utility/FlyTogglePreEvent.java new file mode 100644 index 0000000..6e2a2e9 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/utility/FlyTogglePreEvent.java @@ -0,0 +1,55 @@ +package com.hyperessentials.api.events.utility; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired before a player's fly mode is toggled. + * Cancel to prevent the toggle. + */ +public final class FlyTogglePreEvent implements Cancellable { + + private final UUID playerUuid; + private final boolean newState; + private boolean cancelled; + private String cancelReason; + + public FlyTogglePreEvent(@NotNull UUID playerUuid, boolean newState) { + this.playerUuid = playerUuid; + this.newState = newState; + } + + @NotNull + public UUID playerUuid() { + return playerUuid; + } + + /** The fly state that will be set (true = enabling, false = disabling). */ + public boolean newState() { + return newState; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @Override + @Nullable + public String getCancelReason() { + return cancelReason; + } + + @Override + public void setCancelReason(@Nullable String reason) { + this.cancelReason = reason; + } +} diff --git a/src/main/java/com/hyperessentials/api/events/utility/GodToggleEvent.java b/src/main/java/com/hyperessentials/api/events/utility/GodToggleEvent.java new file mode 100644 index 0000000..35b4178 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/utility/GodToggleEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.utility; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +/** + * Fired after a player's god mode has been toggled. + */ +public record GodToggleEvent(@NotNull UUID playerUuid, boolean newState) {} diff --git a/src/main/java/com/hyperessentials/api/events/utility/GodTogglePreEvent.java b/src/main/java/com/hyperessentials/api/events/utility/GodTogglePreEvent.java new file mode 100644 index 0000000..83ad5f5 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/utility/GodTogglePreEvent.java @@ -0,0 +1,55 @@ +package com.hyperessentials.api.events.utility; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +/** + * Fired before a player's god mode is toggled. + * Cancel to prevent the toggle. + */ +public final class GodTogglePreEvent implements Cancellable { + + private final UUID playerUuid; + private final boolean newState; + private boolean cancelled; + private String cancelReason; + + public GodTogglePreEvent(@NotNull UUID playerUuid, boolean newState) { + this.playerUuid = playerUuid; + this.newState = newState; + } + + @NotNull + public UUID playerUuid() { + return playerUuid; + } + + /** The god mode state that will be set (true = enabling, false = disabling). */ + public boolean newState() { + return newState; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + + @Override + @Nullable + public String getCancelReason() { + return cancelReason; + } + + @Override + public void setCancelReason(@Nullable String reason) { + this.cancelReason = reason; + } +} diff --git a/src/main/java/com/hyperessentials/api/events/warps/WarpDeleteEvent.java b/src/main/java/com/hyperessentials/api/events/warps/WarpDeleteEvent.java new file mode 100644 index 0000000..51e56c2 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/warps/WarpDeleteEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.warps; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public record WarpDeleteEvent( + @NotNull String warpName, + @NotNull UUID actorUuid +) {} diff --git a/src/main/java/com/hyperessentials/api/events/warps/WarpDeletePreEvent.java b/src/main/java/com/hyperessentials/api/events/warps/WarpDeletePreEvent.java new file mode 100644 index 0000000..b41c3f0 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/warps/WarpDeletePreEvent.java @@ -0,0 +1,28 @@ +package com.hyperessentials.api.events.warps; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public final class WarpDeletePreEvent implements Cancellable { + + private final String warpName; + private final UUID actorUuid; + private boolean cancelled; + private String cancelReason; + + public WarpDeletePreEvent(@NotNull String warpName, @NotNull UUID actorUuid) { + this.warpName = warpName; + this.actorUuid = actorUuid; + } + + @NotNull public String warpName() { return warpName; } + @NotNull public UUID actorUuid() { return actorUuid; } + + @Override public boolean isCancelled() { return cancelled; } + @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } + @Override @Nullable public String getCancelReason() { return cancelReason; } + @Override public void setCancelReason(@Nullable String reason) { this.cancelReason = reason; } +} diff --git a/src/main/java/com/hyperessentials/api/events/warps/WarpSetEvent.java b/src/main/java/com/hyperessentials/api/events/warps/WarpSetEvent.java new file mode 100644 index 0000000..50ee8a8 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/warps/WarpSetEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.warps; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public record WarpSetEvent( + @NotNull String warpName, + @NotNull UUID actorUuid +) {} diff --git a/src/main/java/com/hyperessentials/api/events/warps/WarpSetPreEvent.java b/src/main/java/com/hyperessentials/api/events/warps/WarpSetPreEvent.java new file mode 100644 index 0000000..1b5ca2c --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/warps/WarpSetPreEvent.java @@ -0,0 +1,28 @@ +package com.hyperessentials.api.events.warps; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public final class WarpSetPreEvent implements Cancellable { + + private final String warpName; + private final UUID actorUuid; + private boolean cancelled; + private String cancelReason; + + public WarpSetPreEvent(@NotNull String warpName, @NotNull UUID actorUuid) { + this.warpName = warpName; + this.actorUuid = actorUuid; + } + + @NotNull public String warpName() { return warpName; } + @NotNull public UUID actorUuid() { return actorUuid; } + + @Override public boolean isCancelled() { return cancelled; } + @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } + @Override @Nullable public String getCancelReason() { return cancelReason; } + @Override public void setCancelReason(@Nullable String reason) { this.cancelReason = reason; } +} diff --git a/src/main/java/com/hyperessentials/api/events/warps/WarpTeleportEvent.java b/src/main/java/com/hyperessentials/api/events/warps/WarpTeleportEvent.java new file mode 100644 index 0000000..5aca213 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/warps/WarpTeleportEvent.java @@ -0,0 +1,10 @@ +package com.hyperessentials.api.events.warps; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public record WarpTeleportEvent( + @NotNull UUID playerUuid, + @NotNull String warpName +) {} diff --git a/src/main/java/com/hyperessentials/api/events/warps/WarpTeleportPreEvent.java b/src/main/java/com/hyperessentials/api/events/warps/WarpTeleportPreEvent.java new file mode 100644 index 0000000..bfaa614 --- /dev/null +++ b/src/main/java/com/hyperessentials/api/events/warps/WarpTeleportPreEvent.java @@ -0,0 +1,28 @@ +package com.hyperessentials.api.events.warps; + +import com.hyperessentials.api.events.Cancellable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public final class WarpTeleportPreEvent implements Cancellable { + + private final UUID playerUuid; + private final String warpName; + private boolean cancelled; + private String cancelReason; + + public WarpTeleportPreEvent(@NotNull UUID playerUuid, @NotNull String warpName) { + this.playerUuid = playerUuid; + this.warpName = warpName; + } + + @NotNull public UUID playerUuid() { return playerUuid; } + @NotNull public String warpName() { return warpName; } + + @Override public boolean isCancelled() { return cancelled; } + @Override public void setCancelled(boolean cancelled) { this.cancelled = cancelled; } + @Override @Nullable public String getCancelReason() { return cancelReason; } + @Override public void setCancelReason(@Nullable String reason) { this.cancelReason = reason; } +} diff --git a/src/main/java/com/hyperessentials/integration/placeholder/HyperEssentialsExpansion.java b/src/main/java/com/hyperessentials/integration/placeholder/HyperEssentialsExpansion.java new file mode 100644 index 0000000..98270cd --- /dev/null +++ b/src/main/java/com/hyperessentials/integration/placeholder/HyperEssentialsExpansion.java @@ -0,0 +1,481 @@ +package com.hyperessentials.integration.placeholder; + +import at.helpch.placeholderapi.expansion.PlaceholderExpansion; +import com.hyperessentials.BuildInfo; +import com.hyperessentials.HyperEssentials; +import com.hyperessentials.api.HyperEssentialsAPI; +import com.hyperessentials.data.PlayerData; +import com.hyperessentials.module.homes.HomeManager; +import com.hyperessentials.module.homes.HomesModule; +import com.hyperessentials.module.kits.KitManager; +import com.hyperessentials.module.kits.KitsModule; +import com.hyperessentials.module.moderation.ModerationManager; +import com.hyperessentials.module.moderation.ModerationModule; +import com.hyperessentials.module.moderation.VanishManager; +import com.hyperessentials.module.moderation.data.Punishment; +import com.hyperessentials.module.moderation.data.PunishmentType; +import com.hyperessentials.module.spawns.SpawnManager; +import com.hyperessentials.module.spawns.SpawnsModule; +import com.hyperessentials.module.teleport.TeleportModule; +import com.hyperessentials.module.teleport.TpaManager; +import com.hyperessentials.module.utility.UtilityManager; +import com.hyperessentials.module.utility.UtilityModule; +import com.hyperessentials.module.warps.WarpManager; +import com.hyperessentials.module.warps.WarpsModule; +import com.hypixel.hytale.server.core.universe.PlayerRef; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.UUID; + +/** + * PlaceholderAPI expansion for HyperEssentials. + * + *

Exposes essentials data as PAPI placeholders for use by scoreboards, + * holograms, chat formatting, and other PAPI consumers. + * + *

Homes: + * %essentials_home_count% - Number of player's homes + * %essentials_home_limit% - Player's max homes allowed + * %essentials_home_default% - Name of player's default home + * %essentials_has_homes% - Whether player has any homes (true/false) + * + *

Kits: + * %essentials_kit_count% - Total number of kits defined + * %essentials_kit_available_count% - Number of kits available to the player + * %essentials_kit_cooldown_% - Remaining cooldown seconds for a kit + * + *

Moderation: + * %essentials_is_banned% - Whether player is banned (true/false) + * %essentials_is_muted% - Whether player is muted (true/false) + * %essentials_ban_reason% - Reason for active ban + * %essentials_mute_reason% - Reason for active mute + * %essentials_ban_expires% - Ban expiry date or "permanent" + * %essentials_mute_expires% - Mute expiry date or "permanent" + * %essentials_punishment_count% - Total number of punishments + * %essentials_warn_count% - Number of warnings + * + *

Utility: + * %essentials_is_afk% - Whether player is AFK (true/false) + * %essentials_is_flying% - Whether player is flying (true/false) + * %essentials_is_god% - Whether player has god mode (true/false) + * %essentials_is_infinite_stamina% - Whether player has infinite stamina (true/false) + * %essentials_is_vanished% - Whether player is vanished (true/false) + * %essentials_playtime% - Total playtime in milliseconds + * %essentials_playtime_formatted% - Total playtime formatted (e.g., 3d 2h 15m) + * %essentials_session_time% - Current session time in milliseconds + * %essentials_session_time_formatted% - Current session time formatted + * %essentials_first_join% - First join timestamp (ISO) + * %essentials_first_join_formatted% - First join date (yyyy-MM-dd HH:mm) + * %essentials_last_join% - Last join timestamp (ISO) + * %essentials_last_join_formatted% - Last join date (yyyy-MM-dd HH:mm) + * + *

Warps/Spawns/TPA: + * %essentials_warp_count% - Total number of warps + * %essentials_warp_accessible_count% - Number of warps accessible to the player + * %essentials_spawn_count% - Total number of spawns + * %essentials_is_accepting_tpa% - Whether player is accepting TPA requests (true/false) + * %essentials_tpa_pending_count% - Number of incoming TPA requests + */ +public class HyperEssentialsExpansion extends PlaceholderExpansion { + + private static final DateTimeFormatter DATE_FORMAT = + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").withZone(ZoneId.systemDefault()); + + private final HyperEssentials plugin; + + /** Creates a new HyperEssentialsExpansion. */ + public HyperEssentialsExpansion(@NotNull HyperEssentials plugin) { + this.plugin = plugin; + } + + @Override + public @NotNull String getIdentifier() { + return "essentials"; + } + + @Override + public @NotNull String getAuthor() { + return "HyperSystems-Development"; + } + + @Override + public @NotNull String getVersion() { + return BuildInfo.VERSION; + } + + /** Persist across reloads. */ + @Override + public boolean persist() { + return true; + } + + /** Called when a placeholder is requested. */ + @Override + @Nullable + public String onPlaceholderRequest(@Nullable PlayerRef player, @NotNull String params) { + if (player == null) { + return null; + } + + UUID uuid = player.getUuid(); + if (uuid == null) { + return null; + } + + // Handle dynamic kit cooldown placeholders before the switch + String lower = params.toLowerCase(); + if (lower.startsWith("kit_cooldown_")) { + String kitName = lower.substring("kit_cooldown_".length()); + KitManager km = kitManager(); + if (km == null) return ""; + long remainingMs = km.getRemainingCooldown(uuid, kitName); + return String.valueOf(remainingMs / 1000); + } + + return switch (lower) { + // Homes + case "home_count" -> homeCount(uuid); + case "home_limit" -> homeLimit(uuid); + case "home_default" -> homeDefault(uuid); + case "has_homes" -> hasHomes(uuid); + + // Kits + case "kit_count" -> kitCount(); + case "kit_available_count" -> kitAvailableCount(uuid); + + // Moderation + case "is_banned" -> isBanned(uuid); + case "is_muted" -> isMuted(uuid); + case "ban_reason" -> banReason(uuid); + case "mute_reason" -> muteReason(uuid); + case "ban_expires" -> banExpires(uuid); + case "mute_expires" -> muteExpires(uuid); + case "punishment_count" -> punishmentCount(uuid); + case "warn_count" -> warnCount(uuid); + + // Utility + case "is_afk" -> isAfk(uuid); + case "is_flying" -> isFlying(uuid); + case "is_god" -> isGod(uuid); + case "is_infinite_stamina" -> isInfiniteStamina(uuid); + case "is_vanished" -> isVanished(uuid); + case "playtime" -> playtime(uuid); + case "playtime_formatted" -> playtimeFormatted(uuid); + case "session_time" -> sessionTime(uuid); + case "session_time_formatted" -> sessionTimeFormatted(uuid); + case "first_join" -> firstJoin(uuid); + case "first_join_formatted" -> firstJoinFormatted(uuid); + case "last_join" -> lastJoin(uuid); + case "last_join_formatted" -> lastJoinFormatted(uuid); + + // Warps / Spawns / TPA + case "warp_count" -> warpCount(); + case "warp_accessible_count" -> warpAccessibleCount(uuid); + case "spawn_count" -> spawnCount(); + case "is_accepting_tpa" -> isAcceptingTpa(uuid); + case "tpa_pending_count" -> tpaPendingCount(uuid); + + default -> null; + }; + } + + // ========== Homes ========== + + private String homeCount(@NotNull UUID uuid) { + HomeManager hm = homeManager(); + return hm != null ? String.valueOf(hm.getHomeCount(uuid)) : "0"; + } + + private String homeLimit(@NotNull UUID uuid) { + HomeManager hm = homeManager(); + return hm != null ? String.valueOf(hm.getHomeLimit(uuid)) : "0"; + } + + private String homeDefault(@NotNull UUID uuid) { + HomeManager hm = homeManager(); + if (hm == null) return ""; + String def = hm.getDefaultHome(uuid); + return def != null ? def : ""; + } + + private String hasHomes(@NotNull UUID uuid) { + HomeManager hm = homeManager(); + return hm != null ? String.valueOf(hm.getHomeCount(uuid) > 0) : "false"; + } + + // ========== Kits ========== + + private String kitCount() { + KitManager km = kitManager(); + return km != null ? String.valueOf(km.getAllKits().size()) : "0"; + } + + private String kitAvailableCount(@NotNull UUID uuid) { + KitManager km = kitManager(); + return km != null ? String.valueOf(km.getAvailableKits(uuid).size()) : "0"; + } + + // ========== Moderation ========== + + private String isBanned(@NotNull UUID uuid) { + ModerationManager mm = moderationManager(); + return mm != null ? String.valueOf(mm.isBanned(uuid)) : "false"; + } + + private String isMuted(@NotNull UUID uuid) { + ModerationManager mm = moderationManager(); + return mm != null ? String.valueOf(mm.isMuted(uuid)) : "false"; + } + + private String banReason(@NotNull UUID uuid) { + ModerationManager mm = moderationManager(); + if (mm == null) return ""; + Punishment ban = mm.getActiveBan(uuid); + if (ban == null) return ""; + return ban.reason() != null ? ban.reason() : ""; + } + + private String muteReason(@NotNull UUID uuid) { + TpaManager tm = tpaManager(); + if (tm == null) return ""; + PlayerData data = tm.getPlayerData(uuid); + if (data == null) return ""; + Punishment mute = data.getActiveMute(); + if (mute == null) return ""; + return mute.reason() != null ? mute.reason() : ""; + } + + private String banExpires(@NotNull UUID uuid) { + ModerationManager mm = moderationManager(); + if (mm == null) return ""; + Punishment ban = mm.getActiveBan(uuid); + if (ban == null) return ""; + if (ban.isPermanent()) return "permanent"; + return formatInstant(ban.expiresAt()); + } + + private String muteExpires(@NotNull UUID uuid) { + TpaManager tm = tpaManager(); + if (tm == null) return ""; + PlayerData data = tm.getPlayerData(uuid); + if (data == null) return ""; + Punishment mute = data.getActiveMute(); + if (mute == null) return ""; + if (mute.isPermanent()) return "permanent"; + return formatInstant(mute.expiresAt()); + } + + private String punishmentCount(@NotNull UUID uuid) { + ModerationManager mm = moderationManager(); + if (mm == null) return "0"; + return String.valueOf(mm.getHistory(uuid).size()); + } + + private String warnCount(@NotNull UUID uuid) { + ModerationManager mm = moderationManager(); + if (mm == null) return "0"; + List history = mm.getHistory(uuid); + long count = history.stream() + .filter(p -> p.type() == PunishmentType.WARN) + .count(); + return String.valueOf(count); + } + + // ========== Utility ========== + + private String isAfk(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + return um != null ? String.valueOf(um.isAfk(uuid)) : "false"; + } + + private String isFlying(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + return um != null ? String.valueOf(um.isFlying(uuid)) : "false"; + } + + private String isGod(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + return um != null ? String.valueOf(um.isGod(uuid)) : "false"; + } + + private String isInfiniteStamina(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + return um != null ? String.valueOf(um.isInfiniteStamina(uuid)) : "false"; + } + + private String isVanished(@NotNull UUID uuid) { + VanishManager vm = vanishManager(); + return vm != null ? String.valueOf(vm.isVanished(uuid)) : "false"; + } + + private String playtime(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + return um != null ? String.valueOf(um.getTotalPlaytimeMs(uuid)) : "0"; + } + + private String playtimeFormatted(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + if (um == null) return "0m"; + return formatDuration(um.getTotalPlaytimeMs(uuid)); + } + + private String sessionTime(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + if (um == null) return "0"; + Instant sessionStart = um.getSessionStart(uuid); + if (sessionStart == null) return "0"; + return String.valueOf(Duration.between(sessionStart, Instant.now()).toMillis()); + } + + private String sessionTimeFormatted(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + if (um == null) return "0m"; + Instant sessionStart = um.getSessionStart(uuid); + if (sessionStart == null) return "0m"; + return formatDuration(Duration.between(sessionStart, Instant.now()).toMillis()); + } + + private String firstJoin(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + if (um == null) return ""; + Instant instant = um.getFirstJoin(uuid); + return instant != null ? instant.toString() : ""; + } + + private String firstJoinFormatted(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + if (um == null) return ""; + Instant instant = um.getFirstJoin(uuid); + return instant != null ? formatInstant(instant) : ""; + } + + private String lastJoin(@NotNull UUID uuid) { + TpaManager tm = tpaManager(); + if (tm == null) return ""; + PlayerData data = tm.getPlayerData(uuid); + if (data == null) return ""; + return data.getLastJoin().toString(); + } + + private String lastJoinFormatted(@NotNull UUID uuid) { + TpaManager tm = tpaManager(); + if (tm == null) return ""; + PlayerData data = tm.getPlayerData(uuid); + if (data == null) return ""; + return formatInstant(data.getLastJoin()); + } + + // ========== Warps / Spawns / TPA ========== + + private String warpCount() { + WarpManager wm = warpManager(); + return wm != null ? String.valueOf(wm.getWarpCount()) : "0"; + } + + private String warpAccessibleCount(@NotNull UUID uuid) { + WarpManager wm = warpManager(); + return wm != null ? String.valueOf(wm.getAccessibleWarps(uuid).size()) : "0"; + } + + private String spawnCount() { + SpawnManager sm = spawnManager(); + return sm != null ? String.valueOf(sm.getSpawnCount()) : "0"; + } + + private String isAcceptingTpa(@NotNull UUID uuid) { + TpaManager tm = tpaManager(); + return tm != null ? String.valueOf(tm.isAcceptingRequests(uuid)) : "true"; + } + + private String tpaPendingCount(@NotNull UUID uuid) { + TpaManager tm = tpaManager(); + return tm != null ? String.valueOf(tm.getIncomingRequests(uuid).size()) : "0"; + } + + // ========== Manager Accessors (null-safe) ========== + + @Nullable + private HomeManager homeManager() { + HomesModule m = plugin.getHomesModule(); + return (m != null && m.isEnabled()) ? m.getHomeManager() : null; + } + + @Nullable + private KitManager kitManager() { + KitsModule m = plugin.getKitsModule(); + return (m != null && m.isEnabled()) ? m.getKitManager() : null; + } + + @Nullable + private ModerationManager moderationManager() { + ModerationModule m = plugin.getModerationModule(); + return (m != null && m.isEnabled()) ? m.getModerationManager() : null; + } + + @Nullable + private VanishManager vanishManager() { + ModerationModule m = plugin.getModerationModule(); + return (m != null && m.isEnabled()) ? m.getVanishManager() : null; + } + + @Nullable + private UtilityManager utilityManager() { + UtilityModule m = plugin.getUtilityModule(); + return (m != null && m.isEnabled()) ? m.getUtilityManager() : null; + } + + @Nullable + private WarpManager warpManager() { + WarpsModule m = plugin.getWarpsModule(); + return (m != null && m.isEnabled()) ? m.getWarpManager() : null; + } + + @Nullable + private SpawnManager spawnManager() { + SpawnsModule m = plugin.getSpawnsModule(); + return (m != null && m.isEnabled()) ? m.getSpawnManager() : null; + } + + @Nullable + private TpaManager tpaManager() { + TeleportModule m = plugin.getTeleportModule(); + return (m != null && m.isEnabled()) ? m.getTpaManager() : null; + } + + // ========== Helpers ========== + + /** + * Formats a duration in milliseconds to a human-readable string. + * Examples: "3d 2h 15m", "5h 30m", "12m", "0m" + */ + @NotNull + private static String formatDuration(long ms) { + if (ms <= 0) return "0m"; + + long totalMinutes = ms / 60_000; + long days = totalMinutes / 1440; + long hours = (totalMinutes % 1440) / 60; + long minutes = totalMinutes % 60; + + StringBuilder sb = new StringBuilder(); + if (days > 0) sb.append(days).append("d "); + if (hours > 0) sb.append(hours).append("h "); + sb.append(minutes).append("m"); + return sb.toString().trim(); + } + + /** + * Formats an Instant to a human-readable date string (yyyy-MM-dd HH:mm). + */ + @NotNull + private static String formatInstant(@Nullable Instant instant) { + if (instant == null) return ""; + return DATE_FORMAT.format(instant); + } +} diff --git a/src/main/java/com/hyperessentials/integration/placeholder/PlaceholderAPIIntegration.java b/src/main/java/com/hyperessentials/integration/placeholder/PlaceholderAPIIntegration.java new file mode 100644 index 0000000..8d1a021 --- /dev/null +++ b/src/main/java/com/hyperessentials/integration/placeholder/PlaceholderAPIIntegration.java @@ -0,0 +1,83 @@ +package com.hyperessentials.integration.placeholder; + +import com.hyperessentials.HyperEssentials; +import com.hyperessentials.util.Logger; +import org.jetbrains.annotations.Nullable; + +/** + * Soft dependency integration with PlaceholderAPI. + * + *

+ * Detects PlaceholderAPI at runtime and registers the HyperEssentials + * expansion to expose essentials data as placeholders. + * + *

+ * Internal expansions must be manually registered since they are not + * separate JARs in the expansions folder. + */ +public final class PlaceholderAPIIntegration { + + private static boolean available = false; + + @Nullable + private static HyperEssentialsExpansion expansion; + + private PlaceholderAPIIntegration() {} + + /** + * Initializes PlaceholderAPI integration. + * Detects PAPI at runtime and registers the expansion. + * Must be called after all managers are initialized. + * + * @param plugin the HyperEssentials instance + */ + public static void init(HyperEssentials plugin) { + try { + Class.forName("at.helpch.placeholderapi.PlaceholderAPI"); + } catch (ClassNotFoundException e) { + Logger.info("[Integration] PlaceholderAPI not found - placeholders disabled"); + return; + } + + try { + expansion = new HyperEssentialsExpansion(plugin); + // Internal expansions must be manually registered + boolean registered = expansion.register(); + if (registered) { + available = true; + Logger.info("[Integration] PlaceholderAPI expansion registered (%%essentials_*%%)"); + } else { + Logger.warn("PlaceholderAPI expansion registration failed"); + expansion = null; + } + } catch (Exception e) { + Logger.severe("Failed to register PlaceholderAPI expansion: %s", e.getMessage()); + expansion = null; + } + } + + /** + * Shuts down PlaceholderAPI integration. + * Unregisters the expansion. + */ + public static void shutdown() { + if (expansion != null) { + try { + expansion.unregister(); + } catch (Exception e) { + Logger.debug("Failed to unregister PlaceholderAPI expansion: %s", e.getMessage()); + } + expansion = null; + } + available = false; + } + + /** + * Checks if PlaceholderAPI is available and the expansion is registered. + * + * @return true if available + */ + public static boolean isAvailable() { + return available; + } +} diff --git a/src/main/java/com/hyperessentials/integration/placeholder/WiFlowExpansion.java b/src/main/java/com/hyperessentials/integration/placeholder/WiFlowExpansion.java new file mode 100644 index 0000000..bcd4757 --- /dev/null +++ b/src/main/java/com/hyperessentials/integration/placeholder/WiFlowExpansion.java @@ -0,0 +1,507 @@ +package com.hyperessentials.integration.placeholder; + +import com.hyperessentials.BuildInfo; +import com.hyperessentials.HyperEssentials; +import com.hyperessentials.data.PlayerData; +import com.hyperessentials.module.homes.HomeManager; +import com.hyperessentials.module.homes.HomesModule; +import com.hyperessentials.module.kits.KitManager; +import com.hyperessentials.module.kits.KitsModule; +import com.hyperessentials.module.moderation.ModerationManager; +import com.hyperessentials.module.moderation.ModerationModule; +import com.hyperessentials.module.moderation.VanishManager; +import com.hyperessentials.module.moderation.data.Punishment; +import com.hyperessentials.module.moderation.data.PunishmentType; +import com.hyperessentials.module.spawns.SpawnManager; +import com.hyperessentials.module.spawns.SpawnsModule; +import com.hyperessentials.module.teleport.TeleportModule; +import com.hyperessentials.module.teleport.TpaManager; +import com.hyperessentials.module.utility.UtilityManager; +import com.hyperessentials.module.utility.UtilityModule; +import com.hyperessentials.module.warps.WarpManager; +import com.hyperessentials.module.warps.WarpsModule; +import com.wiflow.placeholderapi.context.PlaceholderContext; +import com.wiflow.placeholderapi.expansion.PlaceholderExpansion; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.UUID; + +/** + * WiFlow PlaceholderAPI expansion for HyperEssentials. + * + *

Exposes essentials data as WiFlow placeholders ({@code {essentials_xxx}}) for use + * by scoreboards, holograms, chat formatting, and other WiFlow consumers. + * + *

Homes: + * {essentials_home_count} - Number of player's homes + * {essentials_home_limit} - Player's max homes allowed + * {essentials_home_default} - Name of player's default home + * {essentials_has_homes} - Whether player has any homes (true/false) + * + *

Kits: + * {essentials_kit_count} - Total number of kits defined + * {essentials_kit_available_count} - Number of kits available to the player + * {essentials_kit_cooldown_} - Remaining cooldown seconds for a kit + * + *

Moderation: + * {essentials_is_banned} - Whether player is banned (true/false) + * {essentials_is_muted} - Whether player is muted (true/false) + * {essentials_ban_reason} - Reason for active ban + * {essentials_mute_reason} - Reason for active mute + * {essentials_ban_expires} - Ban expiry date or "permanent" + * {essentials_mute_expires} - Mute expiry date or "permanent" + * {essentials_punishment_count} - Total number of punishments + * {essentials_warn_count} - Number of warnings + * + *

Utility: + * {essentials_is_afk} - Whether player is AFK (true/false) + * {essentials_is_flying} - Whether player is flying (true/false) + * {essentials_is_god} - Whether player has god mode (true/false) + * {essentials_is_infinite_stamina} - Whether player has infinite stamina (true/false) + * {essentials_is_vanished} - Whether player is vanished (true/false) + * {essentials_playtime} - Total playtime in milliseconds + * {essentials_playtime_formatted} - Total playtime formatted (e.g., 3d 2h 15m) + * {essentials_session_time} - Current session time in milliseconds + * {essentials_session_time_formatted} - Current session time formatted + * {essentials_first_join} - First join timestamp (ISO) + * {essentials_first_join_formatted} - First join date (yyyy-MM-dd HH:mm) + * {essentials_last_join} - Last join timestamp (ISO) + * {essentials_last_join_formatted} - Last join date (yyyy-MM-dd HH:mm) + * + *

Warps/Spawns/TPA: + * {essentials_warp_count} - Total number of warps + * {essentials_warp_accessible_count} - Number of warps accessible to the player + * {essentials_spawn_count} - Total number of spawns + * {essentials_is_accepting_tpa} - Whether player is accepting TPA requests (true/false) + * {essentials_tpa_pending_count} - Number of incoming TPA requests + */ +public class WiFlowExpansion extends PlaceholderExpansion { + + private static final DateTimeFormatter DATE_FORMAT = + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm").withZone(ZoneId.systemDefault()); + + private final HyperEssentials plugin; + + /** Creates a new WiFlowExpansion. */ + public WiFlowExpansion(@NotNull HyperEssentials plugin) { + this.plugin = plugin; + } + + /** Returns the identifier. */ + @Override + public String getIdentifier() { + return "essentials"; + } + + /** Returns the author. */ + @Override + public String getAuthor() { + return "HyperSystems-Development"; + } + + /** Returns the version. */ + @Override + public String getVersion() { + return BuildInfo.VERSION; + } + + /** Returns the name. */ + @Override + public String getName() { + return "HyperEssentials"; + } + + @Override + public String getDescription() { + return "HyperEssentials data placeholders: homes, kits, moderation, utility, warps, spawns, TPA"; + } + + /** Persist across reloads. */ + @Override + public boolean persist() { + return true; + } + + /** Returns the placeholders. */ + @Override + public List getPlaceholders() { + return List.of( + "home_count", "home_limit", "home_default", "has_homes", + "kit_count", "kit_available_count", + "is_banned", "is_muted", "ban_reason", "mute_reason", + "ban_expires", "mute_expires", "punishment_count", "warn_count", + "is_afk", "is_flying", "is_god", "is_infinite_stamina", "is_vanished", + "playtime", "playtime_formatted", "session_time", "session_time_formatted", + "first_join", "first_join_formatted", "last_join", "last_join_formatted", + "warp_count", "warp_accessible_count", "spawn_count", + "is_accepting_tpa", "tpa_pending_count" + ); + } + + /** Called when a placeholder is requested. */ + @Override + @Nullable + public String onPlaceholderRequest(@NotNull PlaceholderContext context, @NotNull String params) { + UUID uuid = context.getPlayerUuid(); + if (uuid == null) { + return null; + } + + // Handle dynamic kit cooldown placeholders before the switch + String lower = params.toLowerCase(); + if (lower.startsWith("kit_cooldown_")) { + String kitName = lower.substring("kit_cooldown_".length()); + KitManager km = kitManager(); + if (km == null) return ""; + long remainingMs = km.getRemainingCooldown(uuid, kitName); + return String.valueOf(remainingMs / 1000); + } + + return switch (lower) { + // Homes + case "home_count" -> homeCount(uuid); + case "home_limit" -> homeLimit(uuid); + case "home_default" -> homeDefault(uuid); + case "has_homes" -> hasHomes(uuid); + + // Kits + case "kit_count" -> kitCount(); + case "kit_available_count" -> kitAvailableCount(uuid); + + // Moderation + case "is_banned" -> isBanned(uuid); + case "is_muted" -> isMuted(uuid); + case "ban_reason" -> banReason(uuid); + case "mute_reason" -> muteReason(uuid); + case "ban_expires" -> banExpires(uuid); + case "mute_expires" -> muteExpires(uuid); + case "punishment_count" -> punishmentCount(uuid); + case "warn_count" -> warnCount(uuid); + + // Utility + case "is_afk" -> isAfk(uuid); + case "is_flying" -> isFlying(uuid); + case "is_god" -> isGod(uuid); + case "is_infinite_stamina" -> isInfiniteStamina(uuid); + case "is_vanished" -> isVanished(uuid); + case "playtime" -> playtime(uuid); + case "playtime_formatted" -> playtimeFormatted(uuid); + case "session_time" -> sessionTime(uuid); + case "session_time_formatted" -> sessionTimeFormatted(uuid); + case "first_join" -> firstJoin(uuid); + case "first_join_formatted" -> firstJoinFormatted(uuid); + case "last_join" -> lastJoin(uuid); + case "last_join_formatted" -> lastJoinFormatted(uuid); + + // Warps / Spawns / TPA + case "warp_count" -> warpCount(); + case "warp_accessible_count" -> warpAccessibleCount(uuid); + case "spawn_count" -> spawnCount(); + case "is_accepting_tpa" -> isAcceptingTpa(uuid); + case "tpa_pending_count" -> tpaPendingCount(uuid); + + default -> null; // Unknown placeholder - preserve original text + }; + } + + // ========== Homes ========== + + private String homeCount(@NotNull UUID uuid) { + HomeManager hm = homeManager(); + return hm != null ? String.valueOf(hm.getHomeCount(uuid)) : "0"; + } + + private String homeLimit(@NotNull UUID uuid) { + HomeManager hm = homeManager(); + return hm != null ? String.valueOf(hm.getHomeLimit(uuid)) : "0"; + } + + private String homeDefault(@NotNull UUID uuid) { + HomeManager hm = homeManager(); + if (hm == null) return ""; + String def = hm.getDefaultHome(uuid); + return def != null ? def : ""; + } + + private String hasHomes(@NotNull UUID uuid) { + HomeManager hm = homeManager(); + return hm != null ? String.valueOf(hm.getHomeCount(uuid) > 0) : "false"; + } + + // ========== Kits ========== + + private String kitCount() { + KitManager km = kitManager(); + return km != null ? String.valueOf(km.getAllKits().size()) : "0"; + } + + private String kitAvailableCount(@NotNull UUID uuid) { + KitManager km = kitManager(); + return km != null ? String.valueOf(km.getAvailableKits(uuid).size()) : "0"; + } + + // ========== Moderation ========== + + private String isBanned(@NotNull UUID uuid) { + ModerationManager mm = moderationManager(); + return mm != null ? String.valueOf(mm.isBanned(uuid)) : "false"; + } + + private String isMuted(@NotNull UUID uuid) { + ModerationManager mm = moderationManager(); + return mm != null ? String.valueOf(mm.isMuted(uuid)) : "false"; + } + + private String banReason(@NotNull UUID uuid) { + ModerationManager mm = moderationManager(); + if (mm == null) return ""; + Punishment ban = mm.getActiveBan(uuid); + if (ban == null) return ""; + return ban.reason() != null ? ban.reason() : ""; + } + + private String muteReason(@NotNull UUID uuid) { + TpaManager tm = tpaManager(); + if (tm == null) return ""; + PlayerData data = tm.getPlayerData(uuid); + if (data == null) return ""; + Punishment mute = data.getActiveMute(); + if (mute == null) return ""; + return mute.reason() != null ? mute.reason() : ""; + } + + private String banExpires(@NotNull UUID uuid) { + ModerationManager mm = moderationManager(); + if (mm == null) return ""; + Punishment ban = mm.getActiveBan(uuid); + if (ban == null) return ""; + if (ban.isPermanent()) return "permanent"; + return formatInstant(ban.expiresAt()); + } + + private String muteExpires(@NotNull UUID uuid) { + TpaManager tm = tpaManager(); + if (tm == null) return ""; + PlayerData data = tm.getPlayerData(uuid); + if (data == null) return ""; + Punishment mute = data.getActiveMute(); + if (mute == null) return ""; + if (mute.isPermanent()) return "permanent"; + return formatInstant(mute.expiresAt()); + } + + private String punishmentCount(@NotNull UUID uuid) { + ModerationManager mm = moderationManager(); + if (mm == null) return "0"; + return String.valueOf(mm.getHistory(uuid).size()); + } + + private String warnCount(@NotNull UUID uuid) { + ModerationManager mm = moderationManager(); + if (mm == null) return "0"; + List history = mm.getHistory(uuid); + long count = history.stream() + .filter(p -> p.type() == PunishmentType.WARN) + .count(); + return String.valueOf(count); + } + + // ========== Utility ========== + + private String isAfk(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + return um != null ? String.valueOf(um.isAfk(uuid)) : "false"; + } + + private String isFlying(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + return um != null ? String.valueOf(um.isFlying(uuid)) : "false"; + } + + private String isGod(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + return um != null ? String.valueOf(um.isGod(uuid)) : "false"; + } + + private String isInfiniteStamina(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + return um != null ? String.valueOf(um.isInfiniteStamina(uuid)) : "false"; + } + + private String isVanished(@NotNull UUID uuid) { + VanishManager vm = vanishManager(); + return vm != null ? String.valueOf(vm.isVanished(uuid)) : "false"; + } + + private String playtime(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + return um != null ? String.valueOf(um.getTotalPlaytimeMs(uuid)) : "0"; + } + + private String playtimeFormatted(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + if (um == null) return "0m"; + return formatDuration(um.getTotalPlaytimeMs(uuid)); + } + + private String sessionTime(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + if (um == null) return "0"; + Instant sessionStart = um.getSessionStart(uuid); + if (sessionStart == null) return "0"; + return String.valueOf(Duration.between(sessionStart, Instant.now()).toMillis()); + } + + private String sessionTimeFormatted(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + if (um == null) return "0m"; + Instant sessionStart = um.getSessionStart(uuid); + if (sessionStart == null) return "0m"; + return formatDuration(Duration.between(sessionStart, Instant.now()).toMillis()); + } + + private String firstJoin(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + if (um == null) return ""; + Instant instant = um.getFirstJoin(uuid); + return instant != null ? instant.toString() : ""; + } + + private String firstJoinFormatted(@NotNull UUID uuid) { + UtilityManager um = utilityManager(); + if (um == null) return ""; + Instant instant = um.getFirstJoin(uuid); + return instant != null ? formatInstant(instant) : ""; + } + + private String lastJoin(@NotNull UUID uuid) { + TpaManager tm = tpaManager(); + if (tm == null) return ""; + PlayerData data = tm.getPlayerData(uuid); + if (data == null) return ""; + return data.getLastJoin().toString(); + } + + private String lastJoinFormatted(@NotNull UUID uuid) { + TpaManager tm = tpaManager(); + if (tm == null) return ""; + PlayerData data = tm.getPlayerData(uuid); + if (data == null) return ""; + return formatInstant(data.getLastJoin()); + } + + // ========== Warps / Spawns / TPA ========== + + private String warpCount() { + WarpManager wm = warpManager(); + return wm != null ? String.valueOf(wm.getWarpCount()) : "0"; + } + + private String warpAccessibleCount(@NotNull UUID uuid) { + WarpManager wm = warpManager(); + return wm != null ? String.valueOf(wm.getAccessibleWarps(uuid).size()) : "0"; + } + + private String spawnCount() { + SpawnManager sm = spawnManager(); + return sm != null ? String.valueOf(sm.getSpawnCount()) : "0"; + } + + private String isAcceptingTpa(@NotNull UUID uuid) { + TpaManager tm = tpaManager(); + return tm != null ? String.valueOf(tm.isAcceptingRequests(uuid)) : "true"; + } + + private String tpaPendingCount(@NotNull UUID uuid) { + TpaManager tm = tpaManager(); + return tm != null ? String.valueOf(tm.getIncomingRequests(uuid).size()) : "0"; + } + + // ========== Manager Accessors (null-safe) ========== + + @Nullable + private HomeManager homeManager() { + HomesModule m = plugin.getHomesModule(); + return (m != null && m.isEnabled()) ? m.getHomeManager() : null; + } + + @Nullable + private KitManager kitManager() { + KitsModule m = plugin.getKitsModule(); + return (m != null && m.isEnabled()) ? m.getKitManager() : null; + } + + @Nullable + private ModerationManager moderationManager() { + ModerationModule m = plugin.getModerationModule(); + return (m != null && m.isEnabled()) ? m.getModerationManager() : null; + } + + @Nullable + private VanishManager vanishManager() { + ModerationModule m = plugin.getModerationModule(); + return (m != null && m.isEnabled()) ? m.getVanishManager() : null; + } + + @Nullable + private UtilityManager utilityManager() { + UtilityModule m = plugin.getUtilityModule(); + return (m != null && m.isEnabled()) ? m.getUtilityManager() : null; + } + + @Nullable + private WarpManager warpManager() { + WarpsModule m = plugin.getWarpsModule(); + return (m != null && m.isEnabled()) ? m.getWarpManager() : null; + } + + @Nullable + private SpawnManager spawnManager() { + SpawnsModule m = plugin.getSpawnsModule(); + return (m != null && m.isEnabled()) ? m.getSpawnManager() : null; + } + + @Nullable + private TpaManager tpaManager() { + TeleportModule m = plugin.getTeleportModule(); + return (m != null && m.isEnabled()) ? m.getTpaManager() : null; + } + + // ========== Helpers ========== + + /** + * Formats a duration in milliseconds to a human-readable string. + * Examples: "3d 2h 15m", "5h 30m", "12m", "0m" + */ + @NotNull + private static String formatDuration(long ms) { + if (ms <= 0) return "0m"; + + long totalMinutes = ms / 60_000; + long days = totalMinutes / 1440; + long hours = (totalMinutes % 1440) / 60; + long minutes = totalMinutes % 60; + + StringBuilder sb = new StringBuilder(); + if (days > 0) sb.append(days).append("d "); + if (hours > 0) sb.append(hours).append("h "); + sb.append(minutes).append("m"); + return sb.toString().trim(); + } + + /** + * Formats an Instant to a human-readable date string (yyyy-MM-dd HH:mm). + */ + @NotNull + private static String formatInstant(@Nullable Instant instant) { + if (instant == null) return ""; + return DATE_FORMAT.format(instant); + } +} diff --git a/src/main/java/com/hyperessentials/integration/placeholder/WiFlowPlaceholderIntegration.java b/src/main/java/com/hyperessentials/integration/placeholder/WiFlowPlaceholderIntegration.java new file mode 100644 index 0000000..e37e7d1 --- /dev/null +++ b/src/main/java/com/hyperessentials/integration/placeholder/WiFlowPlaceholderIntegration.java @@ -0,0 +1,106 @@ +package com.hyperessentials.integration.placeholder; + +import com.hyperessentials.HyperEssentials; +import com.hyperessentials.util.ErrorHandler; +import com.hyperessentials.util.Logger; + +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Method; + +/** + * Soft dependency integration with WiFlow PlaceholderAPI. + * + *

All WiFlow classes are accessed via reflection so HyperEssentials compiles + * and runs without the WiFlowPlaceholderAPI JAR present. + * + *

The actual expansion implementation lives in {@code WiFlowExpansion} which + * extends PlaceholderExpansion directly — that class is conditionally compiled + * only when the WiFlow API is available on the classpath. + */ +public final class WiFlowPlaceholderIntegration { + + private static boolean available = false; + + @Nullable + private static Object expansion; + + // Cached reflection handles for shutdown + private static Method unregisterMethod; + + private static Class baseExpansionClass; + + private WiFlowPlaceholderIntegration() {} + + /** + * Initializes WiFlow PlaceholderAPI integration. + * Detects WiFlow at runtime and registers the expansion. + * Must be called after all managers are initialized. + * + * @param plugin the HyperEssentials instance + */ + public static void init(HyperEssentials plugin) { + try { + Class.forName("com.wiflow.placeholderapi.WiFlowPlaceholderAPI"); + } catch (ClassNotFoundException e) { + Logger.info("[Integration] WiFlow PlaceholderAPI not found - WiFlow placeholders disabled"); + return; + } + + try { + // WiFlowExpansion extends PlaceholderExpansion — only compiled when WiFlow is available. + // Load it reflectively to avoid a compile-time dependency in this class. + Class expansionClass = Class.forName( + "com.hyperessentials.integration.placeholder.WiFlowExpansion"); + expansion = expansionClass.getConstructor(HyperEssentials.class).newInstance(plugin); + + // WiFlowPlaceholderAPI.registerExpansion(PlaceholderExpansion) + Class apiClass = Class.forName("com.wiflow.placeholderapi.WiFlowPlaceholderAPI"); + baseExpansionClass = Class.forName("com.wiflow.placeholderapi.expansion.PlaceholderExpansion"); + Method registerMethod = apiClass.getMethod("registerExpansion", baseExpansionClass); + boolean registered = (boolean) registerMethod.invoke(null, expansion); + + if (registered) { + // Cache unregister method for shutdown + unregisterMethod = apiClass.getMethod("unregisterExpansion", baseExpansionClass); + available = true; + Logger.info("[Integration] WiFlow PlaceholderAPI expansion registered ({essentials_*})"); + } else { + Logger.warn("WiFlow PlaceholderAPI expansion registration failed"); + expansion = null; + } + } catch (Exception e) { + ErrorHandler.report("Failed to register WiFlow PlaceholderAPI expansion", e); + expansion = null; + } + } + + /** + * Shuts down WiFlow PlaceholderAPI integration. + * Unregisters the expansion. + */ + public static void shutdown() { + if (expansion != null) { + try { + if (unregisterMethod != null) { + unregisterMethod.invoke(null, expansion); + } + } catch (Exception e) { + Logger.debug("Failed to unregister WiFlow PlaceholderAPI expansion: %s", e.getMessage()); + } + expansion = null; + unregisterMethod = null; + baseExpansionClass = null; + } + available = false; + } + + /** + * Checks if WiFlow PlaceholderAPI is available and the expansion is registered. + * + * @return true if available + */ + public static boolean isAvailable() { + return available; + } +} diff --git a/src/main/java/com/hyperessentials/module/homes/HomeManager.java b/src/main/java/com/hyperessentials/module/homes/HomeManager.java index a39c12b..7d634ff 100644 --- a/src/main/java/com/hyperessentials/module/homes/HomeManager.java +++ b/src/main/java/com/hyperessentials/module/homes/HomeManager.java @@ -1,6 +1,8 @@ package com.hyperessentials.module.homes; import com.hyperessentials.Permissions; +import com.hyperessentials.api.events.EventBus; +import com.hyperessentials.api.events.homes.*; import com.hyperessentials.command.util.CommandUtil; import com.hyperessentials.config.ConfigManager; import com.hyperessentials.config.modules.HomesConfig; @@ -144,10 +146,16 @@ public boolean setHome(@NotNull UUID uuid, @NotNull Home home) { if (isAtLimit(uuid)) return false; } + if (EventBus.publishCancellable(new HomeSetPreEvent(uuid, home.name(), home.world(), home.x(), home.y(), home.z()))) { + return false; + } + homes.setHome(home); savePlayer(uuid); fireHomeChanged(uuid); Logger.debug("[Homes] Set home '%s' for %s", home.name(), uuid); + + EventBus.publish(new HomeSetEvent(uuid, home.name(), home.world(), home.x(), home.y(), home.z())); return true; } @@ -155,6 +163,10 @@ public boolean deleteHome(@NotNull UUID uuid, @NotNull String name) { PlayerHomes homes = cache.get(uuid); if (homes == null) return false; + if (EventBus.publishCancellable(new HomeDeletePreEvent(uuid, name))) { + return false; + } + // Get shares before removing (for reverse index cleanup) Set sharedWith = homes.getShares(name); @@ -177,6 +189,8 @@ public boolean deleteHome(@NotNull UUID uuid, @NotNull String name) { savePlayer(uuid); fireHomeChanged(uuid); Logger.debug("[Homes] Deleted home '%s' for %s", name, uuid); + + EventBus.publish(new HomeDeleteEvent(uuid, name)); } return removed; } @@ -228,10 +242,19 @@ public String getDefaultHome(@NotNull UUID uuid) { public void setDefaultHome(@NotNull UUID uuid, @Nullable String name) { PlayerHomes homes = cache.get(uuid); if (homes == null) return; + + if (name != null && EventBus.publishCancellable(new HomeDefaultSetPreEvent(uuid, name))) { + return; + } + homes.setDefaultHome(name); savePlayer(uuid); fireHomeChanged(uuid); Logger.debug("[Homes] Set default home to '%s' for %s", name, uuid); + + if (name != null) { + EventBus.publish(new HomeDefaultSetEvent(uuid, name)); + } } @Nullable @@ -275,6 +298,10 @@ public void shareHome(@NotNull UUID ownerUuid, @NotNull String homeName, @NotNul PlayerHomes homes = cache.get(ownerUuid); if (homes == null) return; + if (EventBus.publishCancellable(new HomeSharePreEvent(ownerUuid, homeName, targetUuid))) { + return; + } + homes.addShare(homeName, targetUuid); reverseShareIndex.computeIfAbsent(targetUuid, k -> new ArrayList<>()) .add(new SharedHomeRef(ownerUuid, homeName.toLowerCase())); @@ -283,12 +310,18 @@ public void shareHome(@NotNull UUID ownerUuid, @NotNull String homeName, @NotNul fireHomeChanged(ownerUuid); fireHomeChanged(targetUuid); Logger.debug("[Homes] %s shared home '%s' with %s", ownerUuid, homeName, targetUuid); + + EventBus.publish(new HomeShareEvent(ownerUuid, homeName, targetUuid)); } public void unshareHome(@NotNull UUID ownerUuid, @NotNull String homeName, @NotNull UUID targetUuid) { PlayerHomes homes = cache.get(ownerUuid); if (homes == null) return; + if (EventBus.publishCancellable(new HomeUnsharePreEvent(ownerUuid, homeName, targetUuid))) { + return; + } + homes.removeShare(homeName, targetUuid); List refs = reverseShareIndex.get(targetUuid); @@ -301,6 +334,8 @@ public void unshareHome(@NotNull UUID ownerUuid, @NotNull String homeName, @NotN fireHomeChanged(ownerUuid); fireHomeChanged(targetUuid); Logger.debug("[Homes] %s unshared home '%s' from %s", ownerUuid, homeName, targetUuid); + + EventBus.publish(new HomeUnshareEvent(ownerUuid, homeName, targetUuid)); } @NotNull diff --git a/src/main/java/com/hyperessentials/module/kits/KitManager.java b/src/main/java/com/hyperessentials/module/kits/KitManager.java index d031688..c385c7b 100644 --- a/src/main/java/com/hyperessentials/module/kits/KitManager.java +++ b/src/main/java/com/hyperessentials/module/kits/KitManager.java @@ -1,6 +1,8 @@ package com.hyperessentials.module.kits; import com.hyperessentials.Permissions; +import com.hyperessentials.api.events.EventBus; +import com.hyperessentials.api.events.kits.*; import com.hyperessentials.command.util.CommandUtil; import com.hyperessentials.config.ConfigManager; import com.hyperessentials.module.kits.data.Kit; @@ -106,6 +108,10 @@ public ClaimResult claimKit(@NotNull UUID playerUuid, @NotNull PlayerRef playerR @NotNull Kit kit) { if (!canUseKit(playerUuid, kit)) return ClaimResult.NO_PERMISSION; + if (EventBus.publishCancellable(new KitClaimPreEvent(playerUuid, kit.name()))) { + return ClaimResult.NO_PERMISSION; + } + if (kit.oneTime()) { String key = playerUuid + ":" + kit.name(); if (oneTimeClaims.contains(key)) return ClaimResult.ALREADY_CLAIMED; @@ -135,6 +141,8 @@ public ClaimResult claimKit(@NotNull UUID playerUuid, @NotNull PlayerRef playerR } fireKitClaimed(playerUuid); + + EventBus.publish(new KitClaimEvent(playerUuid, kit.name())); return ClaimResult.SUCCESS; } @@ -209,9 +217,24 @@ public void updateKit(@NotNull Kit kit) { } public boolean deleteKit(@NotNull String name) { + return deleteKit(name, null); + } + + public boolean deleteKit(@NotNull String name, @Nullable UUID actorUuid) { + Kit kit = kits.get(name.toLowerCase()); + if (kit == null) return false; + + if (actorUuid != null && EventBus.publishCancellable(new KitDeletePreEvent(kit.name(), actorUuid))) { + return false; + } + Kit removed = kits.remove(name.toLowerCase()); if (removed != null) { storage.deleteKit(removed.uuid()); + + if (actorUuid != null) { + EventBus.publish(new KitDeleteEvent(removed.name(), actorUuid)); + } return true; } return false; diff --git a/src/main/java/com/hyperessentials/module/moderation/ModerationManager.java b/src/main/java/com/hyperessentials/module/moderation/ModerationManager.java index b46bb44..e0059fd 100644 --- a/src/main/java/com/hyperessentials/module/moderation/ModerationManager.java +++ b/src/main/java/com/hyperessentials/module/moderation/ModerationManager.java @@ -1,6 +1,8 @@ package com.hyperessentials.module.moderation; import com.hyperessentials.Permissions; +import com.hyperessentials.api.events.EventBus; +import com.hyperessentials.api.events.moderation.*; import com.hyperessentials.command.util.CommandUtil; import com.hyperessentials.config.ConfigManager; import com.hyperessentials.data.PlayerData; @@ -194,10 +196,18 @@ public void kickPlayersWithIp(@NotNull String ip, @NotNull String reason) { // === Ban Operations === - @NotNull + @Nullable public Punishment ban(@NotNull UUID playerUuid, @NotNull String playerName, @Nullable UUID issuerUuid, @NotNull String issuerName, @Nullable String reason, @Nullable Long durationMs) { + String effectiveReason = reason != null ? reason + : ConfigManager.get().moderation().getDefaultBanReason(); + + if (issuerUuid != null && EventBus.publishCancellable( + new PlayerBanPreEvent(playerUuid, issuerUuid, effectiveReason, durationMs))) { + return null; + } + PlayerData data = getOrCreatePlayerData(playerUuid, playerName); // Revoke any existing active ban first @@ -206,9 +216,6 @@ public Punishment ban(@NotNull UUID playerUuid, @NotNull String playerName, data.revokePunishment(existing.id(), issuerUuid, issuerName); } - String effectiveReason = reason != null ? reason - : ConfigManager.get().moderation().getDefaultBanReason(); - Instant expiresAt = durationMs != null ? Instant.now().plusMillis(durationMs) : null; Punishment punishment = new Punishment( @@ -231,6 +238,9 @@ public Punishment ban(@NotNull UUID playerUuid, @NotNull String playerName, notifyStaff(Permissions.NOTIFY_BAN, issuerName + " banned " + playerName + (punishment.isPermanent() ? " permanently" : " for " + DurationParser.formatHuman(durationMs))); + if (issuerUuid != null) { + EventBus.publish(new PlayerBanEvent(playerUuid, issuerUuid, effectiveReason, durationMs)); + } return punishment; } @@ -241,10 +251,18 @@ public boolean unban(@NotNull UUID playerUuid, @Nullable UUID revokerUuid, @NotN Punishment ban = data.getActiveBan(); if (ban == null) return false; + if (revokerUuid != null && EventBus.publishCancellable(new PlayerUnbanPreEvent(playerUuid, revokerUuid))) { + return false; + } + data.revokePunishment(ban.id(), revokerUuid, revokerName); savePlayerData(playerUuid, data); notifyStaff(Permissions.NOTIFY_BAN, revokerName + " unbanned " + ban.playerName()); + + if (revokerUuid != null) { + EventBus.publish(new PlayerUnbanEvent(playerUuid, revokerUuid)); + } return true; } @@ -269,10 +287,18 @@ public Punishment getActiveBan(@NotNull UUID playerUuid) { // === Mute Operations === - @NotNull + @Nullable public Punishment mute(@NotNull UUID playerUuid, @NotNull String playerName, @Nullable UUID issuerUuid, @NotNull String issuerName, @Nullable String reason, @Nullable Long durationMs) { + String effectiveReason = reason != null ? reason + : ConfigManager.get().moderation().getDefaultMuteReason(); + + if (issuerUuid != null && EventBus.publishCancellable( + new PlayerMutePreEvent(playerUuid, issuerUuid, effectiveReason, durationMs))) { + return null; + } + PlayerData data = getOrCreatePlayerData(playerUuid, playerName); Punishment existing = data.getActiveMute(); @@ -280,9 +306,6 @@ public Punishment mute(@NotNull UUID playerUuid, @NotNull String playerName, data.revokePunishment(existing.id(), issuerUuid, issuerName); } - String effectiveReason = reason != null ? reason - : ConfigManager.get().moderation().getDefaultMuteReason(); - Instant expiresAt = durationMs != null ? Instant.now().plusMillis(durationMs) : null; Punishment punishment = new Punishment( @@ -308,6 +331,9 @@ public Punishment mute(@NotNull UUID playerUuid, @NotNull String playerName, notifyStaff(Permissions.NOTIFY_MUTE, issuerName + " muted " + playerName + (punishment.isPermanent() ? " permanently" : " for " + DurationParser.formatHuman(durationMs))); + if (issuerUuid != null) { + EventBus.publish(new PlayerMuteEvent(playerUuid, issuerUuid, effectiveReason, durationMs)); + } return punishment; } @@ -318,6 +344,10 @@ public boolean unmute(@NotNull UUID playerUuid, @Nullable UUID revokerUuid, @Not Punishment mute = data.getActiveMute(); if (mute == null) return false; + if (revokerUuid != null && EventBus.publishCancellable(new PlayerUnmutePreEvent(playerUuid, revokerUuid))) { + return false; + } + data.revokePunishment(mute.id(), revokerUuid, revokerName); savePlayerData(playerUuid, data); @@ -327,6 +357,10 @@ public boolean unmute(@NotNull UUID playerUuid, @Nullable UUID revokerUuid, @Not } notifyStaff(Permissions.NOTIFY_MUTE, revokerName + " unmuted " + mute.playerName()); + + if (revokerUuid != null) { + EventBus.publish(new PlayerUnmuteEvent(playerUuid, revokerUuid)); + } return true; } @@ -345,13 +379,18 @@ public boolean isMuted(@NotNull UUID playerUuid) { // === Kick Operations === - @NotNull + @Nullable public Punishment kick(@NotNull UUID playerUuid, @NotNull String playerName, @Nullable UUID issuerUuid, @NotNull String issuerName, @Nullable String reason) { String effectiveReason = reason != null ? reason : ConfigManager.get().moderation().getDefaultKickReason(); + if (issuerUuid != null && EventBus.publishCancellable( + new PlayerKickPreEvent(playerUuid, issuerUuid, effectiveReason))) { + return null; + } + Punishment punishment = new Punishment( UUID.randomUUID(), PunishmentType.KICK, playerUuid, playerName, issuerUuid, issuerName, effectiveReason, Instant.now(), @@ -370,18 +409,26 @@ public Punishment kick(@NotNull UUID playerUuid, @NotNull String playerName, } notifyStaff(Permissions.NOTIFY_KICK, issuerName + " kicked " + playerName); + if (issuerUuid != null) { + EventBus.publish(new PlayerKickEvent(playerUuid, issuerUuid, effectiveReason)); + } return punishment; } // === Warn Operations === - @NotNull + @Nullable public Punishment warn(@NotNull UUID playerUuid, @NotNull String playerName, @Nullable UUID issuerUuid, @NotNull String issuerName, @Nullable String reason) { String effectiveReason = reason != null ? reason : ConfigManager.get().moderation().getDefaultWarnReason(); + if (issuerUuid != null && EventBus.publishCancellable( + new PlayerWarnPreEvent(playerUuid, issuerUuid, effectiveReason))) { + return null; + } + Punishment punishment = new Punishment( UUID.randomUUID(), PunishmentType.WARN, playerUuid, playerName, issuerUuid, issuerName, effectiveReason, Instant.now(), @@ -415,6 +462,9 @@ public Punishment warn(@NotNull UUID playerUuid, @NotNull String playerName, } notifyStaff(Permissions.NOTIFY_WARN, issuerName + " warned " + playerName); + if (issuerUuid != null) { + EventBus.publish(new PlayerWarnEvent(playerUuid, issuerUuid, effectiveReason)); + } return punishment; } diff --git a/src/main/java/com/hyperessentials/module/spawns/SpawnManager.java b/src/main/java/com/hyperessentials/module/spawns/SpawnManager.java index e74205d..6965add 100644 --- a/src/main/java/com/hyperessentials/module/spawns/SpawnManager.java +++ b/src/main/java/com/hyperessentials/module/spawns/SpawnManager.java @@ -1,5 +1,7 @@ package com.hyperessentials.module.spawns; +import com.hyperessentials.api.events.EventBus; +import com.hyperessentials.api.events.spawns.*; import com.hyperessentials.data.Spawn; import com.hyperessentials.storage.SpawnStorage; import com.hyperessentials.util.ErrorHandler; @@ -195,6 +197,15 @@ public int importWorldSpawns() { * Sets/updates a spawn for a world. */ public void setSpawn(@NotNull Spawn spawn) { + if (spawn.createdBy() != null) { + try { + UUID actorUuid = UUID.fromString(spawn.createdBy()); + if (EventBus.publishCancellable(new SpawnSetPreEvent(spawn.worldUuid(), actorUuid))) { + return; + } + } catch (IllegalArgumentException ignored) {} + } + if (spawn.isGlobal()) { // Clear old global for (Map.Entry entry : spawns.entrySet()) { @@ -209,16 +220,42 @@ public void setSpawn(@NotNull Spawn spawn) { spawns.put(spawn.worldUuid(), spawn); storage.saveSpawn(spawn); Logger.info("[Spawns] Spawn set for world '%s'%s", spawn.worldName(), spawn.isGlobal() ? " (global)" : ""); + + if (spawn.createdBy() != null) { + try { + UUID actorUuid = UUID.fromString(spawn.createdBy()); + EventBus.publish(new SpawnSetEvent(spawn.worldUuid(), actorUuid)); + } catch (IllegalArgumentException ignored) {} + } } /** * Deletes the spawn for a world. */ public boolean deleteSpawn(@NotNull String worldUuid) { + Spawn spawn = spawns.get(worldUuid); + if (spawn == null) return false; + + if (spawn.createdBy() != null) { + try { + UUID actorUuid = UUID.fromString(spawn.createdBy()); + if (EventBus.publishCancellable(new SpawnDeletePreEvent(worldUuid, actorUuid))) { + return false; + } + } catch (IllegalArgumentException ignored) {} + } + Spawn removed = spawns.remove(worldUuid); if (removed != null) { storage.deleteSpawn(worldUuid); Logger.info("[Spawns] Spawn deleted for world '%s'", removed.worldName()); + + if (removed.createdBy() != null) { + try { + UUID actorUuid = UUID.fromString(removed.createdBy()); + EventBus.publish(new SpawnDeleteEvent(worldUuid, actorUuid)); + } catch (IllegalArgumentException ignored) {} + } return true; } return false; diff --git a/src/main/java/com/hyperessentials/module/teleport/TpaManager.java b/src/main/java/com/hyperessentials/module/teleport/TpaManager.java index caebb4c..31eea1a 100644 --- a/src/main/java/com/hyperessentials/module/teleport/TpaManager.java +++ b/src/main/java/com/hyperessentials/module/teleport/TpaManager.java @@ -1,6 +1,8 @@ package com.hyperessentials.module.teleport; import com.hyperessentials.Permissions; +import com.hyperessentials.api.events.EventBus; +import com.hyperessentials.api.events.teleport.*; import com.hyperessentials.config.modules.TeleportConfig; import com.hyperessentials.data.PlayerData; import com.hyperessentials.data.TeleportRequest; @@ -127,6 +129,10 @@ public TeleportRequest createRequest(@NotNull UUID requesterUuid, @NotNull UUID } } + if (EventBus.publishCancellable(new TpaSendPreEvent(requesterUuid, targetUuid, type == TeleportRequest.Type.TPAHERE))) { + return null; + } + cancelOutgoingRequest(requesterUuid); List targetIncoming = incomingRequests.computeIfAbsent(targetUuid, k -> new ArrayList<>()); @@ -158,6 +164,8 @@ public TeleportRequest createRequest(@NotNull UUID requesterUuid, @NotNull UUID fireTpaChanged(requesterUuid); fireTpaChanged(targetUuid); Logger.debug("TPA request created: %s -> %s (%s)", requesterUuid, targetUuid, type); + + EventBus.publish(new TpaSendEvent(requesterUuid, targetUuid, type == TeleportRequest.Type.TPAHERE)); return request; } @@ -209,18 +217,32 @@ public TeleportRequest getOutgoingRequest(@NotNull UUID uuid) { return request; } - public void acceptRequest(@NotNull TeleportRequest request) { + public boolean acceptRequest(@NotNull TeleportRequest request) { + if (EventBus.publishCancellable(new TpaAcceptPreEvent(request.target(), request.requester()))) { + return false; + } + removeRequest(request); fireTpaChanged(request.requester()); fireTpaChanged(request.target()); Logger.debug("TPA request accepted: %s -> %s", request.requester(), request.target()); + + EventBus.publish(new TpaAcceptEvent(request.target(), request.requester())); + return true; } - public void denyRequest(@NotNull TeleportRequest request) { + public boolean denyRequest(@NotNull TeleportRequest request) { + if (EventBus.publishCancellable(new TpaDenyPreEvent(request.target(), request.requester()))) { + return false; + } + removeRequest(request); fireTpaChanged(request.requester()); fireTpaChanged(request.target()); Logger.debug("TPA request denied: %s -> %s", request.requester(), request.target()); + + EventBus.publish(new TpaDenyEvent(request.target(), request.requester())); + return true; } @Nullable diff --git a/src/main/java/com/hyperessentials/module/utility/UtilityManager.java b/src/main/java/com/hyperessentials/module/utility/UtilityManager.java index bde2c36..952a589 100644 --- a/src/main/java/com/hyperessentials/module/utility/UtilityManager.java +++ b/src/main/java/com/hyperessentials/module/utility/UtilityManager.java @@ -1,5 +1,7 @@ package com.hyperessentials.module.utility; +import com.hyperessentials.api.events.EventBus; +import com.hyperessentials.api.events.utility.*; import com.hyperessentials.command.util.CommandUtil; import com.hyperessentials.config.ConfigManager; import com.hyperessentials.config.modules.UtilityConfig; @@ -118,13 +120,20 @@ public boolean isFlying(@NotNull UUID uuid) { } public boolean toggleFly(@NotNull UUID uuid) { - if (flyingPlayers.contains(uuid)) { - flyingPlayers.remove(uuid); - return false; - } else { + boolean newState = !flyingPlayers.contains(uuid); + + if (EventBus.publishCancellable(new FlyTogglePreEvent(uuid, newState))) { + return !newState; // return current state unchanged + } + + if (newState) { flyingPlayers.add(uuid); - return true; + } else { + flyingPlayers.remove(uuid); } + + EventBus.publish(new FlyToggleEvent(uuid, newState)); + return newState; } public void setFlying(@NotNull UUID uuid, boolean flying) { @@ -139,13 +148,20 @@ public boolean isGod(@NotNull UUID uuid) { } public boolean toggleGod(@NotNull UUID uuid) { - if (godPlayers.contains(uuid)) { - godPlayers.remove(uuid); - return false; - } else { + boolean newState = !godPlayers.contains(uuid); + + if (EventBus.publishCancellable(new GodTogglePreEvent(uuid, newState))) { + return !newState; // return current state unchanged + } + + if (newState) { godPlayers.add(uuid); - return true; + } else { + godPlayers.remove(uuid); } + + EventBus.publish(new GodToggleEvent(uuid, newState)); + return newState; } public void setGod(@NotNull UUID uuid, boolean god) { @@ -160,13 +176,20 @@ public boolean isAfk(@NotNull UUID uuid) { } public boolean toggleAfk(@NotNull UUID uuid) { - if (afkPlayers.contains(uuid)) { - afkPlayers.remove(uuid); - return false; - } else { + boolean newState = !afkPlayers.contains(uuid); + + if (EventBus.publishCancellable(new AfkTogglePreEvent(uuid, newState))) { + return !newState; // return current state unchanged + } + + if (newState) { afkPlayers.add(uuid); - return true; + } else { + afkPlayers.remove(uuid); } + + EventBus.publish(new AfkToggleEvent(uuid, newState)); + return newState; } /** diff --git a/src/main/java/com/hyperessentials/module/warps/WarpManager.java b/src/main/java/com/hyperessentials/module/warps/WarpManager.java index 0fa0e09..da1c8a8 100644 --- a/src/main/java/com/hyperessentials/module/warps/WarpManager.java +++ b/src/main/java/com/hyperessentials/module/warps/WarpManager.java @@ -1,5 +1,7 @@ package com.hyperessentials.module.warps; +import com.hyperessentials.api.events.EventBus; +import com.hyperessentials.api.events.warps.*; import com.hyperessentials.data.Warp; import com.hyperessentials.integration.PermissionManager; import com.hyperessentials.storage.WarpStorage; @@ -51,6 +53,15 @@ public CompletableFuture loadWarps() { public boolean setWarp(@NotNull Warp warp) { boolean isNew = !warps.containsKey(warp.name()); + if (warp.createdBy() != null) { + try { + UUID actorUuid = UUID.fromString(warp.createdBy()); + if (EventBus.publishCancellable(new WarpSetPreEvent(warp.name(), actorUuid))) { + return false; + } + } catch (IllegalArgumentException ignored) {} + } + // If updating an existing warp with a different name (shouldn't happen), remove the old Warp existing = warps.get(warp.name()); if (existing != null && !existing.uuid().equals(warp.uuid())) { @@ -62,6 +73,13 @@ public boolean setWarp(@NotNull Warp warp) { storage.saveWarp(warp); fireWarpChanged(); Logger.info("[Warps] Warp '%s' %s", warp.name(), isNew ? "created" : "updated"); + + if (warp.createdBy() != null) { + try { + UUID actorUuid = UUID.fromString(warp.createdBy()); + EventBus.publish(new WarpSetEvent(warp.name(), actorUuid)); + } catch (IllegalArgumentException ignored) {} + } return isNew; } @@ -71,11 +89,30 @@ public Warp getWarp(@NotNull String name) { } public boolean deleteWarp(@NotNull String name) { + Warp warp = warps.get(name.toLowerCase()); + if (warp == null) return false; + + if (warp.createdBy() != null) { + try { + UUID actorUuid = UUID.fromString(warp.createdBy()); + if (EventBus.publishCancellable(new WarpDeletePreEvent(warp.name(), actorUuid))) { + return false; + } + } catch (IllegalArgumentException ignored) {} + } + Warp removed = warps.remove(name.toLowerCase()); if (removed != null) { storage.deleteWarp(removed.uuid()); fireWarpChanged(); Logger.info("[Warps] Warp '%s' deleted", name); + + if (removed.createdBy() != null) { + try { + UUID actorUuid = UUID.fromString(removed.createdBy()); + EventBus.publish(new WarpDeleteEvent(removed.name(), actorUuid)); + } catch (IllegalArgumentException ignored) {} + } return true; } return false; diff --git a/src/main/resources/manifest.json b/src/main/resources/manifest.json index 12bef33..5c70d52 100644 --- a/src/main/resources/manifest.json +++ b/src/main/resources/manifest.json @@ -7,5 +7,9 @@ "Main": "com.hyperessentials.platform.HyperEssentialsPlugin", "ServerVersion": "${serverVersion}", "SoftDependencies": ["HyperPerms", "VaultUnlocked", "LuckPerms", "HyperFactions"], + "OptionalDependencies": { + "HelpChat:PlaceholderAPI": ">= 1.0.2", + "com.wiflow:WiFlowPlaceholderAPI": ">= 1.0.3" + }, "IncludesAssetPack": true } From f0e0f3bd55a614d474a4ede96816e58ca0eae361 Mon Sep 17 00:00:00 2001 From: derrickmehaffy Date: Mon, 6 Apr 2026 18:04:37 -0700 Subject: [PATCH 2/2] docs: update changelog with API, events, and placeholder additions --- CHANGELOG.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6998f97..89634f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +#### Cancellable Event System +- `Cancellable` interface with cancel reason support for pre-event interception +- `EventBus.publishCancellable()` for pre-event firing with early cancellation +- 58 event classes (29 PreEvent + 29 PostEvent) across 7 modules: + - **Homes**: set, delete, teleport, share, unshare, setDefault + - **Warps**: set, delete, teleport + - **Spawns**: set, delete, teleport + - **Kits**: claim, create, delete + - **Moderation**: ban, unban, mute, unmute, kick, warn + - **Teleport**: TPA send/accept/deny, back, RTP + - **Utility**: fly, god, AFK toggle +- All managers fire PreEvent before action (cancellable) and PostEvent after success + +#### Expanded Public API +- `HyperEssentialsAPI` expanded from 12 to 80+ methods covering all modules +- Home API: getHomes, setHome, deleteHome, getHomeCount, getHomeLimit, shareHome, unshareHome, and more +- Kit API: getKit, getAllKits, getAvailableKits, cooldown queries, one-time claim checks +- Moderation API: isBanned, isMuted, getActiveBan, getPunishmentHistory, isIpBanned +- Utility API: isFlying, isGod, isAfk, isInfiniteStamina, playtime and session queries +- EventBus access: `registerEventListener()` / `unregisterEventListener()` for external plugins +- Manager accessors for advanced plugin use (getHomeManager, getKitManager, etc.) + +#### PlaceholderAPI Support (~37 placeholders) +- `HyperEssentialsExpansion` for PlaceholderAPI (`%essentials_*%`) +- `WiFlowExpansion` for WiFlow PlaceholderAPI (`{essentials_*}`) +- Placeholder categories: homes (4), kits (3+), moderation (8), utility (13), warps/spawns/TPA (5) +- Bridge classes with runtime detection and reflection-based registration +- Conditional WiFlow compilation (excluded when WiFlow JAR not present) + ### Changed - `/home` (no args) no longer falls back to a home named "home" or auto-selects when only one home exists — players must explicitly set a default via the Homes GUI +- `EventBus.fire()` renamed to `EventBus.publish()` for consistency with HyperFactions +- `EventBus` internals switched from `CopyOnWriteArrayList` to `Collections.synchronizedList` ### Fixed