From 81fe3dcf286740aed6f582ca63685693c3875a7e Mon Sep 17 00:00:00 2001 From: kdletters <61648117+kdletters@users.noreply.github.com> Date: Sun, 17 May 2026 01:19:12 +0800 Subject: [PATCH] perf: cache public gallery views --- .hermes/shared-memory/decision-log.md | 3 +- .hermes/shared-memory/pitfalls.md | 8 + ...】前端直订阅公开作品列表准入待办-2026-05-16.md | 27 ++ ...】server-rs与SpacetimeDB数据契约-2026-05-15.md | 39 +++ ...发运维】本地开发验证与生产运维-2026-05-15.md | 2 +- .../crates/spacetime-client/src/big_fish.rs | 28 +- server-rs/crates/spacetime-client/src/lib.rs | 8 + .../crates/spacetime-client/src/mapper.rs | 259 +++++++++++++++++ .../crates/spacetime-client/src/match3d.rs | 20 +- .../big_fish_creation_session_type.rs | 2 + .../big_fish_gallery_view_table.rs | 114 ++++++++ .../big_fish_work_summary_snapshot_type.rs | 97 +++++++ .../match_3_d_gallery_view_row_type.rs | 98 +++++++ .../match_3_d_gallery_view_table.rs | 113 ++++++++ .../src/module_bindings/mod.rs | 130 ++++++++- .../puzzle_anchor_item_type.rs | 20 ++ .../puzzle_anchor_pack_type.rs | 21 ++ .../puzzle_anchor_status_type.rs | 22 ++ .../puzzle_audio_asset_type.rs | 22 ++ .../puzzle_draft_level_type.rs | 30 ++ .../puzzle_gallery_view_table.rs | 264 +----------------- .../puzzle_generated_image_candidate_type.rs | 21 ++ .../puzzle_work_profile_type.rs | 119 ++++++++ .../square_hole_gallery_view_row_type.rs | 108 +++++++ .../square_hole_gallery_view_table.rs | 116 ++++++++ .../square_hole_hole_option_snapshot_type.rs | 19 ++ .../square_hole_shape_option_snapshot_type.rs | 20 ++ .../visual_novel_gallery_view_row_type.rs | 82 ++++++ .../visual_novel_gallery_view_table.rs | 117 ++++++++ .../crates/spacetime-client/src/puzzle.rs | 2 +- .../spacetime-client/src/square_hole.rs | 20 +- .../spacetime-client/src/visual_novel.rs | 26 +- .../spacetime-module/src/big_fish/session.rs | 157 ++++++++++- .../spacetime-module/src/big_fish/tables.rs | 3 +- .../spacetime-module/src/match3d/mod.rs | 88 +++++- .../crates/spacetime-module/src/puzzle.rs | 24 +- .../spacetime-module/src/square_hole/mod.rs | 91 ++++++ .../spacetime-module/src/square_hole/types.rs | 4 +- .../spacetime-module/src/visual_novel.rs | 78 ++++++ 39 files changed, 2124 insertions(+), 298 deletions(-) create mode 100644 .hermes/todos/【后端架构】前端直订阅公开作品列表准入待办-2026-05-16.md create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/big_fish_gallery_view_table.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/big_fish_work_summary_snapshot_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/match_3_d_gallery_view_row_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/match_3_d_gallery_view_table.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/puzzle_anchor_item_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/puzzle_anchor_pack_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/puzzle_anchor_status_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/puzzle_audio_asset_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/puzzle_draft_level_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/puzzle_generated_image_candidate_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/puzzle_work_profile_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/square_hole_gallery_view_row_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/square_hole_gallery_view_table.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/square_hole_hole_option_snapshot_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/square_hole_shape_option_snapshot_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/visual_novel_gallery_view_row_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/visual_novel_gallery_view_table.rs diff --git a/.hermes/shared-memory/decision-log.md b/.hermes/shared-memory/decision-log.md index d5a10fa2..478a9bb7 100644 --- a/.hermes/shared-memory/decision-log.md +++ b/.hermes/shared-memory/decision-log.md @@ -20,7 +20,8 @@ - 背景:作品列表压测和实时性讨论中,曾考虑让浏览器前端直接订阅公开作品列表,减少 HTTP 拉取和 BFF 压力。 - 决策:本轮不直接把作品列表整体交给前端订阅。短期继续由 `api-server` / BFF 通过 `spacetime-client` 长期订阅 SpacetimeDB 公开 read model 并读取本地 cache,维持首屏、排序、字段归一、权限降级和 HTTP fallback。中期可以新增或统一稳定的专用公开作品列表 read model,例如 `public_work_gallery_entry`,作为前端可选直连订阅对象。 -- 边界:前端不得直接订阅 `puzzle_work_profile`、`custom_world_profile` 等领域源表,也不得在前端自行 join、聚合或执行公开权限逻辑;这些逻辑必须先沉到后端投影 / read model。 +- 边界:未来前端直订阅只允许面向稳定、低基数、公开的专用 read model。前端不得直接订阅 `puzzle_work_profile`、`custom_world_profile` 等领域源表,也不得在前端自行 join、聚合或执行公开权限逻辑;这些逻辑必须先沉到后端投影 / read model。 +- 后续准入:若要落地前端直订阅,必须先完成并验收权限边界、字段契约、排序 / 分页、埋点和 BFF 回退策略;缺任一项时继续走 `api-server` / BFF 订阅缓存方案。 - 影响范围:发现页、推荐流、各玩法公开广场、`api-server` 公开列表缓存、SpacetimeDB public view / public 读模型设计。 - 验证方式:新增公开作品列表订阅能力时,检查前端只消费专用 public read model 或 BFF HTTP DTO;检查源表 row shape、权限判断和跨玩法聚合没有下沉到前端页面。 - 关联文档:`docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md`、`docs/【开发运维】本地开发验证与生产运维-2026-05-15.md`。 diff --git a/.hermes/shared-memory/pitfalls.md b/.hermes/shared-memory/pitfalls.md index ad65ed19..6258385c 100644 --- a/.hermes/shared-memory/pitfalls.md +++ b/.hermes/shared-memory/pitfalls.md @@ -99,6 +99,14 @@ - 验证:搜索 `server-rs/crates/spacetime-client/src/puzzle.rs` 不应再出现 gallery 主路径调用 `list_puzzle_gallery_then`;执行 `cargo check --manifest-path server-rs/Cargo.toml -p spacetime-client`、`cargo check --manifest-path server-rs/Cargo.toml -p api-server` 和 schema/runtime access 检查。 - 关联:`server-rs/crates/spacetime-module/src/puzzle.rs`、`server-rs/crates/spacetime-client/src/lib.rs`、`server-rs/crates/spacetime-client/src/puzzle.rs`、`/api/runtime/puzzle/gallery`。 +## 多玩法公开广场列表优先订阅 public view / read model + +- 现象:抓大鹅、方洞挑战、视觉小说、大鱼吃小鱼等公开列表如果沿用 `list_*_works` procedure,即使只读已发布作品,也会在每个 HTTP 请求里回到 SpacetimeDB WASM 侧扫描、反序列化配置并组装列表,50RPS 以上容易变成热点。 +- 原因:个人作品列表和公开广场列表复用了同一套 procedure 输入,导致公开列表为了通过 owner 校验传固定占位 owner,并把可长期同步的公开读模型当成请求期查询。 +- 处理:每个公开广场新增或复用专用 public view / public read model:`match_3_d_gallery_view`、`square_hole_gallery_view`、`visual_novel_gallery_view`、`big_fish_gallery_view`。`spacetime-client` 建连接后订阅这些 view 和对应 `public_work_play_daily_stat` source_type 桶,HTTP gallery 只读本地 cache。个人作品列表、详情、发布、点赞、游玩记录和 Remix 仍走原有 procedure / reducer。 +- 验证:搜索 `server-rs/crates/spacetime-client/src/{match3d,square_hole,visual_novel,big_fish}.rs`,公开 gallery 主路径应读取 `connection.db().*_gallery_view()`,不应调用 `list_*_works_with_input`;执行 `npm run spacetime:generate`、`cargo check -p spacetime-client --manifest-path server-rs/Cargo.toml`、`cargo check -p api-server --manifest-path server-rs/Cargo.toml`、`npm run check:spacetime-schema`。 +- 关联:`server-rs/crates/spacetime-module/src/match3d/mod.rs`、`server-rs/crates/spacetime-module/src/square_hole/mod.rs`、`server-rs/crates/spacetime-module/src/visual_novel.rs`、`server-rs/crates/spacetime-module/src/big_fish/session.rs`、`docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md`。 + ## 自定义世界广场和创作入口配置不要每次 HTTP 请求调用只读 procedure - 现象:`/api/runtime/custom-world-gallery` 每次请求调用 `list_custom_world_gallery_entries` procedure;入口熔断中间件每个玩法请求调用 `get_creation_entry_config` procedure,50RPS 以上会把 SpacetimeDB procedure 调用变成热点。 diff --git a/.hermes/todos/【后端架构】前端直订阅公开作品列表准入待办-2026-05-16.md b/.hermes/todos/【后端架构】前端直订阅公开作品列表准入待办-2026-05-16.md new file mode 100644 index 00000000..943d90e3 --- /dev/null +++ b/.hermes/todos/【后端架构】前端直订阅公开作品列表准入待办-2026-05-16.md @@ -0,0 +1,27 @@ +# 前端直订阅公开作品列表准入待办 + +## 背景 + +未来可以考虑让前端直接订阅公开作品列表,以减少列表读取链路中的 HTTP 往返,并复用 SpacetimeDB 的实时同步能力。 + +## 当前结论 + +短期仍由 `api-server` / BFF 订阅 SpacetimeDB public read model,并从本地 cache 读取后对外提供 HTTP 列表接口。前端不直接订阅作品源表,也不把正式列表排序、分页、权限裁剪逻辑下放到 UI。 + +## 落地前置条件 + +- 建立专用、稳定、低基数的 public read model,例如 `public_work_gallery_entry`。 +- 明确权限边界,只暴露公开列表所需字段,不泄露作者私有信息、审核内部状态或运营字段。 +- 固化字段契约,明确字段含义、默认值、兼容策略和生成绑定更新流程。 +- 明确排序与分页语义,避免依赖自增 ID 顺序,优先使用时间戳或显式排序字段。 +- 补齐埋点方案,能区分直订阅首屏、增量更新、分页加载和 fallback 命中。 +- 保留 BFF HTTP fallback,用于低版本客户端、订阅失败、权限策略调整和灰度回滚。 +- 禁止前端订阅 `puzzle_work_profile`、`custom_world_profile` 等作品源表。 + +## 建议验收 + +- 文档确认直订阅只面向专用 public read model,不绕过 BFF 读取源表。 +- schema、绑定、字段契约、排序分页和权限说明同步更新。 +- 前端具备订阅失败后的 BFF HTTP fallback。 +- 自动测试覆盖公开字段裁剪、排序分页稳定性和 fallback 路径。 +- 监控可观察直订阅成功率、首屏耗时、增量更新延迟和 fallback 比例。 diff --git a/docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md b/docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md index 85388efa..51f21b1b 100644 --- a/docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md +++ b/docs/【后端架构】server-rs与SpacetimeDB数据契约-2026-05-15.md @@ -243,6 +243,7 @@ npm run check:server-rs-ddd - Rust 结构体:`BigFishCreationSession` - 源码:`server-rs/crates/spacetime-module/src/big_fish/tables.rs` +- 索引:`by_big_fish_session_owner_user_id`、`by_big_fish_session_stage`。公开广场 view 使用 `by_big_fish_session_stage` 读取已发布会话,避免扫整表。 ### `big_fish_event` @@ -254,6 +255,13 @@ npm run check:server-rs-ddd - Rust 结构体:`BigFishRuntimeRun` - 源码:`server-rs/crates/spacetime-module/src/big_fish/tables.rs` +### SpacetimeDB view:`big_fish_gallery_view` + +- Rust view:`big_fish_gallery_view` +- 返回类型:`Vec` +- 源码:`server-rs/crates/spacetime-module/src/big_fish/session.rs` +- 说明:大鱼吃小鱼公开广场列表投影,只从 `Published` creation session 组装公开卡片字段;`api-server` 的 `spacetime-client` 长期订阅 `SELECT * FROM big_fish_gallery_view` 与 `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'big-fish'` 后,从本地 cache 构造 `/api/runtime/big-fish/gallery` 响应。公开列表不再每个 HTTP 请求调用 `list_big_fish_works` procedure;个人作品列表、详情、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。 + ### `chapter_progression` - Rust 结构体:`ChapterProgression` @@ -340,6 +348,13 @@ npm run check:server-rs-ddd - Rust 结构体:`Match3DWorkProfileRow` - 源码:`server-rs/crates/spacetime-module/src/match3d/tables.rs` +### SpacetimeDB view:`match_3_d_gallery_view` + +- Rust view:`match3d_gallery_view` +- 返回类型:`Vec` +- 源码:`server-rs/crates/spacetime-module/src/match3d/mod.rs` +- 说明:抓大鹅公开广场列表投影,只暴露 `publication_status = published` 的作品卡片字段;`api-server` 的 `spacetime-client` 长期订阅 `SELECT * FROM match_3_d_gallery_view` 与 `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'match3d'` 后,从本地 cache 构造 `/api/runtime/match3d/gallery` 响应。公开列表不再每个 HTTP 请求调用 `list_match3d_works` procedure;个人作品列表、详情、发布、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。 + ### `npc_state` - Rust 结构体:`NpcState` @@ -479,14 +494,24 @@ npm run check:server-rs-ddd - `SELECT * FROM puzzle_gallery_view` - `SELECT * FROM custom_world_gallery_entry` +- `SELECT * FROM match_3_d_gallery_view` +- `SELECT * FROM square_hole_gallery_view` +- `SELECT * FROM visual_novel_gallery_view` +- `SELECT * FROM big_fish_gallery_view` 下列订阅用于统计或配置缓存,订阅失败不会让公开列表连接整体不可用,调用方保留兼容兜底: - `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'puzzle'` - `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'custom-world'` +- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'match3d'` +- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'square-hole'` +- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'visual-novel'` +- `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'big-fish'` - `SELECT * FROM creation_entry_config` - `SELECT * FROM creation_entry_type_config` +拼图、自定义世界、抓大鹅、方洞挑战、视觉小说和大鱼吃小鱼的公开列表 HTTP 路由都从订阅 cache 读取公开 read model / view。各玩法的个人作品列表、详情、发布、点赞、游玩记录、Remix 和其它需要鉴权或写入副作用的路径继续走 procedure / reducer;不要为了公开列表性能把这些 owner-specific 或 mutation 语义混进 public view。 + `GET /api/creation-entry/config` 和入口熔断优先从订阅 cache 读取创作入口配置;cache 缺失时使用最近一次成功读取的内存快照,再兜底调用 `get_creation_entry_config` procedure 完成空库种子或旧库兼容。 未来可选:若发现页、推荐流和各玩法广场需要统一给浏览器前端直接订阅公开作品列表,只新增 / 统一专用 public read model,例如 `public_work_gallery_entry`。该 read model 必须是后端投影后的公开作品卡片契约,覆盖作品类型、公开作品号、标题、摘要、封面、作者展示名、排序键、公开统计和入口开关后的可见性,不暴露玩法领域源表 row shape。前端可选择订阅这个稳定投影来减少 HTTP 拉取,但不能订阅 `puzzle_work_profile`、`custom_world_profile` 等源表后自行拼装列表;BFF 仍保留首屏、SEO / 分享、旧客户端、订阅失败和灰度期间的 HTTP fallback。 @@ -536,6 +561,13 @@ npm run check:server-rs-ddd - Rust 结构体:`SquareHoleWorkProfileRow` - 源码:`server-rs/crates/spacetime-module/src/square_hole/tables.rs` +### SpacetimeDB view:`square_hole_gallery_view` + +- Rust view:`square_hole_gallery_view` +- 返回类型:`Vec` +- 源码:`server-rs/crates/spacetime-module/src/square_hole/mod.rs` +- 说明:方洞挑战公开广场列表投影,只暴露 `publication_status = published` 的作品卡片字段;`api-server` 的 `spacetime-client` 长期订阅 `SELECT * FROM square_hole_gallery_view` 与 `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'square-hole'` 后,从本地 cache 构造 `/api/runtime/square-hole/gallery` 响应。公开列表不再每个 HTTP 请求调用 `list_square_hole_works` procedure;个人作品列表、详情、发布、点赞、游玩记录和 Remix 仍按原有 procedure / reducer 路径处理。 + ### `story_event` - Rust 结构体:`StoryEvent` @@ -600,3 +632,10 @@ npm run check:server-rs-ddd - Rust 结构体:`VisualNovelWorkProfileRow` - 源码:`server-rs/crates/spacetime-module/src/visual_novel.rs` + +### SpacetimeDB view:`visual_novel_gallery_view` + +- Rust view:`visual_novel_gallery_view` +- 返回类型:`Vec` +- 源码:`server-rs/crates/spacetime-module/src/visual_novel.rs` +- 说明:视觉小说公开广场列表投影,只暴露 `publication_status = published` 的作品卡片字段,不把完整 `draft` 暴露给公开列表订阅;`api-server` 的 `spacetime-client` 长期订阅 `SELECT * FROM visual_novel_gallery_view` 与 `SELECT * FROM public_work_play_daily_stat WHERE source_type = 'visual-novel'` 后,从本地 cache 构造 `/api/runtime/visual-novel/gallery` 响应。公开列表不再每个 HTTP 请求调用 `list_visual_novel_works` procedure;个人历史、详情、运行态和发布仍按原有 procedure / reducer 路径处理。 diff --git a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md index ad890d24..f15f9b7e 100644 --- a/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md +++ b/docs/【开发运维】本地开发验证与生产运维-2026-05-15.md @@ -157,7 +157,7 @@ Jenkins 按 web / api / Spacetime module / build / deploy / publish 拆分 - `genarrative-api.service` 设置 `LimitNOFILE=65535`、`TasksMax=2048`;上线后用 `systemctl show genarrative-api.service -p LimitNOFILE -p TasksMax` 和 `cat /proc/$(pidof api-server)/limits` 核对。 - Nginx `/api/` 与 `/admin/api/` 通过 `genarrative_api` upstream 代理到 `127.0.0.1:8082`,upstream keepalive 为 64;压测时看 `/var/log/nginx/genarrative.access.log` 中的 `request_time`、`upstream_connect_time`、`upstream_header_time`、`upstream_response_time`、`upstream_status`、`request_id`。 - 作品列表 K6 脚本一次 iteration 默认请求两个公开接口,因此约 50 HTTP req/s 的目标命令使用 `SCENARIO=spike START_RPS=5 PEAK_RPS=25 HOLD=60s END_RPS=5 DETAIL_RATIO=0 npm run loadtest:k6:works`。 -- 作品列表短期继续由 `api-server` / BFF 订阅 SpacetimeDB 公开 read model 后读本地 cache,不让浏览器前端直接订阅完整列表;未来如新增 `public_work_gallery_entry` 等专用公开作品列表 read model,前端只可订阅该稳定投影,不能订阅玩法源表后自行 join、聚合或判断权限。 +- 作品列表短期继续由 `api-server` / BFF 订阅 SpacetimeDB 公开 read model 后读本地 cache,不让浏览器前端直接订阅完整列表;未来如新增 `public_work_gallery_entry` 等专用公开作品列表 read model,前端只可订阅稳定、低基数、公开的专用投影,禁止订阅 `puzzle_work_profile`、`custom_world_profile` 等玩法源表后自行 join、聚合或判断权限。前端直订阅落地前必须先补齐权限、字段契约、排序 / 分页、埋点和 BFF 回退策略。 - 50 HTTP req/s 验收目标为 `http_req_failed < 1%`、`p95 < 2s`、`dropped_iterations = 0`,同时压测窗口内 Nginx 无新增 502。 OpenTelemetry 现阶段可选 OTLP traces / metrics / logs,但本地日志与 Nginx 文件日志仍保留: diff --git a/server-rs/crates/spacetime-client/src/big_fish.rs b/server-rs/crates/spacetime-client/src/big_fish.rs index 38c976b4..d9677e29 100644 --- a/server-rs/crates/spacetime-client/src/big_fish.rs +++ b/server-rs/crates/spacetime-client/src/big_fish.rs @@ -7,7 +7,6 @@ use crate::module_bindings::record_big_fish_play_procedure::record_big_fish_play use crate::module_bindings::remix_big_fish_work_procedure::remix_big_fish_work; use crate::module_bindings::start_big_fish_run_procedure::start_big_fish_run; use crate::module_bindings::submit_big_fish_input_procedure::submit_big_fish_input; -use module_big_fish::PUBLIC_BIG_FISH_GALLERY_OWNER_USER_ID; impl SpacetimeClient { pub async fn create_big_fish_session( @@ -75,10 +74,29 @@ impl SpacetimeClient { pub async fn list_big_fish_gallery( &self, ) -> Result, SpacetimeClientError> { - self.list_big_fish_works_with_input(BigFishWorksListInput { - // 中文注释:公开广场读取只依赖 published_only,但旧部署模块会先校验 owner_user_id 非空。 - owner_user_id: PUBLIC_BIG_FISH_GALLERY_OWNER_USER_ID.to_string(), - published_only: true, + self.read_after_connect(move |connection| { + let recent_play_counts = public_work_recent_play_counts(connection, "big-fish"); + let mut items = connection + .db() + .big_fish_gallery_view() + .iter() + .collect::>(); + items.sort_by(|left, right| { + right + .updated_at_micros + .cmp(&left.updated_at_micros) + .then_with(|| left.source_session_id.cmp(&right.source_session_id)) + }); + Ok(items + .into_iter() + .map(|item| { + let recent_play_count_7d = recent_play_counts + .get(&item.source_session_id) + .copied() + .unwrap_or(0); + map_big_fish_gallery_view_row(item, recent_play_count_7d) + }) + .collect()) }) .await } diff --git a/server-rs/crates/spacetime-client/src/lib.rs b/server-rs/crates/spacetime-client/src/lib.rs index 4401f25f..08a17274 100644 --- a/server-rs/crates/spacetime-client/src/lib.rs +++ b/server-rs/crates/spacetime-client/src/lib.rs @@ -542,6 +542,10 @@ impl SpacetimeClient { for query in [ "SELECT * FROM puzzle_gallery_view", "SELECT * FROM custom_world_gallery_entry", + "SELECT * FROM match_3_d_gallery_view", + "SELECT * FROM square_hole_gallery_view", + "SELECT * FROM visual_novel_gallery_view", + "SELECT * FROM big_fish_gallery_view", ] { let subscription = self .subscribe_cached_read_model_query(connection, broken.clone(), query, true) @@ -552,6 +556,10 @@ impl SpacetimeClient { for query in [ "SELECT * FROM public_work_play_daily_stat WHERE source_type = 'puzzle'", "SELECT * FROM public_work_play_daily_stat WHERE source_type = 'custom-world'", + "SELECT * FROM public_work_play_daily_stat WHERE source_type = 'match3d'", + "SELECT * FROM public_work_play_daily_stat WHERE source_type = 'square-hole'", + "SELECT * FROM public_work_play_daily_stat WHERE source_type = 'visual-novel'", + "SELECT * FROM public_work_play_daily_stat WHERE source_type = 'big-fish'", "SELECT * FROM creation_entry_config", "SELECT * FROM creation_entry_type_config", ] { diff --git a/server-rs/crates/spacetime-client/src/mapper.rs b/server-rs/crates/spacetime-client/src/mapper.rs index fe7fa2c8..38551408 100644 --- a/server-rs/crates/spacetime-client/src/mapper.rs +++ b/server-rs/crates/spacetime-client/src/mapper.rs @@ -1708,6 +1708,33 @@ pub(crate) fn map_big_fish_works_procedure_result( }) } +pub(crate) fn map_big_fish_gallery_view_row( + row: BigFishWorkSummarySnapshot, + recent_play_count_7d: u32, +) -> BigFishWorkSummaryRecord { + BigFishWorkSummaryRecord { + work_id: row.work_id, + source_session_id: row.source_session_id, + owner_user_id: row.owner_user_id, + title: row.title, + subtitle: row.subtitle, + summary: row.summary, + cover_image_src: row.cover_image_src, + status: row.status, + updated_at_micros: row.updated_at_micros, + published_at_micros: row.published_at_micros, + publish_ready: row.publish_ready, + level_count: row.level_count, + level_main_image_ready_count: row.level_main_image_ready_count, + level_motion_ready_count: row.level_motion_ready_count, + background_ready: row.background_ready, + play_count: row.play_count, + remix_count: row.remix_count, + like_count: row.like_count, + recent_play_count_7d, + } +} + pub(crate) fn map_big_fish_run_procedure_result( result: BigFishRunProcedureResult, ) -> Result { @@ -3071,6 +3098,16 @@ pub(crate) fn map_puzzle_anchor_pack(snapshot: DomainPuzzleAnchorPack) -> Puzzle } } +fn map_puzzle_anchor_pack_row(snapshot: PuzzleAnchorPack) -> PuzzleAnchorPackRecord { + PuzzleAnchorPackRecord { + theme_promise: map_puzzle_anchor_item_row(snapshot.theme_promise), + visual_subject: map_puzzle_anchor_item_row(snapshot.visual_subject), + visual_mood: map_puzzle_anchor_item_row(snapshot.visual_mood), + composition_hooks: map_puzzle_anchor_item_row(snapshot.composition_hooks), + tags_and_forbidden: map_puzzle_anchor_item_row(snapshot.tags_and_forbidden), + } +} + pub(crate) fn map_puzzle_anchor_item(snapshot: DomainPuzzleAnchorItem) -> PuzzleAnchorItemRecord { PuzzleAnchorItemRecord { key: snapshot.key, @@ -3080,6 +3117,15 @@ pub(crate) fn map_puzzle_anchor_item(snapshot: DomainPuzzleAnchorItem) -> Puzzle } } +fn map_puzzle_anchor_item_row(snapshot: PuzzleAnchorItem) -> PuzzleAnchorItemRecord { + PuzzleAnchorItemRecord { + key: snapshot.key, + label: snapshot.label, + value: snapshot.value, + status: format_puzzle_anchor_status(snapshot.status).to_string(), + } +} + pub(crate) fn map_puzzle_result_draft( snapshot: DomainPuzzleResultDraft, ) -> PuzzleResultDraftRecord { @@ -3142,6 +3188,28 @@ pub(crate) fn map_puzzle_draft_level(snapshot: DomainPuzzleDraftLevel) -> Puzzle } } +fn map_puzzle_draft_level_row(snapshot: PuzzleDraftLevel) -> PuzzleDraftLevelRecord { + PuzzleDraftLevelRecord { + level_id: snapshot.level_id, + level_name: snapshot.level_name, + picture_description: snapshot.picture_description, + picture_reference: snapshot.picture_reference, + ui_background_prompt: snapshot.ui_background_prompt, + ui_background_image_src: snapshot.ui_background_image_src, + ui_background_image_object_key: snapshot.ui_background_image_object_key, + background_music: snapshot.background_music.map(map_puzzle_audio_asset_row), + candidates: snapshot + .candidates + .into_iter() + .map(map_puzzle_generated_image_candidate_row) + .collect(), + selected_candidate_id: snapshot.selected_candidate_id, + cover_image_src: snapshot.cover_image_src, + cover_asset_id: snapshot.cover_asset_id, + generation_status: snapshot.generation_status, + } +} + pub(crate) fn map_puzzle_audio_asset( asset: module_puzzle::PuzzleAudioAsset, ) -> PuzzleAudioAssetRecord { @@ -3157,6 +3225,19 @@ pub(crate) fn map_puzzle_audio_asset( } } +fn map_puzzle_audio_asset_row(asset: PuzzleAudioAsset) -> PuzzleAudioAssetRecord { + PuzzleAudioAssetRecord { + task_id: asset.task_id, + provider: asset.provider, + asset_object_id: asset.asset_object_id, + asset_kind: asset.asset_kind, + audio_src: asset.audio_src, + prompt: asset.prompt, + title: asset.title, + updated_at: asset.updated_at, + } +} + pub(crate) fn map_puzzle_creator_intent( snapshot: DomainPuzzleCreatorIntent, ) -> PuzzleCreatorIntentRecord { @@ -3186,6 +3267,20 @@ pub(crate) fn map_puzzle_generated_image_candidate( } } +fn map_puzzle_generated_image_candidate_row( + snapshot: PuzzleGeneratedImageCandidate, +) -> PuzzleGeneratedImageCandidateRecord { + PuzzleGeneratedImageCandidateRecord { + candidate_id: snapshot.candidate_id, + image_src: snapshot.image_src, + asset_id: snapshot.asset_id, + prompt: snapshot.prompt, + actual_prompt: snapshot.actual_prompt, + source_type: snapshot.source_type, + selected: snapshot.selected, + } +} + pub(crate) fn map_puzzle_agent_message_snapshot( snapshot: DomainPuzzleAgentMessageSnapshot, ) -> PuzzleAgentMessageRecord { @@ -3298,6 +3393,32 @@ fn map_match3d_work_snapshot(snapshot: Match3DWorkJsonRecord) -> Match3DWorkProf } } +pub(crate) fn map_match3d_gallery_view_row(row: Match3DGalleryViewRow) -> Match3DWorkProfileRecord { + Match3DWorkProfileRecord { + work_id: row.profile_id.clone(), + profile_id: row.profile_id, + owner_user_id: row.owner_user_id, + source_session_id: empty_string_to_none(row.source_session_id), + author_display_name: row.author_display_name, + game_name: row.game_name, + theme_text: row.theme_text, + summary: row.summary_text, + tags: row.tags, + cover_image_src: empty_string_to_none(row.cover_image_src), + cover_asset_id: empty_string_to_none(row.cover_asset_id), + reference_image_src: row.reference_image_src, + clear_count: row.clear_count, + difficulty: row.difficulty, + publication_status: normalize_match3d_publication_status(&row.publication_status) + .to_string(), + play_count: row.play_count, + updated_at: format_timestamp_micros(row.updated_at_micros), + published_at: row.published_at_micros.map(format_timestamp_micros), + publish_ready: row.publish_ready, + generated_item_assets_json: row.generated_item_assets_json, + } +} + fn map_match3d_run_json(run_json: String) -> Result { let run = serde_json::from_str::(&run_json).map_err(|error| { SpacetimeClientError::Runtime(format!("match3d run_json 非法: {error}")) @@ -3523,6 +3644,44 @@ fn map_square_hole_work_snapshot( } } +pub(crate) fn map_square_hole_gallery_view_row( + row: SquareHoleGalleryViewRow, +) -> SquareHoleWorkProfileRecord { + SquareHoleWorkProfileRecord { + work_id: row.work_id, + profile_id: row.profile_id, + owner_user_id: row.owner_user_id, + source_session_id: empty_string_to_none(row.source_session_id), + author_display_name: row.author_display_name, + game_name: row.game_name, + theme_text: row.theme_text, + twist_rule: row.twist_rule, + summary: row.summary_text, + tags: row.tags, + cover_image_src: empty_string_to_none(row.cover_image_src), + background_prompt: row.background_prompt, + background_image_src: empty_string_to_none(row.background_image_src), + shape_options: row + .shape_options + .into_iter() + .map(map_square_hole_shape_option_snapshot) + .collect(), + hole_options: row + .hole_options + .into_iter() + .map(map_square_hole_hole_option_snapshot) + .collect(), + shape_count: row.shape_count, + difficulty: row.difficulty, + publication_status: normalize_square_hole_publication_status(&row.publication_status) + .to_string(), + play_count: row.play_count, + updated_at: format_timestamp_micros(row.updated_at_micros), + published_at: row.published_at_micros.map(format_timestamp_micros), + publish_ready: row.publish_ready, + } +} + fn map_square_hole_run_json(run_json: String) -> Result { let run = serde_json::from_str::(&run_json).map_err(|error| { SpacetimeClientError::Runtime(format!("square hole run_json 非法: {error}")) @@ -3612,6 +3771,31 @@ fn map_square_hole_hole_option( } } +fn map_square_hole_shape_option_snapshot( + snapshot: SquareHoleShapeOptionSnapshot, +) -> SquareHoleShapeOptionRecord { + SquareHoleShapeOptionRecord { + option_id: snapshot.option_id, + shape_kind: snapshot.shape_kind, + label: snapshot.label, + target_hole_id: snapshot.target_hole_id, + image_prompt: snapshot.image_prompt, + image_src: empty_string_to_none(snapshot.image_src), + } +} + +fn map_square_hole_hole_option_snapshot( + snapshot: SquareHoleHoleOptionSnapshot, +) -> SquareHoleHoleOptionRecord { + SquareHoleHoleOptionRecord { + hole_id: snapshot.hole_id, + hole_kind: snapshot.hole_kind, + label: snapshot.label, + image_prompt: snapshot.image_prompt, + image_src: empty_string_to_none(snapshot.image_src), + } +} + fn map_square_hole_feedback_snapshot( snapshot: SquareHoleDropFeedbackJsonRecord, ) -> SquareHoleDropFeedbackRecord { @@ -3722,6 +3906,31 @@ fn map_visual_novel_work_snapshot( } } +pub(crate) fn map_visual_novel_gallery_view_row( + row: VisualNovelGalleryViewRow, +) -> VisualNovelWorkProfileRecord { + VisualNovelWorkProfileRecord { + work_id: row.work_id, + profile_id: row.profile_id, + owner_user_id: row.owner_user_id, + source_session_id: row.source_session_id, + author_display_name: row.author_display_name, + work_title: row.work_title, + work_description: row.work_description, + tags: row.tags, + cover_image_src: row.cover_image_src, + source_asset_ids: row.source_asset_ids, + // 中文注释:公开列表 view 不暴露完整 draft,详情页仍通过 detail procedure 读取。 + draft: serde_json::Value::Null, + publication_status: row.publication_status, + publish_ready: row.publish_ready, + play_count: row.play_count, + created_at: format_timestamp_micros(row.created_at_micros), + updated_at: format_timestamp_micros(row.updated_at_micros), + published_at: row.published_at_micros.map(format_timestamp_micros), + } +} + fn map_visual_novel_run_snapshot(snapshot: VisualNovelRunJsonRecord) -> VisualNovelRunRecord { VisualNovelRunRecord { run_id: snapshot.run_id, @@ -3790,6 +3999,22 @@ fn normalize_match3d_stage(value: &str) -> &str { } } +fn format_puzzle_publication_status(value: PuzzlePublicationStatus) -> &'static str { + match value { + PuzzlePublicationStatus::Draft => "draft", + PuzzlePublicationStatus::Published => "published", + } +} + +fn format_puzzle_anchor_status(value: PuzzleAnchorStatus) -> &'static str { + match value { + PuzzleAnchorStatus::Missing => "missing", + PuzzleAnchorStatus::Inferred => "inferred", + PuzzleAnchorStatus::Confirmed => "confirmed", + PuzzleAnchorStatus::Locked => "locked", + } +} + fn normalize_match3d_publication_status(value: &str) -> &str { match value { "Draft" | "draft" => "draft", @@ -3951,6 +4176,40 @@ pub(crate) fn map_puzzle_work_profile( } } +pub(crate) fn map_puzzle_work_profile_row(snapshot: PuzzleWorkProfile) -> PuzzleWorkProfileRecord { + PuzzleWorkProfileRecord { + work_id: snapshot.work_id, + profile_id: snapshot.profile_id, + owner_user_id: snapshot.owner_user_id, + source_session_id: snapshot.source_session_id, + author_display_name: snapshot.author_display_name, + work_title: snapshot.work_title, + work_description: snapshot.work_description, + level_name: snapshot.level_name, + summary: snapshot.summary, + theme_tags: snapshot.theme_tags, + cover_image_src: snapshot.cover_image_src, + cover_asset_id: snapshot.cover_asset_id, + publication_status: format_puzzle_publication_status(snapshot.publication_status) + .to_string(), + updated_at: format_timestamp_micros(snapshot.updated_at_micros), + published_at: snapshot.published_at_micros.map(format_timestamp_micros), + play_count: snapshot.play_count, + remix_count: snapshot.remix_count, + like_count: snapshot.like_count, + recent_play_count_7d: snapshot.recent_play_count_7_d, + point_incentive_total_half_points: snapshot.point_incentive_total_half_points, + point_incentive_claimed_points: snapshot.point_incentive_claimed_points, + publish_ready: snapshot.publish_ready, + anchor_pack: map_puzzle_anchor_pack_row(snapshot.anchor_pack), + levels: snapshot + .levels + .into_iter() + .map(map_puzzle_draft_level_row) + .collect(), + } +} + pub(crate) fn map_puzzle_run_snapshot(snapshot: DomainPuzzleRunSnapshot) -> PuzzleRunRecord { PuzzleRunRecord { run_id: snapshot.run_id, diff --git a/server-rs/crates/spacetime-client/src/match3d.rs b/server-rs/crates/spacetime-client/src/match3d.rs index baaf7bb9..e4b54328 100644 --- a/server-rs/crates/spacetime-client/src/match3d.rs +++ b/server-rs/crates/spacetime-client/src/match3d.rs @@ -225,10 +225,22 @@ impl SpacetimeClient { pub async fn list_match3d_gallery( &self, ) -> Result, SpacetimeClientError> { - self.list_match3d_works_with_input(Match3DWorksListInput { - // 中文注释:公开广场读取只依赖 published_only,owner_user_id 保持非空便于兼容校验。 - owner_user_id: "match3d-public-gallery".to_string(), - published_only: true, + self.read_after_connect(move |connection| { + let mut items = connection + .db() + .match_3_d_gallery_view() + .iter() + .collect::>(); + items.sort_by(|left, right| { + right + .updated_at_micros + .cmp(&left.updated_at_micros) + .then_with(|| left.profile_id.cmp(&right.profile_id)) + }); + Ok(items + .into_iter() + .map(map_match3d_gallery_view_row) + .collect()) }) .await } diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_creation_session_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_creation_session_type.rs index 572889b8..d87690de 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_creation_session_type.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_creation_session_type.rs @@ -92,6 +92,7 @@ impl __sdk::__query_builder::HasCols for BigFishCreationSession { pub struct BigFishCreationSessionIxCols { pub owner_user_id: __sdk::__query_builder::IxCol, pub session_id: __sdk::__query_builder::IxCol, + pub stage: __sdk::__query_builder::IxCol, } impl __sdk::__query_builder::HasIxCols for BigFishCreationSession { @@ -100,6 +101,7 @@ impl __sdk::__query_builder::HasIxCols for BigFishCreationSession { BigFishCreationSessionIxCols { owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"), session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"), + stage: __sdk::__query_builder::IxCol::new(table_name, "stage"), } } } diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_gallery_view_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_gallery_view_table.rs new file mode 100644 index 00000000..2d9419c4 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_gallery_view_table.rs @@ -0,0 +1,114 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use super::big_fish_work_summary_snapshot_type::BigFishWorkSummarySnapshot; +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +/// Table handle for the table `big_fish_gallery_view`. +/// +/// Obtain a handle from the [`BigFishGalleryViewTableAccess::big_fish_gallery_view`] method on [`super::RemoteTables`], +/// like `ctx.db.big_fish_gallery_view()`. +/// +/// Users are encouraged not to explicitly reference this type, +/// but to directly chain method calls, +/// like `ctx.db.big_fish_gallery_view().on_insert(...)`. +pub struct BigFishGalleryViewTableHandle<'ctx> { + imp: __sdk::TableHandle, + ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the table `big_fish_gallery_view`. +/// +/// Implemented for [`super::RemoteTables`]. +pub trait BigFishGalleryViewTableAccess { + #[allow(non_snake_case)] + /// Obtain a [`BigFishGalleryViewTableHandle`], which mediates access to the table `big_fish_gallery_view`. + fn big_fish_gallery_view(&self) -> BigFishGalleryViewTableHandle<'_>; +} + +impl BigFishGalleryViewTableAccess for super::RemoteTables { + fn big_fish_gallery_view(&self) -> BigFishGalleryViewTableHandle<'_> { + BigFishGalleryViewTableHandle { + imp: self + .imp + .get_table::("big_fish_gallery_view"), + ctx: std::marker::PhantomData, + } + } +} + +pub struct BigFishGalleryViewInsertCallbackId(__sdk::CallbackId); +pub struct BigFishGalleryViewDeleteCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::Table for BigFishGalleryViewTableHandle<'ctx> { + type Row = BigFishWorkSummarySnapshot; + type EventContext = super::EventContext; + + fn count(&self) -> u64 { + self.imp.count() + } + fn iter(&self) -> impl Iterator + '_ { + self.imp.iter() + } + + type InsertCallbackId = BigFishGalleryViewInsertCallbackId; + + fn on_insert( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> BigFishGalleryViewInsertCallbackId { + BigFishGalleryViewInsertCallbackId(self.imp.on_insert(Box::new(callback))) + } + + fn remove_on_insert(&self, callback: BigFishGalleryViewInsertCallbackId) { + self.imp.remove_on_insert(callback.0) + } + + type DeleteCallbackId = BigFishGalleryViewDeleteCallbackId; + + fn on_delete( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> BigFishGalleryViewDeleteCallbackId { + BigFishGalleryViewDeleteCallbackId(self.imp.on_delete(Box::new(callback))) + } + + fn remove_on_delete(&self, callback: BigFishGalleryViewDeleteCallbackId) { + self.imp.remove_on_delete(callback.0) + } +} + +#[doc(hidden)] +pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { + let _table = + client_cache.get_or_make_table::("big_fish_gallery_view"); +} + +#[doc(hidden)] +pub(super) fn parse_table_update( + raw_updates: __ws::v2::TableUpdate, +) -> __sdk::Result<__sdk::TableUpdate> { + __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { + __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") + .with_cause(e) + .into() + }) +} + +#[allow(non_camel_case_types)] +/// Extension trait for query builder access to the table `BigFishWorkSummarySnapshot`. +/// +/// Implemented for [`__sdk::QueryTableAccessor`]. +pub trait big_fish_gallery_viewQueryTableAccess { + #[allow(non_snake_case)] + /// Get a query builder for the table `BigFishWorkSummarySnapshot`. + fn big_fish_gallery_view(&self) -> __sdk::__query_builder::Table; +} + +impl big_fish_gallery_viewQueryTableAccess for __sdk::QueryTableAccessor { + fn big_fish_gallery_view(&self) -> __sdk::__query_builder::Table { + __sdk::__query_builder::Table::new("big_fish_gallery_view") + } +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/big_fish_work_summary_snapshot_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_work_summary_snapshot_type.rs new file mode 100644 index 00000000..9bdeeedb --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/big_fish_work_summary_snapshot_type.rs @@ -0,0 +1,97 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct BigFishWorkSummarySnapshot { + pub work_id: String, + pub source_session_id: String, + pub owner_user_id: String, + pub title: String, + pub subtitle: String, + pub summary: String, + pub cover_image_src: Option, + pub status: String, + pub updated_at_micros: i64, + pub publish_ready: bool, + pub level_count: u32, + pub level_main_image_ready_count: u32, + pub level_motion_ready_count: u32, + pub background_ready: bool, + pub play_count: u32, + pub remix_count: u32, + pub like_count: u32, + pub recent_play_count_7_d: u32, + pub published_at_micros: Option, +} + +impl __sdk::InModule for BigFishWorkSummarySnapshot { + type Module = super::RemoteModule; +} + +/// Column accessor struct for the table `BigFishWorkSummarySnapshot`. +/// +/// Provides typed access to columns for query building. +pub struct BigFishWorkSummarySnapshotCols { + pub work_id: __sdk::__query_builder::Col, + pub source_session_id: __sdk::__query_builder::Col, + pub owner_user_id: __sdk::__query_builder::Col, + pub title: __sdk::__query_builder::Col, + pub subtitle: __sdk::__query_builder::Col, + pub summary: __sdk::__query_builder::Col, + pub cover_image_src: __sdk::__query_builder::Col>, + pub status: __sdk::__query_builder::Col, + pub updated_at_micros: __sdk::__query_builder::Col, + pub publish_ready: __sdk::__query_builder::Col, + pub level_count: __sdk::__query_builder::Col, + pub level_main_image_ready_count: __sdk::__query_builder::Col, + pub level_motion_ready_count: __sdk::__query_builder::Col, + pub background_ready: __sdk::__query_builder::Col, + pub play_count: __sdk::__query_builder::Col, + pub remix_count: __sdk::__query_builder::Col, + pub like_count: __sdk::__query_builder::Col, + pub recent_play_count_7_d: __sdk::__query_builder::Col, + pub published_at_micros: __sdk::__query_builder::Col>, +} + +impl __sdk::__query_builder::HasCols for BigFishWorkSummarySnapshot { + type Cols = BigFishWorkSummarySnapshotCols; + fn cols(table_name: &'static str) -> Self::Cols { + BigFishWorkSummarySnapshotCols { + work_id: __sdk::__query_builder::Col::new(table_name, "work_id"), + source_session_id: __sdk::__query_builder::Col::new(table_name, "source_session_id"), + owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), + title: __sdk::__query_builder::Col::new(table_name, "title"), + subtitle: __sdk::__query_builder::Col::new(table_name, "subtitle"), + summary: __sdk::__query_builder::Col::new(table_name, "summary"), + cover_image_src: __sdk::__query_builder::Col::new(table_name, "cover_image_src"), + status: __sdk::__query_builder::Col::new(table_name, "status"), + updated_at_micros: __sdk::__query_builder::Col::new(table_name, "updated_at_micros"), + publish_ready: __sdk::__query_builder::Col::new(table_name, "publish_ready"), + level_count: __sdk::__query_builder::Col::new(table_name, "level_count"), + level_main_image_ready_count: __sdk::__query_builder::Col::new( + table_name, + "level_main_image_ready_count", + ), + level_motion_ready_count: __sdk::__query_builder::Col::new( + table_name, + "level_motion_ready_count", + ), + background_ready: __sdk::__query_builder::Col::new(table_name, "background_ready"), + play_count: __sdk::__query_builder::Col::new(table_name, "play_count"), + remix_count: __sdk::__query_builder::Col::new(table_name, "remix_count"), + like_count: __sdk::__query_builder::Col::new(table_name, "like_count"), + recent_play_count_7_d: __sdk::__query_builder::Col::new( + table_name, + "recent_play_count_7_d", + ), + published_at_micros: __sdk::__query_builder::Col::new( + table_name, + "published_at_micros", + ), + } + } +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_gallery_view_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_gallery_view_row_type.rs new file mode 100644 index 00000000..03b768d3 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_gallery_view_row_type.rs @@ -0,0 +1,98 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct Match3DGalleryViewRow { + pub profile_id: String, + pub owner_user_id: String, + pub source_session_id: String, + pub author_display_name: String, + pub game_name: String, + pub theme_text: String, + pub summary_text: String, + pub tags: Vec, + pub cover_image_src: String, + pub cover_asset_id: String, + pub reference_image_src: Option, + pub clear_count: u32, + pub difficulty: u32, + pub publication_status: String, + pub publish_ready: bool, + pub play_count: u32, + pub updated_at_micros: i64, + pub published_at_micros: Option, + pub generated_item_assets_json: Option, +} + +impl __sdk::InModule for Match3DGalleryViewRow { + type Module = super::RemoteModule; +} + +/// Column accessor struct for the table `Match3DGalleryViewRow`. +/// +/// Provides typed access to columns for query building. +pub struct Match3DGalleryViewRowCols { + pub profile_id: __sdk::__query_builder::Col, + pub owner_user_id: __sdk::__query_builder::Col, + pub source_session_id: __sdk::__query_builder::Col, + pub author_display_name: __sdk::__query_builder::Col, + pub game_name: __sdk::__query_builder::Col, + pub theme_text: __sdk::__query_builder::Col, + pub summary_text: __sdk::__query_builder::Col, + pub tags: __sdk::__query_builder::Col>, + pub cover_image_src: __sdk::__query_builder::Col, + pub cover_asset_id: __sdk::__query_builder::Col, + pub reference_image_src: __sdk::__query_builder::Col>, + pub clear_count: __sdk::__query_builder::Col, + pub difficulty: __sdk::__query_builder::Col, + pub publication_status: __sdk::__query_builder::Col, + pub publish_ready: __sdk::__query_builder::Col, + pub play_count: __sdk::__query_builder::Col, + pub updated_at_micros: __sdk::__query_builder::Col, + pub published_at_micros: __sdk::__query_builder::Col>, + pub generated_item_assets_json: + __sdk::__query_builder::Col>, +} + +impl __sdk::__query_builder::HasCols for Match3DGalleryViewRow { + type Cols = Match3DGalleryViewRowCols; + fn cols(table_name: &'static str) -> Self::Cols { + Match3DGalleryViewRowCols { + profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), + owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), + source_session_id: __sdk::__query_builder::Col::new(table_name, "source_session_id"), + author_display_name: __sdk::__query_builder::Col::new( + table_name, + "author_display_name", + ), + game_name: __sdk::__query_builder::Col::new(table_name, "game_name"), + theme_text: __sdk::__query_builder::Col::new(table_name, "theme_text"), + summary_text: __sdk::__query_builder::Col::new(table_name, "summary_text"), + tags: __sdk::__query_builder::Col::new(table_name, "tags"), + cover_image_src: __sdk::__query_builder::Col::new(table_name, "cover_image_src"), + cover_asset_id: __sdk::__query_builder::Col::new(table_name, "cover_asset_id"), + reference_image_src: __sdk::__query_builder::Col::new( + table_name, + "reference_image_src", + ), + clear_count: __sdk::__query_builder::Col::new(table_name, "clear_count"), + difficulty: __sdk::__query_builder::Col::new(table_name, "difficulty"), + publication_status: __sdk::__query_builder::Col::new(table_name, "publication_status"), + publish_ready: __sdk::__query_builder::Col::new(table_name, "publish_ready"), + play_count: __sdk::__query_builder::Col::new(table_name, "play_count"), + updated_at_micros: __sdk::__query_builder::Col::new(table_name, "updated_at_micros"), + published_at_micros: __sdk::__query_builder::Col::new( + table_name, + "published_at_micros", + ), + generated_item_assets_json: __sdk::__query_builder::Col::new( + table_name, + "generated_item_assets_json", + ), + } + } +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_gallery_view_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_gallery_view_table.rs new file mode 100644 index 00000000..b47d62a3 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/match_3_d_gallery_view_table.rs @@ -0,0 +1,113 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use super::match_3_d_gallery_view_row_type::Match3DGalleryViewRow; +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +/// Table handle for the table `match_3_d_gallery_view`. +/// +/// Obtain a handle from the [`Match3DGalleryViewTableAccess::match_3_d_gallery_view`] method on [`super::RemoteTables`], +/// like `ctx.db.match_3_d_gallery_view()`. +/// +/// Users are encouraged not to explicitly reference this type, +/// but to directly chain method calls, +/// like `ctx.db.match_3_d_gallery_view().on_insert(...)`. +pub struct Match3DGalleryViewTableHandle<'ctx> { + imp: __sdk::TableHandle, + ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the table `match_3_d_gallery_view`. +/// +/// Implemented for [`super::RemoteTables`]. +pub trait Match3DGalleryViewTableAccess { + #[allow(non_snake_case)] + /// Obtain a [`Match3DGalleryViewTableHandle`], which mediates access to the table `match_3_d_gallery_view`. + fn match_3_d_gallery_view(&self) -> Match3DGalleryViewTableHandle<'_>; +} + +impl Match3DGalleryViewTableAccess for super::RemoteTables { + fn match_3_d_gallery_view(&self) -> Match3DGalleryViewTableHandle<'_> { + Match3DGalleryViewTableHandle { + imp: self + .imp + .get_table::("match_3_d_gallery_view"), + ctx: std::marker::PhantomData, + } + } +} + +pub struct Match3DGalleryViewInsertCallbackId(__sdk::CallbackId); +pub struct Match3DGalleryViewDeleteCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::Table for Match3DGalleryViewTableHandle<'ctx> { + type Row = Match3DGalleryViewRow; + type EventContext = super::EventContext; + + fn count(&self) -> u64 { + self.imp.count() + } + fn iter(&self) -> impl Iterator + '_ { + self.imp.iter() + } + + type InsertCallbackId = Match3DGalleryViewInsertCallbackId; + + fn on_insert( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> Match3DGalleryViewInsertCallbackId { + Match3DGalleryViewInsertCallbackId(self.imp.on_insert(Box::new(callback))) + } + + fn remove_on_insert(&self, callback: Match3DGalleryViewInsertCallbackId) { + self.imp.remove_on_insert(callback.0) + } + + type DeleteCallbackId = Match3DGalleryViewDeleteCallbackId; + + fn on_delete( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> Match3DGalleryViewDeleteCallbackId { + Match3DGalleryViewDeleteCallbackId(self.imp.on_delete(Box::new(callback))) + } + + fn remove_on_delete(&self, callback: Match3DGalleryViewDeleteCallbackId) { + self.imp.remove_on_delete(callback.0) + } +} + +#[doc(hidden)] +pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { + let _table = client_cache.get_or_make_table::("match_3_d_gallery_view"); +} + +#[doc(hidden)] +pub(super) fn parse_table_update( + raw_updates: __ws::v2::TableUpdate, +) -> __sdk::Result<__sdk::TableUpdate> { + __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { + __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") + .with_cause(e) + .into() + }) +} + +#[allow(non_camel_case_types)] +/// Extension trait for query builder access to the table `Match3DGalleryViewRow`. +/// +/// Implemented for [`__sdk::QueryTableAccessor`]. +pub trait match_3_d_gallery_viewQueryTableAccess { + #[allow(non_snake_case)] + /// Get a query builder for the table `Match3DGalleryViewRow`. + fn match_3_d_gallery_view(&self) -> __sdk::__query_builder::Table; +} + +impl match_3_d_gallery_viewQueryTableAccess for __sdk::QueryTableAccessor { + fn match_3_d_gallery_view(&self) -> __sdk::__query_builder::Table { + __sdk::__query_builder::Table::new("match_3_d_gallery_view") + } +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/mod.rs b/server-rs/crates/spacetime-client/src/module_bindings/mod.rs index 8e38203c..383ffd25 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/mod.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/mod.rs @@ -149,6 +149,7 @@ pub mod big_fish_draft_compile_input_type; pub mod big_fish_event_kind_type; pub mod big_fish_event_table; pub mod big_fish_event_type; +pub mod big_fish_gallery_view_table; pub mod big_fish_game_draft_type; pub mod big_fish_input_submit_input_type; pub mod big_fish_level_blueprint_type; @@ -170,6 +171,7 @@ pub mod big_fish_session_snapshot_type; pub mod big_fish_work_delete_input_type; pub mod big_fish_work_like_record_input_type; pub mod big_fish_work_remix_input_type; +pub mod big_fish_work_summary_snapshot_type; pub mod big_fish_works_list_input_type; pub mod big_fish_works_procedure_result_type; pub mod bind_asset_object_to_entity_and_return_procedure; @@ -411,6 +413,8 @@ pub mod match_3_d_agent_session_row_type; pub mod match_3_d_agent_session_table; pub mod match_3_d_click_item_procedure_result_type; pub mod match_3_d_draft_compile_input_type; +pub mod match_3_d_gallery_view_row_type; +pub mod match_3_d_gallery_view_table; pub mod match_3_d_run_click_input_type; pub mod match_3_d_run_get_input_type; pub mod match_3_d_run_procedure_result_type; @@ -507,12 +511,18 @@ pub mod puzzle_agent_session_procedure_result_type; pub mod puzzle_agent_session_row_type; pub mod puzzle_agent_session_table; pub mod puzzle_agent_stage_type; +pub mod puzzle_anchor_item_type; +pub mod puzzle_anchor_pack_type; +pub mod puzzle_anchor_status_type; +pub mod puzzle_audio_asset_type; pub mod puzzle_draft_compile_input_type; +pub mod puzzle_draft_level_type; pub mod puzzle_event_kind_type; pub mod puzzle_event_table; pub mod puzzle_event_type; pub mod puzzle_form_draft_save_input_type; pub mod puzzle_gallery_view_table; +pub mod puzzle_generated_image_candidate_type; pub mod puzzle_generated_images_save_input_type; pub mod puzzle_leaderboard_entry_row_type; pub mod puzzle_leaderboard_entry_table; @@ -538,6 +548,7 @@ pub mod puzzle_work_point_incentive_claim_input_type; pub mod puzzle_work_procedure_result_type; pub mod puzzle_work_profile_row_type; pub mod puzzle_work_profile_table; +pub mod puzzle_work_profile_type; pub mod puzzle_work_remix_input_type; pub mod puzzle_work_upsert_input_type; pub mod puzzle_works_list_input_type; @@ -738,6 +749,9 @@ pub mod square_hole_agent_session_row_type; pub mod square_hole_agent_session_table; pub mod square_hole_draft_compile_input_type; pub mod square_hole_drop_shape_procedure_result_type; +pub mod square_hole_gallery_view_row_type; +pub mod square_hole_gallery_view_table; +pub mod square_hole_hole_option_snapshot_type; pub mod square_hole_run_drop_input_type; pub mod square_hole_run_get_input_type; pub mod square_hole_run_procedure_result_type; @@ -747,6 +761,7 @@ pub mod square_hole_run_stop_input_type; pub mod square_hole_run_time_up_input_type; pub mod square_hole_runtime_run_row_type; pub mod square_hole_runtime_run_table; +pub mod square_hole_shape_option_snapshot_type; pub mod square_hole_work_delete_input_type; pub mod square_hole_work_get_input_type; pub mod square_hole_work_procedure_result_type; @@ -836,6 +851,8 @@ pub mod visual_novel_agent_session_get_input_type; pub mod visual_novel_agent_session_procedure_result_type; pub mod visual_novel_agent_session_row_type; pub mod visual_novel_agent_session_table; +pub mod visual_novel_gallery_view_row_type; +pub mod visual_novel_gallery_view_table; pub mod visual_novel_history_procedure_result_type; pub mod visual_novel_run_get_input_type; pub mod visual_novel_run_procedure_result_type; @@ -1005,6 +1022,7 @@ pub use big_fish_draft_compile_input_type::BigFishDraftCompileInput; pub use big_fish_event_kind_type::BigFishEventKind; pub use big_fish_event_table::*; pub use big_fish_event_type::BigFishEvent; +pub use big_fish_gallery_view_table::*; pub use big_fish_game_draft_type::BigFishGameDraft; pub use big_fish_input_submit_input_type::BigFishInputSubmitInput; pub use big_fish_level_blueprint_type::BigFishLevelBlueprint; @@ -1026,6 +1044,7 @@ pub use big_fish_session_snapshot_type::BigFishSessionSnapshot; pub use big_fish_work_delete_input_type::BigFishWorkDeleteInput; pub use big_fish_work_like_record_input_type::BigFishWorkLikeRecordInput; pub use big_fish_work_remix_input_type::BigFishWorkRemixInput; +pub use big_fish_work_summary_snapshot_type::BigFishWorkSummarySnapshot; pub use big_fish_works_list_input_type::BigFishWorksListInput; pub use big_fish_works_procedure_result_type::BigFishWorksProcedureResult; pub use bind_asset_object_to_entity_and_return_procedure::bind_asset_object_to_entity_and_return; @@ -1267,6 +1286,8 @@ pub use match_3_d_agent_session_row_type::Match3DAgentSessionRow; pub use match_3_d_agent_session_table::*; pub use match_3_d_click_item_procedure_result_type::Match3DClickItemProcedureResult; pub use match_3_d_draft_compile_input_type::Match3DDraftCompileInput; +pub use match_3_d_gallery_view_row_type::Match3DGalleryViewRow; +pub use match_3_d_gallery_view_table::*; pub use match_3_d_run_click_input_type::Match3DRunClickInput; pub use match_3_d_run_get_input_type::Match3DRunGetInput; pub use match_3_d_run_procedure_result_type::Match3DRunProcedureResult; @@ -1363,12 +1384,18 @@ pub use puzzle_agent_session_procedure_result_type::PuzzleAgentSessionProcedureR pub use puzzle_agent_session_row_type::PuzzleAgentSessionRow; pub use puzzle_agent_session_table::*; pub use puzzle_agent_stage_type::PuzzleAgentStage; +pub use puzzle_anchor_item_type::PuzzleAnchorItem; +pub use puzzle_anchor_pack_type::PuzzleAnchorPack; +pub use puzzle_anchor_status_type::PuzzleAnchorStatus; +pub use puzzle_audio_asset_type::PuzzleAudioAsset; pub use puzzle_draft_compile_input_type::PuzzleDraftCompileInput; +pub use puzzle_draft_level_type::PuzzleDraftLevel; pub use puzzle_event_kind_type::PuzzleEventKind; pub use puzzle_event_table::*; pub use puzzle_event_type::PuzzleEvent; pub use puzzle_form_draft_save_input_type::PuzzleFormDraftSaveInput; pub use puzzle_gallery_view_table::*; +pub use puzzle_generated_image_candidate_type::PuzzleGeneratedImageCandidate; pub use puzzle_generated_images_save_input_type::PuzzleGeneratedImagesSaveInput; pub use puzzle_leaderboard_entry_row_type::PuzzleLeaderboardEntryRow; pub use puzzle_leaderboard_entry_table::*; @@ -1394,6 +1421,7 @@ pub use puzzle_work_point_incentive_claim_input_type::PuzzleWorkPointIncentiveCl pub use puzzle_work_procedure_result_type::PuzzleWorkProcedureResult; pub use puzzle_work_profile_row_type::PuzzleWorkProfileRow; pub use puzzle_work_profile_table::*; +pub use puzzle_work_profile_type::PuzzleWorkProfile; pub use puzzle_work_remix_input_type::PuzzleWorkRemixInput; pub use puzzle_work_upsert_input_type::PuzzleWorkUpsertInput; pub use puzzle_works_list_input_type::PuzzleWorksListInput; @@ -1594,6 +1622,9 @@ pub use square_hole_agent_session_row_type::SquareHoleAgentSessionRow; pub use square_hole_agent_session_table::*; pub use square_hole_draft_compile_input_type::SquareHoleDraftCompileInput; pub use square_hole_drop_shape_procedure_result_type::SquareHoleDropShapeProcedureResult; +pub use square_hole_gallery_view_row_type::SquareHoleGalleryViewRow; +pub use square_hole_gallery_view_table::*; +pub use square_hole_hole_option_snapshot_type::SquareHoleHoleOptionSnapshot; pub use square_hole_run_drop_input_type::SquareHoleRunDropInput; pub use square_hole_run_get_input_type::SquareHoleRunGetInput; pub use square_hole_run_procedure_result_type::SquareHoleRunProcedureResult; @@ -1603,6 +1634,7 @@ pub use square_hole_run_stop_input_type::SquareHoleRunStopInput; pub use square_hole_run_time_up_input_type::SquareHoleRunTimeUpInput; pub use square_hole_runtime_run_row_type::SquareHoleRuntimeRunRow; pub use square_hole_runtime_run_table::*; +pub use square_hole_shape_option_snapshot_type::SquareHoleShapeOptionSnapshot; pub use square_hole_work_delete_input_type::SquareHoleWorkDeleteInput; pub use square_hole_work_get_input_type::SquareHoleWorkGetInput; pub use square_hole_work_procedure_result_type::SquareHoleWorkProcedureResult; @@ -1692,6 +1724,8 @@ pub use visual_novel_agent_session_get_input_type::VisualNovelAgentSessionGetInp pub use visual_novel_agent_session_procedure_result_type::VisualNovelAgentSessionProcedureResult; pub use visual_novel_agent_session_row_type::VisualNovelAgentSessionRow; pub use visual_novel_agent_session_table::*; +pub use visual_novel_gallery_view_row_type::VisualNovelGalleryViewRow; +pub use visual_novel_gallery_view_table::*; pub use visual_novel_history_procedure_result_type::VisualNovelHistoryProcedureResult; pub use visual_novel_run_get_input_type::VisualNovelRunGetInput; pub use visual_novel_run_procedure_result_type::VisualNovelRunProcedureResult; @@ -2014,6 +2048,7 @@ pub struct DbUpdate { big_fish_asset_slot: __sdk::TableUpdate, big_fish_creation_session: __sdk::TableUpdate, big_fish_event: __sdk::TableUpdate, + big_fish_gallery_view: __sdk::TableUpdate, big_fish_runtime_run: __sdk::TableUpdate, chapter_progression: __sdk::TableUpdate, creation_entry_config: __sdk::TableUpdate, @@ -2030,6 +2065,7 @@ pub struct DbUpdate { inventory_slot: __sdk::TableUpdate, match_3_d_agent_message: __sdk::TableUpdate, match_3_d_agent_session: __sdk::TableUpdate, + match_3_d_gallery_view: __sdk::TableUpdate, match_3_d_runtime_run: __sdk::TableUpdate, match_3_d_work_profile: __sdk::TableUpdate, npc_state: __sdk::TableUpdate, @@ -2054,7 +2090,7 @@ pub struct DbUpdate { puzzle_agent_message: __sdk::TableUpdate, puzzle_agent_session: __sdk::TableUpdate, puzzle_event: __sdk::TableUpdate, - puzzle_gallery_view: __sdk::TableUpdate, + puzzle_gallery_view: __sdk::TableUpdate, puzzle_leaderboard_entry: __sdk::TableUpdate, puzzle_runtime_run: __sdk::TableUpdate, puzzle_work_profile: __sdk::TableUpdate, @@ -2065,6 +2101,7 @@ pub struct DbUpdate { runtime_snapshot: __sdk::TableUpdate, square_hole_agent_message: __sdk::TableUpdate, square_hole_agent_session: __sdk::TableUpdate, + square_hole_gallery_view: __sdk::TableUpdate, square_hole_runtime_run: __sdk::TableUpdate, square_hole_work_profile: __sdk::TableUpdate, story_event: __sdk::TableUpdate, @@ -2076,6 +2113,7 @@ pub struct DbUpdate { user_browse_history: __sdk::TableUpdate, visual_novel_agent_message: __sdk::TableUpdate, visual_novel_agent_session: __sdk::TableUpdate, + visual_novel_gallery_view: __sdk::TableUpdate, visual_novel_runtime_event: __sdk::TableUpdate, visual_novel_runtime_history_entry: __sdk::TableUpdate, visual_novel_runtime_run: __sdk::TableUpdate, @@ -2166,6 +2204,9 @@ impl TryFrom<__ws::v2::TransactionUpdate> for DbUpdate { "big_fish_event" => db_update .big_fish_event .append(big_fish_event_table::parse_table_update(table_update)?), + "big_fish_gallery_view" => db_update.big_fish_gallery_view.append( + big_fish_gallery_view_table::parse_table_update(table_update)?, + ), "big_fish_runtime_run" => db_update.big_fish_runtime_run.append( big_fish_runtime_run_table::parse_table_update(table_update)?, ), @@ -2216,6 +2257,9 @@ impl TryFrom<__ws::v2::TransactionUpdate> for DbUpdate { "match_3_d_agent_session" => db_update.match_3_d_agent_session.append( match_3_d_agent_session_table::parse_table_update(table_update)?, ), + "match_3_d_gallery_view" => db_update.match_3_d_gallery_view.append( + match_3_d_gallery_view_table::parse_table_update(table_update)?, + ), "match_3_d_runtime_run" => db_update.match_3_d_runtime_run.append( match_3_d_runtime_run_table::parse_table_update(table_update)?, ), @@ -2323,6 +2367,9 @@ impl TryFrom<__ws::v2::TransactionUpdate> for DbUpdate { "square_hole_agent_session" => db_update.square_hole_agent_session.append( square_hole_agent_session_table::parse_table_update(table_update)?, ), + "square_hole_gallery_view" => db_update.square_hole_gallery_view.append( + square_hole_gallery_view_table::parse_table_update(table_update)?, + ), "square_hole_runtime_run" => db_update.square_hole_runtime_run.append( square_hole_runtime_run_table::parse_table_update(table_update)?, ), @@ -2356,6 +2403,9 @@ impl TryFrom<__ws::v2::TransactionUpdate> for DbUpdate { "visual_novel_agent_session" => db_update.visual_novel_agent_session.append( visual_novel_agent_session_table::parse_table_update(table_update)?, ), + "visual_novel_gallery_view" => db_update.visual_novel_gallery_view.append( + visual_novel_gallery_view_table::parse_table_update(table_update)?, + ), "visual_novel_runtime_event" => db_update.visual_novel_runtime_event.append( visual_novel_runtime_event_table::parse_table_update(table_update)?, ), @@ -2848,10 +2898,26 @@ impl __sdk::DbUpdate for DbUpdate { &self.visual_novel_work_profile, ) .with_updates_by_pk(|row| &row.profile_id); - diff.puzzle_gallery_view = cache.apply_diff_to_table::( + diff.big_fish_gallery_view = cache.apply_diff_to_table::( + "big_fish_gallery_view", + &self.big_fish_gallery_view, + ); + diff.match_3_d_gallery_view = cache.apply_diff_to_table::( + "match_3_d_gallery_view", + &self.match_3_d_gallery_view, + ); + diff.puzzle_gallery_view = cache.apply_diff_to_table::( "puzzle_gallery_view", &self.puzzle_gallery_view, ); + diff.square_hole_gallery_view = cache.apply_diff_to_table::( + "square_hole_gallery_view", + &self.square_hole_gallery_view, + ); + diff.visual_novel_gallery_view = cache.apply_diff_to_table::( + "visual_novel_gallery_view", + &self.visual_novel_gallery_view, + ); diff } @@ -2931,6 +2997,9 @@ impl __sdk::DbUpdate for DbUpdate { "big_fish_event" => db_update .big_fish_event .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), + "big_fish_gallery_view" => db_update + .big_fish_gallery_view + .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "big_fish_runtime_run" => db_update .big_fish_runtime_run .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), @@ -2979,6 +3048,9 @@ impl __sdk::DbUpdate for DbUpdate { "match_3_d_agent_session" => db_update .match_3_d_agent_session .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), + "match_3_d_gallery_view" => db_update + .match_3_d_gallery_view + .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "match_3_d_runtime_run" => db_update .match_3_d_runtime_run .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), @@ -3084,6 +3156,9 @@ impl __sdk::DbUpdate for DbUpdate { "square_hole_agent_session" => db_update .square_hole_agent_session .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), + "square_hole_gallery_view" => db_update + .square_hole_gallery_view + .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "square_hole_runtime_run" => db_update .square_hole_runtime_run .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), @@ -3117,6 +3192,9 @@ impl __sdk::DbUpdate for DbUpdate { "visual_novel_agent_session" => db_update .visual_novel_agent_session .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), + "visual_novel_gallery_view" => db_update + .visual_novel_gallery_view + .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), "visual_novel_runtime_event" => db_update .visual_novel_runtime_event .append(__sdk::parse_row_list_as_inserts(table_rows.rows)?), @@ -3214,6 +3292,9 @@ impl __sdk::DbUpdate for DbUpdate { "big_fish_event" => db_update .big_fish_event .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), + "big_fish_gallery_view" => db_update + .big_fish_gallery_view + .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "big_fish_runtime_run" => db_update .big_fish_runtime_run .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), @@ -3262,6 +3343,9 @@ impl __sdk::DbUpdate for DbUpdate { "match_3_d_agent_session" => db_update .match_3_d_agent_session .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), + "match_3_d_gallery_view" => db_update + .match_3_d_gallery_view + .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "match_3_d_runtime_run" => db_update .match_3_d_runtime_run .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), @@ -3367,6 +3451,9 @@ impl __sdk::DbUpdate for DbUpdate { "square_hole_agent_session" => db_update .square_hole_agent_session .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), + "square_hole_gallery_view" => db_update + .square_hole_gallery_view + .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "square_hole_runtime_run" => db_update .square_hole_runtime_run .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), @@ -3400,6 +3487,9 @@ impl __sdk::DbUpdate for DbUpdate { "visual_novel_agent_session" => db_update .visual_novel_agent_session .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), + "visual_novel_gallery_view" => db_update + .visual_novel_gallery_view + .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), "visual_novel_runtime_event" => db_update .visual_novel_runtime_event .append(__sdk::parse_row_list_as_deletes(table_rows.rows)?), @@ -3453,6 +3543,7 @@ pub struct AppliedDiff<'r> { big_fish_asset_slot: __sdk::TableAppliedDiff<'r, BigFishAssetSlot>, big_fish_creation_session: __sdk::TableAppliedDiff<'r, BigFishCreationSession>, big_fish_event: __sdk::TableAppliedDiff<'r, BigFishEvent>, + big_fish_gallery_view: __sdk::TableAppliedDiff<'r, BigFishWorkSummarySnapshot>, big_fish_runtime_run: __sdk::TableAppliedDiff<'r, BigFishRuntimeRun>, chapter_progression: __sdk::TableAppliedDiff<'r, ChapterProgression>, creation_entry_config: __sdk::TableAppliedDiff<'r, CreationEntryConfig>, @@ -3469,6 +3560,7 @@ pub struct AppliedDiff<'r> { inventory_slot: __sdk::TableAppliedDiff<'r, InventorySlot>, match_3_d_agent_message: __sdk::TableAppliedDiff<'r, Match3DAgentMessageRow>, match_3_d_agent_session: __sdk::TableAppliedDiff<'r, Match3DAgentSessionRow>, + match_3_d_gallery_view: __sdk::TableAppliedDiff<'r, Match3DGalleryViewRow>, match_3_d_runtime_run: __sdk::TableAppliedDiff<'r, Match3DRuntimeRunRow>, match_3_d_work_profile: __sdk::TableAppliedDiff<'r, Match3DWorkProfileRow>, npc_state: __sdk::TableAppliedDiff<'r, NpcState>, @@ -3493,7 +3585,7 @@ pub struct AppliedDiff<'r> { puzzle_agent_message: __sdk::TableAppliedDiff<'r, PuzzleAgentMessageRow>, puzzle_agent_session: __sdk::TableAppliedDiff<'r, PuzzleAgentSessionRow>, puzzle_event: __sdk::TableAppliedDiff<'r, PuzzleEvent>, - puzzle_gallery_view: __sdk::TableAppliedDiff<'r, PuzzleGalleryViewRow>, + puzzle_gallery_view: __sdk::TableAppliedDiff<'r, PuzzleWorkProfile>, puzzle_leaderboard_entry: __sdk::TableAppliedDiff<'r, PuzzleLeaderboardEntryRow>, puzzle_runtime_run: __sdk::TableAppliedDiff<'r, PuzzleRuntimeRunRow>, puzzle_work_profile: __sdk::TableAppliedDiff<'r, PuzzleWorkProfileRow>, @@ -3504,6 +3596,7 @@ pub struct AppliedDiff<'r> { runtime_snapshot: __sdk::TableAppliedDiff<'r, RuntimeSnapshotRow>, square_hole_agent_message: __sdk::TableAppliedDiff<'r, SquareHoleAgentMessageRow>, square_hole_agent_session: __sdk::TableAppliedDiff<'r, SquareHoleAgentSessionRow>, + square_hole_gallery_view: __sdk::TableAppliedDiff<'r, SquareHoleGalleryViewRow>, square_hole_runtime_run: __sdk::TableAppliedDiff<'r, SquareHoleRuntimeRunRow>, square_hole_work_profile: __sdk::TableAppliedDiff<'r, SquareHoleWorkProfileRow>, story_event: __sdk::TableAppliedDiff<'r, StoryEvent>, @@ -3515,6 +3608,7 @@ pub struct AppliedDiff<'r> { user_browse_history: __sdk::TableAppliedDiff<'r, UserBrowseHistory>, visual_novel_agent_message: __sdk::TableAppliedDiff<'r, VisualNovelAgentMessageRow>, visual_novel_agent_session: __sdk::TableAppliedDiff<'r, VisualNovelAgentSessionRow>, + visual_novel_gallery_view: __sdk::TableAppliedDiff<'r, VisualNovelGalleryViewRow>, visual_novel_runtime_event: __sdk::TableAppliedDiff<'r, VisualNovelRuntimeEvent>, visual_novel_runtime_history_entry: __sdk::TableAppliedDiff<'r, VisualNovelRuntimeHistoryEntryRow>, @@ -3645,6 +3739,11 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { &self.big_fish_event, event, ); + callbacks.invoke_table_row_callbacks::( + "big_fish_gallery_view", + &self.big_fish_gallery_view, + event, + ); callbacks.invoke_table_row_callbacks::( "big_fish_runtime_run", &self.big_fish_runtime_run, @@ -3725,6 +3824,11 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { &self.match_3_d_agent_session, event, ); + callbacks.invoke_table_row_callbacks::( + "match_3_d_gallery_view", + &self.match_3_d_gallery_view, + event, + ); callbacks.invoke_table_row_callbacks::( "match_3_d_runtime_run", &self.match_3_d_runtime_run, @@ -3841,7 +3945,7 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { &self.puzzle_event, event, ); - callbacks.invoke_table_row_callbacks::( + callbacks.invoke_table_row_callbacks::( "puzzle_gallery_view", &self.puzzle_gallery_view, event, @@ -3892,6 +3996,11 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { &self.square_hole_agent_session, event, ); + callbacks.invoke_table_row_callbacks::( + "square_hole_gallery_view", + &self.square_hole_gallery_view, + event, + ); callbacks.invoke_table_row_callbacks::( "square_hole_runtime_run", &self.square_hole_runtime_run, @@ -3943,6 +4052,11 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> { &self.visual_novel_agent_session, event, ); + callbacks.invoke_table_row_callbacks::( + "visual_novel_gallery_view", + &self.visual_novel_gallery_view, + event, + ); callbacks.invoke_table_row_callbacks::( "visual_novel_runtime_event", &self.visual_novel_runtime_event, @@ -4647,6 +4761,7 @@ impl __sdk::SpacetimeModule for RemoteModule { big_fish_asset_slot_table::register_table(client_cache); big_fish_creation_session_table::register_table(client_cache); big_fish_event_table::register_table(client_cache); + big_fish_gallery_view_table::register_table(client_cache); big_fish_runtime_run_table::register_table(client_cache); chapter_progression_table::register_table(client_cache); creation_entry_config_table::register_table(client_cache); @@ -4663,6 +4778,7 @@ impl __sdk::SpacetimeModule for RemoteModule { inventory_slot_table::register_table(client_cache); match_3_d_agent_message_table::register_table(client_cache); match_3_d_agent_session_table::register_table(client_cache); + match_3_d_gallery_view_table::register_table(client_cache); match_3_d_runtime_run_table::register_table(client_cache); match_3_d_work_profile_table::register_table(client_cache); npc_state_table::register_table(client_cache); @@ -4698,6 +4814,7 @@ impl __sdk::SpacetimeModule for RemoteModule { runtime_snapshot_table::register_table(client_cache); square_hole_agent_message_table::register_table(client_cache); square_hole_agent_session_table::register_table(client_cache); + square_hole_gallery_view_table::register_table(client_cache); square_hole_runtime_run_table::register_table(client_cache); square_hole_work_profile_table::register_table(client_cache); story_event_table::register_table(client_cache); @@ -4709,6 +4826,7 @@ impl __sdk::SpacetimeModule for RemoteModule { user_browse_history_table::register_table(client_cache); visual_novel_agent_message_table::register_table(client_cache); visual_novel_agent_session_table::register_table(client_cache); + visual_novel_gallery_view_table::register_table(client_cache); visual_novel_runtime_event_table::register_table(client_cache); visual_novel_runtime_history_entry_table::register_table(client_cache); visual_novel_runtime_run_table::register_table(client_cache); @@ -4739,6 +4857,7 @@ impl __sdk::SpacetimeModule for RemoteModule { "big_fish_asset_slot", "big_fish_creation_session", "big_fish_event", + "big_fish_gallery_view", "big_fish_runtime_run", "chapter_progression", "creation_entry_config", @@ -4755,6 +4874,7 @@ impl __sdk::SpacetimeModule for RemoteModule { "inventory_slot", "match_3_d_agent_message", "match_3_d_agent_session", + "match_3_d_gallery_view", "match_3_d_runtime_run", "match_3_d_work_profile", "npc_state", @@ -4790,6 +4910,7 @@ impl __sdk::SpacetimeModule for RemoteModule { "runtime_snapshot", "square_hole_agent_message", "square_hole_agent_session", + "square_hole_gallery_view", "square_hole_runtime_run", "square_hole_work_profile", "story_event", @@ -4801,6 +4922,7 @@ impl __sdk::SpacetimeModule for RemoteModule { "user_browse_history", "visual_novel_agent_message", "visual_novel_agent_session", + "visual_novel_gallery_view", "visual_novel_runtime_event", "visual_novel_runtime_history_entry", "visual_novel_runtime_run", diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_anchor_item_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_anchor_item_type.rs new file mode 100644 index 00000000..1280d719 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_anchor_item_type.rs @@ -0,0 +1,20 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +use super::puzzle_anchor_status_type::PuzzleAnchorStatus; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct PuzzleAnchorItem { + pub key: String, + pub label: String, + pub value: String, + pub status: PuzzleAnchorStatus, +} + +impl __sdk::InModule for PuzzleAnchorItem { + type Module = super::RemoteModule; +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_anchor_pack_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_anchor_pack_type.rs new file mode 100644 index 00000000..db006609 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_anchor_pack_type.rs @@ -0,0 +1,21 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +use super::puzzle_anchor_item_type::PuzzleAnchorItem; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct PuzzleAnchorPack { + pub theme_promise: PuzzleAnchorItem, + pub visual_subject: PuzzleAnchorItem, + pub visual_mood: PuzzleAnchorItem, + pub composition_hooks: PuzzleAnchorItem, + pub tags_and_forbidden: PuzzleAnchorItem, +} + +impl __sdk::InModule for PuzzleAnchorPack { + type Module = super::RemoteModule; +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_anchor_status_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_anchor_status_type.rs new file mode 100644 index 00000000..feb7a650 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_anchor_status_type.rs @@ -0,0 +1,22 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +#[derive(Copy, Eq, Hash)] +pub enum PuzzleAnchorStatus { + Missing, + + Inferred, + + Confirmed, + + Locked, +} + +impl __sdk::InModule for PuzzleAnchorStatus { + type Module = super::RemoteModule; +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_audio_asset_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_audio_asset_type.rs new file mode 100644 index 00000000..e430a9c9 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_audio_asset_type.rs @@ -0,0 +1,22 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct PuzzleAudioAsset { + pub task_id: String, + pub provider: String, + pub asset_object_id: Option, + pub asset_kind: Option, + pub audio_src: String, + pub prompt: Option, + pub title: Option, + pub updated_at: Option, +} + +impl __sdk::InModule for PuzzleAudioAsset { + type Module = super::RemoteModule; +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_draft_level_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_draft_level_type.rs new file mode 100644 index 00000000..36f12999 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_draft_level_type.rs @@ -0,0 +1,30 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +use super::puzzle_audio_asset_type::PuzzleAudioAsset; +use super::puzzle_generated_image_candidate_type::PuzzleGeneratedImageCandidate; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct PuzzleDraftLevel { + pub level_id: String, + pub level_name: String, + pub picture_description: String, + pub picture_reference: Option, + pub ui_background_prompt: Option, + pub ui_background_image_src: Option, + pub ui_background_image_object_key: Option, + pub background_music: Option, + pub candidates: Vec, + pub selected_candidate_id: Option, + pub cover_image_src: Option, + pub cover_asset_id: Option, + pub generation_status: String, +} + +impl __sdk::InModule for PuzzleDraftLevel { + type Module = super::RemoteModule; +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_gallery_view_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_gallery_view_table.rs index 229fa37a..24857cee 100644 --- a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_gallery_view_table.rs +++ b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_gallery_view_table.rs @@ -2,246 +2,12 @@ // WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. #![allow(unused, clippy::all)] +use super::puzzle_anchor_pack_type::PuzzleAnchorPack; +use super::puzzle_draft_level_type::PuzzleDraftLevel; +use super::puzzle_publication_status_type::PuzzlePublicationStatus; +use super::puzzle_work_profile_type::PuzzleWorkProfile; use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, Copy, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Eq, Hash)] -pub enum PuzzleGalleryAnchorStatus { - Missing, - Inferred, - Confirmed, - Locked, -} - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct PuzzleGalleryAnchorItem { - pub key: String, - pub label: String, - pub value: String, - pub status: PuzzleGalleryAnchorStatus, -} - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct PuzzleGalleryAnchorPack { - pub theme_promise: PuzzleGalleryAnchorItem, - pub visual_subject: PuzzleGalleryAnchorItem, - pub visual_mood: PuzzleGalleryAnchorItem, - pub composition_hooks: PuzzleGalleryAnchorItem, - pub tags_and_forbidden: PuzzleGalleryAnchorItem, -} - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct PuzzleGalleryGeneratedImageCandidate { - pub candidate_id: String, - pub image_src: String, - pub asset_id: String, - pub prompt: String, - pub actual_prompt: Option, - pub source_type: String, - pub selected: bool, -} - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct PuzzleGalleryAudioAsset { - pub task_id: String, - pub provider: String, - pub asset_object_id: Option, - pub asset_kind: Option, - pub audio_src: String, - pub prompt: Option, - pub title: Option, - pub updated_at: Option, -} - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct PuzzleGalleryDraftLevel { - pub level_id: String, - pub level_name: String, - pub picture_description: String, - pub picture_reference: Option, - pub ui_background_prompt: Option, - pub ui_background_image_src: Option, - pub ui_background_image_object_key: Option, - pub background_music: Option, - pub candidates: Vec, - pub selected_candidate_id: Option, - pub cover_image_src: Option, - pub cover_asset_id: Option, - pub generation_status: String, -} - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, Copy, PartialEq, Debug)] -#[sats(crate = __lib)] -#[derive(Eq, Hash)] -pub enum PuzzleGalleryPublicationStatus { - Draft, - Published, -} - -#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] -#[sats(crate = __lib)] -pub struct PuzzleGalleryViewRow { - pub work_id: String, - pub profile_id: String, - pub owner_user_id: String, - pub source_session_id: Option, - pub author_display_name: String, - pub work_title: String, - pub work_description: String, - pub level_name: String, - pub summary: String, - pub theme_tags: Vec, - pub cover_image_src: Option, - pub cover_asset_id: Option, - pub levels: Vec, - pub publication_status: PuzzleGalleryPublicationStatus, - pub updated_at_micros: i64, - pub published_at_micros: Option, - pub play_count: u32, - pub remix_count: u32, - pub like_count: u32, - pub recent_play_count_7d: u32, - pub point_incentive_total_half_points: u64, - pub point_incentive_claimed_points: u64, - pub publish_ready: bool, - pub anchor_pack: PuzzleGalleryAnchorPack, -} - -impl From for module_puzzle::PuzzleAnchorStatus { - fn from(status: PuzzleGalleryAnchorStatus) -> Self { - match status { - PuzzleGalleryAnchorStatus::Missing => Self::Missing, - PuzzleGalleryAnchorStatus::Inferred => Self::Inferred, - PuzzleGalleryAnchorStatus::Confirmed => Self::Confirmed, - PuzzleGalleryAnchorStatus::Locked => Self::Locked, - } - } -} - -impl From for module_puzzle::PuzzleAnchorItem { - fn from(item: PuzzleGalleryAnchorItem) -> Self { - Self { - key: item.key, - label: item.label, - value: item.value, - status: item.status.into(), - } - } -} - -impl From for module_puzzle::PuzzleAnchorPack { - fn from(pack: PuzzleGalleryAnchorPack) -> Self { - Self { - theme_promise: pack.theme_promise.into(), - visual_subject: pack.visual_subject.into(), - visual_mood: pack.visual_mood.into(), - composition_hooks: pack.composition_hooks.into(), - tags_and_forbidden: pack.tags_and_forbidden.into(), - } - } -} - -impl From - for module_puzzle::PuzzleGeneratedImageCandidate -{ - fn from(candidate: PuzzleGalleryGeneratedImageCandidate) -> Self { - Self { - candidate_id: candidate.candidate_id, - image_src: candidate.image_src, - asset_id: candidate.asset_id, - prompt: candidate.prompt, - actual_prompt: candidate.actual_prompt, - source_type: candidate.source_type, - selected: candidate.selected, - } - } -} - -impl From for module_puzzle::PuzzleAudioAsset { - fn from(asset: PuzzleGalleryAudioAsset) -> Self { - Self { - task_id: asset.task_id, - provider: asset.provider, - asset_object_id: asset.asset_object_id, - asset_kind: asset.asset_kind, - audio_src: asset.audio_src, - prompt: asset.prompt, - title: asset.title, - updated_at: asset.updated_at, - } - } -} - -impl From for module_puzzle::PuzzleDraftLevel { - fn from(level: PuzzleGalleryDraftLevel) -> Self { - Self { - level_id: level.level_id, - level_name: level.level_name, - picture_description: level.picture_description, - picture_reference: level.picture_reference, - ui_background_prompt: level.ui_background_prompt, - ui_background_image_src: level.ui_background_image_src, - ui_background_image_object_key: level.ui_background_image_object_key, - background_music: level.background_music.map(Into::into), - candidates: level.candidates.into_iter().map(Into::into).collect(), - selected_candidate_id: level.selected_candidate_id, - cover_image_src: level.cover_image_src, - cover_asset_id: level.cover_asset_id, - generation_status: level.generation_status, - } - } -} - -impl From for module_puzzle::PuzzlePublicationStatus { - fn from(status: PuzzleGalleryPublicationStatus) -> Self { - match status { - PuzzleGalleryPublicationStatus::Draft => Self::Draft, - PuzzleGalleryPublicationStatus::Published => Self::Published, - } - } -} - -impl From for module_puzzle::PuzzleWorkProfile { - fn from(row: PuzzleGalleryViewRow) -> Self { - Self { - work_id: row.work_id, - profile_id: row.profile_id, - owner_user_id: row.owner_user_id, - source_session_id: row.source_session_id, - author_display_name: row.author_display_name, - work_title: row.work_title, - work_description: row.work_description, - level_name: row.level_name, - summary: row.summary, - theme_tags: row.theme_tags, - cover_image_src: row.cover_image_src, - cover_asset_id: row.cover_asset_id, - levels: row.levels.into_iter().map(Into::into).collect(), - publication_status: row.publication_status.into(), - updated_at_micros: row.updated_at_micros, - published_at_micros: row.published_at_micros, - play_count: row.play_count, - remix_count: row.remix_count, - like_count: row.like_count, - recent_play_count_7d: row.recent_play_count_7d, - point_incentive_total_half_points: row.point_incentive_total_half_points, - point_incentive_claimed_points: row.point_incentive_claimed_points, - publish_ready: row.publish_ready, - anchor_pack: row.anchor_pack.into(), - } - } -} - -impl __sdk::InModule for PuzzleGalleryViewRow { - type Module = super::RemoteModule; -} - /// Table handle for the table `puzzle_gallery_view`. /// /// Obtain a handle from the [`PuzzleGalleryViewTableAccess::puzzle_gallery_view`] method on [`super::RemoteTables`], @@ -251,7 +17,7 @@ impl __sdk::InModule for PuzzleGalleryViewRow { /// but to directly chain method calls, /// like `ctx.db.puzzle_gallery_view().on_insert(...)`. pub struct PuzzleGalleryViewTableHandle<'ctx> { - imp: __sdk::TableHandle, + imp: __sdk::TableHandle, ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, } @@ -270,7 +36,7 @@ impl PuzzleGalleryViewTableAccess for super::RemoteTables { PuzzleGalleryViewTableHandle { imp: self .imp - .get_table::("puzzle_gallery_view"), + .get_table::("puzzle_gallery_view"), ctx: std::marker::PhantomData, } } @@ -280,13 +46,13 @@ pub struct PuzzleGalleryViewInsertCallbackId(__sdk::CallbackId); pub struct PuzzleGalleryViewDeleteCallbackId(__sdk::CallbackId); impl<'ctx> __sdk::Table for PuzzleGalleryViewTableHandle<'ctx> { - type Row = PuzzleGalleryViewRow; + type Row = PuzzleWorkProfile; type EventContext = super::EventContext; fn count(&self) -> u64 { self.imp.count() } - fn iter(&self) -> impl Iterator + '_ { + fn iter(&self) -> impl Iterator + '_ { self.imp.iter() } @@ -319,32 +85,32 @@ impl<'ctx> __sdk::Table for PuzzleGalleryViewTableHandle<'ctx> { #[doc(hidden)] pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { - let _table = client_cache.get_or_make_table::("puzzle_gallery_view"); + let _table = client_cache.get_or_make_table::("puzzle_gallery_view"); } #[doc(hidden)] pub(super) fn parse_table_update( raw_updates: __ws::v2::TableUpdate, -) -> __sdk::Result<__sdk::TableUpdate> { +) -> __sdk::Result<__sdk::TableUpdate> { __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { - __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") + __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") .with_cause(e) .into() }) } #[allow(non_camel_case_types)] -/// Extension trait for query builder access to the table `PuzzleGalleryViewRow`. +/// Extension trait for query builder access to the table `PuzzleWorkProfile`. /// /// Implemented for [`__sdk::QueryTableAccessor`]. pub trait puzzle_gallery_viewQueryTableAccess { #[allow(non_snake_case)] - /// Get a query builder for the table `PuzzleGalleryViewRow`. - fn puzzle_gallery_view(&self) -> __sdk::__query_builder::Table; + /// Get a query builder for the table `PuzzleWorkProfile`. + fn puzzle_gallery_view(&self) -> __sdk::__query_builder::Table; } impl puzzle_gallery_viewQueryTableAccess for __sdk::QueryTableAccessor { - fn puzzle_gallery_view(&self) -> __sdk::__query_builder::Table { + fn puzzle_gallery_view(&self) -> __sdk::__query_builder::Table { __sdk::__query_builder::Table::new("puzzle_gallery_view") } } diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_generated_image_candidate_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_generated_image_candidate_type.rs new file mode 100644 index 00000000..6dd003d7 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_generated_image_candidate_type.rs @@ -0,0 +1,21 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct PuzzleGeneratedImageCandidate { + pub candidate_id: String, + pub image_src: String, + pub asset_id: String, + pub prompt: String, + pub actual_prompt: Option, + pub source_type: String, + pub selected: bool, +} + +impl __sdk::InModule for PuzzleGeneratedImageCandidate { + type Module = super::RemoteModule; +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/puzzle_work_profile_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_work_profile_type.rs new file mode 100644 index 00000000..6b41228e --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/puzzle_work_profile_type.rs @@ -0,0 +1,119 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +use super::puzzle_anchor_pack_type::PuzzleAnchorPack; +use super::puzzle_draft_level_type::PuzzleDraftLevel; +use super::puzzle_publication_status_type::PuzzlePublicationStatus; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct PuzzleWorkProfile { + pub work_id: String, + pub profile_id: String, + pub owner_user_id: String, + pub source_session_id: Option, + pub author_display_name: String, + pub work_title: String, + pub work_description: String, + pub level_name: String, + pub summary: String, + pub theme_tags: Vec, + pub cover_image_src: Option, + pub cover_asset_id: Option, + pub levels: Vec, + pub publication_status: PuzzlePublicationStatus, + pub updated_at_micros: i64, + pub published_at_micros: Option, + pub play_count: u32, + pub remix_count: u32, + pub like_count: u32, + pub recent_play_count_7_d: u32, + pub point_incentive_total_half_points: u64, + pub point_incentive_claimed_points: u64, + pub publish_ready: bool, + pub anchor_pack: PuzzleAnchorPack, +} + +impl __sdk::InModule for PuzzleWorkProfile { + type Module = super::RemoteModule; +} + +/// Column accessor struct for the table `PuzzleWorkProfile`. +/// +/// Provides typed access to columns for query building. +pub struct PuzzleWorkProfileCols { + pub work_id: __sdk::__query_builder::Col, + pub profile_id: __sdk::__query_builder::Col, + pub owner_user_id: __sdk::__query_builder::Col, + pub source_session_id: __sdk::__query_builder::Col>, + pub author_display_name: __sdk::__query_builder::Col, + pub work_title: __sdk::__query_builder::Col, + pub work_description: __sdk::__query_builder::Col, + pub level_name: __sdk::__query_builder::Col, + pub summary: __sdk::__query_builder::Col, + pub theme_tags: __sdk::__query_builder::Col>, + pub cover_image_src: __sdk::__query_builder::Col>, + pub cover_asset_id: __sdk::__query_builder::Col>, + pub levels: __sdk::__query_builder::Col>, + pub publication_status: __sdk::__query_builder::Col, + pub updated_at_micros: __sdk::__query_builder::Col, + pub published_at_micros: __sdk::__query_builder::Col>, + pub play_count: __sdk::__query_builder::Col, + pub remix_count: __sdk::__query_builder::Col, + pub like_count: __sdk::__query_builder::Col, + pub recent_play_count_7_d: __sdk::__query_builder::Col, + pub point_incentive_total_half_points: __sdk::__query_builder::Col, + pub point_incentive_claimed_points: __sdk::__query_builder::Col, + pub publish_ready: __sdk::__query_builder::Col, + pub anchor_pack: __sdk::__query_builder::Col, +} + +impl __sdk::__query_builder::HasCols for PuzzleWorkProfile { + type Cols = PuzzleWorkProfileCols; + fn cols(table_name: &'static str) -> Self::Cols { + PuzzleWorkProfileCols { + work_id: __sdk::__query_builder::Col::new(table_name, "work_id"), + profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), + owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), + source_session_id: __sdk::__query_builder::Col::new(table_name, "source_session_id"), + author_display_name: __sdk::__query_builder::Col::new( + table_name, + "author_display_name", + ), + work_title: __sdk::__query_builder::Col::new(table_name, "work_title"), + work_description: __sdk::__query_builder::Col::new(table_name, "work_description"), + level_name: __sdk::__query_builder::Col::new(table_name, "level_name"), + summary: __sdk::__query_builder::Col::new(table_name, "summary"), + theme_tags: __sdk::__query_builder::Col::new(table_name, "theme_tags"), + cover_image_src: __sdk::__query_builder::Col::new(table_name, "cover_image_src"), + cover_asset_id: __sdk::__query_builder::Col::new(table_name, "cover_asset_id"), + levels: __sdk::__query_builder::Col::new(table_name, "levels"), + publication_status: __sdk::__query_builder::Col::new(table_name, "publication_status"), + updated_at_micros: __sdk::__query_builder::Col::new(table_name, "updated_at_micros"), + published_at_micros: __sdk::__query_builder::Col::new( + table_name, + "published_at_micros", + ), + play_count: __sdk::__query_builder::Col::new(table_name, "play_count"), + remix_count: __sdk::__query_builder::Col::new(table_name, "remix_count"), + like_count: __sdk::__query_builder::Col::new(table_name, "like_count"), + recent_play_count_7_d: __sdk::__query_builder::Col::new( + table_name, + "recent_play_count_7_d", + ), + point_incentive_total_half_points: __sdk::__query_builder::Col::new( + table_name, + "point_incentive_total_half_points", + ), + point_incentive_claimed_points: __sdk::__query_builder::Col::new( + table_name, + "point_incentive_claimed_points", + ), + publish_ready: __sdk::__query_builder::Col::new(table_name, "publish_ready"), + anchor_pack: __sdk::__query_builder::Col::new(table_name, "anchor_pack"), + } + } +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_gallery_view_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_gallery_view_row_type.rs new file mode 100644 index 00000000..997f82d8 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_gallery_view_row_type.rs @@ -0,0 +1,108 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +use super::square_hole_hole_option_snapshot_type::SquareHoleHoleOptionSnapshot; +use super::square_hole_shape_option_snapshot_type::SquareHoleShapeOptionSnapshot; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct SquareHoleGalleryViewRow { + pub work_id: String, + pub profile_id: String, + pub owner_user_id: String, + pub source_session_id: String, + pub author_display_name: String, + pub game_name: String, + pub theme_text: String, + pub twist_rule: String, + pub summary_text: String, + pub tags: Vec, + pub cover_image_src: String, + pub background_prompt: String, + pub background_image_src: String, + pub shape_options: Vec, + pub hole_options: Vec, + pub shape_count: u32, + pub difficulty: u32, + pub publication_status: String, + pub publish_ready: bool, + pub play_count: u32, + pub updated_at_micros: i64, + pub published_at_micros: Option, +} + +impl __sdk::InModule for SquareHoleGalleryViewRow { + type Module = super::RemoteModule; +} + +/// Column accessor struct for the table `SquareHoleGalleryViewRow`. +/// +/// Provides typed access to columns for query building. +pub struct SquareHoleGalleryViewRowCols { + pub work_id: __sdk::__query_builder::Col, + pub profile_id: __sdk::__query_builder::Col, + pub owner_user_id: __sdk::__query_builder::Col, + pub source_session_id: __sdk::__query_builder::Col, + pub author_display_name: __sdk::__query_builder::Col, + pub game_name: __sdk::__query_builder::Col, + pub theme_text: __sdk::__query_builder::Col, + pub twist_rule: __sdk::__query_builder::Col, + pub summary_text: __sdk::__query_builder::Col, + pub tags: __sdk::__query_builder::Col>, + pub cover_image_src: __sdk::__query_builder::Col, + pub background_prompt: __sdk::__query_builder::Col, + pub background_image_src: __sdk::__query_builder::Col, + pub shape_options: + __sdk::__query_builder::Col>, + pub hole_options: + __sdk::__query_builder::Col>, + pub shape_count: __sdk::__query_builder::Col, + pub difficulty: __sdk::__query_builder::Col, + pub publication_status: __sdk::__query_builder::Col, + pub publish_ready: __sdk::__query_builder::Col, + pub play_count: __sdk::__query_builder::Col, + pub updated_at_micros: __sdk::__query_builder::Col, + pub published_at_micros: __sdk::__query_builder::Col>, +} + +impl __sdk::__query_builder::HasCols for SquareHoleGalleryViewRow { + type Cols = SquareHoleGalleryViewRowCols; + fn cols(table_name: &'static str) -> Self::Cols { + SquareHoleGalleryViewRowCols { + work_id: __sdk::__query_builder::Col::new(table_name, "work_id"), + profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), + owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), + source_session_id: __sdk::__query_builder::Col::new(table_name, "source_session_id"), + author_display_name: __sdk::__query_builder::Col::new( + table_name, + "author_display_name", + ), + game_name: __sdk::__query_builder::Col::new(table_name, "game_name"), + theme_text: __sdk::__query_builder::Col::new(table_name, "theme_text"), + twist_rule: __sdk::__query_builder::Col::new(table_name, "twist_rule"), + summary_text: __sdk::__query_builder::Col::new(table_name, "summary_text"), + tags: __sdk::__query_builder::Col::new(table_name, "tags"), + cover_image_src: __sdk::__query_builder::Col::new(table_name, "cover_image_src"), + background_prompt: __sdk::__query_builder::Col::new(table_name, "background_prompt"), + background_image_src: __sdk::__query_builder::Col::new( + table_name, + "background_image_src", + ), + shape_options: __sdk::__query_builder::Col::new(table_name, "shape_options"), + hole_options: __sdk::__query_builder::Col::new(table_name, "hole_options"), + shape_count: __sdk::__query_builder::Col::new(table_name, "shape_count"), + difficulty: __sdk::__query_builder::Col::new(table_name, "difficulty"), + publication_status: __sdk::__query_builder::Col::new(table_name, "publication_status"), + publish_ready: __sdk::__query_builder::Col::new(table_name, "publish_ready"), + play_count: __sdk::__query_builder::Col::new(table_name, "play_count"), + updated_at_micros: __sdk::__query_builder::Col::new(table_name, "updated_at_micros"), + published_at_micros: __sdk::__query_builder::Col::new( + table_name, + "published_at_micros", + ), + } + } +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_gallery_view_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_gallery_view_table.rs new file mode 100644 index 00000000..62f4b4b2 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_gallery_view_table.rs @@ -0,0 +1,116 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use super::square_hole_gallery_view_row_type::SquareHoleGalleryViewRow; +use super::square_hole_hole_option_snapshot_type::SquareHoleHoleOptionSnapshot; +use super::square_hole_shape_option_snapshot_type::SquareHoleShapeOptionSnapshot; +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +/// Table handle for the table `square_hole_gallery_view`. +/// +/// Obtain a handle from the [`SquareHoleGalleryViewTableAccess::square_hole_gallery_view`] method on [`super::RemoteTables`], +/// like `ctx.db.square_hole_gallery_view()`. +/// +/// Users are encouraged not to explicitly reference this type, +/// but to directly chain method calls, +/// like `ctx.db.square_hole_gallery_view().on_insert(...)`. +pub struct SquareHoleGalleryViewTableHandle<'ctx> { + imp: __sdk::TableHandle, + ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the table `square_hole_gallery_view`. +/// +/// Implemented for [`super::RemoteTables`]. +pub trait SquareHoleGalleryViewTableAccess { + #[allow(non_snake_case)] + /// Obtain a [`SquareHoleGalleryViewTableHandle`], which mediates access to the table `square_hole_gallery_view`. + fn square_hole_gallery_view(&self) -> SquareHoleGalleryViewTableHandle<'_>; +} + +impl SquareHoleGalleryViewTableAccess for super::RemoteTables { + fn square_hole_gallery_view(&self) -> SquareHoleGalleryViewTableHandle<'_> { + SquareHoleGalleryViewTableHandle { + imp: self + .imp + .get_table::("square_hole_gallery_view"), + ctx: std::marker::PhantomData, + } + } +} + +pub struct SquareHoleGalleryViewInsertCallbackId(__sdk::CallbackId); +pub struct SquareHoleGalleryViewDeleteCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::Table for SquareHoleGalleryViewTableHandle<'ctx> { + type Row = SquareHoleGalleryViewRow; + type EventContext = super::EventContext; + + fn count(&self) -> u64 { + self.imp.count() + } + fn iter(&self) -> impl Iterator + '_ { + self.imp.iter() + } + + type InsertCallbackId = SquareHoleGalleryViewInsertCallbackId; + + fn on_insert( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> SquareHoleGalleryViewInsertCallbackId { + SquareHoleGalleryViewInsertCallbackId(self.imp.on_insert(Box::new(callback))) + } + + fn remove_on_insert(&self, callback: SquareHoleGalleryViewInsertCallbackId) { + self.imp.remove_on_insert(callback.0) + } + + type DeleteCallbackId = SquareHoleGalleryViewDeleteCallbackId; + + fn on_delete( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> SquareHoleGalleryViewDeleteCallbackId { + SquareHoleGalleryViewDeleteCallbackId(self.imp.on_delete(Box::new(callback))) + } + + fn remove_on_delete(&self, callback: SquareHoleGalleryViewDeleteCallbackId) { + self.imp.remove_on_delete(callback.0) + } +} + +#[doc(hidden)] +pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { + let _table = + client_cache.get_or_make_table::("square_hole_gallery_view"); +} + +#[doc(hidden)] +pub(super) fn parse_table_update( + raw_updates: __ws::v2::TableUpdate, +) -> __sdk::Result<__sdk::TableUpdate> { + __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { + __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") + .with_cause(e) + .into() + }) +} + +#[allow(non_camel_case_types)] +/// Extension trait for query builder access to the table `SquareHoleGalleryViewRow`. +/// +/// Implemented for [`__sdk::QueryTableAccessor`]. +pub trait square_hole_gallery_viewQueryTableAccess { + #[allow(non_snake_case)] + /// Get a query builder for the table `SquareHoleGalleryViewRow`. + fn square_hole_gallery_view(&self) -> __sdk::__query_builder::Table; +} + +impl square_hole_gallery_viewQueryTableAccess for __sdk::QueryTableAccessor { + fn square_hole_gallery_view(&self) -> __sdk::__query_builder::Table { + __sdk::__query_builder::Table::new("square_hole_gallery_view") + } +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_hole_option_snapshot_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_hole_option_snapshot_type.rs new file mode 100644 index 00000000..e0251660 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_hole_option_snapshot_type.rs @@ -0,0 +1,19 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct SquareHoleHoleOptionSnapshot { + pub hole_id: String, + pub hole_kind: String, + pub label: String, + pub image_prompt: String, + pub image_src: String, +} + +impl __sdk::InModule for SquareHoleHoleOptionSnapshot { + type Module = super::RemoteModule; +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/square_hole_shape_option_snapshot_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_shape_option_snapshot_type.rs new file mode 100644 index 00000000..8a0d062e --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/square_hole_shape_option_snapshot_type.rs @@ -0,0 +1,20 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct SquareHoleShapeOptionSnapshot { + pub option_id: String, + pub shape_kind: String, + pub label: String, + pub target_hole_id: String, + pub image_prompt: String, + pub image_src: String, +} + +impl __sdk::InModule for SquareHoleShapeOptionSnapshot { + type Module = super::RemoteModule; +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_gallery_view_row_type.rs b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_gallery_view_row_type.rs new file mode 100644 index 00000000..e0199208 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_gallery_view_row_type.rs @@ -0,0 +1,82 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)] +#[sats(crate = __lib)] +pub struct VisualNovelGalleryViewRow { + pub work_id: String, + pub profile_id: String, + pub owner_user_id: String, + pub source_session_id: Option, + pub author_display_name: String, + pub work_title: String, + pub work_description: String, + pub tags: Vec, + pub cover_image_src: Option, + pub source_asset_ids: Vec, + pub publication_status: String, + pub publish_ready: bool, + pub play_count: u32, + pub created_at_micros: i64, + pub updated_at_micros: i64, + pub published_at_micros: Option, +} + +impl __sdk::InModule for VisualNovelGalleryViewRow { + type Module = super::RemoteModule; +} + +/// Column accessor struct for the table `VisualNovelGalleryViewRow`. +/// +/// Provides typed access to columns for query building. +pub struct VisualNovelGalleryViewRowCols { + pub work_id: __sdk::__query_builder::Col, + pub profile_id: __sdk::__query_builder::Col, + pub owner_user_id: __sdk::__query_builder::Col, + pub source_session_id: __sdk::__query_builder::Col>, + pub author_display_name: __sdk::__query_builder::Col, + pub work_title: __sdk::__query_builder::Col, + pub work_description: __sdk::__query_builder::Col, + pub tags: __sdk::__query_builder::Col>, + pub cover_image_src: __sdk::__query_builder::Col>, + pub source_asset_ids: __sdk::__query_builder::Col>, + pub publication_status: __sdk::__query_builder::Col, + pub publish_ready: __sdk::__query_builder::Col, + pub play_count: __sdk::__query_builder::Col, + pub created_at_micros: __sdk::__query_builder::Col, + pub updated_at_micros: __sdk::__query_builder::Col, + pub published_at_micros: __sdk::__query_builder::Col>, +} + +impl __sdk::__query_builder::HasCols for VisualNovelGalleryViewRow { + type Cols = VisualNovelGalleryViewRowCols; + fn cols(table_name: &'static str) -> Self::Cols { + VisualNovelGalleryViewRowCols { + work_id: __sdk::__query_builder::Col::new(table_name, "work_id"), + profile_id: __sdk::__query_builder::Col::new(table_name, "profile_id"), + owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"), + source_session_id: __sdk::__query_builder::Col::new(table_name, "source_session_id"), + author_display_name: __sdk::__query_builder::Col::new( + table_name, + "author_display_name", + ), + work_title: __sdk::__query_builder::Col::new(table_name, "work_title"), + work_description: __sdk::__query_builder::Col::new(table_name, "work_description"), + tags: __sdk::__query_builder::Col::new(table_name, "tags"), + cover_image_src: __sdk::__query_builder::Col::new(table_name, "cover_image_src"), + source_asset_ids: __sdk::__query_builder::Col::new(table_name, "source_asset_ids"), + publication_status: __sdk::__query_builder::Col::new(table_name, "publication_status"), + publish_ready: __sdk::__query_builder::Col::new(table_name, "publish_ready"), + play_count: __sdk::__query_builder::Col::new(table_name, "play_count"), + created_at_micros: __sdk::__query_builder::Col::new(table_name, "created_at_micros"), + updated_at_micros: __sdk::__query_builder::Col::new(table_name, "updated_at_micros"), + published_at_micros: __sdk::__query_builder::Col::new( + table_name, + "published_at_micros", + ), + } + } +} diff --git a/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_gallery_view_table.rs b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_gallery_view_table.rs new file mode 100644 index 00000000..a1f70563 --- /dev/null +++ b/server-rs/crates/spacetime-client/src/module_bindings/visual_novel_gallery_view_table.rs @@ -0,0 +1,117 @@ +// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE +// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD. + +#![allow(unused, clippy::all)] +use super::visual_novel_gallery_view_row_type::VisualNovelGalleryViewRow; +use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws}; + +/// Table handle for the table `visual_novel_gallery_view`. +/// +/// Obtain a handle from the [`VisualNovelGalleryViewTableAccess::visual_novel_gallery_view`] method on [`super::RemoteTables`], +/// like `ctx.db.visual_novel_gallery_view()`. +/// +/// Users are encouraged not to explicitly reference this type, +/// but to directly chain method calls, +/// like `ctx.db.visual_novel_gallery_view().on_insert(...)`. +pub struct VisualNovelGalleryViewTableHandle<'ctx> { + imp: __sdk::TableHandle, + ctx: std::marker::PhantomData<&'ctx super::RemoteTables>, +} + +#[allow(non_camel_case_types)] +/// Extension trait for access to the table `visual_novel_gallery_view`. +/// +/// Implemented for [`super::RemoteTables`]. +pub trait VisualNovelGalleryViewTableAccess { + #[allow(non_snake_case)] + /// Obtain a [`VisualNovelGalleryViewTableHandle`], which mediates access to the table `visual_novel_gallery_view`. + fn visual_novel_gallery_view(&self) -> VisualNovelGalleryViewTableHandle<'_>; +} + +impl VisualNovelGalleryViewTableAccess for super::RemoteTables { + fn visual_novel_gallery_view(&self) -> VisualNovelGalleryViewTableHandle<'_> { + VisualNovelGalleryViewTableHandle { + imp: self + .imp + .get_table::("visual_novel_gallery_view"), + ctx: std::marker::PhantomData, + } + } +} + +pub struct VisualNovelGalleryViewInsertCallbackId(__sdk::CallbackId); +pub struct VisualNovelGalleryViewDeleteCallbackId(__sdk::CallbackId); + +impl<'ctx> __sdk::Table for VisualNovelGalleryViewTableHandle<'ctx> { + type Row = VisualNovelGalleryViewRow; + type EventContext = super::EventContext; + + fn count(&self) -> u64 { + self.imp.count() + } + fn iter(&self) -> impl Iterator + '_ { + self.imp.iter() + } + + type InsertCallbackId = VisualNovelGalleryViewInsertCallbackId; + + fn on_insert( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> VisualNovelGalleryViewInsertCallbackId { + VisualNovelGalleryViewInsertCallbackId(self.imp.on_insert(Box::new(callback))) + } + + fn remove_on_insert(&self, callback: VisualNovelGalleryViewInsertCallbackId) { + self.imp.remove_on_insert(callback.0) + } + + type DeleteCallbackId = VisualNovelGalleryViewDeleteCallbackId; + + fn on_delete( + &self, + callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static, + ) -> VisualNovelGalleryViewDeleteCallbackId { + VisualNovelGalleryViewDeleteCallbackId(self.imp.on_delete(Box::new(callback))) + } + + fn remove_on_delete(&self, callback: VisualNovelGalleryViewDeleteCallbackId) { + self.imp.remove_on_delete(callback.0) + } +} + +#[doc(hidden)] +pub(super) fn register_table(client_cache: &mut __sdk::ClientCache) { + let _table = + client_cache.get_or_make_table::("visual_novel_gallery_view"); +} + +#[doc(hidden)] +pub(super) fn parse_table_update( + raw_updates: __ws::v2::TableUpdate, +) -> __sdk::Result<__sdk::TableUpdate> { + __sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| { + __sdk::InternalError::failed_parse("TableUpdate", "TableUpdate") + .with_cause(e) + .into() + }) +} + +#[allow(non_camel_case_types)] +/// Extension trait for query builder access to the table `VisualNovelGalleryViewRow`. +/// +/// Implemented for [`__sdk::QueryTableAccessor`]. +pub trait visual_novel_gallery_viewQueryTableAccess { + #[allow(non_snake_case)] + /// Get a query builder for the table `VisualNovelGalleryViewRow`. + fn visual_novel_gallery_view(&self) + -> __sdk::__query_builder::Table; +} + +impl visual_novel_gallery_viewQueryTableAccess for __sdk::QueryTableAccessor { + fn visual_novel_gallery_view( + &self, + ) -> __sdk::__query_builder::Table { + __sdk::__query_builder::Table::new("visual_novel_gallery_view") + } +} diff --git a/server-rs/crates/spacetime-client/src/puzzle.rs b/server-rs/crates/spacetime-client/src/puzzle.rs index 3bd25ecd..7bb69899 100644 --- a/server-rs/crates/spacetime-client/src/puzzle.rs +++ b/server-rs/crates/spacetime-client/src/puzzle.rs @@ -414,7 +414,7 @@ impl SpacetimeClient { Ok(items .into_iter() .map(|item| { - let mut record = map_puzzle_work_profile(item.into()); + let mut record = map_puzzle_work_profile_row(item); record.recent_play_count_7d = recent_play_counts .get(&record.profile_id) .copied() diff --git a/server-rs/crates/spacetime-client/src/square_hole.rs b/server-rs/crates/spacetime-client/src/square_hole.rs index ffeb616f..d59c2c56 100644 --- a/server-rs/crates/spacetime-client/src/square_hole.rs +++ b/server-rs/crates/spacetime-client/src/square_hole.rs @@ -228,10 +228,22 @@ impl SpacetimeClient { pub async fn list_square_hole_gallery( &self, ) -> Result, SpacetimeClientError> { - self.list_square_hole_works_with_input(SquareHoleWorksListInput { - // 中文注释:公开广场只依赖 published_only,owner_user_id 用固定值通过输入校验。 - owner_user_id: "square-hole-public-gallery".to_string(), - published_only: true, + self.read_after_connect(move |connection| { + let mut items = connection + .db() + .square_hole_gallery_view() + .iter() + .collect::>(); + items.sort_by(|left, right| { + right + .updated_at_micros + .cmp(&left.updated_at_micros) + .then_with(|| left.profile_id.cmp(&right.profile_id)) + }); + Ok(items + .into_iter() + .map(map_square_hole_gallery_view_row) + .collect()) }) .await } diff --git a/server-rs/crates/spacetime-client/src/visual_novel.rs b/server-rs/crates/spacetime-client/src/visual_novel.rs index bbf7a00f..5d736ffb 100644 --- a/server-rs/crates/spacetime-client/src/visual_novel.rs +++ b/server-rs/crates/spacetime-client/src/visual_novel.rs @@ -6,9 +6,9 @@ use crate::mapper::{ VisualNovelRunSnapshotRecordInput, VisualNovelRunStartRecordInput, VisualNovelRuntimeEventRecord, VisualNovelWorkCompileRecordInput, VisualNovelWorkProfileRecord, VisualNovelWorkUpdateRecordInput, map_visual_novel_agent_session_procedure_result, - map_visual_novel_history_procedure_result, map_visual_novel_run_procedure_result, - map_visual_novel_runtime_event_procedure_result, map_visual_novel_work_procedure_result, - map_visual_novel_works_procedure_result, + map_visual_novel_gallery_view_row, map_visual_novel_history_procedure_result, + map_visual_novel_run_procedure_result, map_visual_novel_runtime_event_procedure_result, + map_visual_novel_work_procedure_result, map_visual_novel_works_procedure_result, }; impl SpacetimeClient { @@ -239,10 +239,22 @@ impl SpacetimeClient { pub async fn list_visual_novel_gallery( &self, ) -> Result, SpacetimeClientError> { - self.list_visual_novel_works_with_input(VisualNovelWorksListInput { - // 中文注释:公开列表只依赖 published_only,owner_user_id 用固定值满足 procedure 输入契约。 - owner_user_id: "visual-novel-public-gallery".to_string(), - published_only: true, + self.read_after_connect(move |connection| { + let mut items = connection + .db() + .visual_novel_gallery_view() + .iter() + .collect::>(); + items.sort_by(|left, right| { + right + .updated_at_micros + .cmp(&left.updated_at_micros) + .then_with(|| left.profile_id.cmp(&right.profile_id)) + }); + Ok(items + .into_iter() + .map(map_visual_novel_gallery_view_row) + .collect()) }) .await } diff --git a/server-rs/crates/spacetime-module/src/big_fish/session.rs b/server-rs/crates/spacetime-module/src/big_fish/session.rs index b7815e0a..6673b488 100644 --- a/server-rs/crates/spacetime-module/src/big_fish/session.rs +++ b/server-rs/crates/spacetime-module/src/big_fish/session.rs @@ -8,9 +8,42 @@ use crate::runtime::{ }; use crate::*; use module_big_fish::{EvaluateBigFishPublishReadinessCommand, evaluate_publish_readiness}; +use spacetimedb::AnonymousViewContext; const INITIAL_BIG_FISH_CREATION_PROGRESS_PERCENT: u32 = 0; +/// 大鱼吃小鱼公开广场列表投影。 +/// +/// 公开列表从已发布 creation session 生成卡片字段;7 日播放数由 +/// `api-server` 订阅 `public_work_play_daily_stat` 后在本地聚合。 +#[spacetimedb::view(accessor = big_fish_gallery_view, public)] +pub fn big_fish_gallery_view(ctx: &AnonymousViewContext) -> Vec { + let mut items = ctx + .db + .big_fish_creation_session() + .by_big_fish_session_stage() + .filter(BigFishCreationStage::Published) + .filter_map(|row| match build_big_fish_gallery_view_row(ctx, &row) { + Ok(snapshot) => Some(snapshot), + Err(error) => { + log::warn!( + "大鱼吃小鱼公开广场 view 跳过损坏的作品投影 session_id={}: {}", + row.session_id, + error + ); + None + } + }) + .collect::>(); + items.sort_by(|left, right| { + right + .updated_at_micros + .cmp(&left.updated_at_micros) + .then_with(|| left.source_session_id.cmp(&right.source_session_id)) + }); + items +} + #[spacetimedb::procedure] pub fn create_big_fish_session( ctx: &mut ProcedureContext, @@ -988,6 +1021,16 @@ pub(crate) fn build_big_fish_work_summary( ctx: &ReducerContext, row: &BigFishCreationSession, now_micros: i64, +) -> Result { + let mut summary = build_big_fish_work_summary_without_recent_count(ctx, row)?; + summary.recent_play_count_7d = + count_recent_public_work_plays(ctx, "big-fish", &row.session_id, now_micros); + Ok(summary) +} + +fn build_big_fish_work_summary_without_recent_count( + ctx: &ReducerContext, + row: &BigFishCreationSession, ) -> Result { let draft = row .draft_json @@ -1052,12 +1095,7 @@ pub(crate) fn build_big_fish_work_summary( play_count: row.play_count, remix_count: row.remix_count, like_count: row.like_count, - recent_play_count_7d: count_recent_public_work_plays( - ctx, - "big-fish", - &row.session_id, - now_micros, - ), + recent_play_count_7d: 0, published_at_micros: row .published_at .or_else(|| (row.stage == BigFishCreationStage::Published).then_some(row.updated_at)) @@ -1065,6 +1103,113 @@ pub(crate) fn build_big_fish_work_summary( }) } +fn build_big_fish_gallery_view_row( + ctx: &AnonymousViewContext, + row: &BigFishCreationSession, +) -> Result { + let draft = row + .draft_json + .as_deref() + .map(deserialize_draft) + .transpose() + .map_err(|error| format!("big_fish.draft_json 非法: {error}"))?; + let asset_slots = list_big_fish_asset_slots_for_view(ctx, &row.session_id); + let coverage = build_asset_coverage(draft.as_ref(), &asset_slots); + let cover_image_src = asset_slots + .iter() + .find(|slot| slot.asset_kind == BigFishAssetKind::StageBackground) + .and_then(|slot| slot.asset_url.clone()) + .or_else(|| { + asset_slots + .iter() + .find(|slot| slot.asset_kind == BigFishAssetKind::LevelMainImage) + .and_then(|slot| slot.asset_url.clone()) + }); + let title = draft + .as_ref() + .map(|value| value.title.clone()) + .filter(|value| !value.trim().is_empty()) + .unwrap_or_else(|| "未命名大鱼草稿".to_string()); + let subtitle = draft + .as_ref() + .map(|value| value.subtitle.clone()) + .filter(|value| !value.trim().is_empty()) + .unwrap_or_else(|| "等待整理玩法草稿".to_string()); + let summary = draft + .as_ref() + .map(|value| value.core_fun.clone()) + .filter(|value| !value.trim().is_empty()) + .unwrap_or_else(|| { + row.last_assistant_reply + .clone() + .unwrap_or_else(|| "继续补齐锚点后即可生成玩法草稿。".to_string()) + }); + + Ok(BigFishWorkSummarySnapshot { + work_id: format!("big-fish-work-{}", row.session_id), + source_session_id: row.session_id.clone(), + owner_user_id: row.owner_user_id.clone(), + title, + subtitle, + summary, + cover_image_src, + status: if row.stage == BigFishCreationStage::Published { + "published".to_string() + } else { + "draft".to_string() + }, + updated_at_micros: row.updated_at.to_micros_since_unix_epoch(), + publish_ready: coverage.publish_ready, + level_count: draft + .as_ref() + .map(|value| value.runtime_params.level_count) + .unwrap_or(BIG_FISH_DEFAULT_LEVEL_COUNT), + level_main_image_ready_count: coverage.level_main_image_ready_count, + level_motion_ready_count: coverage.level_motion_ready_count, + background_ready: coverage.background_ready, + play_count: row.play_count, + remix_count: row.remix_count, + like_count: row.like_count, + recent_play_count_7d: 0, + published_at_micros: row + .published_at + .or_else(|| (row.stage == BigFishCreationStage::Published).then_some(row.updated_at)) + .map(|value| value.to_micros_since_unix_epoch()), + }) +} + +fn list_big_fish_asset_slots_for_view( + ctx: &AnonymousViewContext, + session_id: &str, +) -> Vec { + let mut slots = ctx + .db + .big_fish_asset_slot() + .by_big_fish_asset_session_id() + .filter(session_id) + .map(|slot| BigFishAssetSlotSnapshot { + slot_id: slot.slot_id, + session_id: slot.session_id, + asset_kind: slot.asset_kind, + level: slot.level, + motion_key: slot.motion_key, + status: slot.status, + asset_url: slot.asset_url, + prompt_snapshot: slot.prompt_snapshot, + updated_at_micros: slot.updated_at.to_micros_since_unix_epoch(), + }) + .collect::>(); + slots.sort_by_key(|slot| { + ( + slot.level.unwrap_or(0), + slot.asset_kind.as_str().to_string(), + slot.motion_key.clone().unwrap_or_default(), + slot.slot_id.clone(), + ) + }); + slots +} + fn build_public_big_fish_gallery_list_input() -> BigFishWorksListInput { BigFishWorksListInput { // 中文注释:published_only 分支不会按 owner 过滤;非空占位用于兼容旧部署模块的前置校验。 diff --git a/server-rs/crates/spacetime-module/src/big_fish/tables.rs b/server-rs/crates/spacetime-module/src/big_fish/tables.rs index 997371e8..fa480120 100644 --- a/server-rs/crates/spacetime-module/src/big_fish/tables.rs +++ b/server-rs/crates/spacetime-module/src/big_fish/tables.rs @@ -2,7 +2,8 @@ use crate::*; #[spacetimedb::table( accessor = big_fish_creation_session, - index(accessor = by_big_fish_session_owner_user_id, btree(columns = [owner_user_id])) + index(accessor = by_big_fish_session_owner_user_id, btree(columns = [owner_user_id])), + index(accessor = by_big_fish_session_stage, btree(columns = [stage])) )] pub struct BigFishCreationSession { #[primary_key] diff --git a/server-rs/crates/spacetime-module/src/match3d/mod.rs b/server-rs/crates/spacetime-module/src/match3d/mod.rs index 70a38de2..e7c641b7 100644 --- a/server-rs/crates/spacetime-module/src/match3d/mod.rs +++ b/server-rs/crates/spacetime-module/src/match3d/mod.rs @@ -19,6 +19,62 @@ use module_match3d::{ use serde::Serialize; use serde::de::DeserializeOwned; use serde_json::Value; +use spacetimedb::AnonymousViewContext; + +/// 抓大鹅公开广场列表投影。 +/// +/// `match3d_work_profile` 是玩法源表,HTTP gallery 只订阅这个轻量 view, +/// 避免每个公开列表请求重新调用 procedure 扫描和组装全量列表。 +#[spacetimedb::view(accessor = match3d_gallery_view, public)] +pub fn match3d_gallery_view(ctx: &AnonymousViewContext) -> Vec { + let mut items = ctx + .db + .match3d_work_profile() + .by_match3d_work_publication_status() + .filter(MATCH3D_PUBLICATION_PUBLISHED) + .filter_map(|row| match build_gallery_view_row(&row) { + Ok(item) => Some(item), + Err(error) => { + log::warn!( + "抓大鹅公开广场 view 跳过损坏的作品投影 profile_id={}: {}", + row.profile_id, + error + ); + None + } + }) + .collect::>(); + items.sort_by(|left, right| { + right + .updated_at_micros + .cmp(&left.updated_at_micros) + .then_with(|| left.profile_id.cmp(&right.profile_id)) + }); + items +} + +#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] +pub struct Match3DGalleryViewRow { + pub profile_id: String, + pub owner_user_id: String, + pub source_session_id: String, + pub author_display_name: String, + pub game_name: String, + pub theme_text: String, + pub summary_text: String, + pub tags: Vec, + pub cover_image_src: String, + pub cover_asset_id: String, + pub reference_image_src: Option, + pub clear_count: u32, + pub difficulty: u32, + pub publication_status: String, + pub publish_ready: bool, + pub play_count: u32, + pub updated_at_micros: i64, + pub published_at_micros: Option, + pub generated_item_assets_json: Option, +} #[spacetimedb::procedure] pub fn create_match3d_agent_session( @@ -1004,6 +1060,35 @@ fn build_work_snapshot(row: &Match3DWorkProfileRow) -> Result Result { + let config = parse_config(&row.config_json)?; + Ok(Match3DGalleryViewRow { + profile_id: row.profile_id.clone(), + owner_user_id: row.owner_user_id.clone(), + source_session_id: row.source_session_id.clone(), + author_display_name: row.author_display_name.clone(), + game_name: row.game_name.clone(), + theme_text: row.theme_text.clone(), + summary_text: row.summary_text.clone(), + tags: parse_tags(&row.tags_json)?, + cover_image_src: row.cover_image_src.clone(), + cover_asset_id: row.cover_asset_id.clone(), + reference_image_src: config.reference_image_src, + clear_count: row.clear_count, + difficulty: row.difficulty, + publication_status: row.publication_status.clone(), + publish_ready: is_work_publish_ready(row), + play_count: row.play_count, + updated_at_micros: row.updated_at.to_micros_since_unix_epoch(), + published_at_micros: row + .published_at + .map(|value| value.to_micros_since_unix_epoch()), + generated_item_assets_json: normalize_generated_item_assets_json( + row.generated_item_assets_json.as_deref(), + )?, + }) +} + fn build_initial_run_snapshot( run_id: &str, work: &Match3DWorkProfileRow, @@ -1908,8 +1993,7 @@ mod tests { }; let row_json = to_json_string(&draft); - let restored = - parse_json::(&row_json, "match3d draft_json").unwrap(); + let restored = parse_json::(&row_json, "match3d draft_json").unwrap(); assert_eq!( restored.generated_item_assets_json.as_deref(), diff --git a/server-rs/crates/spacetime-module/src/puzzle.rs b/server-rs/crates/spacetime-module/src/puzzle.rs index 1d65956d..9f0e2c3d 100644 --- a/server-rs/crates/spacetime-module/src/puzzle.rs +++ b/server-rs/crates/spacetime-module/src/puzzle.rs @@ -125,17 +125,19 @@ pub fn puzzle_gallery_view(ctx: &AnonymousViewContext) -> Vec .puzzle_work_profile() .by_puzzle_work_publication_status() .filter(PuzzlePublicationStatus::Published) - .filter_map(|row| match build_puzzle_work_profile_from_row_without_recent_count(&row) { - Ok(profile) => Some(profile), - Err(error) => { - log::warn!( - "拼图广场 view 跳过损坏的作品投影 profile_id={}: {}", - row.profile_id, - error - ); - None - } - }) + .filter_map( + |row| match build_puzzle_work_profile_from_row_without_recent_count(&row) { + Ok(profile) => Some(profile), + Err(error) => { + log::warn!( + "拼图广场 view 跳过损坏的作品投影 profile_id={}: {}", + row.profile_id, + error + ); + None + } + }, + ) .collect::>(); items.sort_by(|left, right| right.updated_at_micros.cmp(&left.updated_at_micros)); items diff --git a/server-rs/crates/spacetime-module/src/square_hole/mod.rs b/server-rs/crates/spacetime-module/src/square_hole/mod.rs index 0d371ec0..8fb909e4 100644 --- a/server-rs/crates/spacetime-module/src/square_hole/mod.rs +++ b/server-rs/crates/spacetime-module/src/square_hole/mod.rs @@ -26,6 +26,65 @@ use module_square_hole::{ }; use serde::Serialize; use serde::de::DeserializeOwned; +use spacetimedb::AnonymousViewContext; + +/// 方洞挑战公开广场列表投影。 +/// +/// HTTP gallery 通过 `spacetime-client` 订阅该 view 后读本地 cache, +/// 不再在每个公开列表请求里调用 `list_square_hole_works` procedure。 +#[spacetimedb::view(accessor = square_hole_gallery_view, public)] +pub fn square_hole_gallery_view(ctx: &AnonymousViewContext) -> Vec { + let mut items = ctx + .db + .square_hole_work_profile() + .by_square_hole_work_publication_status() + .filter(SQUARE_HOLE_PUBLICATION_PUBLISHED) + .filter_map(|row| match build_gallery_view_row(&row) { + Ok(item) => Some(item), + Err(error) => { + log::warn!( + "方洞挑战公开广场 view 跳过损坏的作品投影 profile_id={}: {}", + row.profile_id, + error + ); + None + } + }) + .collect::>(); + items.sort_by(|left, right| { + right + .updated_at_micros + .cmp(&left.updated_at_micros) + .then_with(|| left.profile_id.cmp(&right.profile_id)) + }); + items +} + +#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] +pub struct SquareHoleGalleryViewRow { + pub work_id: String, + pub profile_id: String, + pub owner_user_id: String, + pub source_session_id: String, + pub author_display_name: String, + pub game_name: String, + pub theme_text: String, + pub twist_rule: String, + pub summary_text: String, + pub tags: Vec, + pub cover_image_src: String, + pub background_prompt: String, + pub background_image_src: String, + pub shape_options: Vec, + pub hole_options: Vec, + pub shape_count: u32, + pub difficulty: u32, + pub publication_status: String, + pub publish_ready: bool, + pub play_count: u32, + pub updated_at_micros: i64, + pub published_at_micros: Option, +} #[spacetimedb::procedure] pub fn create_square_hole_agent_session( @@ -880,6 +939,38 @@ fn build_work_snapshot(row: &SquareHoleWorkProfileRow) -> Result Result { + let config = parse_config(&row.config_json)?; + Ok(SquareHoleGalleryViewRow { + work_id: row.work_id.clone(), + profile_id: row.profile_id.clone(), + owner_user_id: row.owner_user_id.clone(), + source_session_id: row.source_session_id.clone(), + author_display_name: row.author_display_name.clone(), + game_name: row.game_name.clone(), + theme_text: row.theme_text.clone(), + twist_rule: row.twist_rule.clone(), + summary_text: row.summary_text.clone(), + tags: parse_tags(&row.tags_json)?, + cover_image_src: row.cover_image_src.clone(), + background_prompt: config.background_prompt, + background_image_src: config.background_image_src, + shape_options: config.shape_options, + hole_options: config.hole_options, + shape_count: row.shape_count, + difficulty: row.difficulty, + publication_status: row.publication_status.clone(), + publish_ready: is_work_publish_ready(row), + play_count: row.play_count, + updated_at_micros: row.updated_at.to_micros_since_unix_epoch(), + published_at_micros: row + .published_at + .map(|value| value.to_micros_since_unix_epoch()), + }) +} + fn refresh_run_row( ctx: &ReducerContext, row: SquareHoleRuntimeRunRow, diff --git a/server-rs/crates/spacetime-module/src/square_hole/types.rs b/server-rs/crates/spacetime-module/src/square_hole/types.rs index 232002e1..ae8a1766 100644 --- a/server-rs/crates/spacetime-module/src/square_hole/types.rs +++ b/server-rs/crates/spacetime-module/src/square_hole/types.rs @@ -222,7 +222,7 @@ pub struct SquareHoleCreatorConfigSnapshot { pub background_image_src: String, } -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct SquareHoleShapeOptionSnapshot { pub option_id: String, @@ -235,7 +235,7 @@ pub struct SquareHoleShapeOptionSnapshot { pub image_src: String, } -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct SquareHoleHoleOptionSnapshot { pub hole_id: String, diff --git a/server-rs/crates/spacetime-module/src/visual_novel.rs b/server-rs/crates/spacetime-module/src/visual_novel.rs index 1e64046c..2fe82fa7 100644 --- a/server-rs/crates/spacetime-module/src/visual_novel.rs +++ b/server-rs/crates/spacetime-module/src/visual_novel.rs @@ -1,6 +1,7 @@ use crate::*; use serde::Serialize; use serde::de::DeserializeOwned; +use spacetimedb::AnonymousViewContext; pub const VISUAL_NOVEL_SOURCE_IDEA: &str = "idea"; pub const VISUAL_NOVEL_SOURCE_DOCUMENT: &str = "document"; @@ -166,6 +167,58 @@ pub struct VisualNovelRuntimeEvent { pub(crate) occurred_at: Timestamp, } +/// 视觉小说公开广场列表投影。 +/// +/// 该 view 只暴露已发布作品卡片需要的公开字段,HTTP gallery 订阅后 +/// 从本地 cache 读取,避免每个列表请求调用 `list_visual_novel_works` procedure。 +#[spacetimedb::view(accessor = visual_novel_gallery_view, public)] +pub fn visual_novel_gallery_view(ctx: &AnonymousViewContext) -> Vec { + let mut items = ctx + .db + .visual_novel_work_profile() + .by_visual_novel_work_publication_status() + .filter(VISUAL_NOVEL_PUBLICATION_PUBLISHED) + .filter_map(|row| match build_gallery_view_row(&row) { + Ok(item) => Some(item), + Err(error) => { + log::warn!( + "视觉小说公开广场 view 跳过损坏的作品投影 profile_id={}: {}", + row.profile_id, + error + ); + None + } + }) + .collect::>(); + items.sort_by(|left, right| { + right + .updated_at_micros + .cmp(&left.updated_at_micros) + .then_with(|| left.profile_id.cmp(&right.profile_id)) + }); + items +} + +#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] +pub struct VisualNovelGalleryViewRow { + pub work_id: String, + pub profile_id: String, + pub owner_user_id: String, + pub source_session_id: Option, + pub author_display_name: String, + pub work_title: String, + pub work_description: String, + pub tags: Vec, + pub cover_image_src: Option, + pub source_asset_ids: Vec, + pub publication_status: String, + pub publish_ready: bool, + pub play_count: u32, + pub created_at_micros: i64, + pub updated_at_micros: i64, + pub published_at_micros: Option, +} + #[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)] pub struct VisualNovelAgentSessionCreateInput { pub session_id: String, @@ -1445,6 +1498,31 @@ fn build_work_snapshot(row: &VisualNovelWorkProfileRow) -> Result Result { + Ok(VisualNovelGalleryViewRow { + work_id: row.work_id.clone(), + profile_id: row.profile_id.clone(), + owner_user_id: row.owner_user_id.clone(), + source_session_id: empty_to_none(&row.source_session_id), + author_display_name: row.author_display_name.clone(), + work_title: row.work_title.clone(), + work_description: row.work_description.clone(), + tags: parse_string_vec_or_empty(&row.tags_json)?, + cover_image_src: empty_to_none(&row.cover_image_src), + source_asset_ids: parse_string_vec_or_empty(&row.source_asset_ids_json)?, + publication_status: row.publication_status.clone(), + publish_ready: row.publish_ready, + play_count: row.play_count, + created_at_micros: row.created_at.to_micros_since_unix_epoch(), + updated_at_micros: row.updated_at.to_micros_since_unix_epoch(), + published_at_micros: row + .published_at + .map(|value| value.to_micros_since_unix_epoch()), + }) +} + fn build_run_snapshot( ctx: &ReducerContext, row: &VisualNovelRuntimeRunRow,