下载 App
不同玩家“发送”流言内容即时存入云端
我试着在分享链接测试留言板流言,重进分享链接测试发现流言没了,有没有办法保存其他玩家的流言,点击“发送”流言内容可以即时存入云端?核心规则:游戏体验不会改变 —— 不需要匹配、不需要房间
嗒:
当前问题:留言数据存在内存中,gameSaveMap_() 尝试写入 clientCloud,但 clientCloud 是按用户隔离的——每个玩家只能看到自己的数据,其他玩家的留言互不可见。要实现跨玩家共

耳内有灰:
WASM 下完整链路
玩家打开分享链接 (WASM)
→ background_match 秒连 → ServerReady
→ Server 实例启动
→ serverCloud:Get(0, "wall_bricks_all") ← 1 次读,全量加载
→ SYNC_ALL → 客户端合并 → 壁上看到所有人的留言 ✅
玩家点"发送"
→ RemoteEvent → Server 入队
→ FlushWriteQueue: Get → 合并 → Set ← 写完即持久化
→ broadcastBrickUpdate → 客户端立即看到 ✅
玩家刷新页面 / 重新进入
→ 新 Server 实例启动
→ serverCloud:Get(0, "wall_bricks_all") ← 读到上次写入的数据
→ SYNC_ALL → 留言还在 ✅
每个环节都是确定性的:
预加载:1 次 Get,不依赖注册表,不会遗漏
写入:RMW 写完 serverCloud:Set 返回即入云,不存在"队列没 flush"的窗口
重进:新实例同一个 key 直接读,数据完整
对比当前方案为什么 WASM 下会丢
当前方案的断裂点:
serverCloud.list:Add("brick_31", data) ← 数据入云了
registerBrickId(31) ← 异步,可能没写完
玩家刷新页面 ← 服务器销毁
新服务器 → 读注册表 → 没有 31 → 不去加载 → 留言"消失"
单 key 整包方案没有这个断裂点,因为数据和索引是同一个东西。
旧代码处理
serverCloud.list + 注册表的代码注释保留,不删。后面如果需要按交互类型做审计日志(谁在什么时间点了什么赞),list 的逐条记录模式更合适,可以从冷宫捞回来做"热数据整包 + 冷数据 list 归档"的双写。
确认方向没问题的话,我就开始改 Server.lua。
:
这次的核心改动:
新策略:每帧只创建一个纹理 handle
之前 PreloadAll 在一帧内对 15 个纹理全部调用 nvgCreateImage,导致所有 handle 瞬间创建完毕,loading 界面 1-2 帧就跳过。
新增的 PreloadStep() 函数:
每次调用最多创建 一个 新的 nvgCreateImage handle
已有 handle 的纹理只做轻量的尺寸复查(几乎零开销)
15 个纹理 → 至少需要 15 帧才能全部创建完毕
在 60fps 下约 0.25 秒,进度条会从 1/15 → 2/15 → … → 15/15 逐步更新
请再次测试,这次应该能看到进度条从 0 逐步填满到 15/15。
如何让分享链接的访问者能看到/使用创作者保存的地图
你的分析方向是对的,但可以更精确地拆解。让我逐层回答。为什么 UI 一样,但数据不一样?这两者本质不同:内容来源特性左侧栏地形列表、工具栏按钮代码(Lua 脚本)打包在构建产物里,所有环境完全一致已保存的地图列表数据(运行时读取存储)取决于存储后端,不同环境/会话各自独立编辑器 UI 看起来一样,是因为它由同一份打包部署的代码渲染。而"加载地图"弹窗里的列表内容,是运行时从存储层读取的——这才是差

