mirror of
https://github.com/JogmansonReal/Radicade.git
synced 2026-10-26 07:29:00 -07:00
575 lines
18 KiB
C#
575 lines
18 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using RadicadeServer.DB;
|
|
using RadicadeServer.Extensions;
|
|
using RadicadeServer.RecNet;
|
|
using RadicadeServer.RecNet.Accounts;
|
|
using RadicadeServer.RecNet.Enums;
|
|
using RadicadeServer.RecNet.Enums.Messages;
|
|
using RadicadeServer.RecNet.Enums.Rooms;
|
|
using RadicadeServer.RecNet.Messages;
|
|
using RadicadeServer.RecNet.Rooms;
|
|
|
|
namespace RadicadeServer.Utils
|
|
{
|
|
public static class RoomUtils
|
|
{
|
|
public static IDbContextFactory<RecDBContext> DbFactory = null!;
|
|
|
|
public static async Task<bool> VerifyRole(long playerId, long roomId, RoleType roleType)
|
|
{
|
|
var role = await GetRoleForPlayer(playerId, roomId);
|
|
if (role == null) return false;
|
|
|
|
return role.Role >= roleType;
|
|
}
|
|
|
|
public static async Task<bool> CanSeeRoom(RoomData room, long? accountId)
|
|
{
|
|
if (room.Accessibility != Accessibility.Private) return true;
|
|
if (accountId == null) return false;
|
|
if (room.CreatorAccountId == accountId.Value) return true;
|
|
if (await VerifyRole(accountId.Value, room.RoomId, RoleType.CoOwner)) return true;
|
|
|
|
if (DbFactory != null)
|
|
{
|
|
await using var db = await DbFactory.CreateDbContextAsync();
|
|
if (await (
|
|
from presence in db.Presences.AsNoTracking()
|
|
join instance in db.RoomInstances.AsNoTracking()
|
|
on presence.roomInstance equals instance.roomInstanceId
|
|
where presence.playerId == accountId.Value && presence.isOnline &&
|
|
instance.roomId == room.RoomId
|
|
select presence.playerId).AnyAsync()) return true;
|
|
}
|
|
|
|
return await HasLiveGameInvite(room.RoomId, accountId.Value);
|
|
}
|
|
|
|
public static async Task<bool> HasLiveGameInvite(long roomId, long accountId)
|
|
{
|
|
if (DbFactory == null) return false;
|
|
|
|
await using var db = await DbFactory.CreateDbContextAsync();
|
|
|
|
long? inviter = await db.Messages.AsNoTracking()
|
|
.Where(message =>
|
|
message.ToPlayerId == accountId &&
|
|
(message.Type == MessageType.GameInvite || message.Type == MessageType.GameInviteV2) &&
|
|
message.RoomId == roomId)
|
|
.OrderByDescending(message => message.Id)
|
|
.Select(message => (long?)message.FromPlayerId)
|
|
.FirstOrDefaultAsync();
|
|
if (inviter == null) return false;
|
|
|
|
return await (
|
|
from presence in db.Presences.AsNoTracking()
|
|
join instance in db.RoomInstances.AsNoTracking()
|
|
on presence.roomInstance equals instance.roomInstanceId
|
|
where presence.playerId == inviter.Value &&
|
|
presence.isOnline &&
|
|
instance.roomId == roomId
|
|
select presence.playerId).AnyAsync();
|
|
}
|
|
|
|
public static async Task<List<RoomData>> VisibleRooms(IEnumerable<RoomData> rooms, long? accountId)
|
|
{
|
|
var visible = new List<RoomData>();
|
|
foreach (var room in rooms)
|
|
{
|
|
if (await CanSeeRoom(room, accountId)) visible.Add(room);
|
|
}
|
|
return visible;
|
|
}
|
|
|
|
public const string PrivateRoomName = "PRIVATE ROOM";
|
|
|
|
public static async Task<bool> IsHiddenFrom(RoomData room, long? accountId)
|
|
=> !room.IsDorm && !await CanSeeRoom(room, accountId);
|
|
|
|
public static FullRoom MaskHiddenRoom(RoomData room)
|
|
{
|
|
return new FullRoom
|
|
{
|
|
RoomId = room.RoomId,
|
|
Name = PrivateRoomName,
|
|
Description = string.Empty,
|
|
ImageName = DBConfig.DefaultRoomImage,
|
|
IsDorm = false,
|
|
State = room.State,
|
|
Accessibility = Accessibility.Private,
|
|
CreatedAt = room.CreatedAt,
|
|
CreatorAccountId = room.CreatorAccountId,
|
|
MaxPlayers = room.MaxPlayers,
|
|
MaxPlayerCalculationMode = room.MaxPlayerCalculationMode,
|
|
CloningAllowed = false,
|
|
DisableRoomComments = true,
|
|
CustomWarning = string.Empty,
|
|
SubRooms = new List<SubRoom>(),
|
|
Roles = new List<RoomRole>(),
|
|
LoadScreens = new List<RoomLoadScreen>(),
|
|
PromoImages = new List<string>(),
|
|
PromoExternalContent = new List<ExternalContent>(),
|
|
DataBlob = string.Empty,
|
|
Tags = new List<ItemTag>(),
|
|
Stats = new RoomStats { RoomId = room.RoomId },
|
|
Version = 1
|
|
};
|
|
}
|
|
|
|
public static async Task<RoomInstance?> ForViewerAsync(RoomInstance? instance, long? viewerId)
|
|
{
|
|
if (instance == null) return null;
|
|
|
|
await using var db = await DbFactory.CreateDbContextAsync();
|
|
var room = await db.Rooms.AsNoTracking().FirstOrDefaultAsync(x => x.RoomId == instance.roomId);
|
|
if (room == null || !await IsHiddenFrom(room, viewerId)) return instance;
|
|
|
|
var masked = instance.Copy();
|
|
masked.name = PrivateRoomName;
|
|
return masked;
|
|
}
|
|
public static async Task<List<RoomRole>> GetRoles(long roomId)
|
|
{
|
|
await using var db = await DbFactory.CreateDbContextAsync();
|
|
|
|
var room = await db.Rooms.AsNoTracking().FirstOrDefaultAsync(x => x.RoomId == roomId);
|
|
if (room == null) return [];
|
|
|
|
var roomRole = await db.RoomRoles.AsNoTracking().Where(x => x.RoomId == roomId).ToListAsync();
|
|
|
|
var creatorRow = roomRole.FirstOrDefault(x => x.AccountId == room.CreatorAccountId);
|
|
if (creatorRow == null)
|
|
roomRole.Add(new RoomRole { AccountId = room.CreatorAccountId, InvitedRole = RoleType.None, Role = RoleType.Creator, RoomId = roomId });
|
|
else if (creatorRow.Role < RoleType.Creator)
|
|
creatorRow.Role = RoleType.Creator;
|
|
|
|
if (room.IsRRO)
|
|
{
|
|
var rroOwners = (await db.ServerConfig.AsNoTracking().FirstOrDefaultAsync(x => x.Key == "HighRanks"))?.Value;
|
|
|
|
foreach (var dev in (rroOwners ?? string.Empty).Split(',', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries))
|
|
{
|
|
if (!long.TryParse(dev, out long userId)) continue;
|
|
|
|
foreach (var role in new[] { RoleType.Creator, RoleType.Moderator })
|
|
{
|
|
if (roomRole.Any(x => x.AccountId == userId && x.Role == role)) continue;
|
|
|
|
roomRole.Add(new RoomRole { AccountId = userId, InvitedRole = RoleType.None, Role = role, RoomId = roomId });
|
|
}
|
|
}
|
|
}
|
|
|
|
return roomRole;
|
|
}
|
|
public static async Task<RoomRole?> GetRoleForPlayer(long playerId, long roomId)
|
|
{
|
|
var roomRoles = await GetRoles(roomId);
|
|
|
|
return roomRoles
|
|
.Where(x => x.AccountId == playerId)
|
|
.OrderByDescending(x => x.Role)
|
|
.FirstOrDefault();
|
|
}
|
|
|
|
public static SubRoomDataSave BuildCurrentSave(SubRoom subRoom)
|
|
{
|
|
return new SubRoomDataSave
|
|
{
|
|
SubRoomDataSaveId = 1,
|
|
SubRoomId = subRoom.SubRoomId,
|
|
DataBlob = subRoom.DataBlob,
|
|
SavedByAccountId = subRoom.SavedByAccountId,
|
|
CreatedAt = subRoom.CreatedAt,
|
|
UnityAssetId = string.IsNullOrEmpty(subRoom.UnityAssetId) ? null : subRoom.UnityAssetId,
|
|
PersistenceVersion = 1,
|
|
OMVersion = 1,
|
|
UgcSubVersion = 1,
|
|
SavedOnPlatform = 0,
|
|
SavedOnDeviceClass = 0,
|
|
Description = string.Empty,
|
|
ModerationState = 0
|
|
};
|
|
}
|
|
|
|
public static object BuildSaveResponse(SubRoom subRoom, string? dataBlobHash)
|
|
{
|
|
return new
|
|
{
|
|
subRoomDataSaveId = 1L,
|
|
subRoomId = subRoom.SubRoomId,
|
|
unityAssetId = string.IsNullOrEmpty(subRoom.UnityAssetId) ? null : subRoom.UnityAssetId,
|
|
unityAsset = (string?)null,
|
|
unityAssetHash = (string?)null,
|
|
dataBlob = subRoom.DataBlob ?? string.Empty,
|
|
dataBlobHash,
|
|
savedByAccountId = (long?)subRoom.SavedByAccountId,
|
|
savedOnPlatform = 0,
|
|
savedOnDeviceClass = 0,
|
|
description = string.Empty,
|
|
createdAt = subRoom.CreatedAt
|
|
};
|
|
}
|
|
|
|
public static async Task<List<SubRoomDataSave>> GetSaveHistory(RecDBContext ctx, long roomId, long subRoomId)
|
|
{
|
|
var subRoom = await ctx.SubRooms.AsNoTracking()
|
|
.FirstOrDefaultAsync(x => x.RoomId == roomId && x.SubRoomId == subRoomId);
|
|
|
|
if (subRoom == null) return new List<SubRoomDataSave>();
|
|
|
|
var saves = new List<SubRoomDataSave>();
|
|
|
|
if (!string.IsNullOrEmpty(subRoom.DataBlob)) saves.Add(BuildCurrentSave(subRoom));
|
|
|
|
var history = await ctx.SubRoomHistory.AsNoTracking()
|
|
.Where(x => x.RoomId == roomId && x.SubRoomId == subRoomId && x.DataBlob != "")
|
|
.OrderByDescending(x => x.CreatedAt)
|
|
.ThenByDescending(x => x.HistoryId)
|
|
.ToListAsync();
|
|
|
|
saves.AddRange(history.Select(BuildRestorableSave));
|
|
|
|
return saves;
|
|
}
|
|
|
|
public static SubRoomDataSave BuildRestorableSave(RestorableSubRoom row)
|
|
{
|
|
return new SubRoomDataSave
|
|
{
|
|
SubRoomDataSaveId = row.HistoryId + 1,
|
|
SubRoomId = row.SubRoomId,
|
|
DataBlob = row.DataBlob,
|
|
SavedByAccountId = row.SavedByAccountId,
|
|
CreatedAt = row.CreatedAt,
|
|
PersistenceVersion = 1,
|
|
OMVersion = 1,
|
|
UgcSubVersion = 1,
|
|
SavedOnPlatform = 0,
|
|
SavedOnDeviceClass = 0,
|
|
Description = string.Empty,
|
|
ModerationState = 0
|
|
};
|
|
}
|
|
|
|
public static FullRoom ConvertToFull(this RoomData room, List<SubRoom> subRooms, RoomStats stats, List<RoomRole> roles)
|
|
{
|
|
FullRoom fullRoom = new FullRoom
|
|
{
|
|
Name = room.Name,
|
|
RoomId = room.RoomId,
|
|
Description = room.Description ?? string.Empty,
|
|
ImageName = room.ImageName,
|
|
IsRRO = room.IsRRO,
|
|
IsDeveloperOwned = room.IsDeveloperOwned,
|
|
IsDorm = room.IsDorm,
|
|
State = room.State,
|
|
Accessibility = room.Accessibility,
|
|
CreatedAt = room.CreatedAt,
|
|
CreatorAccountId = room.CreatorAccountId,
|
|
SupportsJuniors = room.SupportsJuniors,
|
|
SupportsLevelVoting = room.SupportsLevelVoting,
|
|
SupportsMobile = room.SupportsMobile,
|
|
SupportsQuest2 = room.SupportsQuest2,
|
|
SupportsScreens = room.SupportsScreens,
|
|
SupportsTeleportVR = room.SupportsTeleportVR,
|
|
SupportsVRLow = room.SupportsVRLow,
|
|
SupportsWalkVR = room.SupportsWalkVR,
|
|
EncryptVoiceChat = room.EncryptVoiceChat,
|
|
MaxPlayerCalculationMode = room.MaxPlayerCalculationMode,
|
|
MaxPlayers = room.MaxPlayers,
|
|
SubRooms = subRooms,
|
|
Stats = stats,
|
|
CloningAllowed = room.CloningAllowed,
|
|
CustomWarning = room.CustomWarning ?? string.Empty,
|
|
Roles = roles,
|
|
DataBlob = null,
|
|
Tags = StringTools.ReadTags(room.Tags),
|
|
LoadScreens = room.loadScreen.FromJson<List<RoomLoadScreen>>() ?? new(),
|
|
WarningMask = room.WarningMask,
|
|
Version = room.Version,
|
|
DisableRoomComments = room.DisableRoomComments,
|
|
DisableMicAutoMute = room.DisableMicAutoMute,
|
|
MinLevel = room.MinLevel
|
|
};
|
|
|
|
foreach (var subRoom in subRooms)
|
|
{
|
|
subRoom.CurrentSave = string.IsNullOrEmpty(subRoom.DataBlob) ? null : BuildCurrentSave(subRoom);
|
|
|
|
subRoom.CreatorAccountId = subRoom.SavedByAccountId != 0 ? subRoom.SavedByAccountId : null;
|
|
}
|
|
|
|
return fullRoom;
|
|
}
|
|
|
|
public static async Task<List<FullRoom>> BulkConvertRoomData(List<RoomData> data)
|
|
{
|
|
var fullRooms = new List<FullRoom>();
|
|
foreach (var d in data)
|
|
{
|
|
var found = await GetRoom(d.RoomId);
|
|
if (found != null)
|
|
fullRooms.Add(found);
|
|
}
|
|
return fullRooms;
|
|
}
|
|
public static async Task<List<RoomDetail>> BulkConvertRoomDataToRoomDetail(List<RoomData> data)
|
|
{
|
|
var rooms = new List<RoomDetail>();
|
|
foreach (var d in data)
|
|
{
|
|
var found = await GetRoom(d.RoomId);
|
|
if (found != null)
|
|
rooms.Add(found);
|
|
}
|
|
return rooms;
|
|
}
|
|
|
|
public static async Task<FullRoom?> GetRoom(string Name)
|
|
{
|
|
await using var ctx = await DbFactory.CreateDbContextAsync();
|
|
|
|
var room = await ctx.Rooms.AsNoTracking().FirstOrDefaultAsync((x) => x.Name == Name);
|
|
if (room == null && !string.IsNullOrWhiteSpace(Name) && Name.StartsWith("@", StringComparison.Ordinal) && Name.EndsWith("'s Dorm", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var username = Name.Substring(1, Name.Length - 8);
|
|
var owner = await ctx.Profiles.AsNoTracking().FirstOrDefaultAsync(x => x.username == username || x.displayName == username);
|
|
if (owner != null)
|
|
{
|
|
room = await ctx.Rooms.AsNoTracking().FirstOrDefaultAsync(x => x.IsDorm && x.CreatorAccountId == owner.accountId);
|
|
}
|
|
}
|
|
if (room == null) return null;
|
|
|
|
return await GetRoom(room.RoomId);
|
|
}
|
|
public static async Task<FullRoom?> GetRoom(long Id)
|
|
{
|
|
await using var ctx = await DbFactory.CreateDbContextAsync();
|
|
|
|
var room = await ctx.Rooms.AsNoTracking().FirstOrDefaultAsync((x) => x.RoomId == Id);
|
|
if (room == null) return null;
|
|
|
|
var cheers = await ctx.RoomInteractions.AsNoTracking().CountAsync(x => x.RoomId == Id && x.Cheered);
|
|
var favourites = await ctx.RoomInteractions.AsNoTracking().CountAsync(x => x.RoomId == Id && x.Favorited);
|
|
var visitorCount = await ctx.RoomInteractions.AsNoTracking().CountAsync(x => x.RoomId == Id && x.Visited);
|
|
var visitCount = await ctx.RoomInteractions.AsNoTracking()
|
|
.Where(x => x.RoomId == Id && x.Visited)
|
|
.SumAsync(x => (int?)x.VisitCount) ?? 0;
|
|
|
|
var roomStats = new RoomStats { CheerCount = cheers, FavoriteCount = favourites, RoomId = Id, VisitCount = visitCount, VisitorCount = visitorCount };
|
|
|
|
var roomRoles = await GetRoles(Id);
|
|
|
|
var subRooms = await ctx.SubRooms.AsNoTracking().Where((x) => x.RoomId == Id).ToListAsync();
|
|
|
|
var missingBlobs = subRooms
|
|
.Where(x => !string.IsNullOrEmpty(x.DataBlob) && !File.Exists(Path.Join(DBConfig.CDNStorage, x.DataBlob)))
|
|
.ToList();
|
|
|
|
if (missingBlobs.Count > 0)
|
|
{
|
|
var missingIds = missingBlobs.Select(x => x.SubRoomId).ToList();
|
|
|
|
var candidates = await ctx.SubRoomHistory.AsNoTracking()
|
|
.Where(x => missingIds.Contains(x.SubRoomId) && x.DataBlob != "")
|
|
.OrderByDescending(x => x.CreatedAt)
|
|
.ToListAsync();
|
|
|
|
foreach (var subRoom in missingBlobs)
|
|
{
|
|
var recovered = candidates
|
|
.Where(x => x.SubRoomId == subRoom.SubRoomId)
|
|
.Select(x => x.DataBlob)
|
|
.FirstOrDefault(blob => !string.IsNullOrEmpty(blob) && File.Exists(Path.Join(DBConfig.CDNStorage, blob)));
|
|
|
|
subRoom.DataBlob = recovered ?? "";
|
|
ctx.SubRooms.Attach(subRoom);
|
|
ctx.Entry(subRoom).Property(x => x.DataBlob).IsModified = true;
|
|
}
|
|
|
|
await ctx.SaveChangesAsync();
|
|
}
|
|
|
|
return room.ConvertToFull(subRooms, roomStats, roomRoles);
|
|
}
|
|
|
|
public static async Task<RoomStats?> GetRoomStats(long roomId, long? playerId)
|
|
{
|
|
await using var ctx = await DbFactory.CreateDbContextAsync();
|
|
|
|
var cheers = await ctx.RoomInteractions.AsNoTracking().CountAsync(x => x.RoomId == roomId && x.Cheered);
|
|
var favourites = await ctx.RoomInteractions.AsNoTracking().CountAsync(x => x.RoomId == roomId && x.Favorited);
|
|
|
|
var visitorCount = await ctx.RoomInteractions.AsNoTracking().CountAsync(x => x.RoomId == roomId && x.Visited);
|
|
|
|
var visited = 0;
|
|
if (playerId != null)
|
|
{
|
|
var interaction = await ctx.RoomInteractions.AsNoTracking()
|
|
.FirstOrDefaultAsync(x => x.RoomId == roomId && x.PlayerId == playerId);
|
|
|
|
if (interaction != null)
|
|
visited = interaction.VisitCount;
|
|
}
|
|
|
|
return new RoomStats() { CheerCount = cheers, FavoriteCount = favourites, RoomId = roomId, VisitCount = visited, VisitorCount = visitorCount };
|
|
}
|
|
|
|
|
|
public static async Task<FullRoom?> CloneRoom(long originalRoomId, long newCreator, string newName)
|
|
{
|
|
await using var ctx = await DbFactory.CreateDbContextAsync();
|
|
|
|
FullRoom? room = await GetRoom(originalRoomId);
|
|
if (room == null)
|
|
return null;
|
|
|
|
|
|
|
|
var tags = room.Tags;
|
|
var rro = tags.Find(x => x.Tag.StartsWith("rro") && x.Type >= TagType.Auto);
|
|
if (rro != null)
|
|
tags.Remove(rro);
|
|
|
|
RoomData roomData = new RoomData
|
|
{
|
|
State = RoomState.Active,
|
|
SupportsJuniors = room.SupportsJuniors,
|
|
SupportsLevelVoting = room.SupportsLevelVoting,
|
|
SupportsMobile = room.SupportsMobile,
|
|
SupportsQuest2 = room.SupportsQuest2,
|
|
SupportsScreens = room.SupportsScreens,
|
|
SupportsTeleportVR = room.SupportsTeleportVR,
|
|
SupportsVRLow = room.SupportsVRLow,
|
|
SupportsWalkVR = room.SupportsWalkVR,
|
|
Accessibility = Accessibility.Private,
|
|
CloningAllowed = false,
|
|
CreatedAt = DateTime.Now,
|
|
CreatorAccountId = newCreator,
|
|
CustomWarning = room.CustomWarning,
|
|
Description = room.Description,
|
|
DisableMicAutoMute = room.DisableMicAutoMute,
|
|
DisableRoomComments = room.DisableRoomComments,
|
|
EncryptVoiceChat = room.EncryptVoiceChat,
|
|
ImageName = room.ImageName,
|
|
IsDorm = room.IsDorm,
|
|
IsRRO = false,
|
|
|
|
IsDeveloperOwned = !room.IsDorm && await ctx.IsDeveloper(newCreator),
|
|
MaxPlayerCalculationMode = room.MaxPlayerCalculationMode,
|
|
MaxPlayers = room.MaxPlayers,
|
|
MinLevel = room.MinLevel,
|
|
Name = newName,
|
|
Tags = StringTools.CreateTagString(tags),
|
|
WarningMask = room.WarningMask,
|
|
};
|
|
|
|
await ctx.AddAsync(roomData);
|
|
await ctx.SaveChangesAsync();
|
|
|
|
|
|
if (room.SubRooms == null || room.SubRooms.Count == 0)
|
|
{
|
|
ctx.Remove(roomData);
|
|
await ctx.SaveChangesAsync();
|
|
return null;
|
|
}
|
|
|
|
foreach (SubRoom subRoom in room.SubRooms)
|
|
{
|
|
if (subRoom == null) continue;
|
|
await ctx.SubRooms.AddAsync(new SubRoom
|
|
{
|
|
Accessibility = subRoom.Accessibility,
|
|
DataBlob = subRoom.DataBlob,
|
|
UnityAssetId = subRoom.UnityAssetId,
|
|
IsSandbox = subRoom.IsSandbox,
|
|
UnitySceneId = subRoom.UnitySceneId,
|
|
MaxPlayers = subRoom.MaxPlayers,
|
|
Name = subRoom.Name,
|
|
RoomId = roomData.RoomId
|
|
});
|
|
}
|
|
|
|
await ctx.SaveChangesAsync();
|
|
|
|
|
|
await ctx.RoomStats.AddAsync(new RoomStats
|
|
{
|
|
RoomId = roomData.RoomId,
|
|
FavoriteCount = 0,
|
|
CheerCount = 0,
|
|
VisitCount = 0,
|
|
VisitorCount = 0,
|
|
});
|
|
|
|
|
|
await ctx.RoomRoles.AddAsync(new RoomRole
|
|
{
|
|
RoomId = roomData.RoomId,
|
|
Role = RoleType.Creator,
|
|
InvitedRole = RoleType.None,
|
|
AccountId = newCreator
|
|
});
|
|
|
|
await ctx.SaveChangesAsync();
|
|
|
|
return await GetRoom(roomData.RoomId);
|
|
}
|
|
|
|
private static async Task<FullRoom?> GetDormTemplateRoom()
|
|
{
|
|
var templateRoom = await GetRoom(1);
|
|
if (templateRoom != null) return templateRoom;
|
|
|
|
await using var ctx = await DbFactory.CreateDbContextAsync();
|
|
var template = await ctx.Rooms.AsNoTracking().FirstOrDefaultAsync(room => room.IsDorm && room.CreatorAccountId == 1);
|
|
return template == null ? null : await GetRoom(template.RoomId);
|
|
}
|
|
|
|
public static async Task<FullRoom?> GetOrCreateDorm(long playerId)
|
|
{
|
|
await using var ctx = await DbFactory.CreateDbContextAsync();
|
|
|
|
var roomData = await ctx.Rooms.AsNoTracking().FirstOrDefaultAsync((x) => x.IsDorm && x.CreatorAccountId == playerId);
|
|
if (roomData == null)
|
|
{
|
|
var templateRoom = await GetDormTemplateRoom();
|
|
if (templateRoom == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return await CloneRoom(templateRoom.RoomId, playerId, "DormRoom");
|
|
}
|
|
|
|
|
|
var hasSubRoom = await ctx.SubRooms.AnyAsync(s => s.RoomId == roomData.RoomId);
|
|
if (!hasSubRoom)
|
|
{
|
|
var templateRoom = await GetDormTemplateRoom();
|
|
var templateSub = templateRoom?.SubRooms?.FirstOrDefault();
|
|
if (templateSub != null)
|
|
{
|
|
await ctx.SubRooms.AddAsync(new SubRoom
|
|
{
|
|
RoomId = roomData.RoomId,
|
|
DataBlob = templateSub.DataBlob,
|
|
UnityAssetId = templateSub.UnityAssetId,
|
|
IsSandbox = templateSub.IsSandbox,
|
|
UnitySceneId = templateSub.UnitySceneId,
|
|
MaxPlayers = templateSub.MaxPlayers,
|
|
Name = templateSub.Name,
|
|
Accessibility = templateSub.Accessibility
|
|
});
|
|
await ctx.SaveChangesAsync();
|
|
}
|
|
}
|
|
|
|
return await GetRoom(roomData.RoomId);
|
|
}
|
|
}
|
|
}
|