Skip to content

v0.10.0: Per-world settings, config restructure, data migration, leaderboard, activity log, placeholders, bug fixes#74

Merged
derrickmehaffy merged 50 commits into
mainfrom
dev/v0.10.0
Feb 27, 2026
Merged

v0.10.0: Per-world settings, config restructure, data migration, leaderboard, activity log, placeholders, bug fixes#74
derrickmehaffy merged 50 commits into
mainfrom
dev/v0.10.0

Conversation

@derrickmehaffy
Copy link
Copy Markdown
Member

@derrickmehaffy derrickmehaffy commented Feb 27, 2026

Summary

HyperFactions v0.10.0 — 10 GitHub issues resolved plus significant unrequested improvements across config management, data storage, admin tooling, protection, and economy precision.


New Features

Gameplay

  • Per-world settings (#59) — config/worlds.json with per-world claiming, powerLoss, and friendlyFire. Wildcard patterns (%), priority resolution, and admin commands
  • Hardcore power mode (#69) — Shared faction power pool with no floor/cap; deaths affect the faction total directly
  • Explosions in claims (#65) — Global toggle superseded by 9 granular protection overrides (see Config Restructure below)
  • Capture crate & NPC tame protection — 2 new per-role faction permissions (CrateUse, NpcTame, 8 flags total) and 3 new zone flags (crate_pickup, crate_place, npc_tame). Requires HyperProtect-Mixin CaptureCrateGate + SimpleInstantInteractionGate NPC entries
  • Instance world protection — Default instance-% wildcard rule blocks claiming in temporary instance worlds; /f sethome blocked in disallowed worlds; stale claim/home cleanup on startup and reload
  • Configurable role display names — New roles section in config/factions.json for custom role names and abbreviations. All GUIs, commands, and messages use configured names. New placeholders: factions_role_display, factions_role_short

GUI & Information

  • Faction leaderboard (#67) — /f leaderboard with POWER/TERRITORY/BALANCE/MEMBERS/K:D sort modes, pagination, and nav bar
  • Activity log GUI (#68) — Faction logs in nav bar, /f logs, admin global log with type/player/time filters
  • Zone notification settings — Per-zone entry/leave notification toggle, customizable upper/lower title text, admin commands for configuration
  • Admin zone properties page — Consolidated page for zone name, type, and notification settings; replaces separate Rename/Type buttons with single Settings button

Persistence & Placeholders

  • Persistent admin bypass (#71) — Bypass state persists across restarts via PlayerData; auto-cleared if permission removed
  • Treasury placeholders (#66) — treasury_balance, treasury_balance_raw, treasury_autopay, treasury_limit
  • Colored & relational placeholders (#72) — name_colored, tag_colored, legacy variants, relational PAPI placeholders
  • Economy name detectionVaultEconomyProvider.getEconomyName() detects registered economy plugin name via reflection (e.g. "Active (Ecotale)")

Admin Improvements

K/D Management & Info Redesign

  • Per-player K/D reset — Red "Reset K/D" button on admin player info page
  • Global K/D reset — New "Actions" admin page with two-step confirmation for server-wide K/D reset
  • Admin commands/f admin info [faction] and /f admin who [player] open admin GUIs directly from chat
  • Admin version page/f admin version shows mod versions, server version, Java version, and all integration statuses with color-coded status. Console prints text output
  • K/D leaderboard — K/D is now default sort mode, aggregated from member stats with configurable cache refresh (300s default)
  • Player info redesign — Two-column layout: first joined, last online, faction card with View Faction button, scrollable membership history (left); power/combat/bypass controls (right)
  • Faction info redesign — Two-column layout: leadership info (left); power management, economy, and danger zone/disband (right)

Bug Fixes

  • Backup orphaned files (#61) — Skip .tmp/.bak orphans during backup, clean up before zipping, delete incomplete ZIPs on failure
  • Warzone power loss (#62) — Zone check failure now defaults to no power loss (fail-safe) instead of silently applying penalty
  • Kill/death tracking race condition — Per-UUID locking in JsonPlayerStorage to serialize concurrent writes; atomic updatePlayerData method prevents power regen from overwriting kill/death increments
  • Windows atomic write failuresATOMIC_MOVE fails when antivirus/indexer holds a file handle; StorageUtils.writeAtomic() now retries with backoff (3 attempts) then falls back to non-atomic move
  • HyperProtect version hardcodedHyperProtectIntegration now detects actual version from JAR filename in earlyplugins/ instead of hardcoding "1.0.0"

Infrastructure

Config Restructure (V5 → V6 Migration)

Split monolithic config.json into two module configs with automatic migration:

  • config/factions.json — Faction gameplay: power, claims, combat, relations, invites, stuck, roles
  • config/server.json — Server behavior: teleport, autoSave, messages, GUI, permissions, updates

9 new claim protection overrides in config/factions.json:

Category Settings
Item interaction outsiderPickupAllowed, outsiderDropAllowed
Explosions factionlessExplosionsAllowed, enemyExplosionsAllowed, neutralExplosionsAllowed (replaces allowExplosionsInClaims)
Environment fireSpreadAllowed (was hardcoded block)
Entity damage factionlessDamageAllowed, enemyDamageAllowed, neutralDamageAllowed

Treasury permission flags (treasuryDeposit, treasuryWithdraw, treasuryTransfer) added to faction-permissions.json.

Data Directory Restructure (v0 → v1 Migration)

All data files moved into data/ subdirectory with automatic migration:

data/
├── factions/          # Per-faction JSON
├── players/           # Per-player power data
├── chat/              # Per-faction chat history
├── economy/           # Per-faction treasury
├── zones.json
├── invites.json
├── join_requests.json
└── .version           # Data layout version (1)
  • ZIP backup created before migration for safe rollback
  • data/.version marker written last — crash before marker = re-run on next startup
  • Fresh installs skip migration and create data/ directly

Safe-Save Hardening

  • All storage types now use StorageUtils.writeAtomic() (economy, invites, join requests upgraded from direct writes)
  • .bak files cleaned up after successful atomic writes — no more indefinite accumulation
  • Backup system now includes chat, economy, invites, join requests in ZIP archives
  • Per-UUID locking in JsonPlayerStorage — all writes to the same player file serialized via ReentrantLock
  • Windows file contention resiliencewriteAtomic() retries ATOMIC_MOVE 3× with 50/100/150ms backoff, then falls back to non-atomic move

Refactoring

  • Treasury BigDecimal refactor — All economy values converted from double to BigDecimal (~21 files) for currency precision
  • 22 dead methods removed — Unused backward-compat accessor/builder methods in FactionPermissions
  • CoreConfig deprecated — Replaced by FactionsConfig and ServerConfig
  • Logs viewer fix — Crash from #Title.Text selector targeting Group instead of Label; "View All" button enabled on dashboard
  • PlayerDeathSystem cleanup — 5 identical copy-pasted load-increment-save blocks replaced with single trackKillDeath() helper
  • Admin zone flags layout — Restructured from 2-column (16/20) to 3 balanced columns (12/13/11) grouped thematically

Closes

Fixes #59, fixes #61, fixes #62, fixes #65, fixes #66, fixes #67, fixes #68, fixes #69, fixes #71, fixes #72

Test Plan

Core Features

  • Build and deploy: ./gradlew :HyperFactions:shadowJar
  • Verify existing functionality unaffected (create faction, claim, PvP, zones)

Data & Config Migration

  • Data migration: all files moved from root → data/, .version = 1, backup created
  • Data migration: upgrade from pre-v0.10.0 with data files at root level
  • Config migration: old config.json splits correctly via V5→V6
  • Safe-save: .bak files don't accumulate after saves
  • BigDecimal: treasury operations (deposit, withdraw, transfer) with precise amounts

GUI & Leaderboard

  • Leaderboard: /f leaderboard, /f top, all sort modes and pagination
  • K/D leaderboard: defaults to K/D sort, displays faction aggregate ratios
  • Activity log: /f logs nav bar entry, /f admin log with filters
  • Admin actions: Actions page, two-step global K/D reset
  • Admin player info: /f admin who <player> with membership history and View Faction button
  • Admin faction info: two-column layout, disband button works
  • Admin commands: /f admin info <faction> and /f admin who <player> open correct GUIs

Issue Verification

Protection

  • Capture crate entity pickup: DENY in territory, ALLOW in wilderness
  • Capture crate placement: DENY in territory, ALLOW in wilderness
  • NPC F-key tame: DENY in territory, ALLOW in wilderness
  • CrateUse, NpcTame faction permission flags — per-role configurable via /f perm
  • faction-permissions.json auto-generates with new flags

Roles & Config

  • Configurable roles: edit config/factions.json, /f admin reload, verify GUIs/commands/placeholders

Race Conditions

  • Kill/death race condition: rapid kills → all counted in /f who
  • Power regen vs kill/death: regen timer doesn't overwrite kill/death increments

Clean up orphaned temp/backup files before creating backup ZIP.
Skip .tmp and .bak files in addDirectoryToZip visitor.
Delete incomplete ZIP on backup failure.
Zone lookup exception in catch block now returns early (fail-safe)
instead of falling through to apply power loss. Log at WARN level.
Add adminBypassEnabled field to PlayerData with JSON serialization.
toggleAdminBypass now saves to player data file.
On connect, restore bypass if saved and player still has admin perm.
Clear stale bypass flag if player lost admin permission.
Add allowExplosionsInClaims config option (default false). When enabled,
explosions are permitted in faction-claimed chunks (not zones). Full
per-relation support deferred to HyperProtect-Mixin update.
Add color_legacy, name_colored, tag_colored, name_colored_legacy, and
tag_colored_legacy placeholders to both expansions. Implement PAPI
Relational interface for rel_factions_relation and rel_factions_relation_color.
Add hexToNearestLegacyCode utility with exact match and Euclidean RGB
distance fallback.
Add hardcoreMode config option. When enabled, faction power uses a
shared pool instead of individual player power. Death subtracts from
the faction pool (no floor), kills add to it, and regen applies to
the pool directly. Persisted in data/hardcore_power.json.
Add /f leaderboard (alias /f top) command and GUI page with ranked
faction listing. Sort modes: Power, Territory, Balance, Members.
Includes nav bar integration for both faction and new player views.
Replace all double-precision floating point with BigDecimal across 23
economy files for currency precision. Uses string constructor, scale 2,
HALF_UP rounding. Backward-compatible JSON deserialization handles both
old double and new string formats.
Add treasury_balance, treasury_balance_raw, treasury_autopay, and
treasury_limit placeholders to both HyperFactionsExpansion (PAPI)
and WiFlowExpansion. Uses BigDecimal formatting from EconomyManager.
Wire LogsViewerPage into faction nav bar with /f logs command.
Add AdminActivityLogPage for server-wide log aggregation with
type, time, and player filters.
Add WorldsConfig module (config/worlds.json) for configuring per-world
behavior: claiming, power loss, faction/ally friendly fire. Supports
wildcard patterns (% matches any sequence) with priority resolution.

Integrates with ClaimManager (claiming), PlayerDeathSystem (power loss),
and ProtectionChecker (friendly fire). Admin commands: /f admin world
list|info|set|reset. Legacy whitelist/blacklist in CoreConfig still
works as fallback when worlds module is disabled.
Add comprehensive changelog entry covering all 10 issues, BigDecimal
refactor, and per-world settings. Update README feature tables with new
capabilities: per-world settings, hardcore mode, leaderboard, expanded
placeholders.
Fix #Title.Text selector crash on logs page — #Title is a $C.@container
slot (Group), not a Label. Added #LogsTitle ID to the $C.@title template
and target that instead. Enable the View All button in the dashboard
activity feed to navigate to the logs viewer page.
…cersCanEdit accessors

Remove 12 unused accessor methods (memberBreak, memberPlace, memberInteract,
officerBreak, officerPlace, officerInteract, allyBreak, allyPlace, allyInteract,
outsiderBreak, outsiderPlace, outsiderInteract) and 10 unused builder methods
(withOutsiderBreak/Place/Interact, withAllyBreak/Place/Interact,
withMemberBreak/Place/Interact, withPvpEnabled, withOfficersCanEdit) from
FactionPermissions — all verified zero callers.

Fix pvpEnabled() and officersCanEdit() to use get() instead of getRaw() for
consistent fail-closed parent-child flag resolution behavior.
Add treasuryDeposit, treasuryWithdraw, and treasuryTransfer flags to the
defaults and locks sections, nested under a "treasury" key. Enables server
admins to set default treasury permissions and lock them for all factions.

Existing getEffectiveFactionPermissions() already iterates all locks, so
treasury flags are automatically enforced without additional wiring.
Create FactionsConfig (faction gameplay: faction, power, claims, combat,
spawn protection, relations, invites, stuck) and ServerConfig (server
behavior: teleport, auto-save, messages, GUI, permissions, updates).

Add 9 new claim protection overrides to FactionsConfig: outsiderPickup,
outsiderDrop, 3-way explosions (factionless/enemy/neutral), fireSpread,
3-way outsider entity damage (factionless/enemy/neutral).

Move territoryNotificationsEnabled from CoreConfig to AnnouncementConfig.
Mark CoreConfig as @deprecated legacy fallback reader.
Re-route all ConfigManager convenience methods to new backing configs.
Legacy config.json is still loaded as fallback if present.
Extract faction/server settings from monolithic config.json into
config/factions.json + config/server.json. Transform allowExplosionsInClaims
into 3 granular flags (factionless/enemy/neutral). Add 6 new claim
protection settings with behavior-preserving defaults. Move
territoryNotifications into config/announcements.json.

Delete config.json after extraction — configVersion now lives in
config/server.json. All data extracted before deletion, auto-backup
created by MigrationRunner.
shouldBlockExplosion: replace single allowExplosionsInClaims with 3-way
check (factionless/enemy/neutral). Explosion hooks lack player UUID, so
all 3 must be true to allow — documented limitation.

shouldBlockFireSpread: replace hardcoded block with configurable
fireSpreadAllowed check.

canPickupItem: replace hardcoded outsider deny with outsiderPickupAllowed
config check.

canDamagePlayerChunk: add outsider entity damage 3-way check by
relationship (factionless/enemy/neutral) to claim owner.

ItemDropProtectionSystem: add claim-based outsider drop check using
outsiderDropAllowed config (allies exempt).
…ction settings

Rewrite protection docs as 4 focused documents (claims, zones, global, systems)
with protection.md as navigation hub. Update all config references from
CoreConfig/config.json to FactionsConfig/ServerConfig. Document 9 new claim
protection settings, 3-way explosion/damage configs, V5→V6 migration, and
explosion source attribution limitation. Fix treasury GUI note, update storage
file structure, update README quick-start.
…yperProtect lifecycle

CoreConfig is null after V5→V6 migration deletes config.json, causing NPE
in initHyperProtectMixinLifecycle() and AdminUpdateHandler. All HyperProtect
config methods already exist on ServerConfig.
Add per-UUID locking to JsonPlayerStorage to serialize concurrent writes
to the same player file. The previous async load-increment-save pattern
allowed two rapid kills to both read stale data, losing an increment.
savePlayerPower (called by regen timers) could also overwrite kill/death
data via its own unsynchronized load-modify-save cycle.

- Add updatePlayerData(UUID, Consumer) to PlayerStorage for atomic
  read-modify-write with per-UUID ReentrantLock
- Extract savePlayerDataSync() to share between savePlayerData,
  savePlayerPower, and updatePlayerData
- Lock savePlayerData and savePlayerPower to prevent cross-method races
- Extract trackKillDeath() helper in PlayerDeathSystem, replacing 5
  identical copy-pasted load-increment-save blocks
Add roles section to config/factions.json allowing server owners to
customize role names (e.g. Boss/Underboss/Soldier) and short forms
(e.g. BO/UB/SO). All GUIs, commands, and log messages now use
configured display names instead of hardcoded role names.

- Add getRoleDisplayName/getRoleShortName to ConfigManager
- New placeholders: factions_role_display, factions_role_short
- Validate display names non-empty, short names ≤4 chars
- Update /who, /members, /promote, /demote, all GUI pages
- Update PAPI and WiFlow placeholder expansions
Move all data files into data/ subdirectory for cleaner organization.
DataV0ToV1Migration automatically moves factions/, players/, chat/,
economy/, zones.json, invites.json, and join_requests.json on first
startup. Creates ZIP backup before migrating for safe rollback.

- data/.version marker tracks data layout version (1)
- Fresh installs create data/ directly, no migration needed
- If crash before marker write, migration re-runs on next startup
- Register migration in MigrationRegistry
- Update HyperFactions startup to resolve data dir from marker
Upgrade economy, invites, and join request storage to use
StorageUtils.writeAtomic() for crash-safe writes with SHA-256
verification. Expand backup archives to include chat history,
economy, invites, and join requests alongside existing data.

- JsonEconomyStorage, InviteManager, JoinRequestManager now atomic
- .bak files cleaned up after successful writes
- Orphaned .tmp/.bak cleaned on startup
- BackupManager and MigrationRunner include all data/ contents
…placeholders

- config.md: add roles section with mafia theme example
- storage.md: expand safe-save mechanism, data directory migration
- placeholders.md: update tables (35→37), add role_display/role_short
- data-import.md: document DataV0ToV1Migration detection logic
- readme.md: update doc index links
- README.md: mention customizable role display names
Add 2 new per-role faction permission flags (CrateUse, NpcTame) across
all 4 relationship levels (8 flags total, 45→53). Add 3 new zone flags
(crate_pickup, crate_place, npc_tame) in Entity Interaction category
(34→37 flags). UseHook routes interaction class names to specific
InteractionType for independent protection checks. NPC handler uses
NPC_TAME type instead of generic INTERACT.
All 7 ECS protection systems now cancel events when the world name
cannot be determined or an exception occurs (previously allowed the
action silently). Denied block placements now teleport the player to
reset client-predicted ghost blocks that enabled pillar climbing.

BlockBreak/BlockPlace evaluate canInteract() once instead of twice.
Debug logging standardized with [ECS:*] and [OG:*] prefixes.
NpcInteractionProtectionHandler registered in EventRegistration.
Instance World Protection:
- Default instance-% wildcard rule blocks claiming in temp instance worlds
- /f sethome blocked in worlds where claiming is disallowed
- Automatic cleanup of stale claims/homes on startup and config reload

Zone Notification Settings:
- Per-zone notification toggle (notify on entry true/false)
- Customizable upper/lower title text overrides
- Admin commands: /f admin zone notify, /f admin zone title
- Zone info displays notification settings
- TerritoryNotifier uses Zone-aware factories for notification data
Rebalances the 36-flag zone settings page from a lopsided 2-column
layout (16 left / 20 right) to 3 balanced columns grouped thematically:
Left (Combat, Damage, Death), Middle (Building, Interaction, Entity
Interaction), Right (Transport, Items, Spawning). Container widened
from 720 to 880px and shortened from 840 to 680px.
Consolidate zone name editing, type changing, and notification settings
into a single properties page. Zone list replaces separate Rename/Type
buttons with a unified Settings button. Type change modal and flags
page now navigate back to properties when opened from that context.
ATOMIC_MOVE fails on Windows when antivirus or file indexer holds a
brief handle on the target file. StorageUtils.writeAtomic() now retries
3 times with increasing delays (50/100/150ms) before falling back to a
non-atomic move, which is still safe since the .bak backup already
exists at that point. All 8 storage callers benefit automatically.
…ard, admin info redesign

Add per-player and global K/D reset, new "Actions" admin page with two-step
confirmation, faction K/D as default leaderboard sort (cached refresh), and
admin commands `/f admin info` and `/f admin who`.

Redesign admin player info as two-column layout mirroring /f who data: first
joined, last online, faction card with View Faction button, compact membership
history, power/combat controls on right. Redesign admin faction info with
two-column layout and disband button.
Add Admin Version page to admin nav bar showing mod versions and
integration statuses (permissions, protection, placeholders, economy).
/f admin version works from both GUI (players) and console.

VaultEconomyProvider.getEconomyName() detects registered economy plugin
name via reflection (e.g. "Ecotale") for display in GUI and chat.

Fix HyperProtect version always showing "1.0.0" — HyperProtectIntegration
hardcoded the version when lazily creating the bridge. Now detects actual
version from JAR filename in earlyplugins/.
Merge [Unreleased] and old [0.10.0] sections into a single
[Unreleased] entry. Organize Added section by feature area
(Gameplay, Protection, GUI & Admin, Config & Storage,
Placeholders). Group Changed entries by theme. Version
header will be added at release time.
Bump version headers from 0.9.0 to 0.10.0 across all 18
docs files. Add new commands (leaderboard, logs, admin info/
who/version/world), config settings (hardcoreMode, K/D cache,
worlds, claim overrides), placeholders (35→49), zone flags
(37→40), per-UUID locking, and role display names. Update
README counts and JitPack version reference.
Replace duplicated 3-line input parsing pattern across 35 command files
with a single call to CommandUtil.parseRawArgs(). Removes ~70 lines of
boilerplate while preserving identical behavior.

Skipped ChatSubCommand and MoneySubCommand routing logic which
genuinely needs the parts array for command dispatch.
Create centralized UIPaths.java with 110 named constants replacing
150 hardcoded "HyperFactions/..." string literals across 70 GUI files.
Eliminates typo risk and makes path references discoverable.
Add NavEntry interface implemented by all three page registry Entry
records, and NavBarUtil with shared buildButtons() and hasPermission()
methods. Reduces duplicated loop logic across NavBarHelper,
NewPlayerNavBarHelper, and AdminNavBarHelper.
Extract 81 openXxx() methods from GuiManager (2834 lines) into three
dedicated opener classes: FactionPageOpener (35 methods),
AdminPageOpener (38 methods), NewPlayerPageOpener (8 methods).

GuiManager retains page registration, closePage, getters/setters, and
thin delegation methods that preserve the existing public API.
Add forRemoval=true to all bare @deprecated annotations with
appropriate since versions. Remove stale TODO block in
PowerSubCommand (text-only output is the permanent design).
Add FactionPageOpener, AdminPageOpener, NewPlayerPageOpener, UIPaths,
NavBarUtil, NavEntry to architecture.md and gui.md. Update GuiManager
description to reflect delegation pattern. Add WP3-WP7 refactoring
entries to CHANGELOG.
Convert all 399 source files to 2-space indentation, add Checkstyle
10.26.1 with customized Google Java Style config (warnings-only mode).

Changes applied:
- 4-space to 2-space indentation
- Google Java Style import ordering (static first, alphabetized)
- Javadoc stubs on all public methods and types
- Consistent brace placement (NeedBraces, LeftCurlyEol, RightCurly)
- Operator wrapping (trailing operators moved to next line)
- Blank line separators between declarations
- Default cases added to switch statements

Checkstyle config: 120-char line limit, star imports allowed,
relaxed Javadoc (public scope only), common abbreviations permitted.
Restructure to full-width stats row (power, combat, KDR, faction card),
move UUID into header subtitle, and split body into history + controls
columns. Add Origin enum to track navigation source so Back returns to
the correct page (players list vs faction members).
Consolidate duplicated color methods (getRoleColor, getReasonColor,
getLogTypeColor) from 8 GUI pages into a shared GuiColors utility with
semantic resolution methods. Fix 2 color inconsistencies in
AdminPlayerInfoPage (officer #87CEEB→#00AAFF, offline #FF5555→#888888).

Update CurseForge description, docs, and README with accurate v0.10.0
counts (44 commands, 64 pages, 49 placeholders, 11 config files) and
new feature sections.
…rsion detection

ConfigFile.load() now recursively compares serialized keys against disk
JSON and auto-saves when new keys are detected, fixing modules like
FactionPermissionsConfig that bypass base helpers.

Migrate old ZenithDevHQ update URL to HyperSystemsDev on load (custom
URLs preserved). Update defaults in ServerConfig and CoreConfig.

Fix HyperProtect-Mixin update checker showing v0.0.0 by detecting
version from JAR filename before branching, and setting the system
property early for AdminVersionPage.
@derrickmehaffy derrickmehaffy merged commit 8e369e8 into main Feb 27, 2026
@derrickmehaffy derrickmehaffy deleted the dev/v0.10.0 branch February 27, 2026 22:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment