Minecraft的地图更新逻辑是这样的[1]

通常,只有围绕玩家的大部分区块才会被游戏更新。这些区块被称为玩家的区块更新范围。当玩家在世界中移动时,进入范围的新区块会被添加到更新区块的列表中,并且在范围之外的旧区块将被移除。只有在列表中的区块才会被更新以反映时间的流逝。这意味著例如当玩家在其他维度中花上太多时间去探索时,他种下的农作物不会生长,并且烹饪、烧炼或自动化农场在他回来之前都不会完成。


虽然我不了解Minecraft的游戏设计机制,不过题主所说的』还是说一下子就把整个地图下载下来,然后只同步地图更新的事件『 的说法应该是不对的。

原因很简单,以下是Glavocraft上一个周目的离线地图存档+游戏本体:

然后Galvocraft本周目用到的客户端大小:

参考

  1. ^https://minecraft-zh.gamepedia.com/%E5%B8%B8%E5%8A%A0%E8%BD%BD%E5%8C%BA%E5%9F%9F


多人不是特别清楚,单机的操作是,当一个区域附近首次有玩家存在时,生成区块信息,并将其存入region(主世界)或DIM_1(地狱)或DIM1(末地)的.mca文件里;然后若此区域附近有玩家,将信息存入内存进行载入,否则将之从内存卸载(spawn chunk和受/forceload影响的区块例外,这些区块永不卸载,甚至即使你不在对应维度)

多人的话,怀疑可能是在单机的区块生成和载入机制的基础上,仅将玩家附近的那些区域下载了下来。推测的理由是,当你网路状态很差的时候,你所在的区域不会卸载消失,但是当你试图往远走的时候,会看到明显的已载入/未载入区块边界。如果整个地图都下载的话,应该是能够进一步载入远处的区域的(因为这将不再需要网路;虽然里面的生物什么的应该都不会动,因为这部分内容没同步)。另一个理由是,有些地图实际上非常大,但是流量监控显示玩一次mc并没有如此巨大的流量消耗,这只能表明地图并没有被全部下载。


首先多人游戏的地图是走到哪里下载哪里的,但是不是圆,而是正方形。

正方形的大小可以在server.properties中设置,即view-distance

这个值默认为10,代表玩家为中心,上下左右各数10个区块,也就是21*21的范围,441个区块,当玩家走动时会影响区块传递和载入。

当地图发生更新时,有两种情况

  1. 如果更新的是实体(或方块实体),那就不用重传区块,直接传输实体信息
  2. 如果更新的是方块,就会重传整个区块(16*16*255个block)。特别的,如果更新的是区块边上的方块,则有可能会造成隔壁区块更新,这时候就会重传多个区块

所以你在玩mc的过程中,如果遇到区块载入或者渲染出错,在隔壁区块放置或破坏一个方块就有可能恢复正常


作为一个mod开发初学者来说说我的理解。

一般的处理机制是,玩家把动作上传到伺服器,由伺服器进行合法性验证并处理,更改存档文件。

而客户端会不断的尝试与伺服器同步附近的区块,同步的数量与伺服器的视野范围设置有关。

因此,在网路或伺服器卡顿时会发现一种现象,刚挖的方块重新出现,就是因为伺服器还没对你的操作进行处理,所以客户端仍然使用你挖掉方块之前的地图,直到同步为止。

客户端只会等待伺服器的处理结果,不会自己处理,在mcp反编译的源代码中,很多操作都会使用「world.isRemote」来判断当前游戏环境是客户端还是服务端,比如经验变更、方块变更等,如果把这些操作用于客户端,会引起数据不同步。在编写mod的过程中,也要在这些操作前确保world.isRemote为false.

先说这些,想到其他了再更


只会载入玩家附近的区块,根据伺服器视距大小发送对应范围的区块数据


也没关心是怎样的,反正看到人就想打,看到动物就想砍,看到花儿就想采,当然,还有其他的,多多益善嘛哈哈哈哈哈哈哈


全文瞎猜,想要正确答案自己去找会翻代码的人。

首先排除「整张地图全都下载」,桃子吃不完拿出来分了。这样既占用带宽还没啥屁用,毕竟下载下来玩家还得渲染呢。

至于破坏方块后的同步,应该是「将破坏方块的动作上传至伺服器,在进行处理,处理后下发到客户端,单位为一个区块(16*16*16)」。


