This commit is contained in:
2026-04-22 20:14:15 +08:00
parent 0773a0d0ca
commit 0e9c286a57
205 changed files with 25790 additions and 1623 deletions

View File

@@ -17,6 +17,13 @@ VITE_SCENE_IMAGE_PROXY_BASE_URL="/api/custom-world/scene-image"
NODE_SERVER_ADDR=":8081"
NODE_SERVER_TARGET="http://127.0.0.1:8081"
# Rust api-server local target used by the Big Fish compatibility gateway in server-node.
GENARRATIVE_API_PORT="3100"
GENARRATIVE_API_TARGET="http://127.0.0.1:3100"
GENARRATIVE_INTERNAL_API_SECRET="CHANGE_ME_FOR_PRODUCTION"
GENARRATIVE_SPACETIME_SERVER_URL="http://127.0.0.1:3001"
GENARRATIVE_SPACETIME_DATABASE="genarrative-dev"
# Local Caddy upstream target used for dist-based testing.
CADDY_API_UPSTREAM="http://127.0.0.1:8081"

View File

@@ -13,7 +13,8 @@
- UI设计需要兼顾网页端、移动端双端的使用体验确保在不同设备上都能正常显示和操作移动端优先考虑。
- 不要在gitignore中添加.env.local文件。
- 严格遵循简洁的代码风格
- 前端只负责做表现,所有的逻辑、数据都放到Express后端进行运算和存储。
- 前端只负责做表现,所有的逻辑、数据都放到后端工程后端使用server-rs中用Rust+spacetimeDB的方案实现禁止继续使用server-nodeExpress和postgreSQL
- 后端采用多crate设计
- 请默认保持系统的简洁性,能复用、修改、扩展现有系统、页面就不新建新系统新页面。
- 禁止将功能说明描述类的文本默认写入UI界面中。
- prd文档中每个模块的描述要落地设计到可以精准编码到位不能出现需求落地漂移。

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,273 @@
# 大鱼吃小鱼玩法创作与运行态最小落地技术方案
日期:`2026-04-22`
## 1. 文档目的
本文件承接 PRD《AI 原生 Agent-First 大鱼吃小鱼玩法创作工具与玩法系统》,冻结本轮工程落地的最小完整闭环。
本轮目标不是抽象一个通用街机玩法引擎,而是在现有平台内新增一个独立 `big_fish` 玩法域,跑通:
1. 平台创作入口选择大鱼吃小鱼玩法
2. Agent 会话创建、消息提交和 SSE 兼容返回
3. 基于 4 个高杠杆锚点编译玩法草稿
4. 结果页生成等级主图、等级动作、场地背景的正式资产槽位
5. 发布校验
6. 启动测试运行态
7. 后端推进摇杆输入、刷怪、吞噬收编、三合一、屏外清理和胜负裁决
## 2. 本轮明确不做
1. 不接入真实图片 / 动作模型调用,只生成可预览的占位资产引用与冻结提示词快照。
2. 不新增 WebSocket 依赖;首版运行态使用 `POST input + GET snapshot` 的有限 HTTP 辅助接口,后续再升级长连接。
3. 不把 Big Fish 写回 `custom_world``rpgCreation` 或 RPG runtime 旧语义。
4. 不新增作品市场、排行榜、复盘、局外成长、PvP。
5. 不要求前端本地模拟真相;前端只渲染后端 snapshot。
## 3. Rust crate 边界
新增:
1. `server-rs/crates/module-big-fish`
- 纯领域模型、输入校验、草稿编译、资产覆盖率、运行态规则推进。
- 可开启 `spacetime-types` feature`spacetime-module` 派生 SpacetimeDB 类型。
接入:
1. `server-rs/crates/spacetime-module`
- 新增 Big Fish 表与 procedure。
- 只存状态与结构化引用,不做 OSS / LLM 外部 IO。
2. `server-rs/crates/spacetime-client`
- 新增 Big Fish facade隐藏 generated bindings。
3. `server-rs/crates/shared-contracts`
- 新增 HTTP DTO。
4. `server-rs/crates/api-server`
- 新增 `big_fish_creation.rs``big_fish_assets.rs``big_fish_runtime.rs` 或最小合并的 `big_fish.rs`
## 4. SpacetimeDB 表
本轮只新增必要表,所有表主键使用 Axum 生成的显式业务 ID。
### 4.1 `big_fish_creation_session`
字段:
1. `session_id: String`
2. `owner_user_id: String`
3. `seed_text: String`
4. `current_turn: u32`
5. `progress_percent: u32`
6. `stage: BigFishCreationStage`
7. `anchor_pack_json: String`
8. `draft_json: Option<String>`
9. `asset_coverage_json: String`
10. `last_assistant_reply: Option<String>`
11. `publish_ready: bool`
12. `created_at: Timestamp`
13. `updated_at: Timestamp`
索引:
1. `by_big_fish_session_owner_user_id(owner_user_id)`
### 4.2 `big_fish_agent_message`
字段:
1. `message_id: String`
2. `session_id: String`
3. `role: BigFishAgentMessageRole`
4. `kind: BigFishAgentMessageKind`
5. `text: String`
6. `created_at: Timestamp`
索引:
1. `by_big_fish_message_session_id(session_id)`
### 4.3 `big_fish_asset_slot`
字段:
1. `slot_id: String`
2. `session_id: String`
3. `asset_kind: BigFishAssetKind`
4. `level: Option<u32>`
5. `motion_key: Option<String>`
6. `status: BigFishAssetStatus`
7. `asset_url: Option<String>`
8. `prompt_snapshot: String`
9. `updated_at: Timestamp`
索引:
1. `by_big_fish_asset_session_id(session_id)`
2. `by_big_fish_asset_slot(session_id, asset_kind, level, motion_key)`
### 4.4 `big_fish_runtime_run`
字段:
1. `run_id: String`
2. `session_id: String`
3. `owner_user_id: String`
4. `status: BigFishRunStatus`
5. `snapshot_json: String`
6. `last_input_x: f32`
7. `last_input_y: f32`
8. `tick: u64`
9. `created_at: Timestamp`
10. `updated_at: Timestamp`
索引:
1. `by_big_fish_run_owner_user_id(owner_user_id)`
2. `by_big_fish_run_session_id(session_id)`
## 5. SpacetimeDB procedure
本轮全部使用 procedure 同步返回快照,避免 Axum 额外拼读模型。
1. `create_big_fish_session(input) -> BigFishSessionProcedureResult`
2. `get_big_fish_session(input) -> BigFishSessionProcedureResult`
3. `submit_big_fish_message(input) -> BigFishSessionProcedureResult`
4. `compile_big_fish_draft(input) -> BigFishSessionProcedureResult`
5. `generate_big_fish_asset(input) -> BigFishSessionProcedureResult`
6. `publish_big_fish_game(input) -> BigFishSessionProcedureResult`
7. `start_big_fish_run(input) -> BigFishRunProcedureResult`
8. `submit_big_fish_input(input) -> BigFishRunProcedureResult`
9. `get_big_fish_run(input) -> BigFishRunProcedureResult`
说明:
1. `submit_big_fish_message` 只做 deterministic 锚点补全,不调用 LLM。
2. `generate_big_fish_asset` 只写正式资产槽位和提示词快照,真实模型生成后续由 AI/OSS worker 替换。
3. `submit_big_fish_input` 每次至少推进 1 个后端 tick前端不能本地裁决。
4. 运行态所有“持续时间”语义按真实秒数累计,前端即使摇杆静止也要持续以当前输入心跳驱动后端推进,避免刷怪与屏外 `3` 秒清理依赖手速或提交频率。
## 6. HTTP contract
所有接口挂在 `/api/runtime/big-fish/*`,全部需要 Bearer 鉴权。
开发态本地链路补充约定:
1. 浏览器仍只请求同源 `/api/runtime/big-fish/*`
2. `vite -> server-node:8081` 保持不变,由 `server-node` 先复用现有登录态完成 Bearer 校验。
3. `server-node` 仅作为 Big Fish 兼容网关,把“已校验用户身份 + 原始请求体”转发到 Rust `api-server`
4. Rust `api-server` 继续作为 Big Fish 真相后端,正式处理会话、草稿、资产动作和运行态规则。
5. 本地默认端口:
- `vite`: `3000`
- `server-node`: `8081`
- Rust `api-server`: `3100`
- `SpacetimeDB standalone`: `3001`
6. `GENARRATIVE_SPACETIME_DATABASE` 本地开发优先跟随仓库根目录 `spacetime.local.json``database` 字段,避免 `api-server` 默认连到错误数据库名。
- `.env.local` 或进程环境显式配置 `GENARRATIVE_SPACETIME_DATABASE` 时可覆盖本地配置。
- `.env.example` 只提供示例默认值,不得压过 `spacetime.local.json`
### 6.1 创作会话
1. `POST /api/runtime/big-fish/agent/sessions`
2. `GET /api/runtime/big-fish/agent/sessions/{sessionId}`
3. `POST /api/runtime/big-fish/agent/sessions/{sessionId}/messages/stream`
4. `POST /api/runtime/big-fish/agent/sessions/{sessionId}/actions`
`messages/stream` 首版兼容当前前端 SSE 解析方式,只输出:
1. `reply_delta`
2. `session`
3. `done`
4. `error`
`actions` 首版支持:
1. `big_fish_compile_draft`
2. `big_fish_generate_level_main_image`
3. `big_fish_generate_level_motion`
4. `big_fish_generate_stage_background`
5. `big_fish_publish_game`
### 6.2 运行态
1. `POST /api/runtime/big-fish/sessions/{sessionId}/runs`
2. `GET /api/runtime/big-fish/runs/{runId}`
3. `POST /api/runtime/big-fish/runs/{runId}/input`
`input` 请求体:
```json
{
"x": 0.4,
"y": -0.2
}
```
## 7. 运行态最小规则
后端推进规则固定:
1. 开局拥有 1 个 `level = 1` 己方实体。
2. 开局视野内生成至少 2 个同级野生实体。
3. 己方实体碰撞低于或等于自己等级的野生实体时收编。
4. 高于己方等级的野生实体碰撞己方实体时吃掉该己方实体。
5. 每次结算后从低等级开始做三合一连锁合成。
6. 野生实体池围绕玩家最高己方等级维持低 1~2 级与高 1~2 级。
7. 同等级、高 3 级及以上、低 3 级及以下的野生实体,屏外连续 3 秒后删除。
8. 玩家首次拥有最高等级实体时立即胜利。
9. 己方实体归零时失败。
## 8. 前端接入边界
新增目录:
1. `src/services/big-fish-creation/`
2. `src/components/big-fish-creation/`
3. `src/components/big-fish-result/`
4. `src/components/big-fish-runtime/`
复用现有平台入口壳层,但入口脚本必须使用通用平台命名,禁止把 Big Fish 业务状态写进 `rpg-entry` 命名脚本:
1.`src/components/platform-entry/PlatformEntryCreationTypeModal.tsx` 新增“大鱼吃小鱼”选项。
2.`src/components/platform-entry/PlatformEntryFlowShellImpl.tsx` 中新增 Big Fish 专属 stage。
3. Big Fish 不使用 `RpgCreationResultView`,使用 `BigFishResultView`
4. `src/components/rpg-entry/*` 只能保留兼容导出或 RPG 专属组件,不允许承载 Big Fish 业务分支。
前端只允许:
1. 展示会话、草稿、资产槽位、运行快照。
2. 发送聊天、action 和摇杆输入。
3. 根据后端 snapshot 渲染实体。
前端禁止:
1. 自行决定刷怪。
2. 自行决定吞噬 / 合成 / 清理 / 胜负。
## 9. 本轮验收
完成后至少执行:
1. `cargo fmt -p module-big-fish -p shared-contracts -p spacetime-module -p spacetime-client -p api-server`
2. `cargo check -p module-big-fish`
3. `cargo check -p shared-contracts`
4. `cargo check -p spacetime-module`
5. `spacetime generate` 刷新 Rust bindings
6. `cargo check -p spacetime-client`
7. `cargo check -p api-server`
8. 前端类型 / 构建检查
9. `npm run check:encoding`
## 10. 本地开发补充
为避免再次出现 `POST /api/runtime/big-fish/agent/sessions` 命中旧 Node 后端 `404`,本轮额外冻结以下联调口径:
1. `npm run dev` 需要同时拉起:
- `server-node`
- Rust `api-server`
- `vite`
2. `server-node` 新增 Big Fish 专用兼容网关路由,不在 Node 内复制 Big Fish 玩法逻辑。
3. Node -> Rust 转发使用内部桥接头:
- `x-genarrative-authenticated-user-id`
- `x-genarrative-internal-api-secret`
4. Rust 侧只对带正确内部密钥的本地桥接请求接受该用户头,不对普通外部请求放开匿名身份伪造。
如检查发现本轮主链缺口,继续补齐;如已经满足上述验收,不继续扩展额外玩法能力。

View File

@@ -0,0 +1,384 @@
# 拼图玩法创作与运行态最小落地技术方案
日期:`2026-04-22`
## 1. 文档目的
本文件承接 PRD《AI 原生拼图玩法创作工具与玩法系统》,冻结本轮拼图玩法在当前平台内的最小完整闭环。
本轮目标不是抽象一个通用拼图编辑器,也不是额外搭建一个脱离平台的新小游戏站点,而是在现有平台壳层内新增独立 `puzzle` 玩法域,跑通下面这条主链:
1. 平台创作入口选择拼图玩法
2. Agent-first 对话收束 5 个高杠杆视觉锚点
3. 编译结果页草稿
4. 在结果页编辑关卡名、标签并生成候选拼图图片
5. 发布作品进入拼图广场
6. 玩家从广场进入第 1 关
7. 后端初始化 `3x3 / 4x4` 棋盘
8. 后端裁决交换、合并、拖动、拆分与通关
9. 通关后根据“标签相似度 `70%` + 同作者 `30%`”推荐下一关
## 2. 本轮明确不做
1. 不做异形拼块、旋转拼块、道具、体力、倒计时。
2. 不做新的平台站点或新的全局导航系统。
3. 不做前端本地推荐、前端本地裁决、前端本地持久化真相。
4. 不做复杂图片模型编排;首版图片生成沿用 `api-server` 的占位资产生成方式,保证完整链路可跑通。
5. 不把拼图玩法继续挂在 `customWorld``rpgWorld` 或 RPG runtime 旧语义下。
6. 不扩到拼图排行榜、社交评论、收藏、复盘系统。
## 3. 分层边界
### 3.1 前端
前端继续使用当前 `React + TypeScript + Vite` 平台壳层,只负责:
1. 展示拼图创作中心、Agent 工作区、结果页、广场、运行时画布。
2. 发起聊天、结果页编辑、发布、开始游戏、交换与拖动请求。
3. 基于后端快照渲染棋盘、HUD、选中态与合并反馈。
前端禁止:
1. 自行判断下一关推荐。
2. 自行判断拼块是否应当合并。
3. 自行判断合并块是否应当拆分。
4. 自行判断通关。
### 3.2 Axum
`server-rs/crates/api-server` 负责:
1. 对外暴露 `/api/runtime/puzzle-*` HTTP 接口。
2. 鉴权、请求上下文、错误 envelope。
3. 结果页占位图片生成与静态资产落盘。
4. 调用 `spacetime-client` 读写拼图玩法真相态。
### 3.3 SpacetimeDB
`server-rs/crates/spacetime-module` 负责:
1. 存储拼图 Agent session / message。
2. 存储已发布拼图作品 profile。
3. 存储拼图运行态 run snapshot。
4. 通过 procedure 同步返回 session / works / gallery / runtime 快照。
### 3.4 纯领域 crate
新增 `server-rs/crates/module-puzzle`,承载:
1. 5 个锚点与会话阶段的纯领域模型。
2. 草稿编译、标签规范化、发布校验。
3. `3x3 / 4x4` 棋盘初始化。
4. 交换、合并、拖动、拆分、通关与下一关推荐算法。
## 4. 共享契约
### 4.1 TypeScript shared contracts
`packages/shared/src/contracts/` 新增:
1. `puzzleAgentSession.ts`
2. `puzzleAgentDraft.ts`
3. `puzzleAgentActions.ts`
4. `puzzleResultPreview.ts`
5. `puzzleWorkSummary.ts`
6. `puzzleRuntimeSession.ts`
这些文件分别承载:
1. Agent session / message / anchor pack
2. 结果页草稿与候选图片
3. Agent actions 与 works/gallery mutation request
4. 结果页 publish gate / preview
5. owner-only works 与 gallery card
6. runtime run / board / swap / drag / next-level contract
### 4.2 Rust shared contracts
`server-rs/crates/shared-contracts/src/` 新增:
1. `puzzle_agent.rs`
2. `puzzle_works.rs`
3. `puzzle_gallery.rs`
4. `puzzle_runtime.rs`
Rust DTO 只承载对前端公开的 HTTP contract不直接泄露 `module-puzzle` 内部实现细节。
## 5. Spacetime 表与 procedure
本轮保持“最小闭环优先”,作品与运行时仍以结构化字段 + `snapshot_json` 组合持久化,不额外拆出更多高耦合表。
### 5.1 `puzzle_agent_session`
字段:
1. `session_id`
2. `owner_user_id`
3. `seed_text`
4. `current_turn`
5. `progress_percent`
6. `stage`
7. `anchor_pack_json`
8. `draft_json`
9. `last_assistant_reply`
10. `published_profile_id`
11. `created_at`
12. `updated_at`
### 5.2 `puzzle_agent_message`
字段:
1. `message_id`
2. `session_id`
3. `role`
4. `kind`
5. `text`
6. `created_at`
### 5.3 `puzzle_work_profile`
字段:
1. `profile_id`
2. `owner_user_id`
3. `source_session_id`
4. `author_display_name`
5. `level_name`
6. `summary_text`
7. `theme_tags_json`
8. `cover_image_src`
9. `cover_asset_id`
10. `anchor_pack_json`
11. `publication_status`
12. `play_count`
13. `updated_at`
14. `published_at`
### 5.4 `puzzle_runtime_run`
字段:
1. `run_id`
2. `owner_user_id`
3. `entry_profile_id`
4. `current_profile_id`
5. `cleared_level_count`
6. `current_level_index`
7. `current_grid_size`
8. `played_profile_ids_json`
9. `previous_level_tags_json`
10. `snapshot_json`
11. `updated_at`
12. `created_at`
### 5.5 Procedure
本轮全部使用 procedure 同步返回快照,避免 Axum 再次读 private table
1. `create_puzzle_agent_session`
2. `get_puzzle_agent_session`
3. `submit_puzzle_agent_message`
4. `compile_puzzle_agent_draft`
5. `save_puzzle_generated_images`
6. `select_puzzle_cover_image`
7. `publish_puzzle_work`
8. `list_puzzle_works`
9. `get_puzzle_work_detail`
10. `update_puzzle_work`
11. `list_puzzle_gallery`
12. `get_puzzle_gallery_detail`
13. `start_puzzle_run`
14. `get_puzzle_run`
15. `swap_puzzle_pieces`
16. `drag_puzzle_piece_or_group`
17. `advance_puzzle_next_level`
## 6. 结果页图片生成策略
本轮不引入新的真实图像模型编排,而是复用 `api-server` 里已有的占位资产写盘模式:
1. 每次生成 2 张候选图。
2. 候选图通过 `api-server` 写入 `public/generated-puzzle-covers/...`
3. Axum 把候选图 URL、assetId、prompt snapshot 回写到 Spacetime session draft。
4. 创作者在结果页选择其中 1 张作为正式图。
这样可以保证:
1. 结果页图片生成、重生、应用正式图完整可用。
2. 发布链有正式图片可校验。
3. 不额外扩到模型供应商集成。
### 6.1 发布前编辑真相补充
结果页允许创作者在发布前直接编辑:
1. `关卡名`
2. `摘要`
3. `题材标签`
这 3 个字段不能只停留在前端临时态。
本轮冻结为:
1. `publish_puzzle_work` 允许直接携带 `levelName / summary / themeTags`
2. `spacetime-module` 在发布事务内先把这些字段覆盖回 session draft 真相
3. 覆盖后的 draft 再参与发布校验与 profile 持久化
这样可以避免额外新增一条“草稿轻量编辑 procedure”同时确保结果页编辑内容会真实进入广场作品与后续运行时 HUD。
## 7. 运行态规则冻结
### 7.1 难度推进
```ts
function resolvePuzzleGridSize(clearedLevelCount: number): 3 | 4 {
return clearedLevelCount >= 3 ? 4 : 3;
}
```
### 7.2 棋盘初始化
1. 根据正式图片与网格规格生成 `pieceId -> correctRow/correctCol`
2. 随机打乱到非完成态。
3. 生成初始 `mergedGroups = []`,再执行一次正确连接检查。
### 7.3 正确连接
若两个拼块在当前棋盘中四向相邻,且它们在原图上的正确位置也以同方向相邻,则视为正确连接。
所有正确连接链通过并查集合并为 `mergedGroup`
### 7.4 拖动与拆分
1. 单块拖到单块位置:执行交换。
2. 合并块拖到任意目标锚点:保持内部相对布局整体重排。
3. 单块拖到合并块占据位置:先拆分目标合并块,再执行交换,最后重算合并。
### 7.5 通关
当所有拼块回到正确位置,或全盘只剩一个覆盖全部拼块的合并组时,标记当前关卡 `cleared`
### 7.6 下一关推荐
固定公式:
```ts
finalScore = tagSimilarityScore * 0.7 + sameAuthorScore * 0.3;
```
标签相似度首版使用规范化标签集合的 Jaccard。
同分裁决顺序:
1. `tagSimilarityScore` 更高
2. 当前 run 未出现过
3. `play_count` 更低
4. `updated_at` 更近
## 8. 前端接入
### 8.1 平台入口
只改现有平台壳层:
1. 在创作类型弹层新增“拼图玩法”。
2. 新增拼图专属 stage不改 RPG runtime 主链。
### 8.2 组件目录
新增:
1. `src/components/puzzle-agent/`
2. `src/components/puzzle-result/`
3. `src/components/puzzle-gallery/`
4. `src/components/puzzle-runtime/`
### 8.3 服务目录
新增:
1. `src/services/puzzle-agent/`
2. `src/services/puzzle-works/`
3. `src/services/puzzle-gallery/`
4. `src/services/puzzle-runtime/`
本轮全部走 HTTP facade不引入新的前端 Spacetime 直连。
### 8.4 当前前端最小落地补充
当前实现固定走下面这条最小链路:
1. `PlatformEntryCreationTypeModal` 选择 `puzzle`
2. `PuzzleAgentWorkspace` 收束锚点并触发 `compile_puzzle_draft`
3. `PuzzleResultView` 编辑 `levelName / summary / themeTags`
4. 图片生成通过独立 `PuzzleImageStudioModal` 触发,不在结果页内联堆叠
5. 发布后跳转 `PuzzleGalleryDetailView`
6. 从详情进入 `PuzzleRuntimeShell`
创作中心作品展示冻结为:
1. 拼图作品也是平台作品,和其他创作作品共用同一套列表项样式。
2. 创作中心不再保留独立“拼图玩法作品模块”。
3. 拼图作品仅通过 `拼图` 标签与题材标签区分,不额外拆出第二块作品区。
4. 创作中心仍保留统一“新建作品”入口,由创建类型弹层继续分流到 RPG / 拼图玩法。
运行时前端表现冻结为:
1. 使用正式封面图按 `correctRow / correctCol` 做真实网格切片渲染
2. 点击两块时仅前端维护轻量选中态,真正交换以后端返回快照为准
3. 拖动统一采用 pointer 事件,兼顾网页端与移动端
4. 不在前端计算合并、拆分、通关与下一关推荐
## 9. 验收与检查
完成后至少执行:
1. `npm run check:encoding`
2. `npm run typecheck`
3. `npm run test`
4. `cargo check -p module-puzzle`
5. `cargo check -p shared-contracts`
6. `cargo check -p spacetime-module`
7. `spacetime generate --no-config --lang rust --out-dir server-rs/crates/spacetime-client/src/module_bindings --module-path server-rs/crates/spacetime-module --include-private --yes`
8. `cargo check -p spacetime-client`
9. `cargo check -p api-server`
如果检查中发现拼图主链缺口,继续补齐;如果已经满足 PRD 主链和上述检查,不再追加额外玩法能力。
## 10. 2026-04-22 最终验收记录
本轮已按“最小完整闭环、禁止超出需求过度实现”完成拼图玩法主链落地,并补齐收尾检查。
### 10.1 已落地主链
1. 平台创作中心可选择 `puzzle` 玩法入口。
2. `PuzzleAgentWorkspace` 已接入 Agent-first 锚点收束与草稿编译。
3. `PuzzleResultView` 已支持最小结果页编辑与独立图片生成弹层。
4. 发布后作品可进入拼图广场与详情页。
5. `PuzzleRuntimeShell` 已按正式封面图真实切片渲染 `3x3 / 4x4` 关卡。
6. 交换、拖动、拆分、合并、通关、下一关推荐真相全部以后端快照为准。
### 10.2 本轮额外修复的验收阻塞
在最终验收阶段,补齐了与拼图主链无直接业务耦合、但会阻塞仓库整体检查的基线问题:
1. `typecheck` 基线类型不兼容。
2. `AccountModal` 测试 mock 字段落后于最新鉴权契约。
3. `customWorld` 存档归一化中场景连接方向未收敛到强类型。
4. 结果页生成资源在签名 URL 尚未返回时会短暂空白,已调整为先展示原路径占位,再异步替换签名读地址。
### 10.3 实际通过的检查
1. `npm run check:encoding`
2. `npm run typecheck`
3. `npm run test`
4. `cargo check -p module-puzzle`
5. `cargo check -p shared-contracts`
6. `cargo check -p spacetime-module`
7. `cargo check -p spacetime-client`
8. `cargo check -p api-server`
### 10.4 冻结说明
截至本次验收,拼图玩法已满足 PRD 要求的最小产品闭环;未继续扩展排行榜、提示、体力、异形拼块、倒计时、前端本地裁决等超出本轮需求的能力。

View File

@@ -42,6 +42,9 @@
- [SPACETIMEDB_CUSTOM_WORLD_AGENT_SESSION_STAGE6_DESIGN_2026-04-22.md](./SPACETIMEDB_CUSTOM_WORLD_AGENT_SESSION_STAGE6_DESIGN_2026-04-22.md):冻结 `M5` Agent session create / snapshot 的最小 SpacetimeDB 与 Axum facade 闭环,明确本轮不迁移 LLM、SSE、卡片更新和完整 action registry。
- [SPACETIMEDB_CUSTOM_WORLD_AGENT_MESSAGE_STAGE7_DESIGN_2026-04-22.md](./SPACETIMEDB_CUSTOM_WORLD_AGENT_MESSAGE_STAGE7_DESIGN_2026-04-22.md):冻结 `M5` Agent `message submit / operation query` 的 deterministic 最小闭环,明确同步写入 user/assistant 消息、`process_message` operation 与 session 进度推进规则。
- [SPACETIMEDB_CUSTOM_WORLD_AGENT_MESSAGE_STREAM_STAGE8_DESIGN_2026-04-22.md](./SPACETIMEDB_CUSTOM_WORLD_AGENT_MESSAGE_STREAM_STAGE8_DESIGN_2026-04-22.md):冻结 `M5` Agent `/messages/stream` 的最小兼容 SSE facade明确复用 Stage 7 的同步写表逻辑,只输出当前前端真实消费的 `reply_delta / session / done / error` 事件。
- [BIG_FISH_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-22.md](./BIG_FISH_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-22.md):冻结大鱼吃小鱼玩法本轮最小完整落地方案,明确 `module-big-fish`、SpacetimeDB 表 / procedure、Axum facade、前端接入和运行态规则边界。
- [PUZZLE_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-22.md](./PUZZLE_CREATION_AND_RUNTIME_MINIMAL_IMPLEMENTATION_2026-04-22.md):冻结拼图玩法本轮最小完整落地方案,明确 `module-puzzle`、SpacetimeDB 表 / procedure、Axum facade、前端接入以及交换 / 合并 / 拖动 / 拆分 / 下一关推荐边界。
- [UNIFIED_CREATION_AGENT_CHAT_FRAMEWORK_2026-04-22.md](./UNIFIED_CREATION_AGENT_CHAT_FRAMEWORK_2026-04-22.md):冻结所有创作品类 Agent 聊天 UI 与对话进度管理统一框架,明确品类差异只保留锚点映射、提示词/话术和 action。
- [SPACETIMEDB_CUSTOM_WORLD_LIBRARY_DETAIL_STAGE5_EXTENSION_DESIGN_2026-04-22.md](./SPACETIMEDB_CUSTOM_WORLD_LIBRARY_DETAIL_STAGE5_EXTENSION_DESIGN_2026-04-22.md):补齐 `M5` Stage 5 遗漏的 owner-only `GET /api/runtime/custom-world-library/:profileId` 设计,冻结单条 profile detail 的 SpacetimeDB procedure、client facade、404 语义与 Axum 路由扩展方式。
- [SPACETIMEDB_CUSTOM_WORLD_WORKS_AND_AGENT_EXTENSION_STAGE9_DESIGN_2026-04-22.md](./SPACETIMEDB_CUSTOM_WORLD_WORKS_AND_AGENT_EXTENSION_STAGE9_DESIGN_2026-04-22.md):冻结 `M5` 剩余主链的 works、card detail、publish gate、supportedActions、action registry 与 AI/OSS 兼容路由边界,作为 Stage 9 到收口阶段的统一落地依据。
- [M3_BROWSE_HISTORY_AXUM_SPACETIMEDB_DESIGN_2026-04-21.md](./M3_BROWSE_HISTORY_AXUM_SPACETIMEDB_DESIGN_2026-04-21.md):冻结 `M3` 第二批 `browse history` 纵向切片的 `user_browse_history` 表、双路径 facade、宽松归一化、去重排序规则与测试策略。

View File

