长线在线游戏的服务器架构,最怕把一个看似局部的玩法能力做成隐形全局规则。很多 RPG 或战术游戏都会加入宠物、佣兵、召唤物和临时伙伴。玩家可以下达跟随、攻击、撤退、释放技能等指令,AI 也会自主决策。问题在于,伙伴到底听谁的?玩家断线后伙伴是否继续战斗?召唤者死亡后召唤物是否消失?多人队伍里共享佣兵由谁控制?如果没有指令归属架构,伙伴系统会变成散落在战斗服、角色服和 AI 脚本里的特殊逻辑。
这篇文章不把问题抽象成空泛原则,而是从真实线上协作出发,拆解服务边界、状态模型、失败场景、上线验收和团队协作。文章里的结构适合中大型项目直接拿去做评审清单,也适合小团队在系统还没复杂前提前埋好边界。
典型场景
很多 RPG 或战术游戏都会加入宠物、佣兵、召唤物和临时伙伴。玩家可以下达跟随、攻击、撤退、释放技能等指令,AI 也会自主决策。问题在于,伙伴到底听谁的?玩家断线后伙伴是否继续战斗?召唤者死亡后召唤物是否消失?多人队伍里共享佣兵由谁控制?如果没有指令归属架构,伙伴系统会变成散落在战斗服、角色服和 AI 脚本里的特殊逻辑。
架构示意
flowchart TD
P["Player Command"] --> O["Ownership Resolver"]
O --> C["Companion Controller"]
C --> A["AI Planner"]
C --> B["Battle Runtime"]
B --> S["State Replicator"]
S --> P
C --> L["Command Ledger"]
伙伴实体要有独立 owner,不等同于玩家对象
伙伴可能由玩家拥有,也可能由队伍、剧情、活动或系统拥有。实体数据里应保存 ownerType、ownerId、controllerId、controlMode 和 leaseVersion。owner 表示资产或玩法归属,controller 表示当前谁能下指令。玩家拥有宠物但进入自动托管时,controller 可以切到 AI;队伍共享佣兵时,controller 可以是队长或战斗策略服务。把 owner 和 controller 分开,很多边界会清楚。
指令要进入有序队列,不能直接改 AI 状态
玩家点击攻击目标、AI 自动换目标、服务器触发撤退,都应该变成 CompanionCommand。命令带 commandId、source、priority、target、expireTick 和 precondition。控制器按优先级和战斗 tick 顺序裁决,避免玩家指令和 AI 指令互相覆盖。比如玩家手动指定攻击目标时,可以在 3 秒内压制普通 AI 换目标,但不能压制服务器强制撤离。
控制权限要随玩法阶段变化
伙伴在主城、野外、副本、竞技场和剧情里权限不同。竞技场可能禁止手动控制某些召唤物,剧情伙伴可能只允许跟随,不允许更换目标。权限规则不应写死在客户端按钮上,而应由服务端根据 sceneType、battleRule、playerState 和 companionType 生成可用命令集合。客户端只展示服务端允许的按钮。
断线和死亡要有明确托管策略
玩家断线后,伙伴可以原地待命、继续当前行为、切到安全 AI 或随玩家一起离场。不同玩法策略不同,但必须配置化。召唤者死亡后,召唤物可以立即消失、延迟消失、变为中立或继续完成当前技能。服务端要把这些策略写进状态机,而不是在各个技能里补 if。
同步给客户端的是裁决结果,不是所有内部思考
伙伴 AI 可能每个 tick 都计算目标和路径,没必要全量同步。客户端需要知道目标、位置、技能、控制状态和关键原因,例如“指令被沉默效果拒绝”。如果玩家指令被服务端拒绝,返回明确 reason,比客户端按钮按了没反应更好。伙伴系统常被玩家感知为手感问题,实际上很多是服务端反馈不透明。
关键设计取舍
| 维度 | 架构处理 | 主要价值 |
|---|---|---|
| owner | 资产或玩法归属 | 宠物归属、剧情伙伴 |
| controller | 当前指令来源 | 玩家、队长、AI |
| command ledger | 记录指令裁决 | 排查手感争议 |
| policy | 阶段权限规则 | 竞技场、副本限制 |
落地检查清单
- 伙伴实体保存 owner 与 controller 两套概念
- 所有手动和 AI 指令进入统一命令队列
- 服务端下发当前可用命令集合
- 断线、死亡、切图策略配置化
- 拒绝指令返回明确原因并写入指令流水
推荐数据模型与接口契约
落地时,不要急着写一组临时接口。建议先把核心对象、状态版本和幂等键定义清楚。每个请求都应带 requestId、operator 或 playerId、scenario、policyVersion,写操作还要带 mutationId 或 commandId。服务端返回结果时,不只返回成功失败,还应返回 reason、currentState、nextAllowedAction 和 traceId。这样客户端、客服和运营工具都能用同一套解释口径。
数据模型要区分事实、投影和审计。事实表保存权威状态,投影表服务高频查询,审计流水解释状态为什么变化。很多线上疑难问题,并不是状态错了,而是团队不知道状态为什么变成这样。只要审计流水能串起请求来源、规则版本、前后状态和影响对象,事故复盘就会轻很多。
接口契约还要明确哪些错误可重试,哪些错误必须提示玩家,哪些错误需要进入人工队列。比如参数非法、权限不足、规则阻断不应重试;依赖短暂不可用可以重试;状态半提交则应该返回处理中并让客户端查询结果。把这些写进契约,比在客户端和服务端分别猜测要可靠。
故障案例:共享佣兵被两名玩家同时控制
某队伍副本里有一个机关佣兵,队长和副队都能点击控制按钮。早期实现里客户端直接发送 moveCompanion,房间服只校验队伍成员身份。高延迟下两个人同时下达移动和攻击指令,佣兵在机关前来回横跳,最终错过开门窗口。后来控制权被改成 controllerLease,队长可以转交控制,服务端一次只接受当前 controller 的命令,其他成员请求会返回 not_controller。副队仍能看到佣兵状态,但不能覆盖命令。这个改动让玩法规则和技术控制一致。
这个案例的共性是:最初的实现只满足了主路径,却没有给边界状态、重复请求、权限变化和人工排查留下空间。架构改造不只是加一层服务,更重要的是把“谁有权决定”“状态何时提交”“失败后如何解释”写成系统规则。否则下一次玩法扩展时,同类问题还会换个名字出现。
灰度发布与回滚策略
这类架构不适合全量一次切换。第一阶段可以旁路计算,只记录新旧逻辑差异,不影响玩家结果。第二阶段选择低风险区服、内部账号或非核心玩法开启新逻辑,同时保留旧逻辑查询能力。第三阶段才逐步扩大到高价值链路。每个阶段都要有退出条件,例如错误码突增、人工工单上升、状态差异超过阈值、核心链路耗时增加。
回滚策略要保护已经进入新状态的请求。不要简单关闭开关后让处理中任务无人接管。正确做法是停止新请求进入,继续处理存量状态,保留查询和补偿 worker,确认队列清空或人工接管后再完全关闭。对于涉及玩家资产、资格、权限和奖励的系统,回滚本身也应写审计流水。
监控与值班视角
仪表盘至少要有四类指标:请求量和成功率、状态分布、失败原因、人工介入量。只看接口 p95 延迟不够,很多架构问题表现为状态卡住、重复提交、降级比例异常或客服查询量上升。值班人员需要能按玩家、房间、玩法实例、业务单号查询完整链路,而不是在多个服务日志里手工拼。
告警也要分层。核心提交失败、状态机出现非法转换、审计流水缺失、幂等冲突应立即告警;普通降级、重试升高、低优先级队列积压可以进入观察。告警文案要写清楚影响玩家体验还是只影响后台统计。模糊告警会让值班疲劳,最终真正事故也没人重视。
压测与验收重点
压测不能只跑顺滑路径。要模拟弱网重试、重复点击、服务超时、消息乱序、运行时实例重启、运营改配置、玩家中途退出、权限在请求中变化等情况。每个场景结束后,不只看接口是否返回 200,还要检查最终状态是否唯一、审计是否完整、补偿队列是否可解释。
验收时建议让客户端、服务器、策划、运营和客服一起走一遍异常样例。客户端确认提示文案和交互状态,策划确认规则符合设计,运营确认后台能操作,客服确认能解释给玩家,服务器确认数据能闭环。真正稳定的架构,不是只有研发能看懂,而是每个角色都能在自己的工具里看到可信答案。
常见误区
第一个误区是把主路径跑通当成架构完成。线上问题大多来自重试、半提交、权限变化、配置切换和人工干预。第二个误区是把状态判断放在客户端,服务端只做执行。客户端可以优化体验,但权威判断必须在服务端。第三个误区是忽略审计和查询工具,等事故发生后才临时补日志。
还有一个更隐蔽的误区:为了快速上线,把规则写在多个业务服务里。短期看少了一层抽象,长期会让同一个玩家在不同入口看到不同结果。只要规则会被多个场景复用,就应该收敛到一个明确 owner,并通过版本化策略对外提供结果。
数据保留与复盘
数据保留要按业务价值设计。高价值资产、资格、处罚、权限和跨服关系通常需要保留更久;纯表现状态可以较早归档。归档不是删除一切,而是保留摘要、版本、关键状态和审计哈希。这样既控制成本,也能在玩家申诉、运营复盘或经济对账时还原事实。
复盘时不要只问“这次谁写错了”。更应该问:系统为什么允许错误扩大,监控为什么没有提前发现,工具为什么不能快速解释,回滚为什么不够顺畅。把这些答案沉淀回架构,下一次类似问题才不会重复发生。
团队协作边界
这类系统通常横跨多个团队。服务端负责权威状态和契约,客户端负责表现和失败反馈,策划负责规则语义,运营负责灰度和人工干预,客服负责解释玩家问题。任何一个角色缺失,架构都会在上线后暴露短板。设计评审时建议把“谁能改规则、谁能查状态、谁能修复、谁承担误操作”写清楚。
如果系统需要人工操作,后台必须产品化。临时 SQL、临时脚本、口头审批和截图确认都不应该成为长期流程。人工入口越强,审计越要完整;影响范围越大,预览和二次确认越不能省。
总结
伙伴系统看起来偏玩法,底层却是所有权和控制权问题。把 owner、controller、命令队列和托管策略拆开,伙伴 AI 才能在复杂玩法里保持可解释。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。