mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-25 23:18:44 -07:00
Enhance room bulk lookup: add support for ID-based queries and improve result handling; refactor GoToController for presence management and logging; update join timeout service to handle presence deferral; add Crescendo image asset.
This commit is contained in:
@@ -909,22 +909,30 @@ public class RoomsController(
|
|||||||
return Ok(BuildRoomServerDetails(room, scenes, roles: roomRoles));
|
return Ok(BuildRoomServerDetails(room, scenes, roles: roomRoles));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>GET <c>/roomserver/rooms/bulk?name=X&name=Y</c> — bulk
|
/// <summary>GET <c>/roomserver/rooms/bulk?name=X&name=Y</c> or
|
||||||
/// lookup by room name. Used by EJDCNGBEICB's room cache to resolve
|
/// <c>?id=1&id=2</c> — bulk room cache lookup. Decomp-verified
|
||||||
/// well-known names (RecCenter, etc.) to their RoomServerDetails
|
/// in EJDCNGBEICB: the Int64 overload writes query key <c>id</c>
|
||||||
/// shape in one round-trip. Returns the same per-room object that
|
/// and the string overload writes <c>name</c>. Returns the same
|
||||||
/// <c>/roomserver/rooms/{id}</c> emits, one per requested name; names
|
/// per-room object that <c>/roomserver/rooms/{id}</c> emits;
|
||||||
/// we can't resolve are silently skipped (watch handles a shorter
|
/// unresolved entries are silently skipped (watch handles a shorter
|
||||||
/// list fine, but a 404 wedges the room browser).</summary>
|
/// list fine, but a 404 wedges the room browser).</summary>
|
||||||
[HttpGet("roomserver/rooms/bulk")]
|
[HttpGet("roomserver/rooms/bulk")]
|
||||||
[HttpGet("rooms/bulk")]
|
[HttpGet("rooms/bulk")]
|
||||||
public async Task<IActionResult> RoomServerBulkByName()
|
public async Task<IActionResult> RoomServerBulkByName()
|
||||||
{
|
{
|
||||||
var names = Request.Query["name"].Where(n => !string.IsNullOrWhiteSpace(n)).ToArray();
|
var names = Request.Query["name"].Where(n => !string.IsNullOrWhiteSpace(n)).ToArray();
|
||||||
if (names.Length == 0) return Ok(Array.Empty<object>());
|
var ids = Request.Query["id"]
|
||||||
|
.Where(v => !string.IsNullOrWhiteSpace(v))
|
||||||
|
.SelectMany(v => v!.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
|
||||||
|
.Select(v => long.TryParse(v, out var id) ? id : 0)
|
||||||
|
.Where(id => id > 0)
|
||||||
|
.Distinct()
|
||||||
|
.ToArray();
|
||||||
|
if (names.Length == 0 && ids.Length == 0) return Ok(Array.Empty<object>());
|
||||||
|
|
||||||
var pid = CurrentPlayerId ?? 0;
|
var pid = CurrentPlayerId ?? 0;
|
||||||
var results = new List<object>(names.Length);
|
var results = new List<object>(names.Length + ids.Length);
|
||||||
|
var emitted = new HashSet<long>();
|
||||||
foreach (var raw in names)
|
foreach (var raw in names)
|
||||||
{
|
{
|
||||||
var name = raw!.Trim();
|
var name = raw!.Trim();
|
||||||
@@ -948,6 +956,34 @@ public class RoomsController(
|
|||||||
overrideName: DormNameOverride(name));
|
overrideName: DormNameOverride(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var scenes = await db.RoomScenes
|
||||||
|
.Where(s => s.RoomId == room.Id)
|
||||||
|
.OrderBy(s => s.OrderIndex)
|
||||||
|
.ToListAsync();
|
||||||
|
var roomRoles = await db.RoomRoles
|
||||||
|
.Where(r => r.RoomId == room.Id)
|
||||||
|
.ToListAsync();
|
||||||
|
results.Add(BuildRoomServerDetails(room, scenes, roles: roomRoles));
|
||||||
|
emitted.Add(room.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var id in ids)
|
||||||
|
{
|
||||||
|
if (!emitted.Add(id)) continue;
|
||||||
|
|
||||||
|
var room = await rooms.GetByIdAsync(id);
|
||||||
|
if (room is null) continue;
|
||||||
|
|
||||||
|
if (room.IsDormRoom)
|
||||||
|
{
|
||||||
|
var dormBlobName = await db.DormStates
|
||||||
|
.Where(d => d.PlayerId == room.CreatorPlayerId)
|
||||||
|
.Select(d => d.CurrentDataBlobName)
|
||||||
|
.FirstOrDefaultAsync()
|
||||||
|
?? string.Empty;
|
||||||
|
room = CloneWithCreator(room, room.CreatorPlayerId, dormBlobName);
|
||||||
|
}
|
||||||
|
|
||||||
var scenes = await db.RoomScenes
|
var scenes = await db.RoomScenes
|
||||||
.Where(s => s.RoomId == room.Id)
|
.Where(s => s.RoomId == room.Id)
|
||||||
.OrderBy(s => s.OrderIndex)
|
.OrderBy(s => s.OrderIndex)
|
||||||
|
|||||||
@@ -703,29 +703,41 @@ public class GoToController(
|
|||||||
private async Task RecordResponseAsync(MatchmakingResponseDto response)
|
private async Task RecordResponseAsync(MatchmakingResponseDto response)
|
||||||
{
|
{
|
||||||
if (this.CurrentPlayerId() is not long playerId) return;
|
if (this.CurrentPlayerId() is not long playerId) return;
|
||||||
var room = response.RoomInstance;
|
if (response.RoomInstance is null) return;
|
||||||
if (room is null) return;
|
|
||||||
|
|
||||||
var previousRoom = presence.GetRoom(playerId);
|
var targetRoom = response.RoomInstance;
|
||||||
var additionalPlayerIds = await GetEligibleAdditionalPlayerIdsAsync(playerId, previousRoom);
|
var currentRoom = presence.GetRoom(playerId);
|
||||||
await RecordPlayerMoveAsync(playerId, room);
|
var deferPresenceCommit = ShouldDeferPresenceCommit(currentRoom, targetRoom);
|
||||||
|
joinTimeouts.MarkPending(playerId, targetRoom, deferPresenceCommit);
|
||||||
if (additionalPlayerIds.Count == 0)
|
if (deferPresenceCommit)
|
||||||
return;
|
|
||||||
|
|
||||||
logger.LogInformation(
|
|
||||||
"[goto-party] player={PlayerId} moving additional players [{AdditionalPlayerIds}] to instance={InstanceId}",
|
|
||||||
playerId, string.Join(",", additionalPlayerIds), room.RoomInstanceId);
|
|
||||||
|
|
||||||
foreach (var additionalPlayerId in additionalPlayerIds)
|
|
||||||
{
|
{
|
||||||
var roomForPartyMember = CloneRoomInstance(room);
|
logger.LogInformation(
|
||||||
if (roomForPartyMember.IsPrivate)
|
"[goto] deferred presence commit player={PlayerId} room={RoomId} subRoom={SubRoomId} fromInstance={FromInstance} toInstance={ToInstance} fromPhoton={FromPhoton} toPhoton={ToPhoton}",
|
||||||
await privateInstances.InviteAsync(roomForPartyMember.RoomInstanceId, additionalPlayerId);
|
playerId,
|
||||||
|
targetRoom.RoomId,
|
||||||
await RecordPlayerMoveAsync(additionalPlayerId, roomForPartyMember);
|
targetRoom.SubRoomId,
|
||||||
|
currentRoom?.RoomInstanceId,
|
||||||
|
targetRoom.RoomInstanceId,
|
||||||
|
currentRoom?.PhotonRoomId,
|
||||||
|
targetRoom.PhotonRoomId);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
presence.SetRoom(playerId, targetRoom);
|
||||||
|
|
||||||
|
// Real visit tracking: upsert the per-(room, player) row so
|
||||||
|
// we get distinct VisitorCount (unique players ever) AND the
|
||||||
|
// gross VisitCount (every join, including rejoins). Skip the
|
||||||
|
// canonical dorm (RoomId=1) so per-day boots don't skew it.
|
||||||
|
if (targetRoom.RoomId != 1)
|
||||||
|
await RecordVisitAsync(playerId, targetRoom.RoomId);
|
||||||
|
|
||||||
|
// Push a presence-update notification to every accepted-friend
|
||||||
|
// so their watch's "friends" list shows the new room. Cheap
|
||||||
|
// query — Relationships is small, and we only fan out to the
|
||||||
|
// actually-connected friends.
|
||||||
|
await NotifyFriendsOfMoveAsync(playerId, targetRoom);
|
||||||
|
|
||||||
// NOTE: we INTENTIONALLY do NOT self-push SubscriptionUpdateRoom
|
// NOTE: we INTENTIONALLY do NOT self-push SubscriptionUpdateRoom
|
||||||
// from /goto. The watch's Rooms.OnSubscriptionUpdateRoom
|
// from /goto. The watch's Rooms.OnSubscriptionUpdateRoom
|
||||||
// (Cpp2IL_ISIL/.../RecNet/Rooms.txt:2401-2496) is gated on
|
// (Cpp2IL_ISIL/.../RecNet/Rooms.txt:2401-2496) is gated on
|
||||||
@@ -744,76 +756,13 @@ public class GoToController(
|
|||||||
// first one for any (room, subRoom).
|
// first one for any (room, subRoom).
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RecordPlayerMoveAsync(long playerId, RoomInstanceDto room)
|
private static bool ShouldDeferPresenceCommit(RoomInstanceDto? currentRoom, RoomInstanceDto targetRoom) =>
|
||||||
{
|
currentRoom is not null
|
||||||
presence.SetRoom(playerId, room);
|
&& targetRoom.IsPrivate
|
||||||
joinTimeouts.MarkPending(playerId, room);
|
&& currentRoom.RoomId == targetRoom.RoomId
|
||||||
|
&& currentRoom.SubRoomId == targetRoom.SubRoomId
|
||||||
// Real visit tracking: upsert the per-(room, player) row so
|
&& (currentRoom.RoomInstanceId != targetRoom.RoomInstanceId
|
||||||
// we get distinct VisitorCount (unique players ever) AND the
|
|| !string.Equals(currentRoom.PhotonRoomId, targetRoom.PhotonRoomId, StringComparison.OrdinalIgnoreCase));
|
||||||
// gross VisitCount (every join, including rejoins). Skip the
|
|
||||||
// canonical dorm (RoomId=1) so per-day boots don't skew it.
|
|
||||||
if (room.RoomId != 1)
|
|
||||||
await RecordVisitAsync(playerId, room.RoomId);
|
|
||||||
|
|
||||||
// Push a presence-update notification to every accepted-friend
|
|
||||||
// so their watch's "friends" list shows the new room. Cheap
|
|
||||||
// query — Relationships is small, and we only fan out to the
|
|
||||||
// actually-connected friends.
|
|
||||||
await NotifyFriendsOfMoveAsync(playerId, room);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<IReadOnlyList<long>> GetEligibleAdditionalPlayerIdsAsync(
|
|
||||||
long callerPlayerId,
|
|
||||||
RoomInstanceDto? callerPreviousRoom)
|
|
||||||
{
|
|
||||||
if (!Request.HasFormContentType || callerPreviousRoom is null)
|
|
||||||
return Array.Empty<long>();
|
|
||||||
|
|
||||||
var form = await Request.ReadFormAsync();
|
|
||||||
var rawValues = form["AdditionalPlayerIds"]
|
|
||||||
.Concat(form["additionalPlayerIds"])
|
|
||||||
.Concat(form["additionalPlayerIds[]"])
|
|
||||||
.ToArray();
|
|
||||||
if (rawValues.Length == 0)
|
|
||||||
return Array.Empty<long>();
|
|
||||||
|
|
||||||
var ids = rawValues
|
|
||||||
.SelectMany(v => (v ?? string.Empty).Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
|
|
||||||
.Select(v => long.TryParse(v, out var id) ? id : 0)
|
|
||||||
.Where(id => id > 0 && id != callerPlayerId)
|
|
||||||
.Distinct()
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
if (ids.Count == 0)
|
|
||||||
return Array.Empty<long>();
|
|
||||||
|
|
||||||
var eligible = new List<long>(ids.Count);
|
|
||||||
foreach (var id in ids)
|
|
||||||
{
|
|
||||||
var current = presence.GetRoom(id);
|
|
||||||
if (current is not null && IsSameLiveInstance(current, callerPreviousRoom))
|
|
||||||
{
|
|
||||||
eligible.Add(id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.LogWarning(
|
|
||||||
"[goto-party] ignoring AdditionalPlayerIds entry caller={CallerId} additional={AdditionalId} callerPrevious={CallerInstance} additionalCurrent={AdditionalInstance}",
|
|
||||||
callerPlayerId, id, callerPreviousRoom.RoomInstanceId, current?.RoomInstanceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return eligible;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsSameLiveInstance(RoomInstanceDto a, RoomInstanceDto b)
|
|
||||||
{
|
|
||||||
if (a.RoomInstanceId == b.RoomInstanceId)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return !string.IsNullOrWhiteSpace(a.PhotonRoomId)
|
|
||||||
&& string.Equals(a.PhotonRoomId, b.PhotonRoomId, StringComparison.OrdinalIgnoreCase);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Mutate the response so it represents a fresh invite-only
|
/// <summary>Mutate the response so it represents a fresh invite-only
|
||||||
/// match: forks the PhotonRoomId with a per-(player, nonce) suffix
|
/// match: forks the PhotonRoomId with a per-(player, nonce) suffix
|
||||||
|
|||||||
@@ -52,7 +52,18 @@ public class MatchController(
|
|||||||
var pid = this.RequireCurrentPlayerId();
|
var pid = this.RequireCurrentPlayerId();
|
||||||
if (code == 0)
|
if (code == 0)
|
||||||
{
|
{
|
||||||
joinTimeouts.MarkCompleted(pid, instanceId, label);
|
var completed = joinTimeouts.MarkCompleted(pid, instanceId, label);
|
||||||
|
if (completed.HasValue)
|
||||||
|
{
|
||||||
|
presence.SetRoom(pid, completed.Value.TargetRoom);
|
||||||
|
logger.LogInformation(
|
||||||
|
"[joinresult] committed presence player={Player} room={RoomId}/{RoomName} instance={Instance} deferred={Deferred}",
|
||||||
|
pid,
|
||||||
|
completed.Value.TargetRoom.RoomId,
|
||||||
|
completed.Value.TargetRoom.Name,
|
||||||
|
completed.Value.TargetRoom.RoomInstanceId,
|
||||||
|
completed.Value.DeferPresenceCommit);
|
||||||
|
}
|
||||||
logger.LogInformation(
|
logger.LogInformation(
|
||||||
"[joinresult] player={Player} instance={Instance} OK ({Label})",
|
"[joinresult] player={Player} instance={Instance} OK ({Label})",
|
||||||
pid, instanceId, label);
|
pid, instanceId, label);
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"3DCharades": "aj7w8q5nrfyt2ssfoovawtz4l.png",
|
"3DCharades": "aj7w8q5nrfyt2ssfoovawtz4l.png",
|
||||||
"BowlingAlley": "8gwqibu0anm4j0rw54xo2y0yd.png",
|
"BowlingAlley": "8gwqibu0anm4j0rw54xo2y0yd.png",
|
||||||
|
"Crescendo": "image_Crescendo.png",
|
||||||
"CrimsonCauldron": "ae6yh8p6y8p3cuyqkc4l8wi4z.png",
|
"CrimsonCauldron": "ae6yh8p6y8p3cuyqkc4l8wi4z.png",
|
||||||
"DiscGolfLake": "86s8y4ihyhx7n9ac41gwahwze.png",
|
"DiscGolfLake": "86s8y4ihyhx7n9ac41gwahwze.png",
|
||||||
"DiscGolfPropulsion": "6wvnxmrmsw98wsttajp0nreci.png",
|
"DiscGolfPropulsion": "6wvnxmrmsw98wsttajp0nreci.png",
|
||||||
@@ -17,4 +18,4 @@
|
|||||||
"Soccer": "apo2sd115tuwueyoprp8jhx7b.png",
|
"Soccer": "apo2sd115tuwueyoprp8jhx7b.png",
|
||||||
"StuntRunner": "8j4f516axpnpjgnj342t85vkd.png",
|
"StuntRunner": "8j4f516axpnpjgnj342t85vkd.png",
|
||||||
"TheRiseofJumbotron": "8x6qaj4nlbudf1412tupxkq9n.png"
|
"TheRiseofJumbotron": "8x6qaj4nlbudf1412tupxkq9n.png"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,6 +145,10 @@
|
|||||||
<Link>data\images\%(Filename)%(Extension)</Link>
|
<Link>data\images\%(Filename)%(Extension)</Link>
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
|
<None Include="Data\images\image_*.png">
|
||||||
|
<Link>data\images\%(Filename)%(Extension)</Link>
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
<None Include="Data\images\*.jpg">
|
<None Include="Data\images\*.jpg">
|
||||||
<Link>data\images\%(Filename)%(Extension)</Link>
|
<Link>data\images\%(Filename)%(Extension)</Link>
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public sealed class JoinTimeoutService(
|
|||||||
private static readonly TimeSpan Timeout = TimeSpan.FromSeconds(30);
|
private static readonly TimeSpan Timeout = TimeSpan.FromSeconds(30);
|
||||||
private readonly ConcurrentDictionary<long, PendingJoin> _pending = new();
|
private readonly ConcurrentDictionary<long, PendingJoin> _pending = new();
|
||||||
|
|
||||||
public void MarkPending(long playerId, RoomInstanceDto? room)
|
public void MarkPending(long playerId, RoomInstanceDto? room, bool deferPresenceCommit = false)
|
||||||
{
|
{
|
||||||
if (room is null) return;
|
if (room is null) return;
|
||||||
|
|
||||||
@@ -28,9 +28,8 @@ public sealed class JoinTimeoutService(
|
|||||||
ClearForPlayer(playerId, "replaced");
|
ClearForPlayer(playerId, "replaced");
|
||||||
|
|
||||||
var pending = new PendingJoin(
|
var pending = new PendingJoin(
|
||||||
room.RoomInstanceId,
|
room,
|
||||||
room.RoomId,
|
deferPresenceCommit,
|
||||||
room.Name ?? string.Empty,
|
|
||||||
new CancellationTokenSource());
|
new CancellationTokenSource());
|
||||||
|
|
||||||
_pending[playerId] = pending;
|
_pending[playerId] = pending;
|
||||||
@@ -41,26 +40,28 @@ public sealed class JoinTimeoutService(
|
|||||||
_ = WatchAsync(playerId, pending);
|
_ = WatchAsync(playerId, pending);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MarkCompleted(long playerId, long instanceId, string outcome)
|
public (RoomInstanceDto TargetRoom, bool DeferPresenceCommit)? MarkCompleted(long playerId, long instanceId, string outcome)
|
||||||
{
|
{
|
||||||
if (!_pending.TryGetValue(playerId, out var pending) || pending.InstanceId != instanceId)
|
if (!_pending.TryGetValue(playerId, out var pending) || pending.InstanceId != instanceId)
|
||||||
return;
|
return null;
|
||||||
|
|
||||||
if (!RemovePending(playerId, pending))
|
if (!RemovePending(playerId, pending))
|
||||||
return;
|
return null;
|
||||||
|
|
||||||
pending.Cancellation.Cancel();
|
pending.Cancellation.Cancel();
|
||||||
logger.LogInformation(
|
logger.LogInformation(
|
||||||
"[join-watchdog] completed player={PlayerId} instance={InstanceId} outcome={Outcome}",
|
"[join-watchdog] completed player={PlayerId} instance={InstanceId} outcome={Outcome}",
|
||||||
playerId, instanceId, outcome);
|
playerId, instanceId, outcome);
|
||||||
|
return (pending.TargetRoom, pending.DeferPresenceCommit);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task MarkFailedAsync(long playerId, long instanceId, string outcome)
|
public async Task MarkFailedAsync(long playerId, long instanceId, string outcome)
|
||||||
{
|
{
|
||||||
MarkCompleted(playerId, instanceId, outcome);
|
var completed = MarkCompleted(playerId, instanceId, outcome);
|
||||||
|
|
||||||
var current = presence.GetRoom(playerId);
|
var current = presence.GetRoom(playerId);
|
||||||
if (current is null || current.RoomInstanceId != instanceId)
|
var failedRoom = completed.HasValue ? completed.Value.TargetRoom : current;
|
||||||
|
if (failedRoom is null || (!completed.HasValue && current?.RoomInstanceId != instanceId))
|
||||||
{
|
{
|
||||||
logger.LogInformation(
|
logger.LogInformation(
|
||||||
"[join-watchdog] failure ignored player={PlayerId} instance={InstanceId} current={CurrentInstance}",
|
"[join-watchdog] failure ignored player={PlayerId} instance={InstanceId} current={CurrentInstance}",
|
||||||
@@ -72,7 +73,7 @@ public sealed class JoinTimeoutService(
|
|||||||
await notifications.KickPlayerAsync(playerId, "Room join failed. Returning to dorm.");
|
await notifications.KickPlayerAsync(playerId, "Room join failed. Returning to dorm.");
|
||||||
logger.LogWarning(
|
logger.LogWarning(
|
||||||
"[join-watchdog] kicked failed join player={PlayerId} room={RoomId}/{RoomName} instance={InstanceId} outcome={Outcome}",
|
"[join-watchdog] kicked failed join player={PlayerId} room={RoomId}/{RoomName} instance={InstanceId} outcome={Outcome}",
|
||||||
playerId, current.RoomId, current.Name, instanceId, outcome);
|
playerId, failedRoom.RoomId, failedRoom.Name, instanceId, outcome);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task WatchAsync(long playerId, PendingJoin pending)
|
private async Task WatchAsync(long playerId, PendingJoin pending)
|
||||||
@@ -95,7 +96,7 @@ public sealed class JoinTimeoutService(
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var current = presence.GetRoom(playerId);
|
var current = presence.GetRoom(playerId);
|
||||||
if (current is null || current.RoomInstanceId != pending.InstanceId)
|
if (!pending.DeferPresenceCommit && (current is null || current.RoomInstanceId != pending.InstanceId))
|
||||||
{
|
{
|
||||||
logger.LogInformation(
|
logger.LogInformation(
|
||||||
"[join-watchdog] timeout skipped player={PlayerId} pending={PendingInstance} current={CurrentInstance}",
|
"[join-watchdog] timeout skipped player={PlayerId} pending={PendingInstance} current={CurrentInstance}",
|
||||||
@@ -107,7 +108,7 @@ public sealed class JoinTimeoutService(
|
|||||||
await notifications.KickPlayerAsync(playerId, "Room join timed out. Returning to dorm.");
|
await notifications.KickPlayerAsync(playerId, "Room join timed out. Returning to dorm.");
|
||||||
logger.LogWarning(
|
logger.LogWarning(
|
||||||
"[join-watchdog] timed out player={PlayerId} room={RoomId}/{RoomName} instance={InstanceId}",
|
"[join-watchdog] timed out player={PlayerId} room={RoomId}/{RoomName} instance={InstanceId}",
|
||||||
playerId, pending.RoomId, pending.RoomName, pending.InstanceId);
|
playerId, pending.TargetRoom.RoomId, pending.TargetRoom.Name, pending.InstanceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClearForPlayer(long playerId, string reason)
|
private void ClearForPlayer(long playerId, string reason)
|
||||||
@@ -135,8 +136,10 @@ public sealed class JoinTimeoutService(
|
|||||||
(room.PhotonRoomId?.StartsWith("^dormroom_", StringComparison.OrdinalIgnoreCase) ?? false);
|
(room.PhotonRoomId?.StartsWith("^dormroom_", StringComparison.OrdinalIgnoreCase) ?? false);
|
||||||
|
|
||||||
private sealed record PendingJoin(
|
private sealed record PendingJoin(
|
||||||
long InstanceId,
|
RoomInstanceDto TargetRoom,
|
||||||
long RoomId,
|
bool DeferPresenceCommit,
|
||||||
string RoomName,
|
CancellationTokenSource Cancellation)
|
||||||
CancellationTokenSource Cancellation);
|
{
|
||||||
|
public long InstanceId => TargetRoom.RoomInstanceId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user