@@ -0,0 +1,126 @@
# 统一创作品类 Agent 对话框架技术方案
日期:`2026-04-22`
## 1. 目标
把平台内所有“先 Agent 聊天收束锚点,再生成结果页”的创作流程统一到一套前端框架:
1. UI 交互共用一套:标题区、返回、生成结果页按钮、锚点卡片、进度条、操作横幅、聊天气泡、推荐回复、输入框。
2. 对话进度管理共用一套进度归一化、忙碌态判断、SSE `reply_delta / session / error` 解析、操作状态展示。
3. 品类差异只允许落在配置和后端领域逻辑:锚点列表、提示词/占位文案、生成结果页 action、快捷补全/总结话术、结果页与运行态。
## 2. 本轮范围
覆盖当前已接入平台入口的三条创作链:
1. RPG / Custom World Agent 创作。
2. 大鱼吃小鱼 Agent 创作。
3. 拼图 Agent 创作。
本轮不迁移结果页、运行态、发布、资产生成 UI这些仍按各品类自己的页面承载。
## 3. 前端结构
新增目录:
```text
src/components/creation-agent/
├─ CreationAgentWorkspace.tsx
└─ index.ts
src/services/creation-agent/
├─ creationAgentProgress.ts
├─ creationAgentSse.ts
└─ index.ts
```
### 3.1 `CreationAgentWorkspace`
统一组件只接收通用 view model
1. `session`: `CreationAgentSessionView | null`
2. `theme`: 品类主题色与背景 class
3. `primaryAction`: 生成结果页按钮配置
4. `progressActions`: 总结、补全等可选快捷动作
5. `activeOperation`: 可选操作状态
6. `streamingReplyText / isStreamingReply / isBusy / error`
7. `onBack / onSubmitText / onPrimaryAction / onQuickAction`
组件内部只做表现,不读取任何 RPG、Big Fish、Puzzle 专属字段。
### 3.2 会话 view model
各品类工作区负责把自己的 session 映射成:
1. `title`
2. `assistantSummary`
3. `progressPercent`
4. `currentTurn`
5. `anchors: { key, label, value, status }[]`
6. `messages: { id, role, kind, text, createdAt }[]`
7. `recommendedReplies`
因此新增品类时只需要新增 mapper不再复制聊天工作区。
### 3.3 进度管理
`creationAgentProgress.ts` 统一提供:
1. `normalizeCreationAgentProgress(progressPercent)`
2. `isCreationAgentOperationBusy(operation)`
3. `resolveCreationAgentProgressHint(progressPercent, copy?)`
4. `resolveCreationAnchorStatusLabel(status)`
5. `createCreationAgentClientMessageId(prefix)`
### 3.4 SSE 解析
`creationAgentSse.ts` 统一解析现有 SSE 事件:
1. `reply_delta`: 调用 `onUpdate(text)`
2. `session`: 缓存最终 session
3. `error`: 抛出后端错误
4. 流结束后若没有 session抛出品类传入的 incomplete message
各品类 client 只负责打开自己的 URL 和提供类型参数。
## 4. 品类差异边界
### 4.1 RPG / Custom World
保留差异:
1. 8 个 RPG 高杠杆锚点映射。
2. 总结当前设定话术。
3. 补全剩余设定话术。
4. 生成结果页 action`draft_foundation`
### 4.2 大鱼吃小鱼
保留差异:
1. 4 个玩法锚点映射。
2. 输入框占位提示。
3. 生成结果页 action`big_fish_compile_draft`
### 4.3 拼图
保留差异:
1. 拼图视觉/题材锚点映射。
2. 输入框占位提示。
3. 生成结果页 action`compile_puzzle_draft`
## 5. 禁止事项
1. 禁止在统一组件中判断具体品类名称后写分支业务。
2. 禁止把 Big Fish / Puzzle 的状态写入 RPG 命名脚本。
3. 禁止把后端锚点收束、提示词生成或进度裁决搬到前端。
4. 禁止为了统一 UI 改写结果页、运行态或发布流程。
## 6. 验收
1. 三个创作流程的 Agent 聊天区都通过 `CreationAgentWorkspace` 渲染。
2. Big Fish 与 Puzzle 不再各自复制聊天 UI、锚点卡片、输入框和进度条。
3. RPG / Custom World 保留原有“总结当前设定 / 补全剩余设定 / 生成游戏设定草稿”交互。
4. 定向 TypeScript / ESLint / 编码检查通过。

View File

@@ -0,0 +1,190 @@
/**
* 大鱼吃小鱼玩法域前端共享契约。
* 字段与 server-rs/shared-contracts/src/big_fish.rs 保持 camelCase 对齐。
*/
export type CreateBigFishSessionRequest = {
seedText?: string;
};
export type SendBigFishMessageRequest = {
clientMessageId: string;
text: string;
};
export type BigFishActionId =
| 'big_fish_compile_draft'
| 'big_fish_generate_level_main_image'
| 'big_fish_generate_level_motion'
| 'big_fish_generate_stage_background'
| 'big_fish_publish_game';
export type ExecuteBigFishActionRequest = {
action: BigFishActionId;
level?: number;
motionKey?: 'idle_float' | 'move_swim' | string;
};
export type SubmitBigFishInputRequest = {
x: number;
y: number;
};
export type BigFishAnchorStatus =
| 'confirmed'
| 'inferred'
| 'missing'
| 'locked'
| string;
export type BigFishAnchorItemResponse = {
key: string;
label: string;
value: string;
status: BigFishAnchorStatus;
};
export type BigFishAnchorPackResponse = {
gameplayPromise: BigFishAnchorItemResponse;
ecologyVisualTheme: BigFishAnchorItemResponse;
growthLadder: BigFishAnchorItemResponse;
riskTempo: BigFishAnchorItemResponse;
};
export type BigFishLevelBlueprintResponse = {
level: number;
name: string;
oneLineFantasy: string;
silhouetteDirection: string;
sizeRatio: number;
visualPromptSeed: string;
motionPromptSeed: string;
mergeSourceLevel?: number | null;
preyWindow: number[];
threatWindow: number[];
isFinalLevel: boolean;
};
export type BigFishBackgroundBlueprintResponse = {
theme: string;
colorMood: string;
foregroundHints: string;
midgroundComposition: string;
backgroundDepth: string;
safePlayAreaHint: string;
spawnEdgeHint: string;
backgroundPromptSeed: string;
};
export type BigFishRuntimeParamsResponse = {
levelCount: number;
mergeCountPerUpgrade: number;
spawnTargetCount: number;
leaderMoveSpeed: number;
followerCatchUpSpeed: number;
offscreenCullSeconds: number;
preySpawnDeltaLevels: number[];
threatSpawnDeltaLevels: number[];
winLevel: number;
};
export type BigFishGameDraftResponse = {
title: string;
subtitle: string;
coreFun: string;
ecologyTheme: string;
levels: BigFishLevelBlueprintResponse[];
background: BigFishBackgroundBlueprintResponse;
runtimeParams: BigFishRuntimeParamsResponse;
};
export type BigFishAgentMessageResponse = {
id: string;
role: 'user' | 'assistant' | string;
kind: 'chat' | 'system' | 'warning' | string;
text: string;
createdAt: string;
};
export type BigFishAssetKind =
| 'level_main_image'
| 'level_motion'
| 'stage_background'
| string;
export type BigFishAssetStatus = 'empty' | 'ready' | 'generating' | string;
export type BigFishAssetSlotResponse = {
slotId: string;
assetKind: BigFishAssetKind;
level?: number | null;
motionKey?: string | null;
status: BigFishAssetStatus;
assetUrl?: string | null;
promptSnapshot: string;
updatedAt: string;
};
export type BigFishAssetCoverageResponse = {
levelMainImageReadyCount: number;
levelMotionReadyCount: number;
backgroundReady: boolean;
requiredLevelCount: number;
publishReady: boolean;
blockers: string[];
};
export type BigFishSessionSnapshotResponse = {
sessionId: string;
currentTurn: number;
progressPercent: number;
stage: string;
anchorPack: BigFishAnchorPackResponse;
draft?: BigFishGameDraftResponse | null;
assetSlots: BigFishAssetSlotResponse[];
assetCoverage: BigFishAssetCoverageResponse;
messages: BigFishAgentMessageResponse[];
lastAssistantReply?: string | null;
publishReady: boolean;
updatedAt: string;
};
export type BigFishSessionResponse = {
session: BigFishSessionSnapshotResponse;
};
export type BigFishActionResponse = {
session: BigFishSessionSnapshotResponse;
};
export type BigFishVector2Response = {
x: number;
y: number;
};
export type BigFishRuntimeEntityResponse = {
entityId: string;
level: number;
position: BigFishVector2Response;
radius: number;
offscreenSeconds: number;
};
export type BigFishRuntimeSnapshotResponse = {
runId: string;
sessionId: string;
status: 'running' | 'won' | 'failed' | string;
tick: number;
playerLevel: number;
winLevel: number;
leaderEntityId?: string | null;
ownedEntities: BigFishRuntimeEntityResponse[];
wildEntities: BigFishRuntimeEntityResponse[];
cameraCenter: BigFishVector2Response;
lastInput: BigFishVector2Response;
eventLog: string[];
updatedAt: string;
};
export type BigFishRunResponse = {
run: BigFishRuntimeSnapshotResponse;
};

View File

@@ -0,0 +1,59 @@
export type PuzzleAgentSuggestedActionType =
| 'request_summary'
| 'compile_puzzle_draft'
| 'generate_puzzle_images'
| 'publish_puzzle_work';
export interface PuzzleAgentSuggestedAction {
id: string;
actionType: PuzzleAgentSuggestedActionType;
label: string;
}
export type PuzzleAgentActionType =
| 'compile_puzzle_draft'
| 'generate_puzzle_images'
| 'select_puzzle_image'
| 'publish_puzzle_work';
export type PuzzleAgentOperationType =
| 'process_message'
| PuzzleAgentActionType;
export type PuzzleAgentOperationStatus =
| 'queued'
| 'running'
| 'completed'
| 'failed';
export interface PuzzleAgentOperationRecord {
operationId: string;
type: PuzzleAgentOperationType;
status: PuzzleAgentOperationStatus;
phaseLabel: string;
phaseDetail: string;
progress: number;
error?: string | null;
}
export type PuzzleAgentActionRequest =
| { action: 'compile_puzzle_draft' }
| {
action: 'generate_puzzle_images';
promptText?: string | null;
candidateCount?: number;
}
| {
action: 'select_puzzle_image';
candidateId: string;
}
| {
action: 'publish_puzzle_work';
levelName?: string;
summary?: string;
themeTags?: string[];
};
export interface PuzzleAgentActionResponse {
operation: PuzzleAgentOperationRecord;
}

View File

@@ -0,0 +1,58 @@
import type { JsonObject } from './common';
export type PuzzleAnchorStatus =
| 'missing'
| 'inferred'
| 'confirmed'
| 'locked';
export interface PuzzleAnchorItem {
key: string;
label: string;
value: string;
status: PuzzleAnchorStatus;
}
export interface PuzzleAnchorPack {
themePromise: PuzzleAnchorItem;
visualSubject: PuzzleAnchorItem;
visualMood: PuzzleAnchorItem;
compositionHooks: PuzzleAnchorItem;
tagsAndForbidden: PuzzleAnchorItem;
}
export interface PuzzleCreatorIntent {
sourceMode: 'agent_chat';
rawMessagesSummary: string;
themePromise: string;
visualSubject: string;
visualMood: string[];
compositionHooks: string[];
themeTags: string[];
forbiddenDirectives: string[];
}
export interface PuzzleGeneratedImageCandidate {
candidateId: string;
imageSrc: string;
assetId: string;
prompt: string;
actualPrompt?: string | null;
sourceType: 'generated' | 'uploaded';
selected: boolean;
}
export interface PuzzleResultDraft {
levelName: string;
summary: string;
themeTags: string[];
forbiddenDirectives: string[];
creatorIntent: PuzzleCreatorIntent | null;
anchorPack: PuzzleAnchorPack;
candidates: PuzzleGeneratedImageCandidate[];
selectedCandidateId: string | null;
coverImageSrc: string | null;
coverAssetId: string | null;
generationStatus: 'idle' | 'generating' | 'ready';
metadata?: JsonObject | null;
}

View File

@@ -0,0 +1,58 @@
import type { PuzzleAgentActionResponse, PuzzleAgentSuggestedAction } from './puzzleAgentActions';
import type { PuzzleAnchorPack, PuzzleResultDraft } from './puzzleAgentDraft';
import type { PuzzleResultPreviewEnvelope } from './puzzleResultPreview';
export type PuzzleAgentStage =
| 'collecting_anchors'
| 'draft_ready'
| 'image_refining'
| 'ready_to_publish'
| 'published';
export type PuzzleAgentMessageRole = 'user' | 'assistant' | 'system';
export type PuzzleAgentMessageKind =
| 'chat'
| 'summary'
| 'action_result'
| 'warning';
export interface PuzzleAgentMessage {
id: string;
role: PuzzleAgentMessageRole;
kind: PuzzleAgentMessageKind;
text: string;
createdAt: string;
}
export interface PuzzleAgentSessionSnapshot {
sessionId: string;
currentTurn: number;
progressPercent: number;
stage: PuzzleAgentStage;
anchorPack: PuzzleAnchorPack;
draft: PuzzleResultDraft | null;
messages: PuzzleAgentMessage[];
lastAssistantReply: string | null;
publishedProfileId: string | null;
suggestedActions: PuzzleAgentSuggestedAction[];
resultPreview: PuzzleResultPreviewEnvelope | null;
updatedAt: string;
}
export interface CreatePuzzleAgentSessionRequest {
seedText?: string;
}
export interface CreatePuzzleAgentSessionResponse {
session: PuzzleAgentSessionSnapshot;
}
export interface SendPuzzleAgentMessageRequest {
clientMessageId: string;
text: string;
}
export interface SendPuzzleAgentMessageResponse extends PuzzleAgentActionResponse {
session: PuzzleAgentSessionSnapshot;
}

View File

@@ -0,0 +1,21 @@
import type { PuzzleResultDraft } from './puzzleAgentDraft';
export interface PuzzleResultPreviewBlocker {
id: string;
code: string;
message: string;
}
export interface PuzzleResultPreviewFinding {
id: string;
severity: 'info' | 'warning' | 'blocker';
code: string;
message: string;
}
export interface PuzzleResultPreviewEnvelope {
draft: PuzzleResultDraft;
blockers: PuzzleResultPreviewBlocker[];
qualityFindings: PuzzleResultPreviewFinding[];
publishReady: boolean;
}

View File

@@ -0,0 +1,74 @@
export type PuzzleGridSize = 3 | 4;
export interface PuzzleCellPosition {
row: number;
col: number;
}
export interface PuzzlePieceState {
pieceId: string;
correctRow: number;
correctCol: number;
currentRow: number;
currentCol: number;
mergedGroupId: string | null;
}
export interface PuzzleMergedGroupState {
groupId: string;
pieceIds: string[];
occupiedCells: PuzzleCellPosition[];
}
export interface PuzzleBoardSnapshot {
rows: number;
cols: number;
pieces: PuzzlePieceState[];
mergedGroups: PuzzleMergedGroupState[];
selectedPieceId: string | null;
allTilesResolved: boolean;
}
export interface PuzzleRuntimeLevelSnapshot {
runId: string;
levelIndex: number;
gridSize: PuzzleGridSize;
profileId: string;
levelName: string;
authorDisplayName: string;
themeTags: string[];
coverImageSrc: string | null;
board: PuzzleBoardSnapshot;
status: 'playing' | 'cleared';
}
export interface PuzzleRunSnapshot {
runId: string;
entryProfileId: string;
clearedLevelCount: number;
currentLevelIndex: number;
currentGridSize: PuzzleGridSize;
playedProfileIds: string[];
previousLevelTags: string[];
currentLevel: PuzzleRuntimeLevelSnapshot | null;
recommendedNextProfileId: string | null;
}
export interface StartPuzzleRunRequest {
profileId: string;
}
export interface PuzzleRunResponse {
run: PuzzleRunSnapshot;
}
export interface SwapPuzzlePiecesRequest {
firstPieceId: string;
secondPieceId: string;
}
export interface DragPuzzlePieceRequest {
pieceId: string;
targetRow: number;
targetCol: number;
}

View File

@@ -0,0 +1,39 @@
import type { JsonObject } from './common';
import type { PuzzleAnchorPack } from './puzzleAgentDraft';
export type PuzzleWorkPublicationStatus = 'draft' | 'published';
export interface PuzzleWorkSummary {
workId: string;
profileId: string;
ownerUserId: string;
sourceSessionId?: string | null;
authorDisplayName: string;
levelName: string;
summary: string;
themeTags: string[];
coverImageSrc: string | null;
coverAssetId?: string | null;
publicationStatus: PuzzleWorkPublicationStatus;
updatedAt: string;
publishedAt: string | null;
playCount: number;
publishReady: boolean;
}
export interface PuzzleWorkProfile extends PuzzleWorkSummary {
anchorPack: PuzzleAnchorPack;
metadata?: JsonObject | null;
}
export interface PuzzleWorksResponse {
items: PuzzleWorkSummary[];
}
export interface PuzzleWorkDetailResponse {
item: PuzzleWorkProfile;
}
export interface PuzzleWorkMutationResponse {
item: PuzzleWorkProfile;
}

View File

