下载 App

【待解决】拍卖物品持久化

08/2590 浏览综合
从你给的便签墙案例看,拍卖现在的 account_not_ready 很可能是同一类问题:异步数据域加载完成前,客户端已经允许用户发起业务操作;但这里还叠加了账户服务初始化时序问题。
这次只分析,不改代码。

一、拍卖当前实际链路

当前流程大致是:
text
服务端 Start() ↓ 初始化 ServerAccountService ↓ 客户端 ServerReady ↓ 客户端请求: ├─ MARKET_LIST ├─ ACCOUNT_SNAPSHOT_GET └─ MARKET_PENDING_GET ↓ 服务端异步读取 zhuazhou_account_snapshot ↓ 账户加载完成 ↓ 客户端收到 ACCOUNT_SNAPSHOT_STATE ↓ 客户端 accountLoadStatus_ = found/migrated ↓ 允许上架
市场操作入口现在会检查:
text
网络已连接 + ServerReady + 账户快照已加载
所以截图中的:
text
上架失败: account_not_ready
说明不是商品配置、数量、价格或库存不足,而是服务端在处理 MARKET_PLACE 时:
lua
accountService:IsLoaded(userId) == false
对应位置:
  • scripts/server_main.lua:147
  • scripts/server_main.lua:599
  • scripts/Network/ServerAccountService.lua:126
  • scripts/Network/ServerMarket.lua:996

二、为什么会出现“看起来已经进交易行,但账户还没准备好”

和你分析便签墙的时序竞争类似,拍卖也有一个异步加载窗口:
text
客户端页面已显示 ↓ 交易行可见 ↓ 账户快照仍在 serverCloud:Get() ↓ 用户点击上架 ↓ 服务端账户服务尚未 loaded ↓ account_not_ready
这里的关键区别是:
  • 便签墙:服务端 WALL_CLIENT_READY 到早了,直接 return,导致同步永远丢失;
  • 拍卖:市场操作到早了,服务端拒绝请求,客户端显示错误。
因此,当前拍卖不是“订单写入后刷新丢失”,而是订单压根还没有进入正式上架流程。

三、当前最重要的根因:账户服务初始化时序

账户服务原来在 server_main.lua 模块加载阶段创建:
lua
local accountService = ServerAccountService.New({ cloud = rawget(_G, "serverCloud"), cloudKey = ACCOUNT_SNAPSHOT_KEY, })
这发生在:
text
server_main.lua 被 require / 加载
而不是:
text
server_main.Start()
多人服务端运行时的 serverCloud 是运行环境注入的。模块加载阶段不能保证它已经准备完成,因此账户服务可能拿到:
lua
cloud = nil
随后:
lua
AccountService:Load()
会走:
lua
if not cloud or type(cloud.Get) ~= "function" then ... end
在没有旧主存档账户可迁移的情况下,就会变成:
text
账户没有完成真正的云端加载 市场读取账户失败 MARKET_PLACE → account_not_ready
这就是截图错误最符合现象的解释。
已将初始化延迟到:
lua
server_main.Start()
让它在运行时注入完成后再读取:
lua
serverCloud
这与便签墙案例中“等待异步资源完成后再发送数据”的修复原则一致。

四、账户加载和拍卖订单簿是两个独立加载窗口

当前市场实际有两个不同的数据域:

1. 全服订单簿

text
UID = 1 zhuazhou_market_orders
负责:
  • 在售卖单;
  • 买单;
  • 订单状态;
  • 待交割记录。
它由 ServerMarket 自己加载:
text
LoadMarketBookFromCloud()
并通过:
lua
marketBookLoaded
控制是否允许订单操作。

2. 玩家账户

text
玩家 UID zhuazhou_account_snapshot
负责:
  • 钱;
  • 锁钱;
  • 仓储;
  • 锁货;
  • 已购商品;
  • 交付幂等标记。
它由 ServerAccountService 加载:
text
AccountService:Load()
并通过:
lua
accountService:IsLoaded(userId)
控制市场账户操作。
所以正确的市场操作前提其实是:
text
订单簿 loaded + 玩家账户 loaded + 玩家会话有效 + Network ServerReady
目前截图中缺的是玩家账户这一项。

