mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-25 23:18:44 -07:00
feat: Enhance room cloning functionality; ensure cloned rooms include source scenes for complete structure
This commit is contained in:
@@ -1020,7 +1020,42 @@ public class RoomsModerationController(DorkNetDbContext db) : ControllerBase
|
|||||||
};
|
};
|
||||||
db.Rooms.Add(clone);
|
db.Rooms.Add(clone);
|
||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
return Ok(Services.RoomService.ToWireRoom(clone));
|
|
||||||
|
// Copy the source's scenes (subrooms) so the clone is structurally
|
||||||
|
// complete. Without this the clone has zero subrooms and the client's
|
||||||
|
// room reader rejects it. Shallow copy — scenes point at the same data
|
||||||
|
// blobs (copy-on-write happens when the clone is later saved).
|
||||||
|
var sourceScenes = await db.RoomScenes
|
||||||
|
.Where(s => s.RoomId == source.Id)
|
||||||
|
.OrderBy(s => s.OrderIndex)
|
||||||
|
.ToListAsync();
|
||||||
|
var clonedScenes = sourceScenes.Select(s => new RoomSceneEntity
|
||||||
|
{
|
||||||
|
RoomId = clone.Id,
|
||||||
|
OrderIndex = s.OrderIndex,
|
||||||
|
Name = s.Name,
|
||||||
|
RoomSceneLocationId = s.RoomSceneLocationId,
|
||||||
|
DataBlobName = s.DataBlobName,
|
||||||
|
StudioSubRoomDataSaveId = s.StudioSubRoomDataSaveId,
|
||||||
|
StudioUnityAssetId = s.StudioUnityAssetId,
|
||||||
|
StudioAssetBundleNamesCsv = s.StudioAssetBundleNamesCsv,
|
||||||
|
MaxPlayers = s.MaxPlayers,
|
||||||
|
IsSandbox = s.IsSandbox,
|
||||||
|
CanMatchmakeInto = s.CanMatchmakeInto,
|
||||||
|
DataModifiedAt = DateTime.UtcNow,
|
||||||
|
}).ToList();
|
||||||
|
if (clonedScenes.Count > 0)
|
||||||
|
{
|
||||||
|
db.RoomScenes.AddRange(clonedScenes);
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// The 2023 client's clone (RecNet.Runtime NLDBPDCNNCF.GDHIIAHCBMN)
|
||||||
|
// deserializes the response as the FULL room-details object
|
||||||
|
// (FGCPNAACHIK — the same type get-by-id / rename return), NOT the
|
||||||
|
// slim list-room shape. Returning ToWireRoom here made the strict
|
||||||
|
// reader fail → "Failed to copy room: Failed to clone room".
|
||||||
|
return Ok(RoomsController.BuildRoomDetails(clone, clonedScenes));
|
||||||
}
|
}
|
||||||
public sealed class CloneBareRequest { public string? Name { get; set; } }
|
public sealed class CloneBareRequest { public string? Name { get; set; } }
|
||||||
|
|
||||||
|
|||||||
@@ -551,25 +551,29 @@ public class CdnController(
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(fileName)) return false;
|
if (string.IsNullOrWhiteSpace(fileName)) return false;
|
||||||
|
|
||||||
|
// MakerPen across ALL Rec Room Originals: overlay the permissive
|
||||||
|
// room-role data (which grants CanUseMakerPen etc.) onto any AG/RRO
|
||||||
|
// room's data blob. This used to also require an accepted RoomRole,
|
||||||
|
// which limited MakerPen to hand-role-granted rooms (Stunt Runner,
|
||||||
|
// Rec Center). Dropping that requirement gives every RRO editing
|
||||||
|
// rights. Chips are preserved because the overlay only REPLACES the
|
||||||
|
// blob's RoomRoleData field (RoomDataBlobService.OverlayRroEditable-
|
||||||
|
// RoleData) — the game-rule circuit data and GameRoleData are left
|
||||||
|
// intact — so quest rooms keep working, exactly as Stunt Runner does.
|
||||||
if (await db.Rooms.AsNoTracking().AnyAsync(r =>
|
if (await db.Rooms.AsNoTracking().AnyAsync(r =>
|
||||||
r.IsAGRoom &&
|
r.IsAGRoom && r.CurrentDataBlobName == fileName))
|
||||||
r.CurrentDataBlobName == fileName &&
|
|
||||||
db.RoomRoles.Any(rr => rr.RoomId == r.Id && rr.Accepted)))
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (fileName.StartsWith("room_", StringComparison.OrdinalIgnoreCase) &&
|
if (fileName.StartsWith("room_", StringComparison.OrdinalIgnoreCase) &&
|
||||||
fileName.EndsWith("_v1.dat", StringComparison.OrdinalIgnoreCase) &&
|
fileName.EndsWith("_v1.dat", StringComparison.OrdinalIgnoreCase) &&
|
||||||
long.TryParse(fileName[5..^7], out var roomId) &&
|
long.TryParse(fileName[5..^7], out var roomId) &&
|
||||||
await db.Rooms.AsNoTracking().AnyAsync(r => r.Id == roomId && r.IsAGRoom) &&
|
await db.Rooms.AsNoTracking().AnyAsync(r => r.Id == roomId && r.IsAGRoom))
|
||||||
await db.RoomRoles.AsNoTracking().AnyAsync(r => r.RoomId == roomId && r.Accepted))
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return await (
|
return await (
|
||||||
from scene in db.RoomScenes.AsNoTracking()
|
from scene in db.RoomScenes.AsNoTracking()
|
||||||
join room in db.Rooms.AsNoTracking() on scene.RoomId equals room.Id
|
join room in db.Rooms.AsNoTracking() on scene.RoomId equals room.Id
|
||||||
where room.IsAGRoom &&
|
where room.IsAGRoom && scene.DataBlobName == fileName
|
||||||
scene.DataBlobName == fileName &&
|
|
||||||
db.RoomRoles.Any(rr => rr.RoomId == room.Id && rr.Accepted)
|
|
||||||
select scene.Id
|
select scene.Id
|
||||||
).AnyAsync();
|
).AnyAsync();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user