Alt+W had been a no-op since the 2007 DPL->Direct3D port, which stubbed DPLToggleWireframe along with every other dpl_ call. D3D9 has no global wireframe property, so the toggle now records the intent in gWireframe and ExecuteImplementation applies D3DRS_FILLMODE once per frame - which also means it re-asserts itself after a device Reset. The sky dome and the 2D pass are held solid: a wireframed dome buries the geometry you turned the key on to look at, and the gunsight would otherwise come out as bare diagonals. Proving it needed a working copy, and that turned up a separate problem. steam_api.dll was a hard import, so a machine without it died at load time with 0xC0000135 - before a window, before a log line. It is now delay-loaded, and because delay loading only moves that failure to the first call, every Steam path is gated on SteamNetTransport_ClientLibraryPresent(): Install and the two lobby entries, with everything else downstream of one of them. Absent DLL boots and races; absent DLL with RP412STEAM=1 logs the reason and stays on TCP; DLL present brings the transport up exactly as before. The documentation now says which debug keys are real. Five of the seven are still 2007 stubs and always have been, so they are named as inert in environ.ini's template and at the dispatch site - that beats letting the next person debug a dead key, which is how this started. BUILD.md gains a debug-key table, the delay-load contract for anyone adding a Steam call site, and the environ.ini BOM trap that silently reverts L4CONTROLS to KEYBOARD and then fail-fasts for want of a pod mapper. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
118 lines
5.6 KiB
C
118 lines
5.6 KiB
C
//===========================================================================//
|
|
// File: l4steamtransport.h //
|
|
// Project: MUNGA Brick: Steam Network Transport //
|
|
// Contents: NetTransport over ISteamNetworkingSockets (FakeIP) //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1994-1995, Virtual World Entertainment, Inc. //
|
|
// PROPRIETARY AND CONFIDENTIAL //
|
|
//===========================================================================//
|
|
|
|
#pragma once
|
|
|
|
#include "..\munga\style.h"
|
|
|
|
//########################################################################
|
|
// SteamNetTransport - the retail wire (l4steamtransport.cpp). Built
|
|
// only under RP412_STEAM (Steamworks SDK vendored at
|
|
// extern\steamworks_sdk_164; steam_api.dll ships beside the exe, but is
|
|
// delay-loaded and optional - see the note further down).
|
|
//
|
|
// Method mapping onto ISteamNetworkingSockets:
|
|
//
|
|
// Install SteamAPI_Init + InitRelayNetworkAccess, then
|
|
// BeginAsyncRequestFakeIP(2): fake port 0 is the
|
|
// console channel, fake port 1 the game mesh.
|
|
// On success installs itself via NetTransport_Set;
|
|
// on any failure the process stays on Winsock TCP.
|
|
// GetLocalAddresses our FakeIP (the mesh identifies "which [pilots]
|
|
// entry is me" against it).
|
|
// Resolve SteamNetworkingIPAddr::ParseString - FakeIPs ARE
|
|
// IPv4 strings, so egg text stays unchanged.
|
|
// Connect ConnectByIPAddress to the peer's FakeIP + fake
|
|
// game port (SDR routes it; NAT traversal and IP
|
|
// privacy come free); blocks pumping callbacks
|
|
// until Connected, retrying like the TCP
|
|
// connect-while-refused loop.
|
|
// Listen CreateListenSocketP2PFakeIP - first engine port
|
|
// seen maps to fake port 0, second to fake port 1.
|
|
// Accept connection-request callback AcceptConnections
|
|
// queue up; Accept() pops fully-connected ones.
|
|
// Send SendMessageToConnection, reliable lane (the
|
|
// engine's stream framing assumes ordered
|
|
// reliable delivery).
|
|
// Receive ReceiveMessagesOnConnection into the caller's
|
|
// buffer; normalized to ReceiveNoData /
|
|
// ReceiveDisconnected like the Winsock transport.
|
|
// GetRemoteAddress GetRemoteFakeIPForConnection, with the fake
|
|
// port translated back to the ENGINE port so the
|
|
// mesh's SOCKADDR_IN identity checks keep working.
|
|
//
|
|
// Addressing convention under Steam: every pod launches with the same
|
|
// -net port (the lobby fixes it), so the egg's [pilots] entries are
|
|
// "<fakeip>:<engine game port>" - the engine's self-match and peer
|
|
// checks all work on engine ports, and only this transport knows the
|
|
// Steam-assigned fake port values. The lobby layer exchanges each
|
|
// member's FakeIP + fake game port and feeds RegisterPeer before the
|
|
// egg is distributed.
|
|
//########################################################################
|
|
|
|
//########################################################################
|
|
// steam_api.dll is DELAY-LOADED (see the DelayLoadDLLs setting in
|
|
// RP_L4.vcxproj), so the game runs on a machine that has never seen
|
|
// Steam - a plain import of a missing DLL kills the process at load time
|
|
// with 0xC0000135, before a window or a single log line.
|
|
//
|
|
// The catch is that delay loading only MOVES the failure: the first call
|
|
// to a delay-loaded function whose DLL cannot be found raises a fatal
|
|
// exception instead. So every path that would reach a Steam symbol has
|
|
// to ask this first. It is declared outside the RP412_STEAM guard, and
|
|
// answers False in a build without the SDK, so callers need no #ifdef.
|
|
//
|
|
// Cheap and idempotent: one LoadLibrary on first call, cached after.
|
|
// Deliberately the same plain-name load the delay-load helper itself
|
|
// does, so a yes here means the helper will succeed too.
|
|
//########################################################################
|
|
Logical
|
|
SteamNetTransport_ClientLibraryPresent();
|
|
|
|
#ifdef RP412_STEAM
|
|
|
|
// Bring Steam up and make this the process transport. False (with the
|
|
// reason logged) leaves the Winsock transport in place - callers just
|
|
// carry on over TCP.
|
|
Logical
|
|
SteamNetTransport_Install();
|
|
|
|
// Our FakeIP as a dotted string ("169.254.x.y"), for lobby member data
|
|
// and the [pilots] list. Empty until Install succeeds.
|
|
const char *
|
|
SteamNetTransport_GetFakeAddressString();
|
|
|
|
// Our Steam-assigned fake ports (lobby member data): the console
|
|
// channel and the game mesh.
|
|
int
|
|
SteamNetTransport_GetFakeConsolePort();
|
|
int
|
|
SteamNetTransport_GetFakeGamePort();
|
|
|
|
// The engine-side port convention for this session (default 1501;
|
|
// game port is +1). Connect() maps an engine port in a SOCKADDR_IN to
|
|
// the peer's matching Steam fake port.
|
|
void
|
|
SteamNetTransport_SetEnginePorts(int console_port);
|
|
|
|
// The lobby feeds every member's FakeIP + fake ports + SteamID here
|
|
// before anything dials out. The SteamID matters on accept: Steam
|
|
// reports incoming callers under locally-allocated alias addresses,
|
|
// so the transport maps the caller's identity back to the global
|
|
// FakeIP the egg promised. Registering is idempotent per IP.
|
|
void
|
|
SteamNetTransport_RegisterPeer(
|
|
const char *fake_ip,
|
|
int fake_console_port,
|
|
int fake_game_port,
|
|
unsigned __int64 steam_id
|
|
);
|
|
|
|
#endif // RP412_STEAM
|