// Tank for invte

你好,大家。我是王弟的室友、DRE。我今天很光荣能有这个机会可以在这为大家讲解 么C (又名 micro福特) 的本地区块管理系统。也请大家多多指教。。。

这里以 Minecraft/17w16a 的版本为参照,将大致的说到 [1]世界的载入(何时),[2]世界的运行(何样),[3]区块的载入(何时,何法),[4]区块的卸载(何时,何发,会怎样),[5]C/S大致的方块数据的同步概念。

1/Load of the WorLds

本人认为世界的单纯载入并不意味著极大的能源开销问题,你们知道,高密度的方块各种更新 不小量的实体较高密度更新 是较为耗费资源的 不仅是运算的时间资源,运行时存储的空间资源在早期时候也让人有些在意。然而即使这样,我认为很多时候也可以在伺服器开启时载入所有世界。但这并不意味著非法开销问题,亦或功能设定的问题。

3dLord of Chunks

区块的载入很大程度上取决于一个 于server.management中的一个程序 ChunkMap。ChunkMap 持有著一列 ChunkMapEntry, 每个Entry对应一位区块 记录其被「看」到的玩家(这是一点。下文计做listeningPlayers计数器。) 及各种相关该区块的一些相关管理数据。

// 转自一张图片。。

图中的每个瓦块,对应著一个区块/ChunkMapEntry。其中有3个大的"块",代表三个玩家各自所能看到的区块(虽然图中没有标明界限)。可见图中他们各自有不同的viewDistance(通常由伺服器端决定)。假设实际情况如图中所示,最上面一行瓦块对应的区块,只有被一名玩家所看到(最上面那位),因为size(listeningPlayers)不为0,所以那些区块被载入 并收到更新后会传递给区块的listeningPlayers。而第五行第五列(从1开始数的话。。)的瓦块所对应的区块Entry的listeningPlayers则有2为,分别是最上面那位,和中间(垂直方向)那位。所以该区块的更新会传递给这两位人士。

其实图中已经诠释了情况,从一个层度来看,区块列表活动管理可视为 1. load/unload 载入/卸载,和 2. 发生改变。载入/卸载将在lisneningPlayers计数器发生变化时发生 仅当计数器从0变为1时区块被载入,当从正数变为0时区块被卸载。而发生的改变则将通过listeningPlayers传递给对应正在"收听/可见"该区块的人士 。

区块载入于提供区块时。这将首先会检查已被载入/运行的区块列表,假设没有,那么检查从存档载入,若存档也没有该区块,那么则生成一位区块。

4. unloadChunk(si

上文其实有提到,在listeningPlayers从正数(实际上是1,因为即使是1以上 也是递减至1。。)变为0时,区块卸载发生。与之而来的 还有一个呼叫客户端区块卸载。若一个区块Entry的listeningPlayers被减少一位人士后(通常因为该人类跑的太远了 其的viewDistans 看不到该区块了),会发送一个数据包给该客户端,告诉他需要卸载一个区块 并包含该区块的地址 随后客户端将会卸载该区块以让客户端玩家不必持有过多非法不被管理的区块。然而与之对应的 还有一个当玩家被添加到一个区块Entry的listeningPlayers时的操作,那就是发送整个区块的数据 并让该客户端读/显示该区块。值得一提的是,通常玩家对方块的操作 或小量方块更新,只会涉及到对应被更新的方块的数据传输,整体的区块数据传输通常在玩家刚载入该区块时发送。

5. trans of blocks in net sync

在第4段中,有提到一些关于方块传输的内容。是的,小量方块更新 通常仅传输对应被更新的方块。然而,每个被载入的区块对应的瓦块,区块Entry的listeningPlayers计数器又是怎样被更新 增加/减少的。。。这其实则是 ChunkMap 的行为。在world.onTick() 时, ChunkMap被更新,通过遍历每个在该天地玩家,遍历其视野距离 判断能被其看到的区块,再遍历这些能被其看到的区块 若该区块所对应的区块Entry的listeningPlayers包含他的话,那么不做什么,若不包含他,则添加他进去,并将该区块的数据发送给他。遍历完所有玩家后,开始遍历所有已被载入的区块,判断每个区块是否能被每个玩家所见,从对应该区块的区块Entry的listeningPlayers中去掉不可见该区块的玩家,并发送数据包让其客户端卸下该区块。


推荐阅读:
相关文章