任务系统分为世界侧与玩家侧2个部分, 世界侧提供完整的多人游戏同步(跟随世界存档), 玩家提供可重复的个人体验(跟随玩家存档). 当前仅世界侧.
世界任务系统旨在通过以下几项核心功能提供结构化的静态体验.
(Types) 所有世界任务分为 3 类:主线剧情、支线剧情和传说任务. 主线任务是游戏的核心, 旨在引导玩家完成主线故事. 支线任务是可选的, 提供额外的内容和奖励. 传说任务是支线任务的一个特殊子集, 以独特的内容和专属奖励为特色, 使其有别于普通的支线任务.
(Features-Main) 在玩家达到特定的里程碑之前, 任务是锁定的, 但解锁条件是可见的. 某些任务只有在满足特定条件后才会显示. 部分任务具有时间限制, 一旦时限到期, 任务将变得不可用, 直到玩家选择重新开始.
(UI) 任务界面由两部分组成:任务列表和任务详情. 在任务列表中显示所有任务, 每个任务由一张卡片代表. 卡片显示任务名称、类型、状态和剩余时间(如果适用). 玩家可以点击卡片查看任务详情, 其中包括完整的描述、目标、奖励和其他信息. 如果任务是不可见的, 卡片会变灰并仅显示“???”作为名称, 且详情页面保持空白. 界面外观是可选的, 默认风格为大理石板技术风, 随着游戏进程的推进, 将解锁新的主题.
(Features-Sub) 每个任务都是由多个部分组成的组合, 包括任务名称、类型、状态、描述、目标、奖励和其他信息. 任务状态可以是以下之一:已锁定、可接取、已完成或已失败. 目标是玩家为了完成任务必须完成的任务. 奖励在任务完成时发放, 包括物品、世界状态变更或其他收益.
(Features-Objectives) 目标可以有多种类型, 包括但不限于:击杀 NPC、收集物品、消耗物品、到达特定地点、移动一定距离、与 NPC 对话、将物品交给 NPC 以及完成入侵. 系统还提供两种特殊结构:并行目标和分支目标. 一个目标也可以给予玩家完成后续目标所需的奖励, 但这些奖励可能会在目标完成后被移除.
世界侧任务系统
世界侧任务系统目标提供结构化的静态的任务流程
任务构成
- 基础信息: 名称、描述、类型
- 功能信息: 状态、目标、奖励
任务机制
- 锁定与可见性: 任务在达到特定条件处于锁定状态, 详情内容不可见. 大部分任务解锁条件可见;隐藏任务解锁条件不可见, 仅显示"???"作为任务名
- 限时任务: 部分任务有时间限制, 可无条件重试
任务类型
总共包含3个类型, 仅用作分类显示, 不影响游玩体验:
- 主线任务: 游戏核心, 引导玩家推进主线剧情
- 支线任务: 可选内容, 提供额外的剧情内容和奖励
- 传说任务: 内容更为丰富的支线任务, 独特内容和高级奖励
任务状态 & 生命周期
锁定
大部分任务在初始状态下处于锁定状态, 需要达成特定条件后才能解锁 解锁后不会再次锁定
进行中
任务解锁后自动接取, 进入此状态
已完成
任务完成后进入此状态
失败
标记任务因为某种原因失败, 可无条件重试返回进行中状态 可能的原因有:任务计时结束、目标计时结束、任务限制等
任务目标
目标类型
- 击杀NPC:击败一定数量的指定NPC, 多人游戏下计算所有玩家的击杀(未实现在特定条件下击杀, 因BOSS可能需要全伤害计算)
- 收集物品: 在背包中拥有一定数量的指定物品, 多人游戏下计算所有玩家的仓库
- 消耗物品: 消耗一定数量的指定物品, 多人游戏下由全体玩家贡献进度. 由客户端收集上传
- 到达地点: 检测位置、环境、地层
- 行走距离: 可附带条件
- 对话NPC: 检测玩家对话NPC
- 提交物品: 同上, 对话后自动提交. 由客户端收集上传
- 完成事件: 略. 等待事件系统实现同步后启用
特殊结构
- 分支目标: 完成其中一项后自动进入该分支
- 并行目标: 完成任意/全部后可到达后继目标
注:特殊结构之间不可互相包含
目标限时
同任务限时, 可单独重试该目标
目标内奖励
完成某些目标可能获得奖励, 作为后续目标的前置条件. 这些奖励可能在完成目标后被移除, 类似天国魔力
任务奖励
完成任务后向全体玩家发放, 包含物品、世界状态变化等
网络同步
世界侧任务系统采用服务器权威模型, 核心逻辑均在主世界服务器完成, 部分信息由子世界服务器/客户端采集并上传, 在服务器端验证后生效. 由于子世界玩家的客户端无法直接连接至主世界服务器, 因此需要通过子世界服务器转发.
网络分层 (Send / Route)
任务系统通过 PacketResolver 统一管理网络数据包, 分为两层:
- Send (原版 TML):
仅在当前世界内广播, 不跨世界. - Route (跨世界):
结合 TML 与 SubworldLibrary, 在主世界服务器、主世界客户端、子世界服务器、子世界客户端之间进行跨世界传输.
Route 是任务系统跨世界同步的基础.
路由目标 (RouteDestination)
在 Route 层, 任务系统使用两种路由目标:
MainServer(上行)- 所有非主世界服务器 (子服务器、主客户端、子客户端) 均使用此路由.
- 子世界服务器只负责识别并直接转发, 不执行任务逻辑.
- 所有包最终到达主世界服务器, 由其验证并生效.
AllDownstream(下行)- 仅主世界服务器可发送.
- 广播至所有主客户端与子世界服务器, 子世界服务器执行后再转发给其子客户端.
同步方式
- 全任务同步: 含所有任务的信息. 由
ModSystem.NetSend()和ModSystem.NetReceive触发. 与 Terraria 本体相同, 在特定时间点全量同步世界的信息.- 主世界服务器使用
AllDownstream广播完整任务数据.
- 主世界服务器使用
- 单任务同步: 含单个任务的信息. 一般由 数据上传 / 状态改变触发, 对所有客户端进行一次单任务同步.
- 主世界服务器使用
AllDownstream同步单个任务的最新状态.
- 主世界服务器使用
- 数据上传: 含单个玩家的任务进度贡献量, 比如行走的距离, 消耗的物品等. 在客户端与子服务器上进行, 通过任务目标的
OnMPSync方法, 发送数据到主服务器 (发送频率受限).- 客户端与子服务器均使用
MainServer路由上行上传, 由主世界服务器验证后生效.
- 客户端与子服务器均使用
发送主体
- 主世界服务器 (广播至所有客户端和所有子世界及其客户端):
主世界触发世界同步时 (全任务同步), 任务生命周期改变 (单任务同步), 差量数据上传后 (单任务同步).- 主世界服务器是唯一可使用
AllDownstream的节点.
- 主世界服务器是唯一可使用
- 子世界服务器 (直接发送至主世界):
上传子世界本地收集的玩家进度 (客户端收集内容除外).- 始终使用
MainServer路由, 仅转发, 不执行任务逻辑.
- 始终使用
- 客户端 (由子世界服务器转发至主世界):
上传客户端本地收集的玩家进度、请求重试失败任务、请求发放奖励.- 始终使用
MainServer路由; 若处于子世界, 则由子世界服务器转发.
- 始终使用
任务提示
状态切换广播
- 正常更新: 需要
- 加载世界(Load/SaveData): 不需要
- 加载世界(NetSend/Receive): 不需要
- 强制同步(NetSend/Receive): 需要 (可以更换文本)
备注:
- 书写在State属性的get中, 会失去灵活性
- 在多人游戏下, 客户端调用
NetSend/Receive加载世界时,Main.NewText会无效, 因此默认情况下不需要广播. 如果需要广播, 可以在ModPlayer.OnEnterWorld中广播
任务UI
监听任务系统更新, 刷新UI