Unofficial site, not affiliated with modrinth.com.What is this?
Плагины/VillageAI
Все версииVillageAI 3.3.2

VillageAI 3.3.2

Release3 нед. назад

Список изменений

[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³).


Метаданные

Канал релиза

Release

Номер версии

3.3.2

Загрузчики

Bukkit
Paper
Purpur
Spigot

Версии игры

1.21–1.21.11

Загрузок

37

Дата публикации

3 нед. назад

Загрузил

ID версии

Главная