游戏刻 与 刻 为同类游戏设定。
本文所有内容均基于 Java 版,基岩(BE)版不保证所有特性相同(部分已说明 BE 版的内容除外)!
简介
游戏刻(Game Tick,简称 gt )是 Minecraft 底层中用于计量时间的单位,常被用于衡量红石电路延迟、TNT 爆炸时间等重要指标,是Minecraft 中最小的完整时间循环单位,但是实质上,游戏刻是可以被再分的,但是再分后不再是一个完整的时间计量(打一个不太恰当的比方,就像是水分子 H₂O 一样,一个水分子内含一个氧原子和二个氢原子,而通过某些手段,其可以被拆分为一个氧原子和二个氢原子,但是拆分后它不再是一个完整的水分子)同时也不能被视为一个完整的循环周期。在同一个游戏刻内发生的事件其实实际上依然是有先后顺序的,但是他们依然会被定义为“同时”,可以粗浅的理解为这本质上是将一组的同时发生的事件在一个循环内按某些顺序先后处理后打上一个“同时”的标签,这也就使得某些本来玩家期望要在同一个 gt 内按照某种特定顺序发生的事件因为顺序问题不得不更改顺序或将其置于另一个 gt 内进行(实际上这种特性在计算机的运行本身中也有一定的体现)。实际上,对于很多游戏都会有类似的设定,因为用离散的、逻辑性的、有先后顺序的计算机去模拟连续的、同时性的事件本就是一个难题,只是因为 Minecraft 是沙盒游戏的同时加入了红石系统,使得这个现象被特别突出了出来(而不是因为 MOJANG 不会做游戏)。同时,Minecraft 中的一切事件的时间长短都是基于游戏刻的,现实世界的一秒对应 Minecraft 的 20gt,这意味着电脑必须在 1/20=0.05,即在 50 毫秒,如果电脑的运算能力无法在这么短的时间内完成运算,那么一个游戏刻的时间会被延长,使得一秒执行的游戏刻会变少,即对于任意情况,我们都有每秒执行的游戏刻数量 ≤20;同时相应的,当一秒执行的游戏刻变少时,某些游戏内容也会相应的变慢,如熔炉烧制一个物品需要 10 秒即 10*20=200gt,如果此时电脑的处理能力使得一秒仅能执行 10 个 gt 而非 20 个 gt,那么烧制一个物品所需要的时间(现实时间)将会变为 200/10=20 秒。正因为游戏刻的种种特性,使得其变为深入研究 Minecraft 红石系统的玩家游玩中所不可或缺的一部分。
(注:如无深入了解打算可以仅阅读开头的“基础概念与部分属性”部分)
基础概念与部分属性
Minecraft 的循环程序是以每秒 20 周期的固定速度运行的,即 TPS: 20.0。因此每刻发生在每 0.05 秒。在游戏中的一天将正好为 24000 刻,或 20 分钟。但是这个速率也不是完全固定的。如果电脑的性能不足以跟上这个速度,一个游戏刻的运行时间就被延长,每秒的游戏刻就会变少。由于游戏中的绝大多数动作都是以游戏刻而不是真实世界的时钟作为时间基准,这意味着在较慢的电脑上很多事情都要花更长的时间来完成。
每过去一刻,游戏的各方面都会更新:移动的实体位置会发生变化,生物会检查周围环境并更新自身的行为,玩家的生命值和饥饿值会根据玩家的处境发生变化,等等。这些游戏的方面是服务端的行为,和负责渲染游戏本身的客户端的更新速度没有关系。也就是说,游戏的帧率(FPS)不影响 TPS,电脑的图形性能不会影响到游戏机制。
和每秒刻数(TPS)相关的一个单位是每刻毫秒数(MSPT),即服务器实际上用来计算一刻所需的时间。只有在 MSPT 不超过 50 时,TPS 才可以达到 20。以下的游戏机制比较消耗资源,容易导致服务端卡顿:
漏斗收集上方物品。可以通过在漏斗上添加容器方块防止这一行为发生。也可以直接换成吞吐量更大的水流运输。
红石电路更新。应该在时钟等线路上增加开关,以避免不必要的状态改变。另外红石造成的亮度更新也会造成卡顿,可以通过尽量减少空气空间避免。
生物 AI。可以使用照明控制怪物的产生,并使用更高效的技术养殖家畜。
有些 Mods 可以优化或简化游戏逻辑。由于 Mods 是第三方产品,不会特别声称其适用性。
本质
游戏刻的本质其实是按照一个特定的执行顺序进行不同类型的更新与运算,并将执行结束后 50 毫秒内的剩余时间进行延迟。以此为基础作一个循环,最后达到做出所谓“时间”这个概念的目的,而对于这个循环的某一个周期本身,我们称之为游戏刻(Game Tick),同时,对于循环周期的次数(即时间量)则称之为游戏刻(Game Time)。
游戏刻的执行顺序
将游戏进行反编译并使用官方的混淆映射表,进行反混淆后从源码进行解析不难看出 Minecraft 的游戏刻执行顺序,值得注意的是,获取 Minecraft 的源码本身就是不合理且不受法律保护的,虽然官方 MOJANG 默许甚至在一定程度上略微支持这种行为,而在没有获取官方允许授权的情况下对 Minecraft 的源码直接进行公布、抄袭还有用于商业行为是违法的,以下是 Minecraft 在一个游戏刻中执行的顺序(适用于 1.13.2,但是事实上,这个时间顺序在 1.14 以下版本大部分(而不是全部)都适用,对于涉及到底层的执行方面官方很少会对此进行大修改):
成就命令相关。
同步玩家客户端的时间。
极限模式下难度锁困难判断。
群系生成相关。
玩家睡觉逻辑。
生物、怪物刷新。
区块卸载。
天空光衰减计算。
设置 GameTime 与 DayTime(即世界时间相关)。
计划刻(Scheduled tick 或者 Tile tick 亦或者叫做 Next Time Entry)。
随机检查并更新玩家周围的亮度。
天空光的计算与将新增的 Tile Entity 储存至区块内;雷电;下雪与结冰;随机刻。
玩家加载的区块列表更新,并发送客户端方块更新数据包。
村庄运算。
僵尸围城。
地狱门缓存清空。
方块事件(Block Event)。
维度卸载判定相关。
维度相关的运算(目前仅有末地的龙战相关逻辑)。
天气相关实体运算。
玩家实体运算。
普通实体运算。
方块实体运算。
发送客户端实体更新数据包。
网络玩家信息运算。
自动保存。
由于 Minecraft 的游戏延迟与时间更新不同步,两个游戏刻之间的间隔的选择成了一个问题,参考前人的某些理论分析:作为一个离散的时间量,在游戏运算中一定存在某一个时刻,GameTime(游戏刻)这个时间量发生改变,这就是 GameTime 的分界线,这里前人将其划分为 GameTime 与 GameTime+1,同时给出了游戏刻的确切定义:
“GameTime 为 x 的定义为:所有执行 World.worldInfo.getGameTime() 得到的返回值为x的时刻的集合。”
同时,这样可以得到事件 P 发生于 GameTime x 的定义:
“一个事件 P 发生于 GameTick x 的定义为:发生事件 P 时若执行 World.worldInfo.getGameTime() 得到的返回值为 x。”
这么定义的好处:
与计划刻元件的执行时间相对应,在 GameTick 为 N 时所触发的 X gt 延迟的计划刻元件会在 GameTick 为 N+X 时进行更新。
照应前人研究,鉴于以前红石理论多基于命令方块,而命令方块更新依赖 Game Time,如此定义使一些较为远古的红石理论能与其兼容。
可以直观的在代码中调用 World.worldInfo.getGameTime() 来确定当前的 GameTick。
不会调用代码的可以使用命令方块进行调试。
由此可得新的运算顺序:
设置 GameTime与DayTime(即世界时间相关)。
计划刻(Scheduled tick 或者 Tile tick 亦或者叫做 Next Time Entry)。
随机检查并更新玩家周围的亮度。
天空光的计算与将新增的Tile Entity 储存至区块内;雷电;下雪与结冰;随机刻。
玩家加载的区块列表更新,并发送客户端方块更新数据包。
村庄运算。
僵尸围城。
地狱门缓存清空。
方块事件(Block Event)。
维度卸载判定相关。
维度相关的运算(目前仅有末地的龙战相关逻辑)。
天气相关实体运算。
玩家实体运算。
普通实体运算。
方块实体运算。
发送客户端实体更新数据包。
网络玩家信息运算。
自动保存。
成就命令相关。
同步玩家客户端的时间。
极限模式下难度锁困难判断。
群系生成相关。
玩家睡觉逻辑。
生物、怪物刷新。
区块卸载。
天空光衰减计算。
(其实就是把 GameTime 与 DayTime 前面的部分挪到了后面)
简化版顺序
对于较为重要的修改服务端世界相关操作所在的阶段,可得简化版的顺序列表(这个简化表同时适用于两种不同的分界线……):
顺序 | 阶段 | 名称 | 缩写 |
---|---|---|---|
1 | 设置世界时间 | World Time Updata | WTU |
2 | 计划刻 | Scheduled Tick/Tile Tick/Next Time Entry | ST/TT/NTE |
3 | 随机刻与气候 | RandomTick&Climate | RT&C(RTC) |
4 | 村庄相关 | Village | V |
5 | 方块事件 | Block Event | BE |
6 | 实体 | Entity Updata | EU |
7 | 方块实体 | Tile Entity | TE |
8 | 玩家操作 | Network Updata | NU |
9 | 刷怪 | Spawning | S |
10 | 区块加载 | Chunk Unload | CU |
一些容易误判顺序的更新顺序
引用前人理论研究:
活塞推出方块:
当活塞普通推出,即用时 3gt 的推出,此时被推出的方块到达目标位置时,更新顺序为 Tile Entity。而当活塞收到短脉冲,即 0gt,1gt 或者 2gt,此时被推出的方块到达目标位置的更新顺序为 Block Event。如果是推出方块使红石线连接,更新顺序也为 Block Event。活塞破坏绊线:
这是在活塞推出瞬间完成的,绊线被替换为 36 号方块。所以更新顺序为 Block Event。树苗成熟:
自然成熟的树苗是由 random tick 完成,更新顺序为 random tick。发射器骨粉催熟树苗,更新顺序是在发射器更新的 NTE。玩家骨粉催熟的树苗,更新顺序是在玩家更新的 Network Update。命令输入:
命令方块执行命令的更新顺序为 NTE,而玩家执行命令的更新顺序为 Network Update。红石灯:
红石灯是个很特殊的元件,它的点亮与熄灭更新顺序不同,点亮时瞬间点亮,与红石导线一样,没有任何延迟,而在熄灭时,有 4gt 的延迟,并且更新顺序为 NTE。重力方块:
MC 中的沙子、沙砾等,其掉落前 1gt 延迟也是通过 NTE 实现,但它们在接收到 NTE 更新时,并不是立即更新周围方块,而是先创建掉落的沙子实体,等到实体更新时才将方块所在位置设成空气。所以,沙子掉落形成的更新顺序是 Entity Update。
活塞
活塞与粘性活塞的行为与更新顺序十分奇葩,但是此词条仅讨论游戏刻本身,所以此部分将会加入活塞和粘性活塞的词条中。
参考资料
《深度剖析Minecraft #1 游戏流程》——Fallen_Breath
《[理论分析] 红石更新延迟理论》——Gamepiaynmo
《【MC】想学0t?来这里就对了 最详细的0t原理讲解+干货讲解【第一讲之0t基础原理讲解+36号方块篇】》——Donocean
《【MC】XYZ §1.1 红石tick bug【Sancarn&Selulance】》——Sancarn&Selulance(搬运者为:红石科技搬运组)
《【MC】XYZ §1.2-6 红石tick bug【Sancarn&Selulance】》——Sancarn&Selulance(搬运者为:红石科技搬运组)
《游戏刻》——Minecraft wiki
侵删。
资料分类: | 游戏底层事件 |