Builds: yes. The previous commit's pin test failed on '.' (a dot last is refused by its own rule).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
layout_revision(shape, hardpoints) is the revision rule replace_layout and Package share.
SHIP_ID_CHARS and RESERVED_SHIP_IDS mirror ShipAuthoringStore.RequireShipId; ShipSchemaPinTests
sweeps every character and every candidate stem against the C# rule. ship_cc errors no longer
carry the path, mount id, anchor id or object name. C# tests: create judges the ID not the
display name, FindRoot answers the working directory itself, short trailing-dot IDs.
Builds: yes (C# test edits and Python only).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MODEL_ASSET_SLOT, ANCHORS_SLOT and ANCHOR_MEMBERS sit beside the other slot constants and ShipSchemaPinTests binds them
to ShipAuthoring's and ShipAnchor's [Key]s. replace_visual carries an anchor's slots past Order by Id, refuses a blank
or duplicate id, a wrong-length row and a changed ship id, and leaves the hull record and the lines alone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Load reads the raw ship authoring payload and refuses a non-nil retired key 1 (the
pre-S1 embedded hull) naming the old shape, so a stale hull is no longer silently
ignored; ship_cc.py refuses the same file on read and therefore on every save.
A hull naming both a Unity prefab and a visual is refused by one predicate
(ShipAuthoringStore.RequireOneBody), called by Validate and by Compose over every hull
in the derived catalog, shipped ones included; a whitespace-only Prefab is unset. This
replaces the mod-ship-only "cannot name a Unity prefab" check.
The validator also refuses non-finite or negative hardpoint Armor and FiringArc, an
undefined HardpointType or ItemRotation, and an anchor Role outside the eight the
schema documents.
Load wraps MessagePack decode failures with the file path. Python replace_layout
refuses non-boolean layout and hardpoint-footprint cells.
Tests: exact Visual key comparison, HullData.Visual at key 32, a save refreshing
stored_at, plus one case per new refusal. HullData.Visual is now [Inspectable] like
Prefab (Unity editor only; not compiled here).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A mod ship file now holds a HullData at mod-hull:<id> and the ShipAuthoring
visual package at mod-ship:<id>. HullData.Visual (key 32) is the typed ref
between them; ShipAuthoring.Hull (key 1) is retired.
- One joint validator over (hull, visual) is the only semantic check; Load
owns the file structure (one hull, one visual, deterministic keys).
- Compose copies the mod store's records verbatim, so the derived catalog
holds one hull per mod ship.
- ship_cc.py edits the hull record's slots directly; the body[HULL_SLOT]
indirection is gone.
- The package fixture is generated from ShipAuthoringTests.Fixture() (glTF
scene included) and exported when AETHERIA_SHIP_FIXTURE_DIR is set.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
ship_cc.py edited a ShipAuthoring record by bare slot numbers and hardpoint
positions (hp[3], hp[7:], raw[0..6]), and __init__.py copied the
HardpointType and ItemRotation enums by position. Nothing tested either
file and nothing tied the numbers to the C# [Key] attributes that own them.
- ship_cc.py names its schema facts once: the four record slots (each
commented with the C# member it mirrors), HARDPOINT_MEMBERS (HardpointData
member names in slot order), and the two enum name tuples. Hardpoint rows
are built and read through encode_hardpoint/decode_hardpoint; replace_layout
and the Blender operators no longer index a row by literal. __init__.py
builds its enum items from the tuples. The rotation label
"Counterclockwise" becomes "CounterClockwise", matching the C# member.
- tools/blender/tests/test_ship_cc.py (30 unittest cases, bpy-free, needs
CultLib's cultcache-py and msgpack): read, replace_lines, read_layout,
replace_layout (untouched slots and later-schema hardpoint slots preserved
by mount id, schema catalog preserved, every refusal leaves the file
byte-identical), the row codec, and capture_grease_pencil against stand-in
objects.
- ShipSchemaPinTests (C#, 7 cases) reads ship_cc.py and fails when a slot
constant, a HARDPOINT_MEMBERS name or position, or an enum name/value
disagrees with the C# types, and when a serialized ship no longer has the
nested array shapes the Python indexes (schematic [[w, h, cells]], cells
x-major, hardpoint transform and footprint positions).
Reading the slots from the file's schema catalog instead was rejected: the
catalog lists only document members, and Hull, Shape and HardpointData are
nested types it does not describe.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>