CircuitsV2 limits are served as UGC.CircuitsV2.Limit.* gameconfig keys and
are editable from admin Settings. Retail drops any send over 5 RPCs/frame
or 1024 bytes/60 frames; both network budgets now default to 1,000,000,000.
The creation limits are raised too, each against the hazard the client
binary shows for it:
- Chips 3000 -> 30000: the chip-culling manager preallocates four
List<Chip>(Chips), so the 1M clamp stays.
- Compute 50000 -> 500000: a per-frame budget with no allocation; the 10M
cap keeps its counters from wrapping.
- CloudValues 100 -> 1000, InkPerChip 15 -> 0: InkPerChip is an ink COST,
multiplied by min(chips, CloudValues), so lowering it is the increase.
The clamps tighten to 10000 / 30000 to keep that product from overflowing
(the room ink cap is a hard-coded 30000).
- UnculledChips / VisibleChips 500 -> 3000: render-cost counts only.
Room save uploads may now be up to 100 MB (Kestrel's 30 MB default would
413 a big circuits room). Contract and evidence:
docs/recroom-2023-circuitsv2-limits.md.
Also includes the Rec Royale night mode client feature
(docs/recroom-2023-scene-moods.md) and the admin blob enable/reset for
baked RRO sub-rooms.
Every HTTP request the 2023-03-21 client can issue now reaches a handler under
the verb it actually uses: 522/522, with an empty KnownGaps allowlist. The
coverage test asserts it, so a regression fails the build rather than becoming
a 404 in the wild.
The six routes left after the previous pass all needed storage that did not
exist, so they are done here as one schema change rather than stubbed:
- ClubRolePermissionEntity (ClubId, MembershipType, six bools) backs
PUT club/{id}/permissions/{role}. A club with no stored row falls back to the
derived default policy, so every club that predates the table behaves exactly
as before. Partial writes keep the values they currently resolve to, so a
client that omits a field cannot silently revoke a permission.
- ClubAdditionalImageEntity (ClubId, Slot, ImageName) backs the gallery. The
details envelope now emits real {ImageName, Slot} rows instead of an empty
array, and DELETE clears a slot.
- ClubEntity.MinLevel and ClubEntity.ClubChatEnabled back their setters and are
read back by hasDisabledClubChat and the Club wire shape, which previously
reported hardcoded defaults.
- ChatMessageEntity.ModerationState backs PUT thread/message/{id}/moderate,
gated so an author can retract their own message but only club moderators and
admins can action anyone else's.
- TestCaseEntity.CommentsJson backs the QA comment endpoint, appending rather
than overwriting so a second tester's note cannot erase the first.
Also corrects the Joinability comment on ClubEntity, which documented
1=RequestToJoin / 2=InviteOnly. The real enum is Open=0, InviteOnly=1,
AskToJoin=2 — the inverted reading the requesttojoin handler was already fixed
away from, left behind where it could mislead the next change.
Audits every route the March-2023 client can call against what this server
actually serves, and fixes the defects that were breaking gameplay. Adds
docs/recroom-2023-client-api-complete.md as the reference: ~500 route
literals across 13 subsystems, with verb, request/response shape, and a
per-subsystem diff. 315 defects catalogued; the ones fixed here are listed
in its "Already fixed" table.
Path coverage was never the problem — 465 of 506 routes already had
handlers. The failures were in shape, and they cluster into four causes:
- Wrong verb. The verb is a BestHTTP.HTTPMethods ordinal (GET=0 .. PATCH=5),
confirmed from that enum's static constructor. Routes registered POST-only
while the client PUTs returned 405, which made room consumables neither
buyable nor consumable and blocked every room-key edit.
- Bare scalar wrapped in an object. The client reads `1000`, not
`{"Limit":1000}`; the issuing method signature says which. Wrapping makes
the deserializer throw and the feature dies silently.
- [FromBody] vs form-urlencoded. The client sends nearly every write as form
data, which an [ApiController] action bound [FromBody] rejects with 415
before the handler runs. This alone broke all 13 club member-management
endpoints. Adds Binding/FormOrJsonModelBinder so this is fixed once.
- Notify dispatch keys. Both enum overloads of the client's RegisterHandler
lower the id via Int32.ToString() and register only that numeric key, and
lookup is a case-sensitive TryGetValue that returns silently on a miss. We
were sending the enum NAME for most ids, so friend-request updates, forced
logout, maintenance broadcasts, live balance and consumable updates, and
invention moderation pushes all evaporated with no error anywhere.
Notable behavioural bugs fixed:
- Editing a club announcement deleted it: PUT was a third binding on the
delete handler. Split apart, and the missing create route added.
- leaderboard/CheckAndSetStat did not exist. The 2023 client has no SetStat
literal at all, so every leaderboard score it wrote was discarded.
- Setting a club clubhouse cleared it: the handler read roomId from the query
while the client sends it in the body, then wrote the resulting null.
- Club join requests were inverted (the enum is Open=0, InviteOnly=1,
AskToJoin=2), so ask-to-join clubs rejected everyone and invite-only clubs
quietly admitted them.
- Room bans were pushed as id 24, for which the client registers no handler;
they now go out as ModerationKick with IsBan, so the ban takes effect
immediately instead of at next login.
- Room-key ownership queries answered for the wrong player, and "has anyone
bought this key" asked "did I buy it" — always false for the creator.
Also persists settings that were previously acknowledged and dropped
(playlist accessibility/restrictions/level-voting/warning, per-player status
visibility, VR movement mode and avoid-juniors, custom room codes), which is
what the new columns in the migration are for.
One test asserted the old nested PriceAndCurrency response shape; the
client's consumable formatter has no such key and reads Price and
PurchaseCurrencyId flat, so the test was corrected alongside the handler.
- Updated `url-coverage.md` to clarify the behavior of the `api/rooms/v2/myRecent` endpoint.
- Enhanced `StoreService.cs` to include new properties for color variants: `combination_id` and `descriptor`.
- Modified logic in `StoreService` to validate color variants based on the new descriptor instead of swatch GUID.
- Updated database bootstrap scripts to create new tables for `RoomConsumables` and `RoomConsumableOwnership`, including necessary indexes.
- Revised README to reflect changes in debugging options and the introduction of `DorkNet.DebugMod`.
- Updated documentation on request expectations to clarify server-side behavior for room visibility.
- Enhanced installation script to provide clearer instructions for enabling the debug console.
- Added a new document detailing the process for dumping avatar items and color variants from the Rec Room client.
* feat: add 3D Charades word lists management and profanity filter toggle
- Implemented Charades word lists management in the admin UI, allowing for unlimited named word lists with difficulty settings.
- Added functionality to bind live card slots to specific word lists, with automatic fallback to built-in lists.
- Introduced a profanity filter toggle in server settings, enabling or disabling the server-side profanity filter.
- Updated database schema to support new features, including additional columns for profanity filter status and charades slot bindings.
- Enhanced documentation to reflect new features and their usage.
* feat: add identityserver-signing.pfx to .gitignore
* feat: add new matchmake routes for player, event, club, and code
- Implemented new endpoints for retrieving account privacy settings.
- Added fields for privacy preferences such as profile visibility, online status, and activity visibility.
feat: Extend play menu tags functionality
- Updated PlayMenuTagsRequest to include TrendingTags.
- Modified SetPlayMenuTags to handle trending tags.
- Enhanced logging to include trending tags.
fix: Increase maximum archive size for room zip imports
- Updated MaxArchiveBytes from 12GB to 25GB in RoomZipImportController.
feat: Improve CDN image handling
- Added local image path resolution for room images.
- Implemented lazy loading of room image aliases from JSON file.
feat: Enhance match player presence resolution
- Updated ResolveDataBlobForPresenceAsync to consider sub-room IDs and private instance status.
feat: Extend RoomEntity with new properties
- Added AllowNewUsers, MinLevel, MaxPlayerCalculationMode, LoadScreensJson, PromoImagesJson, and PromoExternalContentJson fields.
feat: Update database schema for new room properties
- Added new columns to the Rooms table for AllowNewUsers, MinLevel, MaxPlayerCalculationMode, LoadScreensJson, PromoImagesJson, and PromoExternalContentJson.
feat: Implement platform notifications controller
- Created PlatformNotificationsController for managing user notification preferences.
- Added endpoints for retrieving and setting notification preferences and categories.
- Added support for .assetbundle files in RoomZipImportController.
- Introduced new properties in RoomSceneEntity for handling Studio asset metadata.
- Updated ZipImport method to handle asset bundles during bulk imports.
- Enhanced CdnController to serve Unity asset bundles via a new route.
- Modified GoToController to include Unity asset ID in matchmaking responses.
- Updated database schema to accommodate new fields related to Studio asset bundles.
- Improved URL coverage documentation to reflect new routes for asset bundles.
- Implemented ProgressionEventsController to handle progression event retrieval and active events.
- Created RoomConsumablesController for listing and purchasing room consumables.
- Developed RoomCurrenciesController for managing room currencies, including creation, updates, and balance retrieval.
- Added RoomEarningsDistributionsController to fetch earnings distribution data for rooms.
- Introduced ScreenShareReportsController for reporting screen share incidents.
- Established SubscriptionSeasonsController to provide current subscription season details and rewards.
- Launched UgcPurchasablesController for managing user-generated content purchasables, including bulk operations.
- Added new data entities for customization and room economy, including custom avatar items, room currencies, and UGC purchasables.
- Added MaxCapacity property to RoomEntity and updated related controllers to utilize it.
- Modified RoomsController to set MaxPlayers based on room's MaxCapacity.
- Introduced QuestTeamSize class to dynamically adjust quest party sizes beyond the default limit.
- Updated DevMenu to include options for debugging and managing room settings.
- Created UI elements for adjusting MaxCapacity in the admin interface.
- Added configuration file for DevMenu with default settings.
While account creation is disabled, the only way in is now an
admin-issued single-use signup code (Discord-invite style), redeemed on
the public site's /join page.
Because the 2020 watch login is device-id-bound with no code field, the
flow captures it server-side instead: a new device refused at the
signups-disabled gate (PlatformLogin / account create) is stashed in a
PendingDevices table keyed by the real client IP (CF-Connecting-IP aware).
The /join page then shows the player the device their own client just
reported, they enter their code + username, and the account is minted
bound to that device — so the next launch logs straight in via the
existing device-id path. No watch changes.
- SignupCodeEntity (code, descriptor, optional expiry, redeemer) +
PendingDeviceEntity; idempotent CREATE TABLE in DatabaseBootstrap so
both providers pick them up without a new migration.
- SignupCodeService: generate / list / revoke / redeem + pending-device
capture, single-use + expiry + revoke validation.
- Admin: GET/POST signup-codes + revoke endpoints and a Signup codes
admin-ui page (generate with descriptor/expiry, status table, revoke).
- Public: anonymous /api/site/v1/join pending-devices + redeem, and a
/join site page (+ header link).
- README documents the flow + the post-Initial table-create approach.
Targets Rec Room 2020.12.18 client.
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 the dorknet-clientpatch-{key}.zip
Release asset the launcher fetches.
- .github/workflows/release.yml — auto-publishes both Release assets
on v1-december-* tag push.
Scrubbed via maintainer-side scrub-for-public.ps1: same drop rules as
the prior import, plus build-patcher-zip.ps1 added to the tools/
allow-list so it survives the scrub.