
Список изменений
[3.0.1] - 2026-07-05
Fixed config screen readability/blur issue
- The in-game config screen now paints its own near-opaque background and a bordered content panel instead of relying on the vanilla translucent dim — client blur mods/shaders (the "frosted glass" look) can no longer make it unreadable. Rows have background stripes with hover highlight, high-contrast shadowed text, and the ON/OFF and Mana Mode controls are drawn as real bordered buttons whose hitboxes exactly match the drawn rect (previously a 20px hitbox floated over a 35px row). Long descriptions truncate with a hover tooltip instead of overflowing. (ConfigScreenFactory.java)
- Fixed: boolean toggles were clickable in multiplayer read-only mode — the click silently mutated only the client's SERVER-config mirror (cycle rows were already gated). All row controls are now gated on
canMutate, render disabled on dedicated-server clients, and the screen shows "Read-only: server-managed config. Edit the server TOML or use /ans commands." - "Reset Toggles" now resets
enable_cooldown_systemto its actual TOML default (false); it previously set it totrue.
Source Jar synergy: kill switch + tuning (follow-up to the ANS-CRIT-005 chunk-load deadlock fix)
- Fixed in 2.6.2/3.0.0 and hardened here: the Source Jar synergy scan could touch (and synchronously load) chunks during player tick in ≤2.6.1, which could contribute to chunk-load deadlocks. The scan now remains guarded by a non-loading
hasChunkcheck, and this release adds server-owner controls around it. - New keys under
Source Jar Synergy:enable_source_jar_synergy(defaulttrue— the supported off switch; whenfalsethe periodic scan is skipped entirely),source_jar_scan_interval_ticks(default 20, range 1–200), andsource_jar_scan_radius(default 4, hard cap 8 — at most a 2×2 chunk area). Existing TOMLs are auto-upgraded with defaults; no keys renamed. The multiplier keeps its 0.1 minimum — use the kill switch to disable, not a zero multiplier. The kill switch is also exposed as a toggle in the config screen. - The chunk-coverage math behind the scan guard moved to ChunkScanUtil.java with direct unit coverage; skipped scans are still retried and never cached.
- With
debug_mode = true, a rate-limited counter summary (scans run / skipped due to unloaded chunks / jar hits, plus a slow-scan warning) is logged at most once per minute — counters only, never per-block.
Fixed: crash at boot on installs without Iron's Spellbooks
MixinArsPotionEffectstargets an Ars Nouveau class but its bytecode references Iron'sAttributeRegistry; on an Iron's-less install the mixin processor failed withClassMetadataNotFoundExceptionwhile transformingManaCapEvents, which made Ars Nouveau itself fail to load and killed the server during startup. The mixin is now gated on Iron's presence in ArsNSpellsMixinPlugin.java — it only has an effect when Iron's is the primary mana system, so nothing is lost. (Found because the Iron-less GameTest profile could not boot.)
Full-codebase audit remediation
Remediation from the 3.0.1 full-codebase audit (see AUDIT_FINDINGS.md, AUDIT_ARCHITECTURE.md).
Fixed: transcription/binding ritual tablets were uncraftable when Iron's is loaded
- Both apparatus recipes used pedestal ingredient
irons_spellbooks:spell_book, which is not a registered item — Iron's registers only tiered books (copper_spell_book, …,legendary_spell_book). With Iron's installed, both recipes failed to parse (JsonSyntaxException: Unknown item) and the Spell Transcription / Spellbook Binding tablets could not be crafted. The recipes now accept any tiered Iron's spell book via a new shipped item tagars_n_spells:irons_spell_books(all entries optional, so the tag also loads cleanly on Iron's-less installs). Pack makers can override the tag to restrict tiers. pack.mcmetanow declares the correct 1.20.1 data-pack format (15; was 12).
Fixed: LP cost participants gated on inconsistent config toggles
MixinSanctifiedAbstractSpellbypassed Covenant of the Seven's native LP/death check based onenable_mana_unificationinstead of the LP system's ownenable_lp_systemmaster toggle: with unification off + LP on, both ANS and Covenant processed the cost (the double-penalty/instant-death interaction the bypass exists to prevent); with unification on + LP off, Covenant was bypassed with nobody charging LP. The scroll LP path inMixinScrollItemhad no LP-system gate at all, so scrolls kept charging LP with the system disabled. Both now key offenable_lp_system(default unchanged:true).
Changed
- Mode-dependent features (equipment mana bridging, Source Jar synergy, mana-bar hiding) now consistently respect
mana_unification_mode = "disabled"even when theenable_mana_unificationmaster toggle is stilltrue— previously each site re-implemented the precedence check and this state behaved inconsistently.BridgeManager.isUnificationEnabled()is the documented single source of truth. - The three scroll LP action-bar messages are now translatable (
message.ars_n_spells.lp.*); English text unchanged. ConfigScreenFactorymoved from the commonconfigpackage toclient/screen(it is a clientScreen; the old location risked dedicated-server classloading if ever referenced from common code).- Removed the redundant
MixinIronsManaBarOverlay—ManaBarControlleralready cancels Iron's mana-bar overlay viaRenderGuiOverlayEvent.Prebefore the mixin's injection point could ever run. Visual behavior unchanged. - Removed the dead
IronsLPHandler.storePendingScrollLP(no callers; scroll costs stage throughScrollLPTracker). If any pack invoked it reflectively, that call will now fail to resolve.
[3.0.0] - 2026-07-02
Export Ars spells onto Iron's scrolls and bind them into spellbooks
The Ars → scroll → spellbook workflow is the headline 3.0.0 feature. An Ars Nouveau spell can now be exported onto a real irons_spellbooks:scroll and then bound into a real Iron's spellbook, where it casts through Ars 'n' Spells' existing server-authoritative cross-cast pipeline. The Ars spell is preserved as an opaque ANS sidecar payload (arsnspells:cross_spells) on the real Iron item, coexisting untouched with Iron's own ISB_Spells container — no lossy translation into Iron's registry slot model.
- New binding ritual + tablet. SpellbookBindingRitual.java consumes a carrier scroll and appends its Ars entry onto a spellbook in range, with full pre-mutation validation and translated feedback. The tablet is registered in ModItemsRegistry.java only when Iron's is loaded; the recipe is wrapped in
forge:conditional. - New export/bind utilities. ArsSpellExportUtil.java and IronsBookBindingUtil.java recognize Iron items by registry id (no top-level Iron's imports) and dedup bound spells by their serialized
ars_spellpayload, not the shared placeholder id. - New commands.
/ans export_to_irons_scrolland/ans bind_scroll_to_irons_book(permission level 2) provide a developer/admin path. ArsNSpellsCommands.java. - Cross-spell tooltips. CrossSpellTooltipHandler.java surfaces embedded Ars spells, the active index, and cast/cycle hints on Iron scrolls and spellbooks (still used for generic non-spellbook carriers).
Ars spells in Iron's native spell wheel + the Spell Loom workstation
Bound Ars spells now appear as their own entries in Iron's native spell-selection wheel and cast through Iron's native right-click flow (instead of the ANS sidecar right-click), and are authored at a new Spell Loom block.
- Registered proxy-spell pool. ArsCrossProxySpell + ArsCrossProxyRegistry register a finite pool (
ars_cross_1..8) of real Iron'sAbstractSpells intoSpellRegistry. Each occupies one wheel slot; itsonCastreads the casting book's sidecar entry (matched by pool id) and delegates toCrossCastingHandler.castArsSpell, so cost flows once throughonArsSpellCost/BridgeManager(proxygetManaCostis 0; no double-charge). Iron's-gated; never classloads without Iron's. These are real registered spells, not forged ids — avoiding the lookup/UI-crash risks of fake Iron's spell ids. - Native container write. IronsProxySlotWriter adds each proxy into grown container capacity, so a player's existing Iron's spells are never evicted. IronsBookBindingUtil.appendArsSpellToBook allocates a distinct pool id (the wheel de-dupes by spell id) and enforces the per-book cap; it returns a typed
AppendResult(ADDED/DUPLICATE/BOOK_FULL/FAILED). - Custom name + icon in the wheel. Client-only MixinAbstractSpellArsIcon substitutes the per-spell name and icon for proxy entries (
require = 0, so a future Iron's change degrades to a static fallback rather than crashing). The loom's chosen icon symbol (spark/flame/leaf/bolt/star/eye/drop/moon — 8 shipped 16×16 icons) takes priority; the nature icon is the fallback. The icon color control was dropped pre-release: Iron'sgetSpellIconResourcereturns a plain texture path with no tint hook, so a color could never render. Both the nature and icon keys are whitelisted server-side in SpellLoomExportPacket so crafted packets can't stamp NBT that resolves to a missing texture. - Native right-click preserved. CrossCastingHandler.onRightClickItem now defers to Iron's native flow for Iron's spellbooks (no more hijack); the ANS right-click/sneak-cycle path remains for generic inscribed items.
- Spell Loom workstation. New block + block entity + menu + screen (block/, SpellLoomMenu.java, SpellLoomScreen.java): drop an Ars source + a blank Iron's scroll, set a name/nature/icon, and inscribe a carrier scroll via the server-authoritative SpellLoomExportPacket. Craftable; appears in the Functional Blocks creative tab.
- New config.
allow_ars_spells_in_irons_spellbooks(defaulttrue) andmax_ars_cross_spells_per_irons_spellbook(default-1= no cap, bounded by the pool size 8) under Cross-Cast Inscription. - Localised diagnostics. The previously-raw
arsnspells.crosscast.invalid.*validator messages are now translated. - Limitation / compat. At most 8 Ars spells per book show in the native wheel (Iron's
SpellDatastores only id/level/locked and the wheel merges by id). Network protocol version bumped2 → 3.
Pending-cost race fix (free-cast / mischarge on rapid casts)
The Virtue Ring (aura), Cursed Ring (LP), and Iron's-LP handlers staged a pending resource cost at cost-calc and consumed it at the deferred resolve. They each used a single-entry Map<UUID, PendingX>, so back-to-back casts of delayed-resolution spells (e.g. Ars projectiles whose SpellResolveEvent.Post fires on impact) overwrote each other's staged cost — the first cast paid the second's price and the second cast went free.
- Per-player FIFO queue. VirtueRingHandler.java, CursedRingHandler.java, and IronsLPHandler.java now store a
Deque<PendingX>per player: enqueue at cost-calc, poll FIFO (skipping expired heads) at resolve. No cast goes free and no staged cost is dropped. Empty deques are evicted by the periodic sweep and on logout, not in the hot consume path (which would race a concurrent cost-calc reusing the same deque).
Critical fix: world-load deadlock (also shipped standalone as 2.6.2)
- Fixed a server-thread deadlock while loading chunks. The Source-Jar regen-synergy scan (RegenSynergyHandler.java) called
getBlockStateacross a 9×4×9 volume around each player with no loaded-chunk check; near an unloaded chunk border (login, teleport, dimension change, chunk streaming) this forced a synchronous chunk load on the server thread, freezing the game insideServerChunkCache.getChunkBlocking. The scan now verifies the (at most 4) covered chunks are loaded first and retries next cycle otherwise, never caching a result from a skipped scan; its Y range is clamped to world build height. (ANS-CRIT-005)
High-severity fixes
- Closed a post-cast invulnerability window. In safe mode (
death_on_insufficient_lp = false), LPDeathPrevention's death-event safety net cancelled ANY lethal magic/sacrifice damage while the LP-immune flag was set — and the flag lingers up to ~3s after every successful Cursed-Ring cast, silently negating unrelated killing blows (PvP spells, hostile casters, Blood Magic effects). The death handler now enforces the same same-tick scope as the hurt handler. (ANS-HIGH-028) - Server config values are now applied at world load. The mana-bridge mode was cached at common setup, before the SERVER-type config file is read, so a non-default
mana_unification_mode/enable_mana_unificationinars_n_spells-server.tomlwas silently ignored until someone ran/ans mode set. BridgeManager now re-selects on every config load/reload and initializes defensively (DISABLED until real values exist). The init banner/self-check now logs once per session instead of on every world load. (ANS-HIGH-029) - Failed SEPARATE-mode cross-casts no longer drain Iron's mana. The Iron's share of a dual-cost cross-cast is pre-consumed during the Ars cost-calc (ANS-CRIT-002); if the Ars leg then failed (insufficient Ars mana, downstream cancel), that payment was silently kept. CrossCastingHandler now records the pre-payment on the cast context and refunds it via the secondary bridge on every failed-cast path. (ANS-HIGH-030)
Medium fixes
- Scroll
fullcost mode now actually charges mana. MixinScrollItem validated the mana cost and then charged nothing (Iron's scrolls never deduct mana natively). The cost is now staged at HEAD and consumed at RETURN only when Iron's accepts the use, via the newCastingAuthority.consumeIronsSpellMana(mirrors the validation conversion exactly). (ANS-MED-043) - Scroll LP staging migrated to per-player FIFO. ScrollLPTracker used a single overwriting slot, so a second scroll use before the first's RETURN clobbered the first's staged cost (the same race the ring handlers' deque migration fixed); entries leaked until logout if another mod suppressed the RETURN. Now a per-player deque with a 5s TTL and opportunistic eviction. (ANS-MED-042)
- Removed ~20 config options that were never read (silent modpack-tuning traps): the entire Ars Glyph Bonuses section (
amplify_damage_bonus,extend_time_duration_bonus,split_projectile_count,pierce_armor_penetration,sensitive_crit_bonus), the entire Iron's School Bonuses section (enable_school_bonuses,school_bonus_multiplier, ten*_school_*per-level values), four of the five resonance caps (max_duration_multiplier,max_projectile_split,max_chain_chance,max_area_multiplier— onlymax_damage_multiplieris enforced),enable_category_cooldowns,cooldown_reduction_cap,allow_discount_stacking,mana_sync_interval,enable_caching,cache_duration. Setting any of these had no effect; they can return alongside real implementations. (ANS-MED-044) - Rituals consume one item, not the whole stack. SpellTranscriptionRitual and SpellbookBindingRitual discarded the entire source/scroll
ItemEntity; a stacked input (Iron's scrolls stack to 16) lost the extras.
Hardening / consistency
- Fixed packet ids. PacketHandler registered
ResonanceSyncPacketonly when Iron's was loaded, shifting every later message id with Iron's presence. All packets now register unconditionally with fixed ids (the packet touches no Iron's classes). - CooldownSyncPacket wraps its client-mirror write in the same
DistExecutorclient guard as its sibling S2C packets. - MixinArsPotionEffects resolves its two target
MobEffects once instead of reverse-registry-scanning every active effect twice per player tick. (OPT-019) - MixinResourceBarOverlay's label
@Redirectis pinned toordinal = 0so a future Covenant build can't get stray " / peak" suffixes on other bars. - Deleted dead
util/SafeCasterContext.java(zero callers; superseded by readingevent.contextdirectly). - The in-game config screen's save toast now says the save is scheduled (the write is async; the log is the source of truth) instead of unconditionally claiming success.
- The Spell Loom recipe ships an unlock advancement (recipe toast on picking up a book); the loom's icon button label is now translatable (
ars_n_spells.spell_loom.icon+ars_n_spells.icon.*).
Tests
- Iron-loaded GameTests. CrossCastGameTests.java replaces the previous unconditional
helper.succeed()placeholders with a real CYCLE test driven throughCrossCastingHandler.serverHandleCastand an Iron-loaded export→bind→coexist round-trip on realirons_spellbooksitems. The round-trip self-skips when Iron's is absent and runs under the new opt-in-PwithIronsRuntimeGameTestsprofile (build.gradle). - New unit tests: chunk-guard source assertions for the deadlock fix, death-handler tick scope, SEPARATE-mode refund bookkeeping, ScrollLPTracker FIFO/mana-cost carriage.
Dev environment (build-time only, no player impact)
- Compile classpath corrected to Ars Nouveau 4.12.7.
ars_nouveau_filepointed at CurseMaven file 4781441, which is Ars 4.5.0 — the mod compiled against a different Ars API than the[4.12.7,4.13)range mods.toml requires. Now pinned to file 6688854 (4.12.7). - Forge build target 47.2.0 → 47.4.0, the minimum Iron's 3.15+ accepts (players have been on 47.4.x all along;
loaderVersionstays[47,)). - Runnable dev environment. GeckoLib + Curios (Ars' runtime graph) are now
runtimeOnly, and PlayerAnimator rides the-PwithIronsRuntimeGameTestsprofile, sorunClient/runGameTestServerboot without hand-copied jars. GameTest structure templates are staged fromsrc/test/resources/gameteststructures/into the run dir by the newstageGameTestStructurestask (vanilla/Forge ship none — the suite previously crashed at batch setup with "Could not find structure file gameteststructures/platform.snbt").
