Phase 0: donor-launch spike foundation

Scaffold CoopAllTheThings: Remote Play Together for any XInput game via a
mirror app under a donor appid (real game keeps its own appid, so DRM,
achievements, and playtime stay intact).

- Build: CMake skeleton, ImGui + SafetyHook submodules (no vcpkg)
- common/: host<->hook IPC contract (seqlock pad state, shared-memory RAII)
- host/: borderless D3D11 window + ImGui overlay listing visible XInput pads,
  behind an InputSource interface (Steam Input slots in later)
- README documents the Phase 0 donor-launch validation procedure, anti-cheat
  limitation, and XInput/bitness constraints

Phase 0 validates the riskiest assumption (Steam RPT streams an arbitrary
window under a donor appid and routes guest input to it) before capture and
injection are built.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-18 22:48:31 +02:00
commit cf058aecfa
23 changed files with 1129 additions and 0 deletions

58
host/src/main.cpp Normal file
View File

@@ -0,0 +1,58 @@
// CoopAllTheThings host -- Phase 0 spike.
//
// Brings up the borderless window Steam Remote Play Together will capture and an
// ImGui overlay that lists every controller it can see. The goal of this build
// is to validate the riskiest assumption end-to-end: launch this exe under a
// donor appid (steam -applaunch <donorAppId> <path-to-host.exe>), invite a
// friend, and confirm (a) the window streams and (b) the guest's gamepad shows
// up in the overlay. Capture/injection are built on top of this once it holds.
#include <memory>
#include <windows.h>
#include "d3d11_window.hpp"
#include "debug_overlay.hpp"
#include "imgui_layer.hpp"
#include "input/xinput_source.hpp"
namespace
{
int run()
{
coop::D3D11Window window;
if (!window.create(L"CoopAllTheThings"))
{
MessageBoxW(nullptr, L"Failed to create the D3D11 window.", L"CoopAllTheThings", MB_ICONERROR);
return 1;
}
coop::ImGuiLayer imgui;
if (!imgui.init(window.hwnd(), window.device(), window.context()))
{
MessageBoxW(nullptr, L"Failed to initialize ImGui.", L"CoopAllTheThings", MB_ICONERROR);
return 1;
}
auto input = std::make_unique<coop::XInputSource>();
while (window.pump_messages())
{
input->poll();
imgui.begin_frame();
coop::draw_debug_overlay(*input);
window.render_frame([&imgui]() { imgui.end_frame(); });
}
return 0;
}
} // namespace
int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
{
return run();
}