
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
VillageAI 3.2.0
release1 мая 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.tradeandvillageai.questpermissions. - Unsafe null handling in VillageCommand —
getUnlockedUpgrades()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)
VillageAI 3.1.0
release24 апреля 2026 г.[3.1.0] - 2026-04-24 — Stability & Architecture Improvements
🐛 Bug Fixes
Critical
- Dangerous save command removed —
/villageai savepreviously calledonDisable()followed byonEnable(), which could corrupt game state. Now uses safe synchronous save without reloading the entire system. - Economy config ignored —
economy_config.ymlexisted but was never loaded. Fixed:VillageEconomy.analyzeVillageNeeds()now reads village needs fromvillage_needs.daily_needsandvillage_needs.daily_productionsections in economy config.
High
- Code duplication in trade logic — Trade execution was duplicated between
TradeGuiandEconomyCommand. Created newTradeServiceclass 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 atomicallyhasItems()— Unified item checking logicgetReputationMultiplier()— 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:
- The new
economy_config.ymlis auto-generated on server start - Existing village data is fully compatible
- No manual migration required
VillageAI 3.0.0
release12 апреля 2026 г.[3.0.0] - 2026-04-12 — Major Update: Full Fix + New Features
🐛 Bug Fixes
Critical
- Real item exchange in trades —
executeTrade()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_PROGRESSto prevent two players accepting the same quest. - VillageValidator was dead code —
validateVillageData()searched for a"villages"section that was never written. It now correctly iterates root-level keys (village-0,village-1, …). - No periodic save —
saveVillages()was defined but never called. An autosave timer is now scheduled inonEnable()(default every 5 minutes), preventing data loss on server crash.
High
- NPE in
applyMoraleBuffs—center.getWorld()can return null when a world is unloaded. A null-check is now applied consistently (matching the pattern already used inhasHostilePlayerNearby). - Memory leak in
interactCooldowns— TheHashMapaccumulated entries indefinitely. APlayerQuitEventlistener 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_PROGRESSon accept; only the assigned player can complete or fail them. QuestGeneratorused world UUID instead of village UUID — Every village in the same world shared the same questvillageId. Fixed: UUID is now derived from the village's coordinate-based ID string viaUUID.nameUUIDFromBytes.
Medium
- Morale buffs never applied with default config — Default
speed_amp: 0combined with a> 0guard made the feature permanently inactive. Default changed tospeed_amp: 1and the guard removed. TradeHistory.toString()printed quantity instead of datetime — The format argument wasInteger.valueOf(quantity)instead ofgetDateTime().- Morale buff radius hardcoded to 32 blocks — Now reads
village.check_radiusfrom config for consistency. - Economy state lost on restart —
VillageSnapshotnow persists theUpgradeManagerstate 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
NIGHTstate and closes all doors automatically - Returns to
SAFEat dawn without spawning golems
📡 PlaceholderAPI Integration
- Registers a
villageaiexpansion 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 acceptnow uses and displays full UUIDs (no more truncation bug)VillageStateextended withNIGHTandRAIDstates
VillageAI 2.2.0
release16 марта 2026 г.[2.2.0] - 2026-03-16 - Bug Fixes & Stability Release
🐛 Bug Fixes
- Projectile Damage Exploit —
onDamagenow 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
VillageSnapshotand restored on server restart.VillageManagernow 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
loadingflag toVillageManagerto prevent the creation of duplicate/empty village objects while data is still being loaded asynchronously from disk.
🚀 Performance & Stability
- Atomic File Replaces —
AsyncVillageStoragenow usesFiles.movefor atomic renames, further reducing the risk of file corruption during save operations. - Thread Safety — Enhanced thread safety in
VillageSnapshotandVillageManagerto prevent potentialConcurrentModificationExceptionduring data restoration.
VillageAI 2.1.1
release11 марта 2026 г.[2.1.1] - 2026-03-11 - Bug Fix Release
🐛 Bug Fixes
-
Village data lost on restart —
loadVillagesAsync()andvalidateVillageData()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()calledsaveVillages()which usedCompletableFuture.supplyAsync(). On server shutdown, the JVM kills thread pools before async tasks complete, silently discarding the save.onDisable()now calls a new synchronoussaveVillagesSync()method that blocks until the file is written. -
VillageValidatorNPE on class load —private static final Logger logger = VillageAIPlugin.getInstance().getLogger()was evaluated when the class was first loaded by the JVM — potentially beforeonEnable()sets the instance — causing aNullPointerException. Replaced with a lazylogger()method that reads the instance at call time. -
/vtrade acceptalways 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 questsnow shows the full UUID, and/vtrade acceptparses it directly without reconstruction. -
VillageManager.restoreVillage()did not populatevillagerToVillagemap — Members were written directly into theVillageset, bypassingaddMember(). After a restart,getVillageOf(villager)always returnednullfor all loaded villagers.restoreVillage()now iterates restored members and inserts them into the map.
⚠️ Minor Fixes
-
ECONOMY_UPDATE_INTERVAL = 24000was 24 000 ms (24 seconds), not 24 hours as the comment stated. Changed to86_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()andgenerateTradeOffers()looped all~1000 Materialvalues on every economy update. Both methods now only iterate materials actively tracked inSupplyData, 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.
