Import march-2020-03-10 from private repo (scrubbed 2026-05-27)

Targets Rec Room 2020.03.10 client (also serves 2020.03.06).

Re-import after adding:
- DorkNet.ClientMod/dorknet-clientmod.json.template — config schema
  the launcher's manifest-driven patcher renders into UserData/.
- tools/build-patcher-zip.ps1 — produces dorknet-clientpatch-{key}.zip
  for v1-march-* Release uploads.
- .github/workflows/release.yml — on tag push publishes both
  dorknet-server-march_2020_03_10-win-x64.zip and
  dorknet-clientpatch-march_2020_03_10.zip as Release assets.

Same scrub rules as december; tools/build-patcher-zip.ps1 added to
the maintainer-side allow-list so it survives.
This commit is contained in:
Alexa
2026-05-27 01:06:12 +03:00
commit d471b418b9
389 changed files with 104767 additions and 0 deletions
@@ -0,0 +1,60 @@
using System.ComponentModel.DataAnnotations;
namespace DorkNet.Server.Data.Entities;
/// <summary>
/// One scene within a multi-scene custom room. Most rooms historically
/// had only Scenes[0] (synthesised in <c>BuildRoomDetails</c> from
/// <see cref="RoomEntity.LocationReplicationId"/> +
/// <see cref="RoomEntity.CurrentDataBlobName"/>); rooms imported from a
/// multi-scene archive write one row per chapter here, and the wire-shape
/// builder emits the full <c>Scenes[]</c> array from this table when any
/// rows exist.
///
/// <para>The scene's <see cref="RoomSceneId"/> on the wire is this table's
/// <see cref="OrderIndex"/> — the matchmaking <c>SubRoomId</c> the watch
/// passes to <c>/goto/room/{name}/{subroom}</c> matches against
/// <see cref="Name"/>, then resolves to <see cref="OrderIndex"/> for
/// <c>RoomInstance.SubRoomId</c>.</para>
/// </summary>
public class RoomSceneEntity
{
public long Id { get; set; }
/// <summary>FK to <see cref="RoomEntity"/>. Indexed so the per-room
/// fetch in <c>BuildRoomDetails</c> is one query.</summary>
public long RoomId { get; set; }
/// <summary>0-based index this scene occupies in the wire
/// <c>Scenes[]</c> array. Doubles as the <c>RoomSceneId</c> the
/// matchmaking flow uses for <c>RoomInstance.SubRoomId</c>.</summary>
public int OrderIndex { get; set; }
/// <summary>Display name (e.g. "Lobby", "Ch1_Headfirst"). Matched
/// case-insensitively against the sub-room segment of
/// <c>/goto/room/{name}/{subroom}</c>.</summary>
[MaxLength(128)]
public string Name { get; set; } = string.Empty;
/// <summary>The <c>RoomSceneLocationId</c> GUID the client uses to
/// look up the bundled stage prefab via
/// <c>AGRoomSettings.TryGetRoomSceneLocationById</c>. Defaults to
/// the MakerRoom (Basement) scene GUID — the canonical "blank
/// canvas" stage 2020 custom rooms were built on. Extracted from
/// resources.assets via tools/extract-locations-binary.py: the
/// "Maker Room" Location entry has SceneName=Basement and
/// ReplicationId=a75f7547-79eb-47c6-8986-6767abcb4f92.</summary>
[MaxLength(64)]
public string RoomSceneLocationId { get; set; } = "a75f7547-79eb-47c6-8986-6767abcb4f92";
/// <summary>The <see cref="RoomDataBlobEntity.BlobName"/> the watch
/// downloads as the persisted state for this scene.</summary>
[MaxLength(128)]
public string DataBlobName { get; set; } = string.Empty;
public int MaxPlayers { get; set; } = 8;
public bool IsSandbox { get; set; } = false;
public bool CanMatchmakeInto { get; set; } = true;
public DateTime DataModifiedAt { get; set; } = DateTime.UtcNow;
}