diff --git a/.github/workflows/check-translations.yml b/.github/workflows/check-translations.yml new file mode 100644 index 00000000..a68d7b93 --- /dev/null +++ b/.github/workflows/check-translations.yml @@ -0,0 +1,171 @@ +name: Check Translations + +on: + pull_request: + paths: + - 'src/main/resources/Server/Languages/**' + +jobs: + check-lang-keys: + name: Verify .lang keys + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Check for missing translation keys + run: | + LANG_DIR="src/main/resources/Server/Languages" + EN_DIR="$LANG_DIR/en-US" + EXIT_CODE=0 + TOTAL_MISSING=0 + + if [ ! -d "$EN_DIR" ]; then + echo "::error::No en-US directory found at $EN_DIR" + exit 1 + fi + + # Collect en-US keys per file + for en_file in "$EN_DIR"/*.lang; do + [ -f "$en_file" ] || continue + filename=$(basename "$en_file") + + # Extract keys (non-blank, non-comment lines before '=') + en_keys=$(grep -v '^\s*#' "$en_file" | grep -v '^\s*$' | sed 's/=.*//' | sed 's/\s*$//' | sort) + en_count=$(echo "$en_keys" | wc -l) + + # Check each locale + for locale_dir in "$LANG_DIR"/*/; do + locale=$(basename "$locale_dir") + [ "$locale" = "en-US" ] && continue + + locale_file="$locale_dir/$filename" + + if [ ! -f "$locale_file" ]; then + echo "::error file=$locale_file::[$locale] MISSING FILE: $filename ($en_count keys)" + TOTAL_MISSING=$((TOTAL_MISSING + en_count)) + EXIT_CODE=1 + continue + fi + + # Extract locale keys + locale_keys=$(grep -v '^\s*#' "$locale_file" | grep -v '^\s*$' | sed 's/=.*//' | sed 's/\s*$//' | sort) + + # Find missing keys + missing=$(comm -23 <(echo "$en_keys") <(echo "$locale_keys")) + + if [ -n "$missing" ]; then + count=$(echo "$missing" | wc -l) + echo "::warning file=$locale_file::[$locale] $filename: $count missing key(s)" + echo "$missing" | while read -r key; do + echo " - $key" + done + TOTAL_MISSING=$((TOTAL_MISSING + count)) + EXIT_CODE=1 + fi + + # Find extra keys (in locale but not in en-US) + extra=$(comm -13 <(echo "$en_keys") <(echo "$locale_keys")) + if [ -n "$extra" ]; then + extra_count=$(echo "$extra" | wc -l) + echo "::notice file=$locale_file::[$locale] $filename: $extra_count extra key(s) not in en-US" + fi + done + done + + echo "" + if [ $TOTAL_MISSING -gt 0 ]; then + echo "::error::Total missing keys across all locales: $TOTAL_MISSING" + else + echo "All locales have complete .lang key coverage." + fi + + exit $EXIT_CODE + + check-help-files: + name: Verify help files + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Check for missing help files + run: | + LANG_DIR="src/main/resources/Server/Languages" + EN_HELP="$LANG_DIR/en-US/help" + EXIT_CODE=0 + TOTAL_MISSING=0 + + if [ ! -d "$EN_HELP" ]; then + echo "::error::No en-US/help directory found at $EN_HELP" + exit 1 + fi + + # Collect all en-US help file relative paths + en_files=$(cd "$EN_HELP" && find . -name "*.md" -type f | sort) + en_count=$(echo "$en_files" | wc -l) + echo "Found $en_count help files in en-US" + + # Check each locale + for locale_dir in "$LANG_DIR"/*/; do + locale=$(basename "$locale_dir") + [ "$locale" = "en-US" ] && continue + + locale_help="$locale_dir/help" + + if [ ! -d "$locale_help" ]; then + echo "::error file=$locale_help::[$locale] MISSING help/ directory ($en_count files)" + TOTAL_MISSING=$((TOTAL_MISSING + en_count)) + EXIT_CODE=1 + continue + fi + + # Check each en-US help file exists in locale + missing_files="" + missing_count=0 + while IFS= read -r relpath; do + locale_file="$locale_help/$relpath" + if [ ! -f "$locale_file" ]; then + missing_files="$missing_files - $relpath"$'\n' + missing_count=$((missing_count + 1)) + fi + done <<< "$en_files" + + if [ $missing_count -gt 0 ]; then + echo "::error file=$locale_help::[$locale] $missing_count missing help file(s)" + echo "$missing_files" + TOTAL_MISSING=$((TOTAL_MISSING + missing_count)) + EXIT_CODE=1 + fi + + # Check for untranslated files (identical to en-US) + untranslated=0 + while IFS= read -r relpath; do + locale_file="$locale_help/$relpath" + en_file="$EN_HELP/$relpath" + if [ -f "$locale_file" ] && cmp -s "$en_file" "$locale_file"; then + untranslated=$((untranslated + 1)) + fi + done <<< "$en_files" + + if [ $untranslated -gt 0 ]; then + echo "::warning file=$locale_help::[$locale] $untranslated help file(s) identical to en-US (possibly untranslated)" + fi + + # Check for extra files not in en-US + if [ -d "$locale_help" ]; then + locale_files=$(cd "$locale_help" && find . -name "*.md" -type f | sort) + extra=$(comm -13 <(echo "$en_files") <(echo "$locale_files")) + if [ -n "$extra" ]; then + extra_count=$(echo "$extra" | wc -l) + echo "::notice file=$locale_help::[$locale] $extra_count extra help file(s) not in en-US" + fi + fi + done + + echo "" + if [ $TOTAL_MISSING -gt 0 ]; then + echo "::error::Total missing help files across all locales: $TOTAL_MISSING" + else + echo "All locales have complete help file coverage." + fi + + exit $EXIT_CODE diff --git a/.gitignore b/.gitignore index 7d74e39a..af0c00dc 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .gradle/ build/ !gradle/wrapper/gradle-wrapper.jar +!src/main/java/com/hyperfactions/build/ # IDE .idea/ diff --git a/CHANGELOG.md b/CHANGELOG.md index cecc9d63..2a6e02b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,127 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +**Admin GUI: Runtime Config Editor ([#40](https://github.com/HyperSystems-Development/HyperFactions/issues/40))** +- 11-tab config editor covering all HyperFactions settings: Server, Chat, Announcements, Economy, Factions, Faction Perms, Worldmap, Worlds, Backup, Debug, Gravestones +- Size-adaptive layouts: narrow (520px, 1-col), standard (780px, 2-col), wide (1020px, 4-col) — template switches automatically per tab +- Inline editing with boolean toggles, integer/double steppers, text fields, color pickers, enum dropdowns, and locale selectors +- Faction permissions editor with parent/child toggling (disabling parent auto-disables children), Default/Lock checkboxes per flag +- World overrides editor with add/remove worlds and tri-state per-world settings (Default/Allow/Deny) +- Upkeep scaling tiers modal with add/remove/reorder tiers, promote/demote disable on first/last, and live cost example +- Edit session caching — pending changes survive page close/reopen and modal round-trips +- Input validation with per-field error highlighting, debounced text updates, and save-blocked-on-invalid state +- Per-tab label fixes: "Requires Faction", "Show to Factionless", shortened section names +- ConfigSnapshot for applying changes, ConfigValidator for input bounds, ConfigV7→V8 migration + +**Admin GUI: Backup Manager ([#41](https://github.com/HyperSystems-Development/HyperFactions/issues/41))** +- Paginated backup list with expand/collapse detail view per entry +- Create manual backups with optional custom name +- Restore backups with two-click confirmation and automatic safety backup +- Delete backups with two-click confirmation +- Backup type filter dropdown (All / Hourly / Daily / Weekly / Manual / Migration) + +**Admin GUI: Updates Page ([#42](https://github.com/HyperSystems-Development/HyperFactions/issues/42))** +- Two-column layout: HyperFactions (left) and HyperProtect Mixin (right) with mirrored version info +- Shows current version, latest version, channel, build date, and update status for both +- 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 +- 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 + - `CommandKeys.java` — all player command message keys (create, disband, rename, claim, invite, etc.) + - `HelpKeys.java` — help system message keys (166 constants) + - `AdminKeys.java` — admin command responses and navigation labels + - `GuiKeys.java` — faction and shared GUI page keys + - `AdminGuiKeys.java` — admin GUI page keys (613 constants) +- Deleted original `MessageKeys.java`; updated imports across 130+ files + +**Localize Remaining Hardcoded Strings** +- Territory display banners (Wilderness, SafeZone, WarZone titles and subtitles) — now localized per-player via `TerritoryInfo.getPrimaryText(PlayerRef)` and `getSecondaryText(PlayerRef)` +- Update notification messages — "new version available", version info, and update instructions now localized +- Player death broadcast location — `"{0} died at ({1}, {2}, {3}) in {4}"` now localized +- ~70 admin handler strings localized across `AdminUpdateHandler`, `AdminZoneHandler`, `AdminMapDecayHandler`, and `AdminDebugHandler` — covers update/mixin/rollback flow, zone display, decay status, and debug headers + +**New Translation Entries** +- Added ~467 new entries per locale file across all 10 supported languages (en-US, de-DE, es-ES, fr-FR, it-IT, nl-NL, pl-PL, pt-BR, ru-RU, tl-PH) +- Covers all split key files (help commands, GUI labels, admin GUI) plus newly localized strings + +**API Expansion ([#106](https://github.com/HyperSystems-Development/HyperFactions/issues/106))** +- Comprehensive event system: 20 post-events and 11 cancellable pre-events covering all major faction operations +- `Cancellable` interface for pre-events with `setCancelReason()` for custom denial messages +- Language/i18n API methods: `setPlayerLanguage()`, `getPlayerLanguage()`, `getSupportedLocales()` +- Chat color customization API: `setChatColor()`, `setChatColors()`, `getChatColors()` +- Manager accessor methods: `getChatManager()`, `getEconomyAPI()`, `getJoinRequestManager()` +- Extended query methods: `getFactionPowerStats()`, `getFactionClaimCount()`, `getFactionCount()`, `isFactionRaidable()`, `getPlayerRelation()` +- Config persistence API: `ConfigManager.saveConfig()` and `ConfigManager.reloadConfig()` + +**HyperEssentials Integration APIs ([#107](https://github.com/HyperSystems-Development/HyperFactions/issues/107))** +- New API methods for essentials integration: `hasFactionHome()`, `getFactionHomeWorld()`, `getFactionHomeCoords()`, `getFactionHomeCooldownRemaining()`, `isZoneFlagAllowed()` +- `ESSENTIALS_BACK` zone flag — controls whether /back teleportation works in zones (defaults to allowed) +- `FactionHomeTeleportEvent` and `FactionHomeTeleportPreEvent` events for home teleport tracking + +**Configurable Announcement Colors** +- 7 per-event color settings in `AnnouncementConfig`: `factionCreatedColor`, `factionDisbandedColor`, `leadershipTransferColor`, `overclaimColor`, `warDeclaredColor`, `allianceFormedColor`, `allianceBrokenColor` +- Colors stored in `announcements.json` under a `"colors"` section, loaded/saved with defaults matching previous hardcoded values +- `AnnouncementManager` reads colors from config instead of using hardcoded `broadcastSuccess`/`broadcastError` calls +- Admin GUI: color picker for each event in the Announcements config tab + +**Zone & Power Query API Methods** +- `HyperFactionsAPI.getZone(world, chunkX, chunkZ)` — returns the zone at a chunk position +- `HyperFactionsAPI.getZoneByName(name)` — returns zone by name (case-insensitive) +- `HyperFactionsAPI.getAllZones()` — returns all zones as an unmodifiable collection +- `HyperFactionsAPI.getZonesByType(type)` — returns zones filtered by type (SAFE/WAR) +- `HyperFactionsAPI.isHardcoreMode()` — returns whether hardcore power mode is enabled +- `HyperFactionsAPI.getFactionHardcorePower(factionId)` — returns faction's hardcore power pool value + +**Per-World Max Claims** +- New `maxClaims` per-world setting in `worlds.json` — limits how many claims a single faction can hold in a specific world +- `null` or `0` = use global limit, `>0` = per-faction per-world hard cap +- Enforced in both `/f claim` and `/f overclaim` flows +- Admin commands: `/f admin world set maxclaims `, supports `default`/`0` to clear +- New `WORLD_MAX_CLAIMS_REACHED` claim result handled in all consumer sites (commands, GUI map, dashboard) +- Localized error messages in all 10 locales + +**World Settings API** +- `HyperFactionsAPI.registerWorldSettings(worldKey, settings)` — upsert with persistence, thread-safe +- `HyperFactionsAPI.getWorldSettings(worldName)` — resolved through wildcard pattern matching +- `HyperFactionsAPI.getConfiguredWorldSettings(worldKey)` — exact key match, no pattern resolution +- `HyperFactionsAPI.removeWorldSettings(worldKey)` — removes and persists +- `WorldSettingsResolver` made thread-safe with volatile fields and copy-on-write rebuild + +### Changed + +**Consolidate Duplicate Message Keys** +- Consolidated ~25 duplicate keys into shared `CommonKeys.Common` constants — bare `NO_PERMISSION`, `Back`, `Cancel`, `Save`, `Clear`, `N/A` duplicates replaced with single shared references +- Added `CommonKeys.Common.NO_DESCRIPTION`, `MEMBER_COUNT`, and `ECONOMY_DISABLED` shared keys, replacing 3 identical copies each +- 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..d5390d82 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` @@ -86,28 +86,25 @@ HyperFactions transforms your Hytale server into a dynamic faction-based environ | Transaction log | Implemented | | Faction upkeep system (flat/progressive tiered pricing) | Implemented | | VaultUnlocked integration | Implemented | -| Ecotale integration | [Planned #20](https://github.com/HyperSystems-Development/HyperFactions/issues/20) | ### Protection | 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 (50) | Implemented | -| Command blocking in zones | Implemented | -| Sentry error tracking | Implemented | +| Zone flags (51) | Implemented | ### GUI | 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 +117,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 @@ -140,7 +137,8 @@ HyperFactions transforms your Hytale server into a dynamic faction-based environ | OrbisGuard / OrbisGuard-Mixins | Implemented | | Gravestones | Implemented | | KyuubiSoft Core (citizen NPC protection) | Implemented | -| Sentry (error tracking) | Implemented | +| BetterMap | Implemented | +| HyperEssentials | Implemented | ### Planned Features @@ -154,10 +152,7 @@ HyperFactions transforms your Hytale server into a dynamic faction-based environ | War declarations | [Planned #37](https://github.com/HyperSystems-Development/HyperFactions/issues/37) | | Faction vaults | [Planned #35](https://github.com/HyperSystems-Development/HyperFactions/issues/35) | | 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) | -| CurseForge updates | [Planned #17](https://github.com/HyperSystems-Development/HyperFactions/issues/17) | --- @@ -168,7 +163,7 @@ HyperFactions transforms your Hytale server into a dynamic faction-based environ 3. **Configure** by editing files in `mods/com.hyperfactions_HyperFactions/config/` after first startup — `factions.json` for faction gameplay settings, `server.json` for server behavior settings 4. **Create a faction** with `/f create MyFaction` and claim territory with `/f claim` -**Recommended:** Install [HyperProtect-Mixin](https://www.curseforge.com/hytale/bootstrap/hyperprotect-mixin) in `earlyplugins/` for full protection coverage (27 hook types including teleporter/portal blocking, entity damage, capture crate/NPC protection, mount/barter/fluid/projectile control, and respawn override). +**Recommended:** Install [HyperProtect-Mixin](https://www.curseforge.com/hytale/bootstrap/hyperprotect-mixin) in `earlyplugins/` for full protection coverage (28 hook types including teleporter/portal blocking, entity damage, capture crate/NPC protection, mount/barter/fluid/projectile control, and respawn override). **Optional:** Install [HyperPerms](https://github.com/HyperSystems-Development/HyperPerms) for enhanced permission control with groups, tracks, and contextual permissions. @@ -183,7 +178,7 @@ Comprehensive developer and admin documentation is available in the [`docs/`](do | Document | Description | |----------|-------------| | [architecture.md](docs/architecture.md) | 9-layer design, package structure, dependency graph | -| [managers.md](docs/managers.md) | 15 core managers with responsibilities and lifecycles | +| [managers.md](docs/managers.md) | 16 core managers with responsibilities and lifecycles | ### Systems @@ -191,7 +186,7 @@ Comprehensive developer and admin documentation is available in the [`docs/`](do |----------|-------------| | [commands.md](docs/commands.md) | 52 subcommands across 10 categories with full syntax | | [permissions.md](docs/permissions.md) | 76 permission nodes, chain-based resolution | -| [config.md](docs/config.md) | ConfigManager, 10 config files, migration (v1-v7) | +| [config.md](docs/config.md) | ConfigManager, 11 config files, migration (v1-v8) | | [storage.md](docs/storage.md) | Interface-based storage, JSON adapters, backup system | | [gui.md](docs/gui.md) | 76 pages, 3 registries, navigation flows | | [protection.md](docs/protection.md) | ECS handlers, HyperProtect-Mixin / OrbisGuard-Mixins, zone flags | @@ -201,7 +196,7 @@ Comprehensive developer and admin documentation is available in the [`docs/`](do | Document | Description | |----------|-------------| | [api.md](docs/api.md) | HyperFactionsAPI, EconomyAPI, EventBus for third-party mods | -| [integrations.md](docs/integrations.md) | HyperPerms, LuckPerms, PAPI, WiFlow, HyperProtect-Mixin, OrbisGuard, Gravestones, KyuubiSoft | +| [integrations.md](docs/integrations.md) | HyperPerms, LuckPerms, PAPI, WiFlow, HyperProtect-Mixin, OrbisGuard, Gravestones, KyuubiSoft, BetterMap, HyperEssentials | | [placeholders.md](docs/placeholders.md) | All 49 PAPI & WiFlow placeholders with examples | ### Feature Documentation @@ -209,7 +204,9 @@ Comprehensive developer and admin documentation is available in the [`docs/`](do | Document | Description | |----------|-------------| | [announcements.md](docs/announcements.md) | Server-wide broadcasts, 7 event types | -| [data-import.md](docs/data-import.md) | ElbaphFactions/HyFactions importers, config migration | +| [data-import.md](docs/data-import.md) | ElbaphFactions/HyFactions/SimpleClaims/FactionsX importers, config migration | +| [translation-guide.md](docs/translation-guide.md) | Translation guide for adding new locales | +| [help-markdown.md](docs/help-markdown.md) | Help content markdown format | --- @@ -225,7 +222,7 @@ repositories { } dependencies { - compileOnly 'com.github.HyperSystems-Development:HyperFactions:v0.11.0' + compileOnly 'com.github.HyperSystems-Development:HyperFactions:v0.12.0' } ``` diff --git a/build.gradle b/build.gradle index 88d9feb0..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) @@ -128,6 +128,85 @@ public final class BuildInfo { } } +// Generate help .lang files from markdown sources +tasks.register('generateHelpLang', JavaExec) { + group = 'build' + description = 'Generate help .lang files from markdown sources' + dependsOn 'compileJava' + classpath = sourceSets.main.compileClasspath + files(sourceSets.main.java.classesDirectory) + mainClass = 'com.hyperfactions.build.HelpLangGenerator' + args = [ + file('src/main/resources/Server/Languages').absolutePath, + layout.buildDirectory.dir('generated/resources').get().asFile.absolutePath + ] + inputs.dir(file('src/main/resources/Server/Languages')) + outputs.dir(layout.buildDirectory.dir('generated/resources')) +} + +sourceSets.main.resources.srcDir(layout.buildDirectory.dir('generated/resources')) + +// Check translations: compare keys in en-US against other locales +tasks.register('checkTranslations') { + group = 'verification' + description = 'Report missing translation keys compared to en-US' + doLast { + def langDir = file('src/main/resources/Server/Languages') + def enDir = new File(langDir, 'en-US') + if (!enDir.exists()) { + println "No en-US directory found at ${enDir.absolutePath}" + return + } + // Collect en-US keys per file + def enKeys = [:] + enDir.listFiles({ f -> f.name.endsWith('.lang') } as FileFilter).each { f -> + def keys = [] + f.eachLine { line -> + line = line.trim() + if (line && !line.startsWith('#') && line.contains('=')) { + keys << line.substring(0, line.indexOf('=')).trim() + } + } + enKeys[f.name] = keys + } + // Check each locale + def locales = langDir.listFiles({ f -> f.isDirectory() && f.name != 'en-US' } as FileFilter) + if (!locales) { + println "No non-English locales found." + return + } + def totalMissing = 0 + locales.sort { it.name }.each { localeDir -> + def localeMissing = 0 + enKeys.each { fileName, keys -> + def localeFile = new File(localeDir, fileName) + if (!localeFile.exists()) { + println "[${localeDir.name}] MISSING FILE: ${fileName} (${keys.size()} keys)" + localeMissing += keys.size() + return + } + def localeKeys = [] + localeFile.eachLine { line -> + line = line.trim() + if (line && !line.startsWith('#') && line.contains('=')) { + localeKeys << line.substring(0, line.indexOf('=')).trim() + } + } + def missing = keys.findAll { !localeKeys.contains(it) } + if (missing) { + println "[${localeDir.name}] ${fileName}: ${missing.size()} missing keys" + missing.each { println " - ${it}" } + localeMissing += missing.size() + } + } + if (localeMissing == 0) { + println "[${localeDir.name}] All keys present" + } + totalMissing += localeMissing + } + println "\nTotal missing keys across all locales: ${totalMissing}" + } +} + // Expand version placeholder in manifest.json processResources { def ver = buildVersion @@ -192,6 +271,11 @@ javadoc { failOnError = false } +// Ensure help lang files are generated before processResources copies them +tasks.named('processResources') { + dependsOn 'generateHelpLang' +} + // Ensure build info is generated and HyperPerms shadowJar is built before compiling tasks.named('compileJava') { dependsOn 'generateBuildInfo' diff --git a/curseforge-description.html b/curseforge-description.html index b639e39b..4baacfad 100644 --- a/curseforge-description.html +++ b/curseforge-description.html @@ -5,26 +5,23 @@

