Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/SwarmObserver/scripts/5_Mission/MissionServer.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ modded class MissionServer
else
Print("[SwarmObserver] No logout data found for uid: " + uid);

if (!shouldClientBeObserved(player))

Copilot AI Feb 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldClientBeObserved returns false when player is null, but this file’s existing disconnect flow explicitly accounts for PlayerDisconnected often being invoked without a valid player/identity (hence storing logout data in OnClientDisconnectedEvent). With the new check, a null player will cause SwarmObserver processing to be skipped even for normal voluntary disconnects, preventing restricted-area grace periods/combat notifications from ever running. To keep the intended behavior, base the decision on stored logout data (e.g., store the kickoff reason/flag in SwarmObserverLogoutData during OnClientDisconnectedEvent) or treat player == null as observable when data exists.

Suggested change
if (!shouldClientBeObserved(player))
// Determine whether this client should be observed.
// If the player entity is missing but we have stored logout data, we still want to process it.
bool observeClient;
if (!player && data)
observeClient = true;
else
observeClient = shouldClientBeObserved(player);
if (!observeClient)

Copilot uses AI. Check for mistakes.
{
Print("[SwarmObserver] Player " + (data ? data.PlayerName : "unknown") + " is not subject to observation, skipping");

Copilot AI Feb 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the early-return path, the method calls super.PlayerDisconnected(...) and returns without cleaning up SwarmObserverLogoutManager data (and without the combat state cleanup below). This leaves per-uid logout entries around after a restart/kick-all event and can cause memory growth / stale data on later disconnects. Consider removing stored logout data (and any combat state) before returning, or moving cleanup into a finally-style block that runs for both observed and skipped disconnects.

Suggested change
Print("[SwarmObserver] Player " + (data ? data.PlayerName : "unknown") + " is not subject to observation, skipping");
Print("[SwarmObserver] Player " + (data ? data.PlayerName : "unknown") + " is not subject to observation, skipping");
// Even if the player is not observed, ensure we clean up any stored logout data and combat state
if (data)
SwarmObserverLogoutManager.RemoveLogoutData(uid);
if (player)
GetCombatStateManager().RemoveCombatState(player);

Copilot uses AI. Check for mistakes.
super.PlayerDisconnected(player, identity, uid);
return;
}

if (data)
{
// Handle restricted area violation
Expand Down Expand Up @@ -128,4 +135,25 @@ modded class MissionServer
}
}
}

// Determine if a player should be observed by SwarmObserver
private bool ShouldClientBeObserved(PlayerBase player)
{
if (!player || !player.IsAlive())
return false;

switch (player.GetKickOffReason())
{
case EClientKicked.SERVER_EXIT:
return false;
case EClientKicked.KICK_ALL_ADMIN:
return false;
case EClientKicked.KICK_ALL_SERVER:
return false;
case EClientKicked.SERVER_SHUTDOWN:
return false;
default:
return true;
}
}
}