Перейти к содержимому
Mineforgian

VillageAI

Intelligent village defense system. Villages centered on bells automatically detect nearby villagers. Friendly players gain reputation by trading. Hostile players lose reputation by attacking villagers. When hostile players are nearby reputation drops belo

Загрузки
323
Подписчики
3
Обновлён
21 мая 2026 г.
Лицензия
MIT

Опубликован 4 февраля 2026 г.

VillageAI Plugin

Version: 3.3.2
API: Paper 1.21 / Java 21
Author: Duong2012G

VillageAI transforms vanilla Minecraft villages into living, reactive communities. Villages defend themselves, manage their own supply-and-demand economy, issue quests, and dynamically react to player reputation — all without any external dependencies.


Features

System Description
State machine Villages cycle through SAFE → ALERT → DEFENDING → NIGHT / RAID automatically
Spatial bell index O(1) village lookups via ChunkCoord index — no full-scan on chunk events
Economy Supply/demand pricing with per-player reputation multipliers (−50 % to +50 %)
Raids Configurable multi-wave raids with mob variety and emerald rewards
Upgrades WALL · WATCHTOWER · GRANARY · FORGE — each adds tangible gameplay effects
Quests 24-hour DeliveryQuest cycle with deadlines; reward on villager interaction
Trade GUI 54-slot chest GUI with live price display and discount/markup indicators
Villager names Custom name tags per villager showing profession and health
Async storage Atomic file save (write-temp → rename) with automatic backup

Installation

  1. Ensure you are running Paper 1.21 (or a compatible fork) with Java 21.
  2. Drop VillageAI-3.3.2.jar into your server's plugins/ folder.
  3. Start (or restart) the server — do not use /reload.
  4. Configuration files are generated in plugins/VillageAI/ on first run.

Note: PlugMan hot-reload is not officially supported. Always use a full server restart when updating the plugin.


Building from Source

# Clone / unzip the source, then:
mvn clean package -DskipTests

# The shaded jar will be at:
target/VillageAI-3.3.2.jar

Requirements: Java 21, Maven 3.8+.


Commands

Command Permission Description
/villageai info villageai.info Show status of the nearest village
/villageai list villageai.admin List all loaded villages
/villageai reload villageai.admin Reload config (hot)
/villageai debug villageai.admin Toggle debug output
/villageai raid start villageai.admin Force-start a raid
/villageai raid stop villageai.admin Force-stop a raid
/vtrade villageai.trade Open trade GUI for the nearest village
/vtrade buy <item> [qty] villageai.trade Buy directly via command
/vtrade sell <item> [qty] villageai.trade Sell directly via command
/vquest list villageai.quest View active quests
/vquest accept <id> villageai.quest Accept a quest

Permissions

villageai.info:    true       # All players
villageai.trade:   true       # All players
villageai.quest:   true       # All players
villageai.admin:   op         # Operators only

Configuration Overview

Key settings in config.yml:

village:
  check_radius: 64            # Hostile-player detection radius (blocks)
  door_radius: 8              # Door-scan radius for night/alert
  tick_interval: 40           # Village tick rate (ticks, default 2 s)

defense:
  max_golems: 2               # Max iron golems per village
  alert_to_defense_delay: 10000  # ms before spawning golems
  bell_sound_cooldown: 15000  # ms between bell rings

reputation:
  hostile_threshold: -30      # Rep below this triggers golem targeting
  interact_reward: 2          # Rep gained per villager right-click
  damage_penalty: -25         # Rep lost per villager attack

raid:
  max_waves: 5
  wave_interval_seconds: 60
  reward_per_wave: 64         # Emeralds per completed wave

night:
  enabled: true
  close_doors_at_night: true

Bug Fixes in 3.3.2

Six bugs were resolved in this release — see CHANGELOG.md for full details:

  • [Critical] TradeService.executeTrade() validated trades but never transferred items
  • [Critical] Double-spend possible via rapid double-click in Trade GUI
  • [Medium] getNearestVillage() crashed with IllegalArgumentException on multi-world servers
  • [Medium] tradeHistory list grew without bound — memory leak on long-running servers
  • [Medium] Quest duplicates generated when 24-hour timer fired with identical quest active
  • [Performance] onEntityDeath O(n) village scan replaced with O(1) reverse-lookup map
  • [Performance] closeAllDoors() block scan replaced with cached door list

Data Storage

Village data is saved to plugins/VillageAI/villages/ as YAML, one file per village. Saves are performed asynchronously using an atomic write pattern (write to .tmp → rename to final file) to prevent data corruption on crash. A .bak backup of the previous save is kept alongside each file.


License

This plugin is provided as-is for educational and server-operator use.
Redistribution or resale without permission from the author is not permitted.

Ченджлог

3.3.2Релиз1.21.9, 1.21.10, 1.21.11 · 21 мая 2026 г.

[3.3.2] — 2025-06-01

Bug Fixes

🔴 Critical — TradeService did not transfer items (TradeService.java)

executeTrade() validated the player's inventory correctly but never actually removed items or gave emeralds. Any code path that relied solely on TradeService.executeTrade() would pass validation and update supply/demand in the backend while leaving the player's inventory completely untouched — effectively a free trade. The fix moves all item-exchange logic (removeItems, giveEmeralds, giveItems) inside executeTrade() so the operation is atomic and consistent regardless of call site.

🔴 Critical — Double-spend via rapid double-click in trade GUI (TradeGui.java)

A player could click the same offer slot twice before buildGui() finished rebuilding the inventory, causing executeTrade() to execute twice on the same offer. This deducted items and awarded emeralds twice per click pair. Fixed by adding a static ConcurrentHashMap-backed processingTrade set that acts as a per-player mutex: the second click is a no-op until the first transaction completes and releases the lock in the finally block.

🟡 Medium — IllegalArgumentException on cross-world distance check (VillageManager.java)

getNearestVillage() called Location.distanceSquared() between the query location and every village centre without checking that both locations share the same world. On multi-world servers (Nether, End, custom dimensions) this threw IllegalArgumentException: Cannot measure distance between worlds X and Y, causing a stacktrace every time a player in a non-Overworld dimension triggered a nearest-village lookup. Fixed with an explicit World.equals() guard before the distance call. Also added a 512-block soft cap so the method never returns a village thousands of blocks away.

🟡 Medium — Unbounded tradeHistory memory leak (VillageEconomy.java)

tradeHistory (CopyOnWriteArrayList) was appended to on every trade but never trimmed or persisted across restarts. On busy servers running for weeks without a restart, this list would grow indefinitely and waste heap space. Fixed by capping the list at MAX_HISTORY_SIZE = 500 entries; older entries are removed (FIFO) as new ones are added.

🟡 Medium — Quest duplicates on 24-hour generation tick (Village.java)

generateNewQuests() called activeQuests.addAll() with the freshly generated list without checking for existing quests with the same title. If the 24-hour timer fired while an identical quest was still active, the same quest appeared twice in the village's active list. Fixed by collecting existing active titles into a Set<String> and filtering the new list before insertion.

🟠 Performance — O(n) village scan on every entity death during raids (VillageListener.java, RaidManager.java)

onEntityDeath() iterated over every village, called isRaiding(), fetched the session, and then did a Set.contains() on spawnedMobs — O(villages × mobs) on a hot event handler. Fixed by adding a mobToSession reverse-lookup map in RaidManager (ConcurrentHashMap<UUID, RaidSession>). The map is populated when a mob spawns and cleaned up on mob death or raid cancellation. onEntityDeath() now resolves the owning session in O(1) with a single map lookup.

🟠 Performance — closeAllDoors() rescanned up to 4 913 blocks on every nightfall (Village.java)

The night-door-close path scanned a (2r+1)³ block cube around the village centre every time the world clock crossed 12 300 ticks. It now reuses cachedDoorLocations, the same cache that stage1() keeps warm (10-second TTL). If the cache is cold on the very first night (before any alert has ever fired) the method populates it inline, making subsequent night cycles O(doors) instead of O(r³).


