SYS.READ_STREAM | UTF-8
PATH: LoadingTicket/01-加载票系统中的类型.md
WORDS:1,111
EST_TIME:4 MIN

#01加载票系统中的类型

img.png

本章将建立对加载票这一概念的基本认识。

一个加载票包含了

net.minecraft.server.world.ChunkTicket

  • type 加载票类型,记录加载的原因。
  • level 加载等级,决定区块的运算。
  • tickCreated 创建时间,用于判断加载票是否过期。

在Minecraft一共有8种加载票类型

net.minecraft.server.world.ChunkTicketType

java// EXECUTABLE_BLOCK
public static final ChunkTicketType<Unit> START = create("start", (a, b) -> 0); public static final ChunkTicketType<Unit> DRAGON = create("dragon", (a, b) -> 0); public static final ChunkTicketType<ChunkPos> PLAYER = create("player", Comparator.comparingLong(ChunkPos::toLong)); public static final ChunkTicketType<ChunkPos> FORCED = create("forced", Comparator.comparingLong(ChunkPos::toLong)); public static final ChunkTicketType<ChunkPos> LIGHT = create("light", Comparator.comparingLong(ChunkPos::toLong)); public static final ChunkTicketType<BlockPos> PORTAL = create("portal", Vec3i::compareTo, 300); public static final ChunkTicketType<Integer> POST_TELEPORT = create("post_teleport", Integer::compareTo, 5); public static final ChunkTicketType<ChunkPos> UNKNOWN = create("unknown", Comparator.comparingLong(ChunkPos::toLong), 1);
  • start:用于世界启动时加载出生点。加载距离是 11,即加载等级22 。net.minecraft.server.MinecraftServer#prepareStartRegion
  • dragon:用于进行龙战时加载末地主岛。加载 9 距离,即加载等级24。 net.minecraft.entity.boss.dragon.EnderDragonFight#tick
  • player:玩家加载。
  • forced:用于实现 /forceload指令与强加载出生点。
  • light:用于加载需要计算光照的区块。
  • portal:用于生物或玩家穿过传送门时加载目标维度的区块,300gt(15s)内没有使用过之后,移除与之相关的加载票,加载距离是 3 。net.minecraft.world.PortalForcer#getPortalRect
  • post_teleport:用于生物或者玩家传送时加载目标区块,比如 /tp,5gt后移除。
  • unknown:用于游戏内代码上使用了 getChunk后加载区块,1gt后移除。

加载等级对应着加载距离,算法是:

加载等级 = 33 - 加载距离

net.minecraft.server.world.ChunkTicketManager#addTicket

java// EXECUTABLE_BLOCK
ChunkTicket<T> chunkTicket = new ChunkTicket<>(type, ChunkLevels.getLevelFromType(ChunkLevelType.FULL) - radius, argument); //ChunkLevelType.FULL = 33

需要注意的是,加载距离并不由 ChunkTicketType指定,比如 post_teleport/tp 指令使用时加载距离为 1,而其他情况下为 0。

加载等级被限制在[22-45],至于为什么上限是这个数:

java// EXECUTABLE_BLOCK
public static final int INACCESSIBLE = 33 + ChunkStatus.getMaxDistanceFromFull();

在1.20.1中ChunkStatus.getMaxDistanceFromFull()会返回12,具体请看1.6小结。

在加载等级决定了这个区块能运算什么,一共有四中类型

net.minecraft.server.world.ChunkLevelType

java// EXECUTABLE_BLOCK
public enum ChunkLevelType { INACCESSIBLE, FULL, BLOCK_TICKING, ENTITY_TICKING; }

加载等级与加载等级类型的关系:

net.minecraft.server.world.ChunkLevels#getType

java// EXECUTABLE_BLOCK
public static ChunkLevelType getType(int level) { if (level <= 31) { return ChunkLevelType.ENTITY_TICKING; } else if (level <= 32) { return ChunkLevelType.BLOCK_TICKING; } else { return level <= 33 ? ChunkLevelType.FULL : ChunkLevelType.INACCESSIBLE; } }

加载等级类型决定了区块运算。

  • 运算实体(强加载) ENTITY_TICKING :当加载等级小于等于31时为运算实体,会计算全部的游戏流程,包括实体等等。
  • 基础运算(弱加载) BLOCK_TICKING : 当加载等级小于等于32时为基础运算,不会运算实体,其他正常运算,如红石原件。
  • 加载边界 FULL :当加载等级为33时为加载边界,几乎不会有游戏流程运算,但是会记录实体,也就是说在加载边界的里的实体会被记录上刷怪上线。
  • 不可访问 INACCESSIBLE :当加载等级在大于33时为不可访问,这些区块并没有真正地加载,只是进行了部分的部分的世界生成。

不在本文的讨论范围,但会简略的介绍ChunkHolder的作用。

ChunkHolder是区块管理系统底层中区块的容器,存储了区块本身、区块加载等级、区块生成状态和区块的允许用途。大约可以看成区块在游戏内部的实例。

不在本文的讨论范围,但会简略的介绍ChunkStatus。

ChunkStatus对应了区块生成阶段,1.20.1中有:

  • empty:空区块;
  • structure_starts:获取区块中可能起始生成器结构;
  • structure_reference:用于世界生成;
  • biomes:确定生物群系;
  • noise:生成地形的大致轮廓与基岩层;
  • surface:替换地表附近的方块;
  • carvers:生成洞穴和峡谷;
  • features:生成海底洞穴和峡谷;
  • initialize_light:计算区块的初始光照?;
  • light:计算区块的光照;
  • full:区块加载完成 ProtoChunk转换为 WorldChunk

加载等级对应的区块状态:

  • 34-:full
  • 35:initialize_light
  • 36:carvers
  • 37:biomes
  • 38~45:structure_starts