openvibers/openvibe.games Commits
Remove the last persistence helpers only account merge used (#376)
Changes
@@@ -66,7 +66,7 @@ reads the game's board on OpenVibe.Play (below): 25 entries per page (`rank`, `nbearer or `X-Guest-Token` used by the ticket endpoint. Public reads have per-address limits.The read-only `/leaderboard.html` page shows Salvage Rush's best round scores and Scraplandia's summed haul points, switchable in the page, all time or this week (from Monday 00:00 UTC), 25 a page.Network account exports include results, best scores, unlocks and hauls; account erasure removes them.--Guest character adoption and Network subject merges move progression (including hauls) to the surviving subject.++Guest character adoption moves progression (including hauls) to the surviving subject.## Creator worlds@@@ -105,7 +105,7 @@ five (`GAMES_CREATOR_WORLDS_PER_PERSON`). A world is made at `/worlds`, built in`/worlds?join=<token>`, the token kept only as its hash, good for 7 days until stopped or replaced; migration 0015).Editors save the world's map and scripts and try its draft; the owner alone publishes, renames, deletes and runs theteam (`GET /api/worlds/:id/team`, `DELETE /api/worlds/:id/team/:subject`, an editor leaves with `…/team/me`).-- Two saves at once are still told apart by the map's revision (409). Team places follow account export, merge and++ Two saves at once are still told apart by the map's revision (409). Team places follow account export anddeletion. `/api/worlds/mine` lists them as `team`.- **Official examples:** two published worlds show what the editor can do — **Beacon Hill** (sculpted terrain, abeacon, a path, lights and three zones) and **The Workshop** (a walk-in shed, benches, props, resource nodes and@@@ -124,7 +124,7 @@ five (`GAMES_CREATOR_WORLDS_PER_PERSON`). A world is made at `/worlds`, built inscript adds it to the world's scripts, renamed `…-2` when the name is taken, within the world's four. A use countsonce per person (`POST /api/assets/:id/use`; never the creator's own). The creator renames or deletes an asset(worlds keep their copy); staff take one down (`asset.hidden`, `asset.restored`, `asset.deleted` as-- `games.moderation.action`). Assets and uses follow account export, merge and deletion. Uploaded models, textures++ `games.moderation.action`). Assets and uses follow account export and deletion. Uploaded models, texturesand sounds wait for the Pics safety pipeline, and paid assets for the owner's prices.- **View (2D):** the owner shows a world in first person (`3d`, the default) or **top-down** (`top`, migration 0017;`PATCH /api/worlds/:id {view}`, `/worlds` → **Switch to top-down**). Top-down looks straight down on the player with an@@@ -17,7 +17,6 @@ export {removeWorldPlaces,exportCreatorWorlds,eraseCreatorWorlds,-- moveCreatorWorlds,type CreatorWorld,type CreatorWorldStatus,type CreatorWorldStore,@@@ -27,7 +26,6 @@ export {createCreatorAssetStore,exportCreatorAssets,eraseCreatorAssets,-- moveCreatorAssets,type CreatorAsset,type CreatorAssetKind,type CreatorAssetStatus,@@@ -194,35 +194,3 @@ export async function eraseCreatorAssets(db: Db, subjects: readonly string[]): Pawait db.exec(sql`DELETE FROM creator_asset_uses WHERE subject IN (${idList(subjects)})`)return db.exec(sql`DELETE FROM creator_assets WHERE owner_subject IN (${idList(subjects)})`)}----/**-- * Account merge (ADR-029): the folded-in account's assets belong to the survivor, and so do its uses (one per asset;-- * none on the survivor's own assets, which never count their creator).-- */--export async function moveCreatorAssets(db: Db, from: string, into: string): Promise<number> {-- if (from === into) return 0-- const moved = await db.exec(-- sql`UPDATE creator_assets SET owner_subject = ${into} WHERE owner_subject = ${from}`,-- )-- const touched = (-- await db.many<{ asset_id: string }>(-- sql`SELECT asset_id FROM creator_asset_uses WHERE subject = ${from}`,-- )-- ).map((r) => r.asset_id)-- await db.exec(sql`-- UPDATE creator_asset_uses u SET subject = ${into}-- WHERE u.subject = ${from}-- AND NOT EXISTS (SELECT 1 FROM creator_asset_uses o WHERE o.asset_id = u.asset_id AND o.subject = ${into})-- `)-- await db.exec(sql`DELETE FROM creator_asset_uses WHERE subject = ${from}`)-- await db.exec(sql`-- DELETE FROM creator_asset_uses u USING creator_assets a-- WHERE u.asset_id = a.id AND u.subject = a.owner_subject-- `)-- // Two uses that became one, or a use of what is now one's own, no longer count.-- await db.exec(sql`-- UPDATE creator_assets a SET uses = (SELECT count(*)::int FROM creator_asset_uses u WHERE u.asset_id = a.id)-- WHERE a.owner_subject = ${into}${touched.length ? sql` OR a.id IN (${idList(touched)})` : sql``}-- `)-- return moved--}@@@ -384,25 +384,3 @@ export async function eraseCreatorWorlds(db: Db, subjects: readonly string[]): Pawait removeWorldPlaces(db, ids)return ids.length}----/**-- * Account merge (ADR-029): the folded-in account's worlds belong to the survivor, and so do its team places (one per-- * world; none on a world the survivor now owns).-- */--export async function moveCreatorWorlds(db: Db, from: string, into: string): Promise<number> {-- if (from === into) return 0-- const moved = await db.exec(-- sql`UPDATE creator_worlds SET owner_subject = ${into} WHERE owner_subject = ${from}`,-- )-- await db.exec(sql`-- UPDATE creator_world_members m SET subject = ${into}-- WHERE m.subject = ${from}-- AND NOT EXISTS (SELECT 1 FROM creator_world_members o WHERE o.world_id = m.world_id AND o.subject = ${into})-- `)-- await db.exec(sql`DELETE FROM creator_world_members WHERE subject = ${from}`)-- await db.exec(sql`-- DELETE FROM creator_world_members m USING creator_worlds w-- WHERE m.world_id = w.id AND m.subject = w.owner_subject-- `)-- return moved--}
@@ -66,7 +66,7 @@ reads the game's board on OpenVibe.Play (below): 25 entries per page (`rank`, `n
@@ -66,7 +66,7 @@ reads the game's board on OpenVibe.Play (below): 25 entries per page (`rank`, `n
bearer or `X-Guest-Token` used by the ticket endpoint. Public reads have per-address limits.
bearer or `X-Guest-Token` used by the ticket endpoint. Public reads have per-address limits.
The read-only `/leaderboard.html` page shows Salvage Rush's best round scores and Scraplandia's summed haul points, switchable in the page, all time or this week (from Monday 00:00 UTC), 25 a page.
The read-only `/leaderboard.html` page shows Salvage Rush's best round scores and Scraplandia's summed haul points, switchable in the page, all time or this week (from Monday 00:00 UTC), 25 a page.
Network account exports include results, best scores, unlocks and hauls; account erasure removes them.
Network account exports include results, best scores, unlocks and hauls; account erasure removes them.
-Guest character adoption and Network subject merges move progression (including hauls) to the surviving subject.
+Guest character adoption moves progression (including hauls) to the surviving subject.
## Creator worlds
## Creator worlds
@@ -105,7 +105,7 @@ five (`GAMES_CREATOR_WORLDS_PER_PERSON`). A world is made at `/worlds`, built in
@@ -105,7 +105,7 @@ five (`GAMES_CREATOR_WORLDS_PER_PERSON`). A world is made at `/worlds`, built in
`/worlds?join=<token>`, the token kept only as its hash, good for 7 days until stopped or replaced; migration 0015).
`/worlds?join=<token>`, the token kept only as its hash, good for 7 days until stopped or replaced; migration 0015).
Editors save the world's map and scripts and try its draft; the owner alone publishes, renames, deletes and runs the
Editors save the world's map and scripts and try its draft; the owner alone publishes, renames, deletes and runs the
team (`GET /api/worlds/:id/team`, `DELETE /api/worlds/:id/team/:subject`, an editor leaves with `…/team/me`).
team (`GET /api/worlds/:id/team`, `DELETE /api/worlds/:id/team/:subject`, an editor leaves with `…/team/me`).
- Two saves at once are still told apart by the map's revision (409). Team places follow account export, merge and
+ Two saves at once are still told apart by the map's revision (409). Team places follow account export and
deletion. `/api/worlds/mine` lists them as `team`.
deletion. `/api/worlds/mine` lists them as `team`.
- **Official examples:** two published worlds show what the editor can do — **Beacon Hill** (sculpted terrain, a
- **Official examples:** two published worlds show what the editor can do — **Beacon Hill** (sculpted terrain, a
beacon, a path, lights and three zones) and **The Workshop** (a walk-in shed, benches, props, resource nodes and
beacon, a path, lights and three zones) and **The Workshop** (a walk-in shed, benches, props, resource nodes and
@@ -124,7 +124,7 @@ five (`GAMES_CREATOR_WORLDS_PER_PERSON`). A world is made at `/worlds`, built in
@@ -124,7 +124,7 @@ five (`GAMES_CREATOR_WORLDS_PER_PERSON`). A world is made at `/worlds`, built in
script adds it to the world's scripts, renamed `…-2` when the name is taken, within the world's four. A use counts
script adds it to the world's scripts, renamed `…-2` when the name is taken, within the world's four. A use counts
once per person (`POST /api/assets/:id/use`; never the creator's own). The creator renames or deletes an asset
once per person (`POST /api/assets/:id/use`; never the creator's own). The creator renames or deletes an asset
(worlds keep their copy); staff take one down (`asset.hidden`, `asset.restored`, `asset.deleted` as
(worlds keep their copy); staff take one down (`asset.hidden`, `asset.restored`, `asset.deleted` as
- `games.moderation.action`). Assets and uses follow account export, merge and deletion. Uploaded models, textures
+ `games.moderation.action`). Assets and uses follow account export and deletion. Uploaded models, textures
and sounds wait for the Pics safety pipeline, and paid assets for the owner's prices.
and sounds wait for the Pics safety pipeline, and paid assets for the owner's prices.
- **View (2D):** the owner shows a world in first person (`3d`, the default) or **top-down** (`top`, migration 0017;
- **View (2D):** the owner shows a world in first person (`3d`, the default) or **top-down** (`top`, migration 0017;
`PATCH /api/worlds/:id {view}`, `/worlds` → **Switch to top-down**). Top-down looks straight down on the player with an
`PATCH /api/worlds/:id {view}`, `/worlds` → **Switch to top-down**). Top-down looks straight down on the player with an
@@ -17,7 +17,6 @@ export {
@@ -17,7 +17,6 @@ export {
removeWorldPlaces,
removeWorldPlaces,
exportCreatorWorlds,
exportCreatorWorlds,
eraseCreatorWorlds,
eraseCreatorWorlds,
- moveCreatorWorlds,
type CreatorWorld,
type CreatorWorld,
type CreatorWorldStatus,
type CreatorWorldStatus,
type CreatorWorldStore,
type CreatorWorldStore,
@@ -27,7 +26,6 @@ export {
@@ -27,7 +26,6 @@ export {
createCreatorAssetStore,
createCreatorAssetStore,
exportCreatorAssets,
exportCreatorAssets,
eraseCreatorAssets,
eraseCreatorAssets,
- moveCreatorAssets,
type CreatorAsset,
type CreatorAsset,
type CreatorAssetKind,
type CreatorAssetKind,
type CreatorAssetStatus,
type CreatorAssetStatus,
@@ -194,35 +194,3 @@ export async function eraseCreatorAssets(db: Db, subjects: readonly string[]): P
@@ -194,35 +194,3 @@ export async function eraseCreatorAssets(db: Db, subjects: readonly string[]): P
await db.exec(sql`DELETE FROM creator_asset_uses WHERE subject IN (${idList(subjects)})`)
await db.exec(sql`DELETE FROM creator_asset_uses WHERE subject IN (${idList(subjects)})`)
return db.exec(sql`DELETE FROM creator_assets WHERE owner_subject IN (${idList(subjects)})`)
return db.exec(sql`DELETE FROM creator_assets WHERE owner_subject IN (${idList(subjects)})`)
}
}
-
-/**
- * Account merge (ADR-029): the folded-in account's assets belong to the survivor, and so do its uses (one per asset;
- * none on the survivor's own assets, which never count their creator).
- */
-export async function moveCreatorAssets(db: Db, from: string, into: string): Promise<number> {
- if (from === into) return 0
- const moved = await db.exec(
- sql`UPDATE creator_assets SET owner_subject = ${into} WHERE owner_subject = ${from}`,
- )
- const touched = (
- await db.many<{ asset_id: string }>(
- sql`SELECT asset_id FROM creator_asset_uses WHERE subject = ${from}`,
- )
- ).map((r) => r.asset_id)
- await db.exec(sql`
- UPDATE creator_asset_uses u SET subject = ${into}
- WHERE u.subject = ${from}
- AND NOT EXISTS (SELECT 1 FROM creator_asset_uses o WHERE o.asset_id = u.asset_id AND o.subject = ${into})
- `)
- await db.exec(sql`DELETE FROM creator_asset_uses WHERE subject = ${from}`)
- await db.exec(sql`
- DELETE FROM creator_asset_uses u USING creator_assets a
- WHERE u.asset_id = a.id AND u.subject = a.owner_subject
- `)
- // Two uses that became one, or a use of what is now one's own, no longer count.
- await db.exec(sql`
- UPDATE creator_assets a SET uses = (SELECT count(*)::int FROM creator_asset_uses u WHERE u.asset_id = a.id)
- WHERE a.owner_subject = ${into}${touched.length ? sql` OR a.id IN (${idList(touched)})` : sql``}
- `)
- return moved
-}
@@ -384,25 +384,3 @@ export async function eraseCreatorWorlds(db: Db, subjects: readonly string[]): P
@@ -384,25 +384,3 @@ export async function eraseCreatorWorlds(db: Db, subjects: readonly string[]): P
await removeWorldPlaces(db, ids)
await removeWorldPlaces(db, ids)
return ids.length
return ids.length
}
}
-
-/**
- * Account merge (ADR-029): the folded-in account's worlds belong to the survivor, and so do its team places (one per
- * world; none on a world the survivor now owns).
- */
-export async function moveCreatorWorlds(db: Db, from: string, into: string): Promise<number> {
- if (from === into) return 0
- const moved = await db.exec(
- sql`UPDATE creator_worlds SET owner_subject = ${into} WHERE owner_subject = ${from}`,
- )
- await db.exec(sql`
- UPDATE creator_world_members m SET subject = ${into}
- WHERE m.subject = ${from}
- AND NOT EXISTS (SELECT 1 FROM creator_world_members o WHERE o.world_id = m.world_id AND o.subject = ${into})
- `)
- await db.exec(sql`DELETE FROM creator_world_members WHERE subject = ${from}`)
- await db.exec(sql`
- DELETE FROM creator_world_members m USING creator_worlds w
- WHERE m.world_id = w.id AND m.subject = w.owner_subject
- `)
- return moved
-}