Skip to content

Fix oblong fig_leader PNG URLs missing _stadium suffix - #13

Draft
halestom15 wants to merge 42 commits into
halestom15:Mandos+MacFixfrom
ironsquadronfr-hub:mac-projector-fallback
Draft

Fix oblong fig_leader PNG URLs missing _stadium suffix#13
halestom15 wants to merge 42 commits into
halestom15:Mandos+MacFixfrom
ironsquadronfr-hub:mac-projector-fallback

Conversation

@halestom15

Copy link
Copy Markdown
Owner

Overlays.ttslua referenced range_fig_leader_long.png and range_fig_leader_snail.png, but the assets shipped in mod/data/mac-fallback-assets/ are named with the _stadium suffix (consistent with generate_overlay_assets.py output and the inline copy in mac-patcher/patch_save_for_mac.py). TTS hit a GitHub 404 and surfaced "Load image failed unsupported format: UNKNOWN".

Overlays.ttslua referenced range_fig_leader_long.png and
range_fig_leader_snail.png, but the assets shipped in
mod/data/mac-fallback-assets/ are named with the _stadium suffix
(consistent with generate_overlay_assets.py output and the inline
copy in mac-patcher/patch_save_for_mac.py). TTS hit a GitHub 404
and surfaced "Load image failed unsupported format: UNKNOWN".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@halestom15
halestom15 marked this pull request as draft May 22, 2026 03:22
@halestom15 halestom15 closed this May 22, 2026
@halestom15 halestom15 reopened this Jun 3, 2026
Martin Pourrat and others added 26 commits August 11, 2026 03:47
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Material references the player's built-in Unlit/Transparent via
resources/unity_builtin_extra (like every working vanilla bundle) instead
of embedding a custom shader that TTS U6 on Mac refuses to load.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same normals/UVs/caps as the round silhouettes, so the look matches.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A ray hit only counts as ground if it is not the ignored object, not an
object still in motion (movement template falling into place the frame
the overlay spawns), and not the hovering "Maximum Move" Windows bundle
(floats at +20 in windows mode and caught the center ray). Applied to
all 6 raycast sites; fixes the MaxMove fill decal floating above its
border ring on first spawn.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Mac fallback spawns silhouettes as Custom_Model because the bundles'
embedded shaders do not load on Metal. Oblong bases used hand-built
stadium meshes approximated from the marker cylinder, whose outline reads
as less precise than the Windows original. These are the real meshes
(silh_new_long_1in / silh_new_snail_1in) pulled out of the vanilla
bundles with UnityPy, so the Mac path changes only the rendering, not the
geometry. Faces rewritten as v//vn: the meshes carry no UVs and UnityPy
emitted dangling vt indices that TTS would reject.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The meshes lifted straight out of the vanilla bundles rendered faceted as
Custom_Models: their baked per-vertex normals fight the player's shader.
The hand-built stadiums that looked right shipped no normals at all, so
TTS computed and smoothed them itself. Same treatment here, plus the UVs
the raw export lacked. Geometry is untouched, so the outline stays the
Windows one (elliptical caps, not the semicircles the stadiums assumed).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The meshes lifted from the vanilla bundles render badly as Custom_Models
whatever we do to their normals: their topology differs from the marker's,
and it is the marker topology (82 verts, 100 faces, UVs, no baked normals)
that makes the round bases light correctly.

So move the stadium vertices onto the vanilla outline instead. Splitting a
cylinder left semicircular caps; the real bases are elliptical and about
20% shallower (cap depth 1.55 for a 2.0 half-width). Width, cap start and
tip now match the bundle meshes to within a thousandth.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Keeps the bundle geometry vertex for vertex and only rebuilds the normals.
The bundles' baked normals render the curved flanks faceted; shipping none
at all makes TTS average across the rim where the fan caps share the flank
vertices, so the sides light up like the top. Cluster each vertex's faces
by a 45-degree threshold instead: the flanks smooth along the arc, the rim
stays a hard edge. 48 vertices become 92, geometry unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
gRangeTrigger and gCohesionTrigger toggle by fig GUID, so a stale overlay
left by the hover hotkey made the button's first click turn it OFF instead
of ON. Clear the overlay before triggering, and clear it again on the OFF
branch: exitTargetingMode/clearRangeRulers only reach the vanilla bundle
ruler, so without it the Mac rings stayed on screen.

