fix: push presence when a player comes back online

OnDisconnectedAsync told friends a player went offline, but nothing ever
pushed the opposite transition — PlayerCameOnline existed in
NotificationService with zero callers. The pair was asymmetric, so a SignalR
reconnect (network blip, replica restart) greyed the player out on every
friend's list for the rest of the session even though they were still
playing. Only re-entering a room, which pushes presence via /goto, brought
them back.

AddConnectionAsync already computed the first-connection transition to
maintain the online set but returned void; it now reports it, mirroring
RemoveConnectionAsync.

The push is deliberately conditional on a room already being known. The
presence payload derives isOnline from roomInstance being non-null, so
pushing with no room reads as OFFLINE — worse than staying quiet. On a fresh
boot there is no room yet and the /goto that follows sends the real presence
anyway, so this only fires on reconnects, where the cached room is exactly
what friends need to see again.
This commit is contained in:
Alexa
2026-07-27 23:40:11 +03:00
parent 327dcb789c
commit 49df7393dc
3 changed files with 41 additions and 7 deletions
+24 -3
View File
@@ -40,6 +40,7 @@ namespace DorkNet.Server.Hubs;
[Authorize]
public class NotifyHub(
OnlinePresenceService presence,
PlayerPresenceService playerRooms,
NotificationService notifications,
DorkNetDbContext db,
ServerSettingsService serverSettings,
@@ -95,10 +96,30 @@ public class NotifyHub(
}
await Groups.AddToGroupAsync(Context.ConnectionId, GroupForPlayer(id));
await presence.AddConnectionAsync(id, Context.ConnectionId);
var cameOnline = await presence.AddConnectionAsync(id, Context.ConnectionId);
logger.LogInformation(
"[hub] connected player={PlayerId} conn={ConnectionId} group={Group}",
id, Context.ConnectionId, GroupForPlayer(id));
"[hub] connected player={PlayerId} conn={ConnectionId} group={Group} cameOnline={CameOnline}",
id, Context.ConnectionId, GroupForPlayer(id), cameOnline);
// Tell friends they're back. OnDisconnectedAsync pushes
// PlayerWentOffline, but nothing used to push the opposite
// transition, so the pair was asymmetric: a SignalR reconnect
// (network blip, replica restart) greyed the player out on every
// friend's list for the rest of the session even though they were
// still playing.
//
// Only push when a room is already known. The presence payload
// derives isOnline from roomInstance being non-null, so a push with
// no room reads as OFFLINE — worse than staying quiet. On a fresh
// boot there is no room yet and the /goto that follows sends the
// real presence anyway; this branch is for reconnects, where the
// cached room is exactly what friends need to see again.
if (cameOnline && playerRooms.GetRoom(id) is { } room)
{
var friendIds = await RelationshipQueries.EffectiveFriendIdsAsync(db, serverSettings, id);
if (friendIds.Count > 0)
await notifications.PlayerCameOnline(friendIds, id, room);
}
}
else
{