Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
714 commits
Select commit Hold shift + click to select a range
18e4ed1
[net] the lobby list reads each row's proof and cleans its texts
pelmentor Oct 17, 2026
d9bc076
[server] move the create domain out of lobby.rs
pelmentor Oct 17, 2026
89f8840
[server] stateless announce nonces and a rate class for the challenge
pelmentor Oct 17, 2026
2df5c6c
[server] refuse a malformed name or floor at start; canonical host names
pelmentor Oct 17, 2026
9ce7638
[net] canonical signed names, stop checks in the create, wider text caps
pelmentor Oct 17, 2026
8a0f213
[docs] master name, floor and stateless nonce in the self-hosting text
pelmentor Oct 17, 2026
99d1bad
[net] keep the release record's game text at its own cap
pelmentor Oct 17, 2026
8edd26f
[net] build 230 is the first to sign its lobby announce
pelmentor Oct 17, 2026
cda94e8
[server] the master requires COOP_DOMAIN and checks every alias
pelmentor Oct 17, 2026
669030d
[net] a stopped host announce leaves the lobby it just made
pelmentor Oct 17, 2026
c3a3bd7
[server] a full rate table forgets old keys instead of refusing new ones
pelmentor Oct 17, 2026
d207734
[net] a refused announce that waiting cannot clear is not retried
pelmentor Oct 17, 2026
2e52a5b
[docs] each lobby-proof divergence from MTA names its file and reason
pelmentor Oct 17, 2026
06b95c9
[server] the spent-nonce set is sized to the master's memory
pelmentor Oct 17, 2026
d248fc8
[net] a second stop inside a host's lead-in cancels its announce
pelmentor Oct 17, 2026
532ef02
[server] the block list is asked after the proof; reads are 120/min
pelmentor Oct 17, 2026
fa40c1d
[player] a puppet's touch never runs this machine's player's effects
pelmentor Oct 17, 2026
f68d974
[ue_wrap] a class's own listing identity, read in O(1)
pelmentor Oct 17, 2026
3e7cf68
[player] the puppet module re-resolves only on its own classes' change
pelmentor Oct 17, 2026
b9f33d8
[player] the puppet module checks its own class at each refusal
pelmentor Oct 17, 2026
dd0eff1
[player] wisp_p's touch keeps the world clock, not the host's screen
pelmentor Oct 17, 2026
5320aaa
[ue_wrap] a selftest proves a class's listing identity
pelmentor Oct 17, 2026
b7b2870
[docs] the dispatch map names wisp_p's host seams
pelmentor Oct 17, 2026
cc5dba0
[player] the grunt refusal finds player 0's controller by its class
pelmentor Oct 17, 2026
86a9481
[player] drop the scan file's dead names; the map names the class
pelmentor Oct 17, 2026
ce4f8c1
[config] the PI rows have their own include
pelmentor Oct 17, 2026
49db601
[creatures] npc_adoption reports whether the ghost sweep has run
pelmentor Oct 17, 2026
586f255
[dev] the PI-3 verb observer
pelmentor Oct 17, 2026
7845355
[dev] the PI-3 drill: a still peer's puppet is not the player
pelmentor Oct 17, 2026
7c60c3c
[dev] the PI-3 observer keeps its classes by name and settles its sweeps
pelmentor Oct 17, 2026
53f0fbc
[dev] the PI-3 observer attributes by class name and reads contacts live
pelmentor Oct 17, 2026
4dd5ecf
[dev] the PI-3 observer attributes by class name alone
pelmentor Oct 17, 2026
41094cf
[dev] each PI-3 arm watches for twice its red's slowest verb
pelmentor Oct 17, 2026
dfb21c2
[dev] the PI-3 observer holds its site slot-checked
pelmentor Oct 17, 2026
a414ae9
[dev] the PI-3 arm table's horizon comment names no date
pelmentor Oct 17, 2026
9bde9d1
[dev] each PI-3 spawner wait has its own bound, the join the rig's
pelmentor Oct 17, 2026
cd926fb
[port] the fingerprint table carries the puppet-identity rows
pelmentor Oct 17, 2026
1d1f209
[net] fake-link knobs a run can step
pelmentor Oct 17, 2026
9471eb9
[net] the send-rate line shows the base and the queue
pelmentor Oct 17, 2026
bae076e
[net] the send-rate law reads the queue above the link's base
pelmentor Oct 17, 2026
47b3875
[net] fake-link globals return to their rows at every session start
pelmentor Oct 17, 2026
119bfdb
[net] the send-rate transition line logs only Brake and Hold edges
pelmentor Oct 17, 2026
06a39ee
[ue_wrap] reflection_props::PropertyClassName reads a property type
pelmentor Oct 17, 2026
dc37161
[ue_wrap] spawner_stamp writes what a class's native spawner writes
pelmentor Oct 17, 2026
7e14be7
[npc] SpawnFreshNpcMirror stamps the begun actor before it finishes
pelmentor Oct 17, 2026
ceff277
[dev] PI-3 drill gains the orbbirth arm; every arm stamps its spawn
pelmentor Oct 17, 2026
ffa6942
[dev] stamp rows resolve by the index; Hold ticks while unconnected
pelmentor Oct 17, 2026
18722c4
[ue_wrap] a stamp row holds only while its guard function exists
pelmentor Oct 17, 2026
eee74c4
[npc] the stamp drop cites its precedent and latches per class object
pelmentor Oct 17, 2026
3f79369
[ue_wrap] a stamp row's name is asked once; a missing guard is named
pelmentor Oct 17, 2026
e5f11c4
[port] the fingerprint table carries the spawner-stamp rows
pelmentor Oct 17, 2026
df5751f
[net] the controller publishes each slot's delivered and queued bytes
pelmentor Oct 17, 2026
ba54a62
[net] the joiner's beacon keeps speaking while its world drains
pelmentor Oct 17, 2026
d716eea
[docs] MV-J23 and the phase names say what is waited on
pelmentor Oct 17, 2026
655e970
[net] the Draining label reads like the rest, and a mute host's line too
pelmentor Oct 17, 2026
b1a5596
[net] the Draining owner's state lives where it is read
pelmentor Oct 17, 2026
50f859c
[config] add the native_spawn_probe dev row in its own include
pelmentor Oct 17, 2026
7d48aec
[dev] record Blueprint-spawned creatures per source, and the client orb
pelmentor Oct 17, 2026
758f1ea
[dev] the spawn probe cleans up after itself and says when it cannot
pelmentor Oct 17, 2026
9414eeb
[dev] the PI-3 observer's native post hooks return off the game thread
pelmentor Oct 17, 2026
20d852f
[config] move the diagnostic probe rows out of the dev row list
pelmentor Oct 17, 2026
72752ee
[dev] the spawn probe's clock resets per session; spawner match by slot
pelmentor Oct 17, 2026
db7c1cb
[dev] camera_drill hangs a camera on a wall and a client grabs it
pelmentor Oct 17, 2026
412b423
[dev] camera_drill waits for the director to route, then searches walls
pelmentor Oct 17, 2026
48c6b3e
[dev] camera_drill gains the grab_near and host_grab_near arms
pelmentor Oct 17, 2026
5bd7cf6
[dev] camera_drill's near walk stops within 35 cm of its standpoint
pelmentor Oct 17, 2026
e40067d
[props] a save record waits while the prop is in this player's hands
pelmentor Oct 17, 2026
11a3ab7
[ue_wrap] security_camera reaches a camera's two bits and laptop widget
pelmentor Oct 17, 2026
53b851c
[net] a camera's two bits are the host's; a client's press is an intent
pelmentor Oct 17, 2026
a49bd3d
[dev] camera_drill gains the host-toggle..join state arms
pelmentor Oct 17, 2026
625187a
[net] a camera-light request is in reach of any laptop-widget screen
pelmentor Oct 17, 2026
9568d67
[port] the fingerprint table carries the security-camera rows
pelmentor Oct 17, 2026
3376e3d
[coop] display remote puppets on the base radar
arigalit Oct 17, 2026
82ad7ef
[net] camera lane audit fold: cursed tick, host panel, class default
pelmentor Oct 17, 2026
a1b5fc0
[docs] piles: the trash pile's look-at hint is the game's own box
pelmentor Oct 18, 2026
8cb5509
[dev] a census of the server breaker's inputs
pelmentor Oct 17, 2026
12f7fde
[port] the fingerprint table carries the server breaker's tick
pelmentor Oct 18, 2026
a1be59e
[world] a host creature's event count crosses to every client
pelmentor Oct 18, 2026
68d3e31
[dev] event_relay_drill reads the relayed creature count on both peers
pelmentor Oct 18, 2026
e0fe3ed
[world] creature event relay audit fold: PRE by bound entry
pelmentor Oct 18, 2026
458b0b9
[docs] the creature event count in the dispatch and expression maps
pelmentor Oct 18, 2026
b26e0d0
[world] creature event relay audit fold: bind readiness, zeros, cites
pelmentor Oct 18, 2026
78dbcce
[world] creature event relay: the header and Reconcile's comment
pelmentor Oct 18, 2026
eb55ae9
[net] a joiner gets a connect-edge creature's spawn once
pelmentor Oct 18, 2026
497ec77
[net] joiner spawn skip: the MTA cites at its decision sites
pelmentor Oct 18, 2026
3c803e4
[docs] weather: rain indoors is the game's own effect
pelmentor Oct 18, 2026
0c264d9
[docs] piles: the look-at hint row is withdrawn pending its measurement
pelmentor Oct 18, 2026
c930d6a
[ue_wrap] laptop_widget reaches the laptop interface's tab switcher
pelmentor Oct 18, 2026
3a138d0
[net] the PC user's tab is shown on every peer
pelmentor Oct 18, 2026
3c6c729
[dev] laptop_tab_drill proves the PC user's tab on the viewing peer
pelmentor Oct 18, 2026
7c44351
[dev] laptop_tab_drill: join arm reads the snapshot; enter says why
pelmentor Oct 18, 2026
6817e23
[dev] laptop_tab_drill's holder and reader steps get their own file
pelmentor Oct 18, 2026
450b294
[dev] laptop_tab_drill's refused enter names the two silent gates
pelmentor Oct 18, 2026
190d981
[dev] laptop_tab_drill aims at the screen before it presses enter
pelmentor Oct 18, 2026
62cd44b
[dev] laptop_tab_drill aims at boxScreen, where the game offers enter
pelmentor Oct 18, 2026
b0e4c21
[dev] laptop_tab_drill's aim fan reaches 16 degrees off boxScreen
pelmentor Oct 18, 2026
5762c35
[dev] laptop_tab_drill's aim rides the director's AimFan
pelmentor Oct 18, 2026
6d5eb0e
[dev] laptop_tab_drill holds the laptop and its boxes slot-validated
pelmentor Oct 18, 2026
775762c
[dev] laptop_tab_drill's header fits the comment block cap
pelmentor Oct 18, 2026
6e50bd5
Merge remote-tracking branch 'origin/main' into sync-small-things
arigalit Oct 18, 2026
be148e1
[coop] sync mouse-driven motion for physical swinger doors
arigalit Oct 18, 2026
6c8f5e8
[docs] the base computer and the economy leave devices.md
pelmentor Oct 18, 2026
2276a14
[ci] the prose baseline counts base-computer.md as published
pelmentor Oct 18, 2026
240c9e0
[ue_wrap] add creature presentation, hit and player-verb wrappers
pelmentor Oct 18, 2026
5f44f3b
[creatures] mark parked-family mirrors, refuse their graph entries
pelmentor Oct 18, 2026
2f486ae
[creatures] keep a mirror's mark across a world change
pelmentor Oct 18, 2026
dde16fb
[player] deliver a parked creature's hit to its victim's machine
pelmentor Oct 18, 2026
8915a7a
[creatures] judge a client's hit on a parked creature on the host
pelmentor Oct 18, 2026
dd98f1f
[player] hit judge: a block near the struck point is not cover
pelmentor Oct 18, 2026
8b75f38
[dev] creature hit drill: both directions per parked creature
pelmentor Oct 18, 2026
4b7ff20
[port] the fingerprint table carries the brain-off's and the hit's rows
pelmentor Oct 18, 2026
2307429
[ue_wrap] cache reflected offsets per class and per function
pelmentor Oct 18, 2026
2280c08
[ue_wrap] weapon catalog: a missing length column leaves reach at 0
pelmentor Oct 18, 2026
1079891
[player] hit judge: bound the swing's facing, read the dead flag
pelmentor Oct 18, 2026
be345a2
[player] count a delivered hit only once sent; log applied per class
pelmentor Oct 18, 2026
aa3024b
[creatures] hit intent: cache the call layout, log hits per class
pelmentor Oct 18, 2026
f196b03
[creatures] mirror brain: FName class tests, no kick on an adopted twin
pelmentor Oct 18, 2026
b06961c
[dev] creature hit drill: refill the host's vitals every second
pelmentor Oct 18, 2026
87acc7b
[docs] tag the creature-hit delivery claims and the judge's new checks
pelmentor Oct 18, 2026
3d5debb
[creatures] mirror brain: names first, twin skips counted, cites
pelmentor Oct 18, 2026
f51ce44
[player] player hit: say and count a refused PlayerHit send
pelmentor Oct 18, 2026
58a93ad
[player] hit judge: face the streamed aim in 3-D, drop the alive gate
pelmentor Oct 18, 2026
4f5341c
[player] player hit: count every Deliver that sent nothing
pelmentor Oct 18, 2026
07c4e47
[player] hit judge: newest aim, 60 degree bound, alive gate
pelmentor Oct 18, 2026
692796a
[creatures] mirror brain counts the twin kick skips
pelmentor Oct 18, 2026
49d8401
[net] a positive vital fraction never quantises to zero
pelmentor Oct 18, 2026
3ec8d7a
[net] vitals comments name the hit judge; a NaN encodes as 0
pelmentor Oct 18, 2026
7866d9a
[dev] creature hit drill: log the hound's facing on both peers
pelmentor Oct 18, 2026
2241217
[creatures] a fossil hound mirror faces where the host's body does
pelmentor Oct 18, 2026
6b0d284
[creatures] the hound's facing has a verdict; its comments say what runs
pelmentor Oct 18, 2026
0cea7ba
[coop] sync sleeping bag and mattress transitions
arigalit Oct 18, 2026
9c6b950
[dev] the hound's facing verdict counts turns between samples
pelmentor Oct 18, 2026
853e058
[creatures] the hound's body-yaw test compares class names
pelmentor Oct 18, 2026
1013319
[creatures] the hound's class name is not latched while it reads None
pelmentor Oct 18, 2026
6955e1d
[props] the hold predicate and the reservation table live in prop_hold
pelmentor Oct 17, 2026
d220a45
[coop] sync cord and socket links
arigalit Oct 18, 2026
4b86225
Merge remote-tracking branch 'origin/main' into sync-small-things
arigalit Oct 18, 2026
285ced6
[props] a prop mirror's row can be dropped from outside the destroy file
pelmentor Oct 17, 2026
2916619
[dev] the hook plant is one helper the drills share
pelmentor Oct 17, 2026
ceb5c91
[dev] the remover drill tries props pulled by hooks
pelmentor Oct 17, 2026
f8b91d5
[dev] the remover drill's host half lives in its own file
pelmentor Oct 17, 2026
90019da
[props] the host judges a client's take or use and destroys it on commit
pelmentor Oct 17, 2026
b775fd8
[props] a refused commit is sent again until the host has it
pelmentor Oct 17, 2026
ae4c807
[props] the hold predicate states its timing and its precedents
pelmentor Oct 17, 2026
d833730
[dev] the remover drill's hook steps wait on their own layout
pelmentor Oct 17, 2026
e33ff61
[props] the take-or-use judge reads its waits first, says its failures
pelmentor Oct 17, 2026
e90dbe7
[props] the client keeps every expired request until the host answers it
pelmentor Oct 17, 2026
d843f9d
[coop] sync coffee machines and cups
arigalit Oct 18, 2026
59dbb23
[props] a replay that destroyed its target commits; logs name outcomes
pelmentor Oct 17, 2026
0e57ab2
[props] a client asks the host before taking or using a shared prop
pelmentor Oct 17, 2026
fdfb53b
[props] a selftest drives the take-or-use decisions
pelmentor Oct 17, 2026
6723fc9
[docs] the watched take and use functions are mapped
pelmentor Oct 17, 2026
ab0c696
[props] a client asks only for a shared prop and reads params cheaply
pelmentor Oct 17, 2026
6b46b35
[props] the trash bases resolve through the class index
pelmentor Oct 17, 2026
f40e458
[dev] the hostile drill forges takes and commits against the host
pelmentor Oct 17, 2026
8901caf
[props] a trash class verdict is not kept while its base is unresolved
pelmentor Oct 17, 2026
41ad8e2
[dev] the act drill takes and uses each family of shared prop
pelmentor Oct 17, 2026
13e7193
[props] the trash bases resolve on the game thread only
pelmentor Oct 17, 2026
20c604e
[dev] the act drill's honest phase covers the native and edge cells
pelmentor Oct 17, 2026
82a28b0
[props] prop class tests resolve on the game thread and say so off it
pelmentor Oct 17, 2026
4127a71
[dev] the act drill's client steps live in their own file
pelmentor Oct 17, 2026
873cee9
[props] the prop base uses the class index; retries wait for new classes
pelmentor Oct 17, 2026
817a267
[dev] the act drill races shared props between two clients
pelmentor Oct 17, 2026
a99c65e
[dev] the act drill leaves mid-take and times its windows
pelmentor Oct 17, 2026
3b68468
[dev] drills that take a shared prop wait for the act's end
pelmentor Oct 17, 2026
f34ddc6
[dev] the hand-drop selftest steps on what each peer sees
pelmentor Oct 17, 2026
9d676f9
[dev] the pickup drill acts when the seed is in, not after a count
pelmentor Oct 17, 2026
6a359b3
[props] an unresolved class base is asked again on every call
pelmentor Oct 17, 2026
4c40471
[dev] the drill props helpers are one file
pelmentor Oct 17, 2026
7a2c309
[dev] the drill checks fail at their bounds and read their own acts
pelmentor Oct 17, 2026
3a3b3b4
[dev] the hand-drop census lives in its own file
pelmentor Oct 18, 2026
ab1f50c
[dev] drill holds read the hand item; the shrimp row eats its last
pelmentor Oct 18, 2026
f2817ad
[net] the take-or-use kinds move the protocol to 236
pelmentor Oct 18, 2026
fae2eae
[dev] the hand-drop watcher names its subject or fails
pelmentor Oct 18, 2026
ebc8d03
[dev] the hand-drop throw must leave a new dropped prop
pelmentor Oct 18, 2026
3fc28ba
[dev] the remover drill checks its sight of both crowbars at rest
pelmentor Oct 18, 2026
1375dc5
[dev] the hand-drop throw refuses an empty hand before it throws
pelmentor Oct 18, 2026
71e762a
[dev] the act drill installs once a session
pelmentor Oct 18, 2026
dbc36fa
[dev] the act drill lays its targets beside the client's puppet
pelmentor Oct 18, 2026
c76fd0e
[dev] the drive drill walks to the drive it pockets
pelmentor Oct 18, 2026
916c5cd
[dev] the act drill waits until the mirror can be gathered
pelmentor Oct 18, 2026
721d557
[dev] the act drill waits on the host's drive, not on physics
pelmentor Oct 18, 2026
1e6fe5c
[dev] the drive drill pockets only a drive a player could gather
pelmentor Oct 18, 2026
ce39a85
[props] a drill names the eids whose raw destroys it counts
pelmentor Oct 18, 2026
5efb68b
[dev] the act drill empties the client's hunger before each eat
pelmentor Oct 18, 2026
776ce89
[dev] the drive drill gathers the drive it was born with
pelmentor Oct 18, 2026
48307ac
[dev] the act and drive drills say what they gather in plain words
pelmentor Oct 18, 2026
70b6949
[props] the game's own gather test is one function
pelmentor Oct 18, 2026
e298b31
[dev] the host turns the born drive's physics on, as a slot's pull-out
pelmentor Oct 18, 2026
063e602
[dev] the act drill lays a target on the first floor of a fan
pelmentor Oct 18, 2026
19275de
[dev] the drills' floor and gather failures say what they read
pelmentor Oct 18, 2026
ddd3caa
[props] the host judges each act by the game's own conditions
pelmentor Oct 18, 2026
73ef129
[props] the selftest drives the judge's fits and order
pelmentor Oct 18, 2026
2a58c4c
[dev] the act drill's honest rows meet the take-and-use judge
pelmentor Oct 18, 2026
52157b9
[dev] the hostile drill forges acts the game would never perform
pelmentor Oct 18, 2026
c35ff08
[dev] the drive drill re-places a drive the host lays beside the client
pelmentor Oct 18, 2026
969ae07
[props] the judge checks the verb first and reads every fact fail-closed
pelmentor Oct 18, 2026
3fd92ec
[props] the selftest proves a frozen prop still meets its other terms
pelmentor Oct 18, 2026
4cfaecd
[dev] the drills' new steps fail at their bounds and start clean
pelmentor Oct 18, 2026
d94df72
[props] the judge refuses a hose being placed, as the game does
pelmentor Oct 18, 2026
b4e3a23
[dev] the grab row clears its hand through the director's own process
pelmentor Oct 18, 2026
040c553
[props] the judge's table check and lookups fail closed and quiet
pelmentor Oct 18, 2026
bc1bf2e
[dev] the loaded bin takes a small item dropped from above, upright
pelmentor Oct 18, 2026
d49cf4c
[dev] the remover drill's host walks to the crowbar it hooks
pelmentor Oct 18, 2026
68bfe94
[props] the raw-destroy watch also counts a destroy named by key
pelmentor Oct 18, 2026
8f0e416
[dev] the throw drill waits for the host's drive of the backpack to end
pelmentor Oct 18, 2026
4797d78
[dev] the remover's hook waits share one bound; the host walk ends clean
pelmentor Oct 18, 2026
3ef31ce
[dev] the act drill spawns its targets where a route reaches
pelmentor Oct 18, 2026
3a64cd0
[dev] the remover client binds the hooked crowbar by the host's eid
pelmentor Oct 18, 2026
9c5da85
[dev] the remover host names both crowbars' eids; the client binds them
pelmentor Oct 18, 2026
0011935
[coop] a client knows the explosion classes and sees their births
pelmentor Oct 16, 2026
218f771
[coop] a client dissolves the explosions its own game spawns
pelmentor Oct 16, 2026
7eb1df7
[dev] a drill shows a client dissolving a barrel explosion twice over
pelmentor Oct 16, 2026
95ebaad
[coop] a client watches the explosion copy's verbs and begin-play
pelmentor Oct 16, 2026
23c3e65
[coop] a client's explosion copy writes only its own player's damage
pelmentor Oct 16, 2026
197bdc7
[coop] a client receives and checks the host's ExplosionSpawn
pelmentor Oct 16, 2026
e7dc753
[coop] a client spawns the explosion the host sent
pelmentor Oct 16, 2026
ff27405
[coop] the host captures the explosions its game runs
pelmentor Oct 16, 2026
6517ab8
[coop] the host sends each captured explosion to every client
pelmentor Oct 16, 2026
54f71d7
[coop] the host sees which props an explosion's blast would fling
pelmentor Oct 16, 2026
0f8083f
[coop] the host drives the props an explosion flings to every client
pelmentor Oct 16, 2026
bf04c29
[coop] the host coasts from one prop snapshot per tick
pelmentor Oct 16, 2026
8c3dcfc
[coop] the explosion class table re-syncs on every unlist
pelmentor Oct 16, 2026
51cbdfb
[coop] the host sends an explosion only to peers that can apply it
pelmentor Oct 16, 2026
1dd3056
[coop] a client's explosion copy fails closed
pelmentor Oct 16, 2026
242894d
[coop] a client drops an explosion out of range
pelmentor Oct 16, 2026
b6e947f
[net] ExplosionSpawn rides the high lane
pelmentor Oct 16, 2026
8283256
[coop] the explosion lane's comments say what it does
pelmentor Oct 16, 2026
13ffd28
[ue_wrap] one raw read of an unattached actor's root pose
pelmentor Oct 16, 2026
eb46e1d
[coop] the host's coast reads prop positions raw
pelmentor Oct 16, 2026
b98cfc7
[coop] the explosion lane counts a failed narrowing and logs by role
pelmentor Oct 16, 2026
1b6ed32
[dev] a drill proves the explosion lane's apply, coast and receive
pelmentor Oct 16, 2026
2b32d77
[dev] the explosion drill is split into fixture, host and client files
pelmentor Oct 16, 2026
5a9a93e
[dev] the explosion drill bounds its waits and keeps its papers
pelmentor Oct 16, 2026
ac00be7
[dev] the explosion drill's comments state its bounds and papers' life
pelmentor Oct 17, 2026
932b9cd
[dev] the explosion drill's blast point takes the clearest of eight ways
pelmentor Oct 17, 2026
69b2ce3
[dev] the explosion drill's coast blast moves its papers metres
pelmentor Oct 17, 2026
b0b9ea3
[dev] the explosion drill's coast asks two papers to fly, all to rest
pelmentor Oct 17, 2026
f41d1e0
[dev] the explosion drill's papers lie on the blast point's line
pelmentor Oct 17, 2026
b6950ba
[dev] the explosion drill keys its papers by actor, waits out streams
pelmentor Oct 17, 2026
eb09e1b
[dev] the explosion drill's flown count says what it knows
pelmentor Oct 17, 2026
16c501d
[dev] the explosion drill judges each paper by its own state
pelmentor Oct 17, 2026
7fc68f8
[port] the fingerprint table carries the explosion lane's rows
pelmentor Oct 18, 2026
93dd26c
[docs] the code map names the explosion lane's modules
pelmentor Oct 18, 2026
9b379c5
Merge remote-tracking branch 'origin/main' into sync-small-things
arigalit Oct 18, 2026
1cc6ae7
[dev] trim oversized sync header comments
arigalit Oct 18, 2026
8fdafdc
[docs] update reliable message kind count
arigalit Oct 18, 2026
d891c8c
[port] record the swinger release fingerprint
arigalit Oct 18, 2026
cb17988
[port] add missing interactable fingerprints
arigalit Oct 18, 2026
d7ba2f9
[port] add remaining interactable fingerprints
arigalit Oct 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
20 changes: 16 additions & 4 deletions .github/ci/atlas_regime_gate.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,14 @@ function Invoke-Gate([hashtable]$mutate) {

# --- 3. the atlas ceiling is EXPLICIT ------------------------------------
# ImGui defaults TexMax to 8192. Inheriting it raises the worst DX12 upload
# behind an unbounded fence wait from 16.8 MB to 268 MB.
# behind an unbounded fence wait from 16.8 MB to 268 MB. Two ceilings are
# pinned: 2048, and 4096 under a script face, whose peer text accumulates
# (measured by the l10n drill's atlas arm); both are named
# constants and both sides of the texture take them.
$f = $text['src\votv-coop\src\ui\fonts.cpp']
if ($f -notmatch 'TexMaxWidth\s*=\s*2048' -or $f -notmatch 'TexMaxHeight\s*=\s*2048') {
$fails += "fonts.cpp does not pin TexMaxWidth/TexMaxHeight to 2048 (the 8192 default would be inherited)"
if ($f -notmatch 'kAtlasMax\s*=\s*2048' -or $f -notmatch 'kAtlasMaxScript\s*=\s*4096' -or
$f -notmatch 'TexMaxWidth\s*=\s*io\.Fonts->TexMaxHeight\s*=\s*ActiveScript\(\)\s*\?\s*kAtlasMaxScript\s*:\s*kAtlasMax') {
$fails += "fonts.cpp does not pin TexMaxWidth/TexMaxHeight to 2048 and 4096 (the 8192 default would be inherited)"
}
if ($f -notmatch 'GlyphExcludeRanges') {
$fails += "fonts.cpp no longer sets GlyphExcludeRanges -- every codepoint in every face would bake"
Expand Down Expand Up @@ -167,7 +171,15 @@ if ($Drill) {
want = 'no longer asserts the regime' }
@{ name = 'TexMax inherited'
mut = @{ 'src\votv-coop\src\ui\fonts.cpp' = {
param($t) $t -replace 'TexMaxWidth\s*=\s*2048', 'TexMaxWidth = 8192' } }
param($t) $t -replace 'kAtlasMax\s*=\s*2048', 'kAtlasMax = 8192' } }
want = 'does not pin TexMaxWidth' }
@{ name = 'script ceiling inherited'
mut = @{ 'src\votv-coop\src\ui\fonts.cpp' = {
param($t) $t -replace 'kAtlasMaxScript\s*=\s*4096', 'kAtlasMaxScript = 8192' } }
want = 'does not pin TexMaxWidth' }
@{ name = 'ceiling not chosen by the script'
mut = @{ 'src\votv-coop\src\ui\fonts.cpp' = {
param($t) $t -replace 'ActiveScript\(\)\s*\?\s*kAtlasMaxScript', 'false ? kAtlasMaxScript' } }
want = 'does not pin TexMaxWidth' }
@{ name = 'exclude list a no-op'
mut = @{ 'src\votv-coop\include\coop\text\exclude_ranges.inc' = {
Expand Down
212 changes: 212 additions & 0 deletions .github/ci/data_paths_gate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
#!/usr/bin/env python3
"""data_paths_gate -- the mod's own data is built from its own folder, never from the exe's.

Everything the mod keeps for itself (the ini, the server profile, the player profiles, the seen list,
the thanks cache, the identity key) lives in `ue_wrap::paths::ModDataDir()`, so a copied game folder
carries none of it and a manager's reinstall starts clean. `ue_wrap::paths::ExeDir()` is the game
exe's folder: it stays the home of the logs, the reports, the dumps and what a player authors (a
translator's `.po` files). A data builder written against `ExeDir()` again would put a file back
beside the exe, where a copy of the game folder carries it and a reinstall misses it. This gate holds,
over `src/votv-coop/src` (comments and string literals set aside):

1. a call of `ExeDir(` stands only in the files of EXE_DIR_FILES, each of which builds a file that
belongs beside the exe (a log, a report, a diagnostic, a rig signal, a translator's input, the
game's own files read);
2. a `GetModuleFileName`, `W` or `A`, whose module argument is null (`nullptr`, `NULL`, `0`, or a
`GetModuleHandle` of null) -- the exe's PATH asked of Windows directly, the same folder by
another road -- stands only in the files of EXE_PATH_FILES, all four of which read only.
A `GetModuleHandle(nullptr)` used for the module's base is not a path and is not matched.

The lists are keyed by file, not by line: a line moves with every edit. A file added to a list is a
reviewed decision.

python .github/ci/data_paths_gate.py # PASS/FAIL over the tree
python .github/ci/data_paths_gate.py --tree <dir> # the same over <dir>/src/votv-coop/src
python .github/ci/data_paths_gate.py --drill # the gate must fail each planted fault
"""
import pathlib
import re
import sys

ROOT = pathlib.Path(__file__).resolve().parents[2]

# What each file builds from ExeDir(): the reason it stays beside the exe.
EXE_DIR_FILES = {
"ue_wrap/core/paths.cpp": "ExeDir itself, and ExistsBesideExe",
"bootstrap/boot.cpp": "multivoid-loaded.txt, the install marker",
"ue_wrap/core/log.cpp": "multivoid.log and multivoid.prev.log",
"harness/compat_report.cpp": "the compat report",
"coop/bug_report/report_files.cpp": "the bundle's entry for the compat report",
"coop/bug_report/report_bundle.cpp": "multivoid_reports",
"harness/fingerprint_capture.cpp": "the fingerprint capture, a dev diagnostic",
"harness/screenshot.cpp": "coop-screenshots, a dev diagnostic",
"coop/dev/dependency_dump.cpp": "the dev dump",
"coop/dev/rehost_rejoin.cpp": "the rejoin trigger, a rig signal",
"l10n/l10n.cpp": "multivoid_locale, a translator's own files, read only",
"coop/player/skin_registry.cpp": "Content/Paks/LogicMods, the game's pak tree, read only",
"harness/mod_environment.cpp": "Mods/mods.txt and LogicMods, a census of other mods, read only",
"ue_wrap/core/game_build.cpp": "the game's main pak, read only",
}

# The files that may ask Windows for the exe's path with a null module; all read only.
EXE_PATH_FILES = {
"ue_wrap/core/paths.cpp": "ExeDir itself",
"loader/cppmod_entry.cpp": "the scan for an older mod DLL beside the exe",
"harness/sdk_check.cpp": "the compatibility report's exe line",
"ue_wrap/core/reflection.cpp": "LogGameVersion, the exe's file version",
}

EXE_DIR_CALL = re.compile(r"\bExeDir\s*\(")
NULL_ARG = r"(?:nullptr|NULL|0)"
EXE_PATH_CALL = re.compile(
r"\bGetModuleFileName[WA]?\s*\(\s*(?:" + NULL_ARG +
r"|(?:::\s*)?GetModuleHandle[WA]?\s*\(\s*" + NULL_ARG + r"\s*\))\s*,")
SUFFIXES = (".cpp", ".h", ".hpp", ".inc")
HEX_DIGITS = frozenset("0123456789abcdefABCDEF") # a set: the empty string at a text edge is not a member


def number_run(text, i):
"""Whether the word behind text[i] starts with a digit: a number (1, 700, 0xFF, 0xAB'CD'EF; the walk
crosses the earlier separators), where a quote is a separator; case'a' and u8'a' are words, and
their quote opens a character literal."""
j = i
while j > 0 and (text[j - 1].isalnum() or text[j - 1] in "_'"):
j -= 1
return text[j:j + 1].isdigit()


def strip(text):
"""The code of a C++ text, its comments and string and character literals blanked (newlines kept)."""
out, i, n = [], 0, len(text)
while i < n:
c = text[i]
two = text[i:i + 2]
if two == "//":
j = text.find("\n", i)
j = n if j < 0 else j
i = j
elif two == "/*":
j = text.find("*/", i + 2)
j = n if j < 0 else j + 2
out.append("\n" * text.count("\n", i, j))
i = j
elif c == "'" and text[i - 1:i] in HEX_DIGITS and text[i + 1:i + 2] in HEX_DIGITS and number_run(text, i):
out.append(c) # a C++14 digit separator (1'700'000'000), not the start of a character literal
i += 1
elif c == '"' or c == "'":
m = re.match(r'([^()\\ ]{0,16})\(', text[i + 1:i + 19]) if c == '"' and text[i - 1:i] == "R" else None
if m:
end = text.find(")" + m.group(1) + '"', i)
j = n if end < 0 else end + len(m.group(1)) + 2
else:
j = i + 1
while j < n and text[j] != c:
j += 2 if text[j] == "\\" else 1
j = min(n, j + 1)
out.append("\n" * text.count("\n", i, j))
out.append('""' if c == '"' else "''")
i = j
else:
out.append(c)
i += 1
return "".join(out)


def check(files):
"""files: {path relative to src/votv-coop/src, '/'-separated: text}. Returns the faults."""
faults = []
for path, text in sorted(files.items()):
code = strip(text)
for m in EXE_DIR_CALL.finditer(code):
if path not in EXE_DIR_FILES:
faults.append("%s:%d: ExeDir( builds a path from the exe's folder; the mod's own data goes "
"through ModDataDir (allowed files: data_paths_gate.EXE_DIR_FILES)"
% (path, code.count("\n", 0, m.start()) + 1))
for m in EXE_PATH_CALL.finditer(code):
if path not in EXE_PATH_FILES:
faults.append("%s:%d: GetModuleFileName of the null module is the exe's path by another "
"road (allowed files: data_paths_gate.EXE_PATH_FILES)"
% (path, code.count("\n", 0, m.start()) + 1))
return faults


def tree_files(src):
out = {}
for p in sorted(src.rglob("*")):
if p.is_file() and p.suffix in SUFFIXES:
out[p.relative_to(src).as_posix()] = p.read_text(encoding="utf-8", errors="replace")
return out


def drill():
allowed_dir = next(iter(EXE_DIR_FILES))
allowed_path = next(iter(EXE_PATH_FILES))
call = "std::wstring p = ue_wrap::paths::ExeDir() + L\"\\\\multivoid.ini\";\n"
cases = {
"ExeDir call in a data builder": {"coop/config/config.cpp": call},
"ExeDir call over two lines": {"coop/x/a.cpp": "auto d =\n paths::ExeDir\n ();\n"},
"ExeDir call in a header": {"coop/x/a.h": "inline auto D() { return paths::ExeDir(); }\n"},
"GetModuleFileNameW(nullptr": {"coop/x/a.cpp": "::GetModuleFileNameW(nullptr, buf, MAX_PATH);\n"},
"GetModuleFileNameA(NULL": {"coop/x/a.cpp": "GetModuleFileNameA(NULL, buf, n);\n"},
"GetModuleFileNameW(0": {"coop/x/a.cpp": "GetModuleFileNameW( 0 , buf, n);\n"},
"GetModuleFileName of GetModuleHandle(nullptr)": {
"coop/x/a.cpp": "::GetModuleFileNameW(::GetModuleHandleW(nullptr), exe, MAX_PATH);\n"},
"ExeDir after a digit separator": {
"coop/x/a.cpp": "constexpr long k = 1'700'000'000;\nauto d = paths::ExeDir();\n// it's\n"},
"ExeDir after a 3-group hex literal": {
"coop/x/a.cpp": "auto k = 0xAB'CD'EF; auto d = paths::ExeDir();\n"},
"ExeDir after a letter-led hex group": {
"coop/x/a.cpp": "auto k = 0xDEAD'BEEF'CAFE; auto d = paths::ExeDir();\n"},
"ExeDir after case'a'": {"coop/x/a.cpp": "switch (x) { case'a': auto d = paths::ExeDir(); }\n"},
"ExeDir after u8'a'": {"coop/x/a.cpp": "auto s = u8'a'; auto d = paths::ExeDir();\n"},
"GetModuleFileName(NULL, over two lines": {
"coop/x/a.cpp": "GetModuleFileNameW(\n NULL,\n buf, n);\n"},
}
clean = {
"an allowed file calls ExeDir": {allowed_dir: call},
"an allowed file asks the null module": {allowed_path: "GetModuleFileNameW(nullptr, p, n);\n"},
"ExeDir in a comment": {"coop/x/a.cpp": "// the old ExeDir() place\n/* ExeDir( */\n"},
"ExeDir in a string": {"coop/x/a.cpp": 'const char* s = "ExeDir()";\n'},
"a module variable": {"coop/x/a.cpp": "GetModuleFileNameW(mod, buf, n);\n"},
"the module's base": {"coop/x/a.cpp": "auto b = ::GetModuleHandleW(nullptr);\n"},
"GetModuleFileNameEx of a process": {
"coop/x/a.cpp": "K32GetModuleFileNameExW(proc, nullptr, path, MAX_PATH);\n"},
"a character literal beside a digit separator": {
"coop/x/a.cpp": "char c = 'a'; // ExeDir(\nint n = 0xFF'FF; char d = '\\'';\n"},
"ModDataDir": {"coop/config/config.cpp": "auto d = ue_wrap::paths::ModDataDir();\n"},
}
bad = 0
for name, files in cases.items():
if not check(files):
print("drill: the gate PASSED a planted fault: %s" % name)
bad += 1
for name, files in clean.items():
if check(files):
print("drill: the gate FAILED a clean file: %s" % name)
bad += 1
print("data_paths_gate drill: %s (%d planted fault(s), %d clean case(s))"
% ("PASS" if not bad else "FAIL", len(cases), len(clean)))
return 1 if bad else 0


def main():
if "--drill" in sys.argv:
return drill()
base = ROOT
if "--tree" in sys.argv:
base = pathlib.Path(sys.argv[sys.argv.index("--tree") + 1])
src = base / "src" / "votv-coop" / "src"
if not src.is_dir():
print("data_paths_gate: FAIL (no source folder %s)" % src)
return 1
files = tree_files(src)
faults = check(files)
for f in faults:
print(f)
print("data_paths_gate: %s (%d file(s) read, %d fault(s))"
% ("PASS" if not faults else "FAIL", len(files), len(faults)))
return 1 if faults else 0


if __name__ == "__main__":
sys.exit(main())
Loading
Loading