Also guard both entry points against a nil selectedUnitObj.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A text U+F8FF glyph renders as a missing-glyph box on Windows clients, so
the button uses a white PNG sprite tinted per state instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
In Windows (OFF) mode the fallback was supposed to step aside and let the
vanilla mod draw. It did not, in three distinct ways:

- Range: the vanilla bundle ruler is spawned from the GLOBAL scope
  (!/RangeRulers is required by Global; figs only require !/Cohesion), so
  fig.call("spawnRangeRulerOriginal", fig) always raised "no such
  function". The pcall swallowed it and we fell through to the Mac
  renderer -- Windows mode silently drew Mac overlays. Call the Global
  alias, resolved at call time since !/RangeRulers loads after us.
- Cohesion: vanilla spawnCohesionRuler RESPAWNS rather than toggling, so
  a second click just redrew the ruler and it could never be turned off.
  Read and clear the Projector in the fig scope, where it lives.
- Silhouettes: the dual path was missing outright, and the bundle URL was
  rewritten even in OFF mode.

Also collapse the per-seat mode plumbing into one table-wide overlayMode:
the Lua runs on the host only, so a per-player renderer was never
reachable (see the per-seat POC). gGetMode and gGetDeploymentMode now
both read it, macModeToggle wipes both renderers' overlays so nothing
stale lingers across a switch, and the legacy mode-picker panel is
dropped from saves that still carry one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…draw

Backport of the engine work validated in game on 11 August:

- Replace the mode modal with one table-wide toggle button in
  legionFloatingMenu (grey OFF like Welcome and Chess Clock, green ON),
  carrying the macAppleLogo sprite. Per-seat is abandoned: the overlay is
  visible to everyone, so a Windows player in original mode shows magenta
  to the Mac player regardless.
- Share a macHitIsGround filter across the six raycast sites, so the
  MaxMove fill no longer lands one spawn late. It ignores figures, moving
  objects, and the "Maximum Move" bundle that hovers at +20 in Windows
  mode.
- Coalesce macRedrawAll (one-frame defer plus a sorted signature, skipped
  when identical) so re-clicking at the same speed stops reprojecting the
  decals and the shadows stop shifting.
- Suffix the save name with [MAC PATCH] behind a guard instead of
  renaming outright.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Written before swapping the renderer from flat decals to real Projectors,
so the behaviour layer survives the change and can be checked in game
afterwards. Covers range, cohesion, MaxMove and deployment, object by
object; silhouettes and unit-ID tokens are out of scope now that their
bundles are fixed.

Records two divergences found while reading: mod/src RangeRulers.ttslua
overrides spawnRangeRuler/clearRangeRulers on the ~20 token scripts, which
is the pattern the patcher forbids after a reproducible TTS Mac crash, and
it calls gClearAllRange/gClearAllMaxMove which the patcher engine does not
define. The backport therefore runs the other way: align the source on the
patcher, removing overrides rather than adding them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The toggle no longer compensates for a platform: the bi-platform bundles
render on Metal, so it is now an optional set of enriched overlays that the
club offers, off by default. The Apple logo had become misleading.

- new sprite iron_squadron_logo.png, 128x128, white with the mark in the
  alpha channel so the button can tint it dark on grey and white on green;
  sized to fill 116 of the 128 px because the button is only 52 px wide and
  the wordmark turned to mush any smaller
- CustomUIAsset renamed macAppleLogo -> isqLogo with a fresh file name, TTS
  caching UI sprites by URL
- every player-facing string reworded, tooltips and the broadcast fired on
  each flip, with no mention of Mac left