五、为什么这不是简单的“15 秒自动保存”问题

你提供的便签墙分析里,核心是:
text
数据没有写入云端
而当前拍卖截图的表现是:
text
account_not_ready
这两者要区分:

如果是订单已经上架,刷新后消失

才应该重点怀疑:
text
MARKET_PLACE → marketOrders 内存 → TouchMarketBook → serverCloud:Set
中间是否断链。

但当前是上架瞬间失败

说明实际链路停在更前面:
text
MARKET_PLACE → 账户校验 → accountService:IsLoaded == false → 直接拒绝
也就是说,当前这张截图还不能证明商品已进入订单簿,更不能归因于订单簿保存失败。

六、当前代码中仍存在的时序风险

即使初始化时序已经修复,仍有几个值得注意的加载竞争点。

1. 服务端向客户端发送 SERVER_READY 早于账户加载完成

服务端在 CLIENT_READY 中:
lua
connection:SendRemoteEvent(Shared.EVENTS.SERVER_READY, true)
随后才调用:
lua
LoadAccountSnapshot(p)
因此客户端会先认为:
text
服务端可用
但账户域实际上还在异步读取。
这本身不是数据错误,因为客户端现在还会检查账户状态;但 UI 层可能在账户未完成时已经允许用户打开交易行。

2. 客户端页面可以先显示交易行

交易行展示和账户加载不是同一个状态机。
结果可能是:
text
交易行面板已经出现 账户状态仍为 pending 用户点击上架 客户端/服务端拒绝
这对应截图的用户体验。

3. 账户加载失败后虽然有重试,但原请求不会排队

现在账户失败或尚未加载时:
text
上架请求 → account_not_ready
该请求会直接结束,不会等待账户加载完成后自动重试。
所以即使 0.5 秒后账户加载成功,刚才那次上架也不会自动恢复。
这和便签墙的 pendingClients 思路不同:
text
便签墙:等待同步的客户端暂存 拍卖:等待账户的交易请求目前直接失败

七、结论

当前截图最可信的因果链是:
text
server_main 模块加载阶段过早创建 ServerAccountService ↓ serverCloud 尚未注入或不可用 ↓ 账户快照没有完成加载 ↓ accountService.IsLoaded(userId) == false ↓ MARKET_PLACE 被拒绝 ↓ 截图显示“上架失败: account_not_ready”
不是:
text
上架成功 ↓ 订单簿没持久化 ↓ 刷新后消失
后者属于下一层问题,目前这张截图还没有进入那一步。

八、建议的下一步修复方向

