欢迎光临散文网 会员登陆 & 注册

深度剖析Minecraft #1 游戏流程

2019-12-08 19:14 作者:Fallen_Breath  | 我要投稿

b站不滋瓷markdown真的好麻烦

前往我的博客获得更好的markdown浏览体验以及更为长期的更新支持:

https://fallenbreath.me/2019/12/08/deeply-dissecting-minecraft_1

修订#1:2020-11-07

1 游戏流程

1.1 代码层面上的 GameTime 内游戏运算顺序

下图这张树状剖析图,代表了代码层面上,Minecraft 每执行一次 tick() 时的游戏执行顺序:

游戏流程剖析
游戏流程剖析

如读者感兴趣,这里(见原文)是1.15.2版本的流程分析图

1.2 GameTick

GameTick(gt),也就是游戏刻,或者说游戏里的时间量,是用来衡量电路延迟、生物生存周期等的重要指标。要想明确 GameTick 是什么,就先得给出 GameTick 的定义

作为一个离散的时间量,在游戏的运算过程中一定存在某个时刻,GameTick 这个时间量发生改变,这就是 GameTick 的分界线。在 1.1 节,我们从代码执行顺序的角度列出了游戏的运算顺序。在这个长达 24 条的列表里,我将 GameTick 的分界线的划分在:GameTime 与 DayTime 加一,并给出GameTick的定义:

GameTick 为 x 的定义是:所有执行 World.worldInfo.getGameTime() 得到的返回值为 x 的时刻的集合

于是,我们可以得到事件P发生于GameTick x的定义:

一个事件P发生于 GameTick x 的定义为:
发生事件P时若执行World.worldInfo.getGameTime(),得到的返回值为 x

这样做定义 GameTick 的好处有:

  • 与 TileTick 元件的执行时间相对应。在 GameTick N 触发的 x gt 延迟 TileTick 元件会在 GameTick N + x 执行动作

  • 可以直观地在代码中调用 World.worldInfo.getGameTime() 来确定当前的 GameTick

定义完 GameTick 并确定好分界线后,我们就可以重新排列 1.1 节的树状图,并获得一个 GameTick 内各阶段发生的顺序了:


游戏流程剖析,从 WTU 开始
游戏流程剖析,从 WTU 开始

对于与修改服务端世界相关的操作所在的阶段,即树状图中使用黄色标出的阶段,可归纳得到下常用阶段顺序表:

这个常用阶段顺序表是之后分析最为常用的列表,划重点记笔记!(其实只要记住缩写即可,因为下文会大量使用缩写)

对于之后对精确到一个游戏刻内阶段的分析,我称之为:微观时序分析

1.3 游戏事件执行时刻

这一章节的目的是概述各大部分游戏事件运作的时刻,其中性质的详细描述见后文

在1.2里,存在以下几个游戏阶段为抽象的阶段,并未明确声明在其中会发生什么事件。它们是: 

  • 计划刻 TT 

  • 方块事件 BE 

  • 方块实体 TE 

  • 玩家操作 NU

下面列一下大部分与之相关的游戏事件

  • 中继器、比较器、红石火把、侦测器的激活与熄灭:TT

  • 按钮、压力板、红石灯、绊线、绊线勾的激活:瞬时;熄灭:TT

  • 拉杆、红石线、铁轨、各类活版栅栏木铁门、漏斗、音符盒、投掷器发射器的激活与熄灭:瞬时

  • 投掷器发射器的工作:TT

  • 命令方块的运作:TT

  • 树叶、流体、脚手架的更新:TT

  • 重力方块判定并创建重力方块实体:TT

  • 活塞推拉的开始:BE

  • 移动中方块的运算:TE

  • 移动中方块的到位:BE(粘性活塞受短脉冲);TE(粘性活塞受长信号)

  • 玩家移动、放置破坏方块、与方块交互:NU

注:瞬时指的是可属于任意阶段,触发即运算,且触发与运算之间无法插入其他操作

实例 自加载型区块加载器伪和平

对于基于在卸载后能加载回自身的区块加载器的伪和平,在重加载时是否存在 1gt 的刷怪空档期是至关重要的,因为这直接与伪和平是否可用 100% 阻止生物刷新相关。完美的伪和平装置是不存在可刷怪空档期的

让我们分析一下基于活塞区块加载器的伪和平:

活塞区块加载器,利用了方块事件可以加载区块的原理,通过在每个gt利用活塞计划方块事件来确保自动保存后能加载回自身区块。


备注:此活塞加载器并非完美设计,但足以应用于本实例分析

这个方案是可以 100% 阻止生物刷新的,也就是不存在 1gt 的刷怪间隔。微观时序分析很简单。先列一下相关的阶段:

可看到,在自动保存等引发的区块卸载之后,下一次进行刷怪前,游戏执行了方块事件相关的运算,并在此处加载回了存怪的区块,让怪物容量超过上限,阻止下一次进行刷怪时的生物刷新。因此,这是一个完美的伪和平

如果出于某些原因,活塞区块加载器与存怪装置不在同一个区块,需要使用漏斗加载存怪区块,如下图所示。这样的话这种伪和平装置是否还是完美的?

相关的阶段:

让我们看一下这个设计的区块被卸载时的微观时序

因此,这个伪和平设计也能保证 100% 时刻不刷怪,是个完美的伪和平

假如有个小天才嫌一个漏斗太少,非得多串几个漏斗才接到存怪装置区块,那会怎么样?

区块卸载在 GameTick N,活塞加载器自加载在 GameTick N+1 的 BE,三个漏斗依次加载区块使存怪区域在 GameTick N+1 的 TE 被加载?并不是这样的

TE 阶段有个性质:在 TE 阶段内新增的 TE 实体,并不会立即参与运算,而是会先加入一个临时的列表 addedTileEntityList,等到该 TE 阶段运算结束后再统一添加新 TE 实体至参与运算的 TE 列表 loadedTileEntityList 中,也就是说在 GameTick N 新增的 TE 实体要等到 GameTick N+1 的 TE 阶段才能进行运算

因此,这个小天才活塞区块加载器伪和平的微观时序是这样的:

因此这个伪和平方案在每次被卸载时,足足有 2gt 的刷怪空档期,不是一个完美的伪和平方案


深度剖析Minecraft #1 游戏流程的评论 (共 条)

分享到微博请遵守国家法律