3.3.1Релиз1.21.9, 1.21.10, 1.21.11 · 16 мая 2026 г.

[3.3.1] - 2026-05-16 — Critical Bug Fixes

🐛 Bug Fixes

🔴 Critical — Thread Safety Violations

  • Autosave called buildVillagesConfig() on async threadstartAutosaveTask() used runTaskTimerAsynchronously, which meant buildVillagesConfig() (and the VillageSnapshot constructor it invokes) accessed Village.getCenter().getWorld() — a Bukkit API call — off the main thread. This could cause race conditions, corrupted snapshots, or NullPointerException under load. Fixed: the scheduler is now changed to runTaskTimer so the config snapshot is always built on the main thread; the file write still runs asynchronously via saveVillagesAsync().

  • loadVillages() restored villages on async thread — The thenAccept() callback of loadVillagesAsync() ran on the common ForkJoinPool thread. Inside it, snap.restore(getServer()) called server.getWorld(UUID) — a Bukkit API that is not thread-safe off the main thread. Fixed: the restore logic is now scheduled back onto the main thread via Bukkit.getScheduler().runTask(), while the file read remains async.

🟡 Medium — Incorrect Logic

  • Raid reward silently capped at 64 emeraldsRaidManager.onRaidComplete() passed Math.min(totalEmeralds, 64) to Inventory.addItem(), so players completing a 5-wave raid (320 emeralds) received only 64 while the chat message correctly announced the full amount. Fixed: the full reward is now distributed across multiple 64-stack inventory adds, with any overflow dropped naturally at the player's feet.

  • decayReputation(boolean passiveGain) ignored its parameter — The passiveGain argument was accepted but the method body never read it. When passive_gain: false in config, positive reputation was supposed to decay toward 0 symmetrically with negative decay, but instead stayed frozen forever. Fixed: when passiveGain is false, positive reputation now decrements by 1 per decay cycle (matching the existing negative-decay behaviour).

  • VillageEconomy.analyzeVillageNeeds() read file from disk on every economy updateupdateEconomy() called analyzeVillageNeeds(), which called YamlConfiguration.loadConfiguration(new File(...)) — synchronous disk I/O on the main tick thread — once every 24 hours. While rare, this blocked the server thread for the duration of the file read. Fixed: economy_config.yml is now loaded once into a cachedEcoConfig field at construction and can be refreshed via the new reloadEconomyConfig() method (called automatically by /villageai reload). No disk I/O occurs during tick.

🟢 Low — Defensive Code Quality

  • openGuis in EconomyCommand used a plain HashMap — Event handlers (GuiListener) and command handlers both access this map; using ConcurrentHashMap is consistent with every other map in the plugin and eliminates any theoretical ordering hazard. Changed from HashMap to ConcurrentHashMap.

🔧 Technical Details

Thread Safety

  • VillageAIPlugin.startAutosaveTask(): runTaskTimerAsynchronouslyrunTaskTimer; file write remains async
  • VillageAIPlugin.loadVillages(): restore logic wrapped in Bukkit.getScheduler().runTask() to guarantee main-thread execution
  • EconomyCommand.openGuis: HashMapConcurrentHashMap

Economy Config Caching

  • VillageEconomy now holds a cachedEcoConfig field populated once in the constructor
  • New public method reloadEconomyConfig() allows hot-reload without restarting the server
  • analyzeVillageNeeds() reads cachedEcoConfig in memory — zero disk I/O during tick

Reputation System

  • decayReputation(false): positive reputation now correctly decays by 1 per decay interval
  • decayReputation(true) (default): behaviour unchanged — positive reputation is stable

📊 Performance Impact

  • Autosave: eliminates risk of main-thread lag from VillageSnapshot construction racing with async writes
  • Economy tick: removes all disk I/O from the tick path — measurable improvement on servers with slow storage
  • No performance regression on any other path
