The magic editor field was built with lambdas inside Ability.getAllDefinitions.
subGuiField is generic, so those lambdas took SubGuiAbilityMagic as their
descriptor type. @SideOnly strips the annotated method on a server but not the
synthetic lambdas it generates, so anything reflecting over Ability's declared
methods - Nashorn's adapter generator when a script touches an ability - hit
NoClassDefFoundError. Building the field in the client class keeps the type out
of Ability entirely.
Charge drives the NPC with applyVelocityFlat but never declared that it does, so
locking movement during the active phase zeroed its motion outright while not
locking left the navigator running against it - no setting worked. It now
declares its own movement and locks both phases, so the navigator stays clear.
The value is configured, stored and labelled as damage per second, but a pulse
applied it whole, so the real rate was damage per interval - it only matched at
the default interval of 20. A pulse now deals the share of a second it covers.
The interval is floored at 5 ticks, which also bounds how often a zone scans;
this replaces the per-tick membership check, which cost 20x the entity queries.
Barriers are plain entities, so no LivingHurtEvent fires for them and nothing
scaled an incoming melee hit - vanilla handed over the bare attackDamage
attribute and a dome took one point per swing however strong the attacker was.
Attributes now apply, and modifyBarrierMeleeDamage gives addons the same seam
they already have for barrier health.
- Hazards only checked who was inside once per damage interval, so the boundary
where damage started and stopped drifted by however far an entity moved in
between - several blocks at sprint speed. Membership is now checked every
tick and damage accrues per entity from the time it actually spends inside.
- Barriers counted elapsed ticks instead of holding a deadline, so every tick
the entity missed extended it past its configured duration. They now expire
on an absolute world time like the other energy entities.
- Anchored lasers re-derived their direction straight at the target every tick,
discarding the rate-limited look vector, so track speed did nothing and the
beam was undodgeable. They now converge on the point the owner is aiming at.
- Rotation-locked NPCs aimed energy projectiles and hit-scan projectiles from
the target''s position, so the lock was purely visual. Both now respect the
frozen heading.
heightFactor did not fully cancel ModelTail''s anchor, leaving both the wrapped
and plain monkey tails two pixels below where JBRA renders them on players.
The terminal DAZED to IDLE transition was swallowed before the completion
switch ran, so the finished ability stayed set as the current one and the NPC
never started another until it died and reset. Guard abilities compounded it:
NPCs reuse a single ability instance and onExecute left pendingCompletion set,
ending every later activation on its first tick.
An NPC rolled both clocks and folded the ability''s cooldown into the global one
as well, so the global timer always outlasted the per-ability entry and the
setting could never reject anything. The global timer now only paces the NPC
when the ability tracks its own cooldown.
Dimension change and teleport were already fixed, but disconnect still cleared
cooldowns and login cleared them again, and they were never written to NBT - so
relogging reset every cooldown. They are absolute world-time deadlines, so they
now persist and are restored on load.
Deleting a custom ability only cleared the unlocked list. An active toggle kept
a direct reference and went on ticking, stale hotbar slots survived, and the
client was never resynced so it still showed and could select the ability.
Selecting a key the player no longer has now deselects instead of firing
whatever was previously selected.
Closing the setup GUI saved the market from the server''s stale role and then
re-read that market over the edits it had just applied, so stock and currency
cost changes never survived. The role now saves first and the market is written
from it, and relinking to another market no longer pushes pre-link data over it.
fromGenericType expanded a type variable bound, then expanded the bound''s type
arguments, which led straight back to the same variable. Any enum reaches it
through Enum<E extends Enum<E>>, so typing ability.getAllowedBy() crashed the
client. Track the variables being expanded and emit repeats unbounded.
The scrollbar hit test was pure geometry, so clicking its column before the
profile list had loaded - or on any list short enough not to scroll - divided
by a maxScrollY of zero. The draw path already guarded on the same value.
- Removed auto-open GUI logic upon placing BlockBorder and BlockNpcRedstone.
- Resolved a race condition where the GUI would open before NBT/Permission data was fully synced from the server, causing "Permission Denied" or empty states.
- Fixed a logic bug in SubGuiNpcAvailabilityDialog where 'questId' was incorrectly used instead of 'dialogId' when opening the selection picker.
- This change ensures better UX as manual interaction guarantees all data is properly initialized.
- Created SyncRegistry and SyncHandler
- Extracted all 14 SyncType family handling to their own SyncHandler
- Rewritten SyncController to accomodate the new framework