WIP: feat(coop): add relay rooms, accepted progress sync and a Co-op tab #68
No reviewers
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
needs measurements
question
testing wanted
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Longshot!68
Loading…
Reference in a new issue
No description provided.
Delete branch "mooki/Longshot:coop-relay-wire"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
WIP: this waits for the module/core decision in Longshot issue 42, and for the shared text fields in Longshot pull request 51. The module proposal is open with no replies at this check; no implementing native-module pull request was found in the complete public PR title/body inventory. The text-field parent is still open/WIP.
Friends should be able to play separate games and saves while sharing explicitly accepted progress. This working draft supplies the relay, session, consent and progress layer, not other players' Links, enemies, combat, PvP or warp. It remains a core implementation while the proposal to make co-op the first native module is decided.
What changed
mainbecause the forge cannot take a branch of a fork as the base: until pull request 51 is merged, its commits appear here too, and only the commits after the parent's head are this pull request's. The refreshed parent isd5b2ff117905fa9ad4a5def759efa52f7a5c1078; do not duplicate its four feature patches. After it merges, replay only this child range onto main.host/coop_proto.c,coop_state.c,coop.candcoop_net.c: sealed UDP room/session traffic, signed progress/rules, acceptance tied to member/session identity, bounded state and shutdown. The guest game's sockets remain offline. Co-op is off by default.host/oot_coop.c: runtime classification and getter checks, explicit acceptance and whole-save backup before applying accepted progress through the game's setters. Ordinary area changes do not masquerade as save loads; real loads require acceptance/backup again.gpu/vk/vk_menu.cpp/host/coop_menu.c: name/relay text fields, masked room secret, Make/Join/Accept/Leave, maker remedies and Room rules. Main's Auto persistence and live/Dev controls remain. API 23 appendscoop_view/coop_commandafter the parent's text API22; no numeric option ID is added.third_party/monocypheris the original unmodified4.0.2 source with licence/provenance, used under BSD-2-Clause. Kuba's Windows binder fix and all original author/trailer records remain.auto_steps; all Auto key assertions remain.Protocol boundary, not a cosmetic rename: the earlier port deliberately selected Longshot-domain room/message keys, signatures, offers and schema. Its79 vectors were regenerated and the exact nine domains pinned.
longshot-coop-sync/1includes its final ASCII space. These are now fixed wire constants: a future branding change must not rename them. Matching Longshot protocol/game/schema builds can interoperate; Hookshot-domain and Longshot-domain peers cannot, even with the same secret/relay. That is codec/source proof, not a new two-game Longshot session.Flags and settings
The environment overrides below are deliberately refused from the shareable
longshot_env.txt; they require the real process environment. Settings and input are documented indocs/coop.md, linked from the development guide, and the README's menu documentation. Shared progress forces items/songs/quest shared; own progress forces keys own.HOS_COOPHOS_COOP_NAMEHOS_COOP_SERVERHOS_COOP_PORTHOS_COOP_HOSTHOS_COOP_AUTOHOS_COOP_ROOMHOS_COOP_DROPHOS_COOP_TRACEHOS_COOP_DEMOHOS_COOP_ACCEPTHOS_COOP_PROBEHOS_COOP_TEST_SETHOS_COOP_PROGRESSHOS_COOP_ITEMSHOS_COOP_SONGSHOS_COOP_QUESTHOS_COOP_KEYSHOS_COOP_RUPEESHOS_COOP_AMMOcoopcoop_namecoop_servercoop_portcoop_hostcoop_progresscoop_itemscoop_songscoop_questcoop_keyscoop_rupeescoop_ammoCo-op / Your nameCo-op / RelayCo-op / Make a roomCo-op / Join a roomCo-op / Room secretCo-op / Accept the roomCo-op / Leave the roomCo-op / Remove a playerCo-op / Reset the poolsCo-op / Room rulesCo-op / Co-op at startRoom rules / ProgressRoom rules / ItemsRoom rules / SongsRoom rules / QuestRoom rules / KeysRoom rules / RupeesRoom rules / Ammocoop_relay.py --hostcoop_relay.py --portcoop_relay.py --log-addrscoop_relay.py --max-roomscoop_relay.py --rooms-per-networkcoop_relay.py --log-joinscoop_relay.py --member-copiescoop_relay.py --member-bytesCustom output sizeoutput_resRX_VK_MENU_SCRIPTco-op tests --ccco-op tests --cxxco-op tests --sourceco-op tests --sealedMeasurements
Branch state: on main
d725b3631982ed0035ea3ac9cbe1677e9fad260c; headcca2aebb03efac4d4e070469fd0690800931e2db; whole game-free suite on this head:522 passed, 1 failed, 20 skipped(maind725b3631982ed0035ea3ac9cbe1677e9fad260c:510 passed, 1 failed, 20 skipped); the commits are unchanged by rebases apart from the results table.The only failure on both heads is
tests/test_updater_asset_digest.py: local .NETNU1100, missingMicrosoft.AspNetCore.App.Ref (=10.0.13). The base suite was run once for all moved pull requests of this day; no extra main suite was run for this draft.main:
d725b36319(2026-11-12)this PR: coop-relay-wire @
cca2aebb03Hardware: Core i9-13900K,96GB RAM, Arch Linux7.2.15-1-omarchy; repository-default compiler selection. No GPU used for the new checks.
Scene: authored game-free protocol/session/relay/progress/menu fixtures, not a new game session.
Method: whole suite on the exact refreshed head after the last commit; the main suite is shared across today's moved PRs. Windows-target syntax captures are separate from native execution. No current-game/off-cost measurement or paired speed claim.
How to reproduce:
python -I -B tests/run_all.py --jobs 6 --strict; focused protocol checks arepython -I -B tests/test_coop_proto.pyandpython -I -B tests/test_coop_relay.py. A real two-game proof requires matching Longshot builds, separate disposable saves, reachable relay, manual room acceptance and checked backups; it was not run during this move.d725b3631cca2aebbThe Windows 39-unit result is carried from
a6dcac8f(the same patches before the rebase), not a new comparison.The earlier suite on the d4a69456-based co-op head was519/2/20: that error plus Auto's stale terminal-semicolon expectation. The latter was repaired, and the full suite repeated on the exact final head. Main
d725b363differs fromd4a69456only by scripts, docs and tests, not game code; earlier labelled functional evidence is not invalidated, but this does not turn old Hookshot co-op runs into Longshot protocol proof.All co-op drivers passed in the final whole suite. The old-domain negative test stays literal. The retained port proof reproduced the old vector file byte-for-byte before generating the new family; current vector SHA-256 is
ac00e565141b5c85300dd66f694e17b413d5074abc1010be555c7349eaf3506c. The original79-vector/66-relay-test proof is historical port evidence, not an extra fresh game run.The two unjudged entries are the Python relay's execution and the POSIX-only save-copy driver. Windows runtime-dependent variants were not run. A small Linux empty-environment contract probe passed; it is not Windows networking. The original posted record says GitHub head
9ba4ee007d87112569c47067b8140a7c498d80a9passed Windows and Ubuntu, every job, in fork run43291054852. This historical success is not a check of the new Longshot domains/integration. These checks have not yet been run on a forge runner.Historical game evidence and its limits, retained: Hookshot binaries
2be28f89, Linux/RTX4090/NVIDIA615.78.08,2026-11-12, two windowless games on one PC with separate saves.Historical log excerpts, not from this Longshot head:
These ordinary correctness runs are not a performance/bandwidth comparison. The earlier71d4ab0f tab panel did not open B's Equipment screen and its item proof was a log, not a visible sword pickup. Kuba's Windows71d4ab0f-plus-bind-fix report showed build/link/run, loopback Make/Join/Leave and typing, but not Accept/progress/LAN/cross-OS/controllers/suite; it also included a shader-start fault seen on releases.
Testing
Tested: On this PC: Arch Linux, RTX 4090, NVIDIA 615.78.08, Core i9-13900K. No GPU was used for the new game-free checks: the current-head suite covered co-op protocol/session/relay/sync/events/menu/save drivers. The carried Windows-target check compiled 39 translation units, with no compilation failures and two unjudged drivers; not run on Windows. Historical Hookshot
2be28f89runs on this PC used two windowless games with separate saves: manual scripted Make/Join/Accept, checked whole-save backups, item/song exchange, rename/reacceptance and the corrected maker-exit observation. Their floor-switch and debug-granted Lens checks retain the limits stated above; none is a new Longshot game session or proof of the new protocol's two-game interoperability.Tested but not measured: historical Hookshot menu/progress/hosted-link correctness above; no fresh Longshot gameplay. New source/fixture checks are not gameplay or performance.
Not tested: Current Longshot game build/play, two-game protocol interoperability, off-cost, public relay deployment and the current-runtime cases below. This move stayed source-only while the module/core decision and shared text-field parent remain open. No test request was posted during this move.
The original draft's remaining limitations (the platform/network checks are requested below; the later historical flag/Lens evidence above does not establish a fresh Longshot session):
No current-head game build/play, GPU/two-game/manual-consent/loading-zone/hosted-game proof. No more than two real games, AMD/Deck/controller or Linux physical typing proof. No corrected Lens crossing, new chest/rupee chest/boss/door behavior, remote-area chest, live Remove/Reset/rule change or manual backup restoration. No performance/bandwidth proof or gameplay layer built on events.
Needs other testers:
Screenshots
No current Longshot co-op screenshots: main @
d725b3631has no co-op, and this PR @cca2aebbwas not run in the game. Both retained pictures below were inspected and are explicitly historical.Risk and rollback
Wrong classification or authorization can affect saves. Acceptance, checked whole-folder backup, getters and game setters remain mandatory; being on the roster or receiving an ACK is not consent or completed-backup permission. Network loss/NAT/shared budgets and maker departure can prevent delivery. A restarted maker retaining a key but lacking room rules remains an open design question.
Leave the room or set
coop=0/HOS_COOP=0to disable the session; leavecoop_host=0/HOS_COOP_HOST=0to avoid hosting. Turning off stops further sharing but does not undo already merged progress: recovery uses the pre-room backup, whose manual restoration is not freshly tested. Reverting the child commits removes co-op code but likewise cannot undo an existing save. No firewall/router automation or public relay is enabled by this PR.Reviewer notes
Start with the protocol/domain boundary,
coop_state.cconsent/session/backup gates,oot_coop.cclassification/setters and event cancellation/ACK epochs. Review shared text fields in parent51, not twice. The module/core choice is unresolved in issue42; no loadable-module interface is implemented here. Bodies/enemies/bosses/PvP from itzdaface remain separate work, not silently included. The original questions about a host UDP socket, stage splitting, relay/library ownership, tab/settings names and maker restart remain open.Issues
Original draft: https://github.com/NotRexed/Hookshot/issues/2274
Original proposal: https://github.com/NotRexed/Hookshot/issues/2269
Original combined gameplay proposal: https://github.com/NotRexed/Hookshot/issues/2578
Original module direction: https://github.com/NotRexed/Hookshot/issues/2892
The module-direction issue now exists at #42 . The text-field parent is #51 . See #42 for the module direction and See #83 for stopping a windowless game cleanly on Windows, which a tester raised here and which this does not settle. Old GitHub numbers are not Forgejo closing references.
Checklist
For everyone
type(scope): description).main. Through the shared text-field parent.python -I -B tests/run_all.pyrun and passing (any failure that also fails onmainis named above).third_party/untouched (a new folder with aPROVENANCE.mdinstead). New Monocypher folder only.If applicable
Assisted-by:/Co-Authored-By:trailers.MKWVK_API_VERSIONbumped (gpu/vk/vk_api.h'sMkwVkHostorMkwVkRendererchanged).tests/that reads changed source updated in this PR, not weakened.Moved from NotRexed/Hookshot#2274.
Assisted-by: Claude Opus 5.5
Co-Authored-By: Claude Opus 5.5 [email protected]
Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra [email protected]
The fixture's helper was named accept. On Windows the host's network header brings in winsock2.h, which declares accept(), so the Windows checks could not compile the fixture ("conflicting types for 'accept'") and the event tests never ran there. The helper is named grant. Tested: all eight C fixtures this branch adds or changes compiled for the Windows target (clang --target=x86_64-w64-mingw32, -Wall -Wextra, syntax only): this fixture had 15 errors before and has none now; the four other co-op fixtures show none (three fixtures that take their sources or defines from their Python drivers cannot be judged by that pass). Linux, GCC 16.2.1 and Clang 23.1.3: tests/test_coop_events.py passes as before. Not tested: run on Windows (the project's Windows job does that). Assisted-by: Claude Fable 5.2 Co-Authored-By: Claude Fable 5.2 <[email protected]>Discussion carried over from NotRexed/Hookshot#2274
Every comment that was readable on the original thread when it was copied on 2026-11-12, in order, unchanged except that issue and pull request numbers are written as links to the old repository and names carry no @. Comments by an account that has since been closed there could no longer be read and are missing; where a reply quotes them, the quote remains.
mooki000, 2026-11-12 00:13 UTC (comment, original):
This draft now carries the whole stack as six commits (it was the first part only): the relay and wire format, the merge engine, the runtime session, progress sync, text fields in the Insert menu, and the Co-op tab. Head
71d4ab0fon mainfce53453; it merges withef81aee7without a conflict.The description is rewritten for it: what each commit adds and its tests, how to try it on two PCs or on one, the two-game session on this head, what failed in the test runs and why, what is not tested (Windows first of all: I have no Windows PC and would be glad of a tester), and six questions at the end. It stays a draft until the first of them, a socket in the host at all, is answered.
mooki000, 2026-11-12 01:02 UTC (comment, original):
NotRexed hckrman101 an update that bears on the questions in this draft's description, and one new question.
Two co-op drafts are becoming one. itzdaface opened NotRexed/Hookshot#2578 the same evening as this stack: Windows only, a direct link over a VPN, and well ahead of mine on what players see (the other players as animated Links, shared enemies, bosses, PvP, played with real friends). We agreed there to put them together under this pull request: this stack as the link, the session, consent and progress sync, and his bodies, enemies, bosses and PvP on top as his own commits, ported to this stack's sealed messages. He is building this branch on Windows first, which nobody has done yet. Both drafts stay drafts until you have answered question 2 here: whether a socket in the host is acceptable at all.
Stages (question 1 here, now larger). Together this is a lot to review. Would you take it in this order, each stage off by default and reviewable alone?
The relay (question 3 here, now more pressing). His players asked why co-op needs a VPN, and a relay that someone has to run is the same hurdle moved. I am adding "host on this PC": the relay inside the game for a room's maker, so that on one home network there is nothing else to start, and across the internet the maker forwards one UDP port. Beyond that: would the project consider hosting a public relay? It cannot read or change what it forwards (the room's secret never reaches it), and it has limits per member, per network and in all.
itzdaface, 2026-11-12 02:21 UTC (comment, original):
mooki000 Windows results for
71d4ab0f, as promised. Short version: one compile error, a two-line fix, and after that everything I tried works.Setup: Windows 11, Ryzen 7 7700X, RTX 3060 12 GB, 32 GB RAM. Built with
nx2/make_game.py --updateinto its own game folder, using the Python and llvm-mingw (clang 23.1.5) that ship with the v2.1.0 Hookshot Builder. The relay ran under Python 3.14.5 on the same PC.1. Does it build? Not as it is, by one name
host/oot_coop.chas a static function calledbind. On Windowscoop_net.hpulls inwinsock2.h, which declaresbind(SOCKET, ...):It was the only file in the whole build that failed. The fix is a rename:
With that, everything compiles and links, Monocypher and
-lws2_32 -lbcryptincluded. I did not run the test suite, so I have nothing on the two tests you said don't build on the Windows job.2. Does it run? Yes
First start prepared 38,809 shader programs and the pipelines and ended cleanly. My NVIDIA driver faulted on one pipeline during that, which the game skipped. That also happens on this PC with release builds, so I don't think it is yours.
3. Make a room and Join through a relay on 127.0.0.1? Yes, both ways
Two games on one PC, two folders, from the environment (
HOS_COOP_AUTO=createandjoin, a fixedHOS_COOP_ROOM, both headless):the relay answered in 3 ms,room 234… created (member 1), thenSecond (member 2) joined the roomthe relay answered in 2 ms,Kuba (member 1) joined the room,joined room 234… as member 2silent 15 s, as the doc saysBy hand, from the Co-op tab, in a window, with a second headless game waiting in a room:
WM_CHARis fine)room XHM… created (member 1)in the game,createdandjoined as member 1in the relayKuba (member 1) leftand closed the room at oncejoined room 234… as member 2, and the tab listed the other player4. What does the firewall ask? Nothing
No Windows Firewall prompt appeared, and there is no firewall rule for either test exe afterwards. That is with the relay on loopback only, so it says nothing yet about a relay on another machine.
Not tested yet
Two small notes
HOS_HEADLESS) does not close when Windows asks it to (taskkillwithout/f; there is no window to take the request), so I had to force it. That is why the headless runs showsilent 15 sand not a goodbye. From the window, Leave says goodbye properly.os.link) costs no space and worked fine, since the game only reads them. Might be worth a line in the doc.The fix
It is one commit on my branch (
coop-win, on top of your head). If you add me (itzdaface) as a collaborator on your fork I'll push it straight ontocoop-relay-wire, and later the body, enemy and PvP commits the same way. If you'd rather review each one, I'll open pull requests against your branch. Or just take the two lines above; it's faster than either.mooki000, 2026-11-12 02:27 UTC (comment, original):
itzdaface thank you, this is exactly the report this draft was missing.
The fix goes in as you wrote it (
bindtobind_tables), as a commit with you as co-author, in the next push. I owe you an admission: a Windows-target syntax pass on my side showed this very error earlier today and it was misread as a fault of the check. That pass now runs over every co-op file before a push, and its errors count.The head is about to move, so please wait for it before the next test. The next push replaces
71d4ab0fwith the same six commits on current main (the Bug report row that merged today changes the same menu code as the Co-op tab), and adds:71d4ab0fthe room is offered again, and the save copied again, at every loading zone (the clock I watched to notice "another save was loaded" restarts with every area). Accept and sync work, but you would see the offer come back each time you change area;The helper for messages that must arrive comes a little later: review found two defects in it (a cancelled half-sent event blocked later ones; acknowledgements of two attempts could add up), and it goes in when its tests pass.
Your commits: pull requests against
coop-relay-wireon my fork, please. I merge them without squashing, so they stay yours, and I look at each the same day. I rebase that branch on main now and then and will say so here before I do.Or the other way round, if you prefer: what matters to me is that this base ends up under your players, enemies and PvP, not which pull request carries it. If you would rather keep NotRexed/Hookshot#2578 as the one, say so, and I open the base as a pull request against your
feat/coopinstead; this draft then stays the place where the base alone can be read and tested.Your two notes: the hard-link tip goes into the doc. The windowless game that ignores a polite close on Windows is not co-op's alone; I will look at a console handler for it separately. And thank you for the firewall check: with the relay inside the game, the maker's game listens on a UDP port, so Windows will ask then; I will write down what it asks once one of us has seen it.
Edited: the change merged today is a Bug report row in the Gameplay tab, not a tab of its own; I had the wrong word.
itzdaface, 2026-11-12 02:32 UTC (comment, original):
mooki000 sounds good on all of it. Pull requests against
coop-relay-wireworks for me, and I'm happy with NotRexed/Hookshot#2274 staying the one. I'll wait for the new head, rebuild, and test Accept, sync and "Host on this PC" on Windows, including what the firewall asks.mooki000, 2026-11-12 06:03 UTC (comment, original):
itzdaface the new head is up:
2be28f89, 18 commits on mainde866017(it merges cleanly with main as of now). The branch was force-pushed once, as announced; rebase yourcoop-winon it and send your commits as pull requests againstcoop-relay-wire.What is above the six commits you built:
1c60356fyourbindrename, with you as co-author; the macroINin that file is renamed too (it shadowed a Windows header's).184cceb0,1cd02fc4,68088064: the two tests that did not build on the Windows job, and a fixture's thread count.1f1d0a72the loading-zone fix: the room is no longer offered again and the save no longer copied again at every area change (it watched a clock that restarts in each area; it now watches the save's total play time). A real load of another save still asks again.d2fc0f7fthe relay's limits: 480 forwarded copies and 256 KiB a second per member (twice that as burst), as options ofscripts/coop_relay.py.35931fa8,2be28f89messages that must arrive:coop_send_event(member, kind, bytes, n)andcoop_on_event(kind, callback, user). Up to eight queued events of at most 16 KiB each, sent in 1024-byte parts, sealed anew at every resend until acknowledged, delivered whole, once and in order per sender; leaving, a new session or withdrawn consent cancels. An acknowledgement means "delivered to the callback", not "the game accepted it".b8d0cbedcoop_member_accepted(id): whether this player has accepted that member in this session. Being on the roster is not consent.c517e746docs/coop.md, "Adding a layer": kinds, the calls above, pacing, and what a receiver checks.97f56483,dcf84430Host on this PC: withcoop_host=1inhookshot_options.ini(orHOS_COOP_HOST=1), Make a room starts the relay inside the maker's game (UDP 24680 unless the Relay field names another port). Off by default.Tested here: game-free only, with GCC 16.2.1 and Clang 23.1.3: the protocol, session, relay, event, hosted-relay and text-field checks pass with both (I ran those six myself on this head); the loading-zone and the event fixes each fail on the old code. A Windows-target syntax pass over the 17 host files that are built on Windows shows no error and no clash with a Windows header name. Not done on this head: no game has been built or run from it yet, on Linux or Windows; a two-game session here is queued for tonight and I will post what it shows.
What would help most from Windows, in this order: does it build; Make, Join and Leave through
python -I scripts/coop_relay.py --host 127.0.0.1 --port 24680as before; then Accept and progress sync across a loading zone (the offer should come once, not at every door); then the same with the script stopped andcoop_host=1on the maker, and what the firewall asks.mooki000, 2026-11-12 08:14 UTC (comment, original):
The two-game session on the new line, as promised. Built from
2be28f89; the head is now2f412422, which adds two test-only commits for the Windows checks (a fixture helper namedacceptbeside winsock's, and an emptyHOS_COOP_HOST, which a Windows process cannot hold), so the game code is the same.Setup: Arch Linux, RTX 4090 (NVIDIA 615.78.08), one full build (11 min 24 s) and two copies of it, two games on this PC with their own saves, the relay script on loopback, no window. Everything co-op was set in the Co-op tab by scripted input: no
HOS_COOP_AUTO, noHOS_COOP_ACCEPT.What it showed, in order (2026-11-12 02:04:26 to 02:09:14 local, 288 s; both games exited 0):
No fatal line, crash or device loss in either log, and no kernel or driver message during the run. The run's three checklists (the stack's, the tab's and the older session's) pass with no failure.
Not shown by this run: the relay inside the maker's game (a link-only run of it is next on this PC tonight), a loading zone after acceptance (the fix is shown by its game-free test only), two PCs, Windows, a controller, more than two players.
mooki000, 2026-11-12 08:21 UTC (comment, original):
The in-game relay, two games on this PC, same build (
2be28f89), 02:14:39 to 02:16:41 local:coop_host=1on the maker only and no relay script running, Alice's game logshosting on this PC, makes the room, and its own relay admits Bob; each game sees the other in the room.I am repairing the stop step and running that part once more tonight; the result goes here.
mooki000, 2026-11-12 08:38 UTC (comment, original):
The repaired rerun of the in-game relay's last step (same build
2be28f89, 02:33:34 to 02:34:58 local): passes.coop: relay lost; rejoining, thencoop: connecting to the relayand repeated connection attempts. So the joiner notices that the maker and its relay are gone.Not claimed: that Bob can do anything useful after the loss (he keeps trying to reconnect to a relay that is gone; what the tab should say then is a design question for this pull request), acceptance or progress over the in-game relay, a Leave from the tab.
mooki000, 2026-11-12 12:46 UTC (comment, original):
First, a correction to my reply on NotRexed/Hookshot#2578: one “damage taken so far, highest wins” total loses simultaneous hits from different players. Keep a cumulative component per member/session and enemy incarnation, merge each component by maximum, then sum and clamp to the agreed life cap. Repeated state adds nothing; received damage must not be counted again as a local hit. The pushed “Adding a layer” docs carried the same wrong sentence; it is corrected in
a4c080e0.itzdaface, the base is now
a4c080e0. The game code is still that of2be28f89: the intervening commits are two test fixes and this documentation correction. The two-game tab result therefore covers the same game code: acceptance, save backups and progress exchange through the separate relay. The in-game relay has shown make/join and noticing the maker's exit, not yet acceptance/progress or tab Leave over that relay.For your port, I'd keep the split we agreed:
coop_send_event/coop_on_eventfor PvP requests and boss hand-over, rather than another retry loop. OnlyCOOP_EVENT_QUEUEDmeans it queued; handle a full queue. An ACK means callback delivery, not accepted damage.Callbacks borrow their bytes on the co-op thread: copy bounded work for the game update, then recheck accepted member/session, signed feature permission, area/incarnation and freshness there. Keep mutual PvP opt-in and your cutscene/recovery guard; let the receiver adjudicate a hit rather than trusting a requested heart subtraction. Retries have no time limit while the same accepted sessions remain, so stale hits must still be rejected.
Your planned Windows Accept/sync/hosting checks remain useful, especially a loading zone after acceptance. The base does not yet contain the body, enemy or PvP implementation; those remain your gameplay commits, through pull requests against
coop-relay-wireas agreed.mooki000, 2026-11-12 17:32 UTC (comment, original):
Three proofs from two games running together, as promised for this draft.
Floor-switch flag SHOWN; Lens of Truth SHOWN; clear-room sharing NOT SHOWN by this method.
Two windowless games on one Linux PC (RTX 4090), separate saves, automatic room acceptance and a local relay; not a Windows or two-PC test.
Floor-switch flag — binaries built from
2be28f89, with identical game code to this PR'sa4c080e0.A walked onto the real switch; B stood still. With progress sharing on, both players' flag changed from 0 to 1.
Extracted sender log:
[hos host] coop: sync: sent progress 6fb4f455 = 1 to all.Extracted receiver log:
[hos Presentation Thread] coop: sync: the game shows progress 6fb4f455 = 1 (its getter agrees).With progress sharing off, the same steps set A's flag to 1 while B stayed at 0; the shared-flag assertion correctly failed.
Nothing visible changes on B's screen for this one, so the evidence is the flag in both games (the log lines above and each game's getter), not a picture. The permanent flag transfers; the live switch and its platform timer are not shared.
Lens of Truth — binaries built from
2be28f89, with identical game code to this PR'sa4c080e0.A received the Lens through a debug aid, not from a chest. B received no local grant before the inventory pictures.
Extracted receiver log:
[hos Presentation Thread] coop: sync: applied items 49d1c374 = 1.Receiver's later getter:
[hos BaseProcExecutor3] cheats: inventory Item_GlassTruth +1 (had 1, now 1, event status 2).Both Equipment pages start with an empty Lens slot and then show the goggles, including B's unselected icon.
With item sharing off, A still gets the goggles but B has neither the count nor the Equipment icon; the same transfer assertion fails.
Negative receiver getter:
[hos BaseProcExecutor4] cheats: inventory Item_GlassTruth +1 (had 0, now 0, event status 2).Getter probes happen after the pictures; their
hadvalue is the prior count, and the negative probe itself then grants the item locally.The Equipment page after the grant, player A left and player B right; sharing on above, off below:
Clear room: NOT SHOWN by this method. The scripted sender never clears its room with sharing on or off, so the response to a real clear was not tested. This is a gap in the test, not a finding about the feature; it needs a working clear route or a player to perform the clear.
All games in these four shown-proof runs exited normally, without logged runtime or driver faults. No performance claim or actual Lens-use claim is made.
mooki000, 2026-11-12 18:33 UTC (comment, original):
A note on direction, so nobody is surprised: in NotRexed/Hookshot#2892 I have proposed that co-op become the first module on a small mod interface (the same one a randomizer or a restoration mod would use), instead of landing in the core as this draft has it. That delays co-op, and I think it is the better shape for the project. Whether native modules are acceptable at all is the maintainers' call, and it is one of the questions there.
Until that is answered this draft stays the working branch: it is being rebased over today's main, with a fix for the Windows check that fails here (two test modes shared one UDP port; on Windows a wildcard socket and a loopback one can both bind it, so the fix takes the port exclusively).
itzdaface this touches what we agreed about combining our work: the link, the session and your layers on top would stay as planned, only where they live would change. Your view is welcome in NotRexed/Hookshot#2892.
mooki000, 2026-11-12 19:42 UTC (comment, original):
Co-op rebase:
9ba4ee00on9b6072cd, API 23.The four shared text-field patches retain identical changed lines; range-diff shows 25 identical entries and one context-only Co-op menu entry.
The
save()join keeps co-op settings and drops the obsoletemesh_shaderskey. Only the Mesh shaders row disappears; no Co-op row moves.Windows now requests
SO_EXCLUSIVEADDRUSEbefore binding native co-op and Python relay sockets. Without it, Winsock permits same-user wildcard/specific-address binds to coexist: another program could receive/inject raw datagrams and disturb rooms. Those packets do not reveal sealed player payloads without the room secret; addresses/control metadata are unencrypted. Linux sets neitherSO_REUSEADDRnorSO_REUSEPORTand already rejects overlapping binds.Checks: 38 drivers pass with GCC and Clang, including menu row/order and README checks; Linux full suite 518 passed, 0 failed, 20 skipped. PR preflight and three Windows-target menu syntax captures pass (not Windows execution).
The b7f5a87d fork run passes all eight co-op drivers on Windows and Ubuntu, including port-ownership probes and unchanged concurrent modes; its whole workflow remains red on old-main README and Windows shadow-fixture checks.
No game rerun: the prior two-game Linux evidence covers byte-identical co-op gameplay/update/sync code, supported by the range-diff; it does not prove the changed Windows UDP ownership behavior.
On this exact head a full run of the project's checks in my fork is green on Windows and Ubuntu, every job (run 43291054852): the first fully green Windows run this branch has had. No Windows game, firewall or cross-PC play claim is made.
Direction, as noted above: in NotRexed/Hookshot#2892 I have proposed that co-op become the first module on a mod interface rather than land in the core. This branch stays the working copy, kept current, until that is answered. It also carries NotRexed/Hookshot#2594's four text-field commits underneath; review of those belongs there.
Added the three-part Testing section and updated the full checklist. Added one branch base/head/suite block under Measurements; apart from consolidating duplicate results and minor wording cleanup, nothing else changed.
View command line instructions
Manual merge helper
Use this merge commit message when completing the merge manually.
Checkout
From your project repository, check out a new branch and test the changes.