Перейти к содержимому
Mineforgian

Ars 'n Spells

Ars ’n Spells bridges Ars Nouveau and Iron’s Spells ’n Spellbooks, creating deeper synergy between two major magic systems. Harness mana, spell power, glyphcraft, and spellbooks together through new compatibility features, cross-mod progression

Загрузки
6K
Подписчики
8
Обновлён
6 июля 2026 г.
Лицензия
All-Rights-Reserved

Опубликован 18 марта 2026 г.

Исходный код

Ars 'n' Spells

Ars 'n' Spells bridges Ars Nouveau and Iron's Spells 'n Spellbooks into one seamless magic experience. Unify your mana, share progression between spell systems, and scale your power across both mods — all fully configurable.

Works with Minecraft 1.20.1 on Forge.


Requirements

Mod Required?
Ars Nouveau (4.12.7+) Yes
Iron's Spells 'n Spellbooks (3.15.x) No — falls back to native Ars behavior if absent
Covenant of the Seven (Sanctified Legacy) No — enables LP and aura ring systems
Blood Magic No — optional LP source for Ring of Seven Curses
Apotheosis + Apothic Curios No — lets affix/socket mana stats on curios feed the unified pool

(Curios is required by Ars Nouveau, so it is always present.)


Mana Unification

The core of Ars 'n' Spells: five configurable modes that control how the two mana pools interact.

Mode How it works
ISS Primary (default) Iron's mana is the single source of truth. Ars reads and drains from Iron's pool.
Ars Primary Ars mana is authoritative. Iron's spells drain from Ars mana.
Hybrid Shared bidirectional pool. Choose which HUD bar to display.
Separate Independent pools. Cross-mod casts split costs between both (configurable split).
Disabled No integration — each mod uses its own pool.

Conversion rates between the two mana systems are fully configurable.

The mod automatically hides the redundant mana bar so your HUD stays clean.


Gear & Spell Integration

  • Gear perks cross over — Ars armor bonuses apply to Iron's mana pool (and vice versa), depending on your active mode.
  • Curios & Apotheosis affixes — Mana stats on worn curios (rings, amulets, belts) cross over too, including those rolled by Apotheosis / Apothic Curios affixes and sockets (and by Magical Jewelry, Jewelcraft, and similar). The read is generic — no hard Apotheosis dependency — and can be turned off with the read_curio_attribute_modifiers config. (Combat-only stats like crit or armor pierce are not mana/spell-power and are not bridged.)
  • Spell scaling — Ars spell potency scales with Iron's spell power attributes using additive stacking (not multiplicative). Elemental bonuses are applied based on your first glyph. A configurable spell_power_cap (default 3.0) prevents extreme values.
  • Enchantments — Mana-related enchantments from both mods are respected regardless of which pool is active.

Resonance

When your mana is nearly full (above 95% by default), you gain a Resonance bonus that boosts Iron's spell damage. A reward for mana-efficient play.


Source Jar Synergy

Standing near Ars Nouveau Source Jars passively boosts Iron's mana regeneration. The bonus is configurable via source_jar_synergy_multiplier (default 5.0). The scan is position-cached for performance — it only re-scans when you move.


Cross-Mod Progression & Affinity

  • Progression sharing — Casting Ars spells grants Iron's school progression, and vice versa.
  • Affinity tracking — The mod tracks your spell school usage over time, with optional decay for unused schools.

Cross-Spell Inscription

Cast spells from either mod using items from the other mod through a tablet-driven inscribe / uninscribe ritual flow. Both ritual tablets are crafted at the Enchanting Apparatus and are fully datapack-defined, so pack authors can retune ingredients without code.

Spell Transcription — bind a foreign spell onto an item

  1. Craft the Spell Transcription tablet. Reagent: a novice Ars Nouveau spellbook. Pedestals: an Iron's Spellbooks spellbook, an archwood log, and a source gem block. Costs 2000 source.
  2. Set up the brazier. Place the tablet on a Ritual Brazier and drop two items within ~3 blocks:
    • exactly one source — a filled Ars Nouveau spell parchment, focus, or spellbook, or an Iron's Spellbooks scroll
    • exactly one blank target item to receive the inscription
  3. Activate. Strict disambiguation: more than one of either category, or any already-inscribed item in range, fails the ritual with a chat message that names the items it saw and the rule. Items that already carry an Ars Nouveau spell at root NBT are rejected as targets so right-click resolution stays unambiguous. On success the source is consumed, the target gains the cross-cast inscription, and a binding theme of enchantment-glyph particles + the enchantment-table sound marks the inscribe.
  4. Cast. Right-click the target. Sneak-right-click cycles between multiple inscriptions on the same item.

Mana costs flow through the active unification mode and respect your configured conversion rates. In Separate mode, costs split between both pools according to your dual-cost percentages. Cross-cast spells pay an overhead set by cross_cast_cost_multiplier (default 1.25 = 25% extra) — applied symmetrically to both directions, once per cast, before mana deduction.

Spell Uninscription — strip an inscription cleanly

If you change your mind, the Spell Uninscription ritual returns an inscribed item to a bit-identical fresh-blank state so it can be re-inscribed cleanly.

  1. Craft the Spell Uninscription tablet. Reagent: a blank parchment. Pedestals: a water bucket, a source gem, and an archwood log. 500 source.
  2. Activate with exactly one inscribed item in range and nothing else — sources or stray blanks fail the ritual rather than risk stripping the wrong stack.
  3. The cross-cast NBT is removed cleanly (spells list, cycle index, and any empty residual tag), with an ash + smoke dissolution theme.

The uninscribe ritual works without Iron's Spellbooks loaded, so legacy inscribed items can still be cleaned up after Iron's is removed.


Unified Cooldowns

An optional system that groups similar spells across both mods into shared cooldown categories. Prevents spell spam by locking out related spells when one is cast. Disabled by default.


Covenant of the Seven Integration

When Covenant of the Seven (Sanctified Legacy) is installed, two powerful ring systems unlock.

Ring of Seven Curses — Life Point Casting

Wearing the Cursed Ring converts all mana costs into Life Points (LP).

  • Blood Magic Priority (default) — Draws LP from Blood Magic's Soul Network first, falls back to player health.
  • Blood Magic Only — Soul Network only.
  • Health Only — Always costs health (100 LP = 5 hearts).

If you run out of LP:

  • Safe Mode (default) — Spell is cancelled, you take minor damage (you will never die from this).
  • Death Mode — The spell casts… but it kills you.

LP costs scale with configurable base multipliers and per-tier scaling. Blasphemy LP discounts are independently configurable via blasphemy_lp_discount (default 85%).

Ring of Seven Virtues — Aura Casting

Wearing the Virtue Ring converts mana costs into Aura, a custom resource that regenerates over time (default: 10/sec, 1000 max pool). Aura persists through death and dimension changes. If you run dry, the spell simply fails. Blasphemy aura discounts are independently configurable via blasphemy_aura_discount (default 85%).

Ring Conflict: Wearing both rings at the same time cancels both effects — you'll use normal mana instead, and receive a warning notification.

Blasphemy Curios — School Discounts

Thirteen Blasphemy curio variants (Fire, Ice, Lightning, Holy, Ender, Blood, Evocation, Nature, Eldritch, Aqua, Geo, Wind, Dormant) each provide:

  • 15% base mana discount on all spells
  • +10% bonus when the spell's school matches the curio's element (25% total)

Discounts stack multiplicatively with ring costs. A fully kitted setup can reach up to 40% off.


Scroll Cost Enforcement

Iron's Spellbooks scrolls now respect your resource costs:

Mode Behavior
Full (default) Scrolls consume mana and LP/aura like normal casting.
LP Only Scrolls are mana-free, but LP is still consumed for Cursed Ring wearers.
Free No resource cost for scrolls (LP from Cursed Ring still applies).

Configuration

Everything is configurable via the per-world server config <world>/serverconfig/ars_n_spells-server.toml (changed from config/ars_n_spells-common.toml in 2.0.0). Major options include:

  • Master toggles for mana unification, resonance, cooldowns, progression, and affinity
  • Mana conversion rates and dual-cost split percentages
  • LP system — source mode, death penalty, base/tier multipliers, minimum costs
  • Aura system — max pool, regen rate, tier multipliers
  • Curio discounts — base discount, matching bonus, stacking behavior
  • Curio attribute bridgeread_curio_attribute_modifiers (default on): mirror Apotheosis/Apothic Curios affix & socket mana stats across the unified pool
  • Blasphemy ring discounts — separate LP and aura discount rates
  • Spell scaling — power cap for Iron's attribute stacking
  • Source Jar synergy — proximity regen multiplier
  • Rituals — configurable Mana Infusion amount
  • Scroll cost mode
  • Performance — Source Jar cache move threshold
  • Debug mode for troubleshooting

All options ship with balanced defaults — install and play, or fine-tune to your liking.


Commands

Command Permission Description
/ans mana setdefault &amp;lt;value&amp;gt; Op 2 Set the default max mana
/ans mana getdefault -- View the current default max mana
/ans debug Op 2 Toggle debug mode at runtime
/ans info &amp;lt;player&amp;gt; Op 2 Show mana, aura, resonance, and ring status
/ans mode -- Show current mana unification mode

FAQ / Troubleshooting

Q: Ars mana isn't changing in ISS Primary mode. A: Make sure Iron's Spells 'n Spellbooks (3.15.x) is installed. Check logs for mixin load failures.

Q: I see two mana bars. A: Verify your mana mode is set correctly. Check for overlay conflicts from other UI mods.

Q: "Insufficient LP" even though I have enough hearts. A: Make sure lp_source_mode isn't set to BLOOD_MAGIC_ONLY without Blood Magic installed. The default (BLOOD_MAGIC_PRIORITY) falls back to health.

Q: Scrolls are casting for free. A: Check that scroll_cost_mode is set to full (the default).


License

GNU GPLv3

Ченджлог

3.0.1Релиз1.21.1 · 6 июля 2026 г.

[3.0.1] — full 3.0.x parity with 1.20.1: native spell wheel + Spell Loom (2026-07-05)

Ports the entire Forge 1.20.1 3.0.0/3.0.1 line (including its audit remediation) onto NeoForge 1.21.1, aligning version numbers so 3.0.1 means the same feature set on both game versions. Compile targets: Ars Nouveau 5.11.1 / Iron's Spellbooks 1.21.1-3.16.0 (the Iron's pin was bumped from 3.15.6 to match the play instance; every API this release touches was re-verified against the 3.16.0 jar). Build- and test-verified (60 JUnit tests, 0 failures); in-game runtime validation per TESTING_GUIDE.

Added — Ars spells in Iron's native spell wheel (3.0.0 feature A+B)

  • Export → bind workflow. An Ars Nouveau spell is exported onto a real irons_spellbooks:scroll carrier (ArsSpellExportUtil), then bound onto a real Iron's spellbook (IronsBookBindingUtil.appendArsSpellToBook), where it appears as its own entry in Iron's native spell wheel and casts through Iron's native right-click flow.
  • Proxy-spell pool. Eight real registered Iron's spells (ars_n_spells:ars_cross_1..8, ArsCrossProxyRegistry on SpellRegistry.SPELL_REGISTRY_KEY) drive the wheel entries. Each proxy has mana cost 0 (the delegated Ars cast pays the real cost exactly once), ENDER school (never blocked by "not learned"), instant cast, no cooldown. IronsProxySlotWriter grows the book's native container capacity so the player's real Iron's spells are never evicted.
  • Data model. CrossModSpell gains additive proxy_pool_id / custom_name / nature / icon_symbol fields with backward-compatible codecs — components written by 2.6.1 decode unchanged, and entries without proxy metadata encode byte-identically to the 2.6.1 shape.
  • Wheel cosmetics. New client mixin MixinAbstractSpellArsIcon (gated on Iron's presence, require = 0) substitutes the player-chosen name and a whitelisted nature/icon texture in the wheel. 17 icon textures ship under textures/gui/icons/spell/, plus textures/gui/spell_icons/ars_cross_1..8.png as Iron's un-mixed fallback path so a skipped mixin degrades gracefully instead of showing a missing texture.
  • Spellbook Binding ritual (spellbook_binding tablet, apparatus recipe, brazier ritual): drop one carrier scroll + one Iron's spellbook; validates fully before mutating, consumes ONE scroll (stacks preserved), reports DUPLICATE/BOOK_FULL precisely. Config: allow_ars_spells_in_irons_spellbooks (default true) and max_ars_cross_spells_per_irons_spellbook (default -1 = pool-size bound).
  • Commands /ans export_to_irons_scroll and /ans bind_scroll_to_irons_book (permission 2).
  • Tooltips. CrossSpellTooltipHandler (client) shows inscribed-spell entries and cast/cycle hints on any inscribed item.
  • Right-clicking an Iron's spellbook now always defers to Iron's native flow — the ANS sidecar right-click cast no longer hijacks spellbook clicks.

Added — Spell Loom workstation (3.0.0 feature C)

  • First block in the mod: craftable Spell Loom (gold + lapis + book + obsidian). Right-click opens a 3-slot menu (Ars source + blank Iron's scroll → carrier output) with a name field and nature/icon cyclers. The inscribe action is a server-authoritative payload (SpellLoomExportPayload): the server re-reads the block entity slots, validates the scroll, clamps the name to 40 chars, and whitelists nature/icon keys. Hoppers can interact via the item-handler block capability. Ships blockstate/models/textures, loot table, shaped recipe, and recipe-unlock advancement (all at singular 1.21 datapack paths).

Fixed — audit ports from the 1.20.1 3.0.x line

  • ANS-CRIT-005 (world-load deadlock risk): RegenSynergyHandler's Source-Jar scan now verifies all covered chunks are loaded (non-loading hasChunk via new pure ChunkScanUtil) before reading block states, clamps Y to build height, and skips-and-retries near unloaded chunks. New config: enable_source_jar_synergy (kill switch, default true), source_jar_scan_interval_ticks (20, 1–200), source_jar_scan_radius (4, 1–8).
  • ANS-CRIT-002 / ANS-HIGH-030 (SEPARATE-mode mana integrity): the Iron's share of a dual-cost cast is now pre-paid atomically with the sufficiency check during Ars cost-calc (previously the post-cast TAIL consume silently swallowed failures — a one-way Ars drain), and a failed Ars leg refunds the pre-paid Iron's share via the secondary bridge.
  • F1 (apparatus recipes uncraftable with Iron's loaded): pedestal ingredient irons_spellbooks:spell_book is not a registered item (Iron's ships 16 tiered books). Recipes now use the new #ars_n_spells:irons_spell_books tag (entries required: false, so the tag loads Iron's-less).
  • 3.0.1 config screen: full legibility pass (owned near-opaque background so blur mods can't frost it, bounded panel, row stripes with hover, real button chrome with shared render/click geometry, description truncation + hover tooltip, scrollbar) and full read-only gating in multiplayer. Fixed "Reset Toggles" wrongly setting enable_cooldown_system to true (TOML default is false). Moved to client/screen/ (audit F3).
  • Payload registration hardening: all payloads register unconditionally (an Iron's-gated registration could fail channel negotiation when server/client disagree on Iron's presence); network protocol bumped to "2" so 2.6.1 ↔ 3.0.1 cross-connects are cleanly rejected.
  • F5: the remaining direct enable_mana_unification read in RegenSynergyHandler now routes through BridgeManager.isUnificationEnabled(). F6: /reload-safety of the ritual-tablet splice documented on RitualRegistryHandler.

Removed — dead configuration (ANS-MED-044 / F4 + subsystem-gone keys)

  • Removed 59 config keys no code ever read: the Ars Glyph Bonuses and Iron's School Bonuses sections, 4 resonance caps, category-cooldown keys, allow_discount_stacking, the Performance keys (mana_sync_interval, enable_caching, cache_duration), hybrid_sync_rate, allow_mana_overflow, and — 1.21.1-only, because Blood Magic / Covenant of the Seven have no 1.21.1 builds — the entire Cursed Ring LP, Aura, and Blasphemy sections plus hide_mana_bar_with_ring and scroll_cost_mode (its reader mixin was never ported; re-add key + mixin together if the feature returns). Kept: virtue_ring_discount and max_total_curio_discount (repurposed by the live curio discount system) and the resonance master keys (parity with 1.20.1).
3.0.1Релиз1.20.1 · 6 июля 2026 г.

[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_system to its actual TOML default (false); it previously set it to true.

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 hasChunk check, and this release adds server-owner controls around it.
  • New keys under Source Jar Synergy: enable_source_jar_synergy (default true — the supported off switch; when false the periodic scan is skipped entirely), source_jar_scan_interval_ticks (default 20, range 1–200), and source_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

  • MixinArsPotionEffects targets an Ars Nouveau class but its bytecode references Iron's AttributeRegistry; on an Iron's-less install the mixin processor failed with ClassMetadataNotFoundException while transforming ManaCapEvents, 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 tag ars_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.mcmeta now declares the correct 1.20.1 data-pack format (15; was 12).

Fixed: LP cost participants gated on inconsistent config toggles

  • MixinSanctifiedAbstractSpell bypassed Covenant of the Seven's native LP/death check based on enable_mana_unification instead of the LP system's own enable_lp_system master 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 in MixinScrollItem had no LP-system gate at all, so scrolls kept charging LP with the system disabled. Both now key off enable_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 the enable_mana_unification master toggle is still true — 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.
  • ConfigScreenFactory moved from the common config package to client/screen (it is a client Screen; the old location risked dedicated-server classloading if ever referenced from common code).
  • Removed the redundant MixinIronsManaBarOverlayManaBarController already cancels Iron's mana-bar overlay via RenderGuiOverlayEvent.Pre before the mixin's injection point could ever run. Visual behavior unchanged.
  • Removed the dead IronsLPHandler.storePendingScrollLP (no callers; scroll costs stage through ScrollLPTracker). 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_spell payload, not the shared placeholder id.
  • New commands. /ans export_to_irons_scroll and /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's AbstractSpells into SpellRegistry. Each occupies one wheel slot; its onCast reads the casting book's sidecar entry (matched by pool id) and delegates to CrossCastingHandler.castArsSpell, so cost flows once through onArsSpellCost/BridgeManager (proxy getManaCost is 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's getSpellIconResource returns 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 (default true) and max_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 SpellData stores only id/level/locked and the wheel merges by id). Network protocol version bumped 2 → 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 getBlockState across 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 inside ServerChunkCache.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_unification in ars_n_spells-server.toml was 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 full cost 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 new CastingAuthority.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 — only max_damage_multiplier is 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 ResonanceSyncPacket only 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 DistExecutor client 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 @Redirect is pinned to ordinal = 0 so a future Covenant build can't get stray " / peak" suffixes on other bars.
  • Deleted dead util/SafeCasterContext.java (zero callers; superseded by reading event.context directly).
  • 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 through CrossCastingHandler.serverHandleCast and an Iron-loaded export→bind→coexist round-trip on real irons_spellbooks items. The round-trip self-skips when Iron's is absent and runs under the new opt-in -PwithIronsRuntimeGameTests profile (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_file pointed 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; loaderVersion stays [47,)).
  • Runnable dev environment. GeckoLib + Curios (Ars' runtime graph) are now runtimeOnly, and PlayerAnimator rides the -PwithIronsRuntimeGameTests profile, so runClient/runGameTestServer boot without hand-copied jars. GameTest structure templates are staged from src/test/resources/gameteststructures/ into the run dir by the new stageGameTestStructures task (vanilla/Forge ship none — the suite previously crashed at batch setup with "Could not find structure file gameteststructures/platform.snbt").
2.6.0Релиз1.20.1 · 15 июня 2026 г.

[2.6.0] - 2026-06-14

Apotheosis / Apothic Curios mana bridge

Affixed and socketed curios (rings, amulets, belts) now contribute their mana stats to the unified Ars ↔ Iron's pool. The equipment scanner already read attribute modifiers off armor and weapons — so Apotheosis affixes there always worked — but the curio path read only IManaEquipment and Ars enchantments, so an affixed/socketed ring's max-mana or mana-regen never reached the cross-mod bridge. A Mana Battery Ring took effect in its own system's pool but was invisible to the other.

  • Curios attribute modifiers are now read and mirrored. EquipmentIntegration.java enumerates worn curios via the Curios API (CuriosApi.getCuriosInventory(...).findCurios(...)) and reads each slot's aggregated attribute modifiers (CuriosApi.getAttributeModifiers(slotContext, uuid, stack)), summing Ars max_mana/mana_regen and Iron's max_mana/mana_regen through the same sumModifiers helper and ADDITION-only rule the armor path uses. This routes Apotheosis (with Apothic Curios) affixes & sockets — and any other curio mana gear such as Magical Jewelry or Jewelcraft — through the existing bridge. No double-counting: the curio's own pool already gets the modifier natively; the bridge only mirrors it to the other system, exactly as armor does.
  • No hard Apotheosis dependency. The read is generic (any mod's curio mana attributes), gated behind the new read_curio_attribute_modifiers config (default on) and wrapped so any API surprise degrades to "no bonus" rather than a crash.
  • Spell power needed no change — it is read from the player's total attribute, so affix spell power on armor/weapons/curios already counted. Apothic Attributes' own attributes (crit, armor pierce, fire/cold damage) are combat-only and out of scope for the mana/spell bridge.
  • Build: build.gradle adds a compileOnly Curios API dependency (5.9.1+1.20.1, the version Ars Nouveau bundles at runtime). Curios is always present at runtime via Ars, so this only puts the slot-aware API on the compile classpath.

Ring / aura-HUD correctness and hardening

  • Aura-bar peak tracker is now lock-free. ClientAuraPeakTracker.java stores the personal peak in an AtomicInteger with a monotonic getAndUpdate ratchet, so the render-thread read in the HUD mixin composes cleanly with client-tick writes (and stays correct if a sync writer is ever added).
  • Covenant version-drift probe. ArsNSpellsClient.java logs at startup whether Covenant of the Seven is at the version the aura-bar HUD mixin (MixinResourceBarOverlay) was bytecode-verified against (2.2.6). The mixin uses require = 0, so a mismatch can't crash the client; this makes the silent fallback diagnosable instead.
  • Virtue aura system honors its toggle. VirtueRingHandler.java now short-circuits its handlers when ENABLE_VIRTUE_AURA_SYSTEM is off.
  • Dead alternate-resource stubs removed. CastingAuthority.java dropped the never-implemented detectAlternateResourceCost/validateAlternateResource path (it always returned null/true); Cursed/Virtue ring costs are owned by their dedicated event handlers.

Performance (render + tick hot paths)

  • OPT-008: MixinArsPotionEffects.java only churns the mana attribute modifiers when the value actually changed, instead of a remove/add every server tick (which forced an attribute recompute).
  • OPT-009: ManaBarController.java matches mana overlays on the ResourceLocation namespace/path directly (allocation-free equals) instead of toString() + substring scan every overlay every frame. The matchers are extracted as pure, package-private, unit-testable methods.
  • OPT-010 / MED-019: OverlayDiagnostics.java registers its per-frame render subscriber on the Forge bus only while diagnostics are enabled (zero dispatch cost when off, the default), and uses a TreeSet for already-sorted iteration.
  • IronsLP debug trace gated. IronsLPHandler.java builds its per-cast entry-trace strings only when LOGGER.isDebugEnabled().

Tests

2.5.0Релиз1.21.1 · 15 июня 2026 г.

[2.5.0] — 1.21.1 compatibility & correctness (2026-06-06)

A correctness-focused compatibility release on top of the build-verified 2.0.1 core. The bridge / cross-casting / progression / resonance / rituals stack is unchanged; this release fixes the largest parity gaps, restores two silently-broken datapack features, and hardens optional-mod handling. Compile targets stay pinned to the build-verified Ars Nouveau 5.11.1 / Iron's Spellbooks 3.15.6; the target pack runs AN 5.11.7 / ISS 3.16.0 at runtime (event- and registry-based code tolerates the delta — see Known limitations). Build- and test-verified; in-game runtime validation remains pending (the build environment runs no Minecraft).

Fixed — datapack paths (were build-green but runtime-broken)

  • Ritual recipes are obtainable again. The Spell Transcription / Uninscription apparatus recipes shipped under the 1.20.1 plural path data/ars_n_spells/recipes/…, which Minecraft 1.21 no longer reads (it loads recipe/, singular — verified against the Ars Nouveau and Iron's jars). They never loaded, so the ritual tablets were uncraftable in survival. Moved to data/ars_n_spells/recipe/apparatus/.
  • Ritual recipes now parse. Once relocated, the same apparatus recipes surfaced a second carryover — the 1.20.1 recipe schema (output/item, reagent as an array), which fails AN's current enchanting_apparatus codec with No key result. Migrated to the 1.21 form (result with id+count, reagent as a single object); verified against the live pack (AN 5.11.7) so the Transcription/Uninscription tablets craft at the Enchanting Apparatus. A ResourcePresenceTest schema check now guards the format.
  • Curio spell discount works again. The #ars_n_spells:curio_spell_discount item tag shipped at the plural tags/items/ path (1.20.1) instead of 1.21's tags/item/, so it never loaded and the discount was permanently inert. Moved to tags/item/, and the tag now ships a sensible default (#irons_spellbooks:school_focus, optional).

Added / changed — affinity now covers every Iron's addon school

  • Dynamic, addon-aware affinity. Affinity was keyed by a hardcoded 16-value AffinityType enum, so the ~19 addon schools in the target pack (cataclysm_spellbooks:abyssal, iss_magicfromtheeast:spirit, somakespells:aqua, …) earned no affinity at all — the Iron's handler dropped every school not in the enum. Affinity is now stored as a Map<String,Integer> keyed by the full school id (mirroring progression), so every registered Iron's school tracks automatically, with no per-mod code. New SchoolKeys (the single canonical-key source shared by both handlers and the damage-scaling site) and an Iron's-gated SchoolIndex registry snapshot for /ans diagnostics.
  • Fixed the mirrored Ars-side drop bug. aqua/geo/wind (words the Ars glyph heuristic emits but the enum lacked) threw in AffinityType.valueOf and were silently lost; they now track under ars_n_spells:* keys.
  • Safe save migration. AffinityData uses a versioned codec; a 2.0.x save (bare map of enum-name keys) migrates losslessly — the nine elemental tracks are renamed (FIREirons_spellbooks:fire) with counts intact and re-stamped on first save (idempotent). Owner decision (default): the seven legacy category/source buckets (OFFENSIVE/DEFENSIVE/UTILITY/MOVEMENT/ARCANE/PRIMAL/HYBRID) are dropped on migration — they were never real schools and current code never wrote them. Back up saves if you want to be cautious; flip to quarantine on request.
  • /ans info <player> now lists the player's non-zero affinity tracks and (with Iron's) the registered school count.

Added — Curios discount, both sides

  • The tagged-curio mana discount now applies to Iron's casts too (SpellOnCastEvent.setManaCost), not just Ars casts. The slot scan is shared via a new compat/curios/CuriosAccess. New max_total_curio_discount config (default 0.50) caps the combined discount so stacked curios can't trivialise mana cost.

Hardened — optional-mod & version resilience

  • All mana/resolver mixin injects now carry require = 0, so an Ars/Iron's point-release method-signature change fails soft (skips the inject) instead of crashing mod load. The mixin plugin additionally probes the Ars target classes (ManaCap/ManaData/ SpellResolver) so a class rename also fails soft. (Shadow field drift remains fatal — the eventual event-first migration is the real fix; see Known limitations.)
  • New compat.ModPresence (cached multi-mod presence) + compat.CompatIds; IronsCompat delegates to them. Lightweight foundation; the full module framework is deferred.
  • New #ars_n_spells:magical_companions entity-type tag (aggregates #ars_nouveau:familiar
    • #irons_spellbooks:summons, optional) as datapack scaffolding for future summon synergy.

Tests

  • ResourcePresenceTest asserts every shipped data/asset file exists, parses, and sits at the correct singular 1.21 path (regression guard for the directory-flattening bug above).
  • SchoolKeysTest pins the Ars↔Iron's key agreement and the aqua/geo/wind fix.
  • AffinityDataMigrationTest covers the versioned codec round-trip and the 2.0.x → 2.5.0 legacy migration (rename, bucket drop, re-stamp, clamp).

Known limitations

  • Compile vs runtime version delta. Pinned to AN 5.11.1 / ISS 3.15.6; pack runs 5.11.7 / 3.16.0. A post-2.5.0 task is to validate in-game and optionally move the compile classpath up. Mixin shadow-field drift (e.g. an AN field rename) would still crash on load — require = 0 covers method drift only; migrating the mana bridge to AN/ISS events is the durable fix and is deferred.
  • In-game validation pending (build env has no Minecraft): cast one spell per addon school → affinity increments under the correct id; load a 2.0.x save → elemental tracks migrate with counts intact, buckets dropped; tagged-curio cast drops cost on both Ars and Iron's within the clamp; client + dedicated-server boot with/without Iron's and Curios; ritual tablets craftable at the apparatus.
  • Covenant LP / aura / virtue / blasphemy remain N/A (Branch B). The dead Covenant config keys are intentionally retained to match the canonical 2.0.1 config.
2.0.0Релиз1.20.1 · 29 мая 2026 г.

[2.0.0] - 2026-05-14

Audit-driven major release

2.0.0 addresses the comprehensive technical audit at ars-n-spells-2.0.0.md. Every High and Medium-High hypothesis in the audit's "Ranked Root-Cause Hypotheses" maps to a closed fix below. The major-version bump reflects two breaking changes (new C2S packet ID; clients older than 2.0.0 cannot cross-cast against a 2.0.0 server) plus the architectural reorganization of the cross-cast pipeline.

Phase 1 — Hotfix (cross-cast actually works again)

  • Client-side cancellation no longer swallows the cast. CrossCastingHandler.java used to call handleCrossCast on both sides, return true on the logical client, and then event.setCanceled(true) — so on a dedicated server the client claimed success and cancelled the use, while the server never received any cast trigger. Silent "input detected, nothing happens" failure. The client now short-circuits before any cast logic and sends a new CrossCastRequestPacket instead; the server is the sole authority over cast execution.
  • Cross-cast decoupled from mana unification. The previous BridgeManager.isUnificationEnabled() guard in CrossCastingHandler.onRightClickItem, CrossCastingHandler.onArsSpellCost, and CrossCastIronsHandler.onIronsSpellCast made inscribed items inert whenever mana_mode=disabled or enable_mana_unification=false. The README documents disabled as a mana sharing mode, not as a master switch for cross-cast. Settled policy: cross-cast remains available in every mode; the multiplier still applies; in disabled mode, native upstream pools pay native costs (no SEPARATE split, no ARS_PRIMARY conversion). The unification check survives as an internal mode-branch flag inside each cost site.

Phase 2 — Stabilization (multiplayer authoritative + traceable)

  • New C2S CrossCastRequestPacket. Carries hand, action (CAST/CYCLE), client-observed index, and a client-generated attempt UUID. The server handler re-reads the held stack (no client trust), generates its own attempt UUID for trace correlation, and dispatches to the new CrossCastingHandler.serverHandleCast entry point.
  • New PacketHandler.sendToServer. Helper for the new C2S direction. CrossCastRequestPacket is registered at the tail of the packet ID list so pre-existing IDs (Resonance, Affinity, Cooldown, Aura) do not shift.
  • New CrossCastValidator. Single authority for cross-cast payload validity. Checks index range, payload non-emptiness, spell-type resolution (with namespace fallback), Ars ars_spell non-empty, Iron's spell_id parseability + level ≥ 1 + registry resolution. Rejections produce a translation key the player sees via displayClientMessage and a structured descriptor_rejected trace event. The four-arg public API is the production path; a package-private overload accepts a synthetic Iron's predicate so unit tests do not need Forge bootstrap. 16-case CrossCastValidatorTest covers every branch.
  • attemptId UUID on CrossCastContext.Entry. Threaded from the packet handler through serverHandleCast, into CrossCastContext.begin(...), and read back at every Ars/Iron mixin and event-handler trace point. Parallel cross-casts no longer alias their logs.
  • New util/CrossCastTrace. Structured logger emitting [CrossCastTrace] attempt=<uuid> player=<name> side=<C|S> stage=<symbolic> k=v … exactly as specified in the audit's "Debug Instrumentation Plan". Gated on debug_mode. Stages: INPUT_DETECTED, REQUEST_SENT, REQUEST_RECEIVED, DESCRIPTOR_VALIDATED, DESCRIPTOR_REJECTED, RESOURCE_CHECK, RESOURCE_SPEND, ARS_COST_APPLIED, IRON_COST_APPLIED, UPSTREAM_CAST_ENTER, UPSTREAM_CAST_EXIT, EFFECT_APPLIED, CYCLE_APPLIED. Used from CrossCastingHandler, CrossCastIronsHandler, MixinSpellResolverPreCast, and MixinSpellResolverMana.
  • New CrossCastCostResolver. Single source of truth for the cross-cast cost algorithm — captures the mode × multiplier × ring state matrix in one place. Returns a CostBreakdown(primary, secondary, primaryMode, secondaryMode, mode, unified, ringActive, multiplier) record. Three stages: ARS_PRECALC, IRON_PRECALC, IRON_POSTEVENT. For 2.0.0 this is an authoritative calculator — existing cost-mutation sites still own choreography (event mutation, mixin cancels, ring pending-cost stamping); full delegation onto the resolver is tracked for 2.0.1.
  • New CapabilityResyncHandler. Single owner of bridge-capability resync across PlayerLoggedInEvent, PlayerRespawnEvent, and PlayerChangedDimensionEvent. Replays Affinity (one packet per non-zero school), Cooldown (one packet per active category), and Resonance (when Iron's is loaded). Aura is not duplicated here — AuraCapabilityProvider already covers all three events from 1.10.0. The previous AffinitySyncOnLoginHandler is retired; its login coverage is subsumed.

Phase 3 — Hardening

  • Sealed SpellDescriptor model with ArsSerializedSpellDescriptor and IronsRegistrySpellDescriptor. Typed adapter between the two upstream spell models with uniform validate/serialize/displayName/resolve/systemType/spellId. On-disk NBT shape is unchanged so pre-2.0.0 inscribed items round-trip cleanly via SpellDescriptor.parse(CompoundTag). Full migration of call sites off raw CompoundTag maps onto descriptors is tracked for 2.1.0.
  • New CastContext value record. Threads attempt UUID + player + hand + source stack + descriptor + mode + cost breakdown through the pipeline. Existing sites still pass individual parameters; full migration is tracked for 2.1.0.
  • GameTest scaffold. build.gradle gains a gameTestServer run target gated on the ars_n_spells namespace. CrossCastGameTests ships one sanity scenario confirming the scaffold is wired; the full seven-scenario suite from the audit's "Testing and Validation Strategy" lands in 2.0.1 alongside the structure NBT templates each scenario requires.
  • CI workflow. .github/workflows/ci.yml — JDK 17 on Ubuntu, gradle and ForgeGradle caches, ./gradlew compileJava test as the required-status job, ./gradlew runGameTestServer as an advisory job (continue-on-error true while the GameTest suite is still landing).

Breaking changes

  • Packet ID list grew. CrossCastRequestPacket is appended at the tail of PacketHandler.register(), so existing packet IDs (Resonance, Affinity, Cooldown, Aura) are unchanged. Clients older than 2.0.0 cannot cross-cast against a 2.0.0 server — they cannot send the new packet. Servers older than 2.0.0 cannot serve 2.0.0 clients — they will reject the new packet ID. Use matching client/server versions.
  • AffinitySyncOnLoginHandler removed. Its login-sync responsibility is fully subsumed by CapabilityResyncHandler (which adds respawn + dimension sync). No user-facing behavior change for affinity on login.
  • mana_mode=disabled now permits cross-cast. Previously, setting the mode to disabled (or enable_mana_unification=false) made inscribed items inert. They now cast normally with native upstream pool costs; only mana sharing is suppressed in disabled mode. Modpacks that intentionally wanted cross-cast disabled by setting mana_mode=disabled will see cross-cast become available again — there is no separate enable_cross_casting toggle; the feature is now always-on whenever an inscribed item is held.

Known follow-ups (deferred to 2.0.1 / 2.1.0)

  • 2.0.1: full site delegation onto CrossCastCostResolver (current 2.0.0 has the resolver but call sites still own choreography); CrossCastCostResolverTest with the mode × ring × stage matrix (needs a BridgeManager.testSetMode test-only seam).
  • 2.0.1: the seven cross-cast GameTest scenarios (clean Ars cast, clean Iron cast, malformed NBT rejection, insufficient resources, dimension transition, separate-mode dual cost, ring + cross-cast) — each needs its own structure NBT template.
  • 2.1.0: full migration of CrossCastingHandler / CrossCastValidator call sites off raw CompoundTag maps onto SpellDescriptor; CastContext threaded through the pipeline.
  • 2.1.0: server/client config split, datapack registries for spell schools / cooldown categories / progression rules / cross-cast rules.

Backward compatibility

  • Save format unchanged. AffinityData, ProgressionData, CooldownData, AuraCapability, and arsnspells:cross_spells NBT shapes all preserved. Inscribed items from 1.8.9+ load and cast unchanged at 2.0.0.
  • Mod config unchanged. No keys added, removed, or renamed. The mana_mode=disabled semantics change is documented above.
  • Mixin injection points unchanged. All Ars SpellResolver injects keep their @At targets and method signatures. Mixin-compatible with Ars 4.12.7+; no Iron's-side mixin changes.

Ring of Virtues and Ring of Curses — correctness pass

Investigation found five correctness bugs in the Sanctified Legacy / Covenant of the Seven ring integration. Symptoms ranged from "the rings silently do nothing on a C7-only modpack" to "the player pays both mana and aura on the same spell after unequipping the ring mid-cast." All are fixed in 1.10.0.

  • hasBothRings AND-gate fix. SanctifiedLegacyCompat.java:222 returned false whenever either Covenant of the Seven or Enigmatic Legacy was missing. But C7 ships both rings — meaning a C7-only modpack with both rings equipped silently dropped through every ring path: isWearingCursedRing cancelled out, isWearingVirtueRing cancelled out, ring-conflict notification never fired, and the player paid mana while believing aura was being consumed. The guard is now && instead of ||. hasMatchingBlasphemy was also tightened to use isAvailable() for consistency.
  • Stale pending-cost can't leak across spells anymore. VirtueRingHandler and CursedRingHandler used to consume the pending aura/LP cost purely on UUID lookup at SpellResolveEvent.Pre. If another HIGHEST-priority handler cancelled a spell between SpellCostCalcEvent and SpellResolveEvent.Pre, the pending cost lingered for up to 5 seconds; the next spell — even with the ring unequipped — was charged aura/LP and mana (MixinSpellResolverMana only cancels mana if you're currently wearing the ring). Both handlers now re-verify isWearingVirtueRing / isWearingCursedRing at every consumption site and drop the stale entry if state changed.
  • Resolve consumption moved from Pre to Post. Consuming on SpellResolveEvent.Pre meant that if another mod cancelled the cast at Pre after our HIGHEST handler ran, the resource was charged but the spell never executed ("paid but didn't cast"). Aura/LP is now charged on SpellResolveEvent.Post, which only fires for resolved (non-cancelled) spells. Validation continues to happen at canCast (MixinSpellResolverPreCast) so impossible casts still get blocked cleanly. Pre is kept as a state-drift gate that drops the pending entry if the ring came off between cost-calc and resolve.
  • Iron's Spellbooks + Virtue Ring path now exists. Previously, casting any Iron's spell while wearing the Virtue Ring drained Iron's mana — only the Cursed Ring had an Iron's handler. Symmetric coverage with the new IronsAuraHandler: pre-cast validation against the aura pool, mana zeroed at SpellOnCastEvent, aura consumed instead. Insufficient aura cancels the cast with an action-bar message (no death penalty — Virtue Ring failure is intentionally non-punitive). Iron's scrolls get the same treatment via a new aura branch in MixinScrollItem plus ScrollAuraTracker for the HEAD→RETURN commit pattern that ScrollLPTracker already uses.
  • AuraCapability no longer corrupts new players. AuraCapability.java used to read AURA_MAX_DEFAULT in its constructor and fall back to 100 on IllegalStateException. AttachCapabilitiesEvent can fire before ModConfigEvent.Loading, so any player created before config load was permanently capped at 100 aura (10% of the configured default of 1000). The capability now defers initialization until first server-side access (so config is guaranteed loaded), and loadNBTData runs a one-shot migration: if a saved maxAura == 100 and the configured default is higher, the player is reset to the configured default and an ans_v110_migrated marker is stamped onto the NBT so the heuristic only runs once. Users who legitimately wanted a 100-aura cap should re-apply their config preference after upgrading.

Aura HUD and sync

The mana bar is hidden while the Virtue Ring is worn (since spells cost aura, not mana), but until now nothing replaced it — the player flew blind. 1.10.0 ships the missing pieces:

  • New AuraSyncPacket — server→client sync of (aura, maxAura). Sent on login, dimension change, respawn (post-clone), and whenever the server-side capability marks itself dirty and the mana_sync_interval tick window elapses.
  • New ClientAuraState — client-side mirror, reset on disconnect.
  • New AuraBarControllerRenderGuiOverlayEvent.Post overlay drawn just above the hotbar in aqua tint when the local player wears the Virtue Ring. Hidden when mc.options.hideGui, when the ring isn't equipped, or when the aura system is disabled.

Ring swap mid-cast no longer leaks

The previous handler had no signal for Curios slot changes (LivingEquipmentChangeEvent does not fire for Curios), so the per-player curio cache could stay stale for up to a second and a stamped pending cost could be consumed against the wrong wearer state. The cleanup now happens at the consumption site instead: both SpellResolveEvent.Pre and SpellResolveEvent.Post in the ring handlers re-check isWearingVirtueRing / isWearingCursedRing (with the freshness provided by the 20-tick SanctifiedLegacyCompat curio cache) and drop the pending entry when state has changed. A dedicated CurioChangeEvent listener that would cut the "ring just equipped → not active yet" latency from ~1 s to instant is deferred — the event class is not on this mod's transitive compile classpath without an extra compileOnly dependency declaration.

Configuration

  • New: enable_aura_system (default true) — master toggle mirroring enable_lp_system. When false, the Virtue Ring is ignored and spells use normal mana. Useful for modpacks that want LP but not aura.
  • Removed: virtue_ring_discount — the Ring of Virtue stopped being a mana discount in 1.2.0 (it converts mana to aura). The config key has been dead since then; setting it had no effect. Removed entirely in 1.10.0. Existing configs will get an "unknown key" warning on first load and can safely delete the line.
  • Changed default: aura_minimum_cost is now 10 (was 5) — matches ars_lp_minimum_cost. Existing configs preserve whatever value the user set.

Commands

  • New: /ans aura — non-permissioned subcommand that prints the caller's own aura value. The existing /ans info <player> is unchanged (still op-only).
1.6.3Релиз1.20.1 · 26 марта 2026 г.
  1. Ars 'n' Spells v1.6.3

Bug Fixes

  • Fixed startup crash caused by MixinSanctifiedAbstractSpell using the wrong parameter type (LivingEntity instead of Player), preventing the game from loading when Iron's Spellbooks was present
  • Fixed crash in IronsBridge.setMana() due to missing null check on MagicData
  • Fixed potential crash from null SpellRarity when calculating LP costs for Iron's spells and scrolls
  • Fixed MixinSanctifiedAbstractSpell not being registered in mixin config. Sanctified Legacy LP validation was completely non-functional
  • Fixed MixinSpellStatsPotency being wrongly gated on Iron's Spellbooks. Resonance potency now works even without Iron's installed
  • Fixed potential double LP charge when using spell scrolls with Cursed Ring equipped
  • Fixed BridgeManager creating unnecessary bridge instances on every mana query when unification was disabled

New Features

  • Added /ans mana setdefault <value> command (op level 2) to configure default max mana at runtime
  • Added /ans mana getdefault command to view current default max mana
  • Added ENABLE_LP_SYSTEM config toggle to completely enable or disable the LP (Life Points) system
  • Added DEFAULT_MAX_MANA config option (range: 1.0 to 100,000)
  • Added startup warning when dual-cost percentages do not sum to 1.0

Improvements

  • Rewrote LPDeathPrevention with a flag-based immunity system, preventing Corpse mod from incorrectly triggering on LP damage
  • LP system handlers now respect the ENABLE_LP_SYSTEM toggle across all event handlers
  • Hardcoded fallback mana values now use the configurable DEFAULT_MAX_MANA instead of fixed 100
  • Improved error log formatting in IronsBridge

Housekeeping

  • Cleaned up stray build artifacts (com/, nul) from repository
  • Updated .gitignore with missing entries
  • Added Linux gradlew wrapper

Комментарии

Загружаем…