Avatar

colorfulbird3

INITIALIZING SYSTEM

云端杂谈

代码、学术、提瓦特与泰拉大陆的碎片记录

cover
2026-08-17 10:15:22

DMF0.8.9开发日志

0.8.8 和 0.8.9 刚刚做完,趁着没志愿者帮忙测试( ;∀;)的空档,把这段时间干的事记一笔。 ‍ 0.8.8 的主题是运行时实体。之前在 alpha.20 真机测试的时候发现过:主机快照 755 个对象,客户端只能绑定 753 个,少的那两个是乌鸦群和动物尸体。这类东西不在存档里,是游戏运行时生成的,客户端只靠加载主机存档根本拼不出来。当时只能宽容处理,缺失比例小就跳过,先进游戏再说。0.8.8 就是补这个欠账。 ‍ 协议里加了两条消息:RuntimeEntitySpawn 和 RuntimeEntityDespawn。ID 只能由主机分配,整个会话单调递增,销毁过的编号绝不复用,不然晚到的 Despawn 包会把新生成的对象误杀。注册表也拆开了,持久实体和运行时实体分开管。 ‍ 第一版只挑了掉落物做最小闭环:主机丢个东西,客户端看到它出现,主机捡走,客户端看到它消失。这条链路跑通之后才做的敌人。敌人还是老规矩:主机跑 AI、寻路、血量、攻击,客户端只有一个代理,跟着 15Hz 的状态插值移动,自己什么都不算。敌人死了就发 Despawn,有尸体和掉落就接着 Spawn。 场景切换和热加入也在这个版本里做了。切场景先发 SceneChangeBegin,把动作、实体、背包、战斗的消息全部暂停,两边都加载完、注册表重建稳定之后,再发一份运行时快照,最后 SceneReady。切场景期间旧场景的包直接丢。热加入靠快照恢复,晚进来的玩家能看到当前活着的所有运行时实体。 ‍ 还有一个单独的问题。信任模式之下,两个客户端同时开同一个柜子各拿各的,主机收到两份状态都直接应用,物品就被复制出来了。没有退回审批制,而是给容器加了个乐观版本号:客户端操作前记下当前版本,上报时带上期望版本,主机对得上就接受,对不上就回发最新状态让客户端刷新。还是本地即时操作,只是冲突的时候纠正一下。 ‍ 0.8.9 基本没加玩法,全是工程上的事。服务拆了一轮,PlayerService、CombatService 独立出来,SaveState 也改成了行为化,进度上报收敛到一个入口。传输层做了抽象,加了 FaultInjectingTransport,可以故意丢包、延迟、重复、断线、损坏数据,专门测异常路径,顺手修了断开时重复触发事件的问题。wire 格式没动,不存在版本兼容问题。 测试这边:单元测试 24 项,SelfTests 81 项,回环自测的完整链路(握手、存档、快照、READY)都过。 ‍ 现在双机验证还在跑。等 0.8.8/0.8.9 的实机矩阵跑完,剩下的是 xUnit 全量迁移、RuntimeEntityService 收拢、UDP-KCP 评估,再往后就是 0.9.0,恢复加玩法。
#Darkwood#开发记录#多人联机
cover
2026-08-11 21:25:38

喜报!!Darkwood 联机框架首次完成主机与远端互联

