mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-27 07:58:45 -07:00
Enhance GoToController: refactor instance creation logic to support JoinMode; add ApplyNewInstanceAsync method for improved instance handling
This commit is contained in:
@@ -84,7 +84,7 @@ public class GoToController(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var resp = await BuildResponseAsync(roomName);
|
var resp = await BuildResponseAsync(roomName);
|
||||||
if (createPrivateInstance) await ApplyPrivateInstanceAsync(resp, subRoomId: 0);
|
await ApplyNewInstanceAsync(resp, subRoomId: 0, createPrivateInstance, joinMode);
|
||||||
await RecordResponseAsync(resp);
|
await RecordResponseAsync(resp);
|
||||||
return Ok(resp);
|
return Ok(resp);
|
||||||
}
|
}
|
||||||
@@ -93,7 +93,8 @@ public class GoToController(
|
|||||||
public async Task<ActionResult<MatchmakingResponseDto>> GoToRoomFromBody(
|
public async Task<ActionResult<MatchmakingResponseDto>> GoToRoomFromBody(
|
||||||
[FromForm(Name = "RoomName")] string? roomNameForm,
|
[FromForm(Name = "RoomName")] string? roomNameForm,
|
||||||
[FromForm(Name = "roomName")] string? roomNameLower,
|
[FromForm(Name = "roomName")] string? roomNameLower,
|
||||||
[FromForm(Name = "CreatePrivateInstance")] bool createPrivateInstance = false)
|
[FromForm(Name = "CreatePrivateInstance")] bool createPrivateInstance = false,
|
||||||
|
[FromForm(Name = "JoinMode")] int joinMode = 0)
|
||||||
{
|
{
|
||||||
var roomName = roomNameForm
|
var roomName = roomNameForm
|
||||||
?? roomNameLower
|
?? roomNameLower
|
||||||
@@ -101,7 +102,7 @@ public class GoToController(
|
|||||||
?? Request.Query["roomName"].FirstOrDefault();
|
?? Request.Query["roomName"].FirstOrDefault();
|
||||||
if (string.IsNullOrWhiteSpace(roomName))
|
if (string.IsNullOrWhiteSpace(roomName))
|
||||||
return BadRequest(new { error = "missing roomName" });
|
return BadRequest(new { error = "missing roomName" });
|
||||||
return await GoToRoom(roomName, createPrivateInstance);
|
return await GoToRoom(roomName, createPrivateInstance, joinMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("/goto/none")]
|
[HttpPost("/goto/none")]
|
||||||
@@ -124,7 +125,10 @@ public class GoToController(
|
|||||||
[HttpPost("/goto/room/{roomName}/{subRoomName}")]
|
[HttpPost("/goto/room/{roomName}/{subRoomName}")]
|
||||||
public async Task<ActionResult<MatchmakingResponseDto>> GoToSubRoom(
|
public async Task<ActionResult<MatchmakingResponseDto>> GoToSubRoom(
|
||||||
string roomName, string subRoomName,
|
string roomName, string subRoomName,
|
||||||
[FromForm(Name = "CreatePrivateInstance")] bool createPrivateInstance = false)
|
[FromForm(Name = "CreatePrivateInstance")] bool createPrivateInstance = false,
|
||||||
|
// See GoToRoom: JoinMode 1/2 = fork a fresh public/private
|
||||||
|
// instance of this sub-room rather than rejoining the shared one.
|
||||||
|
[FromForm(Name = "JoinMode")] int joinMode = 0)
|
||||||
{
|
{
|
||||||
// Build (don't record yet) — we need to mutate the RoomInstance
|
// Build (don't record yet) — we need to mutate the RoomInstance
|
||||||
// for the sub-room before presence is recorded, otherwise the
|
// for the sub-room before presence is recorded, otherwise the
|
||||||
@@ -213,11 +217,11 @@ public class GoToController(
|
|||||||
// blob, so the sub-scene visually never changes.
|
// blob, so the sub-scene visually never changes.
|
||||||
if (!string.IsNullOrEmpty(subDataBlob)) resp.RoomInstance.DataBlob = subDataBlob;
|
if (!string.IsNullOrEmpty(subDataBlob)) resp.RoomInstance.DataBlob = subDataBlob;
|
||||||
|
|
||||||
// Private instance mutation goes AFTER sub-room mutation so the
|
// Private/new-instance mutation goes AFTER sub-room mutation so the
|
||||||
// PhotonRoomId we register includes the _sub{N} suffix as its
|
// PhotonRoomId we register includes the _sub{N} suffix as its
|
||||||
// base — invitees coming in via /goto/instance/{id} land in the
|
// base — invitees coming in via /goto/instance/{id} land in the
|
||||||
// exact same sub-room photon match, not the lobby's.
|
// exact same sub-room photon match, not the lobby's.
|
||||||
if (createPrivateInstance) await ApplyPrivateInstanceAsync(resp, subRoomId: subId);
|
await ApplyNewInstanceAsync(resp, subRoomId: subId, createPrivateInstance, joinMode);
|
||||||
|
|
||||||
await RecordResponseAsync(resp);
|
await RecordResponseAsync(resp);
|
||||||
return Ok(resp);
|
return Ok(resp);
|
||||||
@@ -801,6 +805,59 @@ public class GoToController(
|
|||||||
resp.RoomInstance.RoomId, subRoomId, ownerId, inst.InstanceId, inst.PhotonRoomId);
|
resp.RoomInstance.RoomId, subRoomId, ownerId, inst.InstanceId, inst.PhotonRoomId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>Apply the "make a new instance" mutation to a freshly
|
||||||
|
/// built matchmaking response based on the watch's JoinMode (and the
|
||||||
|
/// legacy CreatePrivateInstance flag). Does nothing for ordinary
|
||||||
|
/// PublicMatchmaking joins (JoinMode=0) — those keep the shared,
|
||||||
|
/// deterministic instance that lets randos matchmake together.
|
||||||
|
/// • JoinMode=2 / CreatePrivateInstance → fresh invite-gated
|
||||||
|
/// instance (registered + owned, isPrivate=true).
|
||||||
|
/// • JoinMode=1 → fresh PUBLIC instance (unique id+photon room,
|
||||||
|
/// isPrivate=false, not persisted — lives only while populated).
|
||||||
|
/// Both forks change roomInstanceId AND photonRoomId, which is what
|
||||||
|
/// the watch's transition state machine needs to actually leave the
|
||||||
|
/// current match instead of softlocking on "Going to <room>".</summary>
|
||||||
|
private async Task ApplyNewInstanceAsync(
|
||||||
|
MatchmakingResponseDto resp, long subRoomId, bool createPrivateInstance, int joinMode)
|
||||||
|
{
|
||||||
|
if (createPrivateInstance || joinMode == 2 /* PrivateNewInstance */)
|
||||||
|
{
|
||||||
|
await ApplyPrivateInstanceAsync(resp, subRoomId);
|
||||||
|
}
|
||||||
|
else if (joinMode == 1 /* PublicNewInstance */)
|
||||||
|
{
|
||||||
|
ApplyNewPublicInstance(resp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Fork a fresh PUBLIC instance of the room the watch just
|
||||||
|
/// asked for (JoinMode=PublicNewInstance). Unlike a private instance
|
||||||
|
/// this isn't persisted or invite-gated — it's discoverable through
|
||||||
|
/// live <see cref="PlayerPresenceService"/> presence (friends joining
|
||||||
|
/// via /goto/player) and evaporates once empty. The id is packed the
|
||||||
|
/// same way as <see cref="PrivateInstanceService.RegisterAsync"/>
|
||||||
|
/// (nonce in the low 24 bits, roomId/subRoomId in the high bits, kept
|
||||||
|
/// inside int63 for LitJson) so it can't collide with the shared
|
||||||
|
/// roomId*100000 instance the player is forking away from. The photon
|
||||||
|
/// room id gets a <c>_new{nonce}</c> suffix on the existing base so it
|
||||||
|
/// differs from the shared lobby's room.</summary>
|
||||||
|
private void ApplyNewPublicInstance(MatchmakingResponseDto resp)
|
||||||
|
{
|
||||||
|
var nonce = Random.Shared.Next(0x10000, 0xFFFFFF);
|
||||||
|
var instanceId = (long)(((ulong)(uint)nonce & 0xFFFFFFul)
|
||||||
|
^ ((ulong)resp.RoomInstance.RoomId << 24)
|
||||||
|
^ ((ulong)resp.RoomInstance.SubRoomId << 40));
|
||||||
|
if (instanceId < 0) instanceId = -instanceId;
|
||||||
|
|
||||||
|
resp.RoomInstance.RoomInstanceId = instanceId;
|
||||||
|
resp.RoomInstance.PhotonRoomId = $"{resp.RoomInstance.PhotonRoomId}_new{nonce:x6}";
|
||||||
|
resp.RoomInstance.IsPrivate = false;
|
||||||
|
logger.LogInformation(
|
||||||
|
"[goto-newpublic] room={Room} sub={Sub} → instId={Id} photon={Photon}",
|
||||||
|
resp.RoomInstance.RoomId, resp.RoomInstance.SubRoomId,
|
||||||
|
instanceId, resp.RoomInstance.PhotonRoomId);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Upsert the (room, player) <see cref="RoomVisitEntity"/>
|
/// <summary>Upsert the (room, player) <see cref="RoomVisitEntity"/>
|
||||||
/// row for this join. New rows bump
|
/// row for this join. New rows bump
|
||||||
/// <see cref="RoomEntity.VisitorCount"/> (unique-visitor metric);
|
/// <see cref="RoomEntity.VisitorCount"/> (unique-visitor metric);
|
||||||
|
|||||||
Reference in New Issue
Block a user