feat(scripting): typed layer/skill constants + auto-derived kind; fix GameServer image build #212

Merged
marco merged 2 commits from feat/scripting-dx into main 2026-07-25 23:23:30 +02:00
Owner

Summary

Two follow-ups on top of the just-merged inventory epic (#209/#211), bundled per request:

1. fix(ci) — GameServer image build. The Docker publish --no-restore was failing (IsoMmo.Scripting/obj/project.assets.json not found): the GameServer references IsoMmo.Scripting (#183) but the Dockerfile only copied the Shared + GameServer csproj into the cached restore layer. Copy IsoMmo.Scripting.csproj too. Verified by building the image locally (restore + publish now pass).

2. feat(scripting) — typed closed-vocabulary def fields + auto-derived kind (DX). Establishes a rule and applies it:

  • Closed-vocabulary fields are typed constants generated from the C# enum, exactly like Messages.*. layer / skill on the weapon/item defs now read layer = Layer.OneHanded, skill = Skill.Swordsmanship — LuaLS-autocompleted, drift-free (values reflected from the enum), and validated at load (an invalid skill/layer is a fatal diagnostic, not silently accepted). EquipLayer/SkillName moved to IsoMmo.Shared/Protocol so the scripting host can reflect them without referencing GameServer (layering gate intact; enum ordinals unchanged → no wire/save change, no ProtocolVersion bump).
  • kind is now optional on item{}/weapon{} defs — it defaults to the FQN leaf lowercased (Items.Weapons.Bow"bow"), with an explicit override still allowed; derived-kind collisions are caught. Removes the redundant hand-written line without touching kind's wire/art/catalog/persistence role.
  • Rule recorded in src/IsoMmo.Scripting/CLAUDE.md (hard gate) + a ## Design checklist bullet in the root CLAUDE.md; docs/scripting.md updated (references the generated defs, doesn't mirror the enum values). api.d.lua regenerated.

Screenshots / recording

N/A — no visible/runtime change. The Lua constants are an editor/build-time DX improvement; the CI fix is build-only.

How it was tested

  • just lint (CSharpier + analyzers) — 0 warnings; just test — all green (Scripting 32 incl. new host-rejects-invalid + kind-derivation + api-def assertions and the drift-check, GameServer 271, Client.Core 147, Auth 19, +others); just check-docs clean; just lua-lint (luacheck + lua-language-server) clean — the content type-checks against the generated ---@enum defs.
  • Docker: built src/IsoMmo.GameServer/Dockerfile locally (context = repo root) — restore + publish succeed.

Checklist

  • just lint passes (zero warnings)
  • just test is green
  • The whole solution builds (client and tools included)
  • Multi-platform preserved (pure .NET; enums moved within Shared; no OS-specific dependency)
  • Tests added/updated for this change
  • Linked — follow-up to the #209/#211 scripting layer; no separate issue (bundled)
## Summary Two follow-ups on top of the just-merged inventory epic (#209/#211), bundled per request: **1. `fix(ci)` — GameServer image build.** The Docker `publish --no-restore` was failing (`IsoMmo.Scripting/obj/project.assets.json not found`): the GameServer references `IsoMmo.Scripting` (#183) but the Dockerfile only copied the Shared + GameServer csproj into the cached restore layer. Copy `IsoMmo.Scripting.csproj` too. Verified by building the image locally (restore + publish now pass). **2. `feat(scripting)` — typed closed-vocabulary def fields + auto-derived `kind` (DX).** Establishes a rule and applies it: - **Closed-vocabulary fields are typed constants generated from the C# enum**, exactly like `Messages.*`. `layer` / `skill` on the weapon/item defs now read `layer = Layer.OneHanded`, `skill = Skill.Swordsmanship` — LuaLS-autocompleted, drift-free (values reflected from the enum), and **validated at load** (an invalid `skill`/`layer` is a fatal diagnostic, not silently accepted). `EquipLayer`/`SkillName` moved to `IsoMmo.Shared/Protocol` so the scripting host can reflect them without referencing `GameServer` (layering gate intact; enum ordinals unchanged → no wire/save change, no `ProtocolVersion` bump). - **`kind` is now optional** on `item{}`/`weapon{}` defs — it defaults to the FQN leaf lowercased (`Items.Weapons.Bow` → `"bow"`), with an explicit override still allowed; derived-kind collisions are caught. Removes the redundant hand-written line without touching `kind`'s wire/art/catalog/persistence role. - **Rule recorded** in `src/IsoMmo.Scripting/CLAUDE.md` (hard gate) + a `## Design checklist` bullet in the root `CLAUDE.md`; `docs/scripting.md` updated (references the generated defs, doesn't mirror the enum values). `api.d.lua` regenerated. ## Screenshots / recording N/A — no visible/runtime change. The Lua constants are an editor/build-time DX improvement; the CI fix is build-only. ## How it was tested - `just lint` (CSharpier + analyzers) — 0 warnings; `just test` — all green (Scripting **32** incl. new host-rejects-invalid + kind-derivation + api-def assertions and the drift-check, GameServer 271, Client.Core 147, Auth 19, +others); `just check-docs` clean; `just lua-lint` (luacheck + lua-language-server) clean — the content type-checks against the generated `---@enum` defs. - Docker: built `src/IsoMmo.GameServer/Dockerfile` locally (context = repo root) — restore + publish succeed. ## Checklist - [x] `just lint` passes (zero warnings) - [x] `just test` is green - [x] The whole solution builds (client and tools included) - [x] Multi-platform preserved (pure .NET; enums moved within Shared; no OS-specific dependency) - [x] Tests added/updated for this change - [x] Linked — follow-up to the #209/#211 scripting layer; no separate issue (bundled)
The GameServer references IsoMmo.Scripting (#183) but the Dockerfile only
copied Shared + GameServer csproj before the cached restore, so the
--no-restore publish failed (Scripting's project.assets.json missing). Copy
the Scripting csproj into the restore layer too.
feat(scripting): typed layer/skill constants + auto-derived kind (DX)
Some checks failed
ci / Lua content lint (pull_request) Successful in 33s
ci / Lint & Test (pull_request) Has been cancelled
e9cfd417eb
Closed-vocabulary def fields are now typed constants generated from the C#
enum, like Messages.*: layer=Layer.OneHanded, skill=Skill.Swordsmanship —
LuaLS-autocompleted, drift-free, and validated at load (an invalid value is a
fatal diagnostic). EquipLayer/SkillName moved to IsoMmo.Shared/Protocol so the
scripting host can reflect them without referencing GameServer (ordinals
unchanged; no wire/save change). kind is now optional on item/weapon defs —
it defaults to the FQN leaf (Items.Weapons.Bow -> "bow"), with an explicit
override still allowed; derived-kind collisions are caught. Rule recorded in
Scripting/CLAUDE.md + the root Design checklist. Regenerated api.d.lua.
marco force-pushed feat/scripting-dx from e9cfd417eb
Some checks failed
ci / Lua content lint (pull_request) Successful in 33s
ci / Lint & Test (pull_request) Has been cancelled
to b4ee644f62
All checks were successful
ci / Lua content lint (pull_request) Successful in 1m1s
ci / Lint & Test (pull_request) Successful in 8m22s
2026-07-25 23:13:17 +02:00
Compare
marco merged commit 361967fc53 into main 2026-07-25 23:23:30 +02:00
marco deleted branch feat/scripting-dx 2026-07-25 23:23:30 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
marco/IsoMmo!212
No description provided.