Skip to content

Fix multiplayer non host split screen#1031

Open
MrTheShy wants to merge 4 commits intosmartcmd:mainfrom
MrTheShy:fix-multiplayer-non-host-split-screen
Open

Fix multiplayer non host split screen#1031
MrTheShy wants to merge 4 commits intosmartcmd:mainfrom
MrTheShy:fix-multiplayer-non-host-split-screen

Conversation

@MrTheShy
Copy link
Contributor

@MrTheShy MrTheShy commented Mar 9, 2026

Description

Several split-screen bugs affecting the non-host player on Windows64: joining a session started via the UI, phantom joins from unfocused windows, tutorial popup misplacement, and the debug overlay being clipped to one viewport. This PR addresses all four.

Changes

Previous Behavior

  • Split-screen join via UI: When the host connected to a server through the in-game UI (rather than the command line), the g_Win64MultiplayerIP / g_Win64MultiplayerPort globals were never populated. A second local player attempting to join split-screen would therefore try to connect to an empty address, failing silently.
  • Phantom joins on unfocused window: Gamepad button state was polled every tick regardless of whether the game window had focus. Any gamepad input processed while the user was in a different application could inadvertently trigger a split-screen player join.
  • Tutorial popup positioning: The popup's render position was computed via a hard-coded switch over viewport types, manually offsetting by screenWidth/2 or screenHeight/2. This did not account for the actual 16:9 fit box used by every other scene, so the popup appeared at the wrong coordinates — especially visible in quadrant and non-square split layouts.
  • Debug overlay in split-screen: Opening the debug overlay (F3) during split-screen opened it in the active player's viewport group, clipping it to half the screen.

Root Cause

  • Join via UI: WinsockNetLayer::JoinGame (the path taken by a UI-initiated connection) did not write the resolved IP and port back into the globals that JoinSplitScreen reads. The globals remained zeroed-out from startup.
  • Phantom joins: The tryJoin condition in Minecraft::run_middle had no window-focus guard, so gamepad input was evaluated even when the application was not in the foreground.
  • Tutorial popup: The manual coordinate table was duplicating — incorrectly — the viewport-to-screen-space mapping that UISplitScreenHelpers already provides. It also passed the raw viewport dimensions to IggyPlayerSetDisplaySize, ignoring the fitted sub-rectangle.
  • Debug overlay: ui.NavigateToScene was called without an explicit UI group, defaulting to the current split-screen group instead of the fullscreen group.

New Behavior

  • A second local player can join split-screen successfully even when the host connected through the UI.
  • Gamepad input is ignored for the join trigger while the game window is not focused, preventing phantom joins.
  • The tutorial popup renders at the correct position and size inside each split-screen viewport, consistent with all other UI scenes.
  • The debug overlay spans the entire window when opened during split-screen, making all debug information readable regardless of the current layout.

Fix Implementation

WinsockNetLayer::JoinGame (WinsockNetLayer.cpp): After a successful connection and small-ID assignment, copy the resolved ip and port into g_Win64MultiplayerIP / g_Win64MultiplayerPort. Added a guard in PushFreeSmallId to never recycle small IDs in the range [0, XUSER_MAX_COUNT), which are permanently reserved for the host's local pads — this prevents a recycled ID collision when a remote client reconnects.

Minecraft::run_middle (Minecraft.cpp): Appended && g_KBMInput.IsWindowFocused() to the tryJoin boolean so the join path is only evaluated when the window has focus.

UIComponent_TutorialPopup::render (UIComponent_TutorialPopup.cpp): Replaced the manual per-viewport coordinate switch with GetViewportRect + Fit16x9 from UISplitScreenHelpers.h (the same helpers used by UIScene::render). The fitted width/height are now also passed to IggyPlayerSetDisplaySize instead of the raw viewport dimensions. Added default: break to both safezone switches to silence compiler warnings.

Minecraft::tick (Minecraft.cpp): Pass eUIGroup_Fullscreen as the fifth argument to ui.NavigateToScene when opening the debug overlay, so it is placed in the fullscreen group and covers the whole window.

AI Use Disclosure

Was used to write this pr description

Related Issues

MrTheShy added 4 commits March 9, 2026 11:20
When a non-host client connected to a remote server through the in-game
UI (as opposed to the -ip/-port command line flags), the global variables
g_Win64MultiplayerIP and g_Win64MultiplayerPort were never updated from
their defaults ("127.0.0.1" and the default port). JoinSplitScreen()
relies on these globals to open a second TCP connection for the local
split-screen pad, so it would always attempt to connect to localhost,
failing immediately on any remote session.

Fix: update g_Win64MultiplayerIP and g_Win64MultiplayerPort inside
JoinGame() once the primary connection is established. This ensures
subsequent JoinSplitScreen() calls always reach the correct host
regardless of how the session was joined.

Additionally, guard PushFreeSmallId() against recycling smallIds in the
range [0, XUSER_MAX_COUNT), which are permanently reserved for the
host's local controller slots. Previously, if a host-side local pad
disconnected its smallId could re-enter the free pool and be handed
to an incoming remote client, causing that client's IQNetPlayer slot
to collide with a local pad slot on the non-host machine.
Replace the manual switch-case that computed viewport origin with the shared GetViewportRect/Fit16x9 helpers (from UISplitScreenHelpers.h). This ensures the tutorial popup is positioned and scaled consistently with the rest of the split-screen UI, fitting a 16:9 box inside each viewport and applying safezone offsets correctly.

Also adds missing default:break to safezone switch statements to silence compiler warnings.

Made-with: Cursor
Add g_KBMInput.IsWindowFocused() guard to the tryJoin condition so that gamepad input from background windows does not accidentally trigger a split-screen player join. This avoids phantom joins when the user is interacting with another application.
Pass eUIGroup_Fullscreen to NavigateToScene when opening the debug overlay, so it spans the entire window instead of being confined to a single split-screen viewport. This makes the debug info readable regardless of the current split-screen layout.
@MrTheShy
Copy link
Contributor Author

MrTheShy commented Mar 9, 2026

@codeHusky ready to be merged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant