Commit Graph
50107 Commits
Author SHA1 Message Date
Henrik RydgårdandClaude Opus 5.5 a4e1db4c78 adhoc_multi.py: On CI, show a failing instance's warnings and errors
Pair tests that fail only on a CI runner give nothing to go on but the
output diff. The instance sync's and the relay's warnings say where an
instance stalled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:26:37 +01:00
Henrik RydgårdandClaude Opus 5.5 ec7064e40b test.py: Run the relay ad hoc tests at 800%
Every hop through the relay waits a millisecond or so of real time, which
the speed multiplies: at 1600% on macOS CI a relay PTP receive in
pair/ptppoll timed out. Relay mode hardly gains above 800% anyway (26 s
against 22 s locally); P2P stays at 1600%.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:17:04 +01:00
Henrik RydgårdandClaude Opus 5.5 87636d5132 Instance sync: Leave it out of UWP
UWP has no CreateFileW, and no headless build to run the ad hoc tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:17:04 +01:00
Henrik RydgårdandClaude Opus 5.5 00382b2e6b test.py: Run the ad hoc tests at 1600%, and pair/vanish in P2P again
With the instances in step, a busy runner no longer pulls them apart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:04:00 +01:00
Henrik RydgårdandClaude Opus 5.5 7c9944b478 sceNetAdhoc: Forget a blocking PTP connect when it's done
Its entry in sendTargetPeers stayed, so the next blocking connect from
the same thread on a socket that got the same id returned BUSY
(pspautotests net/adhoc/pair/basic, connect to a closed port, after a
connected socket was closed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:04:00 +01:00
Henrik RydgårdandClaude Opus 5.5 a1a197e685 sceNetAdhoc: A relay PDP send off the network doesn't need a session
Off the network the datagram reaches nobody and the send succeeds, but
the session was recovered first, and a send whose session wasn't up
returned WOULD_BLOCK (pspautotests net/adhoc/pair/vanish, PDP send after
leaving).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:04:00 +01:00
Henrik RydgårdandClaude Opus 5.5 56148606e5 Headless: Keep ad hoc test instances in step in emulated time
Each instance paced itself against the wall clock, so on a busy machine
the one that got less CPU fell behind, and anything a test times across
instances (a peer leaving, a matching timeout) came out differently with
the load: pair/vanish and pair/matching3 failed on macOS CI.

With --sync-file and --sync-count, instances on one machine share a file
of one slot per instance. CoreTiming ends a slice at every emulated
millisecond, publishes it there, and waits until every other instance
has reached it too, so they're never more than a millisecond apart. It
works for any number of instances. One that stops moving (a debugger
pause, a crash) is waited for 2 s and then left out until it moves
again, and one that blocks the CPU thread in real time on something the
others must do (the relay PTP connect) stands aside meanwhile.

Tools/adhoc_multi.py and adhoc_session.py use it (--no-sync turns it
off). The host's 1 s head start is gone: they wait for the server's
port instead. adhoc_multi writes each instance's output to a file, as a
full pipe would now stop the other instances too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 09:04:00 +01:00
Henrik RydgårdandClaude Opus 5.5 841902950a proAdhocServer: Wait for logins and messages with select instead of polling
- Fixes #19248

The server loop polled every socket and slept 10 ms, so it woke 100
times a second with nothing to do, and every message could wait up to
10 ms of real time before it was handled, which at a sped-up emulation
speed is many times that in game time. It now waits in select() on the
listening socket and every user, and wakes at least every 50 ms to notice
being stopped. It also no longer stops serving everyone while the hosting
instance is paused in the debugger.

pspautotests: pair/discover and pair/ptpmsg.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 08:08:20 +01:00
Henrik RydgårdandClaude Opus 5.5 4221c4cd54 sceNetAdhoc: Receive PDP through a queue of the socket's buffer size
A PSP keeps what arrives in the socket's buffer, of the size given to
PdpCreate, and drops a datagram that doesn't fit: a buffer of 0 gets
nothing, one of 2048 bytes only some of ten 1000-byte datagrams
(pspautotests net/adhoc/pair/flow). Each transport now only hands over
the datagrams that have arrived (PdpTakeDatagram), into a queue per
socket that is filled every millisecond and whenever the game looks, and
PdpRecv, its blocking retry, GetPdpStat, PollSocket and game mode read
from that. This replaces each transport's own receive paths, so the
relay now reports the sender with NOT_ENOUGH_SPACE too, and P2P's
blocking receive no longer misreads a stale errno.

A datagram to ourselves goes straight into our own socket's queue, as on
a PSP, so it's there at once through the relay too (net/adhoc/term).

Also from comparing the transports:
- P2P: a blocking Accept of a connection from outside the group keeps
  waiting instead of returning -1.
- Relay: an accepted socket gets an id of its own, not its listener's,
  which blocking calls are told apart by.
- ALERT in PollSocket comes from the socket in both transports.
- No send/receive timeouts are set on the game's sockets: all host
  sockets are non-blocking, and in relay mode the ids aren't host
  sockets at all.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 08:05:38 +01:00
Henrik Rydgård 1b490893e0 Merge pull request #22856 from hrydgard/adhoc-matching-coretiming
Adhoc: Matching in emulated time, a relay poll fix, and pair tests in both modes in CI
2026-10-31 08:05:17 +01:00
Henrik RydgårdandClaude Opus 5.5 02db3f1be4 test.py: Skip pair/vanish in P2P mode for now
It times the socket failures from when the peer drops off the peer list,
which the ad hoc server updates in wall time, so on macOS CI at 600% the
failure lands under a second after it instead of 1-2s. The relay run
still covers it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 07:17:43 +01:00
Henrik RydgårdandClaude Opus 5.5 670b667ed1 test.py: Run the ad hoc tests at 600% on CI
Each instance runs on its own, so on a busy runner they drift apart in
emulated time, and a real second's lag is 8 emulated seconds at 800%:
long enough for pairSync (10 s) to give up on macOS CI. ADHOC_SPEED
still overrides it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 01:49:58 +01:00
Henrik RydgårdandClaude Opus 5.5 978eb5bafe sceNetAdhoc: Check a pending P2P connect the way Winsock reports a failure
Winsock never makes a socket whose connect failed writable; the failure
shows in select's exception set, with the reason in SO_ERROR. The poll
now checks both, and SO_ERROR on a writable socket too, which is where
other systems put a refusal.

Windows still retries a refused connect for about a second before
reporting it, far longer than a PSP at the tests' 800% speed, so
pair/basic is a known P2P failure on Windows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:48:11 +01:00
Henrik RydgårdandClaude Opus 5.5 31369e70fe sceNetAdhoc: Windows fixes for P2P refused connects and off-network receives
- A connect PtpOpen started counted as up as soon as getpeername
  succeeded, which on Windows happens while it's still in progress, even
  one about to be refused. It now needs the socket ready too, and a
  pending connect's failure is read from SO_ERROR, the only place Windows
  reports it (pspautotests net/adhoc/pair/basic).
- Out of the group, PdpRecv only dropped what its peek saw; on Windows a
  peek can fail and leave the next datagram unchecked, so a vanished
  client still got the host's data (pair/vanish).

pspautotests: pair/vanish times PTP's failure from when the peer left the
peer list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:44:36 +01:00
Henrik RydgårdandClaude Opus 5.5 58d051130c sceNetAdhoc: Wait for a relay PTP connect at a fixed point in emulated time
The connect PtpOpen starts goes through the relay on a host thread, so
when it finished in emulated time depended on the emulation speed and on
how busy the host was. At --speed=800 on a loaded CI runner it often
wasn't up within the 100 ms net/adhoc/pair/ptppoll polls for, while on a
PSP it's up a few ms after PtpOpen.

The relay's per-millisecond poll now waits (at most a second, once per
connect) for a connect in progress to finish, filling local listeners'
backlogs meanwhile, since the listener may be on the same console.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:44:36 +01:00
Henrik RydgårdandClaude Opus 5.5 be7a3261b5 sceNetAdhoc: Say why PdpCreate, PtpOpen and PtpListen ignore the game's MAC
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:44:36 +01:00
Henrik RydgårdandClaude Opus 5.5 80d9952861 pspautotests: pdp and ptp cover a late too-big datagram and closing while connecting
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:44:36 +01:00
Henrik RydgårdandClaude Opus 5.5 321a440884 test.py: Run the single-console ad hoc tests in relay mode too, and basic in CI
Like the two-console tests, each runs through the built-in server's relay
and in P2P, with adhoc_known_failures for the ones that fail in one mode.
pair/basic passes in P2P now and moves to tests_good, a known failure
through the relay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:44:36 +01:00
Henrik RydgårdandClaude Opus 5.5 8f1406739e sceNetAdhoc: Relay fixes from comparing the transports' error handling
- GetPtpStat on a listener read its listen session as a connection,
  which could write past it; a listener now reports nothing waiting.
  Neither GetPtpStat nor GetPdpStat reports a dead session's negative
  status as a byte count any more, and a new PDP socket starts with
  nothing waiting instead of its buffer size.
- A poll of a connection whose peer has closed reports DISCONNECT, as
  the P2P transport and a PSP do (pspautotests net/adhoc/poll).
- Only a send that went out counts as the last send for a vanished
  peer's timeout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:44:36 +01:00
Henrik RydgårdandClaude Opus 5.5 c88d3584b5 sceNetAdhoc: A refused PTP connect returns CONNECTION_REFUSED, as on a PSP
A connect to a port nobody listens on is refused within a second on a
PSP, and every later connect on that socket is refused too, even once
something listens there (pspautotests net/adhoc/pair/basic,
pair/ptpclose). PPSSPP recreated the socket and tried again until the
game's timeout ran out, to cover a peer that wasn't listening yet.
Dissidia 012 and Fate/Unlimited Codes, named in the old comments, still
get to their matches.

Also set the established time wherever a connection becomes established,
which the timing of a vanished peer's failure counts from.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:44:36 +01:00
Henrik RydgårdandClaude Opus 5.5 99e518d2b2 sceNetAdhoc: Time adhocctl requests and the joiner's GAME wait in emulated time
How long an adhocctl request waits for the server before giving up, and
how long a joiner's GAME event waits for the host to show up, were
measured in wall time, so a game saw them shorter when sped up and
longer when slowed down.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:44:36 +01:00
Henrik RydgårdandClaude Opus 5.5 f988ab9566 sceNetAdhoc: A relay listener accepts connections into its backlog by itself
A PSP completes a connect to a listener without the game calling Accept,
so an opened PTP connection is up a few ms after PtpOpen (pspautotests
net/adhoc/pair/ptppoll). The relay only answers the connecting side once
the listening side accepts, so the relay transport now accepts pending
connections into a queue as long as the listener's backlog, from a new
per-millisecond AdhocTransport::Poll() and from polls and accepts, and
PtpAccept takes them from there. A poll reports ACCEPT while the queue
isn't empty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:44:36 +01:00
Henrik RydgårdandClaude Opus 5.5 7f094cbf45 sceNetAdhoc: P2P mode handles leaving the network like the relay mode
Out of the group, a PSP's sends reach nobody and nothing reaches it, and
a PTP connection to a peer that has left fails once its retransmits would
have run out. Only the relay transport did this; the P2P one kept sending
over the host's sockets, so neither side ever noticed the other was gone
(pspautotests net/adhoc/pair/vanish).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:44:36 +01:00
Henrik RydgårdandClaude Opus 5.5 52b13079d1 pspautotests: ptppoll opens its connection after the host's idle polls
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:44:36 +01:00
Henrik RydgårdandClaude Opus 5.5 d3a7e13541 test.py: Name the backend split --skip-cpu-independent, and add --only-cpu-independent
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:44:36 +01:00
Henrik RydgårdandClaude Opus 5.5 4a01b6644d test.py: Run the networking tests with one CPU backend in CI
--cpu-backend-only leaves out the tests that don't depend on the CPU
backend (net/ for now, the two-console ones taking about 40 s of a 60 s
run). The Linux CI jobs run everything with the JIT and pass it for
jit-ir, ir and the interpreter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:44:36 +01:00
Henrik RydgårdandClaude Opus 5.5 1f42161f0e adhoc_session.py: Wait in emulated time, and start instances at a speed
wait, press --every, stick, type and until count the instances' emulated
time (the slowest one's), so a script means the same at any speed, and
start --speed PERCENT runs the instances sped up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:44:36 +01:00
Henrik RydgårdandClaude Opus 5.5 acb2acf0b4 sceNetAdhocMatching: Run the input and event loops from CoreTiming instead of host threads
Each started context had two host threads, polling every 10 ms of wall
time: one sent queued packets, received, and ran hellos, keepalives and
timeouts, and the other handed events to the callbacks. A single
CoreTiming event now does both for every running context, every 1 ms of
emulated time, and Stop does what the threads did on their way out.

Matching no longer depends on host scheduling or wall-clock delays, so an
accept's ESTABLISHED comes 1-10 ms after SelectTarget at any emulation
speed, as on a PSP (pspautotests net/adhoc/pair/matchingaccept).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:44:36 +01:00
Henrik RydgårdandClaude Opus 5.5 074b6bf547 test.py: Run the two-console ad hoc tests in relay and P2P mode, and in CI
The pair tests that pass go in tests_good, and each runs twice: through
the built-in server's relay and P2P. pair_known_failures lists the ones
that fail in only one mode. A P2P test that needs a loopback address
the machine lacks (macOS has only 127.0.0.1) is skipped with a warning,
and the run fails at the end with the command that adds it. The macOS
CI runners add 127.0.0.2. Each run gets a random port offset.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:44:36 +01:00
Henrik RydgårdandClaude Opus 5.5 752ecccf43 sceNetAdhoc: Don't treat a relay PTP listener's handle as a PDP session when polling
Polling an unconnected or listening PTP socket for SEND took the PDP
path in postoffice_can_send. For an opened connection that created a
PDP session and stored it as the socket's handle, so its sends and
receives failed afterwards (pspautotests net/adhoc/pair/ptppoll). A PTP
socket that isn't established now just isn't writable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 00:44:36 +01:00
Henrik Rydgård c9e2afb65f Merge pull request #22858 from hrydgard/apctl-getstate-init
sceNetApctl: Fail GetState before Init, let GetLocalEtherAddr work in infrastructure mode
2026-10-31 00:42:51 +01:00
Henrik RydgårdandClaude Opus 5.5 1437c15f52 sceNetApctl: Fail GetState before Init, let GetLocalEtherAddr work in infrastructure mode
- Fixes #22857

PES 2009 calls sceNetApctlGetState first and only calls sceNetApctlInit
when it fails with 0x80410a0d. We returned success, so Init was never
called, apctl's state never advanced and the Netconf dialog waited on
"Connecting to the access point" forever. A PSP returns 0x80410a0d before
Init and after Term (pspautotests net/adhoc/apctlinit).

After that the game polls sceNetGetLocalEtherAddr until it succeeds, which
we only allowed in ad hoc mode. Also allow it once apctl has connected. It
still fails with apctl initialized but not connected, as the test shows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 23:50:28 +01:00
Henrik Rydgård 6b9830a030 Merge pull request #22855 from hrydgard/adhoc-transport
Adhoc: Put the relay and P2P transports behind an interface, in their own files
2026-10-30 21:19:14 +01:00
Henrik RydgårdandClaude Opus 5.5 969bc4a1be sceNetAdhoc: Drop PtpOpen's unused isClient
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 20:22:08 +01:00
Henrik RydgårdandClaude Opus 5.5 0e954b17cb adhoc_session.py: A reference image's alpha channel masks what until compares
For text over a moving background: only the opaque pixels count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 19:09:35 +01:00
Henrik RydgårdandClaude Opus 5.5 958d76ea77 sceNetAdhoc: Move the two transports into their own files
RelayTransport, with the aemu_postoffice helpers only it uses, goes to
AdhocTransportRelay.cpp, and P2PTransport to AdhocTransportP2P.cpp. The
helpers they share with sceNetAdhoc.cpp are declared in
AdhocTransport.h. Moved as they were.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 19:09:35 +01:00
Henrik RydgårdandClaude Opus 5.5 b5db43ca9d sceNetAdhoc: Put PTP, polling and socket cleanup behind AdhocTransport
The relay and P2P halves of PtpOpen, PtpListen, PtpClose, PtpSend,
PtpRecv, PtpAccept and their blocking retries, GetPtpStat, PtpFlush,
PollSocket and deleting all sockets move into RelayTransport and
P2PTransport. Connecting stays shared, with the transports answering
the steps that differ (start, check on, confirm, still pending).

No change in behaviour, except that a relay poll asks the postoffice
whether a socket is readable once instead of twice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 19:09:35 +01:00
Henrik RydgårdandClaude Opus 5.5 7202562695 sceNetAdhoc: Put PDP behind an AdhocTransport interface
The relay and P2P halves of PdpCreate, PdpDelete, PdpSend, PdpRecv, the
blocking PDP receive, GetPdpStat and game mode's readiness checks move into
RelayTransport and P2PTransport, which Transport() picks between by
serverHasRelay. No change in behaviour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 19:09:35 +01:00
Henrik Rydgård 36b6db5458 Merge pull request #22851 from hrydgard/adhoc-9-fixes
Ad hoc 9/9: Fixes from playing games, and 8x faster ad hoc tests
2026-10-30 13:09:06 +01:00
Henrik Rydgård e3a25dccdf Merge pull request #22854 from hrydgard/ui-io-off-thread
UI: Move file I/O off the render thread in a few screens
2026-10-30 13:08:45 +01:00
Henrik RydgårdandClaude Opus 5.5 181c90f758 pspautotests: matchingjoin no longer counts the host's hellos
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 12:26:52 +01:00
Henrik RydgårdandClaude Opus 5.5 c1058fd589 sceNetAdhoc: Disconnect is BUSY until a Create or Connect has connected
As on a PSP (pspautotests net/adhoc/abandon): the Disconnect fails and
the join goes on to CONNECT. Before, it was accepted, and the join's late
answer from the server could still connect us afterwards.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 12:04:33 +01:00
Henrik RydgårdandClaude Opus 5.5 f6f9a00eb7 UI: Move file I/O off the render thread in a few screens
On Android the render thread runs the UI, and surfaceDestroyed waits for
it, so slow storage (SAF especially) there stutters and can become an ANR.

- Store: only check whether the game is installed when an install or
  uninstall finishes, not every frame.
- Savedata: read the modification time with SIZE on the GameInfo worker.
  The popup asked for it every frame, and each button on first draw.
- FirmwareScreen: scan the NAND, and erase it, on a worker thread. It
  rescanned on every RecreateViews, which is after every popup.
- GameScreen: look up the installed update, plugins and what the firmware
  can play on a worker thread. They ran on every RecreateViews, which
  happens as each piece of game info arrives.
- LaunchFile: wait only for the file type, and for PARAM.SFO just in the
  cases that use it.

Also add --start-screen=firmware.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-30 12:01:36 +01:00
Henrik Rydgård 61865a5c89 Merge pull request #22853 from hrydgard/windows-misc-fixes
Windows: Fix D3D11 init error handling, delete old build scripts
2026-10-30 11:56:29 +01:00
Henrik RydgårdandClaude Opus 5.5 d12e19ed35 test.py: Keep the ad hoc tests' ports below Linux's ephemeral ports
With offsets of up to 30000, a port net/adhoc/limits listened on could
be one an outgoing connection was using, and the listen failed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 11:53:44 +01:00
Henrik RydgårdandClaude Opus 5.5 a0669ffbe4 sceNetAdhoc: Don't let an abandoned group join put us in the group
When the game gives up on a join (game mode timed out, or it
disconnected), a join still queued isn't sent anymore, and the rest of
the server's answer to one already sent is dropped: its players, and the
BSSID that came last and connected us. Players joining a group we've
just left (before the server knew) are dropped too, instead of staying
in our peer list.

Replaces the previous fix, which only dropped a late BSSID: on Windows
the join itself was still queued when game mode timed out in
net/adhoc/gamemode, and went out after it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 11:53:44 +01:00
Henrik Rydgård 56c84bb5c0 Merge pull request #22852 from hrydgard/ci-armhf-qemu
CI: Test ARM32 under qemu, and fix the MD5/SHA-1 bus error it found
2026-10-30 11:25:15 +01:00
Henrik RydgårdandClaude Opus 5.5 9d8ef5e8f5 sceNetAdhoc: Ignore the server's answer to a timed-out game mode join
When entering game mode timed out before the server's group BSSID came
back, the late BSSID was taken for a normal group's, and the state went
to CONNECTED: every later CreateEnterGameMode then got ALREADY_CONNECTED.
At the ad hoc tests' 8x speed the 1 s timeouts in net/adhoc/gamemode are
125 ms of wall time, short enough for that on Windows; at 50x it happens
on macOS too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 11:21:57 +01:00
Henrik RydgårdandClaude Opus 5.5 1310070e5a Windows: Fix D3D11 init error handling, delete old build scripts
- Fixes #22842

D3D11 init only took the failure path on E_FAIL, so any other failed
HRESULT from D3D11CreateDevice reported success without a device. Also
stop the generic message overwriting the more specific ones.

The build-x86/x64.cmd scripts targeted VS2015, checked misspelled
variables so never caught a failed build, and nothing uses them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 11:17:06 +01:00
Henrik Rydgård 7705639152 Merge pull request #22849 from hrydgard/adhoc-8-tools
Ad hoc 8/9: Tools for testing multiplayer with several instances
2026-10-30 10:43:49 +01:00