Marathon Input Issues Fix: PC-Games gegen Overlay-Konflikte absichern
Jeder Multiplayer-Entwickler kennt das Gefühl, wenn ein perfekt geplanter Netcode wegen eines Discord-Overlays zusammenbricht. Man verbringt Monate damit, die Server-Infrastruktur auf Latenzen unter 30ms zu optimieren, nur um festzustellen, dass Spieler ihre Schüsse verfehlen, weil eine Streaming-App im Hintergrund den Input-Thread blockiert.
Genau dieses Szenario spielt sich derzeit beim Server Slam von Bungies kommendem Extraction-Shooter Marathon ab. PC-Spieler berichten von massivem Mouse Lag, dropped Inputs und trägen Kamerabewegungen. Bungie hat das Problem offiziell bestätigt und verweist auf Third-Party-Utilities, Streamer-Overlays und spezifische Window-Capture-Methoden als Hauptursache.
In den Community-Foren suchen derzeit tausende Spieler verzweifelt nach einem marathon input issues fix. Die temporäre Lösung auf Spielerseite ist simpel: Den gesamten Monitor streamen statt nur das Game-Window und Overlays deaktivieren.
Für Game-Entwickler stellt sich jedoch eine kritische Architektur-Frage: Warum kapern Streaming-Apps und Overlays überhaupt den Input und wie können wir unsere PC-Clients so programmieren, dass dies verhindert wird?
In diesem Deep Dive analysieren wir das Windows Input Handling, untersuchen, warum OBS Game Capture Frame Pacing Probleme verursacht, und zeigen, wie man Input-Threads entkoppelt, um in feindseligen PC-Umgebungen zu bestehen.
Die Ursache: Wie Overlays die Render Pipeline kapern
Um zu verstehen, warum eine Streaming-App den Mouse Input ruiniert, müssen wir uns ansehen, wie moderne PC-Games auf den Bildschirm gelangen.
Wenn ein Spieler OBS oder ein Discord-Overlay nutzt, machen diese Apps nicht einfach einen Screenshot. Für maximale Performance injizieren sie eine DLL direkt in den Game-Prozess. Diese DLL fängt Graphics API Calls ab – meist über Hooks in der Present-Funktion von DirectX oder vkQueuePresentKHR in Vulkan.
Der Swap Chain Flaschenhals
Durch das Hooking der Swap Chain zwingt das Overlay die Engine zu warten, während der Framebuffer in den eigenen Speicherbereich kopiert wird, bevor der Frame auf dem Monitor erscheint.
Ist die CPU oder GPU durch den Encoder stark ausgelastet, stockt dieser Kopiervorgang. Ein Frame, der 16.6ms (bei 60 FPS) dauern sollte, benötigt plötzlich 24ms. Da die meisten Engines den Windows-Input (WM_MOUSEMOVE) im Main-Thread direkt vor dem Render-Tick abfragen, verzögert ein langsamer Render-Tick zwangsläufig das Input Polling.
Deine 1000Hz Gaming-Maus wird plötzlich in unregelmäßigen Intervallen abgefragt. Der Spieler nimmt dies als schwammiges oder verzögertes Aiming wahr.
Fullscreen vs. Windowed Capture
Bungie merkte an, dass Input-Probleme primär beim Window-Capture auftreten. Das liegt daran, wie der Windows Desktop Window Manager (DWM) die Composition handhabt.
Im Exclusive Fullscreen oder mit dem modernen DXGI Flip Model wird die DWM-Composition umgangen. Das Spiel kommuniziert direkt mit dem Display. Erzwingt eine App jedoch einen Window-Capture-Hook, fällt das Spiel oft in den Composited-Modus zurück, was 1 bis 3 Frames Latenz (16ms bis 48ms) hinzufügt.
Unblockable Input: Die Raw Input API
Wer sein Spiel gegen Overlay-Lag immunisieren will, muss sich von Standard-Windows-Message-Pumps für kritischen Input verabschieden. Sich auf WM_MOUSEMOVE zu verlassen, ist für kompetitive Shooter tödlich.
Stattdessen sollten Entwickler die Raw Input API (WM_INPUT) nutzen und das Input Polling in einen dedizierten High-Priority-Thread auslagern, der komplett vom Render-Loop entkoppelt ist.
Raw Input in C++ (Win32) implementieren
So umgeht man Standard-Queues und registriert Raw Mouse Data direkt von der Hardware. Selbst wenn der Render-Thread durch einen OBS-Hook hängt, empfängt der Input-Accumulator weiterhin die exakten Delta-Bewegungen.
// C++ Win32 Raw Input Initialisierung
void InitializeRawInput(HWND hwnd) {
RAWINPUTDEVICE Rid[1];
Rid[0].usUsagePage = 0x01;
Rid[0].usUsage = 0x02;
Rid[0].dwFlags = 0;
Rid[0].hwndTarget = hwnd;
if (RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])) == FALSE) {
DWORD error = GetLastError();
LogWarning("Failed to register raw input device. Error: %d", error);
}
}
// In der Window Procedure (WndProc)
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_INPUT: {
UINT dwSize = 0;
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
if (dwSize == 0) break;
LPBYTE lpb = new BYTE[dwSize];
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER));
RAWINPUT* raw = (RAWINPUT*)lpb;
if (raw->header.dwType == RIM_TYPEMOUSE) {
int deltaX = raw->data.mouse.lLastX;
int deltaY = raw->data.mouse.lLastY;
InputManager::GetInstance().AccumulateMouseDelta(deltaX, deltaY);
}
delete[] lpb;
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
Unreal Engine: Smoothing deaktivieren
Unreal Engine nutzt Raw Input zwar intern, wendet aber oft Smoothing-Kurven an, die Input Lag bei Framerate-Schwankungen verschlimmern. Erzwingen Sie unsmoothed Input im PlayerController:
void ACompetitivePlayerController::SetupInputComponent() {
Super::SetupInputComponent();
bEnableMouseSmoothing = false;
LocalPlayer->AspectRatioAxisConstraint = AspectRatio_MaintainYFOV;
}
Kaskadeneffekt: Client Lag vs. Server Rollback
Input Lag ist kein rein lokales Problem. In einer Authoritative Server Architektur hat Client-Lag massive Auswirkungen auf den Multiplayer.
Wenn ein Overlay den Client-Loop verzögert, werden Input-Pakete zu spät gesendet. Der Server muss die Simulation dann per Fast-Forward nachholen. Bei starken Verzögerungen greift die Reconciliation: Der Server stellt fest, dass der Predicted State des Clients falsch ist und erzwingt eine Korrektur (Rubberbanding).
Dies sieht oft aus wie Network Latency oder How To Fix Player Location Desync In Uefn And Unreal Engine Multiplayer, ist aber ein lokaler Render-Stall.
Server-seitiges Handling
Um das Erlebnis zu retten, sollte der Server einen Input Buffer nutzen, um Jitter abzufangen.
void ServerProcessClientInputs(ClientConnection* client) {
const int TARGET_BUFFER_SIZE = 2;
int currentBufferSize = client->InputQueue.Size();
if (currentBufferSize > TARGET_BUFFER_SIZE + 3) {
client->InputQueue.DropOldest(currentBufferSize - TARGET_BUFFER_SIZE);
}
if (!client->InputQueue.IsEmpty()) {
InputCommand cmd = client->InputQueue.Pop();
SimulatePlayerMovement(client->PlayerEntity, cmd);
}
}
Mit horizOn können Sie optimierte Game Server mit integriertem Schutz gegen Desync deployen, sodass sich Ihr Team auf den Client-Loop konzentrieren kann.
5 Best Practices für PC Input
- Input vom Rendering entkoppeln: Nutze einen High-Priority-Thread für Raw Input bei 1000Hz.
- DXGI Flip Model erzwingen: Nutze
DXGI_SWAP_EFFECT_FLIP_DISCARD, um den DWM zu umgehen. - Hardware Cursor nutzen: Verwende
SetCursorstatt UI-Texturen für den Mauszeiger. - Warnung bei Hook Injections: Informiere Spieler, wenn Overlay-DLLs wie von OBS aktiv sind.
- Fixed Timestep Simulation: Nutze feste Intervalle für Physik und Input-Verarbeitung.
Fazit
Der Marathon Server Slam zeigt, wie feindselig das PC-Ökosystem sein kann. Während Spieler nach einem Marathon Input Issues Fix suchen, müssen Entwickler Raw Input implementieren und Threads entkoppeln. Für das Backend nutzen Sie am besten horizOn, um Server-Orchestrierung und Desync-Probleme professionell zu lösen.