
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
3.2.0
Compatibility
Changes
[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)
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here.
Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API.
Maven coordinates:
Version ID:
build.gradle:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
// forRepositories(fg.repository) // Uncomment when using ForgeGradle
filter {
includeGroup "maven.modrinth"
}
}
}
// Standard Gradle dependency
dependencies {
implementation "maven.modrinth:QkbM4VXn:eMDKdnq3"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:QkbM4VXn:eMDKdnq3"
}
