From b26ae930141a31c4b47ffb65858191d1a3f94bad Mon Sep 17 00:00:00 2001 From: Alexa <53471801+Alexa-RR@users.noreply.github.com> Date: Sun, 31 May 2026 15:32:16 +0300 Subject: [PATCH] inventions: resolve real creator ids for a room (creatorIds) api/inventions/v1/creatorIds was a stub returning an empty list, so the 2020.03 watch's GetCreatorIdsOfInventionsInRoom never learned which creators it must request invention permissions for before spawning a room's invention-based geometry. Resolve the real set from InventionEntity.CreationRoomId via a shared ResolveRoomInventionsAsync helper: direct matches (created in-place) unioned with the imported cluster (most-frequent non-local CreationRoomId among the room creator's inventions, since zip-imported inventions keep their original Rec Room room id). Returns List of distinct creator account ids. --- .../API/Inventions/InventionsController.cs | 55 +++++++++++++++++-- DorkNet.Server/Data/url-coverage.md | 2 +- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/DorkNet.Server/Controllers/API/Inventions/InventionsController.cs b/DorkNet.Server/Controllers/API/Inventions/InventionsController.cs index 4b671ea..8a4d0bf 100644 --- a/DorkNet.Server/Controllers/API/Inventions/InventionsController.cs +++ b/DorkNet.Server/Controllers/API/Inventions/InventionsController.cs @@ -165,13 +165,58 @@ public class InventionsController( }); } + /// GET api/inventions/v1/creatorIds — the distinct + /// creator account ids of every invention placed in a room + /// (GetCreatorIdsOfInventionsInRoom, called by the 2020.03 + /// watch on room load). It uses these to resolve which creators it + /// must request invention permissions for before spawning a room's + /// invention-based geometry. Returns List<int> — empty + /// when the room has no tracked inventions. [HttpGet("api/inventions/v1/creatorIds")] - public IActionResult CreatorIdsInRoom([FromQuery] long roomId) + public async Task CreatorIdsInRoom([FromQuery] long roomId) { - // We don't yet track per-room invention placements; return - // empty list (correct shape: List). - _ = roomId; - return Ok(Array.Empty()); + var inventions = await ResolveRoomInventionsAsync(roomId); + var creatorIds = inventions + .Select(i => (int)i.CreatorPlayerId) + .Distinct() + .ToList(); + return Ok(creatorIds); + } + + /// Resolve the inventions that belong to a room. Direct + /// matches are inventions whose + /// equals the room's + /// local id (RR-Originals, dorms, anything created in-place). + /// Zip-imported rooms instead carry each invention's ORIGINAL Rec + /// Room CreationRoomId, which won't equal our local id and can't be + /// reverse-resolved without an OriginalRoomId column; we approximate + /// that cluster as the most-frequent non-local CreationRoomId among + /// the room creator's inventions. The two sets are unioned so a room + /// with both kinds resolves fully. + private async Task> ResolveRoomInventionsAsync(long roomId) + { + var creatorId = await db.Rooms + .Where(r => r.Id == roomId) + .Select(r => (long?)r.CreatorPlayerId) + .FirstOrDefaultAsync(); + + long? importedRoomId = null; + if (creatorId is long creator) + { + importedRoomId = await db.Inventions + .Where(i => !i.IsDeleted && i.CreatorPlayerId == creator + && i.CreationRoomId != null && i.CreationRoomId != roomId) + .GroupBy(i => i.CreationRoomId) + .OrderByDescending(g => g.Count()) + .Select(g => g.Key) + .FirstOrDefaultAsync(); + } + + return await db.Inventions + .Where(i => !i.IsDeleted + && (i.CreationRoomId == roomId + || (importedRoomId != null && i.CreationRoomId == importedRoomId))) + .ToListAsync(); } // ── Single fetch ───────────────────────────────────────────────────── diff --git a/DorkNet.Server/Data/url-coverage.md b/DorkNet.Server/Data/url-coverage.md index 8e5af34..5309384 100644 --- a/DorkNet.Server/Data/url-coverage.md +++ b/DorkNet.Server/Data/url-coverage.md @@ -140,7 +140,7 @@ Note: counts are approximate because several client URLs (`api/avatar/v3/saved`, | POST | `api/inventions/v1/batch` | REAL | `InventionsController.Batch` — bulk-fetch inventions by id list, returns multi-row payload | | GET | `api/inventions/v1/details` | REAL | `InventionsController.Details` — extended invention payload with version/creator metadata | | GET | `api/inventions/v1/versions` | REAL | `InventionsController.Versions` — list of `InventionVersionEntity` rows for an invention | -| GET | `api/inventions/v1/creatorIds` | REAL | `InventionsController.CreatorIds` — list of distinct creator player ids over the matching invention set | +| GET | `api/inventions/v1/creatorIds` | REAL | `InventionsController.CreatorIdsInRoom` — distinct creator account ids of the inventions placed in the room, resolved via `InventionEntity.CreationRoomId` (direct + imported-cluster). `List` | | GET | `api/inventions/v1/tagfilters` | REAL | `InventionsController.TagFilters` — returns the curated tag-filter set (currently empty list, but registered as a real handler) | | GET | `api/inventions/v1/delete` | REAL | `InventionsController.Delete` — soft-deletes an invention the caller owns | | GET | `api/inventions/v2/publish` | REAL | `InventionsController.PublishV2` — flips `IsPublished=true`, sets `FirstPublishedAt` |