- MaxMove now wiped along with range and cohesion when the mode flips; it
  used to stay on screen, drawn by the renderer just left behind

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Their bundles are repaired, so the vanilla Projector renders correctly on
both platforms and the dual path has no reason to exist. spawnBoundaryCell
and clearDeploymentBoundary go back to the exact upstream text, restored
from origin/main rather than retyped.

The toggle's scope is now three families: range, cohesion, MaxMove. The
spec's section 5 is kept but marked obsolete, as the record of what the
removed path used to do.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Martin's placement reference: the mark needs breathing room and reads
off-centre. Two changes, on a fresh file name because TTS caches UI sprites
by URL and the old one is already in his client.

- content down to 100 of the 128 px, so roughly 11% of margin
- centred on the alpha's centre of mass rather than its bounding box. The
  wordmark is dense on the right and the outline thin on the left, which put
  the mass 4.4% right of the geometric centre and made the whole thing read
  as shoved right. Margins land at 10 left / 18 right, matching the framing
  of the reference.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two gaps found while fixing the Metal rendering, neither of them macOS
specific: cohesion is missing on 35 units because only three base sizes have
a bundle, and the same range-0.5 offset could be shown on the range template.

Written as a validation request rather than a plan: what is missing, what it
would cost, what it changes for players, and the one question we cannot
answer for them, whether an enriched template should reach everyone or stay
behind the opt-in button.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Replaces the flat-decal renderer with one real Unity Projector per active
overlay. A Projector drapes over table relief and tracks its figure natively,
so the ground raycasts, the hand-built ring and stadium geometry, the
per-entry cache, the coalesced redraw signature and the PNG preload all go
away with it: 748 lines become 215.

Every removal now goes through macRemove, which destroys the Projector
before forgetting the entry, otherwise each click leaks an object. The
Projectors carry the vanilla names on purpose, so the mod's own sweepers
clean them up for free; when a sweeper destroys one we treat the overlay as
switched off rather than respawning behind it.

Also drops what left the toggle's scope: the unit-ID token numbers, the Mac
silhouette renderer, and the deployment dual path.

NOT yet validated in game. The first live run turned up two problems, one
fixed here (the token R button lacked the clear-before-trigger rule, so a
leftover hover overlay inverted it) and one that is a gap in the mod itself
(only three base sizes have a cohesion bundle).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The package existed but only on our disk, so the pull request described a
folder that was not in the branch. It is the durable half of the work: with a
model shipping every couple of weeks, whoever builds the bundles needs to
produce bi-platform ones without us.

- README: the cause, the one-line precision change to make in the shader
  sources, the build-twice-and-merge procedure, and the trap that cost us the
  most time (merging variants inside a single pass looks fine and renders
  wrong, because parameter binding tables are per pass, not per platform)
- BuildBiPlatformBundle.cs: an Editor menu entry plus a batch-mode entry point
- merge_subshader_bundles.py: the merge itself

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two root causes, not one. The known one is the missing Metal variant in
bundles built for Windows only. The second surfaced today: the glow
shaders read a vertex colour channel that no mesh in the mod actually has
(1 of 408, and it carries no custom shader). DirectX and OpenGL substitute
white for a missing channel, Metal substitutes black — and since those
passes are Blend One One, multiplying by zero adds nothing. Lightsabers,
eyes and shields were dark on Mac across 12 bundles, and nobody noticed
because they were no longer magenta.

patch_shader_vertexcolor.py neutralises that read for the macOS build only,
so the Windows SubShader stays byte for byte what it is today.

graft_metal_2019_1.py covers the units whose sources are lost: it grafts a
Metal SubShader into the published bundle, leaving meshes, textures and
materials untouched. It is a sibling of merge_subshader_platforms.py, not a
replacement — Unity changed the shader blob layout between 2019.1 and
2019.4, and each script refuses the other's format.