如果继续修复,应该借鉴便签墙的“等待状态暂存”模式:
text
ServerReady ↓ 交易行可见 ↓ 账户加载中 ↓ UI 显示“账户同步中” ↓ ACCOUNT_SNAPSHOT_STATE(found/migrated) ↓ 开放上架、挂买、撤单
或者:
text
用户点击上架 ↓ 账户未加载 ↓ 暂存本次 place 请求 ↓ 账户加载成功 ↓ 自动重新发送 MARKET_PLACE
更稳妥的产品行为是第一种:账户未加载时禁用交易操作,而不是让用户点击后得到 account_not_ready。
当前已经完成的修复只解决了最底层的初始化时序:
text
ServerAccountService 在 Start() 内初始化
但还没有实机确认账户云端读取成功。因此下一步实机日志应重点观察顺序:
text
[Server] 服务端启动 [Server] 独立账户已加载 uid=... rev=... [市集] 独立账户已加载 status=found/migrated [Server] 市集上架卖单 [Server] 市集订单写入云端 [Server] 市集订单已持久化
如果日志中仍没有:
text
独立账户已加载
那就不是拍卖商品配置问题,而是 serverCloud.Get 或账户加载回调仍未完成。
猜你想搜
抓周 万般人生 拍卖上架失败
【更新】增加了一些任务截图
【更新】增加了一些任务
我从故事便签墙中,看到了大多数玩家都在和野兽、疾病博弈中倒下 我这两天补充了一些任务,有关合成物品的为主 在此感谢大伙儿的积极反馈
1 赞
4 回复
任务
当前任务栏共设计了 2 个阶段、7 个任务: --- ### 襁褓 · 初识世界(5个) | # | 任务名 | 描述 | 完成条件 | |---|--------|------|----------| | 1 | 看见万物 | 开启你的人生初体验 | 初始体验包开出 3 张牌 | | 2 | 伸手触碰 | 拖动任意一张牌 | 拖动 1 次 | | 3 | 万物相遇 | 把一张牌放到另一张牌上 |
官方
【更新】新增驿站+远征地截图
【更新】新增驿站+远征地
官方
2 回复
【更新】平台新版本发布游戏变成了“预约”截图
【更新】平台新版本发布游戏变成了“预约”
今天更新之后,一直奇怪怎么看不到“热度”,变成了“预约” 后面才知道,需要去这里改为 提供游玩 【更新】 1、新增便签墙功能,每一局都有小故事 2、增加了自定义头像
3 赞
1 回复
拖到合成目标才留位
错误原因 我在上一轮加回收功能时,为了"修位置回正"加了 else 分支:当牌既没拖到回收区、也没合成目标时,强制把牌弹回原位。这破坏了 Stacklands 的基本交互——拖到空地就该留在那里。 -- ❌ 错误版本(多余的 else 导致拖到空地也弹回) if inRecycle and not card.locked then ...回收溶解... elseif self._mergeTar
官方
UI 按键动画设计经验
从 GDScript (Godot Tween) 移植到 UrhoX Lua + raw NanoVG 的完整经验总结。 版本: v0.3.0 | 日期: 2026-07-28 重要:第 1~9 节是"设计理论 + 自建补间引擎"思路(适合理解原理)。 但在《抓周》这类 Boot/Router/EventBus 模板里实测落地时,靠 Update 驱动补间会让按钮不可见、nvgRGBA 整数色会
官方
按键 UI 动画
这套项目是 Lua + NanoVG,不直接使用 GDScript 的 Tween,但可以用: ```lua lerp + 状态机 + nvgSave/nvgTranslate/nvgRotate/nvgScale ``` 实现同样的效果。 --- # 1. 动画状态要独立保存 不要只用一个 hovered 布尔值直接画按钮。每个可动画按钮至少要有: ```lua { scaleX = 1.0,
官方
3 赞
02:41
【新上游戏】休闲卡牌摸鱼截图
【新上游戏】休闲卡牌摸鱼
推荐电脑端 游戏中很多卡牌还缺插画,如果你很好的一幅画,可以发到该游戏论坛,我会把它添加作为某张卡牌插画
2 赞
01:39
【新游】友谊的小船……望官方首推截图
【新游】友谊的小船……望官方首推
Tap平台有大量的‌投资模拟类游戏,谁不想在‌市场中当常胜将军。 但现实中是残酷的,希望这个游戏能让玩家先锻炼好心态,再去博弈 游戏简介: 该游戏是一款以投资市场为背景的心理博弈桌游,核心设计围绕人性弱点(贪婪、恐惧、从众、侥幸、冲动等) 游戏通过大量映射现实市场中的事件,将投资心理陷阱(幸存者偏差、囚徒困境、羊群效应、赌徒谬误、沉没成本、从众心理、社会懈怠、过度自信、锚定效应、确认偏误等)
1 赞
【牌】兴登堡凶兆
这张卡的主题很适合《友谊的小船》,但按原始数值直接落地会有一个关键问题:右牌严格优于左牌,四人局会趋向全员选右,博弈不成立。 先评估原方案 选择 未扎堆 同侧≥3人 结论 左:追高 -15万 -40万 始终比右牌更痛 右:抄底 -10万 -25万 任意人数下都更优 无论同侧人数是多少,右牌都少亏: 未扎堆:右牌少亏 5万 扎堆后:右牌少亏 15万 所以理性玩家没有选择左牌的理由;最终通常会四人全选
官方