From e80ab6392b86f9f6e6464bea0b68f9eef2b5b55e Mon Sep 17 00:00:00 2001 From: derrickmehaffy Date: Sat, 14 Mar 2026 23:49:09 -0700 Subject: [PATCH 1/7] chore: remove unused imports and fix volatile field in SentryIntegration - Remove unused MessageUtil import from AdminSubCommand and AdminEconomyHandler - Remove unused UUID import from TreasuryCommandHandler - Make SentryIntegration.initialized volatile for thread safety - Replace System.err.println in EventBus with ErrorHandler.report --- src/main/java/com/hyperfactions/api/events/EventBus.java | 4 ++-- .../java/com/hyperfactions/command/admin/AdminSubCommand.java | 1 - .../command/admin/handler/AdminEconomyHandler.java | 1 - .../hyperfactions/command/economy/TreasuryCommandHandler.java | 1 - .../java/com/hyperfactions/integration/SentryIntegration.java | 2 +- 5 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/hyperfactions/api/events/EventBus.java b/src/main/java/com/hyperfactions/api/events/EventBus.java index 66fb293f..7e35c8f7 100644 --- a/src/main/java/com/hyperfactions/api/events/EventBus.java +++ b/src/main/java/com/hyperfactions/api/events/EventBus.java @@ -1,5 +1,6 @@ package com.hyperfactions.api.events; +import com.hyperfactions.util.ErrorHandler; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; @@ -54,8 +55,7 @@ public static void publish(@NotNull T event) { try { ((Consumer) listener).accept(event); } catch (Exception e) { - // Log but don't propagate - System.err.println("[HyperFactions] Error in event listener: " + e.getMessage()); + ErrorHandler.report("Event bus listener error", e); } } } diff --git a/src/main/java/com/hyperfactions/command/admin/AdminSubCommand.java b/src/main/java/com/hyperfactions/command/admin/AdminSubCommand.java index ea21a8ea..b0271942 100644 --- a/src/main/java/com/hyperfactions/command/admin/AdminSubCommand.java +++ b/src/main/java/com/hyperfactions/command/admin/AdminSubCommand.java @@ -25,7 +25,6 @@ import com.hyperfactions.util.HelpFormatter; import com.hyperfactions.util.AdminKeys; import com.hyperfactions.util.HelpKeys; -import com.hyperfactions.util.MessageUtil; import com.hyperfactions.util.PlayerResolver; import com.hypixel.hytale.component.Ref; import com.hypixel.hytale.component.Store; diff --git a/src/main/java/com/hyperfactions/command/admin/handler/AdminEconomyHandler.java b/src/main/java/com/hyperfactions/command/admin/handler/AdminEconomyHandler.java index f501abcc..e136177f 100644 --- a/src/main/java/com/hyperfactions/command/admin/handler/AdminEconomyHandler.java +++ b/src/main/java/com/hyperfactions/command/admin/handler/AdminEconomyHandler.java @@ -14,7 +14,6 @@ import com.hyperfactions.util.CommonKeys; import com.hyperfactions.util.HelpKeys; import com.hyperfactions.util.Logger; -import com.hyperfactions.util.MessageUtil; import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.command.system.CommandContext; import com.hypixel.hytale.server.core.universe.PlayerRef; diff --git a/src/main/java/com/hyperfactions/command/economy/TreasuryCommandHandler.java b/src/main/java/com/hyperfactions/command/economy/TreasuryCommandHandler.java index 330f7765..ac178d97 100644 --- a/src/main/java/com/hyperfactions/command/economy/TreasuryCommandHandler.java +++ b/src/main/java/com/hyperfactions/command/economy/TreasuryCommandHandler.java @@ -22,7 +22,6 @@ import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.List; -import java.util.UUID; import org.jetbrains.annotations.NotNull; /** diff --git a/src/main/java/com/hyperfactions/integration/SentryIntegration.java b/src/main/java/com/hyperfactions/integration/SentryIntegration.java index bb6188e3..97d098b1 100644 --- a/src/main/java/com/hyperfactions/integration/SentryIntegration.java +++ b/src/main/java/com/hyperfactions/integration/SentryIntegration.java @@ -25,7 +25,7 @@ */ public final class SentryIntegration { - private static boolean initialized = false; + private static volatile boolean initialized = false; /** Buffered errors from before Sentry was initialized. */ private static final List preInitErrors = new ArrayList<>(); From 062a3d71a1ad679aae44e4d8ce58e620dda80579 Mon Sep 17 00:00:00 2001 From: derrickmehaffy Date: Sat, 14 Mar 2026 23:49:28 -0700 Subject: [PATCH 2/7] fix: route all error handling through Sentry via ErrorHandler Convert Logger-only catch blocks across the codebase to use ErrorHandler.report(), which logs to console AND sends to Sentry. Covers platform, managers, integrations, storage, worldmap, GUI, migrations, territory, and update packages. Informational warnings (not in catch blocks) are intentionally left as Logger.warn calls. --- .../hyperfactions/backup/BackupManager.java | 8 +++--- .../config/modules/DebugConfig.java | 3 ++- .../hyperfactions/gui/GuiUpdateService.java | 3 ++- .../gui/admin/ConfigSnapshot.java | 3 ++- .../gui/faction/page/FactionChatPage.java | 4 +-- .../hyperfactions/gui/help/HelpRegistry.java | 3 ++- .../permissions/HyperPermsIntegration.java | 8 +++--- .../PlaceholderAPIIntegration.java | 3 ++- .../WiFlowPlaceholderIntegration.java | 3 ++- .../protection/OrbisGuardIntegration.java | 12 ++++----- .../protection/OrbisMixinsIntegration.java | 25 ++++++++++--------- .../manager/AnnouncementManager.java | 3 ++- .../hyperfactions/manager/ChatManager.java | 3 ++- .../hyperfactions/manager/ClaimManager.java | 13 +++++----- .../hyperfactions/manager/InviteManager.java | 4 +-- .../manager/JoinRequestManager.java | 6 ++--- .../manager/RelationManager.java | 15 +++++------ .../manager/SpawnSuppressionManager.java | 3 ++- .../manager/ZoneMobClearManager.java | 1 - .../config/ConfigV1ToV2Migration.java | 2 +- .../config/ConfigV2ToV3Migration.java | 2 +- .../config/ConfigV3ToV4Migration.java | 2 +- .../config/ConfigV4ToV5Migration.java | 2 +- .../config/ConfigV5ToV6Migration.java | 2 +- .../config/ConfigV6ToV7Migration.java | 4 +-- .../config/ConfigV7ToV8Migration.java | 2 +- .../platform/EventRegistration.java | 11 ++++---- .../platform/HyperFactionsPlugin.java | 8 +++--- .../hyperfactions/platform/WorldSetup.java | 18 +++++-------- .../protection/ecs/PlayerDeathSystem.java | 2 +- .../hyperfactions/storage/StorageUtils.java | 12 ++++----- .../territory/TerritoryNotifier.java | 5 ++-- .../hyperfactions/update/UpdateChecker.java | 14 +++++------ .../update/UpdateNotificationListener.java | 4 +-- .../update/UpdateNotificationPreferences.java | 5 ++-- .../hyperfactions/util/PlayerDBService.java | 2 +- .../worldmap/MapPlayerFilterService.java | 11 +++----- .../worldmap/WorldMapService.java | 7 +----- 38 files changed, 117 insertions(+), 121 deletions(-) diff --git a/src/main/java/com/hyperfactions/backup/BackupManager.java b/src/main/java/com/hyperfactions/backup/BackupManager.java index f4cb3c3d..33dd24f0 100644 --- a/src/main/java/com/hyperfactions/backup/BackupManager.java +++ b/src/main/java/com/hyperfactions/backup/BackupManager.java @@ -443,8 +443,7 @@ public List listBackups() { )); } } catch (Exception e) { - Logger.warn("[Backup] Could not read backup metadata for %s: %s", - file.getFileName(), e.getMessage()); + ErrorHandler.report(String.format("[Backup] Could not read backup metadata for %s", file.getFileName()), e); } } } @@ -556,15 +555,14 @@ private void rotateShutdownBackups() { Files.delete(toDelete); Logger.debug("[Backup] Rotated out old shutdown backup: %s", toDelete.getFileName()); } catch (IOException e) { - Logger.warn("[Backup] Failed to delete old shutdown backup %s: %s", - toDelete.getFileName(), e.getMessage()); + ErrorHandler.report(String.format("[Backup] Failed to delete old shutdown backup %s", toDelete.getFileName()), e); } } int deleted = shutdownBackups.size() - retention; Logger.info("[Backup] Cleaned up %d old shutdown backup(s), keeping %d", deleted, retention); } catch (IOException e) { - Logger.warn("[Backup] Failed to rotate shutdown backups: %s", e.getMessage()); + ErrorHandler.report("[Backup] Failed to rotate shutdown backups", e); } } diff --git a/src/main/java/com/hyperfactions/config/modules/DebugConfig.java b/src/main/java/com/hyperfactions/config/modules/DebugConfig.java index 661342da..dc14a9c3 100644 --- a/src/main/java/com/hyperfactions/config/modules/DebugConfig.java +++ b/src/main/java/com/hyperfactions/config/modules/DebugConfig.java @@ -3,6 +3,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.hyperfactions.config.ModuleConfig; +import com.hyperfactions.util.ErrorHandler; import com.hyperfactions.util.Logger; import java.nio.file.Files; import java.nio.file.Path; @@ -596,7 +597,7 @@ private void migrateLegacySentryConfig() { Files.delete(sentryFile); Logger.info("[Config] Deleted old config/sentry.json"); } catch (Exception e) { - Logger.warn("[Config] Failed to migrate sentry.json: %s", e.getMessage()); + ErrorHandler.report("[Config] Failed to migrate sentry.json", e); } } } diff --git a/src/main/java/com/hyperfactions/gui/GuiUpdateService.java b/src/main/java/com/hyperfactions/gui/GuiUpdateService.java index 8f35d31a..ab7ccc0e 100644 --- a/src/main/java/com/hyperfactions/gui/GuiUpdateService.java +++ b/src/main/java/com/hyperfactions/gui/GuiUpdateService.java @@ -4,6 +4,7 @@ import com.hyperfactions.data.JoinRequest; import com.hyperfactions.data.PendingInvite; import com.hyperfactions.manager.FactionManager; +import com.hyperfactions.util.ErrorHandler; import com.hyperfactions.util.Logger; import com.hypixel.hytale.server.core.universe.PlayerRef; import com.hypixel.hytale.server.core.universe.Universe; @@ -219,7 +220,7 @@ private void dispatchRefresh(@NotNull UUID playerUuid) { try { r.refreshContent(); } catch (Exception e) { - Logger.warn("[GuiUpdate] Error refreshing page for %s: %s", playerUuid, e.getMessage()); + ErrorHandler.report("[GuiUpdate] Error refreshing page for " + playerUuid, e); } } }); diff --git a/src/main/java/com/hyperfactions/gui/admin/ConfigSnapshot.java b/src/main/java/com/hyperfactions/gui/admin/ConfigSnapshot.java index da72ecce..1ef12dc8 100644 --- a/src/main/java/com/hyperfactions/gui/admin/ConfigSnapshot.java +++ b/src/main/java/com/hyperfactions/gui/admin/ConfigSnapshot.java @@ -2,6 +2,7 @@ import com.hyperfactions.config.ConfigManager; import com.hyperfactions.config.modules.*; +import com.hyperfactions.util.ErrorHandler; import com.hyperfactions.util.Logger; import java.math.BigDecimal; @@ -268,7 +269,7 @@ public static void applyChange(String key, Object value) { } } } catch (Exception e) { - Logger.warn("[ConfigEditor] Failed to apply change for key '%s': %s", key, e.getMessage()); + ErrorHandler.report("[ConfigEditor] Failed to apply change for key '" + key + "'", e); } } diff --git a/src/main/java/com/hyperfactions/gui/faction/page/FactionChatPage.java b/src/main/java/com/hyperfactions/gui/faction/page/FactionChatPage.java index 7722a4b4..919931d7 100644 --- a/src/main/java/com/hyperfactions/gui/faction/page/FactionChatPage.java +++ b/src/main/java/com/hyperfactions/gui/faction/page/FactionChatPage.java @@ -15,7 +15,7 @@ import com.hyperfactions.manager.ChatHistoryManager; import com.hyperfactions.manager.ChatManager; import com.hyperfactions.manager.FactionManager; -import com.hyperfactions.util.Logger; +import com.hyperfactions.util.ErrorHandler; import com.hyperfactions.util.MessageUtil; import com.hyperfactions.util.HFMessages; import com.hyperfactions.util.GuiKeys; @@ -211,7 +211,7 @@ private List loadMessages() { .toList(); } } catch (Exception e) { - Logger.warn("[FactionChatPage] Failed to load messages: %s", e.getMessage()); + ErrorHandler.report("Failed to load chat messages", e); return List.of(); } } diff --git a/src/main/java/com/hyperfactions/gui/help/HelpRegistry.java b/src/main/java/com/hyperfactions/gui/help/HelpRegistry.java index d8697468..aa1b9f26 100644 --- a/src/main/java/com/hyperfactions/gui/help/HelpRegistry.java +++ b/src/main/java/com/hyperfactions/gui/help/HelpRegistry.java @@ -4,6 +4,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.hyperfactions.util.ErrorHandler; import com.hyperfactions.util.Logger; import java.io.InputStream; import java.io.InputStreamReader; @@ -107,7 +108,7 @@ private void loadFromManifest() { Logger.info("Loaded %d help topics from manifest", topicsById.size()); } catch (Exception e) { - Logger.warn("Failed to load help manifest: %s", e.getMessage()); + ErrorHandler.report("Failed to load help manifest", e); } } diff --git a/src/main/java/com/hyperfactions/integration/permissions/HyperPermsIntegration.java b/src/main/java/com/hyperfactions/integration/permissions/HyperPermsIntegration.java index 6a8f307a..228963e9 100644 --- a/src/main/java/com/hyperfactions/integration/permissions/HyperPermsIntegration.java +++ b/src/main/java/com/hyperfactions/integration/permissions/HyperPermsIntegration.java @@ -1,5 +1,6 @@ package com.hyperfactions.integration.permissions; +import com.hyperfactions.util.ErrorHandler; import com.hyperfactions.util.Logger; import java.lang.reflect.Method; import java.util.UUID; @@ -85,11 +86,11 @@ public static void init() { } catch (NoSuchMethodException e) { available = false; initError = "Method not found: " + e.getMessage(); - Logger.warn("HyperPerms API mismatch: %s - defaulting to allow all", e.getMessage()); + ErrorHandler.report("HyperPerms API mismatch - defaulting to allow all", e); } catch (Exception e) { available = false; initError = e.getClass().getSimpleName() + ": " + e.getMessage(); - Logger.warn("Failed to initialize HyperPerms integration: %s - defaulting to allow all", e.getMessage()); + ErrorHandler.report("Failed to initialize HyperPerms integration - defaulting to allow all", e); } } @@ -167,8 +168,7 @@ public static boolean hasPermission(@NotNull UUID playerUuid, @NotNull String pe } catch (Exception e) { // Any error in permission check = allow (fail-open) - Logger.warn("[PERM] Exception checking %s for %s: %s, ALLOWING", - permission, playerUuid, e.getMessage()); + ErrorHandler.report("Exception checking permission " + permission + " for " + playerUuid + ", ALLOWING", e); return true; } } diff --git a/src/main/java/com/hyperfactions/integration/placeholder/PlaceholderAPIIntegration.java b/src/main/java/com/hyperfactions/integration/placeholder/PlaceholderAPIIntegration.java index 25dcd172..8b183515 100644 --- a/src/main/java/com/hyperfactions/integration/placeholder/PlaceholderAPIIntegration.java +++ b/src/main/java/com/hyperfactions/integration/placeholder/PlaceholderAPIIntegration.java @@ -1,6 +1,7 @@ package com.hyperfactions.integration.placeholder; import com.hyperfactions.HyperFactions; +import com.hyperfactions.util.ErrorHandler; import com.hyperfactions.util.Logger; import org.jetbrains.annotations.Nullable; @@ -51,7 +52,7 @@ public static void init(HyperFactions plugin) { expansion = null; } } catch (Exception e) { - Logger.warn("Failed to register PlaceholderAPI expansion: %s", e.getMessage()); + ErrorHandler.report("Failed to register PlaceholderAPI expansion", e); expansion = null; } } diff --git a/src/main/java/com/hyperfactions/integration/placeholder/WiFlowPlaceholderIntegration.java b/src/main/java/com/hyperfactions/integration/placeholder/WiFlowPlaceholderIntegration.java index f03f89d4..76cab5a9 100644 --- a/src/main/java/com/hyperfactions/integration/placeholder/WiFlowPlaceholderIntegration.java +++ b/src/main/java/com/hyperfactions/integration/placeholder/WiFlowPlaceholderIntegration.java @@ -1,6 +1,7 @@ package com.hyperfactions.integration.placeholder; import com.hyperfactions.HyperFactions; +import com.hyperfactions.util.ErrorHandler; import com.hyperfactions.util.Logger; import java.lang.reflect.Method; import org.jetbrains.annotations.Nullable; @@ -69,7 +70,7 @@ public static void init(HyperFactions plugin) { expansion = null; } } catch (Exception e) { - Logger.warn("Failed to register WiFlow PlaceholderAPI expansion: %s", e.getMessage()); + ErrorHandler.report("Failed to register WiFlow PlaceholderAPI expansion", e); expansion = null; } } diff --git a/src/main/java/com/hyperfactions/integration/protection/OrbisGuardIntegration.java b/src/main/java/com/hyperfactions/integration/protection/OrbisGuardIntegration.java index 331a6f7c..2fff89bd 100644 --- a/src/main/java/com/hyperfactions/integration/protection/OrbisGuardIntegration.java +++ b/src/main/java/com/hyperfactions/integration/protection/OrbisGuardIntegration.java @@ -1,5 +1,6 @@ package com.hyperfactions.integration.protection; +import com.hyperfactions.util.ErrorHandler; import com.hyperfactions.util.Logger; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -119,11 +120,11 @@ public static void init() { } catch (NoSuchMethodException e) { available = false; initError = "OrbisGuard API mismatch: " + e.getMessage(); - Logger.warn("OrbisGuard API version incompatible: %s", e.getMessage()); + ErrorHandler.report("OrbisGuard API version incompatible", e); } catch (Exception e) { available = false; initError = e.getClass().getSimpleName() + ": " + e.getMessage(); - Logger.warn("Error initializing OrbisGuard integration: %s", e.getMessage()); + ErrorHandler.report("Error initializing OrbisGuard integration", e); } initialized = true; @@ -182,8 +183,7 @@ public static boolean hasProtectiveRegions(@NotNull String worldName, int x, int return false; } catch (Throwable e) { - Logger.warn("Error checking OrbisGuard regions at %s/%d/%d/%d: %s", - worldName, x, y, z, e.getMessage()); + ErrorHandler.report("Error checking OrbisGuard regions", e); return false; // Fail-open } } @@ -326,7 +326,7 @@ public static List getRegionsForWorld(@NotNull String worldName) { return Collections.emptyList(); } catch (Throwable e) { - Logger.warn("Error getting OrbisGuard regions for world %s: %s", worldName, e.getMessage()); + ErrorHandler.report("Error getting OrbisGuard regions for world " + worldName, e); return Collections.emptyList(); } } @@ -368,7 +368,7 @@ public static List getAllRegions() { return result; } catch (Throwable e) { - Logger.warn("Error getting all OrbisGuard regions: %s", e.getMessage()); + ErrorHandler.report("Error getting all OrbisGuard regions", e); return Collections.emptyList(); } } diff --git a/src/main/java/com/hyperfactions/integration/protection/OrbisMixinsIntegration.java b/src/main/java/com/hyperfactions/integration/protection/OrbisMixinsIntegration.java index 4dd456a1..476d5ddf 100644 --- a/src/main/java/com/hyperfactions/integration/protection/OrbisMixinsIntegration.java +++ b/src/main/java/com/hyperfactions/integration/protection/OrbisMixinsIntegration.java @@ -1,5 +1,6 @@ package com.hyperfactions.integration.protection; +import com.hyperfactions.util.ErrorHandler; import com.hyperfactions.util.Logger; import com.hypixel.hytale.server.core.entity.entities.Player; import com.hypixel.hytale.server.core.universe.world.World; @@ -164,7 +165,7 @@ public static void init() { } catch (Exception e) { mixinsAvailable = false; initError = e.getClass().getSimpleName() + ": " + e.getMessage(); - Logger.warn("Error checking OrbisGuard-Mixins availability: %s", e.getMessage()); + ErrorHandler.report("Error checking OrbisGuard-Mixins availability", e); } initialized = true; @@ -436,7 +437,7 @@ public static boolean registerPickupHook(@NotNull PickupCheckCallback callback) Logger.debug("Registered pickup protection hook"); return true; } catch (Exception e) { - Logger.warn("Failed to register pickup hook: %s", e.getMessage()); + ErrorHandler.report("Failed to register pickup hook", e); return false; } } @@ -512,7 +513,7 @@ public static boolean registerHammerHook(@NotNull HammerCheckCallback callback) Logger.debug("Registered hammer protection hook"); return true; } catch (Exception e) { - Logger.warn("Failed to register hammer hook: %s", e.getMessage()); + ErrorHandler.report("Failed to register hammer hook", e); return false; } } @@ -631,7 +632,7 @@ public static boolean registerExplosionHook(@NotNull ExplosionCheckCallback call Logger.debug("Registered explosion protection hook"); return true; } catch (Exception e) { - Logger.warn("Failed to register explosion hook: %s", e.getMessage()); + ErrorHandler.report("Failed to register explosion hook", e); return false; } } @@ -706,7 +707,7 @@ public static boolean registerCommandHook(@NotNull CommandCheckCallback callback Logger.debug("Registered command protection hook"); return true; } catch (Exception e) { - Logger.warn("Failed to register command hook: %s", e.getMessage()); + ErrorHandler.report("Failed to register command hook", e); return false; } } @@ -829,7 +830,7 @@ public static boolean registerDeathHook(@NotNull DeathCheckCallback callback) { Logger.debug("Registered death (keep inventory) hook"); return true; } catch (Exception e) { - Logger.warn("Failed to register death hook: %s", e.getMessage()); + ErrorHandler.report("Failed to register death hook", e); return false; } } @@ -902,7 +903,7 @@ public static boolean registerDurabilityHook(@NotNull DurabilityCheckCallback ca Logger.debug("Registered durability protection hook"); return true; } catch (Exception e) { - Logger.warn("Failed to register durability hook: %s", e.getMessage()); + ErrorHandler.report("Failed to register durability hook", e); return false; } } @@ -975,7 +976,7 @@ public static boolean registerUseHook(@NotNull UseCheckCallback callback) { Logger.debug("Registered use protection hook"); return true; } catch (Exception e) { - Logger.warn("Failed to register use hook: %s", e.getMessage()); + ErrorHandler.report("Failed to register use hook", e); return false; } } @@ -1048,7 +1049,7 @@ public static boolean registerSeatHook(@NotNull SeatCheckCallback callback) { Logger.debug("Registered seat protection hook"); return true; } catch (Exception e) { - Logger.warn("Failed to register seat hook: %s", e.getMessage()); + ErrorHandler.report("Failed to register seat hook", e); return false; } } @@ -1121,7 +1122,7 @@ public static boolean registerHarvestHook(@NotNull HarvestCheckCallback callback Logger.debug("Registered harvest protection hook"); return true; } catch (Exception e) { - Logger.warn("Failed to register harvest hook: %s", e.getMessage()); + ErrorHandler.report("Failed to register harvest hook", e); return false; } } @@ -1279,7 +1280,7 @@ public static boolean registerPlaceHook(@NotNull PlaceCheckCallback callback) { Logger.debug("Registered place protection hook"); return true; } catch (Exception e) { - Logger.warn("Failed to register place hook: %s", e.getMessage()); + ErrorHandler.report("Failed to register place hook", e); return false; } } @@ -1352,7 +1353,7 @@ public static boolean registerSpawnHook(@NotNull SpawnCheckCallback callback) { Logger.debug("Registered spawn control hook"); return true; } catch (Exception e) { - Logger.warn("Failed to register spawn hook: %s", e.getMessage()); + ErrorHandler.report("Failed to register spawn hook", e); return false; } } diff --git a/src/main/java/com/hyperfactions/manager/AnnouncementManager.java b/src/main/java/com/hyperfactions/manager/AnnouncementManager.java index 50560a39..1090748b 100644 --- a/src/main/java/com/hyperfactions/manager/AnnouncementManager.java +++ b/src/main/java/com/hyperfactions/manager/AnnouncementManager.java @@ -2,6 +2,7 @@ import com.hyperfactions.config.ConfigManager; import com.hyperfactions.config.modules.AnnouncementConfig; +import com.hyperfactions.util.ErrorHandler; import com.hyperfactions.util.Logger; import com.hyperfactions.util.CommonKeys; import com.hyperfactions.util.MessageUtil; @@ -168,7 +169,7 @@ private void broadcast(@NotNull java.util.function.FunctionV2", e); return false; } } diff --git a/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV2ToV3Migration.java b/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV2ToV3Migration.java index ddeb161d..0b96e048 100644 --- a/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV2ToV3Migration.java +++ b/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV2ToV3Migration.java @@ -86,7 +86,7 @@ public boolean isApplicable(@NotNull Path dataDir) { } return root.get("configVersion").getAsInt() == 2; } catch (Exception e) { - Logger.warn("[Migration] Failed to check config version: %s", e.getMessage()); + ErrorHandler.report("[Migration] Failed to check config version for V2->V3", e); return false; } } diff --git a/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV3ToV4Migration.java b/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV3ToV4Migration.java index 8ccbd067..e416b045 100644 --- a/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV3ToV4Migration.java +++ b/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV3ToV4Migration.java @@ -106,7 +106,7 @@ public boolean isApplicable(@NotNull Path dataDir) { } return root.get("configVersion").getAsInt() == 3; } catch (Exception e) { - Logger.warn("[Migration] Failed to check config version: %s", e.getMessage()); + ErrorHandler.report("[Migration] Failed to check config version for V3->V4", e); return false; } } diff --git a/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV4ToV5Migration.java b/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV4ToV5Migration.java index fbb2a929..69ce2030 100644 --- a/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV4ToV5Migration.java +++ b/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV4ToV5Migration.java @@ -80,7 +80,7 @@ public boolean isApplicable(@NotNull Path dataDir) { } return root.get("configVersion").getAsInt() == 4; } catch (Exception e) { - Logger.warn("[Migration] Failed to check config version: %s", e.getMessage()); + ErrorHandler.report("[Migration] Failed to check config version for V4->V5", e); return false; } } diff --git a/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV5ToV6Migration.java b/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV5ToV6Migration.java index c72a336b..5613acb9 100644 --- a/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV5ToV6Migration.java +++ b/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV5ToV6Migration.java @@ -92,7 +92,7 @@ public boolean isApplicable(@NotNull Path dataDir) { } return root.get("configVersion").getAsInt() == 5; } catch (Exception e) { - Logger.warn("[Migration] Failed to check config version: %s", e.getMessage()); + ErrorHandler.report("[Migration] Failed to check config version for V5->V6", e); return false; } } diff --git a/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV6ToV7Migration.java b/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV6ToV7Migration.java index 5eeabe6a..1e79f140 100644 --- a/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV6ToV7Migration.java +++ b/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV6ToV7Migration.java @@ -101,7 +101,7 @@ public boolean isApplicable(@NotNull Path dataDir) { } return root.get("configVersion").getAsInt() == 6; } catch (Exception e) { - Logger.warn("[Migration] Failed to check config version: %s", e.getMessage()); + ErrorHandler.report("[Migration] Failed to check config version for V6->V7", e); return false; } } @@ -227,7 +227,7 @@ public MigrationResult execute(@NotNull Path dataDir, @NotNull MigrationOptions } catch (Exception e) { warnings.add("Failed to restructure economy.json: " + e.getMessage() + " (will be auto-fixed on next save)"); - Logger.warn("[Migration] Failed to restructure economy.json: %s", e.getMessage()); + ErrorHandler.report("[Migration] Failed to restructure economy.json", e); } } diff --git a/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV7ToV8Migration.java b/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV7ToV8Migration.java index e225a825..90d04c6a 100644 --- a/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV7ToV8Migration.java +++ b/src/main/java/com/hyperfactions/migration/migrations/config/ConfigV7ToV8Migration.java @@ -86,7 +86,7 @@ public boolean isApplicable(@NotNull Path dataDir) { } return root.get("configVersion").getAsInt() == 7; } catch (Exception e) { - Logger.warn("[Migration] Failed to check config version: %s", e.getMessage()); + ErrorHandler.report("[Migration] Failed to check config version for V7->V8", e); return false; } } diff --git a/src/main/java/com/hyperfactions/platform/EventRegistration.java b/src/main/java/com/hyperfactions/platform/EventRegistration.java index cbe98bc5..1f643e1b 100644 --- a/src/main/java/com/hyperfactions/platform/EventRegistration.java +++ b/src/main/java/com/hyperfactions/platform/EventRegistration.java @@ -17,6 +17,7 @@ import com.hyperfactions.protection.ecs.PvPProtectionSystem; import com.hyperfactions.protection.ecs.TeleportCancelOnDamageSystem; import com.hyperfactions.territory.TerritoryTickingSystem; +import com.hyperfactions.util.ErrorHandler; import com.hyperfactions.util.Logger; import com.hypixel.hytale.component.system.ISystem; import com.hypixel.hytale.event.EventPriority; @@ -28,7 +29,7 @@ import com.hypixel.hytale.server.core.event.events.player.PlayerReadyEvent; import com.hypixel.hytale.server.core.universe.world.events.AddWorldEvent; import com.hypixel.hytale.server.core.universe.world.events.RemoveWorldEvent; -import java.util.logging.Level; + /** * Handles registration of all event listeners and ECS systems for HyperFactions. @@ -169,7 +170,7 @@ private void registerBlockProtectionSystems(ProtectionListener protectionListene Logger.debug("Registered block, item, and player ECS protection systems"); } catch (Exception e) { - plugin.getLogger().at(Level.WARNING).withCause(e).log("Failed to register block protection systems"); + ErrorHandler.report("Failed to register block protection systems", e); } } @@ -186,7 +187,7 @@ private void registerHarvestPickupProtection(ProtectionListener protectionListen plugin.getEntityStoreRegistry().registerSystem(new HarvestPickupProtectionSystem(hyperFactions, protectionListener)); Logger.debug("Registered harvest pickup ECS protection system"); } catch (Exception e) { - plugin.getLogger().at(Level.WARNING).withCause(e).log("Failed to register harvest pickup protection system"); + ErrorHandler.report("Failed to register harvest pickup protection system", e); } } @@ -200,7 +201,7 @@ public void registerTeleportSystems() { Logger.debug("Registered teleport cancel-on-damage ECS system"); } catch (Exception e) { - plugin.getLogger().at(Level.WARNING).withCause(e).log("Failed to register teleport systems"); + ErrorHandler.report("Failed to register teleport systems", e); } } @@ -218,7 +219,7 @@ public void registerTerritorySystems() { Logger.debug("Registered territory ticking ECS system"); } catch (Exception e) { - plugin.getLogger().at(Level.WARNING).withCause(e).log("Failed to register territory ticking system"); + ErrorHandler.report("Failed to register territory ticking system", e); } } diff --git a/src/main/java/com/hyperfactions/platform/HyperFactionsPlugin.java b/src/main/java/com/hyperfactions/platform/HyperFactionsPlugin.java index f4400b5c..e53ac4c9 100644 --- a/src/main/java/com/hyperfactions/platform/HyperFactionsPlugin.java +++ b/src/main/java/com/hyperfactions/platform/HyperFactionsPlugin.java @@ -29,7 +29,7 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import java.util.logging.Level; + /** * Main Hytale plugin class for HyperFactions. @@ -203,7 +203,7 @@ protected void shutdown() { hyperFactions.shutdownKyuubiSoftIntegration(); } } catch (Exception e) { - getLogger().at(java.util.logging.Level.WARNING).withCause(e).log("Failed to shutdown KyuubiSoft integration"); + ErrorHandler.report("Failed to shutdown KyuubiSoft integration", e); } // Clean up territory ticking system @@ -301,7 +301,7 @@ private void registerCommands() { getCommandRegistry().registerCommand(new FactionCommand(hyperFactions, this)); Logger.debug("Registered command: /faction (/f, /hf)"); } catch (Exception e) { - getLogger().at(Level.SEVERE).withCause(e).log("Failed to register commands"); + ErrorHandler.report("Failed to register commands", e); } } @@ -337,7 +337,7 @@ private void registerInteractionCodecs() { Logger.debug("Registered interaction codecs (fluid place/pickup) — crop harvest handled by mixin system"); } } catch (Exception e) { - getLogger().at(Level.WARNING).log("Failed to register interaction codecs: %s", e.getMessage()); + ErrorHandler.report("Failed to register interaction codecs", e); } } diff --git a/src/main/java/com/hyperfactions/platform/WorldSetup.java b/src/main/java/com/hyperfactions/platform/WorldSetup.java index 8b2321c9..6b2f6d7d 100644 --- a/src/main/java/com/hyperfactions/platform/WorldSetup.java +++ b/src/main/java/com/hyperfactions/platform/WorldSetup.java @@ -14,7 +14,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.logging.Level; + /** * Handles world map provider registration, spawn suppression initialization, @@ -46,7 +46,7 @@ public void registerWorldMapProvider() { ); Logger.debug("Registered world map provider (ID: %s)", HyperFactionsWorldMapProvider.ID); } catch (Exception e) { - plugin.getLogger().at(Level.WARNING).withCause(e).log("Failed to register world map provider"); + ErrorHandler.report("Failed to register world map provider", e); } } @@ -80,8 +80,6 @@ public void applyToExistingWorlds() { } hyperFactions.getWorldMapService().registerProviderIfNeeded(world); } catch (Exception e) { - Logger.warn("Failed to register world map for world %s: %s", - world.getName(), e.getMessage()); ErrorHandler.report("Failed to register world map for world " + world.getName(), e); } } @@ -93,7 +91,6 @@ public void applyToExistingWorlds() { hyperFactions.getMapPlayerFilterService().applyToAll(); } catch (Exception e) { - Logger.warn("Failed to apply world map provider to existing worlds: %s", e.getMessage()); ErrorHandler.report("Failed to apply world map provider to existing worlds", e); } } @@ -154,7 +151,7 @@ List applySpawnSuppressionToAllWorlds() { } } } catch (Exception e) { - Logger.warn("Failed to apply spawn suppression to worlds: %s", e.getMessage()); + ErrorHandler.report("Failed to apply spawn suppression to worlds", e); } return failedWorlds; } @@ -168,7 +165,7 @@ public void initializeMobClearing() { hyperFactions.getZoneMobClearManager().initialize(); Logger.info("[Startup] Mob clearing initialized"); } catch (Exception e) { - plugin.getLogger().at(Level.WARNING).withCause(e).log("Failed to initialize mob clearing"); + ErrorHandler.report("Failed to initialize mob clearing", e); } } @@ -194,9 +191,7 @@ public void onWorldAdd(AddWorldEvent event) { // Apply spawn suppression to the new world hyperFactions.getSpawnSuppressionManager().applyToWorld(world); } catch (Exception e) { - plugin.getLogger().at(Level.WARNING).log("Error in AddWorldEvent handler for %s: %s", - world.getName(), e.getMessage()); - ErrorHandler.report(String.format("AddWorldEvent error for %s", world.getName()), e); + ErrorHandler.report("AddWorldEvent error for " + world.getName(), e); } } @@ -208,8 +203,7 @@ public void onWorldRemove(RemoveWorldEvent event) { try { hyperFactions.getWorldMapService().unregisterProvider(world.getName()); } catch (Exception e) { - plugin.getLogger().at(Level.WARNING).log("Error in RemoveWorldEvent handler for %s: %s", - world.getName(), e.getMessage()); + ErrorHandler.report("RemoveWorldEvent error for " + world.getName(), e); } } diff --git a/src/main/java/com/hyperfactions/protection/ecs/PlayerDeathSystem.java b/src/main/java/com/hyperfactions/protection/ecs/PlayerDeathSystem.java index b9525518..9c96d0d1 100644 --- a/src/main/java/com/hyperfactions/protection/ecs/PlayerDeathSystem.java +++ b/src/main/java/com/hyperfactions/protection/ecs/PlayerDeathSystem.java @@ -138,7 +138,7 @@ public void onComponentAdded(@NotNull Ref ref, return; } } catch (Exception e) { - Logger.warn("Zone check failed for %s, defaulting to no power loss: %s", victimUuid, e.getMessage()); + ErrorHandler.report("Zone check failed for " + victimUuid + ", defaulting to no power loss", e); announceDeathLocation(victimUuid, playerRef, store, commandBuffer, ref); return; } diff --git a/src/main/java/com/hyperfactions/storage/StorageUtils.java b/src/main/java/com/hyperfactions/storage/StorageUtils.java index b7ee6161..5f2193b8 100644 --- a/src/main/java/com/hyperfactions/storage/StorageUtils.java +++ b/src/main/java/com/hyperfactions/storage/StorageUtils.java @@ -104,7 +104,7 @@ public static WriteResult writeAtomic(@NotNull Path targetFile, @NotNull String try { Files.copy(targetFile, backupFile, StandardCopyOption.REPLACE_EXISTING); } catch (IOException e) { - Logger.warn("[Storage] Could not create backup for %s: %s", targetFile, e.getMessage()); + ErrorHandler.report(String.format("[Storage] Could not create backup for %s", targetFile), e); // Continue anyway - backup is best-effort } } @@ -290,7 +290,7 @@ public static boolean deleteWithBackup(@NotNull Path targetFile) { try { mainDeleted = Files.deleteIfExists(targetFile); } catch (IOException e) { - Logger.warn("[Storage] Failed to delete %s: %s", targetFile.getFileName(), e.getMessage()); + ErrorHandler.report(String.format("[Storage] Failed to delete %s", targetFile.getFileName()), e); } try { @@ -298,7 +298,7 @@ public static boolean deleteWithBackup(@NotNull Path targetFile) { Logger.debug("[Storage] Deleted backup file: %s", backupFile.getFileName()); } } catch (IOException e) { - Logger.warn("[Storage] Failed to delete backup %s: %s", backupFile.getFileName(), e.getMessage()); + ErrorHandler.report(String.format("[Storage] Failed to delete backup %s", backupFile.getFileName()), e); } return mainDeleted; @@ -339,7 +339,7 @@ public static int cleanupOrphanedFiles(@NotNull Path directory) { cleaned++; Logger.debug("[Storage] Cleaned orphaned temp file: %s", fileName); } catch (IOException e) { - Logger.warn("[Storage] Failed to clean temp file %s: %s", fileName, e.getMessage()); + ErrorHandler.report(String.format("[Storage] Failed to clean temp file %s", fileName), e); } continue; } @@ -354,13 +354,13 @@ public static int cleanupOrphanedFiles(@NotNull Path directory) { cleaned++; Logger.debug("[Storage] Cleaned orphaned backup file: %s", fileName); } catch (IOException e) { - Logger.warn("[Storage] Failed to clean backup file %s: %s", fileName, e.getMessage()); + ErrorHandler.report(String.format("[Storage] Failed to clean backup file %s", fileName), e); } } } } } catch (IOException e) { - Logger.warn("[Storage] Failed to scan directory for cleanup: %s", e.getMessage()); + ErrorHandler.report("[Storage] Failed to scan directory for cleanup", e); } if (cleaned > 0) { diff --git a/src/main/java/com/hyperfactions/territory/TerritoryNotifier.java b/src/main/java/com/hyperfactions/territory/TerritoryNotifier.java index df4857fc..0287c642 100644 --- a/src/main/java/com/hyperfactions/territory/TerritoryNotifier.java +++ b/src/main/java/com/hyperfactions/territory/TerritoryNotifier.java @@ -12,6 +12,7 @@ import com.hyperfactions.storage.PlayerStorage; import com.hyperfactions.territory.TerritoryInfo.TerritoryType; import com.hyperfactions.util.ChunkUtil; +import com.hyperfactions.util.ErrorHandler; import com.hyperfactions.util.Logger; import com.hypixel.hytale.server.core.Message; import com.hypixel.hytale.server.core.universe.PlayerRef; @@ -186,7 +187,7 @@ private void sendTerritoryNotification(@NotNull PlayerRef playerRef, @NotNull Te } catch (Exception e) { // Fallback to chat message if notification fails - Logger.warn("Failed to send territory notification, falling back to chat: %s", e.getMessage()); + ErrorHandler.report("Failed to send territory notification, falling back to chat", e); sendChatFallback(playerRef, territory); } } @@ -209,7 +210,7 @@ private void sendChatFallback(@NotNull PlayerRef playerRef, @NotNull TerritoryIn playerRef.sendMessage(message); } catch (Exception e) { - Logger.warn("Failed to send territory chat fallback: %s", e.getMessage()); + ErrorHandler.report("Failed to send territory chat fallback", e); } } diff --git a/src/main/java/com/hyperfactions/update/UpdateChecker.java b/src/main/java/com/hyperfactions/update/UpdateChecker.java index 46d37f04..6c20b84f 100644 --- a/src/main/java/com/hyperfactions/update/UpdateChecker.java +++ b/src/main/java/com/hyperfactions/update/UpdateChecker.java @@ -280,7 +280,7 @@ public CompletableFuture downloadUpdate(@NotNull UpdateInfo info) { Logger.info("[Update:%s] Backed up current JAR to %s", artifactName, backupFile.getFileName()); } catch (java.nio.file.FileSystemException e) { // Windows locks loaded JARs - can't backup while running - Logger.warn("[Update:%s] Could not backup old JAR (file in use). Please delete %s manually after restart.", artifactName, currentJar.getFileName()); + ErrorHandler.report(String.format("[Update:%s] Could not backup old JAR (file in use): %s", artifactName, currentJar.getFileName()), e); } } @@ -326,7 +326,7 @@ public int cleanupOldBackups(@Nullable String keepVersion) { backupFiles.add(file); } } catch (IOException e) { - Logger.warn("[Update:%s] Failed to list backup files: %s", artifactName, e.getMessage()); + ErrorHandler.report(String.format("[Update:%s] Failed to list backup files", artifactName), e); return 0; } @@ -368,7 +368,7 @@ public int cleanupOldBackups(@Nullable String keepVersion) { deleted++; Logger.info("[Update:%s] Cleanup: Removed old backup %s", artifactName, backupFile.getFileName()); } catch (IOException e) { - Logger.warn("[Update:%s] Failed to delete backup %s: %s", artifactName, backupFile.getFileName(), e.getMessage()); + ErrorHandler.report(String.format("[Update:%s] Failed to delete backup %s", artifactName, backupFile.getFileName()), e); } } @@ -481,7 +481,7 @@ public void createRollbackMarker(@NotNull String fromVersion, @NotNull String to Files.writeString(markerFile, content); Logger.debug("[Update:%s] Created rollback marker: %s -> %s", artifactName, fromVersion, toVersion); } catch (IOException e) { - Logger.warn("[Update:%s] Failed to create rollback marker: %s", artifactName, e.getMessage()); + ErrorHandler.report(String.format("[Update:%s] Failed to create rollback marker", artifactName), e); } } @@ -496,7 +496,7 @@ public void clearRollbackMarker() { Logger.debug("[Update:%s] Cleared rollback marker (server restarted with new version)", artifactName); } } catch (IOException e) { - Logger.warn("[Update:%s] Failed to clear rollback marker: %s", artifactName, e.getMessage()); + ErrorHandler.report(String.format("[Update:%s] Failed to clear rollback marker", artifactName), e); } } @@ -539,7 +539,7 @@ public RollbackInfo getRollbackInfo() { return new RollbackInfo(fromVersion, toVersion, true); } } catch (IOException e) { - Logger.warn("[Update:%s] Failed to read rollback marker: %s", artifactName, e.getMessage()); + ErrorHandler.report(String.format("[Update:%s] Failed to read rollback marker", artifactName), e); } return null; @@ -560,7 +560,7 @@ public Path findLatestBackup() { backupFiles.add(file); } } catch (IOException e) { - Logger.warn("[Update:%s] Failed to list backup files: %s", artifactName, e.getMessage()); + ErrorHandler.report(String.format("[Update:%s] Failed to list backup files for findLatestBackup", artifactName), e); return null; } diff --git a/src/main/java/com/hyperfactions/update/UpdateNotificationListener.java b/src/main/java/com/hyperfactions/update/UpdateNotificationListener.java index 957f40e6..48ccf4e0 100644 --- a/src/main/java/com/hyperfactions/update/UpdateNotificationListener.java +++ b/src/main/java/com/hyperfactions/update/UpdateNotificationListener.java @@ -4,6 +4,7 @@ import com.hyperfactions.Permissions; import com.hyperfactions.integration.PermissionManager; import com.hyperfactions.util.AdminKeys; +import com.hyperfactions.util.ErrorHandler; import com.hyperfactions.util.HFMessages; import com.hyperfactions.util.Logger; import com.hypixel.hytale.event.EventRegistry; @@ -95,8 +96,7 @@ private void onPlayerConnect(PlayerConnectEvent event) { try { checkAndNotify(playerRef); } catch (Exception e) { - Logger.warn("[UpdateNotify] Failed to send notification to %s: %s", - playerRef.getUsername(), e.getMessage()); + ErrorHandler.report("[UpdateNotify] Failed to send notification to " + playerRef.getUsername(), e); } }, NOTIFICATION_DELAY_MS, TimeUnit.MILLISECONDS); } diff --git a/src/main/java/com/hyperfactions/update/UpdateNotificationPreferences.java b/src/main/java/com/hyperfactions/update/UpdateNotificationPreferences.java index 2f97ab81..d43e179a 100644 --- a/src/main/java/com/hyperfactions/update/UpdateNotificationPreferences.java +++ b/src/main/java/com/hyperfactions/update/UpdateNotificationPreferences.java @@ -3,6 +3,7 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; +import com.hyperfactions.util.ErrorHandler; import com.hyperfactions.util.Logger; import com.hyperfactions.util.UuidUtil; import java.io.IOException; @@ -65,7 +66,7 @@ public void load() { } Logger.debug("[UpdatePrefs] Loaded %d preferences", preferences.size()); } catch (IOException e) { - Logger.warn("[UpdatePrefs] Failed to load preferences: %s", e.getMessage()); + ErrorHandler.report("[UpdatePrefs] Failed to load preferences", e); } } @@ -80,7 +81,7 @@ public void save() { Files.writeString(filePath, json, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); Logger.debug("[UpdatePrefs] Saved %d preferences", preferences.size()); } catch (IOException e) { - Logger.warn("[UpdatePrefs] Failed to save preferences: %s", e.getMessage()); + ErrorHandler.report("[UpdatePrefs] Failed to save preferences", e); } } diff --git a/src/main/java/com/hyperfactions/util/PlayerDBService.java b/src/main/java/com/hyperfactions/util/PlayerDBService.java index e19689d4..e02dd66a 100644 --- a/src/main/java/com/hyperfactions/util/PlayerDBService.java +++ b/src/main/java/com/hyperfactions/util/PlayerDBService.java @@ -90,7 +90,7 @@ public record PlayerInfo(@NotNull UUID uuid, @NotNull String username) {} } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (Exception e) { - Logger.warn("PlayerDB lookup failed for '%s': %s", name, e.getMessage()); + ErrorHandler.report("PlayerDB lookup failed for '" + name + "'", e); } return null; }); diff --git a/src/main/java/com/hyperfactions/worldmap/MapPlayerFilterService.java b/src/main/java/com/hyperfactions/worldmap/MapPlayerFilterService.java index f6496bb3..d10610b3 100644 --- a/src/main/java/com/hyperfactions/worldmap/MapPlayerFilterService.java +++ b/src/main/java/com/hyperfactions/worldmap/MapPlayerFilterService.java @@ -173,7 +173,7 @@ public void applyFilter(@NotNull Player player) { cfgShowFactionless, cfgShowFactionlessToFactionless); } catch (Exception e) { - Logger.warn("Failed to apply map player filter: %s", e.getMessage()); + ErrorHandler.report("[MapFilter] Failed to apply map player filter", e); } } @@ -268,7 +268,7 @@ private void updateHiddenPlayers(Player player, PlayerRef viewerRef, UUID viewer factionHiddenPairs.put(viewerUuid, nowHidden); } } catch (Exception e) { - Logger.warn("Failed to update HiddenPlayersManager for viewer: %s", e.getMessage()); + ErrorHandler.report("[MapFilter] Failed to update HiddenPlayersManager for viewer", e); } } @@ -289,7 +289,7 @@ private void clearHiddenPlayers(PlayerRef viewerRef) { hiddenManager.showPlayer(targetUuid); } } catch (Exception e) { - Logger.warn("Failed to clear hidden players for viewer: %s", e.getMessage()); + ErrorHandler.report("[MapFilter] Failed to clear hidden players for viewer", e); } } @@ -323,8 +323,6 @@ public void applyToAll() { applyFilter(player); } } catch (Exception e) { - Logger.warn("Error applying map filters in world %s: %s", - world.getName(), e.getMessage()); ErrorHandler.report("[MapFilter] Error applying filters in world " + world.getName(), e); } }); @@ -334,7 +332,6 @@ public void applyToAll() { } } } catch (Exception e) { - Logger.warn("Error applying map filters to all worlds: %s", e.getMessage()); ErrorHandler.report("[MapFilter] Error applying filters to all worlds", e); } } @@ -393,7 +390,6 @@ public void resetAll() { Logger.debugWorldMap("[MapFilter] resetAll: cleared filters for %d players in %s", players.size(), world.getName()); } catch (Exception e) { - Logger.warn("Error resetting map filters in world: %s", e.getMessage()); ErrorHandler.report("[MapFilter] Error resetting filters in world " + world.getName(), e); } }); @@ -403,7 +399,6 @@ public void resetAll() { } } } catch (Exception e) { - Logger.warn("Error resetting map filters: %s", e.getMessage()); ErrorHandler.report("[MapFilter] Error resetting filters across all worlds", e); } diff --git a/src/main/java/com/hyperfactions/worldmap/WorldMapService.java b/src/main/java/com/hyperfactions/worldmap/WorldMapService.java index 6e8b9dfc..59e4fe7c 100644 --- a/src/main/java/com/hyperfactions/worldmap/WorldMapService.java +++ b/src/main/java/com/hyperfactions/worldmap/WorldMapService.java @@ -148,7 +148,6 @@ public void registerProviderIfNeeded(@NotNull World world) { worldName, currentGeneratorName, betterMapActive); } catch (Exception e) { - Logger.warn("Failed to register world map for world %s: %s", worldName, e.getMessage()); ErrorHandler.report("[WorldMap] Failed to register world map for world " + worldName, e); } } @@ -227,7 +226,6 @@ public void refreshWorldMap(@NotNull World world) { try { player.getWorldMapTracker().clear(); } catch (Exception e) { - Logger.warn("Failed to clear world map tracker for player: %s", e.getMessage()); ErrorHandler.report("[WorldMap] Failed to clear world map tracker for player", e); } } @@ -235,7 +233,6 @@ public void refreshWorldMap(@NotNull World world) { Logger.debugWorldMap("Cleared world map images for world: %s (%d players)", world.getName(), world.getPlayers().size()); } catch (Exception e) { - Logger.warn("Failed to refresh world map for world %s: %s", world.getName(), e.getMessage()); ErrorHandler.report("[WorldMap] Failed to refresh world map for world " + world.getName(), e); } } @@ -263,7 +260,6 @@ public void refreshAllWorldMaps() { } Logger.debugWorldMap("Refreshed world maps for %d/%d worlds", refreshed, registeredWorlds.size()); } catch (Exception e) { - Logger.warn("Failed to refresh all world maps: %s", e.getMessage()); ErrorHandler.report("[WorldMap] Failed to refresh all world maps", e); } } @@ -400,13 +396,12 @@ public void reapplySettings() { try { player.getWorldMapTracker().sendSettings(world); } catch (Exception e) { - Logger.warn("Failed to send map settings to player: %s", e.getMessage()); + ErrorHandler.report("[WorldMap] Failed to send map settings to player", e); } } Logger.debug("[WorldMap] Reapplied settings for world: %s", worldName); } catch (Exception e) { - Logger.warn("Failed to reapply map settings for world %s: %s", worldName, e.getMessage()); ErrorHandler.report("[WorldMap] Failed to reapply settings for world " + worldName, e); } } From 64eb6d09cef669b651c8b9935773c20588a6de61 Mon Sep 17 00:00:00 2001 From: derrickmehaffy Date: Sat, 14 Mar 2026 23:49:41 -0700 Subject: [PATCH 3/7] docs: update changelog, README, and internal docs for v0.12.0 - Add missing changelog entries: SimpleClaims/FactionsX importers, BetterMap compatibility, i18n localization, ocean claim visibility fix - Update README feature tables: importers, config version, admin GUI status, localization, GUI page count - Update all 12 docs/ version headers to 0.12.0 - Add SimpleClaims and FactionsX sections to data-import.md - Add V6->V7 and V7->V8 to migration table - Add admin GUI pages to gui.md (ConfigPage, BackupsPage, UpdatesPage) - Add ZoneMobClearManager to managers.md - Add BetterMap compatibility to integrations.md - Add import subcommands to commands.md admin tree --- CHANGELOG.md | 20 +++++++++ README.md | 16 +++---- docs/api.md | 2 +- docs/architecture.md | 2 +- docs/commands.md | 7 ++- docs/config.md | 2 +- docs/data-import.md | 104 ++++++++++++++++++++++++++++++++++++++++++- docs/gui.md | 18 +++++++- docs/integrations.md | 13 +++++- docs/managers.md | 3 +- docs/permissions.md | 2 +- docs/placeholders.md | 2 +- docs/protection.md | 2 +- docs/readme.md | 2 +- 14 files changed, 174 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7df47652..64216288 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Rollback support with two-click confirmation - HyperProtect detection via ProtectionMixinBridge (works even without update checker) +**SimpleClaims Data Importer ([#99](https://github.com/HyperSystems-Development/HyperFactions/issues/99))** +- Import faction claims from SimpleClaims, converting claim data to HyperFactions territory +- Command: `/f admin import simpleclaims [path]` + +**FactionsX Data Importer ([#98](https://github.com/HyperSystems-Development/HyperFactions/issues/98))** +- Import faction data from FactionsX, converting factions, claims, and player data +- Command: `/f admin import factionsx [path]` + +**World Map Config & BetterMap Compatibility ([#102](https://github.com/HyperSystems-Development/HyperFactions/issues/102))** +- Respect per-world WorldMap enable/disable from world config +- BetterMap integration: compatible with exploration-based map reveal +- Claims and zones render correctly on BetterMap-managed worlds + +**Built-in Localization (i18n) ([#92](https://github.com/HyperSystems-Development/HyperFactions/issues/92))** +- 10 languages: en-US, de-DE, es-ES, fr-FR, it-IT, nl-NL, pl-PL, pt-BR, ru-RU, tl-PH +- ~467 translation entries per locale covering all commands, GUI labels, help content +- Player language detection with configurable default and per-player override +- Markdown-based help content system with translation guide + **Split MessageKeys into Domain-Specific Files** - Split the monolithic `MessageKeys.java` (2,789 lines, 60 inner classes, ~1,298 constants) into 6 focused domain files: - `CommonKeys.java` — shared messages, protection denial, territory notifications, announcements, teleport, chat display @@ -65,6 +84,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Command-specific permission messages with unique wording (e.g., "to create factions", "to claim territory") kept as-is ### Fixed +- **Faction claims in water/ocean nearly invisible on world map** — moved claim overlay to render after water/fluid color ([#90](https://github.com/HyperSystems-Development/HyperFactions/issues/90)) - **Water/lava disappears in own faction claim** — fluid spread was incorrectly tied to `fireSpreadAllowed` config, causing all fluid to be removed in claims when fire spread was disabled. Fluid spread in faction claims is now always allowed ([#95](https://github.com/HyperSystems-Development/HyperFactions/issues/95)) ## [0.11.1] - 2026-03-11 diff --git a/README.md b/README.md index bcf4e4e1..4f79517e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ A comprehensive faction management mod for Hytale servers featuring territory cl ## Overview -HyperFactions transforms your Hytale server into a dynamic faction-based environment where players create factions, claim territories, forge alliances, manage treasuries, and engage in strategic PvP combat. With 76 interactive GUI pages, 46 commands, and deep integration with the HyperSystems ecosystem, it provides a complete faction experience out of the box. +HyperFactions transforms your Hytale server into a dynamic faction-based environment where players create factions, claim territories, forge alliances, manage treasuries, and engage in strategic PvP combat. With 70+ interactive GUI pages, 46 commands, and deep integration with the HyperSystems ecosystem, it provides a complete faction experience out of the box. **Main Commands:** `/faction` | `/f` | `/hf` @@ -107,7 +107,7 @@ HyperFactions transforms your Hytale server into a dynamic faction-based environ | Feature | Status | |---------|--------| -| 76 interactive pages across 3 registries | Implemented | +| 70+ interactive pages across 3 registries | Implemented | | Faction leaderboard | Implemented | | Admin dashboard | Implemented | | Faction browser with search | Implemented | @@ -120,12 +120,12 @@ HyperFactions transforms your Hytale server into a dynamic faction-based environ |---------|--------| | Zone management (SafeZone, WarZone) | Implemented | | Backup system (GFS rotation) | Implemented | -| Data import (ElbaphFactions, HyFactions) | Implemented | -| Config migration (v1-v7) | Implemented | +| Data import (ElbaphFactions, HyFactions, SimpleClaims, FactionsX) | Implemented | +| Config migration (v1-v8) | Implemented | | Update checker | Implemented | -| Admin GUI: Config editor | [Planned #40](https://github.com/HyperSystems-Development/HyperFactions/issues/40) | -| Admin GUI: Backup manager | [Planned #41](https://github.com/HyperSystems-Development/HyperFactions/issues/41) | -| Admin GUI: Updates page | [Planned #42](https://github.com/HyperSystems-Development/HyperFactions/issues/42) | +| Admin GUI: Config editor | Implemented | +| Admin GUI: Backup manager | Implemented | +| Admin GUI: Updates page | Implemented | ### Integrations @@ -156,7 +156,7 @@ HyperFactions transforms your Hytale server into a dynamic faction-based environ | Server-managed factions | [Planned #33](https://github.com/HyperSystems-Development/HyperFactions/issues/33) | | ~~Relational placeholders~~ | [Done in 0.10.0](https://github.com/HyperSystems-Development/HyperFactions/issues/72) | | NPC integrations | [Considering #21](https://github.com/HyperSystems-Development/HyperFactions/issues/21) | -| Localization | [Planned #19](https://github.com/HyperSystems-Development/HyperFactions/issues/19) | +| Localization (10 languages) | Implemented | | CurseForge updates | [Planned #17](https://github.com/HyperSystems-Development/HyperFactions/issues/17) | --- diff --git a/docs/api.md b/docs/api.md index 358bd9c8..4dd41ace 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1,6 +1,6 @@ # HyperFactions Developer API Reference -> **Version**: 0.11.0 | **Package**: `com.hyperfactions.api` +> **Version**: 0.12.0 | **Package**: `com.hyperfactions.api` This document is for third-party mod developers who want to hook into HyperFactions from their own plugins. diff --git a/docs/architecture.md b/docs/architecture.md index 739004fc..4d7bcf27 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,6 +1,6 @@ # HyperFactions Architecture -> **Version**: 0.10.0 | **377 classes** across **69 packages** +> **Version**: 0.12.0 | **451 classes** across **74 packages** ## Overview diff --git a/docs/commands.md b/docs/commands.md index 262a085e..48df267b 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -1,6 +1,6 @@ # HyperFactions Command System -> **Version**: 0.11.0 | **~46 subcommands** across **10 categories** +> **Version**: 0.12.0 | **~46 subcommands** across **10 categories** Architecture documentation for the HyperFactions command system. @@ -355,6 +355,11 @@ Admin commands use nested subcommand structure: │ ├── list │ ├── restore │ └── delete +├── import # Data import from other faction plugins +│ ├── elbaphfactions [path] [flags] # Import from ElbaphFactions +│ ├── hyfactions [path] [flags] # Import from HyFactions V1 +│ ├── simpleclaims [path] [flags] # Import from SimpleClaims +│ └── factionsx [path] [flags] # Import from FactionsX ├── reload # Reload config ├── update # Check for updates │ ├── mixin # Check/download HyperProtect-Mixin diff --git a/docs/config.md b/docs/config.md index 06dd2402..64a8f407 100644 --- a/docs/config.md +++ b/docs/config.md @@ -1,6 +1,6 @@ # HyperFactions Config System -> **Version**: 0.11.0 | **Config version**: 7 | **11 config files** +> **Version**: 0.12.0 | **Config version**: 8 | **11 config files** Architecture documentation for the HyperFactions configuration system. diff --git a/docs/data-import.md b/docs/data-import.md index d09ba51f..9707dde4 100644 --- a/docs/data-import.md +++ b/docs/data-import.md @@ -1,6 +1,6 @@ # HyperFactions Data Import & Migration -> **Version**: 0.10.0 | **Packages**: `com.hyperfactions.importer`, `com.hyperfactions.migration` +> **Version**: 0.12.0 | **Packages**: `com.hyperfactions.importer`, `com.hyperfactions.migration` HyperFactions supports importing data from other faction plugins and automatically migrating its own configuration between versions. @@ -10,6 +10,8 @@ HyperFactions supports importing data from other faction plugins and automatical - [ElbaphFactions Importer](#elbaphfactions-importer) - [HyFactions V1 Importer](#hyfactions-v1-importer) +- [SimpleClaims Importer](#simpleclaims-importer) +- [FactionsX Importer](#factionsx-importer) - [Config Migration System](#config-migration-system) - [Pre-Import Backup](#pre-import-backup) @@ -124,6 +126,104 @@ Same flags as ElbaphFactions: `--dry-run`, `--overwrite`, `--no-zones`, `--no-po --- +## SimpleClaims Importer + +**Command**: `/f admin import simpleclaims [path] [flags]` +**Permission**: `hyperfactions.admin.use` + +Imports faction data from the SimpleClaims mod, converting parties and claims to HyperFactions format. + +### Data Directory + +Default: `mods/SimpleClaims/` (or specify a custom path) + +Supports two storage formats (auto-detected): + +| Format | File | Contents | +|--------|------|----------| +| SQLite | `SimpleClaims.db` | Modern format — parties, claims, name cache in one database | +| JSON | `Parties.json` | Legacy format — party definitions | +| JSON | `Claims.json` | Legacy format — territory claims (ChunkY=Z quirk) | +| JSON | `NameCache.json` | Legacy format — UUID to player name mapping | + +### Command Options + +| Flag | Description | +|------|-------------| +| `--dry-run` | Validate data without importing | +| `--overwrite` | Overwrite existing factions with matching names | +| `--no-power` | Skip power assignment | + +### Data Mapping + +| SimpleClaims | HyperFactions | +|-------------|---------------| +| Party name, description, color | Direct mapping (signed RGB integer converted to `#RRGGBB`) | +| Owner → LEADER, Members → MEMBER | 2 roles only (no officer equivalent) | +| Claims per dimension | FactionClaim records with world/chunkX/chunkZ | +| Protection overrides (place, break, interact, pvp) | FactionPermissions outsider flags | +| Mutual party alliances | ALLY relations (one-way alliances skipped) | +| Player allies | No equivalent — logged as warnings | + +> **Notes:** +> - SimpleClaims has no power system — all imported players receive the configured max power +> - No faction home support +> - No zone (safezone/warzone) support +> - SQLite format requires the SimpleClaims JAR in the mods folder (for the JDBC driver) +> - Black or missing colors are replaced with a random color + +--- + +## FactionsX Importer + +**Command**: `/f admin import factionsx [path] [flags]` +**Permission**: `hyperfactions.admin.use` + +Imports faction data from the FactionsX mod (by Humblegod666), converting factions, claims, zones, and player data to HyperFactions format. + +### Data Directory + +Default: `mods/FactionsX/config/` (or specify a custom path) + +Expected structure: + +| Path | Contents | +|------|----------| +| `factions/{UUID}.json` | Individual JSON files per faction | +| `players/{UUID}.json` | Per-player files (name + power) | +| `Claims.json` | Territory claims by dimension (ChunkY=Z quirk) | +| `Zones.json` | SafeZone and WarZone chunks per dimension | + +### Command Options + +| Flag | Description | +|------|-------------| +| `--dry-run` | Validate data without importing | +| `--overwrite` | Overwrite existing factions with matching names | +| `--no-zones` | Skip zone import | +| `--no-power` | Skip power data import | + +### Data Mapping + +| FactionsX | HyperFactions | +|-----------|---------------| +| Faction name, description, color | Direct mapping (color converted to `#RRGGBB`) | +| Owner (implicit LEADER) + Members | FactionMember records; RECRUIT mapped to MEMBER | +| Claims per dimension | FactionClaim records with world/chunkX/chunkZ | +| SafeZones / WarZones | Zone records with type and claim set | +| Per-player power/maxPower | PlayerPower records (power + max power preserved) | +| Per-role permissions (Build, Claim, Interact, Invite, Kick) | FactionPermissions flags per role | +| Home (x/y/z/dimension) | FactionHome with world mapping | +| Relations (ally/enemy/neutral) | FactionRelation records | + +> **Notes:** +> - Owner is NOT in the Members map — always treated as LEADER implicitly +> - RECRUIT role is mapped to MEMBER (HyperFactions has 3 roles: LEADER, OFFICER, MEMBER) +> - Thread-safe: `ReentrantLock` + `AtomicBoolean` prevents concurrent imports +> - Empty factions (no members) are skipped with a warning + +--- + ## Config Migration System HyperFactions automatically migrates configuration files between versions on startup. @@ -152,6 +252,8 @@ Migrations are applied in sequence. The `MigrationRegistry` builds the chain aut | `ConfigV3ToV4Migration` | v3 | v4 | Restructure permissions, add interaction sub-types | | `ConfigV4ToV5Migration` | v4 | v5 | Remove `warzonePowerLoss`, add per-zone `power_loss` flag | | `ConfigV5ToV6Migration` | v5 | v6 | Split `config.json` into `config/factions.json` + `config/server.json` | +| `ConfigV6ToV7Migration` | v6 | v7 | Restructure economy config, add upkeep settings | +| `ConfigV7ToV8Migration` | v7 | v8 | Add localization settings, language config | **Data Migrations** (run before storage init in `HyperFactions.enable()`): diff --git a/docs/gui.md b/docs/gui.md index 38ffd748..7de12017 100644 --- a/docs/gui.md +++ b/docs/gui.md @@ -1,6 +1,6 @@ # HyperFactions GUI System -> **Version**: 0.11.0 | **~76 pages** across **3 registries** +> **Version**: 0.12.0 | **~70 pages** across **3 registries** Architecture documentation for the HyperFactions GUI system using Hytale's CustomUI. @@ -678,6 +678,22 @@ Inter-faction transfer search. Browse and search target factions for treasury tr #### TreasuryTransferConfirmPage Transfer confirmation modal. Shows source faction, target faction, amount, and fee (if configured). Requires officer+ permission. +## New Pages in v0.12.0 + +### Admin Pages + +#### AdminConfigPage +Runtime config editor with 11 tabs: Server, Chat, Announcements, Economy, Factions, Faction Perms, Worldmap, Worlds, Backup, Debug, Gravestones. Size-adaptive layouts (narrow/standard/wide), inline editing with boolean toggles, integer/double steppers, text fields, color pickers, enum dropdowns, and locale selectors. Edit session caching survives page close/reopen. Per-field validation with error highlighting. Uses ConfigSnapshot for applying changes and ConfigValidator for input bounds. + +#### AdminBackupsPage +Paginated backup list with expand/collapse detail view per entry. Create manual backups with optional custom name. Restore with two-click confirmation and automatic safety backup. Delete with two-click confirmation. Backup type filter dropdown (All / Hourly / Daily / Weekly / Manual / Migration). + +#### AdminUpdatesPage +Two-column layout: HyperFactions (left) and HyperProtect Mixin (right). Shows current version, latest version, channel, build date, and update status. Single "Check for Updates" button checks both simultaneously. Download buttons appear when updates are available. Changelog display for HyperFactions updates. Rollback support with two-click confirmation. + +#### ScalingTiersModalPage +Upkeep scaling tiers editor modal opened from AdminConfigPage Economy tab. Add/remove/reorder tiers with promote/demote buttons (disabled on first/last). Live cost example display. + ## Adding New Pages 1. **Create data record** in appropriate `data/` package: diff --git a/docs/integrations.md b/docs/integrations.md index 45acea07..95605c27 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -1,6 +1,6 @@ # HyperFactions Integration Breakdown -> **Version**: 0.11.0 | **Package**: `com.hyperfactions.integration` +> **Version**: 0.12.0 | **Package**: `com.hyperfactions.integration` HyperFactions integrates with external plugins through soft dependencies. All integrations use reflection-based detection and fail-open design — if a dependency is missing, the feature gracefully degrades. @@ -16,7 +16,7 @@ HyperFactions integrates with external plugins through soft dependencies. All in - [Protection Mixin Bridge](#protection-mixin-bridge) - [HyperProtect-Mixin](#hyperprotect-mixin) (recommended) - [OrbisGuard-Mixins](#orbisguard-mixins) -- [World Map](#world-map) +- [World Map](#world-map) (incl. BetterMap compatibility) - [GravestonePlugin](#gravestoneplugin) - [KyuubiSoft Core](#kyuubisoft-core) - [Sentry](#sentry) @@ -470,6 +470,15 @@ Key settings in `config/worldmap.json`: - `maxChunksPerBatch` — Throttle for large updates - `showFactionTags` — Display faction names on the map +### BetterMap Compatibility + +HyperFactions is compatible with BetterMap's exploration-based map reveal system. When BetterMap is installed: + +- Per-world WorldMap enable/disable settings in `config/worlds.json` are respected +- Claims and zones render correctly on BetterMap-managed worlds +- The `WorldMapService` checks world config before registering map providers +- No additional configuration needed — auto-detected at world load + --- ## GravestonePlugin diff --git a/docs/managers.md b/docs/managers.md index 9e16a29d..120fe720 100644 --- a/docs/managers.md +++ b/docs/managers.md @@ -1,6 +1,6 @@ # HyperFactions Manager Layer -> **Version**: 0.10.0 | **15 core managers** (20 total) +> **Version**: 0.12.0 | **16 core managers** (22 total) The manager layer contains all business logic for HyperFactions, organized by domain. @@ -68,6 +68,7 @@ graph TD | [EconomyManager](#economymanager) | Faction economy (treasury, transactions) | FactionManager | | [AnnouncementManager](#announcementmanager) | Server-wide event broadcasts | None | | [SpawnSuppressionManager](#spawnsuppressionmanager) | Mob spawn control in claims/zones | ZoneManager, ClaimManager | +| [ZoneMobClearManager](#zonemobclearmanager) | Periodic mob clearing in zones | ZoneManager | ## Initialization Order diff --git a/docs/permissions.md b/docs/permissions.md index dd862344..08dfa1ec 100644 --- a/docs/permissions.md +++ b/docs/permissions.md @@ -1,6 +1,6 @@ # HyperFactions Permission Framework -> **Version**: 0.11.0 | **76 permission nodes** across **12 categories** +> **Version**: 0.12.0 | **76 permission nodes** across **12 categories** Architecture documentation for the HyperFactions permission system. diff --git a/docs/placeholders.md b/docs/placeholders.md index e61ad0e7..9f1f32df 100644 --- a/docs/placeholders.md +++ b/docs/placeholders.md @@ -1,6 +1,6 @@ # HyperFactions Placeholders -> **Version**: 0.10.0 | **Expansion Identifier**: `factions` | **51 placeholders** +> **Version**: 0.12.0 | **Expansion Identifier**: `factions` | **51 placeholders** HyperFactions exposes faction data as placeholders through two placeholder APIs: **PlaceholderAPI (PAPI)** and **WiFlow PlaceholderAPI**. Both APIs support the same set of placeholders with identical behavior. diff --git a/docs/protection.md b/docs/protection.md index 2f3e9568..dcfbc910 100644 --- a/docs/protection.md +++ b/docs/protection.md @@ -1,6 +1,6 @@ # HyperFactions Protection System -> **Version**: 0.11.0 +> **Version**: 0.12.0 Multi-layered protection controlling block interactions, PvP combat, damage types, and mob spawning based on zones, faction claims, and player relations. diff --git a/docs/readme.md b/docs/readme.md index 423d6b5a..4814d8ec 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -1,6 +1,6 @@ # HyperFactions Developer Documentation -> **Version**: 0.11.0 | **~409 classes** | **69 packages** | **20 managers** | **~46 commands** | **76 permissions** +> **Version**: 0.12.0 | **~451 classes** | **74 packages** | **22 managers** | **~46 commands** | **76 permissions** Developer documentation for HyperFactions - a comprehensive faction management plugin for Hytale servers. From 74f85566ebd84dbf02b6c69b56c0358f672c791e Mon Sep 17 00:00:00 2001 From: derrickmehaffy Date: Sat, 14 Mar 2026 23:49:47 -0700 Subject: [PATCH 4/7] docs: update CurseForge description for v0.12.0 - Replace What's New section with v0.12.0 features (i18n, admin GUI pages, SimpleClaims/FactionsX importers, BetterMap, ocean fix) - Update data import references to include all 4 importers - Update GUI page count from 65+ to 70+ - Update JitPack version to v0.12.0 --- curseforge-description.html | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/curseforge-description.html b/curseforge-description.html index b639e39b..d8b4e6fa 100644 --- a/curseforge-description.html +++ b/curseforge-description.html @@ -5,26 +5,23 @@

⚔️HyperFactions - The Complete Fact

 

✨ Why HyperFactions?

    -
  • 🖥️ 76 Interactive GUI Pages - Every feature has a polished, interactive GUI. No command memorization needed.
  • +
  • 🖥️ 70+ Interactive GUI Pages - Every feature has a polished, interactive GUI. No command memorization needed.
  • Real-Time GUI Updates - When a member joins, a chunk is claimed, or a relation changes, every open GUI refreshes automatically.
  • 🛡️ 50 Zone Flags - The most granular territory protection available, from PvP and granular friendly fire to mob spawning, transport control, and F-key pickup.
  • -
  • 📦 Data Import - Migrating from ElbaphFactions or HyFactions? One command imports your factions, claims, and relations.
  • +
  • 📦 Data Import - Migrating from ElbaphFactions, HyFactions, SimpleClaims, or FactionsX? One command imports your factions, claims, and relations.
  • ⚙️ Deep Configurability - 11 modular config files covering every aspect of gameplay. Tune it to your server's style.
  • 🚀 Active Development - Regular updates with community-driven features. Open source on GitHub.

 

-

🆕 What's New in v0.11.0

+

🆕 What's New in v0.12.0

    -
  • 💰 Faction Upkeep System - Automated territory maintenance costs with flat or progressive tiered pricing, grace periods, and auto-pay
  • -
  • 🐾 Mob Clearing Zone Flags - 4 new flags to periodically remove hostile, passive, and neutral mobs from zones
  • -
  • 🔍 Sentry Error Tracking - Automatic error reporting with Sentry SDK, admin enable/disable, and source context
  • -
  • 🗺️ World Map Player & Marker Hiding - Hide enemy/neutral players and shared markers on the world map per faction relation
  • -
  • 💡 Light Use Zone Flag - Control toggling lanterns, campfires, torches, and lamps in zones
  • -
  • 🐴 Mount Entry Enforcement - Block mounted players from entering zones, with safe teleport push-back
  • -
  • 🔧 KyuubiSoft Core Integration - Citizen NPC zone protection with auto-detection
  • -
  • 🛡️ HyperProtect-Mixin v1.2.0 - 7 new hook wrappers for mount, barter, fluid, prefab, projectile, crafting, and map markers
  • -
  • 💬 Specific Denial Messages - Action-specific protection denial messages with territory context instead of generic text
  • -
  • 🐛 20+ Bug Fixes - Including SafeZone mount bypass, light use blocking, spawn suppression timing, gravestone loot, and backup race conditions
  • +
  • 🌍 Built-in Localization (i18n) - 10 languages out of the box: English, German, Spanish, French, Italian, Dutch, Polish, Portuguese, Russian, Filipino. Player language auto-detection with configurable default.
  • +
  • ⚙️ Admin GUI: Config Editor - Edit all HyperFactions settings in-game with 11 tabs, size-adaptive layouts, boolean toggles, steppers, color pickers, dropdowns, and input validation
  • +
  • 💾 Admin GUI: Backup Manager - Paginated backup list with create, restore, and delete operations, plus type filtering
  • +
  • 🔄 Admin GUI: Updates Page - Check for HyperFactions and HyperProtect-Mixin updates, download, and rollback — all from the GUI
  • +
  • 📦 SimpleClaims & FactionsX Importers - Two new data importers: migrate from SimpleClaims (SQLite or JSON) or FactionsX with full claim, member, and relation import
  • +
  • 🗺️ BetterMap Compatibility - Per-world WorldMap enable/disable config, claims and zones render correctly on BetterMap-managed worlds
  • +
  • 🌊 Ocean Claim Visibility Fix - Faction claims in water/ocean are now clearly visible on the world map

 

🏰 Core Features

@@ -177,7 +174,7 @@

🔧 Admin Tools

  • Rollback support - /f admin rollback reverts to the previous version before restart
  • 🐛 Debug system - Toggle 7+ debug categories individually for targeted troubleshooting
  • Claim decay management - Monitor and manually trigger inactive faction cleanup
  • -
  • 📦 Data import - Migrate from ElbaphFactions or HyFactions with validation reports
  • +
  • 📦 Data import - Migrate from ElbaphFactions, HyFactions, SimpleClaims, or FactionsX with validation reports
  • Power management - Per-player power set, adjust, reset, bypass toggles, and bulk faction operations
  • 💰 Economy management - Server-wide treasury overview, per-faction balance adjustment
  • 👥 Player browser - Search and manage all server players with sort and quick actions
  • @@ -222,6 +219,8 @@

    📦 Data Migration

    • ElbaphFactions - Full import of factions, members, claims, relations, and zones
    • HyFactions - Full import with validation reporting
    • +
    • SimpleClaims - Import parties and claims (SQLite or JSON format) with alliance detection
    • +
    • FactionsX - Import factions, claims, zones, player power, and per-role permissions

    🗺️ Region Protection

      @@ -401,7 +400,7 @@

      🧑‍💻 For Developers

      } dependencies { - compileOnly 'com.github.HyperSystems-Development:HyperFactions:v0.11.0' + compileOnly 'com.github.HyperSystems-Development:HyperFactions:v0.12.0' }

      See the full Developer API Reference on GitHub for API usage, event listeners, economy integration, and more.

       

      @@ -420,7 +419,7 @@

      🧩 The HyperSystems Suite

      ⚔️ HyperFactions - Complete faction system with territory, diplomacy, economy, and 65+ GUI pages + Complete faction system with territory, diplomacy, economy, and 70+ GUI pages 🛡️ HyperProtect-Mixin From 1f681c7e7d40f10bdee2b71b62248b6d957e9d23 Mon Sep 17 00:00:00 2001 From: derrickmehaffy Date: Sat, 14 Mar 2026 23:49:52 -0700 Subject: [PATCH 5/7] chore: bump version to 0.12.0 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 98289c94..d1fe7993 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ plugins { } group = 'com.hyperfactions' -version = '0.11.1' +version = '0.12.0' // Shared version property avoids accessing project at execution time def buildVersion = objects.property(String).convention(version) From 7d581f0ef963b7535523f7d5ca3530e6de95c2d0 Mon Sep 17 00:00:00 2001 From: derrickmehaffy Date: Sun, 15 Mar 2026 13:01:23 -0700 Subject: [PATCH 6/7] fix: correct CurseForge description inaccuracies - Fix zone flag count: 50 -> 51 (verified against ZoneFlags.ALL_FLAGS) - Fix Integration flags category: was listing removed flags (command blocking, fluid spread, map visibility), now lists actual flags (gravestone access, show on map, essentials homes/warps/kits) - Fix GUI page count: 76 -> 70+ (67 actual page classes) - Add missing Core Features: faction economy with upkeep system, localization (10 languages) - Remove Sentry from public-facing description (dev-only feature) - Convert integrations section from nested lists to tables for easier maintenance as the list grows - Also fix zone flag count in README (50 -> 51) --- README.md | 2 +- curseforge-description.html | 188 +++++++++++++++++++++++++++--------- 2 files changed, 142 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 4f79517e..840de645 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ HyperFactions transforms your Hytale server into a dynamic faction-based environ | Mob spawn suppression | Implemented | | Mob clearing zone flags | Implemented | | Gravestones integration | Implemented | -| Zone flags (50) | Implemented | +| Zone flags (51) | Implemented | | Command blocking in zones | Implemented | | Sentry error tracking | Implemented | diff --git a/curseforge-description.html b/curseforge-description.html index d8b4e6fa..bc8e3dd4 100644 --- a/curseforge-description.html +++ b/curseforge-description.html @@ -7,7 +7,7 @@

      ✨ Why HyperFactions?

      • 🖥️ 70+ Interactive GUI Pages - Every feature has a polished, interactive GUI. No command memorization needed.
      • Real-Time GUI Updates - When a member joins, a chunk is claimed, or a relation changes, every open GUI refreshes automatically.
      • -
      • 🛡️ 50 Zone Flags - The most granular territory protection available, from PvP and granular friendly fire to mob spawning, transport control, and F-key pickup.
      • +
      • 🛡️ 51 Zone Flags - The most granular territory protection available, from PvP and granular friendly fire to mob spawning, transport control, and F-key pickup.
      • 📦 Data Import - Migrating from ElbaphFactions, HyFactions, SimpleClaims, or FactionsX? One command imports your factions, claims, and relations.
      • ⚙️ Deep Configurability - 11 modular config files covering every aspect of gameplay. Tune it to your server's style.
      • 🚀 Active Development - Regular updates with community-driven features. Open source on GitHub.
      • @@ -72,9 +72,21 @@

        ⚔️ Combat System

      • Relationship-based PvP - Allies protected, enemies open, configurable per zone
      • Overclaim defender alerts - Faction members get real-time alerts when territory is being taken
      +

      💰 Faction Economy

      +
        +
      • Faction treasury with deposits, withdrawals, inter-faction transfers, and transaction history
      • +
      • Upkeep system - Automated territory maintenance costs with flat or progressive tiered pricing, grace periods, and auto-pay
      • +
      • VaultUnlocked integration - Works with any economy plugin via the standard economy API
      • +
      +

      🌍 Localization

      +
        +
      • 10 languages built in: English, German, Spanish, French, Italian, Dutch, Polish, Portuguese, Russian, Filipino
      • +
      • Player language auto-detection with configurable default and per-player override
      • +
      • ~467 translation entries per locale covering all commands, GUI labels, and help content
      • +

       

      🛡️ Protection System

      -

      HyperFactions provides comprehensive territory protection with 50 configurable zone flags organized into categories:

      +

      HyperFactions provides comprehensive territory protection with 51 configurable zone flags organized into 10 categories:

      • ⚔️ Combat (7) - PvP, friendly fire (per-faction/per-ally), projectile damage, PvE damage, mob damage
      • 🧱 Building (4) - Build allowed, block place (mixin), hammer use (mixin), builder tools (mixin)
      • @@ -85,7 +97,7 @@

        🛡️ Protection System

      • 💀 Death (2) - Keep inventory (mixin), power loss
      • 💥 Damage (4) - Fall damage, environmental damage, explosion damage (mixin), fire spread (mixin)
      • 🚀 Transport (3) - Teleporter use (mixin), portal use (mixin), mount entry
      • -
      • 🔗 Integration (5) - Show on map, command blocking, map visibility, fluid spread (mixin), mount entry
      • +
      • 🔗 Integration (5) - Gravestone access, show on map, essentials homes, essentials warps, essentials kits

       

      🏟️ SafeZones & WarZones

      @@ -121,7 +133,7 @@

      📢 Server-Wide Announcements

      Each event type can be individually enabled or disabled in announcements.json.

       

      🖥️ Full GUI System

      -

      HyperFactions features 76 interactive GUI pages covering every aspect of gameplay:

      +

      HyperFactions features 70+ interactive GUI pages covering every aspect of gameplay:

      🎮 Player GUI (/f)

      • 📊 Dashboard - Power, claims, members, relations, status, and invites at a glance
      • @@ -196,50 +208,132 @@

        📊 PlaceholderAPI Support

        Use with any scoreboard, hologram, or menu plugin that supports PAPI or WiFlow.

         

        🔌 Integrations

        -

        ⭐ = Recommended Mod by HyperSystems Team

        -

        🔑 Permission Systems

        -

        HyperFactions supports multiple permission providers with automatic detection:

        -
          -
        • HyperPerms - Full integration with faction chat prefixes, rank display, and contextual permissions (Recommended)
        • -
        • LuckPerms - Granular permission control
        • -
        • VaultUnlocked - Chat, economy, and permission compatibility
        • -
        • No permission mod - Works without any permission plugin (configurable allow/deny default)
        • -
        -

        🛡️ Protection Extensions

        -
          -
        • Hyxin + HyperProtect-Mixin - Recommended — 27 protection hooks including F-key pickup, keep inventory, explosion/fire/fluid protection, block placement, transport control, entity damage, mount/barter/projectile control, map marker filtering, and more
        • -
        • Hyxin + OrbisGuard-Mixins - Alternative — 11 protection hooks. Both can run simultaneously (HyperFactions auto-detects and routes hooks accordingly)
        • -
        -

        📊 Placeholder Systems

        - -

        📦 Data Migration

        -
          -
        • ElbaphFactions - Full import of factions, members, claims, relations, and zones
        • -
        • HyFactions - Full import with validation reporting
        • -
        • SimpleClaims - Import parties and claims (SQLite or JSON format) with alliance detection
        • -
        • FactionsX - Import factions, claims, zones, player power, and per-role permissions
        • -
        -

        🗺️ Region Protection

        -
          -
        • OrbisGuard - Auto-blocks claims in OG-protected regions, renders OG regions on world map and territory GUI with colored overlays
        • -
        -

        🤝 Direct Mod Integrations

        -
          -
        • HyBounty — Place bounties on other players with faction-aware protections against abuse
        • -
        • 🪦 Gravestones — Faction-aware gravestone protection with per-zone access control, configurable ally/member access, and death location announcements
        • -
        • 💰 Ecotale — Faction treasury system with deposits, withdrawals, inter-faction transfers, and admin economy tools via VaultUnlocked bridge
        • -
        • 🏘️ KyuubiSoft Core — Citizen NPC zone protection — auto-detects KyuubiSoft citizens and enforces faction territory rules for NPC dialog interactions
        • -
        +

        All integrations use automatic detection and fail-open design. = Recommended

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        ModCategoryDescription
        HyperPermsPermissionsFaction chat prefixes, rank display, and contextual permissions
        LuckPermsPermissionsGranular permission control
        VaultUnlockedEconomyChat, economy, and permission compatibility layer
        HyperProtect-MixinProtection27 mixin hooks — F-key pickup, keep inventory, explosions, fire, fluid, transport, mount, barter, projectile, map markers, and more
        OrbisGuard-MixinsProtection11 mixin hooks (alternative). Both can run simultaneously — auto-detected
        OrbisGuardRegionsBlocks claims in OG regions, renders OG regions on world map and territory GUI
        PlaceholderAPIPlaceholders49 placeholders for scoreboards, chat, and menus
        WiFlow PlaceholderAPIPlaceholders47 placeholders in WiFlow format
        HyBountyGameplayPlayer bounties with faction-aware protections against abuse
        GravestonesGameplayFaction-aware gravestone protection, per-zone access, death location announcements
        EcotaleEconomyFaction treasury via VaultUnlocked — deposits, withdrawals, transfers, admin tools
        KyuubiSoft CoreNPCCitizen NPC zone protection with auto-detection
        +

        📦 Data Import

        + + + + + + + + + + + + + + + + + + + + + + + + + +
        SourceWhat’s Imported
        ElbaphFactionsFactions, members, claims, relations, and zones
        HyFactionsFactions, members, claims, relations, zones, and power
        SimpleClaimsParties, claims (SQLite or JSON), and mutual alliances
        FactionsXFactions, claims, zones, player power, and per-role permissions

        🔮 Upcoming Integrations

        -
          -
        • 📈 RPG Leveling - Faction bonuses and level-based perks for faction members (Planned)
        • -
        • 🗣️ NPC Dialog - Faction NPCs and dialog interactions in claimed territory (Planned)
        • -
        • 📝 NPC Quests Maker - Faction quests and mission systems (Planned)
        • -
        • 📋 BetterScoreBoard - Faction data on the scoreboard HUD (Waiting on BetterScoreBoard to support PlaceholderAPI or WiFlow)
        • -
        + + + + + + + + + + + + + + + + + + + + + + + + + +
        ModStatus
        RPG LevelingPlanned — Faction bonuses and level-based perks
        NPC DialogPlanned — Faction NPCs and dialog in claimed territory
        NPC Quests MakerPlanned — Faction quests and mission systems
        BetterScoreBoardWaiting — Needs PlaceholderAPI or WiFlow support

        💡 Want HyperFactions to integrate with your plugin? Reach out to DMehaffy on Discord to discuss integration opportunities.

         

        📥 Installation

        From 63a160170afc37759aa3eff8c0b2d6899344b4d8 Mon Sep 17 00:00:00 2001 From: derrickmehaffy Date: Sun, 15 Mar 2026 13:03:29 -0700 Subject: [PATCH 7/7] fix: additional accuracy corrections from code verification - Fix HyperProtect-Mixin hook count: 27 -> 28 (verified SLOT_ constants) - Remove "Command blocking in zones" from README (not yet implemented) --- README.md | 3 +-- curseforge-description.html | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 840de645..e6dcb7a5 100644 --- a/README.md +++ b/README.md @@ -93,14 +93,13 @@ HyperFactions transforms your Hytale server into a dynamic faction-based environ | Feature | Status | |---------|--------| | Block, item, PvP protection | Implemented | -| [HyperProtect-Mixin](https://www.curseforge.com/hytale/bootstrap/hyperprotect-mixin) (27 hooks, recommended) | Implemented | +| [HyperProtect-Mixin](https://www.curseforge.com/hytale/bootstrap/hyperprotect-mixin) (28 hooks, recommended) | Implemented | | OrbisGuard-Mixins (11 hooks, alternative) | Implemented | | Dual-provider auto-detection | Implemented | | Mob spawn suppression | Implemented | | Mob clearing zone flags | Implemented | | Gravestones integration | Implemented | | Zone flags (51) | Implemented | -| Command blocking in zones | Implemented | | Sentry error tracking | Implemented | ### GUI diff --git a/curseforge-description.html b/curseforge-description.html index bc8e3dd4..93868f85 100644 --- a/curseforge-description.html +++ b/curseforge-description.html @@ -236,7 +236,7 @@

        🔌 Integrations

        HyperProtect-Mixin Protection - 27 mixin hooks — F-key pickup, keep inventory, explosions, fire, fluid, transport, mount, barter, projectile, map markers, and more + 28 mixin hooks — F-key pickup, keep inventory, explosions, fire, fluid, transport, mount, barter, projectile, map markers, and more OrbisGuard-Mixins