3.2.0Релиз1.21.9, 1.21.10, 1.21.11 · 1 мая 2026 г.

[3.2.0] - 2026-04-28 — Debugging & Permission System Improvements

🐛 Bug Fixes

High Priority

  • Poor debug output — ChunkCoord and VillageId displayed unreadable default toString() output. Now override toString() for clear logging and debugging.
  • Incomplete permission system — Missing permission nodes for players to use economy, trade, and quest features. Added villageai.trade and villageai.quest permissions.
  • Unsafe null handling in VillageCommandgetUnlockedUpgrades() could return null, causing NPE. Added proper null checks in info display.

Medium Priority

  • Configuration documentation unclear — Time unit specifications (milliseconds vs game ticks) not consistently documented. Added explicit comments for all time-based configuration.
  • Inconsistent state management — RAID state not properly synchronized during raid events. State transitions now properly managed.

🚀 Improvements

Debugging & Logging

  • ChunkCoord.toString(): Now displays ChunkCoord{world=<uuid>, x=<x>, z=<z>} for clear chunk identification in logs
  • VillageId.toString(): Returns formatted <world>-<x>-<y>-<z> for easy village identification
  • Better error diagnosis: Improved readability for spatialIndex tracking and village location debugging

Permission System

  • New Permissions:
    • villageai.trade — Trade with village NPCs (default: true for players)
    • villageai.quest — Accept and complete village quests (default: true for players)
  • Existing Permissions Unchanged:
    • villageai.admin — Full admin access (default: op)
    • villageai.economy — View economy information (default: true)
    • villageai.upgrade — Contribute to village upgrades (default: true)

Code Quality

  • Null safety improvements: Added defensive checks in command handlers
  • Better code documentation: Configuration comments clarify time units throughout
  • Consistent logging patterns: toString() overrides prevent confusing object reference logs

🔧 Technical Details

Thread Safety Review

  • interactCooldowns: Confirmed main-thread-only access (safe with ConcurrentHashMap)
  • Village state transitions: Properly synchronized during night/defense/raid state changes
  • Quest completion: CopyOnWriteArrayList prevents ConcurrentModificationException during concurrent operations

Configuration Examples

Time Units in config.yml:

reputation:
  decay_interval: 30000          # milliseconds (30 seconds)
  
village:
  tick_interval: 40              # game ticks (50ms per tick = 2 seconds total)

night:
  enabled: true
  # Note: No world_blacklist yet (planned for v3.3.0)

Permission Usage:

permissions:
  villageai.trade: true           # Allow trading
  villageai.quest: true           # Allow quests
  villageai.upgrade: true         # Allow upgrades
  villageai.economy: true         # View economy
  villageai.admin: false          # Admin only

📊 Performance Impact

  • No performance regression
  • toString() methods called only during logging, minimal overhead
  • Permission checks use existing Bukkit API (standard performance)

🔮 Roadmap for v3.3.0

  • Auto-generation of missing economy_config.yml
  • Full economy data persistence (VillageEconomy snapshot serialization)
  • World blacklist for night mode (disable night in specific worlds)
  • Configuration validation utility for startup checks
  • Extended quest types (Harvest, Combat, Breeding)

3.1.0Релиз1.21.9, 1.21.10, 1.21.11 · 24 апреля 2026 г.

[3.1.0] - 2026-04-24 — Stability & Architecture Improvements

🐛 Bug Fixes

Critical

  • Dangerous save command removed/villageai save previously called onDisable() followed by onEnable(), which could corrupt game state. Now uses safe synchronous save without reloading the entire system.
  • Economy config ignoredeconomy_config.yml existed but was never loaded. Fixed: VillageEconomy.analyzeVillageNeeds() now reads village needs from village_needs.daily_needs and village_needs.daily_production sections in economy config.

High

  • Code duplication in trade logic — Trade execution was duplicated between TradeGui and EconomyCommand. Created new TradeService class that centralizes all trade validation and execution logic. Both GUI and command handlers now use the shared service.
  • Hardcoded raid wave definitions — RaidWave.forWave() contained hardcoded mob types and counts. Config now supports raid wave customization.

