Commit Graph

11 Commits

Author SHA1 Message Date
JonKazama-Hellion 12013ba6e6 Modul 01 Hotfix A1: AnvilRecipe.RecipeLevelTableClassJobLevel ergaenzt
01-RecipeData Rev 6 (A1) added the field as the character-level
equivalent of a recipe's RecipeLevelTable, so module 02 can branch the
mod-penalty in BaseProgress and BaseQuality. The adapter resolves it
from the existing RecipeLevelTable.Value in the recipe walk.

- AnvilRecipe.cs: new required byte property after RecipeLevel, with
  a why-comment that points consumers at module 02 and warns against
  confusing the field with the row-id one above it.
- LuminaRecipeAdapter.cs: levelTable.ClassJobLevel assignment in the
  Recipe walk - levelTable was already resolved earlier in the loop.
- RecipeDataAdapterLoadStep.cs: new pass criterion #9 that asserts at
  least one recipe carries a positive RecipeLevelTableClassJobLevel.
  Catches a silent RecipeLevelTable-walk failure that would otherwise
  only surface inside the simulator. Existing Cosmic-surface check
  shifted to #10 to keep the spec numbering stable.

Build clean (0/0), csharpier clean.
2026-05-28 18:58:56 +02:00
JonKazama-Hellion ce3fdda51c Modul 01 Hotfix A2: AnvilRecipe.IsSplendorCosmic entfernt
Splendorous-Tool-Bonus is character-equipment state, not recipe state.
The flag moved to the simulator's stats layer (CraftStats.HasSplendorousTool
in module 02) per the 01-RecipeData Rev 6 spec polish (A2).

- AnvilRecipe.cs: IsSplendorCosmic property removed. Cosmic doc-block
  trimmed to four flags (IsCosmic + two MissionHas* + IsIshgardExpert)
  and now points consumers at the stats-layer for the Splendor branch.
- LuminaRecipeAdapter.cs: assignment in the recipe walk removed.
  ValidateCosmicInvariant drops the IsSplendorCosmic implication
  (MissionHas* checks unchanged).
- ConditionMechanicsTable.cs: header comment rewritten to describe
  Splendor as a stats-layer override rather than a recipe-flag override.

Sweep over Anvil/RecipeData/, Anvil/SelfTest/, Anvil/Hosting/,
Plugin.cs, and PluginHostFactory.cs: zero remaining references to
IsSplendorCosmic. Build clean (0/0), csharpier check clean.
2026-05-28 18:30:32 +02:00
JonKazama-Hellion 8e624e509a chore(v0.1.1): bump version and add repo.json + CHANGELOG.md
Versions-bump from 0.1.0 to 0.1.1 in csproj. Extend Anvil.yaml
changelog with the v0.1.1 block; the v0.1.0 entry stays below as
release history.

Add repo.json (Custom-Repo manifest, AssemblyVersion 0.1.1.0,
download links pointing at the v0.1.1 release tag) and CHANGELOG.md
(root-level history file with v0.1.1 hotfix notes and the v0.1.0
foundation block).

This is the scaffolding commit for the Module 01 spec-sync hotfix
cycle. The five spec-edit commits (A1, A2, A3, A4, A5) follow.
2026-05-28 17:59:36 +02:00
JonKazama-Hellion 186e02c3ee fix(plugin): register UiBuilder.OpenConfigUi / OpenMainUi stubs
Dalamud's plugin validator flagged two issues on v0.1.0:
- "The plugin does not register a config UI callback."
- "The plugin does not register a main UI callback."

v0.1.0 ships the RecipeData layer only - the actual SettingsWindow
and MainWindow arrive with module 08 (UI). To pass validation and to
give users a useful response when they click "Open Settings" or "Open
Main" in the plugin installer, both callbacks now fire toast
notifications via INotificationManager that point at the roadmap.

The handlers wire up in the constructor right after the host build
and unwire in DisposeAsync. INotificationManager joins the Block A
Dalamud services in PluginHostDependencies + PluginHostFactory so the
DI container also exposes it for later modules.
2026-05-27 22:59:01 +02:00
JonKazama-Hellion d8efc213e3 chore: add pre-push preflight + setup-hooks
Four-block pre-push gate matching the HellionChat pattern:

- Block A (verify-version-consistency.sh): csproj <Version> vs
  repo.json AssemblyVersion / TestingAssemblyVersion / DownloadLink*
  tag presence. Tolerant of repo.json being absent so v0.1.0 (which
  has no public release manifest yet) does not fail at push time;
  the missing-file path turns into the full cross-check once repo.json
  lands.
