Training targets, and restyle the character as an irregular fighter - #12
Closed
ralyodio wants to merge 3 commits into
Closed
Training targets, and restyle the character as an irregular fighter#12ralyodio wants to merge 3 commits into
ralyodio wants to merge 3 commits into
Conversation
Launching the Linux build died immediately: FATAL:setuid_sandbox_host.cc(163)] The SUID sandbox helper binary was found, but is not configured correctly ... chrome-sandbox is owned by root and has mode 4755. Electron sandboxes renderers with unprivileged user namespaces. Ubuntu 23.10 and later restrict those by default, so Chromium falls back to its SUID helper, which must be root-owned and mode 4755. An AppImage is mounted in /tmp as the invoking user, so that can never hold, and Chromium aborts rather than run unsandboxed. Every Ubuntu 23.10+ user was affected; the game had never started for them. The launcher now detects the restriction — apparmor_restrict_unprivileged_userns, max_user_namespaces, or unprivileged_userns_clone — and only then passes --no-sandbox, printing a one-time notice with the sysctl to restore it. Detection rather than always passing the flag: dropping the sandbox unconditionally would weaken every machine, including the majority where it works. NIGHTCELL7_NO_SANDBOX=1 forces it. Second bug, in the delivery path: `nightcell7 update` short-circuits on "Already on the latest version" and never rewrote the launcher, so this fix would never have reached anyone already on v0.1.0. Launcher writing is split into write_linux_launcher() and update refreshes it even when the version has not moved — the launcher carries real logic and is fixed independently of the game. Verified against a stub AppImage on a kernel with apparmor_restrict_unprivileged_userns=1: the flag is added, the notice appears once, an unrestricted kernel keeps its sandbox, the override works, and `update` on a matching version rewrites the launcher. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…tures
**The weapon rendered as a solid white blob on every shot.** Three separate
causes, each found by screenshotting the real fire path in a browser rather
than reasoning about it:
1. The scene runs a GlowLayer for the sodium lamps, and it blooms any
emissive material. A 3.5 cm emissive tracer came out as a metre-wide beam
that washed out the frame and hid everything else. The effect meshes are
now excluded from it, and the tracer is 1.8 cm and additive.
2. `environmentIntensity` is 2.9 scene-wide, which the yard needs — but a
near-polished metal held 30 cm from the camera reflects that straight past
the bloom threshold. It is per-material, so the viewmodel now gets its own
instances at 0.5.
3. The muzzle flash light sat *at* the muzzle, centimetres from the weapon,
so inverse-square falloff gave the gun orders of magnitude more light than
the scene. `excludedMeshes` did not help — the viewmodel is instantiated
from an asset container and instances take lighting from the source mesh —
so the light now sits 0.9 m downrange, which fixes it geometrically. The
flash quad also went from 0.22 m to 0.075 m: at 0.3 m from a 90-degree
camera the original covered a third of the screen.
**Impacts were invisible.** They were firing correctly, but 2-7 cm sparks go
sub-pixel past about thirty metres, so a hit down a lane looked like the round
simply stopped. Sparks and dust are larger, more numerous and longer lived, and
there is now a billboarded impact flash scaled with distance so a hit reads at
any range. Verified in-browser: the tracer terminates on the crosshair and the
flash is clearly visible at the hit point.
**The gallery kept showing old screenshots.** Next's image optimiser serves
/_next/image with `Cache-Control: public, max-age=14400`, and the capture
filenames are deliberately stable, so a returning visitor kept the previous
build's frames for four hours after a re-capture. The server was serving the
new bytes the whole time. `minimumCacheTTL: 0` plus an explicit header on
/media/yard/* means always revalidate; with the ETag Next already sends, an
unchanged image costs a 304 rather than a re-download.
A cache-busting query string was the obvious fix and does not work: Next
rejects a query on a local image unless whitelisted in `images.localPatterns`,
which matches `search` exactly, so a per-capture value cannot be whitelisted
and the build fails. Documented in capture-src.ts so it is not retried.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ar fighter **There was nothing to shoot at.** `character.glb` was built and then had no consumer — the multiplayer entry point that would draw remote players does not exist yet — so the sandbox was an empty yard with a working rifle and no enemy. PRD §40 puts "one enemy and one rifle" ahead of everything else. Five training targets now stand in the yard. They take hits, topple, and stand back up after three seconds. Deliberately targets rather than AI: there is no animation system and no client-side bot pathing, and a figure sliding around frozen in a standing pose would look worse than one that honestly stands still. Hit detection is presentation only, like the weapon effects — the server owns hit registration through resolveHitscan. A target only counts if it is nearer than the world geometry behind it, so one standing behind a container cannot be shot through it. **The character read as a Western regular** — high-cut ballistic helmet, NVG mount, plate carrier with shoulder yoke, pauldrons. That is the wrong silhouette for a story whose stated premise is that neither nationality is the default villain, and whose two factions are fictional. Restyled as an irregular fighter: cloth head wrap with a tail and face cloth, field jacket, simple chest rig with rifle pouches and a bandolier, canvas satchel, rolled blanket, cloth knee wraps. No helmet, no optics mount, no armour plate. It stays unmarked and fictional — no insignia, no script, no religious or ethnic signifiers. Faction identity is carried by an armband and a head-wrap band in the team colour and nothing else. CLAUDE.md gates Iranian/Farsi content on native review that has not happened, and a caricature would fail that review and the PRD's own §21.12 launch gate. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
Author
|
Superseded by a branch cut from current main — the original was branched off a squash-merged branch and conflicted. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
There was nothing to shoot at
character.glbwas built and then had no consumer — the multiplayer entry point that would draw remote players doesn't exist yet — so the sandbox was an empty yard with a working rifle and no enemy. PRD §40 puts "one enemy and one rifle" ahead of everything else.Five training targets now stand in the yard. They take hits, topple, and stand back up after three seconds.
Deliberately targets, not AI: there's no animation system and no client-side bot pathing, and a figure sliding around frozen in a standing pose looks worse than one that honestly stands still.
Hit detection is presentation only, like the weapon effects — the server owns registration via
resolveHitscan. A target only counts if it's nearer than the world geometry behind it, so one standing behind a container can't be shot through it.The character read as a Western regular
High-cut ballistic helmet, NVG mount, plate carrier with shoulder yoke, pauldrons. Wrong silhouette for a story whose stated premise is that neither nationality is the default villain, and whose two factions are fictional.
Restyled as an irregular fighter: cloth head wrap with tail and face cloth, field jacket, simple chest rig with rifle pouches and a bandolier, canvas satchel, rolled blanket, cloth knee wraps. No helmet, no optics mount, no armour plate.
Unmarked and fictional — no insignia, no script, no religious or ethnic signifiers. Faction identity is an armband and head-wrap band in the team colour, nothing else.
CLAUDE.mdgates Iranian/Farsi content on native review that hasn't happened, and a caricature would fail both that and the PRD's §21.12 launch gate.201 tests pass. Format, lint, typecheck clean.
🤖 Generated with Claude Code