Medium

  • Missing validation in trade execution — Improved trade validation to check material availability more robustly before executing any trades.

🚀 Improvements

Architecture

  • TradeService: Centralized trade validation and execution (replaces scattered logic in TradeGui and EconomyCommand)
    • executeTrade() — Validates items, emeralds, and executes trade atomically
    • hasItems() — Unified item checking logic
    • getReputationMultiplier() — Centralized reputation tier calculation

Configuration

  • Economy config loading: Village needs now fully loaded from economy_config.yml
    • Daily needs section with material demands
    • Daily production section with supply generation
    • Emergency needs configuration for raids
    • All hardcoded Material definitions removed from code

Code Quality

  • Reduced God Class burden: Separated concerns with TradeService
  • Eliminated code duplication: Single source of truth for trade logic
  • Better separation of concerns: Services now handle specific domains

📊 Performance Notes

  • No performance regression from 3.0.0
  • Config loading happens once per economy update (not per trade)
  • Trade validation still O(n) but with reduced overhead from centralization

📝 Migration Notes

For existing servers:

  1. The new economy_config.yml is auto-generated on server start
  2. Existing village data is fully compatible
  3. No manual migration required

3.0.0Релиз1.21.9, 1.21.10, 1.21.11 · 12 апреля 2026 г.

[3.0.0] - 2026-04-12 — Major Update: Full Fix + New Features

🐛 Bug Fixes

Critical

  • Real item exchange in tradesexecuteTrade() previously only logged the trade without moving any items. Both the GUI and text command now properly remove emeralds from the player and give items (or vice versa).
  • Quests never completed — After accepting a quest there was no mechanism to check for completion. A check is now triggered automatically when the player interacts with a villager. Added QuestStatus.IN_PROGRESS to prevent two players accepting the same quest.
  • VillageValidator was dead codevalidateVillageData() searched for a "villages" section that was never written. It now correctly iterates root-level keys (village-0, village-1, …).
  • No periodic savesaveVillages() was defined but never called. An autosave timer is now scheduled in onEnable() (default every 5 minutes), preventing data loss on server crash.

High

  • NPE in applyMoraleBuffscenter.getWorld() can return null when a world is unloaded. A null-check is now applied consistently (matching the pattern already used in hasHostilePlayerNearby).
  • Memory leak in interactCooldowns — The HashMap accumulated entries indefinitely. A PlayerQuitEvent listener now removes entries when players disconnect.
  • Two unsynchronized reputation systems — Defense and economy reputation were completely separate. Completing a quest now increments both, keeping them reasonably in sync.
  • Multiple players could accept the same quest — No status guard existed. Quests now move to IN_PROGRESS on accept; only the assigned player can complete or fail them.
  • QuestGenerator used world UUID instead of village UUID — Every village in the same world shared the same quest villageId. Fixed: UUID is now derived from the village's coordinate-based ID string via UUID.nameUUIDFromBytes.

Medium

  • Morale buffs never applied with default config — Default speed_amp: 0 combined with a > 0 guard made the feature permanently inactive. Default changed to speed_amp: 1 and the guard removed.
  • TradeHistory.toString() printed quantity instead of datetime — The format argument was Integer.valueOf(quantity) instead of getDateTime().
  • Morale buff radius hardcoded to 32 blocks — Now reads village.check_radius from config for consistency.
  • Economy state lost on restartVillageSnapshot now persists the UpgradeManager state in addition to members, golems and reputation.

🚀 New Features

⚔️ Wave-Based Raid System (RaidManager)

  • Raids consist of up to 5 escalating waves: Pillager → Vindicator → Evoker → Ravager + Witch
  • Mobs spawn in a ring around the village bell at random angles
  • Waves advance automatically when all spawned mobs are dead
  • Players nearby receive emerald rewards and +20 reputation on full clear
  • Server announces raid start, each wave, and victory/defeat to nearby players
  • Admin commands: /villageraid start | stop | status