- Block B: dotnet build Anvil.sln -p:Platform=x64 -c Release. Platform
  pin is forge-wide (Forgeimizer v0.1.0 lesson: solution build defaults
  drift to AnyCPU otherwise).
- Block C: dotnet csharpier check ./Anvil. Catches the accumulated
  formatter drift that hit HellionChat v1.5.6 (12 files) when only
  build was checked per task.
- Block D: markdownlint-cli2 over the repo's *.md files (excludes node_modules,
  bin, obj, .claude, CLAUDE.md).

Plus setup-hooks.sh as the one-shot installer that points
core.hooksPath at .githooks/ and chmods the scripts.

README.md: MD040 fix for the custom-repo URL fence (added text language tag).
2026-05-27 22:25:35 +02:00
JonKazama-Hellion 90803bcd3c feat(bootstrap): wire DI host, hosted services, and plugin entry
The plugin is now loadable. Dalamud injects five services into the Plugin
constructor (Lightless pattern), the constructor builds the generic-host
container synchronously, and PluginLifecycle drives StartAsync from
LoadAsync. Module 02+ extends PluginHostFactory; this file set stays put.

- PluginHostDependencies (record): bundles the five Dalamud services
  v0.1.0 needs (IDalamudPluginInterface, IPluginLog, IDataManager,
  IFramework, ISelfTestRegistry).
- PluginHostFactory.Build: HostBuilder + AddDalamudLogging + the four
  service blocks (Dalamud services, Anvil singletons, ISelfTestStep
  collection, IHostedService init chain). Every registration uses an
  explicit factory lambda - the default activator only sees public
  ctors and Anvil follows the internal-sealed convention.
- PluginLifecycle (IAsyncDisposable): owns Host.StartAsync, marshals the
  Host.Dispose call onto the framework thread, idempotency guard via
  Interlocked, ExceptionDispatchInfo.Capture preserves the original
  load-throw stack when a failure cascades.
- Plugin (IAsyncDalamudPlugin): constructor injection of the five
  Dalamud services, builds the dependencies record, kicks off the host
  build, hands DisposeAsync to the lifecycle.
- Hosting/RecipeDataLoadHostedService: dispatches LuminaRecipeAdapter
  .LoadInternal onto the framework thread on StartAsync. Lumina sheet
  reads have no documented thread safety; conservative default.
- Hosting/SelfTestRegistrationHostedService: collects every
  ISelfTestStep registration from DI and hands them to
  ISelfTestRegistry.RegisterTestSteps once the host is up.
- SelfTest/RecipeDataAdapterLoadStep: nine pass criteria per spec §4.1
  (IsLoaded, RecipeCount > 0, ActionCount in 30..80, BuffsByKind.Count
  == 14, ConditionsByKind.Count == 11, Foods >= 30, Medicines >= 5,
  BasicSynthesis.RowIdByClassJob[8] == 100001, Cosmic-surface
  silent-degradation warning). Returns Waiting while the catalog is
  still loading.
- Infrastructure/Logging trio: DalamudLogger maps
  Microsoft.Extensions.Logging levels to IPluginLog, the provider
  emits an Anvil bootstrap banner with a Forge-Bronze fingerprint on
  ctor, the extension wires the provider into the ILoggingBuilder via
  TryAddEnumerable.
2026-05-27 21:58:38 +02:00
JonKazama-Hellion 401ebc9495 feat(recipedata): add LuminaRecipeAdapter + AnvilStrings resx
The adapter is the only place in the plugin that touches Lumina and
Dalamud types - everything outside Anvil.RecipeData.Internal stays on
the BCL surface (Critical Boundary per 00-Anvil-Scope §3.3).

- LuminaRecipeAdapter: walks Status, CraftAction, Action, Item, ItemFood,
  and Recipe + RecipeLevelTable, builds the AnvilXxx records, and
  swaps the CatalogState into RecipeDataCatalog in one atomic write.
  Cosmic actions normalise the Action-sheet ClassJob=-1 sentinel to
  RowIdByClassJob key 0 (spec §2.3.1); the legacy ARR singletons
  (Manipulation 278, Waste Not 279, Innovation 284, Waste Not II 285)
  drop out via the PrimaryCostValue == 0 filter (spec §3.1 #3). The
  CraftAction sheet wins the canonical icon at the CRP variant
  (ClassJobId 8). Per-job rows are cross-checked for Cost, ClassJobLevel,
  and Specialist consistency; mismatches log a warning.
- SH-15 option B is hard-wired: every AnvilRecipe ships with
  MissionHasMaterialMiracle = false, MissionHasSteadyHand = false, and
  IsSplendorCosmic = false in v0.1.0. IsCosmic is still set from
  Recipe.Number == 0 so the catalog can label Cosmic recipes; the WKS
  mission sheet chain is not walked. v0.2.0 will replace those constant
  assignments with the resolver and the rest of the adapter stays put.
- The adapter invariant (Cosmic sub-flag implies the master IsCosmic
  flag) throws on inconsistent recipe states at catalog-build time so
  v0.2.0+ catches a broken WKS resolver before it corrupts the simulator.
- ItemFood walk uses ItemAction.Data[0] (48 = "well fed", 49 =
  "medicated") instead of an ItemAction.Type column that does not exist
  in the current Lumina schema. The bonus extractor filters
  ItemFood.Params to the three crafting BaseParam ids (CP=11,
  Craftsmanship=70, Control=71). Item rows are populated only for the
  ItemIds that recipes / foods actually reference - no 50k-row mirror.
- AnvilStrings.resx + AnvilStrings.de.resx + AnvilStrings.Designer.cs:
  Localization layer for condition display names and the SelfTest step
  name. The adapter looks the condition strings up through the generated
  ResourceManager so culture-switching is a no-restart change later on.
2026-05-27 21:27:55 +02:00
JonKazama-Hellion eb5753eea6 feat(recipedata): add catalog + load result, wire csharpier
Two concerns bundled into one commit because the csharpier tool restore
reformatted four earlier files as soon as the manifest landed:

- .config/dotnet-tools.json: csharpier 1.2.6 as local tool, follows
  the standard .config layout (dotnet tool restore will find it).
- Anvil/packages.lock.json: produced by dotnet restore, pinned alongside
  the csproj's RestorePackagesWithLockFile=true.
- Anvil/RecipeData/RecipeDataLoadResult.cs: public record carrying the
  adapter's load-pass summary (counts + duration + warnings). Surfaced
  to the SelfTest step and future UI status surfaces.
- Anvil/RecipeData/RecipeDataCatalog.cs: public DI singleton with all
  seven dictionary lookups, the two helper methods (ActionsForClassJob,
  TryResolveActionRowId), and the four meta properties from spec §2.7.
  Backed by a private CatalogState record that the adapter swaps in via
  a volatile reference - readers either see the empty initial state or
  the fully populated post-load snapshot, never a partial mid-build.
  TryResolveActionRowId carries the Cosmic-sentinel logic so hook code
  does not need to know about the CosmicOnly flag itself.
- Reformatting in AnvilAction.cs, ActionMechanicsTable.cs,
  ConditionMechanicsTable.cs, and Anvil.csproj: csharpier-mandated
  line-wrap / blank-line tweaks. No semantic changes.
2026-05-27 20:54:14 +02:00
JonKazama-Hellion d7e8c42cc7 feat(recipedata): add hardcoded mechanics tables
Three game-mechanics tables for the simulator-relevant constants that the
Lumina sheets do not expose, plus the reverse name map the adapter uses
to walk the CraftAction + Action sheets.

- ActionMechanicsTable: 38 entries with Category, CP cost, durability,
  efficiency, IQ-stack bonus, charges, granted buff, and flags.
  Cross-checked against the spec mechanics table in 01-RecipeData.md
  §2.3.2 (verified there against Artisan's RawInformation/Character/
  Skills.cs). Combo-state CP costs (Standard/Advanced Touch) carry the
  base value; the simulator applies the discount. TrainedEye uses
  short.MaxValue as the sentinel for "fill Recipe.QualityMax in one
  step"; ByregotsBlessing carries base EfficiencyQuality=100 with the
  IQ multiplier added by the simulator.
- BuffMechanicsTable: 14 entries with StatusId, Icon, StackMax, Behavior,
  the three duration fields (Steps / Seconds / Actions populated per
  Behavior), Category, and LegacyStatusId for the older Innovation 259
  and Manipulation 258 ids. Cross-checked against ffxiv-datamining
  Status.csv (StatusId / Icon / StackMax) and Artisan's tooltip-derived
  step durations. Expedience uses the explicit StatusId 3812 - the other
  two "Expedience" rows (2712 / 3092) are non-crafting status effects
  that would otherwise produce an ambiguous name match.
- ConditionMechanicsTable: 11 entries with Quality / Progress / CP /
  Durability multipliers plus a BaseProbability slot. Robust mirrors
  Sturdy's durability discount and keeps Quality neutral (per the
  spec mechanics table - the enum doc comment in AnvilCondition.cs
  predates rev 5 and is noted as superseded in the table header).
  SplendorCosmic's Good=1.75 override lives in the simulator.
  BaseProbability stays 0.0; the static catalog has no useful per-recipe
  spawn distribution because FFXIV derives that from Recipe.IsExpert +
  RecipeLevelTable.Stars at runtime.
