Skip to content

Move old armour to the new looks and keep item data through refreshes - #39

Merged
XxFran10xX merged 4 commits into
feat/armour-metal-tagfrom
feat/armour-look-migration
Oct 10, 2026
Merged

XxFran10xX merged 4 commits into
feat/armour-metal-tagfrom
feat/armour-look-migration

Conversation

@XxFran10xX

Copy link
Copy Markdown
Contributor

Armour crafted before the per-recipe models (#36) still wears the old shared look of its metal: iron is vanilla chainmail, steel is vanilla iron, bronze is bronze_*, abyssalite is netherite, mythril is diamond, infantry is the paper pumpkin and gold, and mage is iron_mage_*. This moves those pieces to their recipe's current model when they are refreshed, without touching their data. It also fixes two ways the existing refresh and ItemsAdder could damage items.

Changes

  • Look migration (ArmourLookMigrator, run by the existing join, ender chest, opened storage, click and equip refresh). A recorded craft that still wears its old default look gets the model for its recipe, e.g. light_helmet gets ia.tfmc_armor:iron_light_helmet. The change goes through ArmorMerger, the same merge skins use, so stats, gems, sockets, lore, durability and name stay. The old default is the scheme's type model (helmet, ...), or the recipe's entry in armour-look-migration.legacy-models for looks that came from another ingredient (infantry paper, mage dust). Any other look is a skin and is kept. The old look is stored in ac_previous_model and logged as [AC][LookMigration]. Every recorded craft also gets its ac_craft_model_scheme tag, which ArmourShop's metal skin lines read. Off unless armour-look-migration.enabled: true.
  • Stat refresh keeps the item's own data (RefreshKeeper). CraftStatRefresher rebuilt outdated items from their MMOItems data only. On TFMCDev01 that repaired them to full durability, reset ArmourShop names, dropped the skin's itemsadder compound, and dropped geminfusion:socket_rarities and tlibs:socket_overrides. The damage taken now carries over (scaled to the new maximum, never breaking an item). The skin, material, model, leather colour, display name and every persistent data key the rebuild does not set come back.
  • ItemsAdder auto_update opt-out (IaAutoUpdate). ItemsAdder rebuilds an item from its definition when the definition's base properties hash no longer matches what it stored for that player slot. That rebuild keeps only amount, durability, persistent data, trim, name and enchantments, so a crafted piece wearing an ItemsAdder look loses its MMOItems data (the 2026-10-03 incident). Crafted pieces with an ItemsAdder look now get itemsadder.override_auto_update: true, which ItemsAdder honours. NBTAPI is a provided dependency and a softdepend.
  • One broken item (e.g. a recorded craft whose MMOItems data is gone) no longer stops a join sweep, and a malformed v. model path no longer throws.
  • ModelApplier holds the model path code that CraftingStation and the migration share.

Testing

  • mvn verify: all tests pass and coverage stays at 100% (the Windows-only EdgeCoverageTest/StationDatabaseCoverageTest failures also happen on main).
  • TFMCDev01, test bots with exact copies of Main armour: 18/18 pieces per bot. Every metal, weight, infantry, mage, alloy and ender chest piece got its new look with only the look fields and AC tags changed. A skinned piece and a premade piece were left alone. Results held after iareload, after a restart and on a second pass. A chest piece migrated when the chest was opened.
  • Outdated-revision path: wear (e.g. 478/500), names, gems and socket data are kept.
  • ItemsAdder definition change (icon swap + iareload): an unprotected copy of a skinned helmet was wiped, while the protected copy stayed intact.
  • Full rehearsal with Main's live configs and all 140 Main players holding crafted or skinned gear (3,442 items): 185 pieces migrated, 146 skins kept, 408 crafts tagged, 324 ItemsAdder looks protected, nothing lost. Items Main's current refresh would damage on next login (3 longbows lose their names, 2 are repaired, 2 lose their look) keep all of it with this change.

Stacked on #37 (and #36); retarget to main once those merge.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 05c6b376-136e-42d6-9a6c-50c44f0dcce1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@XxFran10xX
XxFran10xX force-pushed the feat/armour-metal-tag branch from e8c77bc to 4faad34 Compare October 10, 2026 06:31
XxFran10xX and others added 4 commits October 10, 2026 08:31
…odel

Pieces crafted before the per-recipe models still wear their metal's shared
type model (iron chainmail, steel iron, bronze bronze_*, ...) or the infantry
paper / mage dust look. When AcItemRefresher sees a recorded craft (join,
ender chest, opened storage, click, equip), ArmourLookMigrator gives it the
recipe's current model through ArmorMerger, so its MMOItems data stays. Any
other look is a skin and is kept. The old look is saved in
ac_previous_model and logged. Every recorded craft also gets its model scheme
tag, so ArmourShop's metal skin lines apply to older pieces too.

armour-look-migration.enabled is off by default; legacy-models lists the old
looks of recipes whose look came from another ingredient.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n item

CraftStatRefresher rebuilt outdated crafted items from their MMOItems data
only. On TFMCDev01 that repaired them to full durability, dropped ArmourShop
skin names, the itemsadder compound of skins, and other plugins' data such
as geminfusion:socket_rarities and tlibs:socket_overrides.

RefreshKeeper keeps the damage taken (scaled to the new maximum, never
breaking an item), then puts back the skin through TLibs' ItemSkinPreserver,
the material, model and leather colour, the display name, and every
persistent data key the rebuilt item does not set itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ItemsAdder's auto_update rebuilds an item from its definition when the
definition's base properties hash no longer matches the one it stored for
that player slot. The rebuild keeps only amount, durability, persistent
data, trim, name and enchantments, so a crafted MMOItems piece wearing an
ItemsAdder look loses its stats, gems and lore (the 2026-10-03 incident, and
reproduced on TFMCDev01 by editing a definition or a player's inventory
offline). ItemsAdder skips items whose itemsadder compound has
override_auto_update: true.

The look migration sets that flag on every recorded craft with an ItemsAdder
look (migrated and skinned pieces), and the stat refresh sets it on rebuilt
pieces. NBTAPI becomes a provided dependency and a softdepend.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… paths

A recorded craft whose MMOItems data is gone threw in the stat refresh and
stopped the whole join sweep on TFMCDev01, so the rest of that inventory was
not refreshed or migrated. CraftRefreshListener now logs the item and
carries on. A v.<material>.<model> path with a non-numeric model no longer
throws in the look migration; it simply does not match.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@XxFran10xX
XxFran10xX force-pushed the feat/armour-look-migration branch from b46e1da to 571d50d Compare October 10, 2026 06:31
@XxFran10xX
XxFran10xX merged commit 571d50d into feat/armour-metal-tag Oct 10, 2026
1 check passed
@XxFran10xX
XxFran10xX deleted the feat/armour-look-migration branch October 10, 2026 06:53
XxFran10xX added a commit that referenced this pull request Oct 10, 2026
…rworks

Forging refused extra hits once a hit type had enough, and refused to
finish until every type was exactly complete. Its refusal told the player
the needed counts ("You only have 5 out of 12 Metal hits"). Like
goldsmithing (GemInfusion #39), a piece can now be finished with any
number of hits once its materials are in. Too few or too many hits only
lower the Hits %, and with it the quality. The finish-time "over-reliance"
message is gone too, so the final Hits % is the only feedback. The hit
title (Metal hits: x/needed) and the refusal of a hit type the piece
does not need at all are unchanged.

Finishing also rolls d20 + a modifier from the crafter's base Strength,
like /roll, shown only to them as "Craft roll". A natural 20 always
succeeds and a natural 1 always fails. A Masterwork now needs 100% hits
and a total of 20+ (or a natural 20); perfect hits that miss become the
tier below (Gleaming: Radiant socket / Greater rune slot). The roll never
touches stats, which still come only from the materials, so every
Masterwork has the best stats its materials give. Staff-built pieces
with a set quality do not roll. Alloys are unchanged.

Settings live under d20 in config.yml (modifier table, attribute,
masterwork-dc, force-natural for Dev tests), with defaults in code. The
hit-overshoot-warn keys are removed. "Hit Percenage" is now spelled
"Hit Percentage". AC now builds against the same pinned MMOCore jar as
GemInfusion to read the base attribute.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
XxFran10xX added a commit that referenced this pull request Oct 10, 2026
…asterworks (#41)

* feat: show the hits done in the branding tool status

A branding right-click mid-project (sneaking or not) showed the recipe
and material groups but nothing about the hits, so there was no way to
tell how much work a piece had already had. The status now lists every
crafting hit with the hits done so far, plus the total, before the
finish and cancel lines. All hits are listed, even ones the recipe does
not use, and no needed counts are shown, so nothing about the recipe is
given away. Goldsmithing gets the same view in GemInfusion #39.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat: finish forging with any hits, and a d20 Strength roll for Masterworks

Forging refused extra hits once a hit type had enough, and refused to
finish until every type was exactly complete. Its refusal told the player
the needed counts ("You only have 5 out of 12 Metal hits"). Like
goldsmithing (GemInfusion #39), a piece can now be finished with any
number of hits once its materials are in. Too few or too many hits only
lower the Hits %, and with it the quality. The finish-time "over-reliance"
message is gone too, so the final Hits % is the only feedback. The hit
title (Metal hits: x/needed) and the refusal of a hit type the piece
does not need at all are unchanged.

Finishing also rolls d20 + a modifier from the crafter's base Strength,
like /roll, shown only to them as "Craft roll". A natural 20 always
succeeds and a natural 1 always fails. A Masterwork now needs 100% hits
and a total of 20+ (or a natural 20); perfect hits that miss become the
tier below (Gleaming: Radiant socket / Greater rune slot). The roll never
touches stats, which still come only from the materials, so every
Masterwork has the best stats its materials give. Staff-built pieces
with a set quality do not roll. Alloys are unchanged.

Settings live under d20 in config.yml (modifier table, attribute,
masterwork-dc, force-natural for Dev tests), with defaults in code. The
hit-overshoot-warn keys are removed. "Hit Percenage" is now spelled
"Hit Percentage". AC now builds against the same pinned MMOCore jar as
GemInfusion to read the base attribute.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat: crafting XP follows the Hits %

With any-hit finishing, a piece finished with no hits still paid the full
crafting XP. XP is now the set XP times the finished piece's Hits %
(a staff craft's set quality), so a perfect piece pays all of it and an
unworked one pays nothing. xp-min-percent in config.yml (default 0) sets
a floor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: mention the craft roll and XP scaling in the README

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: staff crafts pay XP for the hits actually done

A staff craft with a set quality paid XP from that quality, so a forced
craft could pay for work nobody did. XP now always follows the real
Hits %; the set quality only changes the piece.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: XxFran10xX <318299142+XxFran10xX@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant