下载 App

发一次测试留言,却显示了2遍

05/041 浏览
现在完全清楚了。根因分析:
重复评论的完整流程:
用户点击"发送" → main.lua 第 1200 行:WallClient.PostComment(brick.id, commentInput, ...)
Client.lua PostComment 内部做了乐观更新到 Client.brickData[brickId].comments(这是 Client 模块自己的缓存)
main.lua 第 1201 行:table.insert(brick.comments, ...) — 又在本地地图 brick 对象上插入了一条(第1次本地插入)
Client.lua 发送 POST_COMMENT 到服务器
服务器 applyChange 把评论加入 brickCache_,然后 broadcastBrickUpdate 广播回所有客户端(包括发送者)
客户端 HandleWallBrickUpdate → onBrickUpdateCallback_ → mergeBrickData → 第 1577-1578 行:brick.comments = cloudData.comments
关键问题在于 第 5 步:服务器广播回了发送者自己。cloudData.comments 包含了服务端新增的那条评论。mergeBrickData 用 brick.comments = cloudData.comments 做整体替换。
但 cloudData 来自 Client.brickData[brickId](Client.lua 的乐观更新缓存),而这个缓存在步骤 2 中已经插入了一条。然后服务器广播回来的数据也包含这条评论。
等等,让我重新理一下。HandleWallBrickUpdate 收到的是服务端的 brickData(brickCache_),不是 Client.brickData。所以 cloudData 来自服务端。
流程是:
main.lua 本地 brick.comments 加了 1 条(现在有 N+1 条)
服务端 brickCache_ 也加了 1 条(现在也有 N+1 条,但可能之前已经有一条旧的同内容评论)
服务端广播回来,mergeBrickData 用 cloudData.comments(N+1 条)替换 brick.comments
如果之前只有 N 条,替换后还是 N+1 条,不会重复。
但如果这条砖块之前就在 brickCache_ 中有旧评论,且 mergeBrickData 在处理中出了问题呢?
等等,我再想想。注意 broadcastBrickUpdate 广播给所有连接,包括发送者自己。如果我们从时序上看:
本地立即 table.insert(brick.comments, newComment) — brick.comments 现在有 [旧…, 新]
服务端处理后广播回来,cloudData.comments = [旧…, 新]
brick.comments = cloudData.comments — 替换为 [旧…, 新]
这是正确的,不应该重复。
让我再仔细看看,是不是还存在第二次合并的路径,比如 rebuildFromCloud 或 SYNC_ALL 触发了第二次合并。或者可能问题在于 Client.brickData 的乐观更新和 BRICK_UPDATE 的交互。
生成正面、背面、侧面,可以走动的角色形象截图
生成正面、背面、侧面,可以走动的角色形象
当前 NPC 角色编辑器的数据结构 编辑器使用 32×32 像素画布,数据结构大致是: 3 个朝向:正面、背面、侧面 2 个动画状态:静止(idle)、行走(walk) 每个状态可以有多帧,支持帧率控制 每帧本质上是一个 32×32 的颜色数组 要解决的 3 个问题 步骤 问题 方案 1. 图片→编辑器 128×128 PNG 导入为 32×32 像素数据 加载图片后逐像素采样(每4×4取1像素)
1 赞
9 回复
以鼠标为锚点缩放
核心数学原理 缩放前后,鼠标指向的那个世界坐标点必须保持在同一屏幕位置。 已知:旧缩放 oldZoom、新缩放 newZoom、鼠标锚点屏幕坐标 (ax, ay)、当前偏移 (panX, panY) 步骤1:算出旧缩放下鼠标指向的世界坐标 wx = (ax - panX) / oldZoom wy = (ay - panY) / oldZoom 步骤2:新缩放后反解新偏移,让 wx/wy
官方
1 赞
穿透层修复
经验一:CSS transform 穿透层修复模式 问题本质 当容器使用 CSS transform: translateX/Y/scale 平移/缩放子树时,即使父容器有 overflow = "hidden",引擎的命中检测可能不裁剪越界区域。如果 transform 后的子树有更高的 zIndex,它会在视觉范围外拦截其他兄弟节点的指针事件。 受影响的场景 地图编辑器(右键平移/滚轮缩放后)
官方
4 赞
精灵平滑移动、墙碰撞体积
一、 渲染层用连续坐标(scripts/页面/校园地图.lua,三处统一): -- NPC 定位(第408-410行) local contLeft = (character.x or 0) * 5 - 18 - charLeft local contTop = (character.y or 0) * 5 - 36 - charTop -- 主角定位(第504-506行) local con
官方
1 赞
地图编辑器仿真 tick 重建抑制
UI 重建频率 = 事件分发的可靠性上限。 只要有一帧 SetRoot 销毁了正在处理 pointer 事件的控件,跨重建边界的 Down/Up 对就会被吞。高频仿真 tick 必须在 UI 边界按页面过滤。 关键代码(scripts/main.lua HandleUpdate) 四步走:先原地处理人员 → 聚合所有仿真 changed → 地图页强制压制 → 只放行显式/登录态变化。 -- ma
官方
4 赞
编辑器实体 zIndex 层级
问题 编辑器中墙段被房间面板覆盖不可见。原因:给房间设 zIndex=1 会创建 stacking context,其内部带背景色/TiledImage 的 floorLayer 作为 paint layer 在合成时盖过了同层级 zIndex=2 的墙段——差距太小不够可靠。 解决:底层不设 zIndex,上层用明显间距 错误做法(zIndex 间距太小 + 给底层也设 zIndex): --
官方
1 赞
碰撞方案
核心教训 1. 格子像素必须匹配精灵尺寸 5px格子+36px精灵=7.2:1比例,任何碰撞方案(AABB/空气墙/单点/格中心)都无法同时满足"不穿墙+四面间距一致+不跳格"。对齐环世界32px后,36px精灵≈1.1格,问题根本解决。 2. 连续渲染 + 格级碰撞的分层设计 渲染用连续坐标 x*S-18(平滑不跳),碰撞用格级检测(不穿墙),二者解耦。 3. 精灵大于格子时,单点检测必然不对称
官方
1 赞
围墙空气墙
问题根源 原系统用单点碰撞(Round(nx), Round(ny) 只检测中心1个点),角色精灵 36px(7.2格) 宽,中心停在 x=0.5 时精灵左半完全覆盖 5px 围墙,视觉"穿墙"。 1. AABB 矩形碰撞检测 — scripts/小人/导航.lua -- 角色碰撞体尺寸(格):脚底占据的地面矩形 -- 半宽 0.5 格(2.5px),半高 0.3 格(1.5px) local A
官方
1 赞
小人的认知系统
这是一个很好的思路。RND 的核心——用"预测误差"度量新奇度,驱动探索——可以直接映射到校园小人的认知系统上,而且不需要真的跑神经网络。下面是方案讨论。 RND 思想到校园小人的映射 RND 原始结构 vs 校园简化版 RND 组件 原始含义 校园小人对应 目标网络(固定随机) 为每个状态生成固定特征 环境的客观快照:房间类型、物件数、人员密度、卫生度、当前时段 预测网络(可训练) 学习预测目标
官方
4 赞
右键拖拽平移
一、问题本质 不是平移公式写错,而是 UrhoX UI 库指针事件派发的两个不对称陷阱叠加: 陷阱 现象 根因文件 OnPointerMove 不向父冒泡 右键按下 isPanning_=true,但 move 事件永远到不了 mapView urhox-libs/UI/Core/Widget.lua(OnPointerDown/Up 有 parent 冒泡,OnPointerMove 没有) H
官方
4 赞