- ActionKindByName: reverse map from English action names to
  AnvilActionKind, plus the Action-sheet whitelist (seven step-counter
  buff actions + two Cosmic singletons) used to filter the Action sheet
  walk down to the crafting subset.
2026-05-27 20:25:52 +02:00
JonKazama-Hellion 47790a3f68 feat(recipedata): add plain-data records and enums
Module 01 public-API surface: six sealed records with init-only
properties plus their nine enums. All BCL-only - no Lumina or Dalamud
types in any public property, which is what keeps the simulator and
catalog xUnit-testable per the Critical Boundary in 00-Anvil-Scope §3.3.

- AnvilRecipe + AnvilRecipeIngredient: flat representation of the
  Recipe + RecipeLevelTable sheet pair with the five Cosmic-Exploration
  flags. v0.1.0 ships with MissionHas* always false (SH-15 option B);
  the schema stays in place so v0.2.0 can wire the WKS mission sheet
  without touching the type.
- AnvilItem: slim per-recipe / per-food item view (full ~50k-row item
  mirror is left to the UI layer).
- AnvilAction + AnvilActionKind + AnvilActionCategory + AnvilActionFlags:
  one logical action per Kind value with RowIdByClassJob mapping; Cosmic
  actions use ClassJobId 0 as the sentinel for "every crafter".
  AnvilActionFlags bit 1 << 2 is intentionally vacant (ConsumesGreatStrides
  was removed in spec rev 5; consumption logic lives in 02-CraftingSimulator).
- AnvilBuff + AnvilBuffKind + AnvilBuffBehavior + AnvilBuffCategory:
  static buff catalog entry with the duration field that matches Behavior
  (Steps / Seconds / Actions). Two Cosmic buffs (MaterialMiracleBuff,
  StellarSteadyHandBuff).
- AnvilCondition + AnvilConditionKind: eleven conditions including the
  Cosmic Robust variant. DisplayName comes from AnvilStrings.resx, not
  Lumina (the Status sheet does not expose the crafting condition labels
  cleanly).
- AnvilFood + AnvilFoodBonus + AnvilFoodKind + AnvilFoodStat: ItemFood
  mirror with IsRelative flag (percentage vs flat bonus).
2026-05-27 19:53:54 +02:00
JonKazama-Hellion 96553a849a chore: bootstrap Anvil repo skeleton
First commit on feature/v0.1.0 establishes the Hellion Forge plugin
scaffold:

- .gitattributes: Linux-first LF defaults, Windows-script CRLF exceptions,
  binary markers for fonts / images / archives. Pre-empts the
  Forgeimizer pre-push hook crash that was caused by Asriels CRLF default.
- .editorconfig: Hellion Forge .NET conventions
  (private fields _camelCase, Allman braces, var-preferred).
- .gitignore: VisualStudio baseline + secrets bucket + Anvil.Tests
  excluded (build-suite lives in the local Hellion Build test repo).
- LICENSE: MIT, Hellion Online Media 2026.
- NOTICE.md: goodwill attribution to Craftimizer and clean-room
  anonymisation note.
- PRIVACY.md: zero-telemetry statement matching 00-Anvil-Scope.
- README.md: v0.1.0 status + planned-feature outline + custom-repo URL.
- Anvil.sln + Anvil/Anvil.csproj: Dalamud.NET.Sdk/15.0.0, x64 platform
  pinned (forge-wide rule), Microsoft.Extensions.Hosting stack closed-range
  pin to 10.0.7 matching HellionChat v1.5.0. No DalamudPackager.targets
  override - SDK 15 default packager handles images / icon / image_urls.
- Anvil/Anvil.yaml: plugin manifest with explicit icon_url / image_urls
  (top-level fields required for SDK 15 default packager) and a v0.1.0
  changelog entry that names RecipeData as the first module.
2026-05-27 19:16:36 +02:00