The published bundles span five Unity versions, so the graft has to be
built by the editor that produced the target. README.md carries the full
chain, the reasoning behind stacking a whole SubShader rather than merging
a pass, and the traps met along the way.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The hover hotkey sets forceFigMode so a hovered token shows the
fig-leader bands rather than its own single ring, and macResolveBundle
reads it -- but gRangeTrigger rebuilt the params table with figGUID
alone, so the flag never arrived and the branch was dead code.
showRangeOnHoveredModel already forwarded it, so the same gesture gave
two different results depending on which path it took.

Found by harness_projectors.py, which drives the Lua the patcher really
writes, outside TTS. 24 checks, all green now.

Also records an open arbitration in the spec: bases with no cohesion
bundle (huge, long, laat, epic, snail) draw nothing, like vanilla, where
the old decal engine fell back to the small radius.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Eight new bi-platform Projector bundles, built from the mod's own range
prefabs, with one thing added: a white band from the base edge out to 3in,
and range 1's orange starting at 3in instead of at the base.

Where the band lands, without a single hand-tuned value: grad is linear in
distance, so 3in sits exactly half way between the base edge (grad ==
uvShadow) and the range 1 edge. On the 27mm base that midpoint is 0.884295
where the exact analytic threshold is 0.884334 -- a thousandth of an inch.
It also works on the oblong materials, whose thresholds Allen tuned by hand
against an orthographic size that follows no formula (33.4, not 30.93):
they inherit that tuning for free.

Separate bundles on purpose. The repaired bundles are served from the TTS
cache under the mod's own Steam URLs, so anything added to them would show
in the mod's original mode too and the toggle would stop meaning anything
for Range. These are new assets with no UGC entry, served from the fork.
The band itself sits behind a _HALFBAND_ON keyword the mod's own materials
do not carry, so their rebuilds stay identical.

Only the hover hotkey reaches them; a token's own R button keeps the mod's
single-ring bundle.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Martin Pourrat and others added 15 commits August 14, 2026 01:31
Martin reported broken arc fragments crossing the middle of a snail base,
and only a snail base. Reproduced outside the game and fixed.

The cause: the BACK arcs are drawn on UVs displaced by _ArcOffset, but cut
by a base mask computed on the undisplaced ones, so they overhang the base
by roughly that displacement. It is -0.029 on long and -0.039 on snail, so
on long the overhang stays under the base edge and on snail it does not.
Same bug on both, visible on one.

The fix widens the cut for the arcs alone, through a new _ArcCut that
defaults to 0 -- `base` keeps serving the range bands, which must not move
by a thousandth. The mod's own materials carry no _ArcCut, so their
rebuilds are unchanged.

The bundles are renamed _v2 because TTS caches by URL: republishing under
the same name downloads nothing.

Also adds RenderProjectorTest, which is what made this findable. The
existing bench frames on the prefab's Renderers and a Projector has none,
so projectors could only ever be judged in game. This one builds the
scene a Projector needs -- a ground plane, the projector 20 units above it
at 90 degrees, an orthographic camera overhead -- and writes a PNG. It
also reports shader support, which caught a Windows-only bundle being
loaded on a Metal editor.

And BuildNamed, which builds only the bundles it is given: the full pass
rebuilds all 360 twice, ~4.5 min, where iterating on one visual now costs
30 seconds end to end.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The previous cut was too blunt: widening it for everyone erased the stray
fragments but opened a gap between the base and where the arcs start.

Zooming the render bench on the base settled it. The vanilla long ruler is
clean -- its four arcs stop symmetrically at the base edge. The vanilla
snail ruler carries two short fragments floating inside the base, detached
from anything, which is exactly what was reported. So the defect is snail
only, and long needs no correction at all.

The cut is now per material, and bisected against the render rather than
guessed: 0.008 still left two specks, 0.014 clears them without opening a
gap, 0.022 started to open one. long keeps 0, which is the vanilla cut
exactly.

The whole thing now sits behind _HALFBAND_ON, so the mod's own materials
compile the untouched branch. That was not true of the previous commit,
which changed their arcs too.

