Preserve partial creation replies on stream failure
Some checks failed
CI / verify (push) Has been cancelled
Some checks failed
CI / verify (push) Has been cancelled
This commit is contained in:
@@ -1,4 +0,0 @@
|
||||
interface:
|
||||
display_name: "新增玩法入口"
|
||||
short_description: "把新增玩法入口的文档、配置、路由和验证流程一次收口"
|
||||
default_prompt: "Use $genarrative-gameplay-entry-type to add a new gameplay entry type end to end in Genarrative."
|
||||
@@ -13,12 +13,14 @@
|
||||
重点补充:RPG 创作与运行时脚本职责地图见 [RPG_CREATION_AND_RUNTIME_SCRIPT_RESPONSIBILITY_MAP_2026-04-28.md](./reference/RPG_CREATION_AND_RUNTIME_SCRIPT_RESPONSIBILITY_MAP_2026-04-28.md)。
|
||||
- [埋点查询](./tracking/README.md):埋点原始事件与聚合投影的本地 SQL 查询。
|
||||
- [运营查询](./operations/README.md):任务、领奖、钱包对账等后台核查查询。
|
||||
- [PRD](./prd):产品需求与阶段计划;后台管理独立前端工程见 [ADMIN_WEB_CONSOLE_PRD_2026-04-30.md](./prd/ADMIN_WEB_CONSOLE_PRD_2026-04-30.md),新增 RPG 开场动画方案见 [AI_NATIVE_RPG_OPENING_ANIMATION_PRD_2026-04-25.md](./prd/AI_NATIVE_RPG_OPENING_ANIMATION_PRD_2026-04-25.md),新增抓大鹅 Match3D 玩法方案见 [AI_NATIVE_MATCH3D_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-04-30.md](./prd/AI_NATIVE_MATCH3D_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-04-30.md)。
|
||||
- [PRD](./prd):产品需求与阶段计划;后台管理独立前端工程见 [ADMIN_WEB_CONSOLE_PRD_2026-04-30.md](./prd/ADMIN_WEB_CONSOLE_PRD_2026-04-30.md),新增 RPG 开场动画方案见 [AI_NATIVE_RPG_OPENING_ANIMATION_PRD_2026-04-25.md](./prd/AI_NATIVE_RPG_OPENING_ANIMATION_PRD_2026-04-25.md),新增抓大鹅 Match3D 玩法方案见 [AI_NATIVE_MATCH3D_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-04-30.md](./prd/AI_NATIVE_MATCH3D_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-04-30.md),方洞挑战创作、发布与试玩闭环见 [AI_NATIVE_SQUARE_HOLE_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-05-04.md](./prd/AI_NATIVE_SQUARE_HOLE_CREATOR_AND_GAMEPLAY_SYSTEM_PRD_2026-05-04.md)。
|
||||
|
||||
生产部署切换到 systemd + Nginx + SpacetimeDB 自托管的总方案见 [PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md](./technical/PRODUCTION_DEPLOYMENT_PLAN_2026-05-02.md),该文档也是当前生产 Jenkinsfile 的唯一入口。SpacetimeDB 表结构变更、自动迁移边界和保留旧数据的分阶段迁移流程见 [SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md](./technical/SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md);private 表迁移 JSON 导入导出、HTTP 413 分片导入和旧数据库迁移流水线经验见 [SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md](./technical/SPACETIMEDB_JSON_STRING_MIGRATION_PROCEDURE_2026-04-27.md) 与 [JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md](./technical/JENKINS_SPACETIMEDB_DATABASE_MIGRATION_PIPELINES_2026-04-29.md);后台管理独立前端工程技术方案见 [ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md](./technical/ADMIN_WEB_CONSOLE_TECHNICAL_SOLUTION_2026-04-30.md)。
|
||||
|
||||
SpacetimeDB 表结构变更、自动迁移边界和保留旧数据的分阶段迁移流程见 [SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md](./technical/SPACETIMEDB_SCHEMA_CHANGE_CONSTRAINTS.md)。
|
||||
|
||||
创作 Agent 问答流式失败时保留已显示回复、并透出更具体上游错误的契约见 [CREATION_AGENT_STREAM_FAILURE_RETENTION_FIX_2026-05-05.md](./technical/CREATION_AGENT_STREAM_FAILURE_RETENTION_FIX_2026-05-05.md)。
|
||||
|
||||
## 推荐阅读顺序
|
||||
|
||||
1. 先看 [经验沉淀](./experience/README.md),快速建立这个项目的开发共识。
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
# AI 原生方洞挑战玩法创作工具与玩法系统 PRD
|
||||
|
||||
更新时间:`2026-05-04`
|
||||
|
||||
## 0. 文档目的
|
||||
|
||||
这份 PRD 用于在当前平台内新增一条“方洞挑战”玩法类型,并先冻结它从入口占位到完整可创建闭环的产品边界。
|
||||
|
||||
本玩法来自参考视频中的核心反差:玩家看到不同形状的积木与多个洞口,会本能判断“形状应放入对应洞口”,但演示不断把不同形状都放进同一个方洞,形成“规则预期被打破”的喜剧张力。
|
||||
|
||||
本次不是简单复制视频内容,也不是只新增一个前端小游戏。正式版本需要把这种反直觉机制抽象成平台内可创作、可试玩、可发布的玩法类型。
|
||||
|
||||
---
|
||||
|
||||
## 1. 一句话定义
|
||||
|
||||
“方洞挑战”是一个反直觉形状分拣玩法:百梦主通过 Agent 设定形状主题、洞口规则、误导节奏和反差演出,系统生成一个移动端优先的单局挑战;玩家在限时内把连续出现的形状投入正确洞口,后端根据当前关卡的真实兼容规则裁决成功、失败和连击。
|
||||
|
||||
---
|
||||
|
||||
## 2. 当前接入级别
|
||||
|
||||
根据 `genarrative-play-type-integration` 的接入分级,本次落地到 **完整玩法闭环**:
|
||||
|
||||
1. 新增玩法 ID:`square-hole`。
|
||||
2. 新增展示名称:`方洞挑战`。
|
||||
3. 新增子标题:`反直觉形状分拣`。
|
||||
4. 在新建作品入口、创作类型弹层、结果页、运行态和作品架展示。
|
||||
5. 支持 Agent 创作、草稿生成、结果页编辑、试玩、发布和公开运行。
|
||||
6. 后端以 `server-rs + Axum + SpacetimeDB` 为真相源,前端只渲染快照与交互。
|
||||
|
||||
不允许把运行规则临时写成前端本地真相,也不复用 `server-node`、Express 或 PostgreSQL。
|
||||
|
||||
---
|
||||
|
||||
## 3. 产品定位
|
||||
|
||||
## 3.1 模板名称
|
||||
|
||||
1. 对外模板名称:`方洞挑战`。
|
||||
2. 对外子标题:`反直觉形状分拣`。
|
||||
3. 开发代号:`SquareHole`。
|
||||
4. 工程玩法域:`square-hole`。
|
||||
5. 后端模块命名预期:`square_hole`。
|
||||
|
||||
## 3.2 核心乐趣
|
||||
|
||||
1. 玩家先根据形状轮廓做直觉判断。
|
||||
2. 关卡通过洞口、提示、视觉遮挡和演出制造误导。
|
||||
3. 真实规则可以是“方洞万能”“指定洞口万能”“颜色优先于形状”“本轮只看尺寸”等反直觉规则。
|
||||
4. 玩家通过连续试探和反馈理解规则,形成短局重复挑战。
|
||||
|
||||
## 3.3 与现有玩法的区别
|
||||
|
||||
1. 不等同于拼图:不切图、不交换、不合并拼块。
|
||||
2. 不等同于抓大鹅:不做三消备选栏,不做堆叠遮挡点击。
|
||||
3. 不等同于大鱼吃小鱼:不做摇杆移动、吞噬、成长等级。
|
||||
4. 不复用 RPG 的世界、角色、章节或剧情推进结构。
|
||||
5. 运行态只保留“当前形状 + 洞口选择 + 后端裁决”,不在前端写正式规则真相。
|
||||
|
||||
---
|
||||
|
||||
## 4. 完整闭环目标
|
||||
|
||||
本次完整闭环必须补齐:
|
||||
|
||||
1. 平台创作入口选择“方洞挑战”。
|
||||
2. Agent 对话收集玩法锚点。
|
||||
3. 生成方洞挑战草稿。
|
||||
4. 进入结果页编辑作品名、标签、封面、形状数量、反差规则和视觉主题。
|
||||
5. 支持发布前试玩。
|
||||
6. 发布作品。
|
||||
7. 玩家从作品详情或广场进入运行态。
|
||||
8. 后端初始化单局形状队列、洞口兼容规则和计分状态。
|
||||
9. 玩家拖拽或点击形状投入洞口。
|
||||
10. 后端裁决投入结果、连击、扣时、失败、胜利和成绩。
|
||||
11. 前端只渲染后端快照与即时反馈,不承接正式规则真相。
|
||||
|
||||
---
|
||||
|
||||
## 5. 创作锚点设计
|
||||
|
||||
Agent 型创作版本至少收集下面 5 个锚点:
|
||||
|
||||
| 锚点 | 字段建议 | 用途 |
|
||||
| --- | --- | --- |
|
||||
| 主题外观 | `themePrompt` | 决定玩具、洞板、背景、形状材质和色彩风格。 |
|
||||
| 反差规则 | `twistRule` | 决定“为什么不是按形状匹配”的真实判定规则。 |
|
||||
| 洞口组 | `holeSet` | 决定本局出现的洞口种类、数量、位置和视觉误导强度。 |
|
||||
| 形状队列 | `shapeSequence` | 决定连续出现的形状、颜色、大小和难度递增。 |
|
||||
| 反馈节奏 | `feedbackRhythm` | 决定成功、错误、连击、惊讶和结算演出风格。 |
|
||||
|
||||
Agent 需要把玩家一句灵感收束为上述锚点,不允许逐项盘问低价值字段。
|
||||
|
||||
## 5.1 Agent AI 生成契约
|
||||
|
||||
方洞挑战的创作对话必须接入 `api-server` 的现有 LLM 能力,不能把用户输入解析成固定模板后直接写回会话。工程实现以 `state.llm_client()` 为唯一模型入口,通过方洞专属 Agent turn 生成回复与下一轮配置。
|
||||
|
||||
单轮模型输出必须是严格 JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"replyText": "",
|
||||
"progressPercent": 0,
|
||||
"nextConfig": {
|
||||
"themeText": "",
|
||||
"twistRule": "",
|
||||
"shapeCount": 12,
|
||||
"difficulty": 4
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
落地约束:
|
||||
|
||||
1. `replyText` 是直接展示给百梦主的中文回复,不得出现 JSON、字段名、内部结构等说明。
|
||||
2. `nextConfig` 必须是完整配置,不允许只输出 patch;缺失字段只能由后端用当前会话配置兜底。
|
||||
3. `shapeCount` 由后端限制在 `6` 到 `24`,`difficulty` 限制在 `1` 到 `10`。
|
||||
4. `quickFillRequested=true` 时,模型应直接补齐剩余配置,后端把 `progressPercent` 固定为 `100`。
|
||||
5. 模型不可用或结果无法解析时,接口返回明确错误,不允许用确定性模板伪装成 AI 回复。
|
||||
6. 非流式消息接口和 SSE 流式消息接口都必须走同一套方洞 Agent turn,SSE 只额外负责把 `replyText` 增量回传。
|
||||
|
||||
---
|
||||
|
||||
## 6. 运行规则设计
|
||||
|
||||
## 6.1 单局结构
|
||||
|
||||
1. 单局默认 `60` 秒。
|
||||
2. 每局默认 `12` 个形状。
|
||||
3. 洞口数量默认 `4` 到 `6` 个。
|
||||
4. 玩家每次只能操作当前形状。
|
||||
5. 正确投入后进入下一个形状。
|
||||
6. 错误投入扣除时间或清空连击。
|
||||
7. 全部形状完成即胜利。
|
||||
8. 时间归零即失败。
|
||||
|
||||
## 6.2 真实兼容规则
|
||||
|
||||
首版可支持下面几类规则:
|
||||
|
||||
1. `shape_match`:形状轮廓匹配。
|
||||
2. `square_hole_priority`:方洞兼容所有形状,其他洞口只作为误导。
|
||||
3. `color_match`:颜色优先于形状。
|
||||
4. `size_match`:尺寸优先于形状。
|
||||
5. `round_prompt`:本轮按后端给出的短提示规则判定。
|
||||
|
||||
其中 `square_hole_priority` 是参考视频核心反差的首选默认规则。
|
||||
|
||||
## 6.3 前端表现
|
||||
|
||||
1. 竖屏优先,桌面端居中显示游戏台。
|
||||
2. 当前形状位于屏幕下半区域,洞板位于上半区域。
|
||||
3. 只显示必要状态:剩余时间、连击、当前进度。
|
||||
4. 不默认展示长篇规则说明。
|
||||
5. 错误反馈用短促动画、颜色闪烁和轻量文字状态,不堆解释。
|
||||
6. 点击按钮弹出的配置或结算必须使用独立面板,不在当前面板下方展开。
|
||||
|
||||
---
|
||||
|
||||
## 7. 后端分层边界
|
||||
|
||||
完整实现时必须遵循当前 `server-rs + Axum + SpacetimeDB` 路线:
|
||||
|
||||
1. `server-rs/crates/module-square-hole`
|
||||
- 纯领域规则、形状队列生成、兼容性裁决、分数计算。
|
||||
- 不依赖 Axum、SpacetimeDB、OSS 或 LLM。
|
||||
2. `server-rs/crates/shared-contracts`
|
||||
- 暴露 Agent、作品、运行态 DTO。
|
||||
3. `server-rs/crates/spacetime-module`
|
||||
- 存储 session、message、work profile、runtime run。
|
||||
- 表结构变化必须同步 `migration.rs` 与表目录。
|
||||
4. `server-rs/crates/spacetime-client`
|
||||
- 提供 api-server 调用 SpacetimeDB 的 typed facade。
|
||||
5. `server-rs/crates/api-server`
|
||||
- 暴露 `/api/creation/square-hole/*` 与 `/api/runtime/square-hole/*`。
|
||||
- 处理鉴权、错误 envelope、LLM turn 和 HTTP facade。
|
||||
|
||||
---
|
||||
|
||||
## 8. 数据模型
|
||||
|
||||
## 8.1 创作 session
|
||||
|
||||
1. `sessionId`
|
||||
2. `ownerUserId`
|
||||
3. `currentTurn`
|
||||
4. `progressPercent`
|
||||
5. `stage`
|
||||
6. `config`
|
||||
7. `draft`
|
||||
8. `messages`
|
||||
9. `lastAssistantReply`
|
||||
10. `publishedProfileId`
|
||||
|
||||
## 8.2 结果页 work profile
|
||||
|
||||
1. `workId`
|
||||
2. `profileId`
|
||||
3. `ownerUserId`
|
||||
4. `sourceSessionId`
|
||||
5. `gameName`
|
||||
6. `themeText`
|
||||
7. `twistRule`
|
||||
8. `summary`
|
||||
9. `tags`
|
||||
10. `coverImageSrc`
|
||||
11. `shapeCount`
|
||||
12. `difficulty`
|
||||
13. `publicationStatus`
|
||||
14. `playCount`
|
||||
15. `updatedAt`
|
||||
16. `publishedAt`
|
||||
|
||||
## 8.3 运行态 run snapshot
|
||||
|
||||
1. `runId`
|
||||
2. `profileId`
|
||||
3. `ownerUserId`
|
||||
4. `status`
|
||||
5. `snapshotVersion`
|
||||
6. `startedAtMs`
|
||||
7. `durationLimitMs`
|
||||
8. `remainingMs`
|
||||
9. `totalShapeCount`
|
||||
10. `completedShapeCount`
|
||||
11. `combo`
|
||||
12. `bestCombo`
|
||||
13. `score`
|
||||
14. `ruleLabel`
|
||||
15. `currentShape`
|
||||
16. `holes`
|
||||
17. `lastFeedback`
|
||||
|
||||
---
|
||||
|
||||
## 9. API 设计
|
||||
|
||||
## 9.1 创作接口
|
||||
|
||||
1. `POST /api/creation/square-hole/sessions`
|
||||
2. `GET /api/creation/square-hole/sessions/{sessionId}`
|
||||
3. `POST /api/creation/square-hole/sessions/{sessionId}/messages`
|
||||
4. `POST /api/creation/square-hole/sessions/{sessionId}/messages/stream`
|
||||
5. `POST /api/creation/square-hole/sessions/{sessionId}/actions`
|
||||
6. `POST /api/creation/square-hole/sessions/{sessionId}/compile`
|
||||
7. `GET /api/creation/square-hole/works`
|
||||
8. `GET /api/creation/square-hole/works/{profileId}`
|
||||
9. `PUT /api/creation/square-hole/works/{profileId}`
|
||||
10. `POST /api/creation/square-hole/works/{profileId}/publish`
|
||||
11. `DELETE /api/creation/square-hole/works/{profileId}`
|
||||
|
||||
## 9.2 运行接口
|
||||
|
||||
1. `GET /api/runtime/square-hole/gallery`
|
||||
2. `GET /api/runtime/square-hole/gallery/{profileId}`
|
||||
3. `POST /api/runtime/square-hole/works/{profileId}/runs`
|
||||
4. `GET /api/runtime/square-hole/runs/{runId}`
|
||||
5. `POST /api/runtime/square-hole/runs/{runId}/drop`
|
||||
6. `POST /api/runtime/square-hole/runs/{runId}/stop`
|
||||
7. `POST /api/runtime/square-hole/runs/{runId}/restart`
|
||||
8. `POST /api/runtime/square-hole/runs/{runId}/time-up`
|
||||
|
||||
---
|
||||
|
||||
## 10. 验收标准
|
||||
|
||||
1. `src/config/newWorkEntryConfig.ts` 中存在 `square-hole` 类型且开放创建。
|
||||
2. 新建作品入口和创作类型弹层能展示“方洞挑战”。
|
||||
3. 能进入 `square-hole` Agent 工作台。
|
||||
4. 能生成草稿并进入结果页。
|
||||
5. 能编辑结果页并保存、发布。
|
||||
6. 能从作品详情或广场进入运行态。
|
||||
7. 能点击或拖拽当前形状投入洞口。
|
||||
8. 后端裁决命中规则、连击、失败和胜利。
|
||||
9. 刷新后可恢复作品与运行态快照。
|
||||
10. `docs/technical/NEW_WORK_ENTRY_CONFIG_2026-05-01.md` 记录该入口开放状态。
|
||||
11. 后端改动完成后必须执行 `npm run api-server:maincloud`,以 `GET /healthz` 返回 `200` 作为主云配置启动 smoke 通过标准,并在 smoke 后清理本次启动进程。
|
||||
@@ -0,0 +1,53 @@
|
||||
# 创作 Agent 流式失败保留可见回复修复 2026-05-05
|
||||
|
||||
## 1. 问题
|
||||
|
||||
方洞挑战等轻量玩法复用 `usePlatformCreationAgentFlowController` 与 `creationAgentSse.ts` 消费 `reply_delta / session / error`。当上游 LLM 已经返回部分 `replyText`,但后续因为超时、上游断流、SSE 解析或最终 JSON 解析失败而发送 `error` 事件时,前端会在 `finally` 里退出流式态。
|
||||
|
||||
旧 UI 只在 `isStreamingReply=true` 时展示临时 assistant 气泡,因此用户会先看到一段回答,然后回答突然消失,只剩错误提示。
|
||||
|
||||
## 2. 目标
|
||||
|
||||
1. 已经展示给用户的流式回复不能因为最终失败从聊天区消失。
|
||||
2. SSE `error` 仍然终止本轮提交,并保留错误提示。
|
||||
3. 后端错误不能只压成 `上游服务请求失败`,应优先把 LLM 流错误原因放到业务 `message`。
|
||||
4. 不修改 SpacetimeDB schema、消息表结构或玩法运行规则。
|
||||
|
||||
## 3. 前端契约
|
||||
|
||||
`readCreationAgentSessionFromSse()` 在收到 `reply_delta` 后再收到 `error` 时,必须先触发 `onUpdate(text)`,再抛出错误。调用方可以从最近一次可见文本中恢复 UI。
|
||||
|
||||
`usePlatformCreationAgentFlowController.submitMessage()` 的失败收尾规则:
|
||||
|
||||
1. 提交时仍先追加 optimistic user message。
|
||||
2. 每次 `onUpdate` 同步更新 `streamingReplyText` 与最近可见回复引用。
|
||||
3. 如果 `streamMessage()` 抛错且最近可见回复非空,把该文本追加为本地 assistant `warning` 消息。
|
||||
4. 再设置 `error`,最后关闭 `isStreamingReply`。
|
||||
5. 成功拿到最终 session 时,以后端 session snapshot 为准,并清空最近可见回复。
|
||||
|
||||
这条本地 `warning` 消息只用于失败态 UI 保留,不代表该 assistant 消息已经写入 SpacetimeDB。
|
||||
|
||||
## 4. 后端契约
|
||||
|
||||
`creation_agent_llm_turn` 在 `LlmClient::stream_text()` 失败时,返回:
|
||||
|
||||
```text
|
||||
<玩法 generation_failed 文案>:<LlmError Display>
|
||||
```
|
||||
|
||||
同时写 `warn` 日志,便于结合 `logs/llm-raw` 定位上游原始输入输出。
|
||||
|
||||
方洞挑战 SSE 错误提取优先级:
|
||||
|
||||
1. `error.details.message`
|
||||
2. `error.message`
|
||||
3. 其它嵌套 JSON message
|
||||
4. 原始 body 文本
|
||||
5. 状态码兜底
|
||||
|
||||
## 5. 验收
|
||||
|
||||
1. `reply_delta` 后收到 `error` 时,测试应断言 `onUpdate` 已经收到可见文本。
|
||||
2. 控制器测试应断言失败后本地消息列表包含 user 消息和 assistant warning 消息。
|
||||
3. `cargo check -p api-server` 通过。
|
||||
4. `npm run typecheck` 与编码检查通过。
|
||||
@@ -22,6 +22,7 @@
|
||||
| 大鱼吃小鱼 | 否 | 是 | 功能仍保留,不在新建作品入口展示 |
|
||||
| 拼图 | 是 | 是 | 点击后进入拼图 Agent 共创工作台 |
|
||||
| 抓大鹅 | 是 | 是 | 点击后进入抓大鹅 Agent 共创工作台 |
|
||||
| 方洞挑战 | 是 | 是 | 点击后进入方洞挑战 Agent 共创工作台,支持草稿、结果页、发布、试玩、作品架与广场 |
|
||||
| AIRP | 是 | 否 | 保留入口,显示敬请期待 |
|
||||
| 视觉小说 | 是 | 否 | 保留入口,显示敬请期待 |
|
||||
|
||||
@@ -31,3 +32,4 @@
|
||||
2. 隐藏玩法不触发入口预加载,也不出现在新建作品入口中。
|
||||
3. 未开放玩法点击态保持禁用,不应进入鉴权或创建会话链路。
|
||||
4. 已开放玩法点击后必须进入对应创建链路;若用户未登录,先走登录保护。
|
||||
5. 方洞挑战作品发布后应生成 `SH-` 作品号,并能从作品架、广场详情和试玩 runtime 回到同一作品详情。
|
||||
|
||||
@@ -29,6 +29,7 @@ spacetime sql <db> "SELECT * FROM custom_world_gallery_entry"
|
||||
| 世界创作 | `custom_world_profile`, `custom_world_session`, `custom_world_agent_session`, `custom_world_agent_message`, `custom_world_agent_operation`, `custom_world_draft_card`, `custom_world_gallery_entry` |
|
||||
| 拼图 | `puzzle_agent_session`, `puzzle_agent_message`, `puzzle_work_profile`, `puzzle_event`, `puzzle_runtime_run`, `puzzle_leaderboard_entry` |
|
||||
| 抓大鹅 Match3D | `match3d_agent_session`, `match3d_agent_message`, `match3d_work_profile`, `match3d_runtime_run` |
|
||||
| 方洞挑战 | `square_hole_agent_session`, `square_hole_agent_message`, `square_hole_work_profile`, `square_hole_runtime_run` |
|
||||
| 大鱼吃小鱼 | `big_fish_creation_session`, `big_fish_agent_message`, `big_fish_asset_slot`, `big_fish_event`, `big_fish_runtime_run` |
|
||||
| 资产 | `asset_object`, `asset_entity_binding`, `asset_event` |
|
||||
| AI 任务 | `ai_task`, `ai_task_stage`, `ai_text_chunk`, `ai_result_reference`, `ai_task_event` |
|
||||
@@ -669,6 +670,53 @@ SELECT * FROM match3d_runtime_run WHERE owner_user_id = '<user_id>' ORDER BY upd
|
||||
SELECT * FROM match3d_runtime_run WHERE profile_id = '<profile_id>';
|
||||
```
|
||||
|
||||
## 方洞挑战表
|
||||
|
||||
### `square_hole_agent_session`
|
||||
|
||||
- 作用:方洞挑战创作 Agent 会话表,保存种子、配置 JSON、草稿 JSON 和发布 profile 指针。
|
||||
- 结构:`session_id PK: String`, `owner_user_id: String`, `seed_text: String`, `current_turn: u32`, `progress_percent: u32`, `stage: String`, `config_json: String`, `draft_json: String`, `last_assistant_reply: String`, `published_profile_id: String`, `created_at: Timestamp`, `updated_at: Timestamp`。
|
||||
- 索引:`owner_user_id`。
|
||||
|
||||
```sql
|
||||
SELECT * FROM square_hole_agent_session WHERE session_id = '<session_id>';
|
||||
SELECT * FROM square_hole_agent_session WHERE owner_user_id = '<user_id>' ORDER BY updated_at DESC;
|
||||
```
|
||||
|
||||
### `square_hole_agent_message`
|
||||
|
||||
- 作用:方洞挑战创作 Agent 消息流水。
|
||||
- 结构:`message_id PK: String`, `session_id: String`, `role: String`, `kind: String`, `text: String`, `created_at: Timestamp`。
|
||||
- 索引:`session_id`。
|
||||
|
||||
```sql
|
||||
SELECT * FROM square_hole_agent_message WHERE session_id = '<session_id>' ORDER BY created_at ASC;
|
||||
```
|
||||
|
||||
### `square_hole_work_profile`
|
||||
|
||||
- 作用:方洞挑战作品主表,保存作品基础信息、反直觉规则、配置、发布状态和游玩次数。
|
||||
- 结构:`profile_id PK: String`, `work_id: String`, `owner_user_id: String`, `source_session_id: String`, `author_display_name: String`, `game_name: String`, `theme_text: String`, `twist_rule: String`, `summary_text: String`, `tags_json: String`, `cover_image_src: String`, `shape_count: u32`, `difficulty: u32`, `config_json: String`, `publication_status: String`, `play_count: u32`, `updated_at: Timestamp`, `published_at: Option<Timestamp>`。
|
||||
- 索引:`owner_user_id`, `publication_status`。
|
||||
|
||||
```sql
|
||||
SELECT * FROM square_hole_work_profile WHERE profile_id = '<profile_id>';
|
||||
SELECT * FROM square_hole_work_profile WHERE owner_user_id = '<user_id>' ORDER BY updated_at DESC;
|
||||
SELECT * FROM square_hole_work_profile WHERE publication_status = 'Published';
|
||||
```
|
||||
|
||||
### `square_hole_runtime_run`
|
||||
|
||||
- 作用:方洞挑战单局运行态表,保存后端权威快照、快照版本、胜负状态和成绩基础字段。
|
||||
- 结构:`run_id PK: String`, `owner_user_id: String`, `profile_id: String`, `status: String`, `snapshot_version: u64`, `started_at_ms: i64`, `duration_limit_ms: i64`, `finished_at_ms: i64`, `elapsed_ms: i64`, `total_shape_count: u32`, `completed_shape_count: u32`, `score: u32`, `snapshot_json: String`, `created_at: Timestamp`, `updated_at: Timestamp`。
|
||||
- 索引:`owner_user_id`, `profile_id`。
|
||||
|
||||
```sql
|
||||
SELECT * FROM square_hole_runtime_run WHERE run_id = '<run_id>';
|
||||
SELECT * FROM square_hole_runtime_run WHERE owner_user_id = '<user_id>' ORDER BY updated_at DESC;
|
||||
SELECT * FROM square_hole_runtime_run WHERE profile_id = '<profile_id>';
|
||||
```
|
||||
|
||||
## 大鱼吃小鱼表
|
||||
|
||||
### `big_fish_creation_session`
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
"admin-web:preview": "npm --prefix apps/admin-web run preview --",
|
||||
"spacetime:generate": "node scripts/generate-spacetime-bindings.mjs",
|
||||
"api-server": "node scripts/api-server-dev.mjs",
|
||||
"api-server:maincloud": "node scripts/api-server-maincloud.mjs",
|
||||
"deploy:rust:remote": "node scripts/run-bash-script.mjs scripts/deploy-rust-remote.sh",
|
||||
"build:production-release": "node scripts/run-bash-script.mjs scripts/build-production-release.sh",
|
||||
"build:rust:ubuntu": "node scripts/run-bash-script.mjs scripts/deploy-rust-remote.sh",
|
||||
|
||||
100
packages/shared/src/contracts/squareHoleAgent.ts
Normal file
100
packages/shared/src/contracts/squareHoleAgent.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* 方洞挑战创作 Agent 共享契约。
|
||||
* 字段按 HTTP facade 的 camelCase DTO 命名,后端领域层 snake_case 字段由 facade 映射。
|
||||
*/
|
||||
export type SquareHoleCreationStage =
|
||||
| 'collecting_config'
|
||||
| 'draft_ready'
|
||||
| string;
|
||||
|
||||
export type SquareHoleAnchorStatus =
|
||||
| 'confirmed'
|
||||
| 'missing'
|
||||
| 'inferred'
|
||||
| string;
|
||||
|
||||
export interface CreateSquareHoleSessionRequest {
|
||||
seedText?: string;
|
||||
themeText?: string;
|
||||
twistRule?: string;
|
||||
shapeCount?: number;
|
||||
difficulty?: number;
|
||||
}
|
||||
|
||||
export interface SendSquareHoleMessageRequest {
|
||||
clientMessageId: string;
|
||||
text: string;
|
||||
quickFillRequested?: boolean;
|
||||
}
|
||||
|
||||
export interface ExecuteSquareHoleActionRequest {
|
||||
action: string;
|
||||
gameName?: string;
|
||||
summary?: string;
|
||||
tags?: string[];
|
||||
coverImageSrc?: string | null;
|
||||
}
|
||||
|
||||
export interface SquareHoleAnchorItemResponse {
|
||||
key: string;
|
||||
label: string;
|
||||
value: string;
|
||||
status: SquareHoleAnchorStatus;
|
||||
}
|
||||
|
||||
export interface SquareHoleAnchorPackResponse {
|
||||
theme: SquareHoleAnchorItemResponse;
|
||||
twistRule: SquareHoleAnchorItemResponse;
|
||||
shapeCount: SquareHoleAnchorItemResponse;
|
||||
difficulty: SquareHoleAnchorItemResponse;
|
||||
}
|
||||
|
||||
export interface SquareHoleCreatorConfig {
|
||||
themeText: string;
|
||||
twistRule: string;
|
||||
shapeCount: number;
|
||||
difficulty: number;
|
||||
}
|
||||
|
||||
export interface SquareHoleResultDraft {
|
||||
profileId: string;
|
||||
gameName: string;
|
||||
themeText: string;
|
||||
twistRule: string;
|
||||
summary: string;
|
||||
tags: string[];
|
||||
shapeCount: number;
|
||||
difficulty: number;
|
||||
publishReady: boolean;
|
||||
blockers: string[];
|
||||
}
|
||||
|
||||
export interface SquareHoleAgentMessage {
|
||||
id: string;
|
||||
role: 'user' | 'assistant' | 'system' | string;
|
||||
kind: 'chat' | 'summary' | 'action_result' | 'warning' | string;
|
||||
text: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface SquareHoleSessionSnapshot {
|
||||
sessionId: string;
|
||||
currentTurn: number;
|
||||
progressPercent: number;
|
||||
stage: SquareHoleCreationStage;
|
||||
anchorPack: SquareHoleAnchorPackResponse;
|
||||
config: SquareHoleCreatorConfig;
|
||||
draft?: SquareHoleResultDraft | null;
|
||||
messages: SquareHoleAgentMessage[];
|
||||
lastAssistantReply?: string | null;
|
||||
publishedProfileId?: string | null;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface SquareHoleSessionResponse {
|
||||
session: SquareHoleSessionSnapshot;
|
||||
}
|
||||
|
||||
export interface SquareHoleActionResponse {
|
||||
session: SquareHoleSessionSnapshot;
|
||||
}
|
||||
99
packages/shared/src/contracts/squareHoleRuntime.ts
Normal file
99
packages/shared/src/contracts/squareHoleRuntime.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* 方洞挑战运行态共享契约。
|
||||
* 后端负责当前形状、洞口兼容、胜负和连击真相;前端只提交洞口选择并渲染快照。
|
||||
*/
|
||||
export type SquareHoleRunStatus =
|
||||
| 'running'
|
||||
| 'won'
|
||||
| 'failed'
|
||||
| 'stopped'
|
||||
| string;
|
||||
export type SquareHoleShapeKind =
|
||||
| 'square'
|
||||
| 'circle'
|
||||
| 'triangle'
|
||||
| 'star'
|
||||
| 'arch'
|
||||
| 'diamond'
|
||||
| string;
|
||||
export type SquareHoleHoleKind =
|
||||
| 'square'
|
||||
| 'circle'
|
||||
| 'triangle'
|
||||
| 'star'
|
||||
| 'arch'
|
||||
| 'diamond'
|
||||
| string;
|
||||
export type SquareHoleDropRejectReason =
|
||||
| 'run_not_active'
|
||||
| 'snapshot_version_mismatch'
|
||||
| 'hole_not_found'
|
||||
| 'incompatible'
|
||||
| 'time_up'
|
||||
| string;
|
||||
|
||||
export interface SquareHoleShapeSnapshot {
|
||||
shapeId: string;
|
||||
shapeKind: SquareHoleShapeKind;
|
||||
label: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
export interface SquareHoleHoleSnapshot {
|
||||
holeId: string;
|
||||
holeKind: SquareHoleHoleKind;
|
||||
label: string;
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export interface SquareHoleRunSnapshot {
|
||||
runId: string;
|
||||
profileId: string;
|
||||
ownerUserId: string;
|
||||
status: SquareHoleRunStatus;
|
||||
snapshotVersion: number;
|
||||
startedAtMs: number;
|
||||
durationLimitMs: number;
|
||||
remainingMs: number;
|
||||
totalShapeCount: number;
|
||||
completedShapeCount: number;
|
||||
combo: number;
|
||||
bestCombo: number;
|
||||
score: number;
|
||||
ruleLabel: string;
|
||||
currentShape?: SquareHoleShapeSnapshot | null;
|
||||
holes: SquareHoleHoleSnapshot[];
|
||||
lastFeedback?: SquareHoleDropFeedback | null;
|
||||
}
|
||||
|
||||
export interface StartSquareHoleRunRequest {
|
||||
profileId: string;
|
||||
}
|
||||
|
||||
export interface DropSquareHoleShapeRequest {
|
||||
runId?: string;
|
||||
holeId: string;
|
||||
clientSnapshotVersion: number;
|
||||
clientEventId: string;
|
||||
droppedAtMs: number;
|
||||
}
|
||||
|
||||
export interface StopSquareHoleRunRequest {
|
||||
clientActionId: string;
|
||||
}
|
||||
|
||||
export interface SquareHoleDropFeedback {
|
||||
accepted: boolean;
|
||||
rejectReason?: SquareHoleDropRejectReason | null;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface SquareHoleDropResponse {
|
||||
feedback: SquareHoleDropFeedback;
|
||||
run: SquareHoleRunSnapshot;
|
||||
}
|
||||
|
||||
export interface SquareHoleRunResponse {
|
||||
run: SquareHoleRunSnapshot;
|
||||
}
|
||||
50
packages/shared/src/contracts/squareHoleWorks.ts
Normal file
50
packages/shared/src/contracts/squareHoleWorks.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 方洞挑战作品读写共享契约。
|
||||
* 作品字段只表达结果页可编辑信息;运行规则真相由后端 runtime 快照负责。
|
||||
*/
|
||||
export type SquareHoleWorkPublicationStatus = 'draft' | 'published' | string;
|
||||
|
||||
export interface PutSquareHoleWorkRequest {
|
||||
gameName: string;
|
||||
themeText?: string;
|
||||
twistRule: string;
|
||||
summary: string;
|
||||
tags: string[];
|
||||
coverImageSrc?: string | null;
|
||||
shapeCount: number;
|
||||
difficulty: number;
|
||||
}
|
||||
|
||||
export interface SquareHoleWorkSummary {
|
||||
workId: string;
|
||||
profileId: string;
|
||||
ownerUserId: string;
|
||||
sourceSessionId?: string | null;
|
||||
gameName: string;
|
||||
themeText: string;
|
||||
twistRule: string;
|
||||
summary: string;
|
||||
tags: string[];
|
||||
coverImageSrc?: string | null;
|
||||
shapeCount: number;
|
||||
difficulty: number;
|
||||
publicationStatus: SquareHoleWorkPublicationStatus;
|
||||
playCount: number;
|
||||
updatedAt: string;
|
||||
publishedAt?: string | null;
|
||||
publishReady: boolean;
|
||||
}
|
||||
|
||||
export interface SquareHoleWorkProfile extends SquareHoleWorkSummary {}
|
||||
|
||||
export interface SquareHoleWorksResponse {
|
||||
items: SquareHoleWorkSummary[];
|
||||
}
|
||||
|
||||
export interface SquareHoleWorkDetailResponse {
|
||||
item: SquareHoleWorkProfile;
|
||||
}
|
||||
|
||||
export interface SquareHoleWorkMutationResponse {
|
||||
item: SquareHoleWorkProfile;
|
||||
}
|
||||
@@ -13,6 +13,9 @@ export * from './contracts/puzzleAgentSession';
|
||||
export * from './contracts/puzzleResultPreview';
|
||||
export * from './contracts/puzzleRuntimeSession';
|
||||
export * from './contracts/puzzleWorkSummary';
|
||||
export * from './contracts/squareHoleAgent';
|
||||
export * from './contracts/squareHoleRuntime';
|
||||
export * from './contracts/squareHoleWorks';
|
||||
export * from './contracts/rpgAgentActions';
|
||||
export * from './contracts/rpgAgentAnchors';
|
||||
export * from './contracts/rpgAgentDraft';
|
||||
|
||||
220
scripts/api-server-maincloud.mjs
Normal file
220
scripts/api-server-maincloud.mjs
Normal file
@@ -0,0 +1,220 @@
|
||||
import { execFileSync, spawn } from 'node:child_process';
|
||||
import { existsSync, readFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
import { setTimeout as delay } from 'node:timers/promises';
|
||||
|
||||
const repoRoot = process.cwd();
|
||||
const apiServerExePath = resolve(
|
||||
repoRoot,
|
||||
'server-rs/target/debug/api-server.exe',
|
||||
);
|
||||
const defaultHealthHost = '127.0.0.1';
|
||||
const defaultHealthPort = '3100';
|
||||
const healthTimeoutMs =
|
||||
Number(process.env.GENARRATIVE_API_SERVER_MAINCLOUD_SMOKE_TIMEOUT_SECONDS) *
|
||||
1000 || 180_000;
|
||||
|
||||
function loadEnvFile(path, target) {
|
||||
if (!existsSync(path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rawText = readFileSync(path, 'utf8');
|
||||
for (const rawLine of rawText.split(/\r?\n/u)) {
|
||||
const line = rawLine.trim();
|
||||
if (!line || line.startsWith('#')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const match = line.match(/^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/u);
|
||||
if (!match) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const [, key, rawValue] = match;
|
||||
if (target[key] !== undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
target[key] = rawValue.replace(/^['"]|['"]$/gu, '');
|
||||
}
|
||||
}
|
||||
|
||||
function stopExistingWindowsApiServer() {
|
||||
if (process.platform !== 'win32') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Windows 下 cargo 重编译不能覆盖正在运行的 exe,只清理本仓库 target 内的 api-server。
|
||||
const command = [
|
||||
'$ErrorActionPreference = "Continue"',
|
||||
'$target = [System.IO.Path]::GetFullPath($env:GENARRATIVE_API_SERVER_EXE_TARGET)',
|
||||
'$processes = Get-Process -Name api-server -ErrorAction SilentlyContinue | Where-Object {',
|
||||
' $_.Path -and ([System.IO.Path]::GetFullPath($_.Path) -ieq $target)',
|
||||
'}',
|
||||
'foreach ($process in $processes) {',
|
||||
' try {',
|
||||
' Stop-Process -Id $process.Id -Force -ErrorAction Stop',
|
||||
' Wait-Process -Id $process.Id -Timeout 5 -ErrorAction SilentlyContinue',
|
||||
' Write-Output $process.Id',
|
||||
' } catch {',
|
||||
' Write-Error "[api-server:maincloud] 忽略旧进程清理瞬时失败 pid=$($process.Id): $($_.Exception.Message)"',
|
||||
' }',
|
||||
'}',
|
||||
'exit 0',
|
||||
].join('\n');
|
||||
|
||||
const output = execFileSync(
|
||||
'powershell.exe',
|
||||
['-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', command],
|
||||
{
|
||||
encoding: 'utf8',
|
||||
env: {
|
||||
...process.env,
|
||||
GENARRATIVE_API_SERVER_EXE_TARGET: apiServerExePath,
|
||||
},
|
||||
},
|
||||
).trim();
|
||||
|
||||
if (output) {
|
||||
console.log(`[api-server:maincloud] 已停止旧 api-server 进程: ${output}`);
|
||||
}
|
||||
}
|
||||
|
||||
function stopProcessTree(child) {
|
||||
if (!child || child.exitCode !== null || child.signalCode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
try {
|
||||
execFileSync('taskkill.exe', ['/PID', String(child.pid), '/T', '/F'], {
|
||||
stdio: 'ignore',
|
||||
});
|
||||
return;
|
||||
} catch {
|
||||
// taskkill 可能已经被进程自然退出抢先;继续走兜底清理。
|
||||
}
|
||||
}
|
||||
|
||||
child.kill('SIGTERM');
|
||||
}
|
||||
|
||||
async function waitForHealthz({ child, healthUrl }) {
|
||||
const deadline = Date.now() + healthTimeoutMs;
|
||||
let childExit = null;
|
||||
child.once('exit', (code, signal) => {
|
||||
childExit = { code, signal };
|
||||
});
|
||||
|
||||
while (Date.now() < deadline) {
|
||||
if (childExit) {
|
||||
throw new Error(
|
||||
`api-server 在 healthz 就绪前退出:code=${childExit.code ?? ''} signal=${
|
||||
childExit.signal ?? ''
|
||||
}`,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(healthUrl, {
|
||||
signal: AbortSignal.timeout(1_000),
|
||||
});
|
||||
const body = await response.text();
|
||||
if (response.status === 200) {
|
||||
return body;
|
||||
}
|
||||
} catch {
|
||||
// 服务启动期间连接失败是预期状态,继续轮询。
|
||||
}
|
||||
|
||||
await delay(500);
|
||||
}
|
||||
|
||||
throw new Error(`等待 /healthz 超时:${healthUrl}`);
|
||||
}
|
||||
|
||||
const mergedEnv = { ...process.env };
|
||||
loadEnvFile(resolve(repoRoot, '.env'), mergedEnv);
|
||||
loadEnvFile(resolve(repoRoot, '.env.local'), mergedEnv);
|
||||
loadEnvFile(resolve(repoRoot, '.env.secrets.local'), mergedEnv);
|
||||
|
||||
mergedEnv.GENARRATIVE_API_HOST =
|
||||
mergedEnv.GENARRATIVE_API_HOST || defaultHealthHost;
|
||||
mergedEnv.GENARRATIVE_API_PORT =
|
||||
mergedEnv.GENARRATIVE_API_PORT || defaultHealthPort;
|
||||
mergedEnv.GENARRATIVE_SPACETIME_SERVER_URL =
|
||||
mergedEnv.GENARRATIVE_SPACETIME_MAINCLOUD_SERVER_URL ||
|
||||
mergedEnv.GENARRATIVE_SPACETIME_SERVER_URL ||
|
||||
'https://maincloud.spacetimedb.com';
|
||||
mergedEnv.GENARRATIVE_SPACETIME_DATABASE =
|
||||
mergedEnv.GENARRATIVE_SPACETIME_MAINCLOUD_DATABASE ||
|
||||
mergedEnv.GENARRATIVE_SPACETIME_DATABASE ||
|
||||
'';
|
||||
mergedEnv.GENARRATIVE_SPACETIME_TOKEN =
|
||||
mergedEnv.GENARRATIVE_SPACETIME_MAINCLOUD_TOKEN ||
|
||||
mergedEnv.GENARRATIVE_SPACETIME_TOKEN ||
|
||||
'';
|
||||
|
||||
if (!mergedEnv.GENARRATIVE_SPACETIME_DATABASE) {
|
||||
console.error(
|
||||
'[api-server:maincloud] 缺少 GENARRATIVE_SPACETIME_MAINCLOUD_DATABASE 或 GENARRATIVE_SPACETIME_DATABASE。',
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
stopExistingWindowsApiServer();
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`[api-server:maincloud] 清理旧 api-server 进程失败: ${error.message}`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(
|
||||
`[api-server:maincloud] SpacetimeDB ${mergedEnv.GENARRATIVE_SPACETIME_DATABASE} @ ${mergedEnv.GENARRATIVE_SPACETIME_SERVER_URL}`,
|
||||
);
|
||||
|
||||
const child = spawn(
|
||||
'cargo',
|
||||
['run', '-p', 'api-server', '--manifest-path', 'server-rs/Cargo.toml'],
|
||||
{
|
||||
cwd: repoRoot,
|
||||
env: mergedEnv,
|
||||
stdio: 'inherit',
|
||||
},
|
||||
);
|
||||
|
||||
const cleanup = () => {
|
||||
stopProcessTree(child);
|
||||
try {
|
||||
stopExistingWindowsApiServer();
|
||||
} catch {
|
||||
// 退出阶段只做 best-effort 清理,不能覆盖真实 smoke 结果。
|
||||
}
|
||||
};
|
||||
|
||||
process.once('SIGINT', () => {
|
||||
cleanup();
|
||||
process.exit(130);
|
||||
});
|
||||
process.once('SIGTERM', () => {
|
||||
cleanup();
|
||||
process.exit(143);
|
||||
});
|
||||
|
||||
try {
|
||||
const healthHost =
|
||||
mergedEnv.GENARRATIVE_API_HOST === '0.0.0.0'
|
||||
? defaultHealthHost
|
||||
: mergedEnv.GENARRATIVE_API_HOST;
|
||||
const healthUrl = `http://${healthHost}:${mergedEnv.GENARRATIVE_API_PORT}/healthz`;
|
||||
const body = await waitForHealthz({ child, healthUrl });
|
||||
console.log(`[api-server:maincloud] /healthz 通过:${body}`);
|
||||
cleanup();
|
||||
} catch (error) {
|
||||
console.error(`[api-server:maincloud] smoke 失败:${error.message}`);
|
||||
cleanup();
|
||||
process.exit(1);
|
||||
}
|
||||
12
server-rs/Cargo.lock
generated
12
server-rs/Cargo.lock
generated
@@ -90,6 +90,7 @@ dependencies = [
|
||||
"module-runtime",
|
||||
"module-runtime-item",
|
||||
"module-runtime-story",
|
||||
"module-square-hole",
|
||||
"module-story",
|
||||
"platform-auth",
|
||||
"platform-llm",
|
||||
@@ -1639,6 +1640,15 @@ dependencies = [
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "module-square-hole"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"shared-kernel",
|
||||
"spacetimedb",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "module-story"
|
||||
version = "0.1.0"
|
||||
@@ -2681,6 +2691,7 @@ dependencies = [
|
||||
"module-runtime",
|
||||
"module-runtime-item",
|
||||
"module-runtime-story",
|
||||
"module-square-hole",
|
||||
"module-story",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -2708,6 +2719,7 @@ dependencies = [
|
||||
"module-quest",
|
||||
"module-runtime",
|
||||
"module-runtime-item",
|
||||
"module-square-hole",
|
||||
"module-story",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
||||
@@ -23,6 +23,7 @@ members = [
|
||||
"crates/module-runtime",
|
||||
"crates/module-runtime-story",
|
||||
"crates/module-runtime-item",
|
||||
"crates/module-square-hole",
|
||||
"crates/module-story",
|
||||
"crates/platform-oss",
|
||||
"crates/platform-auth",
|
||||
|
||||
@@ -25,6 +25,7 @@ module-puzzle = { path = "../module-puzzle" }
|
||||
module-runtime = { path = "../module-runtime" }
|
||||
module-runtime-story = { path = "../module-runtime-story" }
|
||||
module-runtime-item = { path = "../module-runtime-item" }
|
||||
module-square-hole = { path = "../module-square-hole" }
|
||||
module-story = { path = "../module-story" }
|
||||
platform-auth = { path = "../platform-auth" }
|
||||
platform-llm = { path = "../platform-llm" }
|
||||
|
||||
@@ -119,6 +119,14 @@ use crate::{
|
||||
put_runtime_snapshot, resume_profile_save_archive,
|
||||
},
|
||||
runtime_settings::{get_runtime_settings, put_runtime_settings},
|
||||
square_hole::{
|
||||
compile_square_hole_agent_draft, create_square_hole_agent_session, delete_square_hole_work,
|
||||
drop_square_hole_shape, execute_square_hole_agent_action, finish_square_hole_time_up,
|
||||
get_square_hole_agent_session, get_square_hole_run, get_square_hole_work_detail,
|
||||
get_square_hole_works, list_square_hole_gallery, publish_square_hole_work,
|
||||
put_square_hole_work, restart_square_hole_run, start_square_hole_run, stop_square_hole_run,
|
||||
stream_square_hole_agent_message, submit_square_hole_agent_message,
|
||||
},
|
||||
state::AppState,
|
||||
story_battles::{
|
||||
create_story_battle, create_story_npc_battle, get_story_battle_state, resolve_story_battle,
|
||||
@@ -829,6 +837,119 @@ pub fn build_router(state: AppState) -> Router {
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/square-hole/sessions",
|
||||
post(create_square_hole_agent_session).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/square-hole/sessions/{session_id}",
|
||||
get(get_square_hole_agent_session).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/square-hole/sessions/{session_id}/messages",
|
||||
post(submit_square_hole_agent_message).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/square-hole/sessions/{session_id}/messages/stream",
|
||||
post(stream_square_hole_agent_message).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/square-hole/sessions/{session_id}/actions",
|
||||
post(execute_square_hole_agent_action).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/square-hole/sessions/{session_id}/compile",
|
||||
post(compile_square_hole_agent_draft).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/square-hole/works",
|
||||
get(get_square_hole_works).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/square-hole/works/{profile_id}",
|
||||
get(get_square_hole_work_detail)
|
||||
.patch(put_square_hole_work)
|
||||
.put(put_square_hole_work)
|
||||
.delete(delete_square_hole_work)
|
||||
.route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/creation/square-hole/works/{profile_id}/publish",
|
||||
post(publish_square_hole_work).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/square-hole/gallery",
|
||||
get(list_square_hole_gallery),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/square-hole/works/{profile_id}/runs",
|
||||
post(start_square_hole_run).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/square-hole/runs/{run_id}",
|
||||
get(get_square_hole_run).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/square-hole/runs/{run_id}/drop",
|
||||
post(drop_square_hole_shape).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/square-hole/runs/{run_id}/stop",
|
||||
post(stop_square_hole_run).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/square-hole/runs/{run_id}/restart",
|
||||
post(restart_square_hole_run).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/square-hole/runs/{run_id}/time-up",
|
||||
post(finish_square_hole_time_up).route_layer(middleware::from_fn_with_state(
|
||||
state.clone(),
|
||||
require_bearer_auth,
|
||||
)),
|
||||
)
|
||||
.route(
|
||||
"/api/runtime/puzzle/agent/sessions",
|
||||
post(create_puzzle_agent_session)
|
||||
|
||||
@@ -64,8 +64,12 @@ where
|
||||
};
|
||||
|
||||
turn_output.map_err(|error| match error {
|
||||
CreationAgentJsonTurnFailure::Stream(_) => {
|
||||
build_error(messages.generation_failed.to_string())
|
||||
CreationAgentJsonTurnFailure::Stream(error) => {
|
||||
tracing::warn!(
|
||||
error = %error,
|
||||
"创作 Agent 流式 LLM 请求失败"
|
||||
);
|
||||
build_error(format!("{}:{error}", messages.generation_failed))
|
||||
}
|
||||
CreationAgentJsonTurnFailure::Parse => build_error(messages.parse_failed.to_string()),
|
||||
})
|
||||
|
||||
@@ -61,6 +61,8 @@ mod runtime_profile;
|
||||
mod runtime_save;
|
||||
mod runtime_settings;
|
||||
mod session_client;
|
||||
mod square_hole;
|
||||
mod square_hole_agent_turn;
|
||||
mod state;
|
||||
mod story_battles;
|
||||
mod story_sessions;
|
||||
|
||||
@@ -4,6 +4,7 @@ pub(crate) mod character_visual;
|
||||
pub(crate) mod puzzle;
|
||||
pub(crate) mod rpg;
|
||||
pub(crate) mod scene_background;
|
||||
pub(crate) mod square_hole;
|
||||
|
||||
pub(crate) use rpg::agent_chat;
|
||||
pub(crate) use rpg::foundation_draft;
|
||||
|
||||
164
server-rs/crates/api-server/src/prompt/square_hole.rs
Normal file
164
server-rs/crates/api-server/src/prompt/square_hole.rs
Normal file
@@ -0,0 +1,164 @@
|
||||
use serde_json::{Value as JsonValue, json};
|
||||
use spacetime_client::{SquareHoleAgentMessageRecord, SquareHoleAgentSessionRecord};
|
||||
|
||||
use crate::creation_agent_chat::render_quick_fill_extra_rules;
|
||||
|
||||
/// 方洞挑战共创 Agent 的系统提示词。
|
||||
///
|
||||
/// 这里只定义模型职责与输出约束,具体的模型调用、解析和写库由方洞 Agent turn 负责。
|
||||
pub(crate) const SQUARE_HOLE_AGENT_SYSTEM_PROMPT: &str = r#"你是一个负责和百梦主共创“方洞挑战”竖屏玩法的中文创意策划。
|
||||
|
||||
你要把用户灵感收束成一个反直觉形状分拣小游戏:玩家会本能把形状投入对应洞口,但真实规则可能让所有形状都优先进入方洞,形成类似参考视频“所有东西都进方洞”的喜剧反差。
|
||||
|
||||
你必须同时输出:
|
||||
1. 一段直接发给用户的中文回复 replyText
|
||||
2. 当前进度 progressPercent
|
||||
3. 下一轮完整可用的 nextConfig
|
||||
|
||||
硬约束:
|
||||
1. 只能输出 JSON,不能输出代码块或解释
|
||||
2. nextConfig 必须是完整对象,不能只输出 patch
|
||||
3. replyText 必须是自然中文,不能提“字段”“结构”“JSON”“后端”等内部词
|
||||
4. replyText 一次最多推进一个最关键问题
|
||||
5. 如果用户要求自动配置,就直接补齐可发布草稿需要的题材、反差规则、形状数量和难度,不要继续提问
|
||||
6. 默认核心反差优先使用“方洞万能”或“方洞优先”,但可以根据用户题材包装成更有记忆点的规则
|
||||
7. progressPercent 范围只能是 0 到 100
|
||||
8. shapeCount 只能是 6 到 24 的整数,difficulty 只能是 1 到 10 的整数
|
||||
"#;
|
||||
|
||||
const SQUARE_HOLE_AGENT_OUTPUT_CONTRACT: &str = r#"请严格按以下 JSON 输出,不要输出其他文字:
|
||||
{
|
||||
"replyText": "",
|
||||
"progressPercent": 0,
|
||||
"nextConfig": {
|
||||
"themeText": "",
|
||||
"twistRule": "",
|
||||
"shapeCount": 12,
|
||||
"difficulty": 4
|
||||
}
|
||||
}"#;
|
||||
|
||||
pub(crate) const SQUARE_HOLE_AGENT_JSON_TURN_USER_PROMPT: &str = "请按约定输出这一轮的 JSON。";
|
||||
|
||||
/// 方洞挑战草稿生成对话提示词脚本。
|
||||
///
|
||||
/// 方洞首版只需要四个可写回 SpacetimeDB 的配置项,因此提示词直接围绕配置收束,
|
||||
/// 不在模型输出层引入额外锚点,避免和当前持久化 schema 产生漂移。
|
||||
pub(crate) fn build_square_hole_agent_prompt(
|
||||
session: &SquareHoleAgentSessionRecord,
|
||||
quick_fill_requested: bool,
|
||||
) -> String {
|
||||
let quick_fill_rules = if quick_fill_requested {
|
||||
format!(
|
||||
"\n\n{}",
|
||||
render_quick_fill_extra_rules(
|
||||
"当前方洞挑战方向里的题材、反差规则、形状数量和难度",
|
||||
"不要要求用户再提供洞口、形状、演出或难度信息",
|
||||
"输出完整 nextConfig,直接补齐空缺或仍过于泛化的项",
|
||||
"生成结果页",
|
||||
)
|
||||
)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
format!(
|
||||
"模板目标:收束成可试玩、可发布的方洞挑战玩法草稿。{quick_fill_rules}\n\n当前是第 {turn} 轮,当前进度 {progress}% 。\n\n是否要求自动配置:{quick_fill_requested_text}\n\n当前配置:\n{current_config}\n\n最近聊天记录:\n{chat_history}\n\n收束要求:\n1. themeText 描述本局的玩具、道具或场景题材,保持短句。\n2. twistRule 描述真实判定规则,优先体现方洞优先或类似反直觉逻辑。\n3. shapeCount 决定单局形状数量,移动端短局建议 8 到 16。\n4. difficulty 决定误导强度和节奏,建议 3 到 7。\n5. 用户给出明确方向时优先吸收并推进,不要机械问完四个问题。\n\n{contract}",
|
||||
quick_fill_rules = quick_fill_rules,
|
||||
turn = session.current_turn.saturating_add(1),
|
||||
progress = session.progress_percent,
|
||||
quick_fill_requested_text = if quick_fill_requested { "是" } else { "否" },
|
||||
current_config = serialize_square_hole_session_config(session),
|
||||
chat_history =
|
||||
serde_json::to_string_pretty(&build_chat_history(session.messages.as_slice()))
|
||||
.unwrap_or_else(|_| "[]".to_string()),
|
||||
contract = SQUARE_HOLE_AGENT_OUTPUT_CONTRACT,
|
||||
)
|
||||
}
|
||||
|
||||
fn serialize_square_hole_session_config(session: &SquareHoleAgentSessionRecord) -> String {
|
||||
serde_json::to_string_pretty(&json!({
|
||||
"themeText": session.config.theme_text,
|
||||
"twistRule": session.config.twist_rule,
|
||||
"shapeCount": session.config.shape_count,
|
||||
"difficulty": session.config.difficulty,
|
||||
}))
|
||||
.unwrap_or_else(|_| "{}".to_string())
|
||||
}
|
||||
|
||||
fn build_chat_history(messages: &[SquareHoleAgentMessageRecord]) -> Vec<JsonValue> {
|
||||
messages
|
||||
.iter()
|
||||
.map(|message| {
|
||||
json!({
|
||||
"role": message.role,
|
||||
"kind": message.kind,
|
||||
"content": message.text,
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::build_square_hole_agent_prompt;
|
||||
|
||||
fn message(role: &str, text: &str) -> spacetime_client::SquareHoleAgentMessageRecord {
|
||||
spacetime_client::SquareHoleAgentMessageRecord {
|
||||
id: format!("message-{role}"),
|
||||
role: role.to_string(),
|
||||
kind: "chat".to_string(),
|
||||
text: text.to_string(),
|
||||
created_at: "2026-05-04T10:00:00.000Z".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn session_record() -> spacetime_client::SquareHoleAgentSessionRecord {
|
||||
spacetime_client::SquareHoleAgentSessionRecord {
|
||||
session_id: "square-hole-session-test".to_string(),
|
||||
current_turn: 1,
|
||||
progress_percent: 25,
|
||||
stage: "collecting_config".to_string(),
|
||||
anchor_pack: spacetime_client::SquareHoleAnchorPackRecord {
|
||||
theme: anchor("theme", "题材主题", "积木纸箱"),
|
||||
twist_rule: anchor("twistRule", "反差规则", ""),
|
||||
shape_count: anchor("shapeCount", "形状数量", "12"),
|
||||
difficulty: anchor("difficulty", "难度", "4"),
|
||||
},
|
||||
config: spacetime_client::SquareHoleCreatorConfigRecord {
|
||||
theme_text: "积木纸箱".to_string(),
|
||||
twist_rule: "方洞万能".to_string(),
|
||||
shape_count: 12,
|
||||
difficulty: 4,
|
||||
},
|
||||
draft: None,
|
||||
messages: vec![message("user", "做成办公室文具版")],
|
||||
last_assistant_reply: Some("这次可以从办公室文具题材开始。".to_string()),
|
||||
published_profile_id: None,
|
||||
updated_at: "2026-05-04T10:00:00.000Z".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn anchor(key: &str, label: &str, value: &str) -> spacetime_client::SquareHoleAnchorItemRecord {
|
||||
spacetime_client::SquareHoleAnchorItemRecord {
|
||||
key: key.to_string(),
|
||||
label: label.to_string(),
|
||||
value: value.to_string(),
|
||||
status: if value.is_empty() {
|
||||
"missing"
|
||||
} else {
|
||||
"confirmed"
|
||||
}
|
||||
.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn quick_fill_prompt_requires_complete_config() {
|
||||
let prompt = build_square_hole_agent_prompt(&session_record(), true);
|
||||
|
||||
assert!(prompt.contains("用户刚刚主动要求你自动补充剩余关键字"));
|
||||
assert!(prompt.contains("不要再继续提问"));
|
||||
assert!(prompt.contains("nextConfig"));
|
||||
assert!(prompt.contains("progressPercent 直接输出为 100"));
|
||||
}
|
||||
}
|
||||
1481
server-rs/crates/api-server/src/square_hole.rs
Normal file
1481
server-rs/crates/api-server/src/square_hole.rs
Normal file
File diff suppressed because it is too large
Load Diff
307
server-rs/crates/api-server/src/square_hole_agent_turn.rs
Normal file
307
server-rs/crates/api-server/src/square_hole_agent_turn.rs
Normal file
@@ -0,0 +1,307 @@
|
||||
use module_square_hole::{
|
||||
SQUARE_HOLE_MAX_DIFFICULTY, SQUARE_HOLE_MAX_SHAPE_COUNT, SQUARE_HOLE_MIN_DIFFICULTY,
|
||||
SQUARE_HOLE_MIN_SHAPE_COUNT,
|
||||
};
|
||||
use platform_llm::LlmClient;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
use spacetime_client::{SquareHoleAgentMessageFinalizeRecordInput, SquareHoleAgentSessionRecord};
|
||||
|
||||
use crate::creation_agent_llm_turn::{
|
||||
CreationAgentLlmTurnErrorMessages, stream_creation_agent_json_turn,
|
||||
};
|
||||
use crate::prompt::square_hole::{
|
||||
SQUARE_HOLE_AGENT_JSON_TURN_USER_PROMPT, SQUARE_HOLE_AGENT_SYSTEM_PROMPT,
|
||||
build_square_hole_agent_prompt,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct SquareHoleAgentTurnRequest<'a> {
|
||||
pub llm_client: Option<&'a LlmClient>,
|
||||
pub session: &'a SquareHoleAgentSessionRecord,
|
||||
pub quick_fill_requested: bool,
|
||||
pub enable_web_search: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct SquareHoleAgentTurnResult {
|
||||
pub assistant_reply_text: String,
|
||||
pub stage: String,
|
||||
pub progress_percent: u32,
|
||||
pub config_json: String,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct SquareHoleAgentTurnError {
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl SquareHoleAgentTurnError {
|
||||
fn new(message: impl Into<String>) -> Self {
|
||||
Self {
|
||||
message: message.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SquareHoleAgentTurnError {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
formatter.write_str(&self.message)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for SquareHoleAgentTurnError {}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct SquareHoleAgentModelOutput {
|
||||
reply_text: String,
|
||||
progress_percent: u32,
|
||||
next_config: SquareHoleAgentConfigOutput,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct SquareHoleAgentConfigOutput {
|
||||
theme_text: String,
|
||||
twist_rule: String,
|
||||
shape_count: u32,
|
||||
difficulty: u32,
|
||||
}
|
||||
|
||||
pub(crate) async fn run_square_hole_agent_turn<F>(
|
||||
request: SquareHoleAgentTurnRequest<'_>,
|
||||
on_reply_update: F,
|
||||
) -> Result<SquareHoleAgentTurnResult, SquareHoleAgentTurnError>
|
||||
where
|
||||
F: FnMut(&str),
|
||||
{
|
||||
let prompt = build_square_hole_agent_prompt(request.session, request.quick_fill_requested);
|
||||
let turn_output = stream_creation_agent_json_turn(
|
||||
request.llm_client,
|
||||
format!("{SQUARE_HOLE_AGENT_SYSTEM_PROMPT}\n\n{prompt}"),
|
||||
SQUARE_HOLE_AGENT_JSON_TURN_USER_PROMPT,
|
||||
request.enable_web_search,
|
||||
CreationAgentLlmTurnErrorMessages {
|
||||
model_unavailable: "当前模型不可用,请稍后重试。",
|
||||
generation_failed: "方洞挑战聊天生成失败,请稍后重试。",
|
||||
parse_failed: "方洞挑战聊天结果解析失败,请稍后重试。",
|
||||
},
|
||||
on_reply_update,
|
||||
SquareHoleAgentTurnError::new,
|
||||
)
|
||||
.await?;
|
||||
let output = parse_model_output(&turn_output.parsed, request.session)?;
|
||||
let progress_percent = if request.quick_fill_requested {
|
||||
100
|
||||
} else {
|
||||
output.progress_percent.min(100)
|
||||
};
|
||||
|
||||
Ok(SquareHoleAgentTurnResult {
|
||||
assistant_reply_text: output.reply_text,
|
||||
stage: resolve_stage(progress_percent),
|
||||
progress_percent,
|
||||
config_json: serde_json::to_string(&output.next_config)
|
||||
.map_err(|_| SquareHoleAgentTurnError::new("方洞挑战配置序列化失败。"))?,
|
||||
error_message: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn build_finalize_record_input(
|
||||
session_id: String,
|
||||
owner_user_id: String,
|
||||
assistant_message_id: String,
|
||||
result: SquareHoleAgentTurnResult,
|
||||
updated_at_micros: i64,
|
||||
) -> SquareHoleAgentMessageFinalizeRecordInput {
|
||||
SquareHoleAgentMessageFinalizeRecordInput {
|
||||
session_id,
|
||||
owner_user_id,
|
||||
assistant_message_id: Some(assistant_message_id),
|
||||
assistant_reply_text: Some(result.assistant_reply_text),
|
||||
config_json: Some(result.config_json),
|
||||
progress_percent: result.progress_percent,
|
||||
stage: result.stage,
|
||||
updated_at_micros,
|
||||
error_message: result.error_message,
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_model_output(
|
||||
parsed: &JsonValue,
|
||||
session: &SquareHoleAgentSessionRecord,
|
||||
) -> Result<SquareHoleAgentModelOutput, SquareHoleAgentTurnError> {
|
||||
let reply_text = parsed
|
||||
.get("replyText")
|
||||
.and_then(JsonValue::as_str)
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.ok_or_else(|| SquareHoleAgentTurnError::new("方洞挑战聊天结果缺少有效回复,请稍后重试。"))?
|
||||
.to_string();
|
||||
let progress_percent = parsed
|
||||
.get("progressPercent")
|
||||
.and_then(JsonValue::as_u64)
|
||||
.map(|value| value.min(100) as u32)
|
||||
.unwrap_or(session.progress_percent);
|
||||
let next_config_value = parsed
|
||||
.get("nextConfig")
|
||||
.ok_or_else(|| SquareHoleAgentTurnError::new("方洞挑战聊天结果缺少 nextConfig。"))?;
|
||||
let next_config = parse_model_config(next_config_value, session)?;
|
||||
Ok(SquareHoleAgentModelOutput {
|
||||
reply_text,
|
||||
progress_percent,
|
||||
next_config,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_model_config(
|
||||
value: &JsonValue,
|
||||
session: &SquareHoleAgentSessionRecord,
|
||||
) -> Result<SquareHoleAgentConfigOutput, SquareHoleAgentTurnError> {
|
||||
if !value.is_object() {
|
||||
return Err(SquareHoleAgentTurnError::new(
|
||||
"方洞挑战聊天结果中的 nextConfig 必须是对象。",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(SquareHoleAgentConfigOutput {
|
||||
theme_text: read_text_field(value, "themeText")
|
||||
.unwrap_or_else(|| session.config.theme_text.clone()),
|
||||
twist_rule: read_text_field(value, "twistRule")
|
||||
.unwrap_or_else(|| session.config.twist_rule.clone()),
|
||||
shape_count: read_u32_field(value, "shapeCount")
|
||||
.unwrap_or(session.config.shape_count)
|
||||
.clamp(SQUARE_HOLE_MIN_SHAPE_COUNT, SQUARE_HOLE_MAX_SHAPE_COUNT),
|
||||
difficulty: read_u32_field(value, "difficulty")
|
||||
.unwrap_or(session.config.difficulty)
|
||||
.clamp(SQUARE_HOLE_MIN_DIFFICULTY, SQUARE_HOLE_MAX_DIFFICULTY),
|
||||
})
|
||||
}
|
||||
|
||||
fn read_text_field(value: &JsonValue, field_name: &str) -> Option<String> {
|
||||
value
|
||||
.get(field_name)
|
||||
.and_then(JsonValue::as_str)
|
||||
.map(str::trim)
|
||||
.filter(|text| !text.is_empty())
|
||||
.map(str::to_string)
|
||||
}
|
||||
|
||||
fn read_u32_field(value: &JsonValue, field_name: &str) -> Option<u32> {
|
||||
value
|
||||
.get(field_name)
|
||||
.and_then(JsonValue::as_u64)
|
||||
.and_then(|number| u32::try_from(number).ok())
|
||||
}
|
||||
|
||||
fn resolve_stage(progress_percent: u32) -> String {
|
||||
if progress_percent >= 100 {
|
||||
"ReadyToCompile"
|
||||
} else {
|
||||
"Collecting"
|
||||
}
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json::json;
|
||||
|
||||
use super::{parse_model_output, resolve_stage};
|
||||
|
||||
fn session_record() -> spacetime_client::SquareHoleAgentSessionRecord {
|
||||
spacetime_client::SquareHoleAgentSessionRecord {
|
||||
session_id: "square-hole-session-test".to_string(),
|
||||
current_turn: 1,
|
||||
progress_percent: 25,
|
||||
stage: "collecting_config".to_string(),
|
||||
anchor_pack: spacetime_client::SquareHoleAnchorPackRecord {
|
||||
theme: anchor("theme", "题材主题", "纸箱"),
|
||||
twist_rule: anchor("twistRule", "反差规则", "方洞万能"),
|
||||
shape_count: anchor("shapeCount", "形状数量", "12"),
|
||||
difficulty: anchor("difficulty", "难度", "4"),
|
||||
},
|
||||
config: spacetime_client::SquareHoleCreatorConfigRecord {
|
||||
theme_text: "纸箱".to_string(),
|
||||
twist_rule: "方洞万能".to_string(),
|
||||
shape_count: 12,
|
||||
difficulty: 4,
|
||||
},
|
||||
draft: None,
|
||||
messages: Vec::new(),
|
||||
last_assistant_reply: None,
|
||||
published_profile_id: None,
|
||||
updated_at: "2026-05-04T10:00:00.000Z".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn anchor(key: &str, label: &str, value: &str) -> spacetime_client::SquareHoleAnchorItemRecord {
|
||||
spacetime_client::SquareHoleAnchorItemRecord {
|
||||
key: key.to_string(),
|
||||
label: label.to_string(),
|
||||
value: value.to_string(),
|
||||
status: if value.is_empty() {
|
||||
"missing"
|
||||
} else {
|
||||
"confirmed"
|
||||
}
|
||||
.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_model_output_accepts_camel_case_config_contract() {
|
||||
let model_output = json!({
|
||||
"replyText": "可以,把办公室文具都做成会被方洞吞进去的挑战。",
|
||||
"progressPercent": 86,
|
||||
"nextConfig": {
|
||||
"themeText": "办公室文具",
|
||||
"twistRule": "所有文具最终都优先进入方洞",
|
||||
"shapeCount": 14,
|
||||
"difficulty": 6
|
||||
}
|
||||
});
|
||||
|
||||
let output =
|
||||
parse_model_output(&model_output, &session_record()).expect("模型输出应能解析");
|
||||
|
||||
assert_eq!(
|
||||
output.reply_text,
|
||||
"可以,把办公室文具都做成会被方洞吞进去的挑战。"
|
||||
);
|
||||
assert_eq!(output.progress_percent, 86);
|
||||
assert_eq!(output.next_config.theme_text, "办公室文具");
|
||||
assert_eq!(output.next_config.twist_rule, "所有文具最终都优先进入方洞");
|
||||
assert_eq!(output.next_config.shape_count, 14);
|
||||
assert_eq!(output.next_config.difficulty, 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_model_output_clamps_numeric_config() {
|
||||
let model_output = json!({
|
||||
"replyText": "我先把数字压到可试玩范围里。",
|
||||
"progressPercent": 120,
|
||||
"nextConfig": {
|
||||
"themeText": "霓虹积木",
|
||||
"twistRule": "方洞优先",
|
||||
"shapeCount": 99,
|
||||
"difficulty": 0
|
||||
}
|
||||
});
|
||||
|
||||
let output =
|
||||
parse_model_output(&model_output, &session_record()).expect("模型输出应能解析");
|
||||
|
||||
assert_eq!(output.progress_percent, 100);
|
||||
assert_eq!(output.next_config.shape_count, 24);
|
||||
assert_eq!(output.next_config.difficulty, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_stage_switches_to_compile_only_at_complete_progress() {
|
||||
assert_eq!(resolve_stage(99), "Collecting");
|
||||
assert_eq!(resolve_stage(100), "ReadyToCompile");
|
||||
}
|
||||
}
|
||||
14
server-rs/crates/module-square-hole/Cargo.toml
Normal file
14
server-rs/crates/module-square-hole/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "module-square-hole"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[features]
|
||||
default = []
|
||||
spacetime-types = ["dep:spacetimedb"]
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
shared-kernel = { path = "../shared-kernel" }
|
||||
spacetimedb = { workspace = true, optional = true }
|
||||
456
server-rs/crates/module-square-hole/src/application.rs
Normal file
456
server-rs/crates/module-square-hole/src/application.rs
Normal file
@@ -0,0 +1,456 @@
|
||||
use shared_kernel::{normalize_optional_string, normalize_required_string, normalize_string_list};
|
||||
|
||||
use crate::commands::{default_tags_for_theme, validate_publish_requirements};
|
||||
use crate::{
|
||||
SQUARE_HOLE_DEFAULT_DURATION_LIMIT_MS, SQUARE_HOLE_MAX_DIFFICULTY, SQUARE_HOLE_MIN_DIFFICULTY,
|
||||
SquareHoleCreatorConfig, SquareHoleDropConfirmation, SquareHoleDropFeedback,
|
||||
SquareHoleDropInput, SquareHoleDropRejectReason, SquareHoleError, SquareHoleHoleSnapshot,
|
||||
SquareHolePublicationStatus, SquareHoleResultDraft, SquareHoleRunSnapshot, SquareHoleRunStatus,
|
||||
SquareHoleShapeSnapshot, SquareHoleWorkProfile,
|
||||
};
|
||||
|
||||
pub fn compile_result_draft(
|
||||
profile_id: String,
|
||||
config: &SquareHoleCreatorConfig,
|
||||
) -> SquareHoleResultDraft {
|
||||
let game_name = format!("{}方洞挑战", config.theme_text);
|
||||
let summary = format!(
|
||||
"{}主题,{} 个形状,难度 {},真实规则:{}。",
|
||||
config.theme_text, config.shape_count, config.difficulty, config.twist_rule
|
||||
);
|
||||
let mut draft = SquareHoleResultDraft {
|
||||
profile_id,
|
||||
game_name,
|
||||
theme_text: config.theme_text.clone(),
|
||||
twist_rule: config.twist_rule.clone(),
|
||||
summary,
|
||||
tags: default_tags_for_theme(&config.theme_text),
|
||||
shape_count: config.shape_count,
|
||||
difficulty: config.difficulty,
|
||||
publish_ready: false,
|
||||
blockers: Vec::new(),
|
||||
};
|
||||
draft.blockers = validate_publish_requirements(&draft);
|
||||
draft.publish_ready = draft.blockers.is_empty();
|
||||
draft
|
||||
}
|
||||
|
||||
pub fn create_work_profile(
|
||||
work_id: String,
|
||||
profile_id: String,
|
||||
owner_user_id: String,
|
||||
source_session_id: Option<String>,
|
||||
draft: &SquareHoleResultDraft,
|
||||
updated_at_micros: i64,
|
||||
) -> Result<SquareHoleWorkProfile, SquareHoleError> {
|
||||
let work_id = normalize_required_string(work_id).ok_or(SquareHoleError::MissingText)?;
|
||||
let profile_id =
|
||||
normalize_required_string(profile_id).ok_or(SquareHoleError::MissingProfileId)?;
|
||||
let owner_user_id =
|
||||
normalize_required_string(owner_user_id).ok_or(SquareHoleError::MissingOwnerUserId)?;
|
||||
|
||||
Ok(SquareHoleWorkProfile {
|
||||
work_id,
|
||||
profile_id,
|
||||
owner_user_id,
|
||||
source_session_id: normalize_optional_string(source_session_id),
|
||||
game_name: draft.game_name.clone(),
|
||||
theme_text: draft.theme_text.clone(),
|
||||
twist_rule: draft.twist_rule.clone(),
|
||||
summary: draft.summary.clone(),
|
||||
tags: normalize_string_list(draft.tags.clone()),
|
||||
cover_image_src: None,
|
||||
shape_count: draft.shape_count,
|
||||
difficulty: draft.difficulty,
|
||||
publication_status: SquareHolePublicationStatus::Draft,
|
||||
play_count: 0,
|
||||
updated_at_micros,
|
||||
published_at_micros: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn publish_work_profile(
|
||||
profile: &SquareHoleWorkProfile,
|
||||
published_at_micros: i64,
|
||||
) -> Result<SquareHoleWorkProfile, SquareHoleError> {
|
||||
if profile.shape_count == 0 {
|
||||
return Err(SquareHoleError::InvalidShapeCount);
|
||||
}
|
||||
if !(SQUARE_HOLE_MIN_DIFFICULTY..=SQUARE_HOLE_MAX_DIFFICULTY).contains(&profile.difficulty) {
|
||||
return Err(SquareHoleError::InvalidDifficulty);
|
||||
}
|
||||
|
||||
let mut next = profile.clone();
|
||||
next.publication_status = SquareHolePublicationStatus::Published;
|
||||
next.updated_at_micros = published_at_micros;
|
||||
next.published_at_micros = Some(published_at_micros);
|
||||
Ok(next)
|
||||
}
|
||||
|
||||
pub fn start_run_at(
|
||||
run_id: String,
|
||||
owner_user_id: String,
|
||||
profile_id: String,
|
||||
config: &SquareHoleCreatorConfig,
|
||||
started_at_ms: u64,
|
||||
) -> Result<SquareHoleRunSnapshot, SquareHoleError> {
|
||||
let run_id = normalize_required_string(run_id).ok_or(SquareHoleError::MissingRunId)?;
|
||||
let owner_user_id =
|
||||
normalize_required_string(owner_user_id).ok_or(SquareHoleError::MissingOwnerUserId)?;
|
||||
let profile_id =
|
||||
normalize_required_string(profile_id).ok_or(SquareHoleError::MissingProfileId)?;
|
||||
|
||||
Ok(SquareHoleRunSnapshot {
|
||||
run_id,
|
||||
profile_id,
|
||||
owner_user_id,
|
||||
status: SquareHoleRunStatus::Running,
|
||||
snapshot_version: 1,
|
||||
started_at_ms,
|
||||
duration_limit_ms: SQUARE_HOLE_DEFAULT_DURATION_LIMIT_MS,
|
||||
remaining_ms: SQUARE_HOLE_DEFAULT_DURATION_LIMIT_MS,
|
||||
total_shape_count: config.shape_count,
|
||||
completed_shape_count: 0,
|
||||
combo: 0,
|
||||
best_combo: 0,
|
||||
score: 0,
|
||||
rule_label: config.twist_rule.clone(),
|
||||
current_shape: Some(build_shape_at(0, config.shape_count)),
|
||||
holes: default_holes(),
|
||||
last_feedback: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn confirm_drop_at(
|
||||
run: &SquareHoleRunSnapshot,
|
||||
input: &SquareHoleDropInput,
|
||||
) -> Result<SquareHoleDropConfirmation, SquareHoleError> {
|
||||
let hole_id =
|
||||
normalize_required_string(&input.hole_id).ok_or(SquareHoleError::MissingHoleId)?;
|
||||
let mut next = resolve_run_timer_at(run, input.dropped_at_ms);
|
||||
if next.status != SquareHoleRunStatus::Running {
|
||||
return Ok(rejected(next, SquareHoleDropRejectReason::RunNotActive));
|
||||
}
|
||||
if input.client_snapshot_version != next.snapshot_version {
|
||||
return Ok(rejected(
|
||||
next,
|
||||
SquareHoleDropRejectReason::SnapshotVersionMismatch,
|
||||
));
|
||||
}
|
||||
|
||||
let Some(hole) = next.holes.iter().find(|item| item.hole_id == hole_id) else {
|
||||
return Ok(rejected(next, SquareHoleDropRejectReason::HoleNotFound));
|
||||
};
|
||||
let Some(shape) = next.current_shape.clone() else {
|
||||
return Ok(rejected(next, SquareHoleDropRejectReason::Incompatible));
|
||||
};
|
||||
|
||||
if !is_shape_accepted_by_hole(&shape, hole) {
|
||||
next.combo = 0;
|
||||
next.snapshot_version = next.snapshot_version.saturating_add(1);
|
||||
return Ok(rejected(next, SquareHoleDropRejectReason::Incompatible));
|
||||
}
|
||||
|
||||
let message = format!("{}进入{}", shape.label, hole.label);
|
||||
let feedback = SquareHoleDropFeedback {
|
||||
accepted: true,
|
||||
reject_reason: None,
|
||||
message,
|
||||
};
|
||||
next.completed_shape_count = next.completed_shape_count.saturating_add(1);
|
||||
next.combo = next.combo.saturating_add(1);
|
||||
next.best_combo = next.best_combo.max(next.combo);
|
||||
next.score = next.score.saturating_add(100 + next.combo * 10);
|
||||
next.current_shape = if next.completed_shape_count >= next.total_shape_count {
|
||||
next.status = SquareHoleRunStatus::Won;
|
||||
None
|
||||
} else {
|
||||
Some(build_shape_at(
|
||||
next.completed_shape_count,
|
||||
next.total_shape_count,
|
||||
))
|
||||
};
|
||||
next.snapshot_version = next.snapshot_version.saturating_add(1);
|
||||
next.last_feedback = Some(feedback.clone());
|
||||
|
||||
Ok(SquareHoleDropConfirmation {
|
||||
feedback,
|
||||
run: next,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn resolve_run_timer_at(run: &SquareHoleRunSnapshot, now_ms: u64) -> SquareHoleRunSnapshot {
|
||||
let mut next = run.clone();
|
||||
if next.status != SquareHoleRunStatus::Running {
|
||||
return next;
|
||||
}
|
||||
let elapsed_ms = now_ms.saturating_sub(next.started_at_ms);
|
||||
next.remaining_ms = next.duration_limit_ms.saturating_sub(elapsed_ms);
|
||||
if next.remaining_ms == 0 {
|
||||
let feedback = SquareHoleDropFeedback {
|
||||
accepted: false,
|
||||
reject_reason: Some(SquareHoleDropRejectReason::TimeUp),
|
||||
message: "时间到".to_string(),
|
||||
};
|
||||
next.status = SquareHoleRunStatus::Failed;
|
||||
next.combo = 0;
|
||||
next.current_shape = None;
|
||||
next.last_feedback = Some(feedback);
|
||||
next.snapshot_version = next.snapshot_version.saturating_add(1);
|
||||
}
|
||||
next
|
||||
}
|
||||
|
||||
pub fn stop_run_at(run: &SquareHoleRunSnapshot) -> SquareHoleRunSnapshot {
|
||||
let mut next = run.clone();
|
||||
if next.status == SquareHoleRunStatus::Running {
|
||||
next.status = SquareHoleRunStatus::Stopped;
|
||||
next.combo = 0;
|
||||
next.snapshot_version = next.snapshot_version.saturating_add(1);
|
||||
next.last_feedback = Some(SquareHoleDropFeedback {
|
||||
accepted: false,
|
||||
reject_reason: Some(SquareHoleDropRejectReason::RunNotActive),
|
||||
message: "已退出本局".to_string(),
|
||||
});
|
||||
}
|
||||
next
|
||||
}
|
||||
|
||||
pub fn build_shape_at(index: u32, total: u32) -> SquareHoleShapeSnapshot {
|
||||
let kind = if index + 1 == total {
|
||||
"square"
|
||||
} else if index % 4 == 0 {
|
||||
"circle"
|
||||
} else if index % 4 == 1 {
|
||||
"triangle"
|
||||
} else if index % 4 == 2 {
|
||||
"diamond"
|
||||
} else {
|
||||
"star"
|
||||
};
|
||||
|
||||
SquareHoleShapeSnapshot {
|
||||
shape_id: format!("square-hole-shape-{index:03}"),
|
||||
shape_kind: kind.to_string(),
|
||||
label: match kind {
|
||||
"square" => "方块",
|
||||
"circle" => "圆块",
|
||||
"triangle" => "三角块",
|
||||
"diamond" => "菱形块",
|
||||
_ => "星形块",
|
||||
}
|
||||
.to_string(),
|
||||
color: match kind {
|
||||
"square" => "#facc15",
|
||||
"circle" => "#22c55e",
|
||||
"triangle" => "#38bdf8",
|
||||
"diamond" => "#fb7185",
|
||||
_ => "#c084fc",
|
||||
}
|
||||
.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_holes() -> Vec<SquareHoleHoleSnapshot> {
|
||||
vec![
|
||||
SquareHoleHoleSnapshot {
|
||||
hole_id: "square-hole".to_string(),
|
||||
hole_kind: "square".to_string(),
|
||||
label: "方洞".to_string(),
|
||||
x: 0.5,
|
||||
y: 0.28,
|
||||
},
|
||||
SquareHoleHoleSnapshot {
|
||||
hole_id: "circle-hole".to_string(),
|
||||
hole_kind: "circle".to_string(),
|
||||
label: "圆洞".to_string(),
|
||||
x: 0.24,
|
||||
y: 0.54,
|
||||
},
|
||||
SquareHoleHoleSnapshot {
|
||||
hole_id: "triangle-hole".to_string(),
|
||||
hole_kind: "triangle".to_string(),
|
||||
label: "三角洞".to_string(),
|
||||
x: 0.76,
|
||||
y: 0.54,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn is_shape_accepted_by_hole(
|
||||
shape: &SquareHoleShapeSnapshot,
|
||||
hole: &SquareHoleHoleSnapshot,
|
||||
) -> bool {
|
||||
// 中文注释:首版核心反差固定为“方洞万能”,保留同形状洞口兼容便于后续扩展规则。
|
||||
hole.hole_kind == "square" || hole.hole_kind == shape.shape_kind
|
||||
}
|
||||
|
||||
fn rejected(
|
||||
mut run: SquareHoleRunSnapshot,
|
||||
reject_reason: SquareHoleDropRejectReason,
|
||||
) -> SquareHoleDropConfirmation {
|
||||
let message = match reject_reason {
|
||||
SquareHoleDropRejectReason::RunNotActive => "当前局已结束",
|
||||
SquareHoleDropRejectReason::SnapshotVersionMismatch => "操作慢了一步",
|
||||
SquareHoleDropRejectReason::HoleNotFound => "洞口不存在",
|
||||
SquareHoleDropRejectReason::Incompatible => "这个洞不对",
|
||||
SquareHoleDropRejectReason::TimeUp => "时间到",
|
||||
}
|
||||
.to_string();
|
||||
let feedback = SquareHoleDropFeedback {
|
||||
accepted: false,
|
||||
reject_reason: Some(reject_reason),
|
||||
message,
|
||||
};
|
||||
run.last_feedback = Some(feedback.clone());
|
||||
SquareHoleDropConfirmation { feedback, run }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::commands::build_creator_config;
|
||||
|
||||
fn test_config(shape_count: u32) -> SquareHoleCreatorConfig {
|
||||
build_creator_config("玩具", "方洞万能", shape_count, 4).expect("config should be valid")
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn draft_is_publishable_with_required_fields() {
|
||||
let draft = compile_result_draft("profile-1".to_string(), &test_config(8));
|
||||
|
||||
assert!(draft.publish_ready);
|
||||
assert!(draft.blockers.is_empty());
|
||||
assert!(draft.tags.contains(&"方洞挑战".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_starts_with_current_shape_and_default_holes() {
|
||||
let run = start_run_at(
|
||||
"run-1".to_string(),
|
||||
"user-1".to_string(),
|
||||
"profile-1".to_string(),
|
||||
&test_config(8),
|
||||
1_000,
|
||||
)
|
||||
.expect("run should start");
|
||||
|
||||
assert_eq!(run.status, SquareHoleRunStatus::Running);
|
||||
assert!(run.current_shape.is_some());
|
||||
assert_eq!(run.holes.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn square_hole_accepts_non_square_shape() {
|
||||
let run = start_run_at(
|
||||
"run-1".to_string(),
|
||||
"user-1".to_string(),
|
||||
"profile-1".to_string(),
|
||||
&test_config(8),
|
||||
1_000,
|
||||
)
|
||||
.expect("run should start");
|
||||
let result = confirm_drop_at(
|
||||
&run,
|
||||
&SquareHoleDropInput {
|
||||
run_id: run.run_id.clone(),
|
||||
owner_user_id: run.owner_user_id.clone(),
|
||||
hole_id: "square-hole".to_string(),
|
||||
client_snapshot_version: run.snapshot_version,
|
||||
client_event_id: "event-1".to_string(),
|
||||
dropped_at_ms: 1_100,
|
||||
},
|
||||
)
|
||||
.expect("drop should resolve");
|
||||
|
||||
assert!(result.feedback.accepted);
|
||||
assert_eq!(result.run.completed_shape_count, 1);
|
||||
assert_eq!(result.run.combo, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrong_non_square_hole_rejects_and_resets_combo() {
|
||||
let mut run = start_run_at(
|
||||
"run-1".to_string(),
|
||||
"user-1".to_string(),
|
||||
"profile-1".to_string(),
|
||||
&test_config(8),
|
||||
1_000,
|
||||
)
|
||||
.expect("run should start");
|
||||
run.current_shape = Some(build_shape_at(1, 8));
|
||||
run.combo = 2;
|
||||
|
||||
let result = confirm_drop_at(
|
||||
&run,
|
||||
&SquareHoleDropInput {
|
||||
run_id: run.run_id.clone(),
|
||||
owner_user_id: run.owner_user_id.clone(),
|
||||
hole_id: "circle-hole".to_string(),
|
||||
client_snapshot_version: run.snapshot_version,
|
||||
client_event_id: "event-1".to_string(),
|
||||
dropped_at_ms: 1_100,
|
||||
},
|
||||
)
|
||||
.expect("drop should resolve");
|
||||
|
||||
assert!(!result.feedback.accepted);
|
||||
assert_eq!(
|
||||
result.feedback.reject_reason,
|
||||
Some(SquareHoleDropRejectReason::Incompatible)
|
||||
);
|
||||
assert_eq!(result.run.combo, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn last_shape_win_finishes_run() {
|
||||
let mut run = start_run_at(
|
||||
"run-1".to_string(),
|
||||
"user-1".to_string(),
|
||||
"profile-1".to_string(),
|
||||
&test_config(6),
|
||||
1_000,
|
||||
)
|
||||
.expect("run should start");
|
||||
run.completed_shape_count = 5;
|
||||
run.current_shape = Some(build_shape_at(5, 6));
|
||||
|
||||
let result = confirm_drop_at(
|
||||
&run,
|
||||
&SquareHoleDropInput {
|
||||
run_id: run.run_id.clone(),
|
||||
owner_user_id: run.owner_user_id.clone(),
|
||||
hole_id: "square-hole".to_string(),
|
||||
client_snapshot_version: run.snapshot_version,
|
||||
client_event_id: "event-1".to_string(),
|
||||
dropped_at_ms: 1_100,
|
||||
},
|
||||
)
|
||||
.expect("drop should resolve");
|
||||
|
||||
assert_eq!(result.run.status, SquareHoleRunStatus::Won);
|
||||
assert!(result.run.current_shape.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn timer_expiration_fails_running_run() {
|
||||
let run = start_run_at(
|
||||
"run-1".to_string(),
|
||||
"user-1".to_string(),
|
||||
"profile-1".to_string(),
|
||||
&test_config(8),
|
||||
1_000,
|
||||
)
|
||||
.expect("run should start");
|
||||
|
||||
let expired = resolve_run_timer_at(&run, 1_000 + SQUARE_HOLE_DEFAULT_DURATION_LIMIT_MS);
|
||||
|
||||
assert_eq!(expired.status, SquareHoleRunStatus::Failed);
|
||||
assert_eq!(
|
||||
expired
|
||||
.last_feedback
|
||||
.and_then(|feedback| feedback.reject_reason),
|
||||
Some(SquareHoleDropRejectReason::TimeUp)
|
||||
);
|
||||
}
|
||||
}
|
||||
116
server-rs/crates/module-square-hole/src/commands.rs
Normal file
116
server-rs/crates/module-square-hole/src/commands.rs
Normal file
@@ -0,0 +1,116 @@
|
||||
use shared_kernel::{normalize_required_string, normalize_string_list};
|
||||
|
||||
use crate::{
|
||||
SQUARE_HOLE_MAX_DIFFICULTY, SQUARE_HOLE_MAX_SHAPE_COUNT, SQUARE_HOLE_MIN_DIFFICULTY,
|
||||
SQUARE_HOLE_MIN_SHAPE_COUNT, SquareHoleCreatorConfig, SquareHoleError, SquareHoleResultDraft,
|
||||
};
|
||||
|
||||
pub fn validate_shape_count(value: u32) -> Result<u32, SquareHoleError> {
|
||||
if (SQUARE_HOLE_MIN_SHAPE_COUNT..=SQUARE_HOLE_MAX_SHAPE_COUNT).contains(&value) {
|
||||
Ok(value)
|
||||
} else {
|
||||
Err(SquareHoleError::InvalidShapeCount)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate_difficulty(value: u32) -> Result<u32, SquareHoleError> {
|
||||
if (SQUARE_HOLE_MIN_DIFFICULTY..=SQUARE_HOLE_MAX_DIFFICULTY).contains(&value) {
|
||||
Ok(value)
|
||||
} else {
|
||||
Err(SquareHoleError::InvalidDifficulty)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn normalize_theme_text(value: impl AsRef<str>) -> Result<String, SquareHoleError> {
|
||||
normalize_required_string(value).ok_or(SquareHoleError::MissingText)
|
||||
}
|
||||
|
||||
pub fn build_creator_config(
|
||||
theme_text: &str,
|
||||
twist_rule: &str,
|
||||
shape_count: u32,
|
||||
difficulty: u32,
|
||||
) -> Result<SquareHoleCreatorConfig, SquareHoleError> {
|
||||
Ok(SquareHoleCreatorConfig {
|
||||
theme_text: normalize_theme_text(theme_text)?,
|
||||
twist_rule: normalize_required_string(twist_rule).ok_or(SquareHoleError::MissingText)?,
|
||||
shape_count: validate_shape_count(shape_count)?,
|
||||
difficulty: validate_difficulty(difficulty)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn build_default_tags(theme_text: &str) -> Vec<String> {
|
||||
normalize_string_list(vec![
|
||||
"方洞挑战".to_string(),
|
||||
theme_text.to_string(),
|
||||
"反直觉".to_string(),
|
||||
])
|
||||
}
|
||||
|
||||
pub fn default_tags_for_theme(theme_text: &str) -> Vec<String> {
|
||||
let mut tags = vec![
|
||||
"方洞挑战".to_string(),
|
||||
"反直觉".to_string(),
|
||||
theme_text.to_string(),
|
||||
];
|
||||
tags.sort();
|
||||
tags.dedup();
|
||||
tags
|
||||
}
|
||||
|
||||
pub fn validate_publish_requirements(draft: &SquareHoleResultDraft) -> Vec<String> {
|
||||
let mut blockers = Vec::new();
|
||||
if normalize_required_string(&draft.game_name).is_none() {
|
||||
blockers.push("游戏名称不能为空".to_string());
|
||||
}
|
||||
if normalize_required_string(&draft.summary).is_none() {
|
||||
blockers.push("简介不能为空".to_string());
|
||||
}
|
||||
if normalize_required_string(&draft.theme_text).is_none() {
|
||||
blockers.push("题材不能为空".to_string());
|
||||
}
|
||||
if normalize_required_string(&draft.twist_rule).is_none() {
|
||||
blockers.push("反直觉规则不能为空".to_string());
|
||||
}
|
||||
if normalize_string_list(draft.tags.clone()).is_empty() {
|
||||
blockers.push("至少需要 1 个标签".to_string());
|
||||
}
|
||||
if validate_shape_count(draft.shape_count).is_err() {
|
||||
blockers.push(format!(
|
||||
"形状数量必须在 {} 到 {} 之间",
|
||||
SQUARE_HOLE_MIN_SHAPE_COUNT, SQUARE_HOLE_MAX_SHAPE_COUNT
|
||||
));
|
||||
}
|
||||
if validate_difficulty(draft.difficulty).is_err() {
|
||||
blockers.push("难度必须在 1 到 10 之间".to_string());
|
||||
}
|
||||
blockers
|
||||
}
|
||||
|
||||
#[deprecated(note = "请使用 compile_result_draft(profile_id, &config)")]
|
||||
pub fn build_result_draft(
|
||||
profile_id: String,
|
||||
theme_text: String,
|
||||
twist_rule: String,
|
||||
shape_count: u32,
|
||||
difficulty: u32,
|
||||
) -> SquareHoleResultDraft {
|
||||
let game_name = format!("{theme_text}方洞挑战");
|
||||
let summary = format!(
|
||||
"{theme_text}主题,{} 个形状,难度 {},规则:{twist_rule}",
|
||||
shape_count, difficulty
|
||||
);
|
||||
let blockers = Vec::new();
|
||||
SquareHoleResultDraft {
|
||||
profile_id,
|
||||
game_name,
|
||||
theme_text,
|
||||
twist_rule,
|
||||
summary,
|
||||
tags: build_default_tags("方洞挑战"),
|
||||
shape_count,
|
||||
difficulty,
|
||||
publish_ready: true,
|
||||
blockers,
|
||||
}
|
||||
}
|
||||
204
server-rs/crates/module-square-hole/src/domain.rs
Normal file
204
server-rs/crates/module-square-hole/src/domain.rs
Normal file
@@ -0,0 +1,204 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "spacetime-types")]
|
||||
use spacetimedb::SpacetimeType;
|
||||
|
||||
pub const SQUARE_HOLE_SESSION_ID_PREFIX: &str = "square-hole-session-";
|
||||
pub const SQUARE_HOLE_MESSAGE_ID_PREFIX: &str = "square-hole-message-";
|
||||
pub const SQUARE_HOLE_PROFILE_ID_PREFIX: &str = "square-hole-profile-";
|
||||
pub const SQUARE_HOLE_WORK_ID_PREFIX: &str = "square-hole-work-";
|
||||
pub const SQUARE_HOLE_RUN_ID_PREFIX: &str = "square-hole-run-";
|
||||
pub const SQUARE_HOLE_MIN_SHAPE_COUNT: u32 = 6;
|
||||
pub const SQUARE_HOLE_MAX_SHAPE_COUNT: u32 = 24;
|
||||
pub const SQUARE_HOLE_MIN_DIFFICULTY: u32 = 1;
|
||||
pub const SQUARE_HOLE_MAX_DIFFICULTY: u32 = 10;
|
||||
pub const SQUARE_HOLE_DEFAULT_DURATION_LIMIT_MS: u64 = 60_000;
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum SquareHoleCreationStage {
|
||||
CollectingConfig,
|
||||
DraftReady,
|
||||
ReadyToPublish,
|
||||
Published,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum SquareHolePublicationStatus {
|
||||
Draft,
|
||||
Published,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum SquareHoleRunStatus {
|
||||
Running,
|
||||
Won,
|
||||
Failed,
|
||||
Stopped,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum SquareHoleDropRejectReason {
|
||||
RunNotActive,
|
||||
SnapshotVersionMismatch,
|
||||
HoleNotFound,
|
||||
Incompatible,
|
||||
TimeUp,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct SquareHoleCreatorConfig {
|
||||
pub theme_text: String,
|
||||
pub twist_rule: String,
|
||||
pub shape_count: u32,
|
||||
pub difficulty: u32,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct SquareHoleResultDraft {
|
||||
pub profile_id: String,
|
||||
pub game_name: String,
|
||||
pub theme_text: String,
|
||||
pub twist_rule: String,
|
||||
pub summary: String,
|
||||
pub tags: Vec<String>,
|
||||
pub shape_count: u32,
|
||||
pub difficulty: u32,
|
||||
pub publish_ready: bool,
|
||||
pub blockers: Vec<String>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct SquareHoleWorkProfile {
|
||||
pub work_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub source_session_id: Option<String>,
|
||||
pub game_name: String,
|
||||
pub theme_text: String,
|
||||
pub twist_rule: String,
|
||||
pub summary: String,
|
||||
pub tags: Vec<String>,
|
||||
pub cover_image_src: Option<String>,
|
||||
pub shape_count: u32,
|
||||
pub difficulty: u32,
|
||||
pub publication_status: SquareHolePublicationStatus,
|
||||
pub play_count: u32,
|
||||
pub updated_at_micros: i64,
|
||||
pub published_at_micros: Option<i64>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct SquareHoleShapeSnapshot {
|
||||
pub shape_id: String,
|
||||
pub shape_kind: String,
|
||||
pub label: String,
|
||||
pub color: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct SquareHoleHoleSnapshot {
|
||||
pub hole_id: String,
|
||||
pub hole_kind: String,
|
||||
pub label: String,
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct SquareHoleDropFeedback {
|
||||
pub accepted: bool,
|
||||
pub reject_reason: Option<SquareHoleDropRejectReason>,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct SquareHoleRunSnapshot {
|
||||
pub run_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub status: SquareHoleRunStatus,
|
||||
pub snapshot_version: u64,
|
||||
pub started_at_ms: u64,
|
||||
pub duration_limit_ms: u64,
|
||||
pub remaining_ms: u64,
|
||||
pub total_shape_count: u32,
|
||||
pub completed_shape_count: u32,
|
||||
pub combo: u32,
|
||||
pub best_combo: u32,
|
||||
pub score: u32,
|
||||
pub rule_label: String,
|
||||
pub current_shape: Option<SquareHoleShapeSnapshot>,
|
||||
pub holes: Vec<SquareHoleHoleSnapshot>,
|
||||
pub last_feedback: Option<SquareHoleDropFeedback>,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct SquareHoleDropInput {
|
||||
pub run_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub hole_id: String,
|
||||
pub client_snapshot_version: u64,
|
||||
pub client_event_id: String,
|
||||
pub dropped_at_ms: u64,
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct SquareHoleDropConfirmation {
|
||||
pub feedback: SquareHoleDropFeedback,
|
||||
pub run: SquareHoleRunSnapshot,
|
||||
}
|
||||
|
||||
impl SquareHoleCreationStage {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::CollectingConfig => "collecting_config",
|
||||
Self::DraftReady => "draft_ready",
|
||||
Self::ReadyToPublish => "ready_to_publish",
|
||||
Self::Published => "published",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SquareHolePublicationStatus {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Draft => "draft",
|
||||
Self::Published => "published",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SquareHoleRunStatus {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::Running => "running",
|
||||
Self::Won => "won",
|
||||
Self::Failed => "failed",
|
||||
Self::Stopped => "stopped",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SquareHoleDropRejectReason {
|
||||
pub fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::RunNotActive => "run_not_active",
|
||||
Self::SnapshotVersionMismatch => "snapshot_version_mismatch",
|
||||
Self::HoleNotFound => "hole_not_found",
|
||||
Self::Incompatible => "incompatible",
|
||||
Self::TimeUp => "time_up",
|
||||
}
|
||||
}
|
||||
}
|
||||
37
server-rs/crates/module-square-hole/src/errors.rs
Normal file
37
server-rs/crates/module-square-hole/src/errors.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum SquareHoleError {
|
||||
MissingText,
|
||||
MissingOwnerUserId,
|
||||
InvalidShapeCount,
|
||||
InvalidDifficulty,
|
||||
MissingProfileId,
|
||||
MissingRunId,
|
||||
MissingHoleId,
|
||||
RunNotActive,
|
||||
SnapshotVersionMismatch,
|
||||
HoleNotFound,
|
||||
Incompatible,
|
||||
}
|
||||
|
||||
impl Display for SquareHoleError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let message = match self {
|
||||
Self::MissingText => "文本不能为空",
|
||||
Self::MissingOwnerUserId => "owner_user_id 缺失",
|
||||
Self::InvalidShapeCount => "形状数量必须在 6 到 24 之间",
|
||||
Self::InvalidDifficulty => "难度必须在 1 到 10 之间",
|
||||
Self::MissingProfileId => "缺少 profileId",
|
||||
Self::MissingRunId => "缺少 runId",
|
||||
Self::MissingHoleId => "缺少 holeId",
|
||||
Self::RunNotActive => "当前运行态未激活",
|
||||
Self::SnapshotVersionMismatch => "快照版本不一致",
|
||||
Self::HoleNotFound => "洞口不存在",
|
||||
Self::Incompatible => "当前形状不能投入这个洞口",
|
||||
};
|
||||
write!(f, "{message}")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for SquareHoleError {}
|
||||
25
server-rs/crates/module-square-hole/src/events.rs
Normal file
25
server-rs/crates/module-square-hole/src/events.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
//! 方洞挑战领域事件。
|
||||
//!
|
||||
//! 事件只表达已经发生的领域事实,是否持久化、投影或通知前端由
|
||||
//! SpacetimeDB adapter 与 BFF 编排层决定。
|
||||
|
||||
/// 方洞挑战领域事件。
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum SquareHoleDomainEvent {
|
||||
DraftCompiled {
|
||||
profile_id: String,
|
||||
owner_user_id: String,
|
||||
occurred_at_micros: i64,
|
||||
},
|
||||
WorkPublished {
|
||||
profile_id: String,
|
||||
owner_user_id: String,
|
||||
occurred_at_micros: i64,
|
||||
},
|
||||
RunSettled {
|
||||
run_id: String,
|
||||
owner_user_id: String,
|
||||
status: String,
|
||||
occurred_at_micros: i64,
|
||||
},
|
||||
}
|
||||
11
server-rs/crates/module-square-hole/src/lib.rs
Normal file
11
server-rs/crates/module-square-hole/src/lib.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
mod application;
|
||||
mod commands;
|
||||
mod domain;
|
||||
mod errors;
|
||||
mod events;
|
||||
|
||||
pub use application::*;
|
||||
pub use commands::*;
|
||||
pub use domain::*;
|
||||
pub use errors::*;
|
||||
pub use events::*;
|
||||
@@ -16,4 +16,7 @@ pub mod puzzle_runtime;
|
||||
pub mod puzzle_works;
|
||||
pub mod runtime;
|
||||
pub mod runtime_story;
|
||||
pub mod square_hole_agent;
|
||||
pub mod square_hole_runtime;
|
||||
pub mod square_hole_works;
|
||||
pub mod story;
|
||||
|
||||
122
server-rs/crates/shared-contracts/src/square_hole_agent.rs
Normal file
122
server-rs/crates/shared-contracts/src/square_hole_agent.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CreateSquareHoleSessionRequest {
|
||||
#[serde(default)]
|
||||
pub seed_text: Option<String>,
|
||||
#[serde(default)]
|
||||
pub theme_text: Option<String>,
|
||||
#[serde(default)]
|
||||
pub twist_rule: Option<String>,
|
||||
#[serde(default)]
|
||||
pub shape_count: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub difficulty: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SendSquareHoleMessageRequest {
|
||||
pub client_message_id: String,
|
||||
pub text: String,
|
||||
#[serde(default)]
|
||||
pub quick_fill_requested: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ExecuteSquareHoleActionRequest {
|
||||
pub action: String,
|
||||
#[serde(default)]
|
||||
pub game_name: Option<String>,
|
||||
#[serde(default)]
|
||||
pub summary: Option<String>,
|
||||
#[serde(default)]
|
||||
pub tags: Option<Vec<String>>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleAnchorItemResponse {
|
||||
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 SquareHoleAnchorPackResponse {
|
||||
pub theme: SquareHoleAnchorItemResponse,
|
||||
pub twist_rule: SquareHoleAnchorItemResponse,
|
||||
pub shape_count: SquareHoleAnchorItemResponse,
|
||||
pub difficulty: SquareHoleAnchorItemResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleCreatorConfigResponse {
|
||||
pub theme_text: String,
|
||||
pub twist_rule: String,
|
||||
pub shape_count: u32,
|
||||
pub difficulty: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleResultDraftResponse {
|
||||
pub profile_id: String,
|
||||
pub game_name: String,
|
||||
pub theme_text: String,
|
||||
pub twist_rule: String,
|
||||
pub summary: String,
|
||||
pub tags: Vec<String>,
|
||||
pub shape_count: u32,
|
||||
pub difficulty: u32,
|
||||
pub publish_ready: bool,
|
||||
pub blockers: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleAgentMessageResponse {
|
||||
pub id: String,
|
||||
pub role: String,
|
||||
pub kind: String,
|
||||
pub text: String,
|
||||
pub created_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleSessionSnapshotResponse {
|
||||
pub session_id: String,
|
||||
pub current_turn: u32,
|
||||
pub progress_percent: u32,
|
||||
pub stage: String,
|
||||
pub anchor_pack: SquareHoleAnchorPackResponse,
|
||||
pub config: SquareHoleCreatorConfigResponse,
|
||||
#[serde(default)]
|
||||
pub draft: Option<SquareHoleResultDraftResponse>,
|
||||
pub messages: Vec<SquareHoleAgentMessageResponse>,
|
||||
#[serde(default)]
|
||||
pub last_assistant_reply: Option<String>,
|
||||
#[serde(default)]
|
||||
pub published_profile_id: Option<String>,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleSessionResponse {
|
||||
pub session: SquareHoleSessionSnapshotResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleActionResponse {
|
||||
pub session: SquareHoleSessionSnapshotResponse,
|
||||
}
|
||||
89
server-rs/crates/shared-contracts/src/square_hole_runtime.rs
Normal file
89
server-rs/crates/shared-contracts/src/square_hole_runtime.rs
Normal file
@@ -0,0 +1,89 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct StartSquareHoleRunRequest {
|
||||
pub profile_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DropSquareHoleShapeRequest {
|
||||
#[serde(default)]
|
||||
pub run_id: Option<String>,
|
||||
pub hole_id: String,
|
||||
pub client_snapshot_version: u64,
|
||||
pub client_event_id: String,
|
||||
pub dropped_at_ms: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct StopSquareHoleRunRequest {
|
||||
pub client_action_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleShapeSnapshotResponse {
|
||||
pub shape_id: String,
|
||||
pub shape_kind: String,
|
||||
pub label: String,
|
||||
pub color: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleHoleSnapshotResponse {
|
||||
pub hole_id: String,
|
||||
pub hole_kind: String,
|
||||
pub label: String,
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleDropFeedbackResponse {
|
||||
pub accepted: bool,
|
||||
#[serde(default)]
|
||||
pub reject_reason: Option<String>,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleRunSnapshotResponse {
|
||||
pub run_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub status: String,
|
||||
pub snapshot_version: u64,
|
||||
pub started_at_ms: u64,
|
||||
pub duration_limit_ms: u64,
|
||||
pub remaining_ms: u64,
|
||||
pub total_shape_count: u32,
|
||||
pub completed_shape_count: u32,
|
||||
pub combo: u32,
|
||||
pub best_combo: u32,
|
||||
pub score: u32,
|
||||
pub rule_label: String,
|
||||
#[serde(default)]
|
||||
pub current_shape: Option<SquareHoleShapeSnapshotResponse>,
|
||||
pub holes: Vec<SquareHoleHoleSnapshotResponse>,
|
||||
#[serde(default)]
|
||||
pub last_feedback: Option<SquareHoleDropFeedbackResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleRunResponse {
|
||||
pub run: SquareHoleRunSnapshotResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleDropResponse {
|
||||
pub feedback: SquareHoleDropFeedbackResponse,
|
||||
pub run: SquareHoleRunSnapshotResponse,
|
||||
}
|
||||
66
server-rs/crates/shared-contracts/src/square_hole_works.rs
Normal file
66
server-rs/crates/shared-contracts/src/square_hole_works.rs
Normal file
@@ -0,0 +1,66 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PutSquareHoleWorkRequest {
|
||||
pub game_name: String,
|
||||
#[serde(default)]
|
||||
pub theme_text: Option<String>,
|
||||
pub twist_rule: String,
|
||||
pub summary: String,
|
||||
pub tags: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
pub shape_count: u32,
|
||||
pub difficulty: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleWorkSummaryResponse {
|
||||
pub work_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
#[serde(default)]
|
||||
pub source_session_id: Option<String>,
|
||||
pub game_name: String,
|
||||
pub theme_text: String,
|
||||
pub twist_rule: String,
|
||||
pub summary: String,
|
||||
pub tags: Vec<String>,
|
||||
#[serde(default)]
|
||||
pub cover_image_src: Option<String>,
|
||||
pub shape_count: u32,
|
||||
pub difficulty: u32,
|
||||
pub publication_status: String,
|
||||
pub play_count: u32,
|
||||
pub updated_at: String,
|
||||
#[serde(default)]
|
||||
pub published_at: Option<String>,
|
||||
pub publish_ready: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleWorkProfileResponse {
|
||||
#[serde(flatten)]
|
||||
pub summary: SquareHoleWorkSummaryResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleWorksResponse {
|
||||
pub items: Vec<SquareHoleWorkSummaryResponse>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleWorkDetailResponse {
|
||||
pub item: SquareHoleWorkProfileResponse,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SquareHoleWorkMutationResponse {
|
||||
pub item: SquareHoleWorkProfileResponse,
|
||||
}
|
||||
@@ -17,6 +17,7 @@ module-puzzle = { path = "../module-puzzle" }
|
||||
module-runtime = { path = "../module-runtime" }
|
||||
module-runtime-story = { path = "../module-runtime-story" }
|
||||
module-runtime-item = { path = "../module-runtime-item" }
|
||||
module-square-hole = { path = "../module-square-hole" }
|
||||
module-story = { path = "../module-story" }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
|
||||
@@ -51,6 +51,15 @@ pub use mapper::{
|
||||
PuzzleSelectCoverImageRecordInput, PuzzleWorkLikeReportRecordInput,
|
||||
PuzzleWorkPointIncentiveClaimRecordInput, PuzzleWorkProfileRecord, PuzzleWorkRemixRecordInput,
|
||||
PuzzleWorkUpsertRecordInput, ResolveCombatActionRecord, ResolveNpcBattleInteractionInput,
|
||||
SquareHoleAgentMessageFinalizeRecordInput, SquareHoleAgentMessageRecord,
|
||||
SquareHoleAgentMessageSubmitRecordInput, SquareHoleAgentSessionCreateRecordInput,
|
||||
SquareHoleAgentSessionRecord, SquareHoleAnchorItemRecord, SquareHoleAnchorPackRecord,
|
||||
SquareHoleCompileDraftRecordInput, SquareHoleCreatorConfigRecord,
|
||||
SquareHoleDropConfirmationRecord, SquareHoleDropFeedbackRecord, SquareHoleHoleSnapshotRecord,
|
||||
SquareHoleResultDraftRecord, SquareHoleRunDropRecordInput, SquareHoleRunRecord,
|
||||
SquareHoleRunRestartRecordInput, SquareHoleRunStartRecordInput, SquareHoleRunStopRecordInput,
|
||||
SquareHoleRunTimeUpRecordInput, SquareHoleShapeSnapshotRecord, SquareHoleWorkProfileRecord,
|
||||
SquareHoleWorkUpdateRecordInput,
|
||||
};
|
||||
|
||||
pub mod ai;
|
||||
@@ -64,6 +73,7 @@ pub mod match3d;
|
||||
pub mod npc;
|
||||
pub mod puzzle;
|
||||
pub mod runtime;
|
||||
pub mod square_hole;
|
||||
pub mod story;
|
||||
pub mod story_runtime;
|
||||
|
||||
|
||||
@@ -1575,6 +1575,110 @@ pub(crate) fn map_match3d_click_item_procedure_result(
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn map_square_hole_agent_session_procedure_result(
|
||||
result: SquareHoleAgentSessionProcedureResult,
|
||||
) -> Result<SquareHoleAgentSessionRecord, SpacetimeClientError> {
|
||||
if !result.ok {
|
||||
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||
}
|
||||
|
||||
let session_json = result
|
||||
.session_json
|
||||
.ok_or_else(|| SpacetimeClientError::missing_snapshot("square hole agent session 快照"))?;
|
||||
let session =
|
||||
serde_json::from_str::<SquareHoleAgentSessionJsonRecord>(&session_json).map_err(
|
||||
|error| {
|
||||
SpacetimeClientError::Runtime(format!(
|
||||
"square hole session_json 非法: {error}"
|
||||
))
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(map_square_hole_agent_session_snapshot(session))
|
||||
}
|
||||
|
||||
pub(crate) fn map_square_hole_work_procedure_result(
|
||||
result: SquareHoleWorkProcedureResult,
|
||||
) -> Result<SquareHoleWorkProfileRecord, SpacetimeClientError> {
|
||||
if !result.ok {
|
||||
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||
}
|
||||
|
||||
let work_json = result
|
||||
.work_json
|
||||
.ok_or_else(|| SpacetimeClientError::missing_snapshot("square hole work 快照"))?;
|
||||
let work = serde_json::from_str::<SquareHoleWorkJsonRecord>(&work_json).map_err(|error| {
|
||||
SpacetimeClientError::Runtime(format!("square hole work_json 非法: {error}"))
|
||||
})?;
|
||||
|
||||
Ok(map_square_hole_work_snapshot(work))
|
||||
}
|
||||
|
||||
pub(crate) fn map_square_hole_works_procedure_result(
|
||||
result: SquareHoleWorksProcedureResult,
|
||||
) -> Result<Vec<SquareHoleWorkProfileRecord>, SpacetimeClientError> {
|
||||
if !result.ok {
|
||||
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||
}
|
||||
|
||||
let items_json = result
|
||||
.items_json
|
||||
.ok_or_else(|| SpacetimeClientError::missing_snapshot("square hole works 快照"))?;
|
||||
let items = serde_json::from_str::<Vec<SquareHoleWorkJsonRecord>>(&items_json).map_err(
|
||||
|error| {
|
||||
SpacetimeClientError::Runtime(format!("square hole works items_json 非法: {error}"))
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(items.into_iter().map(map_square_hole_work_snapshot).collect())
|
||||
}
|
||||
|
||||
pub(crate) fn map_square_hole_run_procedure_result(
|
||||
result: SquareHoleRunProcedureResult,
|
||||
) -> Result<SquareHoleRunRecord, SpacetimeClientError> {
|
||||
if !result.ok {
|
||||
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||
}
|
||||
|
||||
let run_json = result
|
||||
.run_json
|
||||
.ok_or_else(|| SpacetimeClientError::missing_snapshot("square hole run 快照"))?;
|
||||
map_square_hole_run_json(run_json)
|
||||
}
|
||||
|
||||
pub(crate) fn map_square_hole_drop_shape_procedure_result(
|
||||
result: SquareHoleDropShapeProcedureResult,
|
||||
) -> Result<SquareHoleDropConfirmationRecord, SpacetimeClientError> {
|
||||
if !result.ok {
|
||||
return Err(SpacetimeClientError::procedure_failed(result.error_message));
|
||||
}
|
||||
|
||||
let run_json = result
|
||||
.run_json
|
||||
.ok_or_else(|| SpacetimeClientError::missing_snapshot("square hole drop run 快照"))?;
|
||||
let feedback_json = result.feedback_json.ok_or_else(|| {
|
||||
SpacetimeClientError::missing_snapshot("square hole drop feedback 快照")
|
||||
})?;
|
||||
let run = map_square_hole_run_json(run_json)?;
|
||||
let feedback =
|
||||
serde_json::from_str::<SquareHoleDropFeedbackJsonRecord>(&feedback_json).map_err(
|
||||
|error| {
|
||||
SpacetimeClientError::Runtime(format!(
|
||||
"square hole feedback_json 非法: {error}"
|
||||
))
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(SquareHoleDropConfirmationRecord {
|
||||
status: result.status,
|
||||
accepted: feedback.accepted,
|
||||
reject_reason: feedback.reject_reason.clone(),
|
||||
failure_reason: result.failure_reason,
|
||||
feedback: map_square_hole_feedback_snapshot(feedback),
|
||||
run,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn map_story_session_procedure_result(
|
||||
result: StorySessionProcedureResult,
|
||||
) -> Result<StorySessionResultRecord, SpacetimeClientError> {
|
||||
@@ -2815,6 +2919,198 @@ fn build_match3d_anchor_item(key: &str, label: &str, value: &str) -> Match3DAnch
|
||||
}
|
||||
}
|
||||
|
||||
fn map_square_hole_agent_session_snapshot(
|
||||
snapshot: SquareHoleAgentSessionJsonRecord,
|
||||
) -> SquareHoleAgentSessionRecord {
|
||||
let config = map_square_hole_creator_config(snapshot.config);
|
||||
SquareHoleAgentSessionRecord {
|
||||
session_id: snapshot.session_id,
|
||||
current_turn: snapshot.current_turn,
|
||||
progress_percent: snapshot.progress_percent,
|
||||
stage: normalize_square_hole_stage(&snapshot.stage).to_string(),
|
||||
anchor_pack: build_square_hole_anchor_pack(&config),
|
||||
config,
|
||||
draft: snapshot.draft.map(map_square_hole_result_draft),
|
||||
messages: snapshot
|
||||
.messages
|
||||
.into_iter()
|
||||
.map(map_square_hole_agent_message_snapshot)
|
||||
.collect(),
|
||||
last_assistant_reply: empty_string_to_none(snapshot.last_assistant_reply),
|
||||
published_profile_id: snapshot.published_profile_id,
|
||||
updated_at: format_timestamp_micros(snapshot.updated_at_micros),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_square_hole_creator_config(
|
||||
snapshot: SquareHoleCreatorConfigJsonRecord,
|
||||
) -> SquareHoleCreatorConfigRecord {
|
||||
SquareHoleCreatorConfigRecord {
|
||||
theme_text: snapshot.theme_text,
|
||||
twist_rule: snapshot.twist_rule,
|
||||
shape_count: snapshot.shape_count,
|
||||
difficulty: snapshot.difficulty,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_square_hole_result_draft(
|
||||
snapshot: SquareHoleDraftJsonRecord,
|
||||
) -> SquareHoleResultDraftRecord {
|
||||
SquareHoleResultDraftRecord {
|
||||
profile_id: snapshot.profile_id,
|
||||
game_name: snapshot.game_name,
|
||||
theme_text: snapshot.theme_text,
|
||||
twist_rule: snapshot.twist_rule,
|
||||
summary: snapshot.summary_text,
|
||||
tags: snapshot.tags,
|
||||
shape_count: snapshot.shape_count,
|
||||
difficulty: snapshot.difficulty,
|
||||
publish_ready: false,
|
||||
blockers: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_square_hole_agent_message_snapshot(
|
||||
snapshot: SquareHoleAgentMessageJsonRecord,
|
||||
) -> SquareHoleAgentMessageRecord {
|
||||
SquareHoleAgentMessageRecord {
|
||||
id: snapshot.message_id,
|
||||
role: snapshot.role,
|
||||
kind: normalize_square_hole_message_kind(&snapshot.kind).to_string(),
|
||||
text: snapshot.text,
|
||||
created_at: format_timestamp_micros(snapshot.created_at_micros),
|
||||
}
|
||||
}
|
||||
|
||||
fn map_square_hole_work_snapshot(
|
||||
snapshot: SquareHoleWorkJsonRecord,
|
||||
) -> SquareHoleWorkProfileRecord {
|
||||
SquareHoleWorkProfileRecord {
|
||||
work_id: snapshot.work_id,
|
||||
profile_id: snapshot.profile_id,
|
||||
owner_user_id: snapshot.owner_user_id,
|
||||
source_session_id: empty_string_to_none(snapshot.source_session_id),
|
||||
author_display_name: snapshot.author_display_name,
|
||||
game_name: snapshot.game_name,
|
||||
theme_text: snapshot.theme_text,
|
||||
twist_rule: snapshot.twist_rule,
|
||||
summary: snapshot.summary_text,
|
||||
tags: snapshot.tags,
|
||||
cover_image_src: empty_string_to_none(snapshot.cover_image_src),
|
||||
shape_count: snapshot.shape_count,
|
||||
difficulty: snapshot.difficulty,
|
||||
publication_status: normalize_square_hole_publication_status(&snapshot.publication_status)
|
||||
.to_string(),
|
||||
play_count: snapshot.play_count,
|
||||
updated_at: format_timestamp_micros(snapshot.updated_at_micros),
|
||||
published_at: snapshot.published_at_micros.map(format_timestamp_micros),
|
||||
publish_ready: snapshot.publish_ready,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_square_hole_run_json(run_json: String) -> Result<SquareHoleRunRecord, SpacetimeClientError> {
|
||||
let run = serde_json::from_str::<SquareHoleRunJsonRecord>(&run_json).map_err(|error| {
|
||||
SpacetimeClientError::Runtime(format!("square hole run_json 非法: {error}"))
|
||||
})?;
|
||||
Ok(map_square_hole_run_snapshot(run))
|
||||
}
|
||||
|
||||
fn map_square_hole_run_snapshot(snapshot: SquareHoleRunJsonRecord) -> SquareHoleRunRecord {
|
||||
SquareHoleRunRecord {
|
||||
run_id: snapshot.run_id,
|
||||
profile_id: snapshot.profile_id,
|
||||
owner_user_id: snapshot.owner_user_id,
|
||||
status: normalize_square_hole_run_status(&snapshot.status).to_string(),
|
||||
snapshot_version: snapshot.snapshot_version,
|
||||
started_at_ms: i64_to_u64_ms(snapshot.started_at_ms),
|
||||
duration_limit_ms: i64_to_u64_ms(snapshot.duration_limit_ms),
|
||||
server_now_ms: Some(i64_to_u64_ms(snapshot.server_now_ms)),
|
||||
remaining_ms: i64_to_u64_ms(snapshot.remaining_ms),
|
||||
total_shape_count: snapshot.total_shape_count,
|
||||
completed_shape_count: snapshot.completed_shape_count,
|
||||
combo: snapshot.combo,
|
||||
best_combo: snapshot.best_combo,
|
||||
score: snapshot.score,
|
||||
rule_label: snapshot.rule_label,
|
||||
current_shape: snapshot.current_shape.map(map_square_hole_shape_snapshot),
|
||||
holes: snapshot
|
||||
.holes
|
||||
.into_iter()
|
||||
.map(map_square_hole_hole_snapshot)
|
||||
.collect(),
|
||||
last_feedback: snapshot
|
||||
.last_feedback
|
||||
.map(map_square_hole_feedback_snapshot),
|
||||
last_confirmed_action_id: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_square_hole_shape_snapshot(
|
||||
snapshot: SquareHoleShapeJsonRecord,
|
||||
) -> SquareHoleShapeSnapshotRecord {
|
||||
SquareHoleShapeSnapshotRecord {
|
||||
shape_id: snapshot.shape_id,
|
||||
shape_kind: snapshot.shape_kind,
|
||||
label: snapshot.label,
|
||||
color: snapshot.color,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_square_hole_hole_snapshot(
|
||||
snapshot: SquareHoleHoleJsonRecord,
|
||||
) -> SquareHoleHoleSnapshotRecord {
|
||||
SquareHoleHoleSnapshotRecord {
|
||||
hole_id: snapshot.hole_id,
|
||||
hole_kind: snapshot.hole_kind,
|
||||
label: snapshot.label,
|
||||
x: snapshot.x,
|
||||
y: snapshot.y,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_square_hole_feedback_snapshot(
|
||||
snapshot: SquareHoleDropFeedbackJsonRecord,
|
||||
) -> SquareHoleDropFeedbackRecord {
|
||||
SquareHoleDropFeedbackRecord {
|
||||
accepted: snapshot.accepted,
|
||||
reject_reason: snapshot
|
||||
.reject_reason
|
||||
.map(|value| normalize_square_hole_reject_reason(&value).to_string()),
|
||||
message: snapshot.message,
|
||||
}
|
||||
}
|
||||
|
||||
fn build_square_hole_anchor_pack(
|
||||
config: &SquareHoleCreatorConfigRecord,
|
||||
) -> SquareHoleAnchorPackRecord {
|
||||
let shape_count = config.shape_count.to_string();
|
||||
let difficulty = config.difficulty.to_string();
|
||||
SquareHoleAnchorPackRecord {
|
||||
theme: build_square_hole_anchor_item("theme", "题材主题", config.theme_text.as_str()),
|
||||
twist_rule: build_square_hole_anchor_item("twistRule", "反差规则", config.twist_rule.as_str()),
|
||||
shape_count: build_square_hole_anchor_item("shapeCount", "形状数量", shape_count.as_str()),
|
||||
difficulty: build_square_hole_anchor_item("difficulty", "难度", difficulty.as_str()),
|
||||
}
|
||||
}
|
||||
|
||||
fn build_square_hole_anchor_item(
|
||||
key: &str,
|
||||
label: &str,
|
||||
value: &str,
|
||||
) -> SquareHoleAnchorItemRecord {
|
||||
SquareHoleAnchorItemRecord {
|
||||
key: key.to_string(),
|
||||
label: label.to_string(),
|
||||
value: value.to_string(),
|
||||
status: if value.trim().is_empty() {
|
||||
"missing"
|
||||
} else {
|
||||
"confirmed"
|
||||
}
|
||||
.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_match3d_stage(value: &str) -> &str {
|
||||
match value {
|
||||
"Collecting" | "collecting" | "collecting_config" => "collecting_config",
|
||||
@@ -2840,6 +3136,54 @@ fn normalize_match3d_message_kind(value: &str) -> &str {
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_square_hole_stage(value: &str) -> &str {
|
||||
match value {
|
||||
"Collecting" | "CollectingConfig" | "collecting" | "collecting_config" => {
|
||||
"collecting_config"
|
||||
}
|
||||
"ReadyToCompile" | "ready_to_compile" => "ready_to_compile",
|
||||
"DraftCompiled" | "DraftReady" | "draft_compiled" | "draft_ready" => "draft_ready",
|
||||
"Published" | "published" => "published",
|
||||
_ => value,
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_square_hole_publication_status(value: &str) -> &str {
|
||||
match value {
|
||||
"Draft" | "draft" => "draft",
|
||||
"Published" | "published" => "published",
|
||||
_ => value,
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_square_hole_run_status(value: &str) -> &str {
|
||||
match value {
|
||||
"Running" | "running" => "running",
|
||||
"Won" | "won" => "won",
|
||||
"Failed" | "failed" => "failed",
|
||||
"Stopped" | "stopped" => "stopped",
|
||||
_ => value,
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_square_hole_message_kind(value: &str) -> &str {
|
||||
match value {
|
||||
"text" => "chat",
|
||||
_ => value,
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_square_hole_reject_reason(value: &str) -> &str {
|
||||
match value {
|
||||
"RunNotActive" | "run_not_active" => "run_not_active",
|
||||
"SnapshotVersionMismatch" | "snapshot_version_mismatch" => "snapshot_version_mismatch",
|
||||
"HoleNotFound" | "hole_not_found" => "hole_not_found",
|
||||
"Incompatible" | "incompatible" => "incompatible",
|
||||
"TimeUp" | "time_up" => "time_up",
|
||||
_ => value,
|
||||
}
|
||||
}
|
||||
|
||||
fn empty_string_to_none(value: String) -> Option<String> {
|
||||
let trimmed = value.trim();
|
||||
if trimmed.is_empty() {
|
||||
@@ -5592,6 +5936,378 @@ struct Match3DRunJsonRecord {
|
||||
failure_reason: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleAgentSessionCreateRecordInput {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub seed_text: String,
|
||||
pub welcome_message_id: String,
|
||||
pub welcome_message_text: String,
|
||||
pub config_json: Option<String>,
|
||||
pub created_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleAgentMessageSubmitRecordInput {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub user_message_id: String,
|
||||
pub user_message_text: String,
|
||||
pub submitted_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleAgentMessageFinalizeRecordInput {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub assistant_message_id: Option<String>,
|
||||
pub assistant_reply_text: Option<String>,
|
||||
pub config_json: Option<String>,
|
||||
pub progress_percent: u32,
|
||||
pub stage: String,
|
||||
pub updated_at_micros: i64,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleCompileDraftRecordInput {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub profile_id: String,
|
||||
pub author_display_name: String,
|
||||
pub game_name: Option<String>,
|
||||
pub summary_text: Option<String>,
|
||||
pub tags_json: Option<String>,
|
||||
pub cover_image_src: Option<String>,
|
||||
pub compiled_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleWorkUpdateRecordInput {
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub game_name: String,
|
||||
pub theme_text: String,
|
||||
pub twist_rule: String,
|
||||
pub summary_text: String,
|
||||
pub tags_json: String,
|
||||
pub cover_image_src: String,
|
||||
pub shape_count: u32,
|
||||
pub difficulty: u32,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleRunStartRecordInput {
|
||||
pub run_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub profile_id: String,
|
||||
pub started_at_ms: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleRunDropRecordInput {
|
||||
pub run_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub hole_id: String,
|
||||
pub client_snapshot_version: u64,
|
||||
pub client_event_id: String,
|
||||
pub dropped_at_ms: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleRunStopRecordInput {
|
||||
pub run_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub stopped_at_ms: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleRunRestartRecordInput {
|
||||
pub source_run_id: String,
|
||||
pub next_run_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub restarted_at_ms: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleRunTimeUpRecordInput {
|
||||
pub run_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub finished_at_ms: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleAnchorItemRecord {
|
||||
pub key: String,
|
||||
pub label: String,
|
||||
pub value: String,
|
||||
pub status: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleAnchorPackRecord {
|
||||
pub theme: SquareHoleAnchorItemRecord,
|
||||
pub twist_rule: SquareHoleAnchorItemRecord,
|
||||
pub shape_count: SquareHoleAnchorItemRecord,
|
||||
pub difficulty: SquareHoleAnchorItemRecord,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleCreatorConfigRecord {
|
||||
pub theme_text: String,
|
||||
pub twist_rule: String,
|
||||
pub shape_count: u32,
|
||||
pub difficulty: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleResultDraftRecord {
|
||||
pub profile_id: String,
|
||||
pub game_name: String,
|
||||
pub theme_text: String,
|
||||
pub twist_rule: String,
|
||||
pub summary: String,
|
||||
pub tags: Vec<String>,
|
||||
pub shape_count: u32,
|
||||
pub difficulty: u32,
|
||||
pub publish_ready: bool,
|
||||
pub blockers: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleAgentMessageRecord {
|
||||
pub id: String,
|
||||
pub role: String,
|
||||
pub kind: String,
|
||||
pub text: String,
|
||||
pub created_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleAgentSessionRecord {
|
||||
pub session_id: String,
|
||||
pub current_turn: u32,
|
||||
pub progress_percent: u32,
|
||||
pub stage: String,
|
||||
pub anchor_pack: SquareHoleAnchorPackRecord,
|
||||
pub config: SquareHoleCreatorConfigRecord,
|
||||
pub draft: Option<SquareHoleResultDraftRecord>,
|
||||
pub messages: Vec<SquareHoleAgentMessageRecord>,
|
||||
pub last_assistant_reply: Option<String>,
|
||||
pub published_profile_id: Option<String>,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleWorkProfileRecord {
|
||||
pub work_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub source_session_id: Option<String>,
|
||||
pub author_display_name: String,
|
||||
pub game_name: String,
|
||||
pub theme_text: String,
|
||||
pub twist_rule: String,
|
||||
pub summary: String,
|
||||
pub tags: Vec<String>,
|
||||
pub cover_image_src: Option<String>,
|
||||
pub shape_count: u32,
|
||||
pub difficulty: u32,
|
||||
pub publication_status: String,
|
||||
pub play_count: u32,
|
||||
pub updated_at: String,
|
||||
pub published_at: Option<String>,
|
||||
pub publish_ready: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleShapeSnapshotRecord {
|
||||
pub shape_id: String,
|
||||
pub shape_kind: String,
|
||||
pub label: String,
|
||||
pub color: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct SquareHoleHoleSnapshotRecord {
|
||||
pub hole_id: String,
|
||||
pub hole_kind: String,
|
||||
pub label: String,
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SquareHoleDropFeedbackRecord {
|
||||
pub accepted: bool,
|
||||
pub reject_reason: Option<String>,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct SquareHoleRunRecord {
|
||||
pub run_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub status: String,
|
||||
pub snapshot_version: u64,
|
||||
pub started_at_ms: u64,
|
||||
pub duration_limit_ms: u64,
|
||||
pub server_now_ms: Option<u64>,
|
||||
pub remaining_ms: u64,
|
||||
pub total_shape_count: u32,
|
||||
pub completed_shape_count: u32,
|
||||
pub combo: u32,
|
||||
pub best_combo: u32,
|
||||
pub score: u32,
|
||||
pub rule_label: String,
|
||||
pub current_shape: Option<SquareHoleShapeSnapshotRecord>,
|
||||
pub holes: Vec<SquareHoleHoleSnapshotRecord>,
|
||||
pub last_feedback: Option<SquareHoleDropFeedbackRecord>,
|
||||
pub last_confirmed_action_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct SquareHoleDropConfirmationRecord {
|
||||
pub status: String,
|
||||
pub accepted: bool,
|
||||
pub reject_reason: Option<String>,
|
||||
pub failure_reason: Option<String>,
|
||||
pub feedback: SquareHoleDropFeedbackRecord,
|
||||
pub run: SquareHoleRunRecord,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct SquareHoleCreatorConfigJsonRecord {
|
||||
theme_text: String,
|
||||
twist_rule: String,
|
||||
shape_count: u32,
|
||||
difficulty: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct SquareHoleAgentMessageJsonRecord {
|
||||
message_id: String,
|
||||
#[allow(dead_code)]
|
||||
session_id: String,
|
||||
role: String,
|
||||
kind: String,
|
||||
text: String,
|
||||
created_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct SquareHoleDraftJsonRecord {
|
||||
profile_id: String,
|
||||
game_name: String,
|
||||
theme_text: String,
|
||||
twist_rule: String,
|
||||
summary_text: String,
|
||||
tags: Vec<String>,
|
||||
shape_count: u32,
|
||||
difficulty: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct SquareHoleAgentSessionJsonRecord {
|
||||
session_id: String,
|
||||
#[allow(dead_code)]
|
||||
owner_user_id: String,
|
||||
#[allow(dead_code)]
|
||||
seed_text: String,
|
||||
current_turn: u32,
|
||||
progress_percent: u32,
|
||||
stage: String,
|
||||
config: SquareHoleCreatorConfigJsonRecord,
|
||||
draft: Option<SquareHoleDraftJsonRecord>,
|
||||
messages: Vec<SquareHoleAgentMessageJsonRecord>,
|
||||
last_assistant_reply: String,
|
||||
published_profile_id: Option<String>,
|
||||
#[allow(dead_code)]
|
||||
created_at_micros: i64,
|
||||
updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct SquareHoleWorkJsonRecord {
|
||||
work_id: String,
|
||||
profile_id: String,
|
||||
owner_user_id: String,
|
||||
source_session_id: String,
|
||||
author_display_name: String,
|
||||
game_name: String,
|
||||
theme_text: String,
|
||||
twist_rule: String,
|
||||
summary_text: String,
|
||||
tags: Vec<String>,
|
||||
cover_image_src: String,
|
||||
shape_count: u32,
|
||||
difficulty: u32,
|
||||
#[allow(dead_code)]
|
||||
config: SquareHoleCreatorConfigJsonRecord,
|
||||
publication_status: String,
|
||||
publish_ready: bool,
|
||||
play_count: u32,
|
||||
updated_at_micros: i64,
|
||||
published_at_micros: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct SquareHoleShapeJsonRecord {
|
||||
shape_id: String,
|
||||
shape_kind: String,
|
||||
label: String,
|
||||
color: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct SquareHoleHoleJsonRecord {
|
||||
hole_id: String,
|
||||
hole_kind: String,
|
||||
label: String,
|
||||
x: f32,
|
||||
y: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct SquareHoleDropFeedbackJsonRecord {
|
||||
accepted: bool,
|
||||
reject_reason: Option<String>,
|
||||
message: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, serde::Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct SquareHoleRunJsonRecord {
|
||||
run_id: String,
|
||||
profile_id: String,
|
||||
owner_user_id: String,
|
||||
status: String,
|
||||
snapshot_version: u64,
|
||||
started_at_ms: i64,
|
||||
duration_limit_ms: i64,
|
||||
server_now_ms: i64,
|
||||
remaining_ms: i64,
|
||||
total_shape_count: u32,
|
||||
completed_shape_count: u32,
|
||||
combo: u32,
|
||||
best_combo: u32,
|
||||
score: u32,
|
||||
rule_label: String,
|
||||
current_shape: Option<SquareHoleShapeJsonRecord>,
|
||||
holes: Vec<SquareHoleHoleJsonRecord>,
|
||||
last_feedback: Option<SquareHoleDropFeedbackJsonRecord>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct PuzzleAnchorItemRecord {
|
||||
pub key: String,
|
||||
|
||||
@@ -47,9 +47,11 @@ pub trait accept_quest {
|
||||
&self,
|
||||
input: QuestRecordInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()>;
|
||||
}
|
||||
|
||||
@@ -58,9 +60,11 @@ impl accept_quest for super::RemoteReducers {
|
||||
&self,
|
||||
input: QuestRecordInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()> {
|
||||
self.imp
|
||||
.invoke_reducer_with_callback(AcceptQuestArgs { input }, callback)
|
||||
|
||||
@@ -47,9 +47,11 @@ pub trait acknowledge_quest_completion {
|
||||
&self,
|
||||
input: QuestCompletionAckInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()>;
|
||||
}
|
||||
|
||||
@@ -58,9 +60,11 @@ impl acknowledge_quest_completion for super::RemoteReducers {
|
||||
&self,
|
||||
input: QuestCompletionAckInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()> {
|
||||
self.imp
|
||||
.invoke_reducer_with_callback(AcknowledgeQuestCompletionArgs { input }, callback)
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait admin_disable_profile_redeem_code {
|
||||
input: RuntimeProfileRedeemCodeAdminDisableInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileRedeemCodeAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileRedeemCodeAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl admin_disable_profile_redeem_code for super::RemoteProcedures {
|
||||
input: RuntimeProfileRedeemCodeAdminDisableInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileRedeemCodeAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileRedeemCodeAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, RuntimeProfileRedeemCodeAdminProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait admin_disable_profile_task_config {
|
||||
input: RuntimeProfileTaskConfigAdminDisableInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileTaskConfigAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileTaskConfigAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl admin_disable_profile_task_config for super::RemoteProcedures {
|
||||
input: RuntimeProfileTaskConfigAdminDisableInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileTaskConfigAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileTaskConfigAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, RuntimeProfileTaskConfigAdminProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait admin_list_profile_invite_codes {
|
||||
input: RuntimeProfileInviteCodeAdminListInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileInviteCodeAdminListProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileInviteCodeAdminListProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl admin_list_profile_invite_codes for super::RemoteProcedures {
|
||||
input: RuntimeProfileInviteCodeAdminListInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileInviteCodeAdminListProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileInviteCodeAdminListProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, RuntimeProfileInviteCodeAdminListProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait admin_list_profile_redeem_codes {
|
||||
input: RuntimeProfileRedeemCodeAdminListInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileRedeemCodeAdminListProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileRedeemCodeAdminListProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl admin_list_profile_redeem_codes for super::RemoteProcedures {
|
||||
input: RuntimeProfileRedeemCodeAdminListInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileRedeemCodeAdminListProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileRedeemCodeAdminListProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, RuntimeProfileRedeemCodeAdminListProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait admin_list_profile_task_configs {
|
||||
input: RuntimeProfileTaskConfigAdminListInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileTaskConfigAdminListProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileTaskConfigAdminListProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl admin_list_profile_task_configs for super::RemoteProcedures {
|
||||
input: RuntimeProfileTaskConfigAdminListInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileTaskConfigAdminListProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileTaskConfigAdminListProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, RuntimeProfileTaskConfigAdminListProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait admin_upsert_profile_invite_code {
|
||||
input: RuntimeProfileInviteCodeAdminUpsertInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileInviteCodeAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileInviteCodeAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl admin_upsert_profile_invite_code for super::RemoteProcedures {
|
||||
input: RuntimeProfileInviteCodeAdminUpsertInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileInviteCodeAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileInviteCodeAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, RuntimeProfileInviteCodeAdminProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait admin_upsert_profile_redeem_code {
|
||||
input: RuntimeProfileRedeemCodeAdminUpsertInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileRedeemCodeAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileRedeemCodeAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl admin_upsert_profile_redeem_code for super::RemoteProcedures {
|
||||
input: RuntimeProfileRedeemCodeAdminUpsertInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileRedeemCodeAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileRedeemCodeAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, RuntimeProfileRedeemCodeAdminProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait admin_upsert_profile_task_config {
|
||||
input: RuntimeProfileTaskConfigAdminUpsertInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileTaskConfigAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileTaskConfigAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl admin_upsert_profile_task_config for super::RemoteProcedures {
|
||||
input: RuntimeProfileTaskConfigAdminUpsertInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileTaskConfigAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileTaskConfigAdminProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, RuntimeProfileTaskConfigAdminProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait advance_puzzle_next_level {
|
||||
input: PuzzleRunNextLevelInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleRunProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleRunProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl advance_puzzle_next_level for super::RemoteProcedures {
|
||||
input: PuzzleRunNextLevelInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleRunProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleRunProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, PuzzleRunProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait append_ai_text_chunk_and_return {
|
||||
input: AiTextChunkAppendInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl append_ai_text_chunk_and_return for super::RemoteProcedures {
|
||||
input: AiTextChunkAppendInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, AiTaskProcedureResult>(
|
||||
|
||||
@@ -34,10 +34,10 @@ pub trait apply_chapter_progression_ledger_entry_and_return {
|
||||
input: ChapterProgressionLedgerInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<ChapterProgressionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<ChapterProgressionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -47,10 +47,10 @@ impl apply_chapter_progression_ledger_entry_and_return for super::RemoteProcedur
|
||||
input: ChapterProgressionLedgerInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<ChapterProgressionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<ChapterProgressionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, ChapterProgressionProcedureResult>(
|
||||
|
||||
@@ -50,9 +50,11 @@ pub trait apply_chapter_progression_ledger_entry {
|
||||
&self,
|
||||
input: ChapterProgressionLedgerInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()>;
|
||||
}
|
||||
|
||||
@@ -61,9 +63,11 @@ impl apply_chapter_progression_ledger_entry for super::RemoteReducers {
|
||||
&self,
|
||||
input: ChapterProgressionLedgerInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()> {
|
||||
self.imp.invoke_reducer_with_callback(
|
||||
ApplyChapterProgressionLedgerEntryArgs { input },
|
||||
|
||||
@@ -47,9 +47,11 @@ pub trait apply_inventory_mutation {
|
||||
&self,
|
||||
input: InventoryMutationInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()>;
|
||||
}
|
||||
|
||||
@@ -58,9 +60,11 @@ impl apply_inventory_mutation for super::RemoteReducers {
|
||||
&self,
|
||||
input: InventoryMutationInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()> {
|
||||
self.imp
|
||||
.invoke_reducer_with_callback(ApplyInventoryMutationArgs { input }, callback)
|
||||
|
||||
@@ -47,9 +47,11 @@ pub trait apply_quest_signal {
|
||||
&self,
|
||||
input: QuestSignalApplyInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()>;
|
||||
}
|
||||
|
||||
@@ -58,9 +60,11 @@ impl apply_quest_signal for super::RemoteReducers {
|
||||
&self,
|
||||
input: QuestSignalApplyInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()> {
|
||||
self.imp
|
||||
.invoke_reducer_with_callback(ApplyQuestSignalArgs { input }, callback)
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait attach_ai_result_reference_and_return {
|
||||
input: AiResultReferenceInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl attach_ai_result_reference_and_return for super::RemoteProcedures {
|
||||
input: AiResultReferenceInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, AiTaskProcedureResult>(
|
||||
|
||||
@@ -34,10 +34,10 @@ pub trait authorize_database_migration_operator {
|
||||
input: DatabaseMigrationAuthorizeOperatorInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<DatabaseMigrationOperatorProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<DatabaseMigrationOperatorProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -47,10 +47,10 @@ impl authorize_database_migration_operator for super::RemoteProcedures {
|
||||
input: DatabaseMigrationAuthorizeOperatorInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<DatabaseMigrationOperatorProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<DatabaseMigrationOperatorProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, DatabaseMigrationOperatorProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait begin_story_session_and_return {
|
||||
input: StorySessionInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<StorySessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<StorySessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl begin_story_session_and_return for super::RemoteProcedures {
|
||||
input: StorySessionInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<StorySessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<StorySessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, StorySessionProcedureResult>(
|
||||
|
||||
@@ -47,9 +47,11 @@ pub trait begin_story_session {
|
||||
&self,
|
||||
input: StorySessionInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()>;
|
||||
}
|
||||
|
||||
@@ -58,9 +60,11 @@ impl begin_story_session for super::RemoteReducers {
|
||||
&self,
|
||||
input: StorySessionInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()> {
|
||||
self.imp
|
||||
.invoke_reducer_with_callback(BeginStorySessionArgs { input }, callback)
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait bind_asset_object_to_entity_and_return {
|
||||
input: AssetEntityBindingInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AssetEntityBindingProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AssetEntityBindingProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl bind_asset_object_to_entity_and_return for super::RemoteProcedures {
|
||||
input: AssetEntityBindingInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AssetEntityBindingProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AssetEntityBindingProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, AssetEntityBindingProcedureResult>(
|
||||
|
||||
@@ -47,9 +47,11 @@ pub trait bind_asset_object_to_entity {
|
||||
&self,
|
||||
input: AssetEntityBindingInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()>;
|
||||
}
|
||||
|
||||
@@ -58,9 +60,11 @@ impl bind_asset_object_to_entity for super::RemoteReducers {
|
||||
&self,
|
||||
input: AssetEntityBindingInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()> {
|
||||
self.imp
|
||||
.invoke_reducer_with_callback(BindAssetObjectToEntityArgs { input }, callback)
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait cancel_ai_task_and_return {
|
||||
input: AiTaskCancelInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl cancel_ai_task_and_return for super::RemoteProcedures {
|
||||
input: AiTaskCancelInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, AiTaskProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait claim_profile_task_reward_and_return {
|
||||
input: RuntimeProfileTaskClaimInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileTaskClaimProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileTaskClaimProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl claim_profile_task_reward_and_return for super::RemoteProcedures {
|
||||
input: RuntimeProfileTaskClaimInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileTaskClaimProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileTaskClaimProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, RuntimeProfileTaskClaimProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait claim_puzzle_work_point_incentive {
|
||||
input: PuzzleWorkPointIncentiveClaimInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleWorkProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleWorkProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl claim_puzzle_work_point_incentive for super::RemoteProcedures {
|
||||
input: PuzzleWorkPointIncentiveClaimInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleWorkProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleWorkProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, PuzzleWorkProcedureResult>(
|
||||
|
||||
@@ -34,10 +34,10 @@ pub trait clear_database_migration_import_chunks {
|
||||
input: DatabaseMigrationImportChunksClearInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<DatabaseMigrationProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<DatabaseMigrationProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -47,10 +47,10 @@ impl clear_database_migration_import_chunks for super::RemoteProcedures {
|
||||
input: DatabaseMigrationImportChunksClearInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<DatabaseMigrationProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<DatabaseMigrationProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, DatabaseMigrationProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait clear_platform_browse_history_and_return {
|
||||
input: RuntimeBrowseHistoryClearInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeBrowseHistoryProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeBrowseHistoryProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl clear_platform_browse_history_and_return for super::RemoteProcedures {
|
||||
input: RuntimeBrowseHistoryClearInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeBrowseHistoryProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeBrowseHistoryProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, RuntimeBrowseHistoryProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait click_match_3_d_item {
|
||||
input: Match3DRunClickInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<Match3DClickItemProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<Match3DClickItemProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl click_match_3_d_item for super::RemoteProcedures {
|
||||
input: Match3DRunClickInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<Match3DClickItemProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<Match3DClickItemProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, Match3DClickItemProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait compile_big_fish_draft {
|
||||
input: BigFishDraftCompileInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<BigFishSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<BigFishSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl compile_big_fish_draft for super::RemoteProcedures {
|
||||
input: BigFishDraftCompileInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<BigFishSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<BigFishSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, BigFishSessionProcedureResult>(
|
||||
|
||||
@@ -34,10 +34,10 @@ pub trait compile_custom_world_published_profile {
|
||||
input: CustomWorldPublishedProfileCompileInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldPublishedProfileCompileResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldPublishedProfileCompileResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -47,10 +47,10 @@ impl compile_custom_world_published_profile for super::RemoteProcedures {
|
||||
input: CustomWorldPublishedProfileCompileInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldPublishedProfileCompileResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldPublishedProfileCompileResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, CustomWorldPublishedProfileCompileResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait compile_match_3_d_draft {
|
||||
input: Match3DDraftCompileInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<Match3DAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<Match3DAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl compile_match_3_d_draft for super::RemoteProcedures {
|
||||
input: Match3DDraftCompileInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<Match3DAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<Match3DAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, Match3DAgentSessionProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait compile_puzzle_agent_draft {
|
||||
input: PuzzleDraftCompileInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl compile_puzzle_agent_draft for super::RemoteProcedures {
|
||||
input: PuzzleDraftCompileInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, PuzzleAgentSessionProcedureResult>(
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::square_hole_agent_session_procedure_result_type::SquareHoleAgentSessionProcedureResult;
|
||||
use super::square_hole_draft_compile_input_type::SquareHoleDraftCompileInput;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
struct CompileSquareHoleDraftArgs {
|
||||
pub input: SquareHoleDraftCompileInput,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for CompileSquareHoleDraftArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the procedure `compile_square_hole_draft`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteProcedures`].
|
||||
pub trait compile_square_hole_draft {
|
||||
fn compile_square_hole_draft(&self, input: SquareHoleDraftCompileInput) {
|
||||
self.compile_square_hole_draft_then(input, |_, _| {});
|
||||
}
|
||||
|
||||
fn compile_square_hole_draft_then(
|
||||
&self,
|
||||
input: SquareHoleDraftCompileInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<SquareHoleAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
impl compile_square_hole_draft for super::RemoteProcedures {
|
||||
fn compile_square_hole_draft_then(
|
||||
&self,
|
||||
input: SquareHoleDraftCompileInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<SquareHoleAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, SquareHoleAgentSessionProcedureResult>(
|
||||
"compile_square_hole_draft",
|
||||
CompileSquareHoleDraftArgs { input },
|
||||
__callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -31,10 +31,10 @@ pub trait complete_ai_stage_and_return {
|
||||
input: AiStageCompletionInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl complete_ai_stage_and_return for super::RemoteProcedures {
|
||||
input: AiStageCompletionInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, AiTaskProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait complete_ai_task_and_return {
|
||||
input: AiTaskFinishInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl complete_ai_task_and_return for super::RemoteProcedures {
|
||||
input: AiTaskFinishInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, AiTaskProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait confirm_asset_object_and_return {
|
||||
input: AssetObjectUpsertInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AssetObjectProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AssetObjectProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl confirm_asset_object_and_return for super::RemoteProcedures {
|
||||
input: AssetObjectUpsertInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AssetObjectProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AssetObjectProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, AssetObjectProcedureResult>(
|
||||
|
||||
@@ -47,9 +47,11 @@ pub trait confirm_asset_object {
|
||||
&self,
|
||||
input: AssetObjectUpsertInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()>;
|
||||
}
|
||||
|
||||
@@ -58,9 +60,11 @@ impl confirm_asset_object for super::RemoteReducers {
|
||||
&self,
|
||||
input: AssetObjectUpsertInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()> {
|
||||
self.imp
|
||||
.invoke_reducer_with_callback(ConfirmAssetObjectArgs { input }, callback)
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait consume_profile_wallet_points_and_return {
|
||||
input: RuntimeProfileWalletAdjustmentInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileWalletAdjustmentProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileWalletAdjustmentProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl consume_profile_wallet_points_and_return for super::RemoteProcedures {
|
||||
input: RuntimeProfileWalletAdjustmentInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileWalletAdjustmentProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileWalletAdjustmentProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, RuntimeProfileWalletAdjustmentProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait continue_story_and_return {
|
||||
input: StoryContinueInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<StorySessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<StorySessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl continue_story_and_return for super::RemoteProcedures {
|
||||
input: StoryContinueInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<StorySessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<StorySessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, StorySessionProcedureResult>(
|
||||
|
||||
@@ -47,9 +47,11 @@ pub trait continue_story {
|
||||
&self,
|
||||
input: StoryContinueInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()>;
|
||||
}
|
||||
|
||||
@@ -58,9 +60,11 @@ impl continue_story for super::RemoteReducers {
|
||||
&self,
|
||||
input: StoryContinueInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()> {
|
||||
self.imp
|
||||
.invoke_reducer_with_callback(ContinueStoryArgs { input }, callback)
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait create_ai_task_and_return {
|
||||
input: AiTaskCreateInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl create_ai_task_and_return for super::RemoteProcedures {
|
||||
input: AiTaskCreateInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, AiTaskProcedureResult>(
|
||||
|
||||
@@ -47,9 +47,11 @@ pub trait create_ai_task {
|
||||
&self,
|
||||
input: AiTaskCreateInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()>;
|
||||
}
|
||||
|
||||
@@ -58,9 +60,11 @@ impl create_ai_task for super::RemoteReducers {
|
||||
&self,
|
||||
input: AiTaskCreateInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()> {
|
||||
self.imp
|
||||
.invoke_reducer_with_callback(CreateAiTaskArgs { input }, callback)
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait create_battle_state_and_return {
|
||||
input: BattleStateInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<BattleStateProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<BattleStateProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl create_battle_state_and_return for super::RemoteProcedures {
|
||||
input: BattleStateInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<BattleStateProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<BattleStateProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, BattleStateProcedureResult>(
|
||||
|
||||
@@ -47,9 +47,11 @@ pub trait create_battle_state {
|
||||
&self,
|
||||
input: BattleStateInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()>;
|
||||
}
|
||||
|
||||
@@ -58,9 +60,11 @@ impl create_battle_state for super::RemoteReducers {
|
||||
&self,
|
||||
input: BattleStateInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()> {
|
||||
self.imp
|
||||
.invoke_reducer_with_callback(CreateBattleStateArgs { input }, callback)
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait create_big_fish_session {
|
||||
input: BigFishSessionCreateInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<BigFishSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<BigFishSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl create_big_fish_session for super::RemoteProcedures {
|
||||
input: BigFishSessionCreateInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<BigFishSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<BigFishSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, BigFishSessionProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait create_custom_world_agent_session {
|
||||
input: CustomWorldAgentSessionCreateInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl create_custom_world_agent_session for super::RemoteProcedures {
|
||||
input: CustomWorldAgentSessionCreateInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, CustomWorldAgentSessionProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait create_match_3_d_agent_session {
|
||||
input: Match3DAgentSessionCreateInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<Match3DAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<Match3DAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl create_match_3_d_agent_session for super::RemoteProcedures {
|
||||
input: Match3DAgentSessionCreateInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<Match3DAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<Match3DAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, Match3DAgentSessionProcedureResult>(
|
||||
|
||||
@@ -34,10 +34,10 @@ pub trait create_profile_recharge_order_and_return {
|
||||
input: RuntimeProfileRechargeOrderCreateInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileRechargeCenterProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileRechargeCenterProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -47,10 +47,10 @@ impl create_profile_recharge_order_and_return for super::RemoteProcedures {
|
||||
input: RuntimeProfileRechargeOrderCreateInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileRechargeCenterProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeProfileRechargeCenterProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, RuntimeProfileRechargeCenterProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait create_puzzle_agent_session {
|
||||
input: PuzzleAgentSessionCreateInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl create_puzzle_agent_session for super::RemoteProcedures {
|
||||
input: PuzzleAgentSessionCreateInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, PuzzleAgentSessionProcedureResult>(
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::square_hole_agent_session_create_input_type::SquareHoleAgentSessionCreateInput;
|
||||
use super::square_hole_agent_session_procedure_result_type::SquareHoleAgentSessionProcedureResult;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
struct CreateSquareHoleAgentSessionArgs {
|
||||
pub input: SquareHoleAgentSessionCreateInput,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for CreateSquareHoleAgentSessionArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the procedure `create_square_hole_agent_session`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteProcedures`].
|
||||
pub trait create_square_hole_agent_session {
|
||||
fn create_square_hole_agent_session(&self, input: SquareHoleAgentSessionCreateInput) {
|
||||
self.create_square_hole_agent_session_then(input, |_, _| {});
|
||||
}
|
||||
|
||||
fn create_square_hole_agent_session_then(
|
||||
&self,
|
||||
input: SquareHoleAgentSessionCreateInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<SquareHoleAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
impl create_square_hole_agent_session for super::RemoteProcedures {
|
||||
fn create_square_hole_agent_session_then(
|
||||
&self,
|
||||
input: SquareHoleAgentSessionCreateInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<SquareHoleAgentSessionProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, SquareHoleAgentSessionProcedureResult>(
|
||||
"create_square_hole_agent_session",
|
||||
CreateSquareHoleAgentSessionArgs { input },
|
||||
__callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -31,10 +31,10 @@ pub trait delete_big_fish_work {
|
||||
input: BigFishWorkDeleteInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<BigFishWorksProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<BigFishWorksProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl delete_big_fish_work for super::RemoteProcedures {
|
||||
input: BigFishWorkDeleteInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<BigFishWorksProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<BigFishWorksProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, BigFishWorksProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait delete_custom_world_agent_session {
|
||||
input: CustomWorldAgentSessionGetInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldWorksListResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldWorksListResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl delete_custom_world_agent_session for super::RemoteProcedures {
|
||||
input: CustomWorldAgentSessionGetInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldWorksListResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldWorksListResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, CustomWorldWorksListResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait delete_custom_world_profile_and_return {
|
||||
input: CustomWorldProfileDeleteInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldProfileListResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldProfileListResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl delete_custom_world_profile_and_return for super::RemoteProcedures {
|
||||
input: CustomWorldProfileDeleteInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldProfileListResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldProfileListResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, CustomWorldProfileListResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait delete_match_3_d_work {
|
||||
input: Match3DWorkDeleteInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<Match3DWorksProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<Match3DWorksProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl delete_match_3_d_work for super::RemoteProcedures {
|
||||
input: Match3DWorkDeleteInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<Match3DWorksProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<Match3DWorksProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, Match3DWorksProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait delete_puzzle_work {
|
||||
input: PuzzleWorkDeleteInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleWorksProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleWorksProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl delete_puzzle_work for super::RemoteProcedures {
|
||||
input: PuzzleWorkDeleteInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleWorksProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleWorksProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, PuzzleWorksProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait delete_runtime_snapshot_and_return {
|
||||
input: RuntimeSnapshotDeleteInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeSnapshotProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeSnapshotProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl delete_runtime_snapshot_and_return for super::RemoteProcedures {
|
||||
input: RuntimeSnapshotDeleteInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeSnapshotProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<RuntimeSnapshotProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, RuntimeSnapshotProcedureResult>(
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::square_hole_work_delete_input_type::SquareHoleWorkDeleteInput;
|
||||
use super::square_hole_works_procedure_result_type::SquareHoleWorksProcedureResult;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
struct DeleteSquareHoleWorkArgs {
|
||||
pub input: SquareHoleWorkDeleteInput,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for DeleteSquareHoleWorkArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the procedure `delete_square_hole_work`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteProcedures`].
|
||||
pub trait delete_square_hole_work {
|
||||
fn delete_square_hole_work(&self, input: SquareHoleWorkDeleteInput) {
|
||||
self.delete_square_hole_work_then(input, |_, _| {});
|
||||
}
|
||||
|
||||
fn delete_square_hole_work_then(
|
||||
&self,
|
||||
input: SquareHoleWorkDeleteInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<SquareHoleWorksProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
impl delete_square_hole_work for super::RemoteProcedures {
|
||||
fn delete_square_hole_work_then(
|
||||
&self,
|
||||
input: SquareHoleWorkDeleteInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<SquareHoleWorksProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, SquareHoleWorksProcedureResult>(
|
||||
"delete_square_hole_work",
|
||||
DeleteSquareHoleWorkArgs { input },
|
||||
__callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -31,10 +31,10 @@ pub trait drag_puzzle_piece_or_group {
|
||||
input: PuzzleRunDragInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleRunProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleRunProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl drag_puzzle_piece_or_group for super::RemoteProcedures {
|
||||
input: PuzzleRunDragInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleRunProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<PuzzleRunProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, PuzzleRunProcedureResult>(
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// THIS FILE IS AUTOMATICALLY GENERATED BY SPACETIMEDB. EDITS TO THIS FILE
|
||||
// WILL NOT BE SAVED. MODIFY TABLES IN YOUR MODULE SOURCE CODE INSTEAD.
|
||||
|
||||
#![allow(unused, clippy::all)]
|
||||
use spacetimedb_sdk::__codegen::{self as __sdk, __lib, __sats, __ws};
|
||||
|
||||
use super::square_hole_drop_shape_procedure_result_type::SquareHoleDropShapeProcedureResult;
|
||||
use super::square_hole_run_drop_input_type::SquareHoleRunDropInput;
|
||||
|
||||
#[derive(__lib::ser::Serialize, __lib::de::Deserialize, Clone, PartialEq, Debug)]
|
||||
#[sats(crate = __lib)]
|
||||
struct DropSquareHoleShapeArgs {
|
||||
pub input: SquareHoleRunDropInput,
|
||||
}
|
||||
|
||||
impl __sdk::InModule for DropSquareHoleShapeArgs {
|
||||
type Module = super::RemoteModule;
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
/// Extension trait for access to the procedure `drop_square_hole_shape`.
|
||||
///
|
||||
/// Implemented for [`super::RemoteProcedures`].
|
||||
pub trait drop_square_hole_shape {
|
||||
fn drop_square_hole_shape(&self, input: SquareHoleRunDropInput) {
|
||||
self.drop_square_hole_shape_then(input, |_, _| {});
|
||||
}
|
||||
|
||||
fn drop_square_hole_shape_then(
|
||||
&self,
|
||||
input: SquareHoleRunDropInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<SquareHoleDropShapeProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
impl drop_square_hole_shape for super::RemoteProcedures {
|
||||
fn drop_square_hole_shape_then(
|
||||
&self,
|
||||
input: SquareHoleRunDropInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<SquareHoleDropShapeProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, SquareHoleDropShapeProcedureResult>(
|
||||
"drop_square_hole_shape",
|
||||
DropSquareHoleShapeArgs { input },
|
||||
__callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -50,9 +50,11 @@ pub trait ensure_analytics_date_dimension_for_date {
|
||||
&self,
|
||||
input: AnalyticsDateDimensionEnsureInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()>;
|
||||
}
|
||||
|
||||
@@ -61,9 +63,11 @@ impl ensure_analytics_date_dimension_for_date for super::RemoteReducers {
|
||||
&self,
|
||||
input: AnalyticsDateDimensionEnsureInput,
|
||||
|
||||
callback: impl FnOnce(&super::ReducerEventContext, Result<Result<(), String>, __sdk::InternalError>)
|
||||
+ Send
|
||||
+ 'static,
|
||||
callback: impl FnOnce(
|
||||
&super::ReducerEventContext,
|
||||
Result<Result<(), String>, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) -> __sdk::Result<()> {
|
||||
self.imp.invoke_reducer_with_callback(
|
||||
EnsureAnalyticsDateDimensionForDateArgs { input },
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait execute_custom_world_agent_action {
|
||||
input: CustomWorldAgentActionExecuteInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldAgentActionExecuteResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldAgentActionExecuteResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl execute_custom_world_agent_action for super::RemoteProcedures {
|
||||
input: CustomWorldAgentActionExecuteInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldAgentActionExecuteResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<CustomWorldAgentActionExecuteResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, CustomWorldAgentActionExecuteResult>(
|
||||
|
||||
@@ -27,10 +27,10 @@ pub trait export_auth_store_snapshot_from_tables {
|
||||
&self,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AuthStoreSnapshotProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AuthStoreSnapshotProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -39,10 +39,10 @@ impl export_auth_store_snapshot_from_tables for super::RemoteProcedures {
|
||||
&self,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AuthStoreSnapshotProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AuthStoreSnapshotProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, AuthStoreSnapshotProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait export_database_migration_to_file {
|
||||
input: DatabaseMigrationExportInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<DatabaseMigrationProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<DatabaseMigrationProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl export_database_migration_to_file for super::RemoteProcedures {
|
||||
input: DatabaseMigrationExportInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<DatabaseMigrationProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<DatabaseMigrationProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, DatabaseMigrationProcedureResult>(
|
||||
|
||||
@@ -31,10 +31,10 @@ pub trait fail_ai_task_and_return {
|
||||
input: AiTaskFailureInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ impl fail_ai_task_and_return for super::RemoteProcedures {
|
||||
input: AiTaskFailureInput,
|
||||
|
||||
__callback: impl FnOnce(
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
&super::ProcedureEventContext,
|
||||
Result<AiTaskProcedureResult, __sdk::InternalError>,
|
||||
) + Send
|
||||
+ 'static,
|
||||
) {
|
||||
self.imp
|
||||
.invoke_procedure_with_callback::<_, AiTaskProcedureResult>(
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user