@@ -579,7 +579,7 @@ export function createRpgAgentSessionFixture(): RpgAgentSessionSnapshot {
lockState: {
lockedCardIds: ['world-foundation'],
},
draftProfile,
draftProfile: draftProfile as unknown as Record<string, unknown>,
messages: [
{
id: 'message-1',

View File

@@ -1,5 +1,6 @@
export * from './assets/qwenSprite';
export * from './contracts/auth';
export type * from './contracts/bigFish';
export * from './contracts/common';
export type * from './contracts/customWorldAgent';
export * from './contracts/rpgAgentActions';
@@ -9,6 +10,12 @@ export * from './contracts/rpgAgentSession';
export * from './contracts/rpgCreationFixtures';
export * from './contracts/rpgCreationPreview';
export * from './contracts/rpgCreationWorkSummary';
export * from './contracts/puzzleAgentActions';
export * from './contracts/puzzleAgentDraft';
export * from './contracts/puzzleAgentSession';
export * from './contracts/puzzleResultPreview';
export * from './contracts/puzzleRuntimeSession';
export * from './contracts/puzzleWorkSummary';
export * from './contracts/rpgRuntimeChat';
export * from './contracts/rpgRuntimeQuestAssist';
export * from './contracts/rpgRuntimeStoryAction';

View File

@@ -1,11 +1,12 @@
import net from 'node:net';
import path from 'node:path';
import {spawn} from 'node:child_process';
import {existsSync, readFileSync} from 'node:fs';
import net from 'node:net';
import path from 'node:path';
import {fileURLToPath, pathToFileURL} from 'node:url';
const repoRoot = fileURLToPath(new URL('../', import.meta.url));
const serverRoot = fileURLToPath(new URL('../server-node/', import.meta.url));
const serverRsRoot = fileURLToPath(new URL('../server-rs/', import.meta.url));
const viteCliPath = fileURLToPath(new URL('./vite-cli.mjs', import.meta.url));
const serverTsxCliPath = fileURLToPath(
new URL('../server-node/node_modules/tsx/dist/cli.mjs', import.meta.url),
@@ -16,6 +17,8 @@ const serverTsxLoaderPath = fileURLToPath(
const serverTsxLoaderUrl = pathToFileURL(serverTsxLoaderPath).href;
const envExamplePath = fileURLToPath(new URL('../.env.example', import.meta.url));
const envLocalPath = fileURLToPath(new URL('../.env.local', import.meta.url));
const spacetimeConfigPath = fileURLToPath(new URL('../spacetime.json', import.meta.url));
const spacetimeLocalConfigPath = fileURLToPath(new URL('../spacetime.local.json', import.meta.url));
const bundledNodePath = fileURLToPath(
new URL('../.tools/node-v22.22.2-win-x64/node.exe', import.meta.url),
);
@@ -25,6 +28,11 @@ const bundledNpmCliPath = fileURLToPath(
const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
const DEFAULT_DEV_DATABASE_URL = 'postgresql://postgres:postgres@127.0.0.1:5432/genarrative';
const DEV_MEMORY_DATABASE_URL = 'pg-mem://genarrative-dev';
const DEFAULT_RUST_API_HOST = '127.0.0.1';
const DEFAULT_RUST_API_PORT = '3100';
const DEFAULT_SPACETIME_SERVER_URL = 'http://127.0.0.1:3001';
const DEFAULT_SPACETIME_DATABASE = 'genarrative-dev';
const DEFAULT_INTERNAL_API_SECRET = 'genarrative-dev-internal-bridge';
function parseEnvContents(contents) {
return contents
@@ -63,6 +71,18 @@ function readEnvFile(filePath) {
return parseEnvContents(readFileSync(filePath, 'utf8'));
}
function readJsonFile(filePath) {
if (!existsSync(filePath)) {
return null;
}
try {
return JSON.parse(readFileSync(filePath, 'utf8'));
} catch {
return null;
}
}
function resolveDatabaseProbeTarget(databaseUrl) {
const trimmed = databaseUrl.trim();
if (!trimmed || !/^postgres(?:ql)?:\/\//u.test(trimmed)) {
@@ -177,6 +197,8 @@ function prependEnvPath(envMap, nextEntry) {
const exampleEnv = readEnvFile(envExamplePath);
const localEnv = readEnvFile(envLocalPath);
const spacetimeConfig = readJsonFile(spacetimeConfigPath);
const spacetimeLocalConfig = readJsonFile(spacetimeLocalConfigPath);
const mergedEnv = {
...exampleEnv,
@@ -196,6 +218,22 @@ mergedEnv.PROJECT_ROOT = mergedEnv.PROJECT_ROOT || repoRoot;
mergedEnv.NODE_SERVER_ADDR = mergedEnv.NODE_SERVER_ADDR || ':8081';
mergedEnv.NODE_SERVER_TARGET =
mergedEnv.NODE_SERVER_TARGET || resolveServerTarget(mergedEnv.NODE_SERVER_ADDR);
mergedEnv.GENARRATIVE_API_HOST =
mergedEnv.GENARRATIVE_API_HOST || DEFAULT_RUST_API_HOST;
mergedEnv.GENARRATIVE_API_PORT =
mergedEnv.GENARRATIVE_API_PORT || DEFAULT_RUST_API_PORT;
mergedEnv.GENARRATIVE_API_TARGET =
mergedEnv.GENARRATIVE_API_TARGET ||
`http://${mergedEnv.GENARRATIVE_API_HOST}:${mergedEnv.GENARRATIVE_API_PORT}`;
mergedEnv.GENARRATIVE_INTERNAL_API_SECRET =
mergedEnv.GENARRATIVE_INTERNAL_API_SECRET || DEFAULT_INTERNAL_API_SECRET;
mergedEnv.GENARRATIVE_SPACETIME_SERVER_URL =
mergedEnv.GENARRATIVE_SPACETIME_SERVER_URL || DEFAULT_SPACETIME_SERVER_URL;
mergedEnv.GENARRATIVE_SPACETIME_DATABASE =
mergedEnv.GENARRATIVE_SPACETIME_DATABASE ||
spacetimeLocalConfig?.database ||
spacetimeConfig?.database ||
DEFAULT_SPACETIME_DATABASE;
mergedEnv.DATABASE_URL =
mergedEnv.DATABASE_URL || DEFAULT_DEV_DATABASE_URL;
mergedEnv.VITE_DEV_HOST = mergedEnv.VITE_DEV_HOST || '127.0.0.1';
@@ -205,9 +243,23 @@ mergedEnv.npm_config_scripts_prepend_node_path = 'true';
const exampleDatabaseUrl = `${exampleEnv.DATABASE_URL || ''}`.trim();
const localDatabaseUrl = `${localEnv.DATABASE_URL || ''}`.trim();
const processDatabaseUrl = `${process.env.DATABASE_URL || ''}`.trim();
const exampleSpacetimeDatabase = `${exampleEnv.GENARRATIVE_SPACETIME_DATABASE || ''}`.trim();
const localSpacetimeDatabase = `${localEnv.GENARRATIVE_SPACETIME_DATABASE || ''}`.trim();
const processSpacetimeDatabase = `${process.env.GENARRATIVE_SPACETIME_DATABASE || ''}`.trim();
const hasExplicitDatabaseUrl =
Boolean(processDatabaseUrl) ||
(Boolean(localDatabaseUrl) && localDatabaseUrl !== exampleDatabaseUrl);
const hasExplicitSpacetimeDatabase =
Boolean(processSpacetimeDatabase) ||
(Boolean(localSpacetimeDatabase) && localSpacetimeDatabase !== exampleSpacetimeDatabase);
// 本地开发默认跟随仓库当前的 Spacetime 数据库名,只有显式覆盖时才尊重环境变量。
if (!hasExplicitSpacetimeDatabase) {
mergedEnv.GENARRATIVE_SPACETIME_DATABASE =
spacetimeLocalConfig?.database ||
spacetimeConfig?.database ||
DEFAULT_SPACETIME_DATABASE;
}
if (!hasExplicitDatabaseUrl) {
const databaseProbeTarget = resolveDatabaseProbeTarget(mergedEnv.DATABASE_URL);
@@ -228,6 +280,14 @@ if (!hasExplicitDatabaseUrl) {
console.log(`[dev:node] PROJECT_ROOT=${mergedEnv.PROJECT_ROOT}`);
console.log(`[dev:node] NODE_SERVER_ADDR=${mergedEnv.NODE_SERVER_ADDR}`);
console.log(`[dev:node] NODE_SERVER_TARGET=${mergedEnv.NODE_SERVER_TARGET}`);
console.log(`[dev:node] GENARRATIVE_API_TARGET=${mergedEnv.GENARRATIVE_API_TARGET}`);
console.log('[dev:node] GENARRATIVE_INTERNAL_API_SECRET=[configured]');
console.log(
`[dev:node] GENARRATIVE_SPACETIME_SERVER_URL=${mergedEnv.GENARRATIVE_SPACETIME_SERVER_URL}`,
);
console.log(
`[dev:node] GENARRATIVE_SPACETIME_DATABASE=${mergedEnv.GENARRATIVE_SPACETIME_DATABASE}`,
);
console.log(`[dev:node] DATABASE_URL=${redactDatabaseUrl(mergedEnv.DATABASE_URL)}`);
console.log(`[dev:node] VITE_DEV_HOST=${mergedEnv.VITE_DEV_HOST}`);
console.log(`[dev:node] NODE_RUNTIME=${runtimeNodePath}`);
@@ -329,6 +389,38 @@ const serverProcess = existsSync(serverTsxLoaderPath)
stdio: 'inherit',
});
const rustApiProcess = process.platform === 'win32'
? spawn(
'powershell',
[
'-NoProfile',
'-ExecutionPolicy',
'Bypass',
'-File',
path.join(serverRsRoot, 'scripts', 'dev.ps1'),
'-ApiHost',
mergedEnv.GENARRATIVE_API_HOST,
'-Port',
mergedEnv.GENARRATIVE_API_PORT,
],
{
cwd: repoRoot,
env: mergedEnv,
stdio: 'inherit',
},
)
: spawn(
'bash',
[
path.join(serverRsRoot, 'scripts', 'dev.sh'),
],
{
cwd: repoRoot,
env: mergedEnv,
stdio: 'inherit',
},
);
const viteProcess = spawn(
runtimeNodePath,
[viteCliPath, '--port=3000', `--host=${mergedEnv.VITE_DEV_HOST}`],
@@ -340,6 +432,7 @@ const viteProcess = spawn(
);
registerChild('node server', serverProcess, () => viteProcess);
registerChild('rust api-server', rustApiProcess, () => viteProcess);
registerChild('vite dev server', viteProcess, () => serverProcess);
process.on('SIGINT', () => {

View File

@@ -10,12 +10,14 @@ import { responseEnvelopeMiddleware } from './middleware/responseEnvelope.js';
import { createCharacterAssetRoutes } from './modules/assets/characterAssetRoutes.js';
import { createEditorRoutes } from './modules/editor/editorRoutes.js';
import { createAuthRoutes } from './routes/authRoutes.js';
import { createBigFishProxyRoutes } from './routes/bigFishProxyRoutes.js';
import { createCustomWorldAgentRoutes } from './routes/customWorldAgent.js';
import { createPuzzleProxyRoutes } from './routes/puzzleProxyRoutes.js';
import { createRpgEntrySaveRoutes } from './routes/rpg-entry/rpgEntrySaveRoutes.js';
import { createRpgWorldLibraryRoutes } from './routes/rpg-entry/rpgWorldLibraryRoutes.js';
import { createRpgProfileRoutes } from './routes/rpg-profile/rpgProfileRoutes.js';
import { createRpgRuntimeAiAssistRoutes } from './routes/rpg-runtime/rpgRuntimeAiAssistRoutes.js';
import { createRpgRuntimeStoryRoutes } from './routes/rpg-runtime/rpgRuntimeStoryRoutes.js';
import { createCustomWorldAgentRoutes } from './routes/customWorldAgent.js';
function matchesRoutePrefix(
request: express.Request,
@@ -212,6 +214,16 @@ export function createApp(context: AppContext) {
withRouteMeta({ routeVersion: '2026-04-21', operation: 'rpg.creation.agent.api' }),
createCustomWorldAgentRoutes(context),
);
app.use(
'/api/runtime/big-fish',
withRouteMeta({ routeVersion: '2026-04-22', operation: 'bigFish.runtime.proxy.api' }),
createBigFishProxyRoutes(context),
);
app.use(
'/api/runtime/puzzle',
withRouteMeta({ routeVersion: '2026-04-22', operation: 'puzzle.runtime.proxy.api' }),
createPuzzleProxyRoutes(context),
);
app.use(
express.static(context.config.publicDir, {
fallthrough: true,

View File

@@ -0,0 +1,329 @@
import { Readable } from 'node:stream';
import { type Request, type Response,Router } from 'express';
import type { AppContext } from '../context.js';
import { badRequest, upstreamError } from '../errors.js';
import {
API_RESPONSE_ENVELOPE_HEADER,
API_VERSION_HEADER,
asyncHandler,
prepareApiResponse,
RESPONSE_TIME_HEADER,
ROUTE_VERSION_HEADER,
} from '../http.js';
import { requireJwtAuth } from '../middleware/auth.js';
import { routeMeta } from '../middleware/routeMeta.js';
const BIG_FISH_ROUTE_VERSION = '2026-04-22';
const DEFAULT_RUST_API_TARGET = 'http://127.0.0.1:3100';
const DEFAULT_INTERNAL_API_SECRET = 'genarrative-dev-internal-bridge';
const INTERNAL_USER_HEADER = 'x-genarrative-authenticated-user-id';
const INTERNAL_SECRET_HEADER = 'x-genarrative-internal-api-secret';
function resolveRustApiTarget(context: AppContext) {
const configured =
context.config.rawEnv.GENARRATIVE_API_TARGET?.trim() ||
context.config.rawEnv.RUST_API_SERVER_TARGET?.trim() ||
'';
return configured || DEFAULT_RUST_API_TARGET;
}
function resolveInternalApiSecret(context: AppContext) {
return (
context.config.rawEnv.GENARRATIVE_INTERNAL_API_SECRET?.trim() ||
DEFAULT_INTERNAL_API_SECRET
);
}
function normalizeRouteSuffix(path: string) {
const normalized = path.startsWith('/') ? path : `/${path}`;
return normalized.replace(/\/+$/u, '');
}
function buildUpstreamUrl(context: AppContext, pathSuffix: string) {
const baseUrl = resolveRustApiTarget(context).replace(/\/+$/u, '');
return `${baseUrl}${normalizeRouteSuffix(pathSuffix)}`;
}
function pickForwardHeaders(
request: Request,
context: AppContext,
userId: string,
) {
const forwardedHeaders = new Headers();
const contentType = request.header('content-type')?.trim();
if (contentType) {
forwardedHeaders.set('content-type', contentType);
}
const accept = request.header('accept')?.trim();
if (accept) {
forwardedHeaders.set('accept', accept);
}
const requestId = request.requestId?.trim();
if (requestId) {
forwardedHeaders.set('x-request-id', requestId);
}
const envelope = request.header(API_RESPONSE_ENVELOPE_HEADER)?.trim();
if (envelope) {
forwardedHeaders.set(API_RESPONSE_ENVELOPE_HEADER, envelope);
}
forwardedHeaders.set(INTERNAL_USER_HEADER, userId);
const internalSecret = resolveInternalApiSecret(context);
if (internalSecret) {
forwardedHeaders.set(INTERNAL_SECRET_HEADER, internalSecret);
}
return forwardedHeaders;
}
function readBodyAllowed(method: string) {
return !['GET', 'HEAD'].includes(method.toUpperCase());
}
async function proxyBigFishRequest(params: {
context: AppContext;
request: Request;
response: Response;
pathSuffix: string;
streamBody?: boolean;
}) {
const { context, request, response, pathSuffix, streamBody = false } = params;
const userId = request.userId?.trim();
if (!userId) {
throw badRequest('缺少已认证用户上下文');
}
const upstreamUrl = buildUpstreamUrl(context, pathSuffix);
const method = request.method.toUpperCase();
const body =
readBodyAllowed(method) && request.body !== undefined
? JSON.stringify(request.body)
: undefined;
let upstreamResponse: globalThis.Response;
try {
upstreamResponse = await fetch(upstreamUrl, {
method,
// 这里显式转发“已通过 Node 校验的用户身份”,让 Big Fish 继续由 Rust 真相后端处理。
headers: pickForwardHeaders(request, context, userId),
body,
});
} catch (error) {
request.log?.error(
{
err: error,
user_id: userId,
upstream_url: upstreamUrl,
},
'big fish upstream request failed',
);
throw upstreamError('大鱼吃小鱼后端暂时不可用');
}
prepareApiResponse(request, response, {
statusCode: upstreamResponse.status,
headers: {
'Content-Type':
upstreamResponse.headers.get('content-type') ||
'application/json; charset=utf-8',
'Cache-Control':
upstreamResponse.headers.get('cache-control') || 'no-cache',
},
routeMeta: {
routeVersion: BIG_FISH_ROUTE_VERSION,
},
});
const upstreamRequestId = upstreamResponse.headers.get('x-request-id');
if (upstreamRequestId) {
response.setHeader('x-upstream-request-id', upstreamRequestId);
}
const upstreamRouteVersion = upstreamResponse.headers.get(ROUTE_VERSION_HEADER);
if (upstreamRouteVersion) {
response.setHeader('x-upstream-route-version', upstreamRouteVersion);
}
const upstreamApiVersion = upstreamResponse.headers.get(API_VERSION_HEADER);
if (upstreamApiVersion) {
response.setHeader('x-upstream-api-version', upstreamApiVersion);
}
const upstreamLatency = upstreamResponse.headers.get(RESPONSE_TIME_HEADER);
if (upstreamLatency) {
response.setHeader('x-upstream-response-time-ms', upstreamLatency);
}
if (streamBody) {
if (!upstreamResponse.body) {
throw upstreamError('大鱼吃小鱼流式响应不可用');
}
response.flushHeaders?.();
await Readable.fromWeb(upstreamResponse.body as never).pipe(response);
return;
}
response.end(await upstreamResponse.text());
}
function readParam(value: string | string[] | undefined) {
return Array.isArray(value) ? value[0]?.trim() || '' : value?.trim() || '';
}
export function createBigFishProxyRoutes(context: AppContext) {
const router = Router();
const requireAuth = requireJwtAuth(context.config, context.userRepository);
router.use(requireAuth);
router.post(
'/agent/sessions',
routeMeta({ operation: 'runtime.bigFish.createSession', routeVersion: BIG_FISH_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
await proxyBigFishRequest({
context,
request,
response,
pathSuffix: '/api/runtime/big-fish/agent/sessions',
});
}),
);
router.get(
'/agent/sessions/:sessionId',
routeMeta({ operation: 'runtime.bigFish.getSession', routeVersion: BIG_FISH_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
const sessionId = readParam(request.params.sessionId);
if (!sessionId) {
throw badRequest('sessionId is required');
}
await proxyBigFishRequest({
context,
request,
response,
pathSuffix: `/api/runtime/big-fish/agent/sessions/${encodeURIComponent(sessionId)}`,
});
}),
);
router.post(
'/agent/sessions/:sessionId/messages',
routeMeta({ operation: 'runtime.bigFish.sendMessage', routeVersion: BIG_FISH_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
const sessionId = readParam(request.params.sessionId);
if (!sessionId) {
throw badRequest('sessionId is required');
}
await proxyBigFishRequest({
context,
request,
response,
pathSuffix: `/api/runtime/big-fish/agent/sessions/${encodeURIComponent(sessionId)}/messages`,
});
}),
);
router.post(
'/agent/sessions/:sessionId/messages/stream',
routeMeta({
operation: 'runtime.bigFish.streamMessage',
routeVersion: BIG_FISH_ROUTE_VERSION,
}),
asyncHandler(async (request, response) => {
const sessionId = readParam(request.params.sessionId);
if (!sessionId) {
throw badRequest('sessionId is required');
}
await proxyBigFishRequest({
context,
request,
response,
pathSuffix: `/api/runtime/big-fish/agent/sessions/${encodeURIComponent(sessionId)}/messages/stream`,
streamBody: true,
});
}),
);
router.post(
'/agent/sessions/:sessionId/actions',
routeMeta({ operation: 'runtime.bigFish.executeAction', routeVersion: BIG_FISH_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
const sessionId = readParam(request.params.sessionId);
if (!sessionId) {
throw badRequest('sessionId is required');
}
await proxyBigFishRequest({
context,
request,
response,
pathSuffix: `/api/runtime/big-fish/agent/sessions/${encodeURIComponent(sessionId)}/actions`,
});
}),
);
router.post(
'/sessions/:sessionId/runs',
routeMeta({ operation: 'runtime.bigFish.startRun', routeVersion: BIG_FISH_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
const sessionId = readParam(request.params.sessionId);
if (!sessionId) {
throw badRequest('sessionId is required');
}
await proxyBigFishRequest({
context,
request,
response,
pathSuffix: `/api/runtime/big-fish/sessions/${encodeURIComponent(sessionId)}/runs`,
});
}),
);
router.get(
'/runs/:runId',
routeMeta({ operation: 'runtime.bigFish.getRun', routeVersion: BIG_FISH_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
const runId = readParam(request.params.runId);
if (!runId) {
throw badRequest('runId is required');
}
await proxyBigFishRequest({
context,
request,
response,
pathSuffix: `/api/runtime/big-fish/runs/${encodeURIComponent(runId)}`,
});
}),
);
router.post(
'/runs/:runId/input',
routeMeta({ operation: 'runtime.bigFish.submitInput', routeVersion: BIG_FISH_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
const runId = readParam(request.params.runId);
if (!runId) {
throw badRequest('runId is required');
}
await proxyBigFishRequest({
context,
request,
response,
pathSuffix: `/api/runtime/big-fish/runs/${encodeURIComponent(runId)}/input`,
});
}),
);
return router;
}

View File

@@ -0,0 +1,439 @@
import { Readable } from 'node:stream';
import { type Request, type Response, Router } from 'express';
import type { AppContext } from '../context.js';
import { badRequest, upstreamError } from '../errors.js';
import {
API_RESPONSE_ENVELOPE_HEADER,
API_VERSION_HEADER,
asyncHandler,
prepareApiResponse,
RESPONSE_TIME_HEADER,
ROUTE_VERSION_HEADER,
} from '../http.js';
import { requireJwtAuth } from '../middleware/auth.js';
import { routeMeta } from '../middleware/routeMeta.js';
const PUZZLE_ROUTE_VERSION = '2026-04-22';
const DEFAULT_RUST_API_TARGET = 'http://127.0.0.1:3100';
const DEFAULT_INTERNAL_API_SECRET = 'genarrative-dev-internal-bridge';
const INTERNAL_USER_HEADER = 'x-genarrative-authenticated-user-id';
const INTERNAL_SECRET_HEADER = 'x-genarrative-internal-api-secret';
function resolveRustApiTarget(context: AppContext) {
const configured =
context.config.rawEnv.GENARRATIVE_API_TARGET?.trim() ||
context.config.rawEnv.RUST_API_SERVER_TARGET?.trim() ||
'';
return configured || DEFAULT_RUST_API_TARGET;
}
function resolveInternalApiSecret(context: AppContext) {
return (
context.config.rawEnv.GENARRATIVE_INTERNAL_API_SECRET?.trim() ||
DEFAULT_INTERNAL_API_SECRET
);
}
function normalizeRouteSuffix(path: string) {
const normalized = path.startsWith('/') ? path : `/${path}`;
return normalized.replace(/\/+$/u, '');
}
function buildUpstreamUrl(context: AppContext, pathSuffix: string) {
const baseUrl = resolveRustApiTarget(context).replace(/\/+$/u, '');
return `${baseUrl}${normalizeRouteSuffix(pathSuffix)}`;
}
function pickForwardHeaders(
request: Request,
context: AppContext,
userId: string,
) {
const forwardedHeaders = new Headers();
const contentType = request.header('content-type')?.trim();
if (contentType) {
forwardedHeaders.set('content-type', contentType);
}
const accept = request.header('accept')?.trim();
if (accept) {
forwardedHeaders.set('accept', accept);
}
const requestId = request.requestId?.trim();
if (requestId) {
forwardedHeaders.set('x-request-id', requestId);
}
const envelope = request.header(API_RESPONSE_ENVELOPE_HEADER)?.trim();
if (envelope) {
forwardedHeaders.set(API_RESPONSE_ENVELOPE_HEADER, envelope);
}
forwardedHeaders.set(INTERNAL_USER_HEADER, userId);
const internalSecret = resolveInternalApiSecret(context);
if (internalSecret) {
forwardedHeaders.set(INTERNAL_SECRET_HEADER, internalSecret);
}
return forwardedHeaders;
}
function readBodyAllowed(method: string) {
return !['GET', 'HEAD'].includes(method.toUpperCase());
}
async function proxyPuzzleRequest(params: {
context: AppContext;
request: Request;
response: Response;
pathSuffix: string;
streamBody?: boolean;
}) {
const { context, request, response, pathSuffix, streamBody = false } = params;
const userId = request.userId?.trim();
if (!userId) {
throw badRequest('缺少已认证用户上下文');
}
const upstreamUrl = buildUpstreamUrl(context, pathSuffix);
const method = request.method.toUpperCase();
const body =
readBodyAllowed(method) && request.body !== undefined
? JSON.stringify(request.body)
: undefined;
let upstreamResponse: globalThis.Response;
try {
upstreamResponse = await fetch(upstreamUrl, {
method,
headers: pickForwardHeaders(request, context, userId),
body,
});
} catch (error) {
request.log?.error(
{
err: error,
user_id: userId,
upstream_url: upstreamUrl,
},
'puzzle upstream request failed',
);
throw upstreamError('拼图后端暂时不可用');
}
prepareApiResponse(request, response, {
statusCode: upstreamResponse.status,
headers: {
'Content-Type':
upstreamResponse.headers.get('content-type') ||
'application/json; charset=utf-8',
'Cache-Control':
upstreamResponse.headers.get('cache-control') || 'no-cache',
},
routeMeta: {
routeVersion: PUZZLE_ROUTE_VERSION,
},
});
const upstreamRequestId = upstreamResponse.headers.get('x-request-id');
if (upstreamRequestId) {
response.setHeader('x-upstream-request-id', upstreamRequestId);
}
const upstreamRouteVersion = upstreamResponse.headers.get(ROUTE_VERSION_HEADER);
if (upstreamRouteVersion) {
response.setHeader('x-upstream-route-version', upstreamRouteVersion);
}
const upstreamApiVersion = upstreamResponse.headers.get(API_VERSION_HEADER);
if (upstreamApiVersion) {
response.setHeader('x-upstream-api-version', upstreamApiVersion);
}
const upstreamLatency = upstreamResponse.headers.get(RESPONSE_TIME_HEADER);
if (upstreamLatency) {
response.setHeader('x-upstream-response-time-ms', upstreamLatency);
}
if (streamBody) {
if (!upstreamResponse.body) {
throw upstreamError('拼图流式响应不可用');
}
response.flushHeaders?.();
await Readable.fromWeb(upstreamResponse.body as never).pipe(response);
return;
}
response.end(await upstreamResponse.text());
}
function readParam(value: string | string[] | undefined) {
return Array.isArray(value) ? value[0]?.trim() || '' : value?.trim() || '';
}
export function createPuzzleProxyRoutes(context: AppContext) {
const router = Router();
const requireAuth = requireJwtAuth(context.config, context.userRepository);
router.use(requireAuth);
router.post(
'/agent/sessions',
routeMeta({ operation: 'runtime.puzzle.createSession', routeVersion: PUZZLE_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
await proxyPuzzleRequest({
context,
request,
response,
pathSuffix: '/api/runtime/puzzle/agent/sessions',
});
}),
);
router.get(
'/agent/sessions/:sessionId',
routeMeta({ operation: 'runtime.puzzle.getSession', routeVersion: PUZZLE_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
const sessionId = readParam(request.params.sessionId);
if (!sessionId) {
throw badRequest('sessionId is required');
}
await proxyPuzzleRequest({
context,
request,
response,
pathSuffix: `/api/runtime/puzzle/agent/sessions/${encodeURIComponent(sessionId)}`,
});
}),
);
router.post(
'/agent/sessions/:sessionId/messages',
routeMeta({ operation: 'runtime.puzzle.sendMessage', routeVersion: PUZZLE_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
const sessionId = readParam(request.params.sessionId);
if (!sessionId) {
throw badRequest('sessionId is required');
}
await proxyPuzzleRequest({
context,
request,
response,
pathSuffix: `/api/runtime/puzzle/agent/sessions/${encodeURIComponent(sessionId)}/messages`,
});
}),
);
router.post(
'/agent/sessions/:sessionId/messages/stream',
routeMeta({
operation: 'runtime.puzzle.streamMessage',
routeVersion: PUZZLE_ROUTE_VERSION,
}),
asyncHandler(async (request, response) => {
const sessionId = readParam(request.params.sessionId);
if (!sessionId) {
throw badRequest('sessionId is required');
}
await proxyPuzzleRequest({
context,
request,
response,
pathSuffix: `/api/runtime/puzzle/agent/sessions/${encodeURIComponent(sessionId)}/messages/stream`,
streamBody: true,
});
}),
);
router.post(
'/agent/sessions/:sessionId/actions',
routeMeta({ operation: 'runtime.puzzle.executeAction', routeVersion: PUZZLE_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
const sessionId = readParam(request.params.sessionId);
if (!sessionId) {
throw badRequest('sessionId is required');
}
await proxyPuzzleRequest({
context,
request,
response,
pathSuffix: `/api/runtime/puzzle/agent/sessions/${encodeURIComponent(sessionId)}/actions`,
});
}),
);
router.get(
'/works',
routeMeta({ operation: 'runtime.puzzle.listWorks', routeVersion: PUZZLE_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
await proxyPuzzleRequest({
context,
request,
response,
pathSuffix: '/api/runtime/puzzle/works',
});
}),
);
router.get(
'/works/:profileId',
routeMeta({ operation: 'runtime.puzzle.getWorkDetail', routeVersion: PUZZLE_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
const profileId = readParam(request.params.profileId);
if (!profileId) {
throw badRequest('profileId is required');
}
await proxyPuzzleRequest({
context,
request,
response,
pathSuffix: `/api/runtime/puzzle/works/${encodeURIComponent(profileId)}`,
});
}),
);
router.put(
'/works/:profileId',
routeMeta({ operation: 'runtime.puzzle.updateWork', routeVersion: PUZZLE_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
const profileId = readParam(request.params.profileId);
if (!profileId) {
throw badRequest('profileId is required');
}
await proxyPuzzleRequest({
context,
request,
response,
pathSuffix: `/api/runtime/puzzle/works/${encodeURIComponent(profileId)}`,
});
}),
);
router.get(
'/gallery',
routeMeta({ operation: 'runtime.puzzle.listGallery', routeVersion: PUZZLE_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
await proxyPuzzleRequest({
context,
request,
response,
pathSuffix: '/api/runtime/puzzle/gallery',
});
}),
);
router.get(
'/gallery/:profileId',
routeMeta({ operation: 'runtime.puzzle.getGalleryDetail', routeVersion: PUZZLE_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
const profileId = readParam(request.params.profileId);
if (!profileId) {
throw badRequest('profileId is required');
}
await proxyPuzzleRequest({
context,
request,
response,
pathSuffix: `/api/runtime/puzzle/gallery/${encodeURIComponent(profileId)}`,
});
}),
);
router.post(
'/runs',
routeMeta({ operation: 'runtime.puzzle.startRun', routeVersion: PUZZLE_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
await proxyPuzzleRequest({
context,
request,
response,
pathSuffix: '/api/runtime/puzzle/runs',
});
}),
);
router.get(
'/runs/:runId',
routeMeta({ operation: 'runtime.puzzle.getRun', routeVersion: PUZZLE_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
const runId = readParam(request.params.runId);
if (!runId) {
throw badRequest('runId is required');
}
await proxyPuzzleRequest({
context,
request,
response,
pathSuffix: `/api/runtime/puzzle/runs/${encodeURIComponent(runId)}`,
});
}),
);
router.post(
'/runs/:runId/swap',
routeMeta({ operation: 'runtime.puzzle.swapPieces', routeVersion: PUZZLE_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
const runId = readParam(request.params.runId);
if (!runId) {
throw badRequest('runId is required');
}
await proxyPuzzleRequest({
context,
request,
response,
pathSuffix: `/api/runtime/puzzle/runs/${encodeURIComponent(runId)}/swap`,
});
}),
);
router.post(
'/runs/:runId/drag',
routeMeta({ operation: 'runtime.puzzle.dragPiece', routeVersion: PUZZLE_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
const runId = readParam(request.params.runId);
if (!runId) {
throw badRequest('runId is required');
}
await proxyPuzzleRequest({
context,
request,
response,
pathSuffix: `/api/runtime/puzzle/runs/${encodeURIComponent(runId)}/drag`,
});
}),
);
router.post(
'/runs/:runId/next-level',
routeMeta({ operation: 'runtime.puzzle.nextLevel', routeVersion: PUZZLE_ROUTE_VERSION }),
asyncHandler(async (request, response) => {
const runId = readParam(request.params.runId);
if (!runId) {
throw badRequest('runId is required');
}
await proxyPuzzleRequest({
context,
request,
response,
pathSuffix: `/api/runtime/puzzle/runs/${encodeURIComponent(runId)}/next-level`,
});
}),
);
return router;
}

26
server-rs/Cargo.lock generated
View File

@@ -78,6 +78,7 @@ dependencies = [
"module-ai",
"module-assets",
"module-auth",
"module-big-fish",
"module-combat",
"module-custom-world",
"module-inventory",
@@ -1425,6 +1426,16 @@ dependencies = [
"uuid",
]
[[package]]
name = "module-big-fish"
version = "0.1.0"
dependencies = [
"serde",
"serde_json",
"shared-kernel",
"spacetimedb",
]
[[package]]
name = "module-combat"
version = "0.1.0"
@@ -1471,6 +1482,16 @@ dependencies = [
"spacetimedb",
]
[[package]]
name = "module-puzzle"
version = "0.1.0"
dependencies = [
"serde",
"serde_json",
"shared-kernel",
"spacetimedb",
]
[[package]]
name = "module-quest"
version = "0.1.0"
@@ -2487,10 +2508,12 @@ version = "0.1.0"
dependencies = [
"module-ai",
"module-assets",
"module-big-fish",
"module-combat",
"module-custom-world",
"module-inventory",
"module-npc",
"module-puzzle",
"module-runtime",
"module-runtime-item",
"module-story",
@@ -2507,15 +2530,18 @@ dependencies = [
"log",
"module-ai",
"module-assets",
"module-big-fish",
"module-combat",
"module-custom-world",
"module-inventory",
"module-npc",
"module-progression",
"module-puzzle",
"module-quest",
"module-runtime",
"module-runtime-item",
"module-story",
"serde",
"serde_json",
"shared-kernel",
"spacetimedb",

View File

@@ -8,10 +8,12 @@ members = [
"crates/module-ai",
"crates/module-assets",
"crates/module-auth",
"crates/module-big-fish",
"crates/module-combat",
"crates/module-inventory",
"crates/module-custom-world",
"crates/module-npc",
"crates/module-puzzle",
"crates/module-progression",
"crates/module-quest",
"crates/module-runtime",

View File

@@ -11,6 +11,7 @@ reqwest = { version = "0.12", default-features = false, features = ["json", "rus
module-ai = { path = "../module-ai" }
module-assets = { path = "../module-assets" }
module-auth = { path = "../module-auth" }
module-big-fish = { path = "../module-big-fish" }
module-combat = { path = "../module-combat" }
module-custom-world = { path = "../module-custom-world" }
module-inventory = { path = "../module-inventory" }

View File

@@ -24,6 +24,11 @@ use crate::{
},
auth_me::auth_me,
auth_sessions::auth_sessions,
big_fish::{
create_big_fish_session, execute_big_fish_action, get_big_fish_run, get_big_fish_session,
start_big_fish_run, stream_big_fish_message, submit_big_fish_input,
submit_big_fish_message,
},
custom_world::{
create_custom_world_agent_session, execute_custom_world_agent_action,
get_custom_world_agent_card_detail,
@@ -48,6 +53,13 @@ use crate::{
logout_all::logout_all,
password_entry::password_entry,
phone_auth::{phone_login, send_phone_code},
puzzle::{
advance_puzzle_next_level, create_puzzle_agent_session, drag_puzzle_piece_or_group,
execute_puzzle_agent_action, get_puzzle_agent_session, get_puzzle_gallery_detail,
get_puzzle_run, get_puzzle_work_detail, get_puzzle_works, list_puzzle_gallery,
put_puzzle_work, start_puzzle_run, stream_puzzle_agent_message,
submit_puzzle_agent_message, swap_puzzle_pieces,
},
refresh_session::refresh_session,
request_context::{attach_request_context, resolve_request_id},
response_headers::propagate_request_id_header,
@@ -348,6 +360,153 @@ pub fn build_router(state: AppState) -> Router {
require_bearer_auth,
)),
)
.route(
"/api/runtime/big-fish/agent/sessions",
post(create_big_fish_session).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/big-fish/agent/sessions/{session_id}",
get(get_big_fish_session).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/big-fish/agent/sessions/{session_id}/messages",
post(submit_big_fish_message).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/big-fish/agent/sessions/{session_id}/messages/stream",
post(stream_big_fish_message).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/big-fish/agent/sessions/{session_id}/actions",
post(execute_big_fish_action).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/big-fish/sessions/{session_id}/runs",
post(start_big_fish_run).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/big-fish/runs/{run_id}",
get(get_big_fish_run).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/big-fish/runs/{run_id}/input",
post(submit_big_fish_input).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/puzzle/agent/sessions",
post(create_puzzle_agent_session).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/puzzle/agent/sessions/{session_id}",
get(get_puzzle_agent_session).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/puzzle/agent/sessions/{session_id}/messages",
post(submit_puzzle_agent_message).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/puzzle/agent/sessions/{session_id}/messages/stream",
post(stream_puzzle_agent_message).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/puzzle/agent/sessions/{session_id}/actions",
post(execute_puzzle_agent_action).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/puzzle/works",
get(get_puzzle_works).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/puzzle/works/{profile_id}",
get(get_puzzle_work_detail)
.put(put_puzzle_work)
.route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route("/api/runtime/puzzle/gallery", get(list_puzzle_gallery))
.route(
"/api/runtime/puzzle/gallery/{profile_id}",
get(get_puzzle_gallery_detail),
)
.route(
"/api/runtime/puzzle/runs",
post(start_puzzle_run).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/puzzle/runs/{run_id}",
get(get_puzzle_run).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/puzzle/runs/{run_id}/swap",
post(swap_puzzle_pieces).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/puzzle/runs/{run_id}/drag",
post(drag_puzzle_piece_or_group).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/runtime/puzzle/runs/{run_id}/next-level",
post(advance_puzzle_next_level).route_layer(middleware::from_fn_with_state(
state.clone(),
require_bearer_auth,
)),
)
.route(
"/api/custom-world/entity",
post(generate_custom_world_entity).route_layer(middleware::from_fn_with_state(

View File

@@ -8,8 +8,12 @@ use axum::{
middleware::Next,
response::Response,
};
use platform_auth::{AccessTokenClaims, read_refresh_session_token, verify_access_token};
use platform_auth::{
AccessTokenClaims, AuthProvider, BindingStatus, read_refresh_session_token,
verify_access_token,
};
use serde_json::{Value, json};
use time::OffsetDateTime;
use tracing::warn;
use crate::{
@@ -17,6 +21,9 @@ use crate::{
state::AppState,
};
const INTERNAL_AUTH_USER_ID_HEADER: &str = "x-genarrative-authenticated-user-id";
const INTERNAL_API_SECRET_HEADER: &str = "x-genarrative-internal-api-secret";
// 统一把已校验的 claims 写入 request extensions避免后续 handler 再次重复解析 Bearer token。
#[derive(Clone, Debug)]
pub struct AuthenticatedAccessToken {
@@ -53,6 +60,15 @@ pub async fn require_bearer_auth(
mut request: Request,
next: Next,
) -> Result<Response, AppError> {
if request.uri().path().starts_with("/api/runtime/big-fish/")
&& let Some(claims) = try_build_internal_forwarded_claims(&state, request.headers())
{
request
.extensions_mut()
.insert(AuthenticatedAccessToken::new(claims));
return Ok(next.run(request).await);
}
let bearer_token = extract_bearer_token(request.headers())?;
let request_id = request
.extensions()
@@ -172,13 +188,60 @@ fn extract_bearer_token(headers: &HeaderMap) -> Result<String, AppError> {
Ok(token.to_string())
}
fn try_build_internal_forwarded_claims(
state: &AppState,
headers: &HeaderMap,
) -> Option<AccessTokenClaims> {
let expected_secret = state.config.internal_api_secret.as_ref()?.trim();
if expected_secret.is_empty() {
return None;
}
let provided_secret = headers
.get(INTERNAL_API_SECRET_HEADER)
.and_then(|value| value.to_str().ok())
.map(str::trim)
.filter(|value| !value.is_empty())?;
if provided_secret != expected_secret {
return None;
}
let user_id = headers
.get(INTERNAL_AUTH_USER_ID_HEADER)
.and_then(|value| value.to_str().ok())
.map(str::trim)
.filter(|value| !value.is_empty())?
.to_string();
// 这里的 claims 只服务于经 Node 已鉴权后的本地内部转发链路,避免在开发态复制整套账号仓储。
AccessTokenClaims::from_input(
platform_auth::AccessTokenClaimsInput {
user_id: user_id.clone(),
session_id: format!("internal-forwarded-{user_id}"),
provider: AuthProvider::Password,
roles: vec!["user".to_string()],
token_version: 0,
phone_verified: false,
binding_status: BindingStatus::Active,
display_name: None,
},
state.auth_jwt_config(),
OffsetDateTime::now_utc(),
)
.ok()
}
#[cfg(test)]
mod tests {
use super::{RefreshSessionToken, extract_bearer_token};
use super::{
INTERNAL_API_SECRET_HEADER, INTERNAL_AUTH_USER_ID_HEADER, RefreshSessionToken,
extract_bearer_token, try_build_internal_forwarded_claims,
};
use axum::{
http::{HeaderMap, HeaderValue, StatusCode, header::AUTHORIZATION},
response::IntoResponse,
};
use crate::{config::AppConfig, state::AppState};
#[test]
fn extract_bearer_token_accepts_standard_header() {
@@ -209,4 +272,26 @@ mod tests {
assert_eq!(token.token(), "refresh-token-01");
}
#[test]
fn internal_forwarded_claims_require_matching_secret() {
let mut config = AppConfig::default();
config.internal_api_secret = Some("bridge-secret".to_string());
let state = AppState::new(config).expect("state should build");
let mut headers = HeaderMap::new();
headers.insert(
INTERNAL_AUTH_USER_ID_HEADER,
HeaderValue::from_static("user_forwarded_01"),
);
headers.insert(
INTERNAL_API_SECRET_HEADER,
HeaderValue::from_static("bridge-secret"),
);
let claims =
try_build_internal_forwarded_claims(&state, &headers).expect("claims should resolve");
assert_eq!(claims.user_id(), "user_forwarded_01");
assert_eq!(claims.token_version(), 0);
}
}

View File

@@ -0,0 +1,653 @@
use axum::{
Json,
extract::{Extension, Path, State, rejection::JsonRejection},
http::{HeaderName, StatusCode, header},
response::{IntoResponse, Response},
};
use serde_json::{Value, json};
use shared_contracts::big_fish::{
BigFishActionResponse, BigFishAgentMessageResponse, BigFishAnchorItemResponse,
BigFishAnchorPackResponse, BigFishAssetCoverageResponse, BigFishAssetSlotResponse,
BigFishBackgroundBlueprintResponse, BigFishGameDraftResponse, BigFishLevelBlueprintResponse,
BigFishRuntimeEntityResponse, BigFishRuntimeParamsResponse, BigFishRuntimeSnapshotResponse,
BigFishRunResponse, BigFishSessionResponse, BigFishSessionSnapshotResponse,
BigFishVector2Response, CreateBigFishSessionRequest, ExecuteBigFishActionRequest,
SendBigFishMessageRequest, SubmitBigFishInputRequest,
};
use shared_kernel::build_prefixed_uuid_id;
use spacetime_client::{
BigFishAgentMessageRecord, BigFishAnchorItemRecord, BigFishAnchorPackRecord,
BigFishAssetCoverageRecord, BigFishAssetGenerateRecordInput, BigFishAssetSlotRecord,
BigFishBackgroundBlueprintRecord, BigFishGameDraftRecord, BigFishLevelBlueprintRecord,
BigFishMessageSubmitRecordInput, BigFishRunInputSubmitRecordInput, BigFishRunStartRecordInput,
BigFishRuntimeEntityRecord, BigFishRuntimeParamsRecord, BigFishRuntimeRecord,
BigFishSessionCreateRecordInput, BigFishSessionRecord, BigFishVector2Record,
SpacetimeClientError,
};
use crate::{
api_response::json_success_body, auth::AuthenticatedAccessToken, http_error::AppError,
request_context::RequestContext, state::AppState,
};
pub async fn create_big_fish_session(
State(state): State<AppState>,
Extension(request_context): Extension<RequestContext>,
Extension(authenticated): Extension<AuthenticatedAccessToken>,
payload: Result<Json<CreateBigFishSessionRequest>, JsonRejection>,
) -> Result<Json<Value>, Response> {
let Json(payload) = payload.map_err(|error| {
big_fish_error_response(
&request_context,
AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({
"provider": "big-fish",
"message": error.body_text(),
})),
)
})?;
let seed_text = payload.seed_text.unwrap_or_default().trim().to_string();
let session = state
.spacetime_client()
.create_big_fish_session(BigFishSessionCreateRecordInput {
session_id: build_prefixed_uuid_id("big-fish-session-"),
owner_user_id: authenticated.claims().user_id().to_string(),
seed_text: seed_text.clone(),
welcome_message_id: build_prefixed_uuid_id("big-fish-message-"),
welcome_message_text: build_big_fish_welcome_text(&seed_text),
created_at_micros: current_utc_micros(),
})
.await
.map_err(|error| big_fish_error_response(&request_context, map_big_fish_client_error(error)))?;
Ok(json_success_body(
Some(&request_context),
BigFishSessionResponse {
session: map_big_fish_session_response(session),
},
))
}
pub async fn get_big_fish_session(
State(state): State<AppState>,
Path(session_id): Path<String>,
Extension(request_context): Extension<RequestContext>,
Extension(authenticated): Extension<AuthenticatedAccessToken>,
) -> Result<Json<Value>, Response> {
ensure_non_empty(&request_context, &session_id, "sessionId")?;
let session = state
.spacetime_client()
.get_big_fish_session(session_id, authenticated.claims().user_id().to_string())
.await
.map_err(|error| big_fish_error_response(&request_context, map_big_fish_client_error(error)))?;
Ok(json_success_body(
Some(&request_context),
BigFishSessionResponse {
session: map_big_fish_session_response(session),
},
))
}
pub async fn submit_big_fish_message(
State(state): State<AppState>,
Path(session_id): Path<String>,
Extension(request_context): Extension<RequestContext>,
Extension(authenticated): Extension<AuthenticatedAccessToken>,
payload: Result<Json<SendBigFishMessageRequest>, JsonRejection>,
) -> Result<Json<Value>, Response> {
let Json(payload) = payload.map_err(|error| {
big_fish_error_response(
&request_context,
AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({
"provider": "big-fish",
"message": error.body_text(),
})),
)
})?;
ensure_non_empty(&request_context, &session_id, "sessionId")?;
let client_message_id = payload.client_message_id.trim().to_string();
let message_text = payload.text.trim().to_string();
if client_message_id.is_empty() || message_text.is_empty() {
return Err(big_fish_bad_request(
&request_context,
"clientMessageId and text are required",
));
}
let session = state
.spacetime_client()
.submit_big_fish_message(BigFishMessageSubmitRecordInput {
session_id,
owner_user_id: authenticated.claims().user_id().to_string(),
user_message_id: client_message_id,
user_message_text: message_text,
assistant_message_id: build_prefixed_uuid_id("big-fish-message-"),
submitted_at_micros: current_utc_micros(),
})
.await
.map_err(|error| big_fish_error_response(&request_context, map_big_fish_client_error(error)))?;
Ok(json_success_body(
Some(&request_context),
BigFishSessionResponse {
session: map_big_fish_session_response(session),
},
))
}
pub async fn stream_big_fish_message(
State(state): State<AppState>,
Path(session_id): Path<String>,
Extension(request_context): Extension<RequestContext>,
Extension(authenticated): Extension<AuthenticatedAccessToken>,
payload: Result<Json<SendBigFishMessageRequest>, JsonRejection>,
) -> Result<Response, Response> {
let Json(payload) = payload.map_err(|error| {
big_fish_error_response(
&request_context,
AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({
"provider": "big-fish",
"message": error.body_text(),
})),
)
})?;
ensure_non_empty(&request_context, &session_id, "sessionId")?;
let owner_user_id = authenticated.claims().user_id().to_string();
let session = state
.spacetime_client()
.submit_big_fish_message(BigFishMessageSubmitRecordInput {
session_id,
owner_user_id,
user_message_id: payload.client_message_id.trim().to_string(),
user_message_text: payload.text.trim().to_string(),
assistant_message_id: build_prefixed_uuid_id("big-fish-message-"),
submitted_at_micros: current_utc_micros(),
})
.await
.map_err(|error| big_fish_error_response(&request_context, map_big_fish_client_error(error)))?;
let session_response = map_big_fish_session_response(session);
let reply_text = session_response
.last_assistant_reply
.clone()
.unwrap_or_else(|| "锚点已更新。".to_string());
let mut sse_body = String::new();
append_sse_event(&request_context, &mut sse_body, "reply_delta", &json!({ "text": reply_text }))?;
append_sse_event(&request_context, &mut sse_body, "session", &json!({ "session": session_response }))?;
append_sse_event(&request_context, &mut sse_body, "done", &json!({ "ok": true }))?;
Ok(build_event_stream_response(sse_body))
}
pub async fn execute_big_fish_action(
State(state): State<AppState>,
Path(session_id): Path<String>,
Extension(request_context): Extension<RequestContext>,
Extension(authenticated): Extension<AuthenticatedAccessToken>,
payload: Result<Json<ExecuteBigFishActionRequest>, JsonRejection>,
) -> Result<Json<Value>, Response> {
let Json(payload) = payload.map_err(|error| {
big_fish_error_response(
&request_context,
AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({
"provider": "big-fish",
"message": error.body_text(),
})),
)
})?;
ensure_non_empty(&request_context, &session_id, "sessionId")?;
let owner_user_id = authenticated.claims().user_id().to_string();
let now = current_utc_micros();
let session = match payload.action.trim() {
"big_fish_compile_draft" => {
state
.spacetime_client()
.compile_big_fish_draft(session_id, owner_user_id, now)
.await
}
"big_fish_generate_level_main_image" => {
state
.spacetime_client()
.generate_big_fish_asset(BigFishAssetGenerateRecordInput {
session_id,
owner_user_id,
asset_kind: "level_main_image".to_string(),
level: payload.level,
motion_key: None,
generated_at_micros: now,
})
.await
}
"big_fish_generate_level_motion" => {
state
.spacetime_client()
.generate_big_fish_asset(BigFishAssetGenerateRecordInput {
session_id,
owner_user_id,
asset_kind: "level_motion".to_string(),
level: payload.level,
motion_key: payload.motion_key,
generated_at_micros: now,
})
.await
}
"big_fish_generate_stage_background" => {
state
.spacetime_client()
.generate_big_fish_asset(BigFishAssetGenerateRecordInput {
session_id,
owner_user_id,
asset_kind: "stage_background".to_string(),
level: None,
motion_key: None,
generated_at_micros: now,
})
.await
}
"big_fish_publish_game" => {
state
.spacetime_client()
.publish_big_fish_game(session_id, owner_user_id, now)
.await
}
other => {
return Err(big_fish_bad_request(
&request_context,
format!("action `{other}` is not supported").as_str(),
));
}
}
.map_err(|error| big_fish_error_response(&request_context, map_big_fish_client_error(error)))?;
Ok(json_success_body(
Some(&request_context),
BigFishActionResponse {
session: map_big_fish_session_response(session),
},
))
}
pub async fn start_big_fish_run(
State(state): State<AppState>,
Path(session_id): Path<String>,
Extension(request_context): Extension<RequestContext>,
Extension(authenticated): Extension<AuthenticatedAccessToken>,
) -> Result<Json<Value>, Response> {
ensure_non_empty(&request_context, &session_id, "sessionId")?;
let run = state
.spacetime_client()
.start_big_fish_run(BigFishRunStartRecordInput {
run_id: build_prefixed_uuid_id("big-fish-run-"),
session_id,
owner_user_id: authenticated.claims().user_id().to_string(),
started_at_micros: current_utc_micros(),
})
.await
.map_err(|error| big_fish_error_response(&request_context, map_big_fish_client_error(error)))?;
Ok(json_success_body(
Some(&request_context),
BigFishRunResponse {
run: map_big_fish_runtime_response(run),
},
))
}
pub async fn get_big_fish_run(
State(state): State<AppState>,
Path(run_id): Path<String>,
Extension(request_context): Extension<RequestContext>,
Extension(authenticated): Extension<AuthenticatedAccessToken>,
) -> Result<Json<Value>, Response> {
ensure_non_empty(&request_context, &run_id, "runId")?;
let run = state
.spacetime_client()
.get_big_fish_run(run_id, authenticated.claims().user_id().to_string())
.await
.map_err(|error| big_fish_error_response(&request_context, map_big_fish_client_error(error)))?;
Ok(json_success_body(
Some(&request_context),
BigFishRunResponse {
run: map_big_fish_runtime_response(run),
},
))
}
pub async fn submit_big_fish_input(
State(state): State<AppState>,
Path(run_id): Path<String>,
Extension(request_context): Extension<RequestContext>,
Extension(authenticated): Extension<AuthenticatedAccessToken>,
payload: Result<Json<SubmitBigFishInputRequest>, JsonRejection>,
) -> Result<Json<Value>, Response> {
let Json(payload) = payload.map_err(|error| {
big_fish_error_response(
&request_context,
AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({
"provider": "big-fish",
"message": error.body_text(),
})),
)
})?;
ensure_non_empty(&request_context, &run_id, "runId")?;
let run = state
.spacetime_client()
.submit_big_fish_input(BigFishRunInputSubmitRecordInput {
run_id,
owner_user_id: authenticated.claims().user_id().to_string(),
input_x: payload.x,
input_y: payload.y,
submitted_at_micros: current_utc_micros(),
})
.await
.map_err(|error| big_fish_error_response(&request_context, map_big_fish_client_error(error)))?;
Ok(json_success_body(
Some(&request_context),
BigFishRunResponse {
run: map_big_fish_runtime_response(run),
},
))
}
fn map_big_fish_session_response(session: BigFishSessionRecord) -> BigFishSessionSnapshotResponse {
BigFishSessionSnapshotResponse {
session_id: session.session_id,
current_turn: session.current_turn,
progress_percent: session.progress_percent,
stage: session.stage,
anchor_pack: map_big_fish_anchor_pack_response(session.anchor_pack),
draft: session.draft.map(map_big_fish_draft_response),
asset_slots: session
.asset_slots
.into_iter()
.map(map_big_fish_asset_slot_response)
.collect(),
asset_coverage: map_big_fish_asset_coverage_response(session.asset_coverage),
messages: session
.messages
.into_iter()
.map(map_big_fish_agent_message_response)
.collect(),
last_assistant_reply: session.last_assistant_reply,
publish_ready: session.publish_ready,
updated_at: session.updated_at,
}
}
fn map_big_fish_anchor_pack_response(anchor_pack: BigFishAnchorPackRecord) -> BigFishAnchorPackResponse {
BigFishAnchorPackResponse {
gameplay_promise: map_big_fish_anchor_item_response(anchor_pack.gameplay_promise),
ecology_visual_theme: map_big_fish_anchor_item_response(anchor_pack.ecology_visual_theme),
growth_ladder: map_big_fish_anchor_item_response(anchor_pack.growth_ladder),
risk_tempo: map_big_fish_anchor_item_response(anchor_pack.risk_tempo),
}
}
fn map_big_fish_anchor_item_response(anchor: BigFishAnchorItemRecord) -> BigFishAnchorItemResponse {
BigFishAnchorItemResponse {
key: anchor.key,
label: anchor.label,
value: anchor.value,
status: anchor.status,
}
}
fn map_big_fish_draft_response(draft: BigFishGameDraftRecord) -> BigFishGameDraftResponse {
BigFishGameDraftResponse {
title: draft.title,
subtitle: draft.subtitle,
core_fun: draft.core_fun,
ecology_theme: draft.ecology_theme,
levels: draft
.levels
.into_iter()
.map(map_big_fish_level_response)
.collect(),
background: map_big_fish_background_response(draft.background),
runtime_params: map_big_fish_runtime_params_response(draft.runtime_params),
}
}
fn map_big_fish_level_response(level: BigFishLevelBlueprintRecord) -> BigFishLevelBlueprintResponse {
BigFishLevelBlueprintResponse {
level: level.level,
name: level.name,
one_line_fantasy: level.one_line_fantasy,
silhouette_direction: level.silhouette_direction,
size_ratio: level.size_ratio,
visual_prompt_seed: level.visual_prompt_seed,
motion_prompt_seed: level.motion_prompt_seed,
merge_source_level: level.merge_source_level,
prey_window: level.prey_window,
threat_window: level.threat_window,
is_final_level: level.is_final_level,
}
}
fn map_big_fish_background_response(
background: BigFishBackgroundBlueprintRecord,
) -> BigFishBackgroundBlueprintResponse {
BigFishBackgroundBlueprintResponse {
theme: background.theme,
color_mood: background.color_mood,
foreground_hints: background.foreground_hints,
midground_composition: background.midground_composition,
background_depth: background.background_depth,
safe_play_area_hint: background.safe_play_area_hint,
spawn_edge_hint: background.spawn_edge_hint,
background_prompt_seed: background.background_prompt_seed,
}
}
fn map_big_fish_runtime_params_response(
params: BigFishRuntimeParamsRecord,
) -> BigFishRuntimeParamsResponse {
BigFishRuntimeParamsResponse {
level_count: params.level_count,
merge_count_per_upgrade: params.merge_count_per_upgrade,
spawn_target_count: params.spawn_target_count,
leader_move_speed: params.leader_move_speed,
follower_catch_up_speed: params.follower_catch_up_speed,
offscreen_cull_seconds: params.offscreen_cull_seconds,
prey_spawn_delta_levels: params.prey_spawn_delta_levels,
threat_spawn_delta_levels: params.threat_spawn_delta_levels,
win_level: params.win_level,
}
}
fn map_big_fish_asset_slot_response(slot: BigFishAssetSlotRecord) -> BigFishAssetSlotResponse {
BigFishAssetSlotResponse {
slot_id: slot.slot_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: slot.updated_at,
}
}
fn map_big_fish_asset_coverage_response(
coverage: BigFishAssetCoverageRecord,
) -> BigFishAssetCoverageResponse {
BigFishAssetCoverageResponse {
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,
required_level_count: coverage.required_level_count,
publish_ready: coverage.publish_ready,
blockers: coverage.blockers,
}
}
fn map_big_fish_agent_message_response(
message: BigFishAgentMessageRecord,
) -> BigFishAgentMessageResponse {
BigFishAgentMessageResponse {
id: message.message_id,
role: message.role,
kind: message.kind,
text: message.text,
created_at: message.created_at,
}
}
fn map_big_fish_runtime_response(run: BigFishRuntimeRecord) -> BigFishRuntimeSnapshotResponse {
BigFishRuntimeSnapshotResponse {
run_id: run.run_id,
session_id: run.session_id,
status: run.status,
tick: run.tick,
player_level: run.player_level,
win_level: run.win_level,
leader_entity_id: run.leader_entity_id,
owned_entities: run
.owned_entities
.into_iter()
.map(map_big_fish_entity_response)
.collect(),
wild_entities: run
.wild_entities
.into_iter()
.map(map_big_fish_entity_response)
.collect(),
camera_center: map_big_fish_vector_response(run.camera_center),
last_input: map_big_fish_vector_response(run.last_input),
event_log: run.event_log,
updated_at: run.updated_at,
}
}
fn map_big_fish_entity_response(entity: BigFishRuntimeEntityRecord) -> BigFishRuntimeEntityResponse {
BigFishRuntimeEntityResponse {
entity_id: entity.entity_id,
level: entity.level,
position: map_big_fish_vector_response(entity.position),
radius: entity.radius,
offscreen_seconds: entity.offscreen_seconds,
}
}
fn map_big_fish_vector_response(vector: BigFishVector2Record) -> BigFishVector2Response {
BigFishVector2Response {
x: vector.x,
y: vector.y,
}
}
fn build_big_fish_welcome_text(seed_text: &str) -> String {
if seed_text.trim().is_empty() {
return "我会先帮你确定大鱼吃小鱼的核心锚点。可以从主题生态、成长阶梯或风险节奏开始。".to_string();
}
"我已经收到你的玩法起点,会先把它整理成锚点并准备结果页草稿。".to_string()
}
fn ensure_non_empty(
request_context: &RequestContext,
value: &str,
field_name: &str,
) -> Result<(), Response> {
if value.trim().is_empty() {
return Err(big_fish_bad_request(
request_context,
format!("{field_name} is required").as_str(),
));
}
Ok(())
}
fn big_fish_bad_request(request_context: &RequestContext, message: &str) -> Response {
big_fish_error_response(
request_context,
AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({
"provider": "big-fish",
"message": message,
})),
)
}
fn append_sse_event(
request_context: &RequestContext,
body: &mut String,
event: &str,
payload: &Value,
) -> Result<(), Response> {
let payload_text = serde_json::to_string(payload).map_err(|error| {
big_fish_error_response(
request_context,
AppError::from_status(StatusCode::INTERNAL_SERVER_ERROR).with_details(json!({
"provider": "big-fish",
"message": format!("SSE payload 序列化失败:{error}"),
})),
)
})?;
body.push_str("event: ");
body.push_str(event);
body.push('\n');
body.push_str("data: ");
body.push_str(&payload_text);
body.push_str("\n\n");
Ok(())
}
fn build_event_stream_response(body: String) -> Response {
(
[
(header::CONTENT_TYPE, "text/event-stream; charset=utf-8"),
(header::CACHE_CONTROL, "no-cache"),
(HeaderName::from_static("x-accel-buffering"), "no"),
],
body,
)
.into_response()
}
fn map_big_fish_client_error(error: SpacetimeClientError) -> AppError {
let status = match &error {
SpacetimeClientError::Procedure(message)
if message.contains("big_fish_creation_session 不存在")
|| message.contains("big_fish_runtime_run 不存在") =>
{
StatusCode::NOT_FOUND
}
SpacetimeClientError::Procedure(message)
if message.contains("不能为空")
|| message.contains("尚未编译")
|| message.contains("不允许")
|| message.contains("非法")
|| message.contains("缺少") =>
{
StatusCode::BAD_REQUEST
}
SpacetimeClientError::Runtime(_) => StatusCode::BAD_REQUEST,
_ => StatusCode::BAD_GATEWAY,
};
AppError::from_status(status).with_details(json!({
"provider": "spacetimedb",
"message": error.to_string(),
}))
}
fn big_fish_error_response(request_context: &RequestContext, error: AppError) -> Response {
error.into_response_with_context(Some(request_context))
}
fn current_utc_micros() -> i64 {
use std::time::{SystemTime, UNIX_EPOCH};
let duration = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("system clock should be after unix epoch");
i64::try_from(duration.as_micros()).expect("current unix micros should fit in i64")
}

View File

@@ -6,6 +6,7 @@ use platform_llm::{
};
const DEFAULT_LLM_MODEL: &str = "doubao-1-5-pro-32k-character-250715";
const DEFAULT_INTERNAL_API_SECRET: &str = "genarrative-dev-internal-bridge";
// 集中管理 api-server 的启动配置,避免入口层直接散落环境变量解析逻辑。
#[derive(Clone, Debug)]
@@ -13,6 +14,7 @@ pub struct AppConfig {
pub bind_host: String,
pub bind_port: u16,
pub log_filter: String,
pub internal_api_secret: Option<String>,
pub jwt_issuer: String,
pub jwt_secret: String,
pub jwt_access_token_ttl_seconds: u64,
@@ -62,6 +64,7 @@ impl Default for AppConfig {
bind_host: "127.0.0.1".to_string(),
bind_port: 3000,
log_filter: "info,tower_http=info".to_string(),
internal_api_secret: Some(DEFAULT_INTERNAL_API_SECRET.to_string()),
jwt_issuer: "https://auth.genarrative.local".to_string(),
jwt_secret: "genarrative-dev-secret".to_string(),
jwt_access_token_ttl_seconds: 2 * 60 * 60,
@@ -130,6 +133,9 @@ impl AppConfig {
config.log_filter = log_filter;
}
config.internal_api_secret =
read_first_non_empty_env(&["GENARRATIVE_INTERNAL_API_SECRET"]);
if let Some(jwt_issuer) =
read_first_non_empty_env(&["GENARRATIVE_JWT_ISSUER", "JWT_ISSUER"])
{

View File

@@ -6,6 +6,7 @@ mod auth;
mod auth_me;
mod auth_session;
mod auth_sessions;
mod big_fish;
mod config;
mod custom_world;
mod custom_world_ai;
@@ -18,6 +19,7 @@ mod logout;
mod logout_all;
mod password_entry;
mod phone_auth;
mod puzzle;
mod refresh_session;
mod request_context;
mod response_headers;

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
use axum::{
Json,
extract::{Extension, State},
extract::{Extension, Path, State, rejection::JsonRejection},
http::StatusCode,
response::Response,
};
@@ -54,6 +54,91 @@ pub async fn resolve_runtime_story_state(
))
}
pub async fn get_runtime_story_state(
State(_state): State<AppState>,
Path(session_id): Path<String>,
Extension(request_context): Extension<RequestContext>,
Extension(_authenticated): Extension<AuthenticatedAccessToken>,
) -> Result<Json<Value>, Response> {
let session_id = normalize_required_string(session_id.as_str()).ok_or_else(|| {
runtime_story_error_response(
&request_context,
AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({
"provider": "runtime-story",
"field": "sessionId",
"message": "sessionId 不能为空",
})),
)
})?;
Ok(json_success_body(
Some(&request_context),
build_runtime_story_state_response(&session_id, None, build_runtime_story_empty_snapshot(&session_id)),
))
}
pub async fn resolve_runtime_story_action(
State(_state): State<AppState>,
Extension(request_context): Extension<RequestContext>,
Extension(_authenticated): Extension<AuthenticatedAccessToken>,
payload: Result<Json<Value>, JsonRejection>,
) -> Result<Json<Value>, Response> {
let payload = optional_runtime_story_payload(payload)?;
let session_id = read_payload_session_id(&payload).ok_or_else(|| {
runtime_story_error_response(
&request_context,
AppError::from_status(StatusCode::BAD_REQUEST).with_details(json!({
"provider": "runtime-story",
"field": "sessionId",
"message": "sessionId 不能为空",
})),
)
})?;
let client_version = read_u32_field(&payload, "clientVersion");
let snapshot = read_payload_snapshot(&payload)
.unwrap_or_else(|| build_runtime_story_empty_snapshot(&session_id));
let mut response = build_runtime_story_state_response(&session_id, client_version, snapshot);
response.presentation.action_text = read_runtime_story_action_text(&payload).unwrap_or_default();
Ok(json_success_body(Some(&request_context), response))
}
pub async fn generate_runtime_story_initial(
State(_state): State<AppState>,
Extension(request_context): Extension<RequestContext>,
Extension(_authenticated): Extension<AuthenticatedAccessToken>,
payload: Result<Json<Value>, JsonRejection>,
) -> Result<Json<Value>, Response> {
let payload = optional_runtime_story_payload(payload)?;
let session_id = read_payload_session_id(&payload).unwrap_or_else(|| "runtime-main".to_string());
let client_version = read_u32_field(&payload, "clientVersion");
let snapshot = read_payload_snapshot(&payload)
.unwrap_or_else(|| build_runtime_story_empty_snapshot(&session_id));
Ok(json_success_body(
Some(&request_context),
build_runtime_story_state_response(&session_id, client_version, snapshot),
))
}
pub async fn generate_runtime_story_continue(
State(_state): State<AppState>,
Extension(request_context): Extension<RequestContext>,
Extension(_authenticated): Extension<AuthenticatedAccessToken>,
payload: Result<Json<Value>, JsonRejection>,
) -> Result<Json<Value>, Response> {
let payload = optional_runtime_story_payload(payload)?;
let session_id = read_payload_session_id(&payload).unwrap_or_else(|| "runtime-main".to_string());
let client_version = read_u32_field(&payload, "clientVersion");
let snapshot = read_payload_snapshot(&payload)
.unwrap_or_else(|| build_runtime_story_empty_snapshot(&session_id));
Ok(json_success_body(
Some(&request_context),
build_runtime_story_state_response(&session_id, client_version, snapshot),
))
}
fn build_runtime_story_state_response(
requested_session_id: &str,
client_version: Option<u32>,
@@ -107,6 +192,61 @@ fn build_runtime_story_state_response(
}
}
fn optional_runtime_story_payload(
payload: Result<Json<Value>, JsonRejection>,
) -> Result<Value, Response> {
match payload {
Ok(Json(value)) => Ok(value),
Err(error) if error.status() == StatusCode::UNSUPPORTED_MEDIA_TYPE => Ok(json!({})),
Err(error) if error.status() == StatusCode::BAD_REQUEST => Ok(json!({})),
Err(error) => Err(AppError::from_status(StatusCode::BAD_REQUEST)
.with_details(json!({
"provider": "runtime-story",
"message": error.body_text(),
}))
.into_response_with_context(None)),
}
}
fn read_payload_session_id(payload: &Value) -> Option<String> {
read_required_string_field(payload, "sessionId")
.or_else(|| read_field(payload, "action").and_then(|action| read_required_string_field(action, "sessionId")))
.or_else(|| read_field(payload, "snapshot").and_then(|snapshot| {
read_object_field(snapshot, "gameState").and_then(read_runtime_session_id)
}))
}
fn read_payload_snapshot(payload: &Value) -> Option<RuntimeStorySnapshotPayload> {
let snapshot = read_field(payload, "snapshot")?.clone();
serde_json::from_value(snapshot).ok()
}
fn read_runtime_story_action_text(payload: &Value) -> Option<String> {
let action = read_field(payload, "action")?;
read_optional_string_field(action, "functionId")
.or_else(|| read_optional_string_field(action, "type"))
}
fn build_runtime_story_empty_snapshot(session_id: &str) -> RuntimeStorySnapshotPayload {
RuntimeStorySnapshotPayload {
saved_at: time::OffsetDateTime::now_utc()
.format(&time::format_description::well_known::Rfc3339)
.unwrap_or_else(|_| "1970-01-01T00:00:00Z".to_string()),
bottom_tab: "adventure".to_string(),
game_state: json!({
"runtimeSessionId": session_id,
"runtimeActionVersion": 0,
"playerHp": 1,
"playerMaxHp": 1,
"playerMana": 0,
"playerMaxMana": 1,
"inBattle": false,
"npcInteractionActive": false
}),
current_story: None,
}
}
fn build_runtime_story_companions(game_state: &Value) -> Vec<RuntimeStoryCompanionViewModel> {
read_array_field(game_state, "companions")
.into_iter()

View File

@@ -0,0 +1,15 @@
[package]
name = "module-big-fish"
edition.workspace = true
version.workspace = true
license.workspace = true
[features]
default = []
spacetime-types = ["dep:spacetimedb"]
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
shared-kernel = { path = "../shared-kernel" }
spacetimedb = { workspace = true, optional = true }

File diff suppressed because it is too large Load Diff

View File

@@ -153,6 +153,7 @@ pub enum CustomWorldFieldError {
MissingMessageText,
MissingOperationId,
MissingPhaseLabel,
MissingAction,
InvalidProgressPercent,
MissingCardId,
MissingCardTitle,
@@ -290,6 +291,7 @@ pub struct CustomWorldAgentSessionSnapshot {
pub lock_state_json: Option<String>,
pub draft_profile_json: Option<String>,
pub last_assistant_reply: Option<String>,
pub publish_gate_json: Option<String>,
pub result_preview_json: Option<String>,
pub pending_clarifications_json: String,
pub quality_findings_json: String,
@@ -297,6 +299,7 @@ pub struct CustomWorldAgentSessionSnapshot {
pub recommended_replies_json: String,
pub asset_coverage_json: String,
pub checkpoints_json: String,
pub supported_actions_json: String,
pub messages: Vec<CustomWorldAgentMessageSnapshot>,
pub draft_cards: Vec<CustomWorldDraftCardSnapshot>,
pub operations: Vec<CustomWorldAgentOperationSnapshot>,
@@ -425,6 +428,126 @@ pub struct CustomWorldAgentOperationProcedureResult {
pub error_message: Option<String>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CustomWorldWorksListInput {
pub owner_user_id: String,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CustomWorldPublishBlockerSnapshot {
pub blocker_id: String,
pub code: String,
pub message: String,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CustomWorldPublishGateSnapshot {
pub profile_id: String,
pub blockers: Vec<CustomWorldPublishBlockerSnapshot>,
pub blocker_count: u32,
pub publish_ready: bool,
pub can_enter_world: bool,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CustomWorldWorkSummarySnapshot {
pub work_id: String,
pub source_type: String,
pub status: String,
pub title: String,
pub subtitle: String,
pub summary: String,
pub cover_image_src: Option<String>,
pub cover_render_mode: Option<String>,
pub cover_character_image_srcs_json: String,
pub updated_at_micros: i64,
pub published_at_micros: Option<i64>,
pub stage: Option<RpgAgentStage>,
pub stage_label: Option<String>,
pub playable_npc_count: u32,
pub landmark_count: u32,
pub role_visual_ready_count: Option<u32>,
pub role_animation_ready_count: Option<u32>,
pub role_asset_summary_label: Option<String>,
pub session_id: Option<String>,
pub profile_id: Option<String>,
pub can_resume: bool,
pub can_enter_world: bool,
pub blocker_count: u32,
pub publish_ready: bool,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CustomWorldWorksListResult {
pub ok: bool,
pub items: Vec<CustomWorldWorkSummarySnapshot>,
pub error_message: Option<String>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CustomWorldAgentCardDetailGetInput {
pub session_id: String,
pub owner_user_id: String,
pub card_id: String,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CustomWorldDraftCardDetailSectionSnapshot {
pub section_id: String,
pub label: String,
pub value: String,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CustomWorldDraftCardDetailSnapshot {
pub card_id: String,
pub kind: RpgAgentDraftCardKind,
pub title: String,
pub sections: Vec<CustomWorldDraftCardDetailSectionSnapshot>,
pub linked_ids_json: String,
pub locked: bool,
pub editable: bool,
pub editable_section_ids_json: String,
pub warning_messages_json: String,
pub asset_status: Option<CustomWorldRoleAssetStatus>,
pub asset_status_label: Option<String>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CustomWorldDraftCardDetailResult {
pub ok: bool,
pub card: Option<CustomWorldDraftCardDetailSnapshot>,
pub error_message: Option<String>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CustomWorldAgentActionExecuteInput {
pub session_id: String,
pub owner_user_id: String,
pub operation_id: String,
pub action: String,
pub payload_json: Option<String>,
pub submitted_at_micros: i64,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CustomWorldAgentActionExecuteResult {
pub ok: bool,
pub operation: Option<CustomWorldAgentOperationSnapshot>,
pub error_message: Option<String>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CustomWorldPublishedProfileCompileInput {
@@ -941,6 +1064,52 @@ pub fn validate_custom_world_agent_operation_get_input(
Ok(())
}
pub fn validate_custom_world_works_list_input(
input: &CustomWorldWorksListInput,
) -> Result<(), CustomWorldFieldError> {
if input.owner_user_id.trim().is_empty() {
return Err(CustomWorldFieldError::MissingOwnerUserId);
}
Ok(())
}
pub fn validate_custom_world_agent_card_detail_get_input(
input: &CustomWorldAgentCardDetailGetInput,
) -> Result<(), CustomWorldFieldError> {
if input.session_id.trim().is_empty() {
return Err(CustomWorldFieldError::MissingSessionId);
}
if input.owner_user_id.trim().is_empty() {
return Err(CustomWorldFieldError::MissingOwnerUserId);
}
if input.card_id.trim().is_empty() {
return Err(CustomWorldFieldError::MissingCardId);
}
Ok(())
}
pub fn validate_custom_world_agent_action_execute_input(
input: &CustomWorldAgentActionExecuteInput,
) -> Result<(), CustomWorldFieldError> {
validate_custom_world_agent_operation_get_input(&CustomWorldAgentOperationGetInput {
session_id: input.session_id.clone(),
owner_user_id: input.owner_user_id.clone(),
operation_id: input.operation_id.clone(),
})?;
if input.action.trim().is_empty() {
return Err(CustomWorldFieldError::MissingAction);
}
if let Some(payload_json) = input.payload_json.as_deref() {
if !payload_json.trim().is_empty() {
ensure_json_object(payload_json)?;
}
}
Ok(())
}
pub fn validate_custom_world_agent_message_fields(
message_id: &str,
session_id: &str,
@@ -1321,6 +1490,7 @@ impl fmt::Display for CustomWorldFieldError {
Self::MissingPhaseLabel => {
f.write_str("custom_world_agent_operation.phase_label 不能为空")
}
Self::MissingAction => f.write_str("custom_world_agent_action.action 不能为空"),
Self::InvalidProgressPercent => f.write_str("progress 必须位于 0~100"),
Self::MissingCardId => f.write_str("custom_world_draft_card.card_id 不能为空"),
Self::MissingCardTitle => f.write_str("custom_world_draft_card.title 不能为空"),

View File

@@ -0,0 +1,15 @@
[package]
name = "module-puzzle"
edition.workspace = true
version.workspace = true
license.workspace = true
[features]
default = []
spacetime-types = ["dep:spacetimedb"]
[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
shared-kernel = { path = "../shared-kernel" }
spacetimedb = { workspace = true, optional = true }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,238 @@
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct CreateBigFishSessionRequest {
#[serde(default)]
pub seed_text: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct SendBigFishMessageRequest {
pub client_message_id: String,
pub text: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ExecuteBigFishActionRequest {
pub action: String,
#[serde(default)]
pub level: Option<u32>,
#[serde(default)]
pub motion_key: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct SubmitBigFishInputRequest {
pub x: f32,
pub y: f32,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct BigFishAnchorItemResponse {
pub key: String,
pub label: String,
pub value: String,
pub status: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct BigFishAnchorPackResponse {
pub gameplay_promise: BigFishAnchorItemResponse,
pub ecology_visual_theme: BigFishAnchorItemResponse,
pub growth_ladder: BigFishAnchorItemResponse,
pub risk_tempo: BigFishAnchorItemResponse,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct BigFishLevelBlueprintResponse {
pub level: u32,
pub name: String,
pub one_line_fantasy: String,
pub silhouette_direction: String,
pub size_ratio: f32,
pub visual_prompt_seed: String,
pub motion_prompt_seed: String,
pub merge_source_level: Option<u32>,
pub prey_window: Vec<u32>,
pub threat_window: Vec<u32>,
pub is_final_level: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct BigFishBackgroundBlueprintResponse {
pub theme: String,
pub color_mood: String,
pub foreground_hints: String,
pub midground_composition: String,
pub background_depth: String,
pub safe_play_area_hint: String,
pub spawn_edge_hint: String,
pub background_prompt_seed: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct BigFishRuntimeParamsResponse {
pub level_count: u32,
pub merge_count_per_upgrade: u32,
pub spawn_target_count: u32,
pub leader_move_speed: f32,
pub follower_catch_up_speed: f32,
pub offscreen_cull_seconds: f32,
pub prey_spawn_delta_levels: Vec<u32>,
pub threat_spawn_delta_levels: Vec<u32>,
pub win_level: u32,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct BigFishGameDraftResponse {
pub title: String,
pub subtitle: String,
pub core_fun: String,
pub ecology_theme: String,
pub levels: Vec<BigFishLevelBlueprintResponse>,
pub background: BigFishBackgroundBlueprintResponse,
pub runtime_params: BigFishRuntimeParamsResponse,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct BigFishAgentMessageResponse {
pub id: String,
pub role: String,
pub kind: String,
pub text: String,
pub created_at: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct BigFishAssetSlotResponse {
pub slot_id: String,
pub asset_kind: String,
pub level: Option<u32>,
pub motion_key: Option<String>,
pub status: String,
pub asset_url: Option<String>,
pub prompt_snapshot: String,
pub updated_at: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct BigFishAssetCoverageResponse {
pub level_main_image_ready_count: u32,
pub level_motion_ready_count: u32,
pub background_ready: bool,
pub required_level_count: u32,
pub publish_ready: bool,
pub blockers: Vec<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct BigFishSessionSnapshotResponse {
pub session_id: String,
pub current_turn: u32,
pub progress_percent: u32,
pub stage: String,
pub anchor_pack: BigFishAnchorPackResponse,
pub draft: Option<BigFishGameDraftResponse>,
pub asset_slots: Vec<BigFishAssetSlotResponse>,
pub asset_coverage: BigFishAssetCoverageResponse,
pub messages: Vec<BigFishAgentMessageResponse>,
pub last_assistant_reply: Option<String>,
pub publish_ready: bool,
pub updated_at: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct BigFishSessionResponse {
pub session: BigFishSessionSnapshotResponse,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct BigFishActionResponse {
pub session: BigFishSessionSnapshotResponse,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct BigFishVector2Response {
pub x: f32,
pub y: f32,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct BigFishRuntimeEntityResponse {
pub entity_id: String,
pub level: u32,
pub position: BigFishVector2Response,
pub radius: f32,
pub offscreen_seconds: f32,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct BigFishRuntimeSnapshotResponse {
pub run_id: String,
pub session_id: String,
pub status: String,
pub tick: u64,
pub player_level: u32,
pub win_level: u32,
pub leader_entity_id: Option<String>,
pub owned_entities: Vec<BigFishRuntimeEntityResponse>,
pub wild_entities: Vec<BigFishRuntimeEntityResponse>,
pub camera_center: BigFishVector2Response,
pub last_input: BigFishVector2Response,
pub event_log: Vec<String>,
pub updated_at: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct BigFishRunResponse {
pub run: BigFishRuntimeSnapshotResponse,
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn big_fish_session_request_uses_camel_case() {
let payload = serde_json::to_value(CreateBigFishSessionRequest {
seed_text: Some("深海机械鱼".to_string()),
})
.expect("payload should serialize");
assert_eq!(payload, json!({ "seedText": "深海机械鱼" }));
}
#[test]
fn big_fish_action_request_uses_camel_case() {
let payload = serde_json::to_value(ExecuteBigFishActionRequest {
action: "big_fish_generate_level_motion".to_string(),
level: Some(3),
motion_key: Some("move_swim".to_string()),
})
.expect("payload should serialize");
assert_eq!(payload["motionKey"], json!("move_swim"));
assert_eq!(payload["level"], json!(3));
}
}

View File

@@ -2,7 +2,12 @@ pub mod ai;
pub mod api;
pub mod assets;
pub mod auth;
pub mod big_fish;
pub mod llm;
pub mod puzzle_agent;
pub mod puzzle_gallery;
pub mod puzzle_runtime;
pub mod puzzle_works;
pub mod runtime;
pub mod runtime_story;
pub mod story;

View File

@@ -0,0 +1,188 @@
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct CreatePuzzleAgentSessionRequest {
#[serde(default)]
pub seed_text: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct SendPuzzleAgentMessageRequest {
pub client_message_id: String,
pub text: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ExecutePuzzleAgentActionRequest {
pub action: String,
#[serde(default)]
pub prompt_text: Option<String>,
#[serde(default)]
pub candidate_count: Option<u32>,
#[serde(default)]
pub candidate_id: Option<String>,
#[serde(default)]
pub level_name: Option<String>,
#[serde(default)]
pub summary: Option<String>,
#[serde(default)]
pub theme_tags: Option<Vec<String>>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleAnchorItemResponse {
pub key: String,
pub label: String,
pub value: String,
pub status: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleAnchorPackResponse {
pub theme_promise: PuzzleAnchorItemResponse,
pub visual_subject: PuzzleAnchorItemResponse,
pub visual_mood: PuzzleAnchorItemResponse,
pub composition_hooks: PuzzleAnchorItemResponse,
pub tags_and_forbidden: PuzzleAnchorItemResponse,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleGeneratedImageCandidateResponse {
pub candidate_id: String,
pub image_src: String,
pub asset_id: String,
pub prompt: String,
#[serde(default)]
pub actual_prompt: Option<String>,
pub source_type: String,
pub selected: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleCreatorIntentResponse {
pub source_mode: String,
pub raw_messages_summary: String,
pub theme_promise: String,
pub visual_subject: String,
pub visual_mood: Vec<String>,
pub composition_hooks: Vec<String>,
pub theme_tags: Vec<String>,
pub forbidden_directives: Vec<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleResultDraftResponse {
pub level_name: String,
pub summary: String,
pub theme_tags: Vec<String>,
pub forbidden_directives: Vec<String>,
#[serde(default)]
pub creator_intent: Option<PuzzleCreatorIntentResponse>,
pub anchor_pack: PuzzleAnchorPackResponse,
pub candidates: Vec<PuzzleGeneratedImageCandidateResponse>,
#[serde(default)]
pub selected_candidate_id: Option<String>,
#[serde(default)]
pub cover_image_src: Option<String>,
#[serde(default)]
pub cover_asset_id: Option<String>,
pub generation_status: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleAgentMessageResponse {
pub id: String,
pub role: String,
pub kind: String,
pub text: String,
pub created_at: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleAgentSuggestedActionResponse {
pub id: String,
pub action_type: String,
pub label: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleResultPreviewBlockerResponse {
pub id: String,
pub code: String,
pub message: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleResultPreviewFindingResponse {
pub id: String,
pub severity: String,
pub code: String,
pub message: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleResultPreviewEnvelopeResponse {
pub draft: PuzzleResultDraftResponse,
pub blockers: Vec<PuzzleResultPreviewBlockerResponse>,
pub quality_findings: Vec<PuzzleResultPreviewFindingResponse>,
pub publish_ready: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleAgentSessionSnapshotResponse {
pub session_id: String,
pub current_turn: u32,
pub progress_percent: u32,
pub stage: String,
pub anchor_pack: PuzzleAnchorPackResponse,
#[serde(default)]
pub draft: Option<PuzzleResultDraftResponse>,
pub messages: Vec<PuzzleAgentMessageResponse>,
#[serde(default)]
pub last_assistant_reply: Option<String>,
#[serde(default)]
pub published_profile_id: Option<String>,
pub suggested_actions: Vec<PuzzleAgentSuggestedActionResponse>,
#[serde(default)]
pub result_preview: Option<PuzzleResultPreviewEnvelopeResponse>,
pub updated_at: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleAgentSessionResponse {
pub session: PuzzleAgentSessionSnapshotResponse,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleAgentOperationResponse {
pub operation_id: String,
pub operation_type: String,
pub status: String,
pub phase_label: String,
pub phase_detail: String,
pub progress: u32,
#[serde(default)]
pub error: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleAgentActionResponse {
pub operation: PuzzleAgentOperationResponse,
}

View File

@@ -0,0 +1,15 @@
use serde::{Deserialize, Serialize};
use crate::puzzle_works::PuzzleWorkSummaryResponse;
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleGalleryResponse {
pub items: Vec<PuzzleWorkSummaryResponse>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleGalleryDetailResponse {
pub item: PuzzleWorkSummaryResponse,
}

View File

@@ -0,0 +1,99 @@
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct StartPuzzleRunRequest {
pub profile_id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct SwapPuzzlePiecesRequest {
pub first_piece_id: String,
pub second_piece_id: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DragPuzzlePieceRequest {
pub piece_id: String,
pub target_row: u32,
pub target_col: u32,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleCellPositionResponse {
pub row: u32,
pub col: u32,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzlePieceStateResponse {
pub piece_id: String,
pub correct_row: u32,
pub correct_col: u32,
pub current_row: u32,
pub current_col: u32,
#[serde(default)]
pub merged_group_id: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleMergedGroupStateResponse {
pub group_id: String,
pub piece_ids: Vec<String>,
pub occupied_cells: Vec<PuzzleCellPositionResponse>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleBoardSnapshotResponse {
pub rows: u32,
pub cols: u32,
pub pieces: Vec<PuzzlePieceStateResponse>,
pub merged_groups: Vec<PuzzleMergedGroupStateResponse>,
#[serde(default)]
pub selected_piece_id: Option<String>,
pub all_tiles_resolved: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleRuntimeLevelSnapshotResponse {
pub run_id: String,
pub level_index: u32,
pub grid_size: u32,
pub profile_id: String,
pub level_name: String,
pub author_display_name: String,
pub theme_tags: Vec<String>,
#[serde(default)]
pub cover_image_src: Option<String>,
pub board: PuzzleBoardSnapshotResponse,
pub status: String,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleRunSnapshotResponse {
pub run_id: String,
pub entry_profile_id: String,
pub cleared_level_count: u32,
pub current_level_index: u32,
pub current_grid_size: u32,
pub played_profile_ids: Vec<String>,
pub previous_level_tags: Vec<String>,
#[serde(default)]
pub current_level: Option<PuzzleRuntimeLevelSnapshotResponse>,
#[serde(default)]
pub recommended_next_profile_id: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleRunResponse {
pub run: PuzzleRunSnapshotResponse,
}

View File

@@ -0,0 +1,65 @@
use serde::{Deserialize, Serialize};
use crate::puzzle_agent::PuzzleAnchorPackResponse;
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PutPuzzleWorkRequest {
pub level_name: String,
pub summary: String,
pub theme_tags: Vec<String>,
#[serde(default)]
pub cover_image_src: Option<String>,
#[serde(default)]
pub cover_asset_id: Option<String>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleWorkSummaryResponse {
pub work_id: String,
pub profile_id: String,
pub owner_user_id: String,
#[serde(default)]
pub source_session_id: Option<String>,
pub author_display_name: String,
pub level_name: String,
pub summary: String,
pub theme_tags: Vec<String>,
#[serde(default)]
pub cover_image_src: Option<String>,
#[serde(default)]
pub cover_asset_id: Option<String>,
pub publication_status: String,
pub updated_at: String,
#[serde(default)]
pub published_at: Option<String>,
pub play_count: u32,
pub publish_ready: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleWorkProfileResponse {
#[serde(flatten)]
pub summary: PuzzleWorkSummaryResponse,
pub anchor_pack: PuzzleAnchorPackResponse,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleWorksResponse {
pub items: Vec<PuzzleWorkSummaryResponse>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleWorkDetailResponse {
pub item: PuzzleWorkProfileResponse,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleWorkMutationResponse {
pub item: PuzzleWorkProfileResponse,
}

View File

@@ -6,11 +6,13 @@ license.workspace = true
[dependencies]
module-ai = { path = "../module-ai" }
module-big-fish = { path = "../module-big-fish" }
module-custom-world = { path = "../module-custom-world" }
module-assets = { path = "../module-assets" }
module-combat = { path = "../module-combat" }
module-inventory = { path = "../module-inventory" }
module-npc = { path = "../module-npc" }
module-puzzle = { path = "../module-puzzle" }
module-runtime = { path = "../module-runtime" }
module-runtime-item = { path = "../module-runtime-item" }
module-story = { path = "../module-story" }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
// 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_run_next_level_input_type::PuzzleRunNextLevelInput;
use super::puzzle_run_procedure_result_type::PuzzleRunProcedureResult;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
struct AdvancePuzzleNextLevelArgs {
pub input: PuzzleRunNextLevelInput,
}
impl __sdk::InModule for AdvancePuzzleNextLevelArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `advance_puzzle_next_level`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait advance_puzzle_next_level {
fn advance_puzzle_next_level(&self, input: PuzzleRunNextLevelInput,
) {
self.advance_puzzle_next_level_then(input, |_, _| {});
}
fn advance_puzzle_next_level_then(
&self,
input: PuzzleRunNextLevelInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleRunProcedureResult, __sdk::InternalError>) + Send + 'static,
);
}
impl advance_puzzle_next_level for super::RemoteProcedures {
fn advance_puzzle_next_level_then(
&self,
input: PuzzleRunNextLevelInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleRunProcedureResult, __sdk::InternalError>) + Send + 'static,
) {
self.imp.invoke_procedure_with_callback::<_, PuzzleRunProcedureResult>(
"advance_puzzle_next_level",
AdvancePuzzleNextLevelArgs { input, },
__callback,
);
}
}

View File

@@ -0,0 +1,31 @@
// 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 BigFishAgentMessageKind {
Chat,
Summary,
ActionResult,
Warning,
}
impl __sdk::InModule for BigFishAgentMessageKind {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,29 @@
// 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 BigFishAgentMessageRole {
User,
Assistant,
System,
}
impl __sdk::InModule for BigFishAgentMessageRole {
type Module = super::RemoteModule;
}

View File

@@ -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::big_fish_agent_message_role_type::BigFishAgentMessageRole;
use super::big_fish_agent_message_kind_type::BigFishAgentMessageKind;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct BigFishAgentMessageSnapshot {
pub message_id: String,
pub session_id: String,
pub role: BigFishAgentMessageRole,
pub kind: BigFishAgentMessageKind,
pub text: String,
pub created_at_micros: i64,
}
impl __sdk::InModule for BigFishAgentMessageSnapshot {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,165 @@
// 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::big_fish_agent_message_type::BigFishAgentMessage;
use super::big_fish_agent_message_role_type::BigFishAgentMessageRole;
use super::big_fish_agent_message_kind_type::BigFishAgentMessageKind;
/// Table handle for the table `big_fish_agent_message`.
///
/// Obtain a handle from the [`BigFishAgentMessageTableAccess::big_fish_agent_message`] method on [`super::RemoteTables`],
/// like `ctx.db.big_fish_agent_message()`.
///
/// Users are encouraged not to explicitly reference this type,
/// but to directly chain method calls,
/// like `ctx.db.big_fish_agent_message().on_insert(...)`.
pub struct BigFishAgentMessageTableHandle<'ctx> {
imp: __sdk::TableHandle<BigFishAgentMessage>,
ctx: std::marker::PhantomData<&'ctx super::RemoteTables>,
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the table `big_fish_agent_message`.
///
/// Implemented for [`super::RemoteTables`].
pub trait BigFishAgentMessageTableAccess {
#[allow(non_snake_case)]
/// Obtain a [`BigFishAgentMessageTableHandle`], which mediates access to the table `big_fish_agent_message`.
fn big_fish_agent_message(&self) -> BigFishAgentMessageTableHandle<'_>;
}
impl BigFishAgentMessageTableAccess for super::RemoteTables {
fn big_fish_agent_message(&self) -> BigFishAgentMessageTableHandle<'_> {
BigFishAgentMessageTableHandle {
imp: self.imp.get_table::<BigFishAgentMessage>("big_fish_agent_message"),
ctx: std::marker::PhantomData,
}
}
}
pub struct BigFishAgentMessageInsertCallbackId(__sdk::CallbackId);
pub struct BigFishAgentMessageDeleteCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::Table for BigFishAgentMessageTableHandle<'ctx> {
type Row = BigFishAgentMessage;
type EventContext = super::EventContext;
fn count(&self) -> u64 { self.imp.count() }
fn iter(&self) -> impl Iterator<Item = BigFishAgentMessage> + '_ { self.imp.iter() }
type InsertCallbackId = BigFishAgentMessageInsertCallbackId;
fn on_insert(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> BigFishAgentMessageInsertCallbackId {
BigFishAgentMessageInsertCallbackId(self.imp.on_insert(Box::new(callback)))
}
fn remove_on_insert(&self, callback: BigFishAgentMessageInsertCallbackId) {
self.imp.remove_on_insert(callback.0)
}
type DeleteCallbackId = BigFishAgentMessageDeleteCallbackId;
fn on_delete(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> BigFishAgentMessageDeleteCallbackId {
BigFishAgentMessageDeleteCallbackId(self.imp.on_delete(Box::new(callback)))
}
fn remove_on_delete(&self, callback: BigFishAgentMessageDeleteCallbackId) {
self.imp.remove_on_delete(callback.0)
}
}
pub struct BigFishAgentMessageUpdateCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::TableWithPrimaryKey for BigFishAgentMessageTableHandle<'ctx> {
type UpdateCallbackId = BigFishAgentMessageUpdateCallbackId;
fn on_update(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static,
) -> BigFishAgentMessageUpdateCallbackId {
BigFishAgentMessageUpdateCallbackId(self.imp.on_update(Box::new(callback)))
}
fn remove_on_update(&self, callback: BigFishAgentMessageUpdateCallbackId) {
self.imp.remove_on_update(callback.0)
}
}
/// Access to the `message_id` unique index on the table `big_fish_agent_message`,
/// which allows point queries on the field of the same name
/// via the [`BigFishAgentMessageMessageIdUnique::find`] method.
///
/// Users are encouraged not to explicitly reference this type,
/// but to directly chain method calls,
/// like `ctx.db.big_fish_agent_message().message_id().find(...)`.
pub struct BigFishAgentMessageMessageIdUnique<'ctx> {
imp: __sdk::UniqueConstraintHandle<BigFishAgentMessage, String>,
phantom: std::marker::PhantomData<&'ctx super::RemoteTables>,
}
impl<'ctx> BigFishAgentMessageTableHandle<'ctx> {
/// Get a handle on the `message_id` unique index on the table `big_fish_agent_message`.
pub fn message_id(&self) -> BigFishAgentMessageMessageIdUnique<'ctx> {
BigFishAgentMessageMessageIdUnique {
imp: self.imp.get_unique_constraint::<String>("message_id"),
phantom: std::marker::PhantomData,
}
}
}
impl<'ctx> BigFishAgentMessageMessageIdUnique<'ctx> {
/// Find the subscribed row whose `message_id` column value is equal to `col_val`,
/// if such a row is present in the client cache.
pub fn find(&self, col_val: &String) -> Option<BigFishAgentMessage> {
self.imp.find(col_val)
}
}
#[doc(hidden)]
pub(super) fn register_table(client_cache: &mut __sdk::ClientCache<super::RemoteModule>) {
let _table = client_cache.get_or_make_table::<BigFishAgentMessage>("big_fish_agent_message");
_table.add_unique_constraint::<String>("message_id", |row| &row.message_id);
}
#[doc(hidden)]
pub(super) fn parse_table_update(
raw_updates: __ws::v2::TableUpdate,
) -> __sdk::Result<__sdk::TableUpdate<BigFishAgentMessage>> {
__sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| {
__sdk::InternalError::failed_parse(
"TableUpdate<BigFishAgentMessage>",
"TableUpdate",
).with_cause(e).into()
})
}
#[allow(non_camel_case_types)]
/// Extension trait for query builder access to the table `BigFishAgentMessage`.
///
/// Implemented for [`__sdk::QueryTableAccessor`].
pub trait big_fish_agent_messageQueryTableAccess {
#[allow(non_snake_case)]
/// Get a query builder for the table `BigFishAgentMessage`.
fn big_fish_agent_message(&self) -> __sdk::__query_builder::Table<BigFishAgentMessage>;
}
impl big_fish_agent_messageQueryTableAccess for __sdk::QueryTableAccessor {
fn big_fish_agent_message(&self) -> __sdk::__query_builder::Table<BigFishAgentMessage> {
__sdk::__query_builder::Table::new("big_fish_agent_message")
}
}

View File

@@ -0,0 +1,79 @@
// 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::big_fish_agent_message_role_type::BigFishAgentMessageRole;
use super::big_fish_agent_message_kind_type::BigFishAgentMessageKind;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct BigFishAgentMessage {
pub message_id: String,
pub session_id: String,
pub role: BigFishAgentMessageRole,
pub kind: BigFishAgentMessageKind,
pub text: String,
pub created_at: __sdk::Timestamp,
}
impl __sdk::InModule for BigFishAgentMessage {
type Module = super::RemoteModule;
}
/// Column accessor struct for the table `BigFishAgentMessage`.
///
/// Provides typed access to columns for query building.
pub struct BigFishAgentMessageCols {
pub message_id: __sdk::__query_builder::Col<BigFishAgentMessage, String>,
pub session_id: __sdk::__query_builder::Col<BigFishAgentMessage, String>,
pub role: __sdk::__query_builder::Col<BigFishAgentMessage, BigFishAgentMessageRole>,
pub kind: __sdk::__query_builder::Col<BigFishAgentMessage, BigFishAgentMessageKind>,
pub text: __sdk::__query_builder::Col<BigFishAgentMessage, String>,
pub created_at: __sdk::__query_builder::Col<BigFishAgentMessage, __sdk::Timestamp>,
}
impl __sdk::__query_builder::HasCols for BigFishAgentMessage {
type Cols = BigFishAgentMessageCols;
fn cols(table_name: &'static str) -> Self::Cols {
BigFishAgentMessageCols {
message_id: __sdk::__query_builder::Col::new(table_name, "message_id"),
session_id: __sdk::__query_builder::Col::new(table_name, "session_id"),
role: __sdk::__query_builder::Col::new(table_name, "role"),
kind: __sdk::__query_builder::Col::new(table_name, "kind"),
text: __sdk::__query_builder::Col::new(table_name, "text"),
created_at: __sdk::__query_builder::Col::new(table_name, "created_at"),
}
}
}
/// Indexed column accessor struct for the table `BigFishAgentMessage`.
///
/// Provides typed access to indexed columns for query building.
pub struct BigFishAgentMessageIxCols {
pub message_id: __sdk::__query_builder::IxCol<BigFishAgentMessage, String>,
pub session_id: __sdk::__query_builder::IxCol<BigFishAgentMessage, String>,
}
impl __sdk::__query_builder::HasIxCols for BigFishAgentMessage {
type IxCols = BigFishAgentMessageIxCols;
fn ix_cols(table_name: &'static str) -> Self::IxCols {
BigFishAgentMessageIxCols {
message_id: __sdk::__query_builder::IxCol::new(table_name, "message_id"),
session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"),
}
}
}
impl __sdk::__query_builder::CanBeLookupTable for BigFishAgentMessage {}

View File

@@ -0,0 +1,27 @@
// 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::big_fish_anchor_status_type::BigFishAnchorStatus;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct BigFishAnchorItem {
pub key: String,
pub label: String,
pub value: String,
pub status: BigFishAnchorStatus,
}
impl __sdk::InModule for BigFishAnchorItem {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,27 @@
// 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::big_fish_anchor_item_type::BigFishAnchorItem;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct BigFishAnchorPack {
pub gameplay_promise: BigFishAnchorItem,
pub ecology_visual_theme: BigFishAnchorItem,
pub growth_ladder: BigFishAnchorItem,
pub risk_tempo: BigFishAnchorItem,
}
impl __sdk::InModule for BigFishAnchorPack {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,31 @@
// 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 BigFishAnchorStatus {
Confirmed,
Inferred,
Missing,
Locked,
}
impl __sdk::InModule for BigFishAnchorStatus {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,28 @@
// 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 BigFishAssetCoverage {
pub level_main_image_ready_count: u32,
pub level_motion_ready_count: u32,
pub background_ready: bool,
pub required_level_count: u32,
pub publish_ready: bool,
pub blockers: Vec::<String>,
}
impl __sdk::InModule for BigFishAssetCoverage {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,29 @@
// 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::big_fish_asset_kind_type::BigFishAssetKind;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct BigFishAssetGenerateInput {
pub session_id: String,
pub owner_user_id: String,
pub asset_kind: BigFishAssetKind,
pub level: Option::<u32>,
pub motion_key: Option::<String>,
pub generated_at_micros: i64,
}
impl __sdk::InModule for BigFishAssetGenerateInput {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,29 @@
// 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 BigFishAssetKind {
LevelMainImage,
LevelMotion,
StageBackground,
}
impl __sdk::InModule for BigFishAssetKind {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,33 @@
// 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::big_fish_asset_kind_type::BigFishAssetKind;
use super::big_fish_asset_status_type::BigFishAssetStatus;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct BigFishAssetSlotSnapshot {
pub slot_id: String,
pub session_id: String,
pub asset_kind: BigFishAssetKind,
pub level: Option::<u32>,
pub motion_key: Option::<String>,
pub status: BigFishAssetStatus,
pub asset_url: Option::<String>,
pub prompt_snapshot: String,
pub updated_at_micros: i64,
}
impl __sdk::InModule for BigFishAssetSlotSnapshot {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,165 @@
// 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::big_fish_asset_slot_type::BigFishAssetSlot;
use super::big_fish_asset_kind_type::BigFishAssetKind;
use super::big_fish_asset_status_type::BigFishAssetStatus;
/// Table handle for the table `big_fish_asset_slot`.
///
/// Obtain a handle from the [`BigFishAssetSlotTableAccess::big_fish_asset_slot`] method on [`super::RemoteTables`],
/// like `ctx.db.big_fish_asset_slot()`.
///
/// Users are encouraged not to explicitly reference this type,
/// but to directly chain method calls,
/// like `ctx.db.big_fish_asset_slot().on_insert(...)`.
pub struct BigFishAssetSlotTableHandle<'ctx> {
imp: __sdk::TableHandle<BigFishAssetSlot>,
ctx: std::marker::PhantomData<&'ctx super::RemoteTables>,
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the table `big_fish_asset_slot`.
///
/// Implemented for [`super::RemoteTables`].
pub trait BigFishAssetSlotTableAccess {
#[allow(non_snake_case)]
/// Obtain a [`BigFishAssetSlotTableHandle`], which mediates access to the table `big_fish_asset_slot`.
fn big_fish_asset_slot(&self) -> BigFishAssetSlotTableHandle<'_>;
}
impl BigFishAssetSlotTableAccess for super::RemoteTables {
fn big_fish_asset_slot(&self) -> BigFishAssetSlotTableHandle<'_> {
BigFishAssetSlotTableHandle {
imp: self.imp.get_table::<BigFishAssetSlot>("big_fish_asset_slot"),
ctx: std::marker::PhantomData,
}
}
}
pub struct BigFishAssetSlotInsertCallbackId(__sdk::CallbackId);
pub struct BigFishAssetSlotDeleteCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::Table for BigFishAssetSlotTableHandle<'ctx> {
type Row = BigFishAssetSlot;
type EventContext = super::EventContext;
fn count(&self) -> u64 { self.imp.count() }
fn iter(&self) -> impl Iterator<Item = BigFishAssetSlot> + '_ { self.imp.iter() }
type InsertCallbackId = BigFishAssetSlotInsertCallbackId;
fn on_insert(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> BigFishAssetSlotInsertCallbackId {
BigFishAssetSlotInsertCallbackId(self.imp.on_insert(Box::new(callback)))
}
fn remove_on_insert(&self, callback: BigFishAssetSlotInsertCallbackId) {
self.imp.remove_on_insert(callback.0)
}
type DeleteCallbackId = BigFishAssetSlotDeleteCallbackId;
fn on_delete(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> BigFishAssetSlotDeleteCallbackId {
BigFishAssetSlotDeleteCallbackId(self.imp.on_delete(Box::new(callback)))
}
fn remove_on_delete(&self, callback: BigFishAssetSlotDeleteCallbackId) {
self.imp.remove_on_delete(callback.0)
}
}
pub struct BigFishAssetSlotUpdateCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::TableWithPrimaryKey for BigFishAssetSlotTableHandle<'ctx> {
type UpdateCallbackId = BigFishAssetSlotUpdateCallbackId;
fn on_update(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static,
) -> BigFishAssetSlotUpdateCallbackId {
BigFishAssetSlotUpdateCallbackId(self.imp.on_update(Box::new(callback)))
}
fn remove_on_update(&self, callback: BigFishAssetSlotUpdateCallbackId) {
self.imp.remove_on_update(callback.0)
}
}
/// Access to the `slot_id` unique index on the table `big_fish_asset_slot`,
/// which allows point queries on the field of the same name
/// via the [`BigFishAssetSlotSlotIdUnique::find`] method.
///
/// Users are encouraged not to explicitly reference this type,
/// but to directly chain method calls,
/// like `ctx.db.big_fish_asset_slot().slot_id().find(...)`.
pub struct BigFishAssetSlotSlotIdUnique<'ctx> {
imp: __sdk::UniqueConstraintHandle<BigFishAssetSlot, String>,
phantom: std::marker::PhantomData<&'ctx super::RemoteTables>,
}
impl<'ctx> BigFishAssetSlotTableHandle<'ctx> {
/// Get a handle on the `slot_id` unique index on the table `big_fish_asset_slot`.
pub fn slot_id(&self) -> BigFishAssetSlotSlotIdUnique<'ctx> {
BigFishAssetSlotSlotIdUnique {
imp: self.imp.get_unique_constraint::<String>("slot_id"),
phantom: std::marker::PhantomData,
}
}
}
impl<'ctx> BigFishAssetSlotSlotIdUnique<'ctx> {
/// Find the subscribed row whose `slot_id` column value is equal to `col_val`,
/// if such a row is present in the client cache.
pub fn find(&self, col_val: &String) -> Option<BigFishAssetSlot> {
self.imp.find(col_val)
}
}
#[doc(hidden)]
pub(super) fn register_table(client_cache: &mut __sdk::ClientCache<super::RemoteModule>) {
let _table = client_cache.get_or_make_table::<BigFishAssetSlot>("big_fish_asset_slot");
_table.add_unique_constraint::<String>("slot_id", |row| &row.slot_id);
}
#[doc(hidden)]
pub(super) fn parse_table_update(
raw_updates: __ws::v2::TableUpdate,
) -> __sdk::Result<__sdk::TableUpdate<BigFishAssetSlot>> {
__sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| {
__sdk::InternalError::failed_parse(
"TableUpdate<BigFishAssetSlot>",
"TableUpdate",
).with_cause(e).into()
})
}
#[allow(non_camel_case_types)]
/// Extension trait for query builder access to the table `BigFishAssetSlot`.
///
/// Implemented for [`__sdk::QueryTableAccessor`].
pub trait big_fish_asset_slotQueryTableAccess {
#[allow(non_snake_case)]
/// Get a query builder for the table `BigFishAssetSlot`.
fn big_fish_asset_slot(&self) -> __sdk::__query_builder::Table<BigFishAssetSlot>;
}
impl big_fish_asset_slotQueryTableAccess for __sdk::QueryTableAccessor {
fn big_fish_asset_slot(&self) -> __sdk::__query_builder::Table<BigFishAssetSlot> {
__sdk::__query_builder::Table::new("big_fish_asset_slot")
}
}

View File

@@ -0,0 +1,88 @@
// 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::big_fish_asset_kind_type::BigFishAssetKind;
use super::big_fish_asset_status_type::BigFishAssetStatus;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct BigFishAssetSlot {
pub slot_id: String,
pub session_id: String,
pub asset_kind: BigFishAssetKind,
pub level: Option::<u32>,
pub motion_key: Option::<String>,
pub status: BigFishAssetStatus,
pub asset_url: Option::<String>,
pub prompt_snapshot: String,
pub updated_at: __sdk::Timestamp,
}
impl __sdk::InModule for BigFishAssetSlot {
type Module = super::RemoteModule;
}
/// Column accessor struct for the table `BigFishAssetSlot`.
///
/// Provides typed access to columns for query building.
pub struct BigFishAssetSlotCols {
pub slot_id: __sdk::__query_builder::Col<BigFishAssetSlot, String>,
pub session_id: __sdk::__query_builder::Col<BigFishAssetSlot, String>,
pub asset_kind: __sdk::__query_builder::Col<BigFishAssetSlot, BigFishAssetKind>,
pub level: __sdk::__query_builder::Col<BigFishAssetSlot, Option::<u32>>,
pub motion_key: __sdk::__query_builder::Col<BigFishAssetSlot, Option::<String>>,
pub status: __sdk::__query_builder::Col<BigFishAssetSlot, BigFishAssetStatus>,
pub asset_url: __sdk::__query_builder::Col<BigFishAssetSlot, Option::<String>>,
pub prompt_snapshot: __sdk::__query_builder::Col<BigFishAssetSlot, String>,
pub updated_at: __sdk::__query_builder::Col<BigFishAssetSlot, __sdk::Timestamp>,
}
impl __sdk::__query_builder::HasCols for BigFishAssetSlot {
type Cols = BigFishAssetSlotCols;
fn cols(table_name: &'static str) -> Self::Cols {
BigFishAssetSlotCols {
slot_id: __sdk::__query_builder::Col::new(table_name, "slot_id"),
session_id: __sdk::__query_builder::Col::new(table_name, "session_id"),
asset_kind: __sdk::__query_builder::Col::new(table_name, "asset_kind"),
level: __sdk::__query_builder::Col::new(table_name, "level"),
motion_key: __sdk::__query_builder::Col::new(table_name, "motion_key"),
status: __sdk::__query_builder::Col::new(table_name, "status"),
asset_url: __sdk::__query_builder::Col::new(table_name, "asset_url"),
prompt_snapshot: __sdk::__query_builder::Col::new(table_name, "prompt_snapshot"),
updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"),
}
}
}
/// Indexed column accessor struct for the table `BigFishAssetSlot`.
///
/// Provides typed access to indexed columns for query building.
pub struct BigFishAssetSlotIxCols {
pub session_id: __sdk::__query_builder::IxCol<BigFishAssetSlot, String>,
pub slot_id: __sdk::__query_builder::IxCol<BigFishAssetSlot, String>,
}
impl __sdk::__query_builder::HasIxCols for BigFishAssetSlot {
type IxCols = BigFishAssetSlotIxCols;
fn ix_cols(table_name: &'static str) -> Self::IxCols {
BigFishAssetSlotIxCols {
session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"),
slot_id: __sdk::__query_builder::IxCol::new(table_name, "slot_id"),
}
}
}
impl __sdk::__query_builder::CanBeLookupTable for BigFishAssetSlot {}

View File

@@ -0,0 +1,27 @@
// 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 BigFishAssetStatus {
Missing,
Ready,
}
impl __sdk::InModule for BigFishAssetStatus {
type Module = super::RemoteModule;
}

View File

@@ -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,
};
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct BigFishBackgroundBlueprint {
pub theme: String,
pub color_mood: String,
pub foreground_hints: String,
pub midground_composition: String,
pub background_depth: String,
pub safe_play_area_hint: String,
pub spawn_edge_hint: String,
pub background_prompt_seed: String,
}
impl __sdk::InModule for BigFishBackgroundBlueprint {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,164 @@
// 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::big_fish_creation_session_type::BigFishCreationSession;
use super::big_fish_creation_stage_type::BigFishCreationStage;
/// Table handle for the table `big_fish_creation_session`.
///
/// Obtain a handle from the [`BigFishCreationSessionTableAccess::big_fish_creation_session`] method on [`super::RemoteTables`],
/// like `ctx.db.big_fish_creation_session()`.
///
/// Users are encouraged not to explicitly reference this type,
/// but to directly chain method calls,
/// like `ctx.db.big_fish_creation_session().on_insert(...)`.
pub struct BigFishCreationSessionTableHandle<'ctx> {
imp: __sdk::TableHandle<BigFishCreationSession>,
ctx: std::marker::PhantomData<&'ctx super::RemoteTables>,
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the table `big_fish_creation_session`.
///
/// Implemented for [`super::RemoteTables`].
pub trait BigFishCreationSessionTableAccess {
#[allow(non_snake_case)]
/// Obtain a [`BigFishCreationSessionTableHandle`], which mediates access to the table `big_fish_creation_session`.
fn big_fish_creation_session(&self) -> BigFishCreationSessionTableHandle<'_>;
}
impl BigFishCreationSessionTableAccess for super::RemoteTables {
fn big_fish_creation_session(&self) -> BigFishCreationSessionTableHandle<'_> {
BigFishCreationSessionTableHandle {
imp: self.imp.get_table::<BigFishCreationSession>("big_fish_creation_session"),
ctx: std::marker::PhantomData,
}
}
}
pub struct BigFishCreationSessionInsertCallbackId(__sdk::CallbackId);
pub struct BigFishCreationSessionDeleteCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::Table for BigFishCreationSessionTableHandle<'ctx> {
type Row = BigFishCreationSession;
type EventContext = super::EventContext;
fn count(&self) -> u64 { self.imp.count() }
fn iter(&self) -> impl Iterator<Item = BigFishCreationSession> + '_ { self.imp.iter() }
type InsertCallbackId = BigFishCreationSessionInsertCallbackId;
fn on_insert(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> BigFishCreationSessionInsertCallbackId {
BigFishCreationSessionInsertCallbackId(self.imp.on_insert(Box::new(callback)))
}
fn remove_on_insert(&self, callback: BigFishCreationSessionInsertCallbackId) {
self.imp.remove_on_insert(callback.0)
}
type DeleteCallbackId = BigFishCreationSessionDeleteCallbackId;
fn on_delete(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> BigFishCreationSessionDeleteCallbackId {
BigFishCreationSessionDeleteCallbackId(self.imp.on_delete(Box::new(callback)))
}
fn remove_on_delete(&self, callback: BigFishCreationSessionDeleteCallbackId) {
self.imp.remove_on_delete(callback.0)
}
}
pub struct BigFishCreationSessionUpdateCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::TableWithPrimaryKey for BigFishCreationSessionTableHandle<'ctx> {
type UpdateCallbackId = BigFishCreationSessionUpdateCallbackId;
fn on_update(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static,
) -> BigFishCreationSessionUpdateCallbackId {
BigFishCreationSessionUpdateCallbackId(self.imp.on_update(Box::new(callback)))
}
fn remove_on_update(&self, callback: BigFishCreationSessionUpdateCallbackId) {
self.imp.remove_on_update(callback.0)
}
}
/// Access to the `session_id` unique index on the table `big_fish_creation_session`,
/// which allows point queries on the field of the same name
/// via the [`BigFishCreationSessionSessionIdUnique::find`] method.
///
/// Users are encouraged not to explicitly reference this type,
/// but to directly chain method calls,
/// like `ctx.db.big_fish_creation_session().session_id().find(...)`.
pub struct BigFishCreationSessionSessionIdUnique<'ctx> {
imp: __sdk::UniqueConstraintHandle<BigFishCreationSession, String>,
phantom: std::marker::PhantomData<&'ctx super::RemoteTables>,
}
impl<'ctx> BigFishCreationSessionTableHandle<'ctx> {
/// Get a handle on the `session_id` unique index on the table `big_fish_creation_session`.
pub fn session_id(&self) -> BigFishCreationSessionSessionIdUnique<'ctx> {
BigFishCreationSessionSessionIdUnique {
imp: self.imp.get_unique_constraint::<String>("session_id"),
phantom: std::marker::PhantomData,
}
}
}
impl<'ctx> BigFishCreationSessionSessionIdUnique<'ctx> {
/// Find the subscribed row whose `session_id` column value is equal to `col_val`,
/// if such a row is present in the client cache.
pub fn find(&self, col_val: &String) -> Option<BigFishCreationSession> {
self.imp.find(col_val)
}
}
#[doc(hidden)]
pub(super) fn register_table(client_cache: &mut __sdk::ClientCache<super::RemoteModule>) {
let _table = client_cache.get_or_make_table::<BigFishCreationSession>("big_fish_creation_session");
_table.add_unique_constraint::<String>("session_id", |row| &row.session_id);
}
#[doc(hidden)]
pub(super) fn parse_table_update(
raw_updates: __ws::v2::TableUpdate,
) -> __sdk::Result<__sdk::TableUpdate<BigFishCreationSession>> {
__sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| {
__sdk::InternalError::failed_parse(
"TableUpdate<BigFishCreationSession>",
"TableUpdate",
).with_cause(e).into()
})
}
#[allow(non_camel_case_types)]
/// Extension trait for query builder access to the table `BigFishCreationSession`.
///
/// Implemented for [`__sdk::QueryTableAccessor`].
pub trait big_fish_creation_sessionQueryTableAccess {
#[allow(non_snake_case)]
/// Get a query builder for the table `BigFishCreationSession`.
fn big_fish_creation_session(&self) -> __sdk::__query_builder::Table<BigFishCreationSession>;
}
impl big_fish_creation_sessionQueryTableAccess for __sdk::QueryTableAccessor {
fn big_fish_creation_session(&self) -> __sdk::__query_builder::Table<BigFishCreationSession> {
__sdk::__query_builder::Table::new("big_fish_creation_session")
}
}

View File

@@ -0,0 +1,99 @@
// 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::big_fish_creation_stage_type::BigFishCreationStage;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct BigFishCreationSession {
pub session_id: String,
pub owner_user_id: String,
pub seed_text: String,
pub current_turn: u32,
pub progress_percent: u32,
pub stage: BigFishCreationStage,
pub anchor_pack_json: String,
pub draft_json: Option::<String>,
pub asset_coverage_json: String,
pub last_assistant_reply: Option::<String>,
pub publish_ready: bool,
pub created_at: __sdk::Timestamp,
pub updated_at: __sdk::Timestamp,
}
impl __sdk::InModule for BigFishCreationSession {
type Module = super::RemoteModule;
}
/// Column accessor struct for the table `BigFishCreationSession`.
///
/// Provides typed access to columns for query building.
pub struct BigFishCreationSessionCols {
pub session_id: __sdk::__query_builder::Col<BigFishCreationSession, String>,
pub owner_user_id: __sdk::__query_builder::Col<BigFishCreationSession, String>,
pub seed_text: __sdk::__query_builder::Col<BigFishCreationSession, String>,
pub current_turn: __sdk::__query_builder::Col<BigFishCreationSession, u32>,
pub progress_percent: __sdk::__query_builder::Col<BigFishCreationSession, u32>,
pub stage: __sdk::__query_builder::Col<BigFishCreationSession, BigFishCreationStage>,
pub anchor_pack_json: __sdk::__query_builder::Col<BigFishCreationSession, String>,
pub draft_json: __sdk::__query_builder::Col<BigFishCreationSession, Option::<String>>,
pub asset_coverage_json: __sdk::__query_builder::Col<BigFishCreationSession, String>,
pub last_assistant_reply: __sdk::__query_builder::Col<BigFishCreationSession, Option::<String>>,
pub publish_ready: __sdk::__query_builder::Col<BigFishCreationSession, bool>,
pub created_at: __sdk::__query_builder::Col<BigFishCreationSession, __sdk::Timestamp>,
pub updated_at: __sdk::__query_builder::Col<BigFishCreationSession, __sdk::Timestamp>,
}
impl __sdk::__query_builder::HasCols for BigFishCreationSession {
type Cols = BigFishCreationSessionCols;
fn cols(table_name: &'static str) -> Self::Cols {
BigFishCreationSessionCols {
session_id: __sdk::__query_builder::Col::new(table_name, "session_id"),
owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"),
seed_text: __sdk::__query_builder::Col::new(table_name, "seed_text"),
current_turn: __sdk::__query_builder::Col::new(table_name, "current_turn"),
progress_percent: __sdk::__query_builder::Col::new(table_name, "progress_percent"),
stage: __sdk::__query_builder::Col::new(table_name, "stage"),
anchor_pack_json: __sdk::__query_builder::Col::new(table_name, "anchor_pack_json"),
draft_json: __sdk::__query_builder::Col::new(table_name, "draft_json"),
asset_coverage_json: __sdk::__query_builder::Col::new(table_name, "asset_coverage_json"),
last_assistant_reply: __sdk::__query_builder::Col::new(table_name, "last_assistant_reply"),
publish_ready: __sdk::__query_builder::Col::new(table_name, "publish_ready"),
created_at: __sdk::__query_builder::Col::new(table_name, "created_at"),
updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"),
}
}
}
/// Indexed column accessor struct for the table `BigFishCreationSession`.
///
/// Provides typed access to indexed columns for query building.
pub struct BigFishCreationSessionIxCols {
pub owner_user_id: __sdk::__query_builder::IxCol<BigFishCreationSession, String>,
pub session_id: __sdk::__query_builder::IxCol<BigFishCreationSession, String>,
}
impl __sdk::__query_builder::HasIxCols for BigFishCreationSession {
type IxCols = BigFishCreationSessionIxCols;
fn ix_cols(table_name: &'static str) -> Self::IxCols {
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"),
}
}
}
impl __sdk::__query_builder::CanBeLookupTable for BigFishCreationSession {}

View File

@@ -0,0 +1,33 @@
// 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 BigFishCreationStage {
CollectingAnchors,
DraftReady,
AssetRefining,
ReadyToPublish,
Published,
}
impl __sdk::InModule for BigFishCreationStage {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,25 @@
// 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 BigFishDraftCompileInput {
pub session_id: String,
pub owner_user_id: String,
pub compiled_at_micros: i64,
}
impl __sdk::InModule for BigFishDraftCompileInput {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,32 @@
// 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::big_fish_level_blueprint_type::BigFishLevelBlueprint;
use super::big_fish_background_blueprint_type::BigFishBackgroundBlueprint;
use super::big_fish_runtime_params_type::BigFishRuntimeParams;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct BigFishGameDraft {
pub title: String,
pub subtitle: String,
pub core_fun: String,
pub ecology_theme: String,
pub levels: Vec::<BigFishLevelBlueprint>,
pub background: BigFishBackgroundBlueprint,
pub runtime_params: BigFishRuntimeParams,
}
impl __sdk::InModule for BigFishGameDraft {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,33 @@
// 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 BigFishLevelBlueprint {
pub level: u32,
pub name: String,
pub one_line_fantasy: String,
pub silhouette_direction: String,
pub size_ratio: f32,
pub visual_prompt_seed: String,
pub motion_prompt_seed: String,
pub merge_source_level: Option::<u32>,
pub prey_window: Vec::<u32>,
pub threat_window: Vec::<u32>,
pub is_final_level: bool,
}
impl __sdk::InModule for BigFishLevelBlueprint {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,28 @@
// 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 BigFishMessageSubmitInput {
pub session_id: String,
pub owner_user_id: String,
pub user_message_id: String,
pub user_message_text: String,
pub assistant_message_id: String,
pub submitted_at_micros: i64,
}
impl __sdk::InModule for BigFishMessageSubmitInput {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,25 @@
// 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 BigFishPublishInput {
pub session_id: String,
pub owner_user_id: String,
pub published_at_micros: i64,
}
impl __sdk::InModule for BigFishPublishInput {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,24 @@
// 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 BigFishRunGetInput {
pub run_id: String,
pub owner_user_id: String,
}
impl __sdk::InModule for BigFishRunGetInput {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,27 @@
// 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 BigFishRunInputSubmitInput {
pub run_id: String,
pub owner_user_id: String,
pub input_x: f32,
pub input_y: f32,
pub submitted_at_micros: i64,
}
impl __sdk::InModule for BigFishRunInputSubmitInput {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,26 @@
// 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::big_fish_runtime_snapshot_type::BigFishRuntimeSnapshot;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct BigFishRunProcedureResult {
pub ok: bool,
pub run: Option::<BigFishRuntimeSnapshot>,
pub error_message: Option::<String>,
}
impl __sdk::InModule for BigFishRunProcedureResult {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,26 @@
// 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 BigFishRunStartInput {
pub run_id: String,
pub session_id: String,
pub owner_user_id: String,
pub started_at_micros: i64,
}
impl __sdk::InModule for BigFishRunStartInput {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,29 @@
// 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 BigFishRunStatus {
Running,
Won,
Failed,
}
impl __sdk::InModule for BigFishRunStatus {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,28 @@
// 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::big_fish_vector_2_type::BigFishVector2;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct BigFishRuntimeEntity {
pub entity_id: String,
pub level: u32,
pub position: BigFishVector2,
pub radius: f32,
pub offscreen_seconds: f32,
}
impl __sdk::InModule for BigFishRuntimeEntity {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,31 @@
// 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 BigFishRuntimeParams {
pub level_count: u32,
pub merge_count_per_upgrade: u32,
pub spawn_target_count: u32,
pub leader_move_speed: f32,
pub follower_catch_up_speed: f32,
pub offscreen_cull_seconds: f32,
pub prey_spawn_delta_levels: Vec::<u32>,
pub threat_spawn_delta_levels: Vec::<u32>,
pub win_level: u32,
}
impl __sdk::InModule for BigFishRuntimeParams {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,164 @@
// 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::big_fish_runtime_run_type::BigFishRuntimeRun;
use super::big_fish_run_status_type::BigFishRunStatus;
/// Table handle for the table `big_fish_runtime_run`.
///
/// Obtain a handle from the [`BigFishRuntimeRunTableAccess::big_fish_runtime_run`] method on [`super::RemoteTables`],
/// like `ctx.db.big_fish_runtime_run()`.
///
/// Users are encouraged not to explicitly reference this type,
/// but to directly chain method calls,
/// like `ctx.db.big_fish_runtime_run().on_insert(...)`.
pub struct BigFishRuntimeRunTableHandle<'ctx> {
imp: __sdk::TableHandle<BigFishRuntimeRun>,
ctx: std::marker::PhantomData<&'ctx super::RemoteTables>,
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the table `big_fish_runtime_run`.
///
/// Implemented for [`super::RemoteTables`].
pub trait BigFishRuntimeRunTableAccess {
#[allow(non_snake_case)]
/// Obtain a [`BigFishRuntimeRunTableHandle`], which mediates access to the table `big_fish_runtime_run`.
fn big_fish_runtime_run(&self) -> BigFishRuntimeRunTableHandle<'_>;
}
impl BigFishRuntimeRunTableAccess for super::RemoteTables {
fn big_fish_runtime_run(&self) -> BigFishRuntimeRunTableHandle<'_> {
BigFishRuntimeRunTableHandle {
imp: self.imp.get_table::<BigFishRuntimeRun>("big_fish_runtime_run"),
ctx: std::marker::PhantomData,
}
}
}
pub struct BigFishRuntimeRunInsertCallbackId(__sdk::CallbackId);
pub struct BigFishRuntimeRunDeleteCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::Table for BigFishRuntimeRunTableHandle<'ctx> {
type Row = BigFishRuntimeRun;
type EventContext = super::EventContext;
fn count(&self) -> u64 { self.imp.count() }
fn iter(&self) -> impl Iterator<Item = BigFishRuntimeRun> + '_ { self.imp.iter() }
type InsertCallbackId = BigFishRuntimeRunInsertCallbackId;
fn on_insert(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> BigFishRuntimeRunInsertCallbackId {
BigFishRuntimeRunInsertCallbackId(self.imp.on_insert(Box::new(callback)))
}
fn remove_on_insert(&self, callback: BigFishRuntimeRunInsertCallbackId) {
self.imp.remove_on_insert(callback.0)
}
type DeleteCallbackId = BigFishRuntimeRunDeleteCallbackId;
fn on_delete(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row) + Send + 'static,
) -> BigFishRuntimeRunDeleteCallbackId {
BigFishRuntimeRunDeleteCallbackId(self.imp.on_delete(Box::new(callback)))
}
fn remove_on_delete(&self, callback: BigFishRuntimeRunDeleteCallbackId) {
self.imp.remove_on_delete(callback.0)
}
}
pub struct BigFishRuntimeRunUpdateCallbackId(__sdk::CallbackId);
impl<'ctx> __sdk::TableWithPrimaryKey for BigFishRuntimeRunTableHandle<'ctx> {
type UpdateCallbackId = BigFishRuntimeRunUpdateCallbackId;
fn on_update(
&self,
callback: impl FnMut(&Self::EventContext, &Self::Row, &Self::Row) + Send + 'static,
) -> BigFishRuntimeRunUpdateCallbackId {
BigFishRuntimeRunUpdateCallbackId(self.imp.on_update(Box::new(callback)))
}
fn remove_on_update(&self, callback: BigFishRuntimeRunUpdateCallbackId) {
self.imp.remove_on_update(callback.0)
}
}
/// Access to the `run_id` unique index on the table `big_fish_runtime_run`,
/// which allows point queries on the field of the same name
/// via the [`BigFishRuntimeRunRunIdUnique::find`] method.
///
/// Users are encouraged not to explicitly reference this type,
/// but to directly chain method calls,
/// like `ctx.db.big_fish_runtime_run().run_id().find(...)`.
pub struct BigFishRuntimeRunRunIdUnique<'ctx> {
imp: __sdk::UniqueConstraintHandle<BigFishRuntimeRun, String>,
phantom: std::marker::PhantomData<&'ctx super::RemoteTables>,
}
impl<'ctx> BigFishRuntimeRunTableHandle<'ctx> {
/// Get a handle on the `run_id` unique index on the table `big_fish_runtime_run`.
pub fn run_id(&self) -> BigFishRuntimeRunRunIdUnique<'ctx> {
BigFishRuntimeRunRunIdUnique {
imp: self.imp.get_unique_constraint::<String>("run_id"),
phantom: std::marker::PhantomData,
}
}
}
impl<'ctx> BigFishRuntimeRunRunIdUnique<'ctx> {
/// Find the subscribed row whose `run_id` column value is equal to `col_val`,
/// if such a row is present in the client cache.
pub fn find(&self, col_val: &String) -> Option<BigFishRuntimeRun> {
self.imp.find(col_val)
}
}
#[doc(hidden)]
pub(super) fn register_table(client_cache: &mut __sdk::ClientCache<super::RemoteModule>) {
let _table = client_cache.get_or_make_table::<BigFishRuntimeRun>("big_fish_runtime_run");
_table.add_unique_constraint::<String>("run_id", |row| &row.run_id);
}
#[doc(hidden)]
pub(super) fn parse_table_update(
raw_updates: __ws::v2::TableUpdate,
) -> __sdk::Result<__sdk::TableUpdate<BigFishRuntimeRun>> {
__sdk::TableUpdate::parse_table_update(raw_updates).map_err(|e| {
__sdk::InternalError::failed_parse(
"TableUpdate<BigFishRuntimeRun>",
"TableUpdate",
).with_cause(e).into()
})
}
#[allow(non_camel_case_types)]
/// Extension trait for query builder access to the table `BigFishRuntimeRun`.
///
/// Implemented for [`__sdk::QueryTableAccessor`].
pub trait big_fish_runtime_runQueryTableAccess {
#[allow(non_snake_case)]
/// Get a query builder for the table `BigFishRuntimeRun`.
fn big_fish_runtime_run(&self) -> __sdk::__query_builder::Table<BigFishRuntimeRun>;
}
impl big_fish_runtime_runQueryTableAccess for __sdk::QueryTableAccessor {
fn big_fish_runtime_run(&self) -> __sdk::__query_builder::Table<BigFishRuntimeRun> {
__sdk::__query_builder::Table::new("big_fish_runtime_run")
}
}

View File

@@ -0,0 +1,92 @@
// 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::big_fish_run_status_type::BigFishRunStatus;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct BigFishRuntimeRun {
pub run_id: String,
pub session_id: String,
pub owner_user_id: String,
pub status: BigFishRunStatus,
pub snapshot_json: String,
pub last_input_x: f32,
pub last_input_y: f32,
pub tick: u64,
pub created_at: __sdk::Timestamp,
pub updated_at: __sdk::Timestamp,
}
impl __sdk::InModule for BigFishRuntimeRun {
type Module = super::RemoteModule;
}
/// Column accessor struct for the table `BigFishRuntimeRun`.
///
/// Provides typed access to columns for query building.
pub struct BigFishRuntimeRunCols {
pub run_id: __sdk::__query_builder::Col<BigFishRuntimeRun, String>,
pub session_id: __sdk::__query_builder::Col<BigFishRuntimeRun, String>,
pub owner_user_id: __sdk::__query_builder::Col<BigFishRuntimeRun, String>,
pub status: __sdk::__query_builder::Col<BigFishRuntimeRun, BigFishRunStatus>,
pub snapshot_json: __sdk::__query_builder::Col<BigFishRuntimeRun, String>,
pub last_input_x: __sdk::__query_builder::Col<BigFishRuntimeRun, f32>,
pub last_input_y: __sdk::__query_builder::Col<BigFishRuntimeRun, f32>,
pub tick: __sdk::__query_builder::Col<BigFishRuntimeRun, u64>,
pub created_at: __sdk::__query_builder::Col<BigFishRuntimeRun, __sdk::Timestamp>,
pub updated_at: __sdk::__query_builder::Col<BigFishRuntimeRun, __sdk::Timestamp>,
}
impl __sdk::__query_builder::HasCols for BigFishRuntimeRun {
type Cols = BigFishRuntimeRunCols;
fn cols(table_name: &'static str) -> Self::Cols {
BigFishRuntimeRunCols {
run_id: __sdk::__query_builder::Col::new(table_name, "run_id"),
session_id: __sdk::__query_builder::Col::new(table_name, "session_id"),
owner_user_id: __sdk::__query_builder::Col::new(table_name, "owner_user_id"),
status: __sdk::__query_builder::Col::new(table_name, "status"),
snapshot_json: __sdk::__query_builder::Col::new(table_name, "snapshot_json"),
last_input_x: __sdk::__query_builder::Col::new(table_name, "last_input_x"),
last_input_y: __sdk::__query_builder::Col::new(table_name, "last_input_y"),
tick: __sdk::__query_builder::Col::new(table_name, "tick"),
created_at: __sdk::__query_builder::Col::new(table_name, "created_at"),
updated_at: __sdk::__query_builder::Col::new(table_name, "updated_at"),
}
}
}
/// Indexed column accessor struct for the table `BigFishRuntimeRun`.
///
/// Provides typed access to indexed columns for query building.
pub struct BigFishRuntimeRunIxCols {
pub owner_user_id: __sdk::__query_builder::IxCol<BigFishRuntimeRun, String>,
pub run_id: __sdk::__query_builder::IxCol<BigFishRuntimeRun, String>,
pub session_id: __sdk::__query_builder::IxCol<BigFishRuntimeRun, String>,
}
impl __sdk::__query_builder::HasIxCols for BigFishRuntimeRun {
type IxCols = BigFishRuntimeRunIxCols;
fn ix_cols(table_name: &'static str) -> Self::IxCols {
BigFishRuntimeRunIxCols {
owner_user_id: __sdk::__query_builder::IxCol::new(table_name, "owner_user_id"),
run_id: __sdk::__query_builder::IxCol::new(table_name, "run_id"),
session_id: __sdk::__query_builder::IxCol::new(table_name, "session_id"),
}
}
}
impl __sdk::__query_builder::CanBeLookupTable for BigFishRuntimeRun {}

View File

@@ -0,0 +1,38 @@
// 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::big_fish_run_status_type::BigFishRunStatus;
use super::big_fish_runtime_entity_type::BigFishRuntimeEntity;
use super::big_fish_vector_2_type::BigFishVector2;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct BigFishRuntimeSnapshot {
pub run_id: String,
pub session_id: String,
pub status: BigFishRunStatus,
pub tick: u64,
pub player_level: u32,
pub win_level: u32,
pub leader_entity_id: Option::<String>,
pub owned_entities: Vec::<BigFishRuntimeEntity>,
pub wild_entities: Vec::<BigFishRuntimeEntity>,
pub camera_center: BigFishVector2,
pub last_input: BigFishVector2,
pub event_log: Vec::<String>,
pub updated_at_micros: i64,
}
impl __sdk::InModule for BigFishRuntimeSnapshot {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,28 @@
// 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 BigFishSessionCreateInput {
pub session_id: String,
pub owner_user_id: String,
pub seed_text: String,
pub welcome_message_id: String,
pub welcome_message_text: String,
pub created_at_micros: i64,
}
impl __sdk::InModule for BigFishSessionCreateInput {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,24 @@
// 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 BigFishSessionGetInput {
pub session_id: String,
pub owner_user_id: String,
}
impl __sdk::InModule for BigFishSessionGetInput {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,26 @@
// 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::big_fish_session_snapshot_type::BigFishSessionSnapshot;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct BigFishSessionProcedureResult {
pub ok: bool,
pub session: Option::<BigFishSessionSnapshot>,
pub error_message: Option::<String>,
}
impl __sdk::InModule for BigFishSessionProcedureResult {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,43 @@
// 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::big_fish_creation_stage_type::BigFishCreationStage;
use super::big_fish_anchor_pack_type::BigFishAnchorPack;
use super::big_fish_game_draft_type::BigFishGameDraft;
use super::big_fish_asset_slot_snapshot_type::BigFishAssetSlotSnapshot;
use super::big_fish_asset_coverage_type::BigFishAssetCoverage;
use super::big_fish_agent_message_snapshot_type::BigFishAgentMessageSnapshot;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
pub struct BigFishSessionSnapshot {
pub session_id: String,
pub owner_user_id: String,
pub seed_text: String,
pub current_turn: u32,
pub progress_percent: u32,
pub stage: BigFishCreationStage,
pub anchor_pack: BigFishAnchorPack,
pub draft: Option::<BigFishGameDraft>,
pub asset_slots: Vec::<BigFishAssetSlotSnapshot>,
pub asset_coverage: BigFishAssetCoverage,
pub messages: Vec::<BigFishAgentMessageSnapshot>,
pub last_assistant_reply: Option::<String>,
pub publish_ready: bool,
pub created_at_micros: i64,
pub updated_at_micros: i64,
}
impl __sdk::InModule for BigFishSessionSnapshot {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,24 @@
// 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 BigFishVector2 {
pub x: f32,
pub y: f32,
}
impl __sdk::InModule for BigFishVector2 {
type Module = super::RemoteModule;
}

View File

@@ -0,0 +1,58 @@
// 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::big_fish_draft_compile_input_type::BigFishDraftCompileInput;
use super::big_fish_session_procedure_result_type::BigFishSessionProcedureResult;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
struct CompileBigFishDraftArgs {
pub input: BigFishDraftCompileInput,
}
impl __sdk::InModule for CompileBigFishDraftArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `compile_big_fish_draft`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait compile_big_fish_draft {
fn compile_big_fish_draft(&self, input: BigFishDraftCompileInput,
) {
self.compile_big_fish_draft_then(input, |_, _| {});
}
fn compile_big_fish_draft_then(
&self,
input: BigFishDraftCompileInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<BigFishSessionProcedureResult, __sdk::InternalError>) + Send + 'static,
);
}
impl compile_big_fish_draft for super::RemoteProcedures {
fn compile_big_fish_draft_then(
&self,
input: BigFishDraftCompileInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<BigFishSessionProcedureResult, __sdk::InternalError>) + Send + 'static,
) {
self.imp.invoke_procedure_with_callback::<_, BigFishSessionProcedureResult>(
"compile_big_fish_draft",
CompileBigFishDraftArgs { input, },
__callback,
);
}
}

View File

@@ -0,0 +1,58 @@
// 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_draft_compile_input_type::PuzzleDraftCompileInput;
use super::puzzle_agent_session_procedure_result_type::PuzzleAgentSessionProcedureResult;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
struct CompilePuzzleAgentDraftArgs {
pub input: PuzzleDraftCompileInput,
}
impl __sdk::InModule for CompilePuzzleAgentDraftArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `compile_puzzle_agent_draft`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait compile_puzzle_agent_draft {
fn compile_puzzle_agent_draft(&self, input: PuzzleDraftCompileInput,
) {
self.compile_puzzle_agent_draft_then(input, |_, _| {});
}
fn compile_puzzle_agent_draft_then(
&self,
input: PuzzleDraftCompileInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleAgentSessionProcedureResult, __sdk::InternalError>) + Send + 'static,
);
}
impl compile_puzzle_agent_draft for super::RemoteProcedures {
fn compile_puzzle_agent_draft_then(
&self,
input: PuzzleDraftCompileInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleAgentSessionProcedureResult, __sdk::InternalError>) + Send + 'static,
) {
self.imp.invoke_procedure_with_callback::<_, PuzzleAgentSessionProcedureResult>(
"compile_puzzle_agent_draft",
CompilePuzzleAgentDraftArgs { input, },
__callback,
);
}
}

View File

@@ -0,0 +1,58 @@
// 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::big_fish_session_procedure_result_type::BigFishSessionProcedureResult;
use super::big_fish_session_create_input_type::BigFishSessionCreateInput;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
struct CreateBigFishSessionArgs {
pub input: BigFishSessionCreateInput,
}
impl __sdk::InModule for CreateBigFishSessionArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `create_big_fish_session`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait create_big_fish_session {
fn create_big_fish_session(&self, input: BigFishSessionCreateInput,
) {
self.create_big_fish_session_then(input, |_, _| {});
}
fn create_big_fish_session_then(
&self,
input: BigFishSessionCreateInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<BigFishSessionProcedureResult, __sdk::InternalError>) + Send + 'static,
);
}
impl create_big_fish_session for super::RemoteProcedures {
fn create_big_fish_session_then(
&self,
input: BigFishSessionCreateInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<BigFishSessionProcedureResult, __sdk::InternalError>) + Send + 'static,
) {
self.imp.invoke_procedure_with_callback::<_, BigFishSessionProcedureResult>(
"create_big_fish_session",
CreateBigFishSessionArgs { input, },
__callback,
);
}
}

View File

@@ -0,0 +1,58 @@
// 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_agent_session_procedure_result_type::PuzzleAgentSessionProcedureResult;
use super::puzzle_agent_session_create_input_type::PuzzleAgentSessionCreateInput;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
struct CreatePuzzleAgentSessionArgs {
pub input: PuzzleAgentSessionCreateInput,
}
impl __sdk::InModule for CreatePuzzleAgentSessionArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `create_puzzle_agent_session`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait create_puzzle_agent_session {
fn create_puzzle_agent_session(&self, input: PuzzleAgentSessionCreateInput,
) {
self.create_puzzle_agent_session_then(input, |_, _| {});
}
fn create_puzzle_agent_session_then(
&self,
input: PuzzleAgentSessionCreateInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleAgentSessionProcedureResult, __sdk::InternalError>) + Send + 'static,
);
}
impl create_puzzle_agent_session for super::RemoteProcedures {
fn create_puzzle_agent_session_then(
&self,
input: PuzzleAgentSessionCreateInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleAgentSessionProcedureResult, __sdk::InternalError>) + Send + 'static,
) {
self.imp.invoke_procedure_with_callback::<_, PuzzleAgentSessionProcedureResult>(
"create_puzzle_agent_session",
CreatePuzzleAgentSessionArgs { input, },
__callback,
);
}
}

View File

@@ -0,0 +1,58 @@
// 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_run_procedure_result_type::PuzzleRunProcedureResult;
use super::puzzle_run_drag_input_type::PuzzleRunDragInput;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
struct DragPuzzlePieceOrGroupArgs {
pub input: PuzzleRunDragInput,
}
impl __sdk::InModule for DragPuzzlePieceOrGroupArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `drag_puzzle_piece_or_group`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait drag_puzzle_piece_or_group {
fn drag_puzzle_piece_or_group(&self, input: PuzzleRunDragInput,
) {
self.drag_puzzle_piece_or_group_then(input, |_, _| {});
}
fn drag_puzzle_piece_or_group_then(
&self,
input: PuzzleRunDragInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleRunProcedureResult, __sdk::InternalError>) + Send + 'static,
);
}
impl drag_puzzle_piece_or_group for super::RemoteProcedures {
fn drag_puzzle_piece_or_group_then(
&self,
input: PuzzleRunDragInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleRunProcedureResult, __sdk::InternalError>) + Send + 'static,
) {
self.imp.invoke_procedure_with_callback::<_, PuzzleRunProcedureResult>(
"drag_puzzle_piece_or_group",
DragPuzzlePieceOrGroupArgs { input, },
__callback,
);
}
}

View File

@@ -0,0 +1,58 @@
// 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::big_fish_session_procedure_result_type::BigFishSessionProcedureResult;
use super::big_fish_asset_generate_input_type::BigFishAssetGenerateInput;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
struct GenerateBigFishAssetArgs {
pub input: BigFishAssetGenerateInput,
}
impl __sdk::InModule for GenerateBigFishAssetArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `generate_big_fish_asset`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait generate_big_fish_asset {
fn generate_big_fish_asset(&self, input: BigFishAssetGenerateInput,
) {
self.generate_big_fish_asset_then(input, |_, _| {});
}
fn generate_big_fish_asset_then(
&self,
input: BigFishAssetGenerateInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<BigFishSessionProcedureResult, __sdk::InternalError>) + Send + 'static,
);
}
impl generate_big_fish_asset for super::RemoteProcedures {
fn generate_big_fish_asset_then(
&self,
input: BigFishAssetGenerateInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<BigFishSessionProcedureResult, __sdk::InternalError>) + Send + 'static,
) {
self.imp.invoke_procedure_with_callback::<_, BigFishSessionProcedureResult>(
"generate_big_fish_asset",
GenerateBigFishAssetArgs { input, },
__callback,
);
}
}

View File

@@ -0,0 +1,58 @@
// 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::big_fish_run_get_input_type::BigFishRunGetInput;
use super::big_fish_run_procedure_result_type::BigFishRunProcedureResult;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
struct GetBigFishRunArgs {
pub input: BigFishRunGetInput,
}
impl __sdk::InModule for GetBigFishRunArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `get_big_fish_run`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait get_big_fish_run {
fn get_big_fish_run(&self, input: BigFishRunGetInput,
) {
self.get_big_fish_run_then(input, |_, _| {});
}
fn get_big_fish_run_then(
&self,
input: BigFishRunGetInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<BigFishRunProcedureResult, __sdk::InternalError>) + Send + 'static,
);
}
impl get_big_fish_run for super::RemoteProcedures {
fn get_big_fish_run_then(
&self,
input: BigFishRunGetInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<BigFishRunProcedureResult, __sdk::InternalError>) + Send + 'static,
) {
self.imp.invoke_procedure_with_callback::<_, BigFishRunProcedureResult>(
"get_big_fish_run",
GetBigFishRunArgs { input, },
__callback,
);
}
}

View File

@@ -0,0 +1,58 @@
// 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::big_fish_session_procedure_result_type::BigFishSessionProcedureResult;
use super::big_fish_session_get_input_type::BigFishSessionGetInput;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
struct GetBigFishSessionArgs {
pub input: BigFishSessionGetInput,
}
impl __sdk::InModule for GetBigFishSessionArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `get_big_fish_session`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait get_big_fish_session {
fn get_big_fish_session(&self, input: BigFishSessionGetInput,
) {
self.get_big_fish_session_then(input, |_, _| {});
}
fn get_big_fish_session_then(
&self,
input: BigFishSessionGetInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<BigFishSessionProcedureResult, __sdk::InternalError>) + Send + 'static,
);
}
impl get_big_fish_session for super::RemoteProcedures {
fn get_big_fish_session_then(
&self,
input: BigFishSessionGetInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<BigFishSessionProcedureResult, __sdk::InternalError>) + Send + 'static,
) {
self.imp.invoke_procedure_with_callback::<_, BigFishSessionProcedureResult>(
"get_big_fish_session",
GetBigFishSessionArgs { input, },
__callback,
);
}
}

View File

@@ -0,0 +1,58 @@
// 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_agent_session_procedure_result_type::PuzzleAgentSessionProcedureResult;
use super::puzzle_agent_session_get_input_type::PuzzleAgentSessionGetInput;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
struct GetPuzzleAgentSessionArgs {
pub input: PuzzleAgentSessionGetInput,
}
impl __sdk::InModule for GetPuzzleAgentSessionArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `get_puzzle_agent_session`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait get_puzzle_agent_session {
fn get_puzzle_agent_session(&self, input: PuzzleAgentSessionGetInput,
) {
self.get_puzzle_agent_session_then(input, |_, _| {});
}
fn get_puzzle_agent_session_then(
&self,
input: PuzzleAgentSessionGetInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleAgentSessionProcedureResult, __sdk::InternalError>) + Send + 'static,
);
}
impl get_puzzle_agent_session for super::RemoteProcedures {
fn get_puzzle_agent_session_then(
&self,
input: PuzzleAgentSessionGetInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleAgentSessionProcedureResult, __sdk::InternalError>) + Send + 'static,
) {
self.imp.invoke_procedure_with_callback::<_, PuzzleAgentSessionProcedureResult>(
"get_puzzle_agent_session",
GetPuzzleAgentSessionArgs { input, },
__callback,
);
}
}

View File

@@ -0,0 +1,58 @@
// 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_work_get_input_type::PuzzleWorkGetInput;
use super::puzzle_work_procedure_result_type::PuzzleWorkProcedureResult;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
struct GetPuzzleGalleryDetailArgs {
pub input: PuzzleWorkGetInput,
}
impl __sdk::InModule for GetPuzzleGalleryDetailArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `get_puzzle_gallery_detail`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait get_puzzle_gallery_detail {
fn get_puzzle_gallery_detail(&self, input: PuzzleWorkGetInput,
) {
self.get_puzzle_gallery_detail_then(input, |_, _| {});
}
fn get_puzzle_gallery_detail_then(
&self,
input: PuzzleWorkGetInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleWorkProcedureResult, __sdk::InternalError>) + Send + 'static,
);
}
impl get_puzzle_gallery_detail for super::RemoteProcedures {
fn get_puzzle_gallery_detail_then(
&self,
input: PuzzleWorkGetInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleWorkProcedureResult, __sdk::InternalError>) + Send + 'static,
) {
self.imp.invoke_procedure_with_callback::<_, PuzzleWorkProcedureResult>(
"get_puzzle_gallery_detail",
GetPuzzleGalleryDetailArgs { input, },
__callback,
);
}
}

View File

@@ -0,0 +1,58 @@
// 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_run_procedure_result_type::PuzzleRunProcedureResult;
use super::puzzle_run_get_input_type::PuzzleRunGetInput;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
struct GetPuzzleRunArgs {
pub input: PuzzleRunGetInput,
}
impl __sdk::InModule for GetPuzzleRunArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `get_puzzle_run`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait get_puzzle_run {
fn get_puzzle_run(&self, input: PuzzleRunGetInput,
) {
self.get_puzzle_run_then(input, |_, _| {});
}
fn get_puzzle_run_then(
&self,
input: PuzzleRunGetInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleRunProcedureResult, __sdk::InternalError>) + Send + 'static,
);
}
impl get_puzzle_run for super::RemoteProcedures {
fn get_puzzle_run_then(
&self,
input: PuzzleRunGetInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleRunProcedureResult, __sdk::InternalError>) + Send + 'static,
) {
self.imp.invoke_procedure_with_callback::<_, PuzzleRunProcedureResult>(
"get_puzzle_run",
GetPuzzleRunArgs { input, },
__callback,
);
}
}

View File

@@ -0,0 +1,58 @@
// 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_work_get_input_type::PuzzleWorkGetInput;
use super::puzzle_work_procedure_result_type::PuzzleWorkProcedureResult;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
struct GetPuzzleWorkDetailArgs {
pub input: PuzzleWorkGetInput,
}
impl __sdk::InModule for GetPuzzleWorkDetailArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `get_puzzle_work_detail`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait get_puzzle_work_detail {
fn get_puzzle_work_detail(&self, input: PuzzleWorkGetInput,
) {
self.get_puzzle_work_detail_then(input, |_, _| {});
}
fn get_puzzle_work_detail_then(
&self,
input: PuzzleWorkGetInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleWorkProcedureResult, __sdk::InternalError>) + Send + 'static,
);
}
impl get_puzzle_work_detail for super::RemoteProcedures {
fn get_puzzle_work_detail_then(
&self,
input: PuzzleWorkGetInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleWorkProcedureResult, __sdk::InternalError>) + Send + 'static,
) {
self.imp.invoke_procedure_with_callback::<_, PuzzleWorkProcedureResult>(
"get_puzzle_work_detail",
GetPuzzleWorkDetailArgs { input, },
__callback,
);
}
}

View File

@@ -0,0 +1,53 @@
// 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_works_procedure_result_type::PuzzleWorksProcedureResult;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
struct ListPuzzleGalleryArgs {
}
impl __sdk::InModule for ListPuzzleGalleryArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `list_puzzle_gallery`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait list_puzzle_gallery {
fn list_puzzle_gallery(&self, ) {
self.list_puzzle_gallery_then( |_, _| {});
}
fn list_puzzle_gallery_then(
&self,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleWorksProcedureResult, __sdk::InternalError>) + Send + 'static,
);
}
impl list_puzzle_gallery for super::RemoteProcedures {
fn list_puzzle_gallery_then(
&self,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleWorksProcedureResult, __sdk::InternalError>) + Send + 'static,
) {
self.imp.invoke_procedure_with_callback::<_, PuzzleWorksProcedureResult>(
"list_puzzle_gallery",
ListPuzzleGalleryArgs { },
__callback,
);
}
}

View File

@@ -0,0 +1,58 @@
// 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_works_procedure_result_type::PuzzleWorksProcedureResult;
use super::puzzle_works_list_input_type::PuzzleWorksListInput;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
struct ListPuzzleWorksArgs {
pub input: PuzzleWorksListInput,
}
impl __sdk::InModule for ListPuzzleWorksArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `list_puzzle_works`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait list_puzzle_works {
fn list_puzzle_works(&self, input: PuzzleWorksListInput,
) {
self.list_puzzle_works_then(input, |_, _| {});
}
fn list_puzzle_works_then(
&self,
input: PuzzleWorksListInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleWorksProcedureResult, __sdk::InternalError>) + Send + 'static,
);
}
impl list_puzzle_works for super::RemoteProcedures {
fn list_puzzle_works_then(
&self,
input: PuzzleWorksListInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<PuzzleWorksProcedureResult, __sdk::InternalError>) + Send + 'static,
) {
self.imp.invoke_procedure_with_callback::<_, PuzzleWorksProcedureResult>(
"list_puzzle_works",
ListPuzzleWorksArgs { input, },
__callback,
);
}
}

View File

@@ -51,6 +51,41 @@ pub mod battle_state_procedure_result_type;
pub mod battle_state_query_input_type;
pub mod battle_state_snapshot_type;
pub mod battle_status_type;
pub mod big_fish_agent_message_type;
pub mod big_fish_agent_message_kind_type;
pub mod big_fish_agent_message_role_type;
pub mod big_fish_agent_message_snapshot_type;
pub mod big_fish_anchor_item_type;
pub mod big_fish_anchor_pack_type;
pub mod big_fish_anchor_status_type;
pub mod big_fish_asset_coverage_type;
pub mod big_fish_asset_generate_input_type;
pub mod big_fish_asset_kind_type;
pub mod big_fish_asset_slot_type;
pub mod big_fish_asset_slot_snapshot_type;
pub mod big_fish_asset_status_type;
pub mod big_fish_background_blueprint_type;
pub mod big_fish_creation_session_type;
pub mod big_fish_creation_stage_type;
pub mod big_fish_draft_compile_input_type;
pub mod big_fish_game_draft_type;
pub mod big_fish_level_blueprint_type;
pub mod big_fish_message_submit_input_type;
pub mod big_fish_publish_input_type;
pub mod big_fish_run_get_input_type;
pub mod big_fish_run_input_submit_input_type;
pub mod big_fish_run_procedure_result_type;
pub mod big_fish_run_start_input_type;
pub mod big_fish_run_status_type;
pub mod big_fish_runtime_entity_type;
pub mod big_fish_runtime_params_type;
pub mod big_fish_runtime_run_type;
pub mod big_fish_runtime_snapshot_type;
pub mod big_fish_session_create_input_type;
pub mod big_fish_session_get_input_type;
pub mod big_fish_session_procedure_result_type;
pub mod big_fish_session_snapshot_type;
pub mod big_fish_vector_2_type;
pub mod chapter_pace_band_type;
pub mod chapter_progression_type;
pub mod chapter_progression_get_input_type;
@@ -142,6 +177,33 @@ pub mod profile_dashboard_state_type;
pub mod profile_played_world_type;
pub mod profile_save_archive_type;
pub mod profile_wallet_ledger_type;
pub mod puzzle_agent_message_kind_type;
pub mod puzzle_agent_message_role_type;
pub mod puzzle_agent_message_row_type;
pub mod puzzle_agent_message_submit_input_type;
pub mod puzzle_agent_session_create_input_type;
pub mod puzzle_agent_session_get_input_type;
pub mod puzzle_agent_session_procedure_result_type;
pub mod puzzle_agent_session_row_type;
pub mod puzzle_agent_stage_type;
pub mod puzzle_draft_compile_input_type;
pub mod puzzle_generated_images_save_input_type;
pub mod puzzle_publication_status_type;
pub mod puzzle_publish_input_type;
pub mod puzzle_run_drag_input_type;
pub mod puzzle_run_get_input_type;
pub mod puzzle_run_next_level_input_type;
pub mod puzzle_run_procedure_result_type;
pub mod puzzle_run_start_input_type;
pub mod puzzle_run_swap_input_type;
pub mod puzzle_runtime_run_row_type;
pub mod puzzle_select_cover_image_input_type;
pub mod puzzle_work_get_input_type;
pub mod puzzle_work_procedure_result_type;
pub mod puzzle_work_profile_row_type;
pub mod puzzle_work_upsert_input_type;
pub mod puzzle_works_list_input_type;
pub mod puzzle_works_procedure_result_type;
pub mod quest_completion_ack_input_type;
pub mod quest_hostile_npc_defeated_signal_type;
pub mod quest_item_delivered_signal_type;
@@ -271,6 +333,10 @@ pub mod ai_text_chunk_table;
pub mod asset_entity_binding_table;
pub mod asset_object_table;
pub mod battle_state_table;
pub mod big_fish_agent_message_table;
pub mod big_fish_asset_slot_table;
pub mod big_fish_creation_session_table;
pub mod big_fish_runtime_run_table;
pub mod chapter_progression_table;
pub mod custom_world_agent_message_table;
pub mod custom_world_agent_operation_table;
@@ -286,6 +352,10 @@ pub mod profile_dashboard_state_table;
pub mod profile_played_world_table;
pub mod profile_save_archive_table;
pub mod profile_wallet_ledger_table;
pub mod puzzle_agent_message_table;
pub mod puzzle_agent_session_table;
pub mod puzzle_runtime_run_table;
pub mod puzzle_work_profile_table;
pub mod quest_log_table;
pub mod quest_record_table;
pub mod runtime_setting_table;
@@ -294,6 +364,7 @@ pub mod story_event_table;
pub mod story_session_table;
pub mod treasure_record_table;
pub mod user_browse_history_table;
pub mod advance_puzzle_next_level_procedure;
pub mod append_ai_text_chunk_and_return_procedure;
pub mod apply_chapter_progression_ledger_entry_and_return_procedure;
pub mod attach_ai_result_reference_and_return_procedure;
@@ -301,18 +372,26 @@ pub mod begin_story_session_and_return_procedure;
pub mod bind_asset_object_to_entity_and_return_procedure;
pub mod cancel_ai_task_and_return_procedure;
pub mod clear_platform_browse_history_and_return_procedure;
pub mod compile_big_fish_draft_procedure;
pub mod compile_custom_world_published_profile_procedure;
pub mod compile_puzzle_agent_draft_procedure;
pub mod complete_ai_stage_and_return_procedure;
pub mod complete_ai_task_and_return_procedure;
pub mod confirm_asset_object_and_return_procedure;
pub mod continue_story_and_return_procedure;
pub mod create_ai_task_and_return_procedure;
pub mod create_battle_state_and_return_procedure;
pub mod create_big_fish_session_procedure;
pub mod create_custom_world_agent_session_procedure;
pub mod create_puzzle_agent_session_procedure;
pub mod delete_runtime_snapshot_and_return_procedure;
pub mod drag_puzzle_piece_or_group_procedure;
pub mod execute_custom_world_agent_action_procedure;
pub mod fail_ai_task_and_return_procedure;
pub mod generate_big_fish_asset_procedure;
pub mod get_battle_state_procedure;
pub mod get_big_fish_run_procedure;
pub mod get_big_fish_session_procedure;
pub mod get_chapter_progression_procedure;
pub mod get_custom_world_agent_card_detail_procedure;
pub mod get_custom_world_agent_operation_procedure;
@@ -322,6 +401,10 @@ pub mod get_custom_world_library_detail_procedure;
pub mod get_player_progression_or_default_procedure;
pub mod get_profile_dashboard_procedure;
pub mod get_profile_play_stats_procedure;
pub mod get_puzzle_agent_session_procedure;
pub mod get_puzzle_gallery_detail_procedure;
pub mod get_puzzle_run_procedure;
pub mod get_puzzle_work_detail_procedure;
pub mod get_runtime_inventory_state_procedure;
pub mod get_runtime_setting_or_default_procedure;
pub mod get_runtime_snapshot_procedure;
@@ -333,16 +416,29 @@ pub mod list_custom_world_works_procedure;
pub mod list_platform_browse_history_procedure;
pub mod list_profile_save_archives_procedure;
pub mod list_profile_wallet_ledger_procedure;
pub mod list_puzzle_gallery_procedure;
pub mod list_puzzle_works_procedure;
pub mod publish_big_fish_game_procedure;
pub mod publish_custom_world_profile_and_return_procedure;
pub mod publish_custom_world_world_procedure;
pub mod publish_puzzle_work_procedure;
pub mod resolve_combat_action_and_return_procedure;
pub mod resolve_npc_battle_interaction_and_return_procedure;
pub mod resolve_npc_interaction_and_return_procedure;
pub mod resolve_npc_social_action_and_return_procedure;
pub mod resolve_treasure_interaction_and_return_procedure;
pub mod resume_profile_save_archive_and_return_procedure;
pub mod save_puzzle_generated_images_procedure;
pub mod select_puzzle_cover_image_procedure;
pub mod start_big_fish_run_procedure;
pub mod start_puzzle_run_procedure;
pub mod submit_big_fish_input_procedure;
pub mod submit_big_fish_message_procedure;
pub mod submit_custom_world_agent_message_procedure;
pub mod submit_puzzle_agent_message_procedure;
pub mod swap_puzzle_pieces_procedure;
pub mod unpublish_custom_world_profile_and_return_procedure;
pub mod update_puzzle_work_procedure;
pub mod upsert_chapter_progression_and_return_procedure;
pub mod upsert_custom_world_profile_and_return_procedure;
pub mod upsert_npc_state_and_return_procedure;
@@ -390,6 +486,41 @@ pub use battle_state_procedure_result_type::BattleStateProcedureResult;
pub use battle_state_query_input_type::BattleStateQueryInput;
pub use battle_state_snapshot_type::BattleStateSnapshot;
pub use battle_status_type::BattleStatus;
pub use big_fish_agent_message_type::BigFishAgentMessage;
pub use big_fish_agent_message_kind_type::BigFishAgentMessageKind;
pub use big_fish_agent_message_role_type::BigFishAgentMessageRole;
pub use big_fish_agent_message_snapshot_type::BigFishAgentMessageSnapshot;
pub use big_fish_anchor_item_type::BigFishAnchorItem;
pub use big_fish_anchor_pack_type::BigFishAnchorPack;
pub use big_fish_anchor_status_type::BigFishAnchorStatus;
pub use big_fish_asset_coverage_type::BigFishAssetCoverage;
pub use big_fish_asset_generate_input_type::BigFishAssetGenerateInput;
pub use big_fish_asset_kind_type::BigFishAssetKind;
pub use big_fish_asset_slot_type::BigFishAssetSlot;
pub use big_fish_asset_slot_snapshot_type::BigFishAssetSlotSnapshot;
pub use big_fish_asset_status_type::BigFishAssetStatus;
pub use big_fish_background_blueprint_type::BigFishBackgroundBlueprint;
pub use big_fish_creation_session_type::BigFishCreationSession;
pub use big_fish_creation_stage_type::BigFishCreationStage;
pub use big_fish_draft_compile_input_type::BigFishDraftCompileInput;
pub use big_fish_game_draft_type::BigFishGameDraft;
pub use big_fish_level_blueprint_type::BigFishLevelBlueprint;
pub use big_fish_message_submit_input_type::BigFishMessageSubmitInput;
pub use big_fish_publish_input_type::BigFishPublishInput;
pub use big_fish_run_get_input_type::BigFishRunGetInput;
pub use big_fish_run_input_submit_input_type::BigFishRunInputSubmitInput;
pub use big_fish_run_procedure_result_type::BigFishRunProcedureResult;
pub use big_fish_run_start_input_type::BigFishRunStartInput;
pub use big_fish_run_status_type::BigFishRunStatus;
pub use big_fish_runtime_entity_type::BigFishRuntimeEntity;
pub use big_fish_runtime_params_type::BigFishRuntimeParams;
pub use big_fish_runtime_run_type::BigFishRuntimeRun;
pub use big_fish_runtime_snapshot_type::BigFishRuntimeSnapshot;
pub use big_fish_session_create_input_type::BigFishSessionCreateInput;
pub use big_fish_session_get_input_type::BigFishSessionGetInput;
pub use big_fish_session_procedure_result_type::BigFishSessionProcedureResult;
pub use big_fish_session_snapshot_type::BigFishSessionSnapshot;
pub use big_fish_vector_2_type::BigFishVector2;
pub use chapter_pace_band_type::ChapterPaceBand;
pub use chapter_progression_type::ChapterProgression;
pub use chapter_progression_get_input_type::ChapterProgressionGetInput;
@@ -481,6 +612,33 @@ pub use profile_dashboard_state_type::ProfileDashboardState;
pub use profile_played_world_type::ProfilePlayedWorld;
pub use profile_save_archive_type::ProfileSaveArchive;
pub use profile_wallet_ledger_type::ProfileWalletLedger;
pub use puzzle_agent_message_kind_type::PuzzleAgentMessageKind;
pub use puzzle_agent_message_role_type::PuzzleAgentMessageRole;
pub use puzzle_agent_message_row_type::PuzzleAgentMessageRow;
pub use puzzle_agent_message_submit_input_type::PuzzleAgentMessageSubmitInput;
pub use puzzle_agent_session_create_input_type::PuzzleAgentSessionCreateInput;
pub use puzzle_agent_session_get_input_type::PuzzleAgentSessionGetInput;
pub use puzzle_agent_session_procedure_result_type::PuzzleAgentSessionProcedureResult;
pub use puzzle_agent_session_row_type::PuzzleAgentSessionRow;
pub use puzzle_agent_stage_type::PuzzleAgentStage;
pub use puzzle_draft_compile_input_type::PuzzleDraftCompileInput;
pub use puzzle_generated_images_save_input_type::PuzzleGeneratedImagesSaveInput;
pub use puzzle_publication_status_type::PuzzlePublicationStatus;
pub use puzzle_publish_input_type::PuzzlePublishInput;
pub use puzzle_run_drag_input_type::PuzzleRunDragInput;
pub use puzzle_run_get_input_type::PuzzleRunGetInput;
pub use puzzle_run_next_level_input_type::PuzzleRunNextLevelInput;
pub use puzzle_run_procedure_result_type::PuzzleRunProcedureResult;
pub use puzzle_run_start_input_type::PuzzleRunStartInput;
pub use puzzle_run_swap_input_type::PuzzleRunSwapInput;
pub use puzzle_runtime_run_row_type::PuzzleRuntimeRunRow;
pub use puzzle_select_cover_image_input_type::PuzzleSelectCoverImageInput;
pub use puzzle_work_get_input_type::PuzzleWorkGetInput;
pub use puzzle_work_procedure_result_type::PuzzleWorkProcedureResult;
pub use puzzle_work_profile_row_type::PuzzleWorkProfileRow;
pub use puzzle_work_upsert_input_type::PuzzleWorkUpsertInput;
pub use puzzle_works_list_input_type::PuzzleWorksListInput;
pub use puzzle_works_procedure_result_type::PuzzleWorksProcedureResult;
pub use quest_completion_ack_input_type::QuestCompletionAckInput;
pub use quest_hostile_npc_defeated_signal_type::QuestHostileNpcDefeatedSignal;
pub use quest_item_delivered_signal_type::QuestItemDeliveredSignal;
@@ -586,6 +744,10 @@ pub use ai_text_chunk_table::*;
pub use asset_entity_binding_table::*;
pub use asset_object_table::*;
pub use battle_state_table::*;
pub use big_fish_agent_message_table::*;
pub use big_fish_asset_slot_table::*;
pub use big_fish_creation_session_table::*;
pub use big_fish_runtime_run_table::*;
pub use chapter_progression_table::*;
pub use custom_world_agent_message_table::*;
pub use custom_world_agent_operation_table::*;
@@ -601,6 +763,10 @@ pub use profile_dashboard_state_table::*;
pub use profile_played_world_table::*;
pub use profile_save_archive_table::*;
pub use profile_wallet_ledger_table::*;
pub use puzzle_agent_message_table::*;
pub use puzzle_agent_session_table::*;
pub use puzzle_runtime_run_table::*;
pub use puzzle_work_profile_table::*;
pub use quest_log_table::*;
pub use quest_record_table::*;
pub use runtime_setting_table::*;
@@ -633,6 +799,7 @@ pub use unpublish_custom_world_profile_reducer::unpublish_custom_world_profile;
pub use upsert_chapter_progression_reducer::upsert_chapter_progression;
pub use upsert_custom_world_profile_reducer::upsert_custom_world_profile;
pub use upsert_npc_state_reducer::upsert_npc_state;
pub use advance_puzzle_next_level_procedure::advance_puzzle_next_level;
pub use append_ai_text_chunk_and_return_procedure::append_ai_text_chunk_and_return;
pub use apply_chapter_progression_ledger_entry_and_return_procedure::apply_chapter_progression_ledger_entry_and_return;
pub use attach_ai_result_reference_and_return_procedure::attach_ai_result_reference_and_return;
@@ -640,18 +807,26 @@ pub use begin_story_session_and_return_procedure::begin_story_session_and_return
pub use bind_asset_object_to_entity_and_return_procedure::bind_asset_object_to_entity_and_return;
pub use cancel_ai_task_and_return_procedure::cancel_ai_task_and_return;
pub use clear_platform_browse_history_and_return_procedure::clear_platform_browse_history_and_return;
pub use compile_big_fish_draft_procedure::compile_big_fish_draft;
pub use compile_custom_world_published_profile_procedure::compile_custom_world_published_profile;
pub use compile_puzzle_agent_draft_procedure::compile_puzzle_agent_draft;
pub use complete_ai_stage_and_return_procedure::complete_ai_stage_and_return;
pub use complete_ai_task_and_return_procedure::complete_ai_task_and_return;
pub use confirm_asset_object_and_return_procedure::confirm_asset_object_and_return;
pub use continue_story_and_return_procedure::continue_story_and_return;
pub use create_ai_task_and_return_procedure::create_ai_task_and_return;
pub use create_battle_state_and_return_procedure::create_battle_state_and_return;
pub use create_big_fish_session_procedure::create_big_fish_session;
pub use create_custom_world_agent_session_procedure::create_custom_world_agent_session;
pub use create_puzzle_agent_session_procedure::create_puzzle_agent_session;
pub use delete_runtime_snapshot_and_return_procedure::delete_runtime_snapshot_and_return;
pub use drag_puzzle_piece_or_group_procedure::drag_puzzle_piece_or_group;
pub use execute_custom_world_agent_action_procedure::execute_custom_world_agent_action;
pub use fail_ai_task_and_return_procedure::fail_ai_task_and_return;
pub use generate_big_fish_asset_procedure::generate_big_fish_asset;
pub use get_battle_state_procedure::get_battle_state;
pub use get_big_fish_run_procedure::get_big_fish_run;
pub use get_big_fish_session_procedure::get_big_fish_session;
pub use get_chapter_progression_procedure::get_chapter_progression;
pub use get_custom_world_agent_card_detail_procedure::get_custom_world_agent_card_detail;
pub use get_custom_world_agent_operation_procedure::get_custom_world_agent_operation;
@@ -661,6 +836,10 @@ pub use get_custom_world_library_detail_procedure::get_custom_world_library_deta
pub use get_player_progression_or_default_procedure::get_player_progression_or_default;
pub use get_profile_dashboard_procedure::get_profile_dashboard;
pub use get_profile_play_stats_procedure::get_profile_play_stats;
pub use get_puzzle_agent_session_procedure::get_puzzle_agent_session;
pub use get_puzzle_gallery_detail_procedure::get_puzzle_gallery_detail;
pub use get_puzzle_run_procedure::get_puzzle_run;
pub use get_puzzle_work_detail_procedure::get_puzzle_work_detail;
pub use get_runtime_inventory_state_procedure::get_runtime_inventory_state;
pub use get_runtime_setting_or_default_procedure::get_runtime_setting_or_default;
pub use get_runtime_snapshot_procedure::get_runtime_snapshot;
@@ -672,16 +851,29 @@ pub use list_custom_world_works_procedure::list_custom_world_works;
pub use list_platform_browse_history_procedure::list_platform_browse_history;
pub use list_profile_save_archives_procedure::list_profile_save_archives;
pub use list_profile_wallet_ledger_procedure::list_profile_wallet_ledger;
pub use list_puzzle_gallery_procedure::list_puzzle_gallery;
pub use list_puzzle_works_procedure::list_puzzle_works;
pub use publish_big_fish_game_procedure::publish_big_fish_game;
pub use publish_custom_world_profile_and_return_procedure::publish_custom_world_profile_and_return;
pub use publish_custom_world_world_procedure::publish_custom_world_world;
pub use publish_puzzle_work_procedure::publish_puzzle_work;
pub use resolve_combat_action_and_return_procedure::resolve_combat_action_and_return;
pub use resolve_npc_battle_interaction_and_return_procedure::resolve_npc_battle_interaction_and_return;
pub use resolve_npc_interaction_and_return_procedure::resolve_npc_interaction_and_return;
pub use resolve_npc_social_action_and_return_procedure::resolve_npc_social_action_and_return;
pub use resolve_treasure_interaction_and_return_procedure::resolve_treasure_interaction_and_return;
pub use resume_profile_save_archive_and_return_procedure::resume_profile_save_archive_and_return;
pub use save_puzzle_generated_images_procedure::save_puzzle_generated_images;
pub use select_puzzle_cover_image_procedure::select_puzzle_cover_image;
pub use start_big_fish_run_procedure::start_big_fish_run;
pub use start_puzzle_run_procedure::start_puzzle_run;
pub use submit_big_fish_input_procedure::submit_big_fish_input;
pub use submit_big_fish_message_procedure::submit_big_fish_message;
pub use submit_custom_world_agent_message_procedure::submit_custom_world_agent_message;
pub use submit_puzzle_agent_message_procedure::submit_puzzle_agent_message;
pub use swap_puzzle_pieces_procedure::swap_puzzle_pieces;
pub use unpublish_custom_world_profile_and_return_procedure::unpublish_custom_world_profile_and_return;
pub use update_puzzle_work_procedure::update_puzzle_work;
pub use upsert_chapter_progression_and_return_procedure::upsert_chapter_progression_and_return;
pub use upsert_custom_world_profile_and_return_procedure::upsert_custom_world_profile_and_return;
pub use upsert_npc_state_and_return_procedure::upsert_npc_state_and_return;
@@ -945,6 +1137,10 @@ pub struct DbUpdate {
asset_entity_binding: __sdk::TableUpdate<AssetEntityBinding>,
asset_object: __sdk::TableUpdate<AssetObject>,
battle_state: __sdk::TableUpdate<BattleState>,
big_fish_agent_message: __sdk::TableUpdate<BigFishAgentMessage>,
big_fish_asset_slot: __sdk::TableUpdate<BigFishAssetSlot>,
big_fish_creation_session: __sdk::TableUpdate<BigFishCreationSession>,
big_fish_runtime_run: __sdk::TableUpdate<BigFishRuntimeRun>,
chapter_progression: __sdk::TableUpdate<ChapterProgression>,
custom_world_agent_message: __sdk::TableUpdate<CustomWorldAgentMessage>,
custom_world_agent_operation: __sdk::TableUpdate<CustomWorldAgentOperation>,
@@ -960,6 +1156,10 @@ pub struct DbUpdate {
profile_played_world: __sdk::TableUpdate<ProfilePlayedWorld>,
profile_save_archive: __sdk::TableUpdate<ProfileSaveArchive>,
profile_wallet_ledger: __sdk::TableUpdate<ProfileWalletLedger>,
puzzle_agent_message: __sdk::TableUpdate<PuzzleAgentMessageRow>,
puzzle_agent_session: __sdk::TableUpdate<PuzzleAgentSessionRow>,
puzzle_runtime_run: __sdk::TableUpdate<PuzzleRuntimeRunRow>,
puzzle_work_profile: __sdk::TableUpdate<PuzzleWorkProfileRow>,
quest_log: __sdk::TableUpdate<QuestLog>,
quest_record: __sdk::TableUpdate<QuestRecord>,
runtime_setting: __sdk::TableUpdate<RuntimeSetting>,
@@ -985,6 +1185,10 @@ impl TryFrom<__ws::v2::TransactionUpdate> for DbUpdate {
"asset_entity_binding" => db_update.asset_entity_binding.append(asset_entity_binding_table::parse_table_update(table_update)?),
"asset_object" => db_update.asset_object.append(asset_object_table::parse_table_update(table_update)?),
"battle_state" => db_update.battle_state.append(battle_state_table::parse_table_update(table_update)?),
"big_fish_agent_message" => db_update.big_fish_agent_message.append(big_fish_agent_message_table::parse_table_update(table_update)?),
"big_fish_asset_slot" => db_update.big_fish_asset_slot.append(big_fish_asset_slot_table::parse_table_update(table_update)?),
"big_fish_creation_session" => db_update.big_fish_creation_session.append(big_fish_creation_session_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)?),
"chapter_progression" => db_update.chapter_progression.append(chapter_progression_table::parse_table_update(table_update)?),
"custom_world_agent_message" => db_update.custom_world_agent_message.append(custom_world_agent_message_table::parse_table_update(table_update)?),
"custom_world_agent_operation" => db_update.custom_world_agent_operation.append(custom_world_agent_operation_table::parse_table_update(table_update)?),
@@ -1000,6 +1204,10 @@ impl TryFrom<__ws::v2::TransactionUpdate> for DbUpdate {
"profile_played_world" => db_update.profile_played_world.append(profile_played_world_table::parse_table_update(table_update)?),
"profile_save_archive" => db_update.profile_save_archive.append(profile_save_archive_table::parse_table_update(table_update)?),
"profile_wallet_ledger" => db_update.profile_wallet_ledger.append(profile_wallet_ledger_table::parse_table_update(table_update)?),
"puzzle_agent_message" => db_update.puzzle_agent_message.append(puzzle_agent_message_table::parse_table_update(table_update)?),
"puzzle_agent_session" => db_update.puzzle_agent_session.append(puzzle_agent_session_table::parse_table_update(table_update)?),
"puzzle_runtime_run" => db_update.puzzle_runtime_run.append(puzzle_runtime_run_table::parse_table_update(table_update)?),
"puzzle_work_profile" => db_update.puzzle_work_profile.append(puzzle_work_profile_table::parse_table_update(table_update)?),
"quest_log" => db_update.quest_log.append(quest_log_table::parse_table_update(table_update)?),
"quest_record" => db_update.quest_record.append(quest_record_table::parse_table_update(table_update)?),
"runtime_setting" => db_update.runtime_setting.append(runtime_setting_table::parse_table_update(table_update)?),
@@ -1037,6 +1245,10 @@ impl __sdk::DbUpdate for DbUpdate {
diff.asset_entity_binding = cache.apply_diff_to_table::<AssetEntityBinding>("asset_entity_binding", &self.asset_entity_binding).with_updates_by_pk(|row| &row.binding_id);
diff.asset_object = cache.apply_diff_to_table::<AssetObject>("asset_object", &self.asset_object).with_updates_by_pk(|row| &row.asset_object_id);
diff.battle_state = cache.apply_diff_to_table::<BattleState>("battle_state", &self.battle_state).with_updates_by_pk(|row| &row.battle_state_id);
diff.big_fish_agent_message = cache.apply_diff_to_table::<BigFishAgentMessage>("big_fish_agent_message", &self.big_fish_agent_message).with_updates_by_pk(|row| &row.message_id);
diff.big_fish_asset_slot = cache.apply_diff_to_table::<BigFishAssetSlot>("big_fish_asset_slot", &self.big_fish_asset_slot).with_updates_by_pk(|row| &row.slot_id);
diff.big_fish_creation_session = cache.apply_diff_to_table::<BigFishCreationSession>("big_fish_creation_session", &self.big_fish_creation_session).with_updates_by_pk(|row| &row.session_id);
diff.big_fish_runtime_run = cache.apply_diff_to_table::<BigFishRuntimeRun>("big_fish_runtime_run", &self.big_fish_runtime_run).with_updates_by_pk(|row| &row.run_id);
diff.chapter_progression = cache.apply_diff_to_table::<ChapterProgression>("chapter_progression", &self.chapter_progression).with_updates_by_pk(|row| &row.chapter_progression_id);
diff.custom_world_agent_message = cache.apply_diff_to_table::<CustomWorldAgentMessage>("custom_world_agent_message", &self.custom_world_agent_message).with_updates_by_pk(|row| &row.message_id);
diff.custom_world_agent_operation = cache.apply_diff_to_table::<CustomWorldAgentOperation>("custom_world_agent_operation", &self.custom_world_agent_operation).with_updates_by_pk(|row| &row.operation_id);
@@ -1052,6 +1264,10 @@ impl __sdk::DbUpdate for DbUpdate {
diff.profile_played_world = cache.apply_diff_to_table::<ProfilePlayedWorld>("profile_played_world", &self.profile_played_world).with_updates_by_pk(|row| &row.played_world_id);
diff.profile_save_archive = cache.apply_diff_to_table::<ProfileSaveArchive>("profile_save_archive", &self.profile_save_archive).with_updates_by_pk(|row| &row.archive_id);
diff.profile_wallet_ledger = cache.apply_diff_to_table::<ProfileWalletLedger>("profile_wallet_ledger", &self.profile_wallet_ledger).with_updates_by_pk(|row| &row.wallet_ledger_id);
diff.puzzle_agent_message = cache.apply_diff_to_table::<PuzzleAgentMessageRow>("puzzle_agent_message", &self.puzzle_agent_message).with_updates_by_pk(|row| &row.message_id);
diff.puzzle_agent_session = cache.apply_diff_to_table::<PuzzleAgentSessionRow>("puzzle_agent_session", &self.puzzle_agent_session).with_updates_by_pk(|row| &row.session_id);
diff.puzzle_runtime_run = cache.apply_diff_to_table::<PuzzleRuntimeRunRow>("puzzle_runtime_run", &self.puzzle_runtime_run).with_updates_by_pk(|row| &row.run_id);
diff.puzzle_work_profile = cache.apply_diff_to_table::<PuzzleWorkProfileRow>("puzzle_work_profile", &self.puzzle_work_profile).with_updates_by_pk(|row| &row.profile_id);
diff.quest_log = cache.apply_diff_to_table::<QuestLog>("quest_log", &self.quest_log).with_updates_by_pk(|row| &row.log_id);
diff.quest_record = cache.apply_diff_to_table::<QuestRecord>("quest_record", &self.quest_record).with_updates_by_pk(|row| &row.quest_id);
diff.runtime_setting = cache.apply_diff_to_table::<RuntimeSetting>("runtime_setting", &self.runtime_setting).with_updates_by_pk(|row| &row.user_id);
@@ -1074,6 +1290,10 @@ for table_rows in raw.tables {
"asset_entity_binding" => db_update.asset_entity_binding.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
"asset_object" => db_update.asset_object.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
"battle_state" => db_update.battle_state.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
"big_fish_agent_message" => db_update.big_fish_agent_message.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
"big_fish_asset_slot" => db_update.big_fish_asset_slot.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
"big_fish_creation_session" => db_update.big_fish_creation_session.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)?),
"chapter_progression" => db_update.chapter_progression.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
"custom_world_agent_message" => db_update.custom_world_agent_message.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
"custom_world_agent_operation" => db_update.custom_world_agent_operation.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
@@ -1089,6 +1309,10 @@ for table_rows in raw.tables {
"profile_played_world" => db_update.profile_played_world.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
"profile_save_archive" => db_update.profile_save_archive.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
"profile_wallet_ledger" => db_update.profile_wallet_ledger.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
"puzzle_agent_message" => db_update.puzzle_agent_message.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
"puzzle_agent_session" => db_update.puzzle_agent_session.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
"puzzle_runtime_run" => db_update.puzzle_runtime_run.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
"puzzle_work_profile" => db_update.puzzle_work_profile.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
"quest_log" => db_update.quest_log.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
"quest_record" => db_update.quest_record.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
"runtime_setting" => db_update.runtime_setting.append(__sdk::parse_row_list_as_inserts(table_rows.rows)?),
@@ -1111,6 +1335,10 @@ for table_rows in raw.tables {
"asset_entity_binding" => db_update.asset_entity_binding.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
"asset_object" => db_update.asset_object.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
"battle_state" => db_update.battle_state.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
"big_fish_agent_message" => db_update.big_fish_agent_message.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
"big_fish_asset_slot" => db_update.big_fish_asset_slot.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
"big_fish_creation_session" => db_update.big_fish_creation_session.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)?),
"chapter_progression" => db_update.chapter_progression.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
"custom_world_agent_message" => db_update.custom_world_agent_message.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
"custom_world_agent_operation" => db_update.custom_world_agent_operation.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
@@ -1126,6 +1354,10 @@ for table_rows in raw.tables {
"profile_played_world" => db_update.profile_played_world.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
"profile_save_archive" => db_update.profile_save_archive.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
"profile_wallet_ledger" => db_update.profile_wallet_ledger.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
"puzzle_agent_message" => db_update.puzzle_agent_message.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
"puzzle_agent_session" => db_update.puzzle_agent_session.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
"puzzle_runtime_run" => db_update.puzzle_runtime_run.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
"puzzle_work_profile" => db_update.puzzle_work_profile.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
"quest_log" => db_update.quest_log.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
"quest_record" => db_update.quest_record.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
"runtime_setting" => db_update.runtime_setting.append(__sdk::parse_row_list_as_deletes(table_rows.rows)?),
@@ -1150,6 +1382,10 @@ pub struct AppliedDiff<'r> {
asset_entity_binding: __sdk::TableAppliedDiff<'r, AssetEntityBinding>,
asset_object: __sdk::TableAppliedDiff<'r, AssetObject>,
battle_state: __sdk::TableAppliedDiff<'r, BattleState>,
big_fish_agent_message: __sdk::TableAppliedDiff<'r, BigFishAgentMessage>,
big_fish_asset_slot: __sdk::TableAppliedDiff<'r, BigFishAssetSlot>,
big_fish_creation_session: __sdk::TableAppliedDiff<'r, BigFishCreationSession>,
big_fish_runtime_run: __sdk::TableAppliedDiff<'r, BigFishRuntimeRun>,
chapter_progression: __sdk::TableAppliedDiff<'r, ChapterProgression>,
custom_world_agent_message: __sdk::TableAppliedDiff<'r, CustomWorldAgentMessage>,
custom_world_agent_operation: __sdk::TableAppliedDiff<'r, CustomWorldAgentOperation>,
@@ -1165,6 +1401,10 @@ pub struct AppliedDiff<'r> {
profile_played_world: __sdk::TableAppliedDiff<'r, ProfilePlayedWorld>,
profile_save_archive: __sdk::TableAppliedDiff<'r, ProfileSaveArchive>,
profile_wallet_ledger: __sdk::TableAppliedDiff<'r, ProfileWalletLedger>,
puzzle_agent_message: __sdk::TableAppliedDiff<'r, PuzzleAgentMessageRow>,
puzzle_agent_session: __sdk::TableAppliedDiff<'r, PuzzleAgentSessionRow>,
puzzle_runtime_run: __sdk::TableAppliedDiff<'r, PuzzleRuntimeRunRow>,
puzzle_work_profile: __sdk::TableAppliedDiff<'r, PuzzleWorkProfileRow>,
quest_log: __sdk::TableAppliedDiff<'r, QuestLog>,
quest_record: __sdk::TableAppliedDiff<'r, QuestRecord>,
runtime_setting: __sdk::TableAppliedDiff<'r, RuntimeSetting>,
@@ -1190,6 +1430,10 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> {
callbacks.invoke_table_row_callbacks::<AssetEntityBinding>("asset_entity_binding", &self.asset_entity_binding, event);
callbacks.invoke_table_row_callbacks::<AssetObject>("asset_object", &self.asset_object, event);
callbacks.invoke_table_row_callbacks::<BattleState>("battle_state", &self.battle_state, event);
callbacks.invoke_table_row_callbacks::<BigFishAgentMessage>("big_fish_agent_message", &self.big_fish_agent_message, event);
callbacks.invoke_table_row_callbacks::<BigFishAssetSlot>("big_fish_asset_slot", &self.big_fish_asset_slot, event);
callbacks.invoke_table_row_callbacks::<BigFishCreationSession>("big_fish_creation_session", &self.big_fish_creation_session, event);
callbacks.invoke_table_row_callbacks::<BigFishRuntimeRun>("big_fish_runtime_run", &self.big_fish_runtime_run, event);
callbacks.invoke_table_row_callbacks::<ChapterProgression>("chapter_progression", &self.chapter_progression, event);
callbacks.invoke_table_row_callbacks::<CustomWorldAgentMessage>("custom_world_agent_message", &self.custom_world_agent_message, event);
callbacks.invoke_table_row_callbacks::<CustomWorldAgentOperation>("custom_world_agent_operation", &self.custom_world_agent_operation, event);
@@ -1205,6 +1449,10 @@ impl<'r> __sdk::AppliedDiff<'r> for AppliedDiff<'r> {
callbacks.invoke_table_row_callbacks::<ProfilePlayedWorld>("profile_played_world", &self.profile_played_world, event);
callbacks.invoke_table_row_callbacks::<ProfileSaveArchive>("profile_save_archive", &self.profile_save_archive, event);
callbacks.invoke_table_row_callbacks::<ProfileWalletLedger>("profile_wallet_ledger", &self.profile_wallet_ledger, event);
callbacks.invoke_table_row_callbacks::<PuzzleAgentMessageRow>("puzzle_agent_message", &self.puzzle_agent_message, event);
callbacks.invoke_table_row_callbacks::<PuzzleAgentSessionRow>("puzzle_agent_session", &self.puzzle_agent_session, event);
callbacks.invoke_table_row_callbacks::<PuzzleRuntimeRunRow>("puzzle_runtime_run", &self.puzzle_runtime_run, event);
callbacks.invoke_table_row_callbacks::<PuzzleWorkProfileRow>("puzzle_work_profile", &self.puzzle_work_profile, event);
callbacks.invoke_table_row_callbacks::<QuestLog>("quest_log", &self.quest_log, event);
callbacks.invoke_table_row_callbacks::<QuestRecord>("quest_record", &self.quest_record, event);
callbacks.invoke_table_row_callbacks::<RuntimeSetting>("runtime_setting", &self.runtime_setting, event);
@@ -1871,6 +2119,10 @@ fn register_tables(client_cache: &mut __sdk::ClientCache<Self>) {
asset_entity_binding_table::register_table(client_cache);
asset_object_table::register_table(client_cache);
battle_state_table::register_table(client_cache);
big_fish_agent_message_table::register_table(client_cache);
big_fish_asset_slot_table::register_table(client_cache);
big_fish_creation_session_table::register_table(client_cache);
big_fish_runtime_run_table::register_table(client_cache);
chapter_progression_table::register_table(client_cache);
custom_world_agent_message_table::register_table(client_cache);
custom_world_agent_operation_table::register_table(client_cache);
@@ -1886,6 +2138,10 @@ fn register_tables(client_cache: &mut __sdk::ClientCache<Self>) {
profile_played_world_table::register_table(client_cache);
profile_save_archive_table::register_table(client_cache);
profile_wallet_ledger_table::register_table(client_cache);
puzzle_agent_message_table::register_table(client_cache);
puzzle_agent_session_table::register_table(client_cache);
puzzle_runtime_run_table::register_table(client_cache);
puzzle_work_profile_table::register_table(client_cache);
quest_log_table::register_table(client_cache);
quest_record_table::register_table(client_cache);
runtime_setting_table::register_table(client_cache);
@@ -1903,6 +2159,10 @@ const ALL_TABLE_NAMES: &'static [&'static str] = &[
"asset_entity_binding",
"asset_object",
"battle_state",
"big_fish_agent_message",
"big_fish_asset_slot",
"big_fish_creation_session",
"big_fish_runtime_run",
"chapter_progression",
"custom_world_agent_message",
"custom_world_agent_operation",
@@ -1918,6 +2178,10 @@ const ALL_TABLE_NAMES: &'static [&'static str] = &[
"profile_played_world",
"profile_save_archive",
"profile_wallet_ledger",
"puzzle_agent_message",
"puzzle_agent_session",
"puzzle_runtime_run",
"puzzle_work_profile",
"quest_log",
"quest_record",
"runtime_setting",

View File

@@ -0,0 +1,58 @@
// 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::big_fish_session_procedure_result_type::BigFishSessionProcedureResult;
use super::big_fish_publish_input_type::BigFishPublishInput;
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
#[sats(crate = __lib)]
struct PublishBigFishGameArgs {
pub input: BigFishPublishInput,
}
impl __sdk::InModule for PublishBigFishGameArgs {
type Module = super::RemoteModule;
}
#[allow(non_camel_case_types)]
/// Extension trait for access to the procedure `publish_big_fish_game`.
///
/// Implemented for [`super::RemoteProcedures`].
pub trait publish_big_fish_game {
fn publish_big_fish_game(&self, input: BigFishPublishInput,
) {
self.publish_big_fish_game_then(input, |_, _| {});
}
fn publish_big_fish_game_then(
&self,
input: BigFishPublishInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<BigFishSessionProcedureResult, __sdk::InternalError>) + Send + 'static,
);
}
impl publish_big_fish_game for super::RemoteProcedures {
fn publish_big_fish_game_then(
&self,
input: BigFishPublishInput,
__callback: impl FnOnce(&super::ProcedureEventContext, Result<BigFishSessionProcedureResult, __sdk::InternalError>) + Send + 'static,
) {
self.imp.invoke_procedure_with_callback::<_, BigFishSessionProcedureResult>(
"publish_big_fish_game",
PublishBigFishGameArgs { input, },
__callback,
);
}
}

Some files were not shown because too many files have changed in this diff Show More