:
修改总结:
main.lua 中 EnterGame() 的加载策略改为:
优先从静态文件加载 — MapData.Load("data/default_map.json"),这个文件会随构建打包,所有用户(包括分享链接)都能读到
静态文件不存在时回退 clientCloud — 保留原有的云端加载逻辑,方便本地开发调试
clientCloud 也不可用时 — 显示友好提示"地图未就绪"
保存逻辑也做了防护 — saveMapToCloud() 会检查 clientCloud 是否存在,不存在时跳过云端保存,避免报错。
关键点:我之前的修改只在**“玩家入口”**(EnterGame())中添加了静态文件加载,编辑器仍然从 clientCloud 读取——所以分享链接上的编辑器看到的是不同用户的 clientCloud 数据。
请你在分享链接上点击**“玩家入口”**按钮测试——那里才是从静态文件 default_map.json 加载地图的路径。
不过,编辑器也应该在启动时自动加载静态地图作为默认内容。让我加上这个逻辑。
问题原因是 MapData.Load() 使用 fileSystem:FileExists() 检查文件存在性——这个 API 检查的是原始文件系统路径,在 WASM 中无法找到已打包的资源文件。改用 cache:GetFile() 后,会从引擎的资源缓存中搜索,可以正确找到构建打包的文件。
留言墙牌匾设计
1. 列表项跳转 + 返回定位
VirtualList 本身只渲染可见行,点击跳转到砖块详情不会有性能问题。返回定位的方案:
牌匾弹窗(VirtualList,记住 scrollOffset)
↓ 点击某条留言
砖块详情弹窗(showBrickViewModal)
↓ 关闭
牌匾弹窗(恢复之前的 scrollOffset)
实现方式:打开砖块详情前,记录当前 VirtualList 的 scr

:
问题原因:拆除屋檐/柱子时调用的是旧版全局方法 mapData:UninstallRoof(),它只检查已弃用的 self.roofInstalled 全局字段。而实际屋檐数据存储在 wallParts[wk].roofInstalled 中。
修复:从 piece.data.wallKey 解析出 anchorRow, anchorCol,改为调用 mapData:UninstallWallParts(row, col),这个方法会正确清除对应墙段的 pillarsInstalled 和 roofInstalled。
:
改动清单
CollisionMap.lua:
构造函数新增 self.wallStrips = {} 数组
Rebuild() 步骤 4 从网格阻挡改为门槛条:遍历 GetWallGroups() 按砖块跨度计算宽度,有柱子时加 PILLAR_VIS_W
新增 RebuildWallStrips() 方法(增量更新,添砖/装柱后调用)
IsAreaBlocked() 新增段落 C 检测 wallStrips
_IsInAnyStrip() 新增 wallStrips 循环(防 Q/E 旋转卡住)
删除旧的 MarkWallBlocked() 方法
main.lua:3 处 MarkWallBlocked() 调用全部替换为 RebuildWallStrips()
MapCanvas.lua:新增绿色调试可视化,渲染留言墙门槛条(与建筑的蓝色区分)
宽度计算逻辑
halfW = (maxBX - minBX + 1) * 16 / 2
如果 pillarsInstalled:
halfW += 48 * 0.32 (≈15.36)
1 砖 → halfW=8
3 砖 → halfW=24
6 砖 → halfW=48
6 砖+柱子 → halfW≈63
可以预览看看绿色门槛条的位置是否和砖墙对齐。
:
构建成功。完整流程总结:
保存并同步到游戏选角的完整流程
步骤 操作 背后发生了什么
1 编辑器里修改角色 画布上编辑像素
2 点击 “保存” CharStorage.Save() → 写入 characters/{id}.json
3 点击 “<- 返回” 回到游戏 进入主界面
4 角色选择弹窗自动弹出 buildRoster() 扫描 characters/*.json,你的角色出现在列表最前面,带缩略图
5 选角色 → 点"进入游戏" loadCharData() 从 sandbox 读取你修改后的角色数据
两种场景都已覆盖
全新自建角色:编辑器新建 → 保存 → 游戏选角弹窗自动出现(带动态生成的缩略图)
导入并修改内置角色(如"爸爸"):导入 → 修改 → 保存 → 游戏中选"爸爸"时会优先加载你修改后的版本(sandbox 优先于 assets)
不需要任何额外操作,编辑器的"保存"就是唯一入口。