An attempt in between, kept out: cutting the back arcs in their own frame,
displaced by sqrt(2) * _ArcOffset along the base's long axis. It reads
right and the render disagreed -- it let the far pair run deep into the
base on long, which vanilla does not.

Bundles renamed _v3, TTS caches by URL.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Martin, in game: still a gap. The widened cut is what makes it -- it is a
monotone trade-off, measured on snail: 0 puts the arcs against the base and
brings the two stray fragments back, 0.008 shrinks them to specks with a
visible gap, 0.014 clears them with a clear gap.

His instruction is that the arcs start at the base, so the cut goes back to
0 on both oblongs, which is the mod's own cut exactly. The snail fragments
come back with it, as in the mod today. Clearing them without opening a gap
means reworking the shader's front/rear arc split, not pushing this value
further.

The property stays, defaulting to 0, so the lever is documented and there
if the rework needs it.

Bundles renamed _v4, TTS caches by URL.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Not the cut. _ArcOffset.

It splits the arcs into two families, one anchored toward the front of the
base and one toward the rear, so they radiate from both ends of a long base
instead of a single point. The wider the offset, the further apart the two
anchors -- and past a threshold the INNER TIP of the rear family emerges
from the side of the base. Those tips are the two fragments.

Measured on snail, changing that one value and nothing else:

  0        arcs converge at the centre, clean
  -0.029   clean            (this is the long material's own value)
  -0.033   two pixels
  -0.037   fragments visible
  -0.039   the reported defect (snail's shipped value)

So snail goes to -0.029. The anchors move 26% closer, which does not read
in play, and the defect goes without cutting anything: the arcs still meet
the base edge with no gap. _ArcCut stays at 0 everywhere -- it treated the
symptom.

Bundles renamed _v5, TTS caches by URL.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Martin was right twice: moving _ArcOffset on snail is not allowed, the
anchor spread is a property of that base size; and a translation of the
rear centre should not, on its own, make fragments appear.

It does not. The split does.

_ArcOffset moves the rear X along the base's long axis, but the plane
separating the front family from the rear one is placed at |_ArcOffset|,
not at where that X is actually centred. So the rear branches get cut
across rather than at their apex, and the two stumps remain. They stay
hidden while they fall under the base; widening the anchor moves them
further from the axis without widening the base, which is why they surface
past a threshold. The FRONT family never had the problem: its plane, x = 0,
is exactly its own centre.

The true displacement is sqrt(2) * _ArcOffset in UV, so 2*sqrt(2) once in
centred coordinates. Hence _BackSplit = 2.8284271, which is a geometric
constant and not a tuned value. The check that confirms the reading: at
that value the rear apex lands exactly at the end of the base -- 0.110
against a half-length of 0.111 on snail, 0.082 against 0.0895 on long.
Which is where Allen meant to anchor the rear arcs all along.

_ArcOffset is back to its shipped values on both oblongs, _ArcCut stays 0,
and both render clean: four arcs meeting the base, no stumps, no gap.

Bundles renamed _v6, TTS caches by URL.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
getCohesionLinks() only knows small, medium and large. On anything else
vanilla spawnCohesionRuler returns without drawing, so huge, laat and epic
units simply had no cohesion ring. They have one now.

Nothing was invented. BB_CohesionProjector draws its ring at the
projector's outer edge and reads nothing else, so the whole geometry is a
single number: ortho = half the base + 3in. That is exactly what the mod's
own three carry (27mm -> 3.531496 = 0.53150 + 3, 50mm -> 3.984252,
70mm -> 4.377953). 3in is range 1/2, the distance cohesion is measured at,
and the same one the white band marks on the rulers.

long and snail are left out on purpose: the cohesion shader only knows
Circle(), it cannot draw a stadium. They need an oblong variant built the
way BB_OblongRangeProjector is, with oblongVert and Capsule.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
long and snail had none, and they could not: the mod's cohesion shader
computes its gradient with Circle(), so it can only draw a disc, and a disc
on an elongated base would be wrong.

BB_OblongCohesionProjector is written for them. The round one places its
ring at the projector's edge, which works because the edge of a square
projector is a circle of known radius; for a capsule the distance to the
base is not the distance to the centre, so this one measures it and
compares against _RingDistance. Same profile otherwise: dark at the base,
bright at range 1/2.

The base geometry is not invented. It is read back out of the oblong RANGE
materials, the only place in the project where those dimensions are
written: radius 1.00748in for both, segment 2.99029in on long and
3.70231in on snail.

Two things the render bench caught that reading could not:

The oblong range prefabs have TWO levels -- a root at 90 degrees about X
like every other projector, and a CHILD named `projector` rolled 90 degrees
about Z that carries the component. That child roll is what aligns the
capsule's long axis with the base. A flat, single-level prefab renders the
stadium across the model instead of along it. It has to be on the child
precisely because TTS imposes its own rotation on the root.

And the bench must impose the pose rather than compose with the prefab's:
composing broke the long range ruler's render, while imposing matches what
the game shows.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Martin, in game: it works, but it is not range 1/2.

My reading of the oblong base was half its real width. The mod's oblong
shader masks the base with Step(grad, smoothness, uvShadow), which is
Capsule(...) < 1 - uvShadow -- and 1 - uvShadow IS the normalised radius.
So its base reaches TWO radii from the segment, not one. Measured against
the render to be sure: the long base is 2.02in half-width, where the naive
reading gives 1.007in.

The cohesion stadium was therefore built around a base half as wide, and
its ring fell short. The radius is now passed to the shader explicitly, in
inches, rather than derived from _BaseSize, so the mistake cannot be
replayed there.

Checked with the camera locked to the same extent for both bundles, which
is what -fov on the bench is for: the ring now measures 5.06in half-width
and 6.53in half-length against 5.015 and 6.51 expected, and lands on the
outer edge of the white range 1/2 band of the same base.

The round sizes were already right -- huge measures 4.93in against 4.97
expected, on the band.

Bundles renamed _v3, TTS caches by URL.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
It showed range 1. Martin wants range 1/2 on it.

The mod already had exactly this object, and it is not a range ruler: the
POI's 3in ring is BB_CohesionProjector with its orthographic size at 4, one
inch of base radius plus three. Ours is the same build at the token's own
base -- 27mm, so 0.53150 + 3 = 3.53150 -- and it keeps the ring's current
amber, so only the SIZE changes. Measured on the bench at 3.54in.

Routed by the object's NAME, not by rangeKey: "token" is shared by
Objective, Condition, Cad Bane, Proton Charge and Complete the Mission, and
only Objective should change. The bench now checks both halves of that --
Objective gets ours, Condition still gets the mod's.

The hover hotkey is untouched, it still draws the fig-leader bands.

Nothing here covers an Advantage token: the mod has none, under that name
or any other. Asked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Advantage token the game means is the mod's Condition token (Martin,
14 Aug). It shares the Objective's base and colour, so the ring is now
named for what it is -- token05_27mm_isq -- and serves both.

Bane, Proton Charge and Complete the Mission carry the same rangeKey and
keep the mod's range 1 ring. That is the point of routing by name, and the
bench pins both sides of it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Its range routing was never wired, and the five clears on that path only
ever touch the mod's ruler, so RANGE then ATTACK leaves two rulers on
screen. That was going to be the next fix.

It is not a fix. Martin, 14 Aug: the feature dates from V1 of the game,
three years ago, and is no longer accurate under V2. So the spec now says
so plainly -- known, accepted, do not wire it. If it is ever revisited it
will be to bring attack mode up to V2 or drop it, which belongs to the V2
tuning batch, not here.

Written down because the finding reads exactly like a bug, and the next
person through will otherwise spend an evening fixing something that
should not exist.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Martin: fix the hole while we wait for a V2 tool to replace the feature.

attackMode() now goes through gClearRange + gRangeTrigger like the RANGE
button, and exitTargetingMode, exitAttackMode and clearTemplates each clear
our overlay alongside their existing pcalls. RANGE then ATTACK no longer
leaves two rulers on screen.

Defined in ORDER_TOKEN_BUTTON_OVERRIDES rather than the Cohesion block,
because that one is appended last and therefore wins. The May ban still
holds: spawnRangeRuler and clearRangeRulers are not overridden on the Order
Token -- only their callers are redefined.

The bench grew an Order Token scope to prove it. The patcher's block is
loaded into a stubbed environment whose vanilla spawnRangeRuler raises, so
a regression fails the run instead of passing quietly. Seven checks, 36 in
total.

The spec says plainly that this is a holding fix on a feature that dates
from V1 and is not accurate under V2.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The 1011-line divergence in mod/src was the decal-era overlay engine: the
873-line Overlays.ttslua, its require, the RangeRulers router, the Cohesion
wrapper, the Order_Token overrides and the isqLogo UI asset. All of it was
superseded on 12 August when the patcher moved to real Projectors, and
Martin cancelled the backport on the 14th: the engine lives in the patcher,
the PR's mergeable content is the asset fix. mod/src now matches
origin/main exactly, which also retires the two source-vs-patcher
divergences the spec tracked (including the latent SIGSEGV one).

In the patcher, two dead pieces found by auditing every injected block:
macRemoveAll was defined and never called, and macActivePlayerForMove was
written by all nine movement buttons to feed a gGetMode argument that the
table-wide mode has ignored since per-seat was dropped. Removed, with the
comment that documented the capture.

Bench: 36 checks, green before and after.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The branch had accumulated three kinds of ballast that a reviewer would have
to wade through before reaching the fix.

Dead assets: mod/data/mac-fallback-assets held 47 files, of which the
patcher references 15 (eight Projectors, five half-cohesion bundles, the
logo, the 0.5 token ring). The other 32 are the decal era and the
silhouette experiments: the range_fig_leader PNGs, the deployment and
max-move decals, the cohesion halo, four generations of stadium and
silhouette meshes, and both silhouette_mac_fallback bundles. Nothing in
the chain has loaded any of them since the move to Projectors on
12 August. They remain reachable at the overlays-decals-v1 tag.

Investigation notes and one-shot scripts: the retro-*.md retrospectives,
design-refactor.md, SHADER_INVENTORY.md and materials-reference.md are our
French working notes, and inspect_*.py, scan_bundles.py,
extract_projector_specs.py, patch_cohesion_rename.py and
generate_overlay_assets.py were written to answer questions that are now
answered. They are archived on our side; the repair chain that stays
useful lives on in tools/.

Stale README: it still advertised the mirror-into-a-save-slot behaviour,
removed on 11 August, and indexed the files above.

Bench: 36 checks, green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Our four markdown files become plain text, so the only .md left in the repo are
the ones that were already yours.

They were also out of date, in ways that mattered:

- mac-patcher/README described the decal-and-vector-lines engine and gave the
  Unity 6 shader bug as the root cause. Neither has been true since 12 August:
  rendering moved to real Projectors, and the root cause is bundles built
  without a Metal variant. Rewritten around what the module actually is, an
  optional overlay behind an off-by-default button, plus the attack chain
  marked as the stopgap it is.
- mac-support-package/README and the release README still said eight bundles
  had no surviving sources and stayed broken. They have been grafted since
  12 August: nothing is left broken on Mac. Both now carry the second root
  cause too, the vertex-colour one, which is the half that matters for the
  minis they will build next.
- "byte-identical to what is published today" is dropped. The Windows SubShader
  comes from our rebuild, not from the published file. What is true, and enough,
  is that the merge does not touch it.
- The patcher's own docstring said it was a Mac cohesion fallback spawning
  vector lines. The injected markers keep their historical "mac" names, since
  the idempotence pass matches them by regex.

Counts throughout are now the ones the inventories give: 266 bundles referenced,
152 repaired (143 rebuilt, 9 grafted), 114 that were never broken.

Bench: 36 checks, green.

Co-Authored-By: Claude Opus 5 (1M context) <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