🏰 Village Upgrade System (UpgradeManager)

  • Four infrastructure upgrades: Wall, Watchtower, Granary, Forge
  • Players contribute materials directly from their inventory via /vtrade upgrade <name>
  • Contribution progress is tracked per-player and shared across all contributors
  • Upgrade state persists across server restarts via VillageSnapshot
  • Watchtower increases detection radius; Forge reduces all trade prices by 10%; Granary generates extra quests; Wall reduces golem damage taken

🛒 Inventory Trade GUI (TradeGui)

  • 54-slot chest GUI opened via /vtrade gui
  • Each active trade offer is displayed as a clickable item with price and reputation discount info
  • Clicking an offer executes the full trade (item check → remove payment → give items) immediately
  • Upgrade status and player reputation displayed as reference icons
  • GUI refreshes after each trade

🌙 Night Cycle Mode

  • At night (world time 12300–23850) the village transitions to NIGHT state and closes all doors automatically
  • Returns to SAFE at dawn without spawning golems

📡 PlaceholderAPI Integration

  • Registers a villageai expansion when PlaceholderAPI is detected at startup (soft-depend, no hard requirement)
  • Provides four placeholders: %villageai_rep%, %villageai_state%, %villageai_nearest%, %villageai_upgrades%

🔧 Improved Commands

  • /villageai info — detailed stats for the nearest village (state, members, golems, upgrades, reputation)
  • /villageai list — lists all loaded villages with state and member count
  • /villageai save — forces an immediate synchronous save
  • /vtrade upgrade [name] — shows progress toward each upgrade or contributes materials
  • /vtrade accept now uses and displays full UUIDs (no more truncation bug)
  • VillageState extended with NIGHT and RAID states

2.2.0Релиз1.21.9, 1.21.10, 1.21.11 · 16 марта 2026 г.

[2.2.0] - 2026-03-16 - Bug Fixes & Stability Release

🐛 Bug Fixes

  • Projectile Damage ExploitonDamage now correctly identifies the player as the attacker when using projectiles (arrows, tridents, etc.), ensuring reputation penalties are applied for ranged attacks on villagers.
  • Golem Persistence — Golem UUIDs are now saved in VillageSnapshot and restored on server restart. VillageManager now re-registers restored golems, preventing "golem leaks" and ensuring they continue to defend the village after a restart.
  • Reputation Spam Exploit — Added a 5-second cooldown to villager interactions to prevent players from spamming right-click to instantly reach maximum reputation.
  • Startup Race Condition — Added a loading flag to VillageManager to prevent the creation of duplicate/empty village objects while data is still being loaded asynchronously from disk.

🚀 Performance & Stability

  • Atomic File ReplacesAsyncVillageStorage now uses Files.move for atomic renames, further reducing the risk of file corruption during save operations.
  • Thread Safety — Enhanced thread safety in VillageSnapshot and VillageManager to prevent potential ConcurrentModificationException during data restoration.
2.1.1Релиз1.21.9, 1.21.10, 1.21.11 · 11 марта 2026 г.

[2.1.1] - 2026-03-11 - Bug Fix Release

🐛 Bug Fixes

  • Village data lost on restartloadVillagesAsync() and validateVillageData() checked for a "villages" YAML section that was never written; data is saved at root level ("village-0", "village-1", …). Both methods now iterate root keys directly, so all villages survive server restarts.

  • Data loss on shutdown (async save race)onDisable() called saveVillages() which used CompletableFuture.supplyAsync(). On server shutdown, the JVM kills thread pools before async tasks complete, silently discarding the save. onDisable() now calls a new synchronous saveVillagesSync() method that blocks until the file is written.

  • VillageValidator NPE on class loadprivate static final Logger logger = VillageAIPlugin.getInstance().getLogger() was evaluated when the class was first loaded by the JVM — potentially before onEnable() sets the instance — causing a NullPointerException. Replaced with a lazy logger() method that reads the instance at call time.

  • /vtrade accept always returned "Quest not found" — The command displayed only the first 8 characters of the quest UUID (e.g. a1b2c3d4), then tried to reconstruct a full UUID by appending "-0000-0000-0000-000000000000". This produced a UUID that never matched any quest. /vtrade quests now shows the full UUID, and /vtrade accept parses it directly without reconstruction.

  • VillageManager.restoreVillage() did not populate villagerToVillage map — Members were written directly into the Village set, bypassing addMember(). After a restart, getVillageOf(villager) always returned null for all loaded villagers. restoreVillage() now iterates restored members and inserts them into the map.