⚔️HyperFactions - The Complete Fact

 

✨ Why HyperFactions?

 

-

🆕 What's New in v0.11.0

+

🆕 What's New in v0.12.0

 

🏰 Core Features

@@ -75,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

    + +

    🌍 Localization

    +

     

    🛡️ 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:

     

    🏟️ SafeZones & WarZones

    @@ -96,70 +105,70 @@

    🏟️ SafeZones & SafeZones - No PvP, no mob spawning, keep inventory on death. Perfect for spawn areas and markets.
  • 🔴 WarZones - Full PvP with no power loss on death. Ideal for arenas and events.
  • -
  • 🗺️ Visual map indicators - SafeZones appear teal, WarZones appear purple on all maps
  • -
  • 🔧 Per-flag customization - Override any default on a per-zone basis
  • -
  • 🐾 Mob spawn control - Integrated with Hytale's native spawn suppression system for reliable mob blocking
  • -
  • ✏️ Zone creation wizard - Create zones by claiming single chunks, circular radius, square radius, or using the visual map
  • +
  • Visual map indicators - SafeZones appear teal, WarZones appear purple on all maps
  • +
  • Per-flag customization - Override any default on a per-zone basis
  • +
  • Mob spawn control - Integrated with Hytale's native spawn suppression system for reliable mob blocking
  • +
  • Zone creation wizard - Create zones by claiming single chunks, circular radius, square radius, or using the visual map
  •  

    💬 Faction & Alliance Chat

     

    📢 Server-Wide Announcements

    Major faction events are broadcast to all online players with configurable toggles:

    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)

    🆕 New Player GUI

    🔐 Admin GUI (/f admin)

    🧠 Smart GUI Behavior