feat: integrate with Divinity plugin stats, healing, CC, and durability - #1775
feat: integrate with Divinity plugin stats, healing, CC, and durability#1775Travja wants to merge 3 commits into
Conversation
Split out of #1677 (piece 2 of 8). Adds studio.magemonkey:divinity as a provided dependency and a PluginChecker.isDivinityActive() flag, then wires several mechanics into it when active: - DivinityHook: clampStatAmount() caps StatMechanic modifiers to Divinity's configured stat cap, applyStatToMob()/removeStatFromMob() apply temporary Divinity stat effects to non-player entities. - StatMechanic: clamps player stat modifiers via Divinity's caps (unless ignore-divinity-cap), and applies stat effects to mobs. - HealMechanic: applies Divinity's healing-cast/healing-received multipliers (unless ignored via settings). - StatusMechanic: applies Divinity's CC-duration multiplier and CC-resistance reduction to status flag durations. - DurabilityMechanic: reduces Divinity-tracked item durability alongside vanilla durability. - DamageMechanic: sets short-lived caster metadata flags (crit/dodge/ block ignore, bleed/vamp disable, skill-crit ignore) around damage application for Divinity's damage listener to read. All Divinity calls are guarded by PluginChecker.isDivinityActive() or wrapped in try/catch, so behavior is unchanged when Divinity isn't installed.
…/DurabilityMechanic HealMechanic, StatusMechanic, and DurabilityMechanic called into Divinity's EntityStats/ItemStats API directly, guarded only by catch(Exception). If Divinity isn't installed, the first invocation of one of those calls throws NoClassDefFoundError - a LinkageError, not an Exception - so the catch block never runs and the mechanic breaks on every server without Divinity installed (the common case, since Divinity is optional). StatMechanic already avoided this by checking PluginChecker.isDivinityActive() before touching any Divinity class. Apply the same guard to the other three mechanics, and broaden the catch to Throwable as defense-in-depth for when Divinity is present but behaves unexpectedly (e.g. an incompatible version). Adds regression tests exercising each mechanic with Divinity inactive (the default in this test environment, matching a server without the plugin installed) to confirm they no longer risk crashing there.
Travja
left a comment
There was a problem hiding this comment.
While adding tests for this PR I found and fixed a real crash risk: HealMechanic, StatusMechanic, and DurabilityMechanic called Divinity's EntityStats/ItemStats API directly, guarded only by catch (Exception ignored). If Divinity isn't installed — the common case, since it's an optional integration — the first call into those classes throws NoClassDefFoundError, which is a LinkageError/Error, not an Exception. That means the catch block never runs and the mechanic breaks on every server without Divinity installed.
StatMechanic already avoided this correctly by checking PluginChecker.isDivinityActive() before touching any Divinity class. I applied the same guard to the other three mechanics and broadened the catch to Throwable as defense-in-depth for when Divinity is present but misbehaves (e.g. version mismatch). Added regression tests for each mechanic with Divinity inactive (the default in the test environment) to confirm they no longer risk crashing there.
Pushed as new commits on this branch — nothing else changed.
Generated by Claude Code
ItemLoreStat, DoubleUnaryOperator, and AdjustStatEffect were referenced by fully-qualified name inline instead of via a normal import. Also dropped a couple of stale comments claiming these references were "confined to this method body" for "lazy class-loading" - imports are compile-time only and don't affect runtime class loading, and the other Divinity types in this file were already plain class-level imports, so the claim didn't hold even before this change. Note: this branch still has the separate, unresolved compile error where TypedStat.Type.HEALING_CAST/HEALING_RECEIVED/CC_DURATION/ CC_RESISTANCE (referenced from HealMechanic/StatusMechanic) don't exist in the pinned divinity dependency version - this commit doesn't touch that.
Split out of #1677 (piece 2 of 8 — see that PR for the full breakdown).
What
Adds
studio.magemonkey:divinityas aprovideddependency and aPluginChecker.isDivinityActive()flag, then wires several mechanics into it when active:clampStatAmount()capsStatMechanicmodifiers to Divinity's configured stat cap;applyStatToMob()/removeStatFromMob()apply temporary Divinity stat effects to non-player entities.ignore-divinity-cap), and can now apply stat effects to non-player mobs too.All Divinity calls are guarded by
PluginChecker.isDivinityActive()or wrapped in try/catch, so behavior should be unchanged when Divinity isn't installed.Why split out separately
This is the largest coherent feature in #1677 and has no dependency on the other split pieces. It's the one most worth extra review scrutiny since it adds an external plugin dependency and several new config options — testable in isolation with/without Divinity present.
Testing
Could not build locally in this environment (private Maven repo
repo.travja.dev, including the newdivinitydependency, isn't reachable from the sandbox). Needs CI/manual verification, particularly: behavior with Divinity absent (should be a no-op), stat capping math, and the CC duration/resistance formulas.Generated by Claude Code