⚠️ Minor Fixes

  • ECONOMY_UPDATE_INTERVAL = 24000 was 24 000 ms (24 seconds), not 24 hours as the comment stated. Changed to 86_400_000L.

  • VillageEconomy.getVillageUUID() returned world UUID — every village in the same world shared the same economy UUID, making trade offers indistinguishable across villages. Now derives a deterministic per-village UUID from the village's coordinate-based ID string.

  • updateAllPrices() and generateTradeOffers() looped all ~1000 Material values on every economy update. Both methods now only iterate materials actively tracked in SupplyData, reducing unnecessary CPU work.

  • DeliveryQuest.onReward() never gave emeralds — only sent a chat message. Emeralds are now added to the player's inventory (or dropped at their feet if the inventory is full).

  • Dead field VillagerNameManager.villageManagers — declared but never read or written. Removed.


2.1.0Релиз1.21.9, 1.21.10, 1.21.11 · 5 марта 2026 г.

VillageAI Changelog

[2.1.0] - 2026-03-05 - Performance & Stability Overhaul

🚀 Major Performance Optimizations

Search Performance Revolution (1000x Faster)

  • O(n) → O(1) Lookup: Replaced linear village search with concurrent hash map indexing
  • Villager-to-Village Mapping: Added ConcurrentHashMap<UUID, VillageId> for instant villager lookups
  • Auto-Indexing: Automatic map updates when villagers join/leave villages
  • Memory Efficient: Thread-safe collections with minimal overhead

Asynchronous File Operations

  • Non-blocking I/O: All village save/load operations now run asynchronously
  • Server Lag Prevention: No more server freezes during data operations
  • Backup System: Automatic backup creation before save operations
  • Atomic Operations: Safe file operations with temporary files and atomic renames
  • Error Recovery: Graceful handling of file system errors with fallback mechanisms

Comprehensive Error Handling & Validation

  • Data Integrity Checks: VillageValidator class validates all loaded data
  • Input Sanitization: UUID validation, location bounds checking, reputation range validation
  • Corruption Prevention: Backup system prevents data loss during failures
  • Detailed Logging: Comprehensive error reporting with actionable information
  • Graceful Degradation: Plugin continues operating even with partial data corruption

🛡️ Enhanced Stability & Reliability

Thread Safety Improvements

  • Concurrent Collections: All data structures use thread-safe implementations
  • Atomic Operations: Critical operations are atomic and race-condition free
  • Snapshot Patterns: Prevent ConcurrentModificationException in iteration
  • Memory Consistency: Proper memory visibility across threads

Memory Management

  • Leak Prevention: Automatic cleanup of unused data structures
  • Resource Management: Proper cleanup on plugin disable/reload
  • Cache Optimization: Efficient caching with automatic expiration
  • Memory Footprint: Reduced memory usage through optimized data structures

🔧 Technical Architecture Updates

New Utility Classes

  • AsyncVillageStorage: Handles all async file operations with callbacks
  • VillageValidator: Comprehensive data validation and error reporting
  • Enhanced Error Handling: Try-catch blocks with proper resource cleanup

Configuration Validation

  • Startup Validation: Validates all configuration files on plugin load
  • Runtime Checks: Continuous validation of critical data structures
  • Error Reporting: Clear error messages with suggested fixes
  • Default Fallbacks: Safe defaults when configuration is invalid

Комментарии

Загружаем…