《我的世界》让很多第三方受到启发,从而在客户端之外创建出有用的世界文件查看和编辑工具。 Universal Minecraft Editor 和 MCEdit 等工具很受社区欢迎,它们需要知道在磁盘上何处查找 LevelDB 文件中的所有关卡数据。 在版本 1.18.3 中,传统 actor 存储升级为新型 actor 存储, actor 数据在 LevelDB 文件中的存储位置发生了变化,这些第三方开发者需要知晓。
传统 actor 数据是什么样?
在版本 1.18.3 之前, actor 数据按区块存储,所有 actor 都以 Blob 的形式存储在区块中。 这意味着,只要有任何一个 actor 更改,就必须:
- 从区块中每一个 actor 收集数据
- 将每个 actor 的数据附加到单个缓冲/Blob 中
- 将这些分组数据写入区块
为什么移动 actor 数据?
传统 actor 数据存储格式意味着,如果区块中的一个 actor 更改,就必须保存全部数据,即使实际上只有一个 actor 的数据更改了。 这样,会执行大量不必要的操作,区块之间的实体传输处理开销巨大,系统也非常脆弱。
新型 actor 数据在磁盘上是如何存储的?
新型 actor 存储是将每一个 actor 存储在唯一的单个 LevelDB 键下。 这样,如果只对单个 actor 进行处理,可以减少操作。 这同时也意味着,区块中没有面向所有 actor 的键值对。 实际上,各个 actor 键具有各自的键空间,与其余的区块数据分开,并且区块在磁盘上没有直接引用其包含的 actor 的数据。
相反,我们使用区块中的数据确定性地生成区块唯一密钥,在其中存储区块中 actor 的 LevelDB 密钥的摘要。 这些摘要条目也与非 actor 区块数据和 actor 密钥空间分开。
让我们看一下它在磁盘上存储方式:
区块键空间
在图表的左侧,我们可以看到区块键空间。 这些键采用 <Chunk Position><DimensionID>
的传统区块键形式。 有一种非常古老的无维度 ID 的传统区块格式,因此可以加载非常古老的世界,其中区块键没有维度 ID。 它们将保存在具有维度 ID 的新键下。 这一旧行为仍然存在。
这些是通过在磁盘上将它们连续推到一起使用的最小键。 区块键作为前缀,用于存储区块中所有非 actor 数据的键。 来自区块的每种类型的数据都有自己的键 ID,该 ID 附加到区块键前缀。
非 actor 数据区块密钥 ID
enum class LevelChunkTag : char {
Data3D = 43,
Version, // This was moved to the front as needed for the extended heights feature. Old chunks will not have this data.
Data2D,
Data2DLegacy,
SubChunkPrefix,
LegacyTerrain,
BlockEntity,
Entity, // Legacy actor storage which will be deleted from LevelDB upon upgrading the chunk to use modern actor storage
PendingTicks,
LegacyBlockExtraData,
BiomeState,
FinalizedState,
ConversionData, // Data that the converter provides that are used at runtime for things like blending
BorderBlocks,
HardcodedSpawners,
RandomTicks,
CheckSums,
GenerationSeed,
GeneratedPreCavesAndCliffsBlending,
BlendingBiomeHeight,
LegacyVersion = 118
};
actor 摘要键空间
中间是摘要键空间。 每个摘要键都采用 dg<Chunk Key>
的形式。
dg
dg 是所有摘要键的硬编码前缀。 这会强制所有摘要在磁盘上连续存储,并增加所有摘要键的大小,以便将它们放置在 LevelDB 中的非 actor 区块数据之前。<Chunk Key>
是与数据关联的区块使用的相同键字符串。
actor 键空间
右边是 actor 键空间。 每个 actor 键的形式为 actorpref<ActorUniqueID>
。
actorpref
actorpref 是用于所有 actor 键的硬编码前缀。 这会强制所有 actor 数据在磁盘上连续存储,并增加所有 actor 键的大小,以便它们位于非 actor 区块数据和 LevelDB 中的所有摘要之前。<ActorUniqueID>
是每个 actor 添加到关卡时生成的唯一 ID。 此 ID 在游戏会话之间保持一致,并且仅在这个世界中是唯一的。 其他世界中的其他 actor 可能有相同的 ID,但同一个世界的 actor 不会有相同的 ID。