**今天!!我的联机框架迎来了一个里程碑式的进展!!!主机和远端可以互联了!!!!** 之前测试基本都是在自己电脑上双开。虽然也能连接,也能收发消息,但本机双开和两台真实电脑联机毕竟不是一回事,很多网络问题只有换到真正的远端环境里才会暴露出来。 ‍ 这次找了另一台电脑,通过 Radmin VPN 组了一个虚拟局域网。主机用默认的端口启动,另一台电脑直接填写 Radmin 的 IP 地址连接。 连接成功以后,主机会读取当前正在玩的存档,把它压缩成一个快照,再分成很多小块发给客户端。这次测试的存档大概有 5 MB,客户端下载完成后会自动写入独立的联机存档目录,然后加载主机的存档。 ‍ 再然后就是主机开服、客户端连接、下载存档、加载存档,然后进入同一个世界!! ‍ 终于终于,我修改了无数次的代码,两端终于连接起来了。 ‍ 这次还顺便把玩家身份分配跑了一遍。主机是 P0,第一个加入的客户端是 P1,以后继续加入就是 P2、P3。这个编号看起来没什么特别的,但之后同步位置、动画、背包和场景交互,都得靠它判断到底是谁在操作,不然两台电脑上的本地玩家对象很容易互相覆盖。 ‍ 玩家状态同步目前走的是主机权威的思路。客户端只负责发送自己的位置、方向和动作,主机收到以后做一下检查,再转发给其他玩家。其他电脑不会直接照搬收到的位置,而是稍微做一点插值,尽量避免远端玩家走路时一顿一顿的。 远端玩家模型现在也已经能创建了,不过显示效果还在调。 ‍ 目前可以说“远端玩家对象已经有了”,但还不能说“远端玩家已经完整显示了”。有时候连接成功以后模型没有生成,有时候能生成,但动画或者手上的东西没有同步。这个部分应该还要继续磨一阵。 ‍ 联机以后,箱子肯定不能像单机那样由每台电脑各自修改。否则两个人同时打开一个箱子,很容易各拿走一次同样的物品,最后直接变成复制物品。 现在的处理方式是给每个容器加一个库存版本号。客户端想拿东西时,会把自己看到的版本一起发给主机。主机确认版本没有过期以后才真正修改库存,然后把新结果广播给所有玩家。如果两个人几乎同时拿同一个东西,后到的请求就会因为版本不一致被拒绝,再用主机的正确状态覆盖回来。 ‍ 实际测试以后,问题当然也出来了一大堆。 目前最明显的是客户端进入存档以后偶尔会突然断开。有些连接虽然还在,但远端玩家模型没有生成。切换场景以后,玩家状态包也可能莫名其妙停止发送。实体捕获模块里还有一些空引用警告,一旦开始重复刷,日志文件很快就会变得特别大。 箱子、地面物品、工作台、门和敌人这些东西,也还没有全部接进新的主机权威系统。特别是敌人 AI,之后必须只让主机真正运行,客户端只显示主机发来的结果,不然两边的敌人各自寻路、各自攻击,场面肯定会越来越乱。 ‍ 现在这些问题不重要,重要的是我的联机框架搭起来了!!。我们Darkwood玩家不只是能在自己的电脑上自娱自乐了,两台真实电脑通过 Radmin VPN等方式建立连接,然后一同游玩和探索,阴暗的森林里不再是孤单的一个人。 ‍ 接下来先把进入世界后偶发断线的问题处理掉,然后继续完善 P0、P1 的状态广播和远端模型。等玩家本身稳定以后,再慢慢把共享箱子、掉落物、门、工作台和敌人 AI 接进来。 ‍ 历经千辛万苦,我的联机框架有了底座。后面虽然还有很多问题需要解决,但那些都是小事,可以慢慢修。 今天真是值得庆祝的一天~`(゜-゜)つロ 干杯~`
2026-08-09 00:00:00

Darkwood 联机框架有大更新了

Darkwood 联机框架更新了多端实体状态同步逻辑。 这次主要不是增加几个网络消息,而是把实体同步的整体思路重新做了一遍:从之前进入世界时发送一份很大的世界快照,改成更接近 Minecraft 的主机权威复制架构。 ‍ 现在由主机负责运行敌人 AI、物理、伤害和交互逻辑,客户端主要负责发送输入和显示主机状态。主机大约每秒捕获 20 次世界状态,只把发生变化的部分发给客户端。这样可以减少一次性同步大量实体造成的卡顿和断线,也能避免双方各自运行 AI 后出现不同的路径和随机结果。 ‍ 实体现在有两层 ID:根据存档对象生成、跨加载尽量稳定的 Persistent ID,以及只在当前场景有效的短 Network ID。场景切换时会递增 Epoch,客户端会自动丢弃旧场景消息,避免重连后出现幽灵实体。 同步消息也拆开了:实体进入范围时发送 Spawn,状态变化时发送 Delta,定期发送完整 Keyframe 做校正,实体离开范围或被移除时发送 Despawn。状态本身还按位置旋转、生命值、开关状态和动画拆成 DirtyMask,只更新真正变化的字段。 ‍ 主机现在会根据玩家位置管理兴趣范围,不同实体使用不同距离,边界还会留一点滞后,避免玩家在边缘来回走时实体不停 Spawn 和 Despawn。刚进入场景时,Spawn 也会分批发送,尽量压低瞬时网络峰值。敌人和物品的位置会在客户端插值,门窗、生命值和破坏状态则直接应用,后续 Keyframe 再负责纠正偶尔的丢包或漂移。 ‍ 攻击、开门、开关物品等操作也改成了带序号的命令。主机会检查实体是否存在、是否在兴趣范围内、玩家距离是否合理,以及命令是否重复或过期,验证通过后才执行操作。 库存部分则从“客户端直接覆盖整库存”改成了带修订号的乐观事务。这样可以避免两名玩家同时拿取同一件物品时出现复制、回滚或数量叠加。 然后还加入了定期同步摘要和更完整的断线清理。存档传输协议也升级到了 v2。 ‍ 这次重构之后,框架的同步骨架算是稳定了一大截,但距离真正长时间多人游玩还有不少测试要做,尤其是场景切换、动态生成实体、高延迟和库存并发操作。
#Darkwood#开发记录#多人联机