William_Shi
本帖最后由 William_Shi 于 2023-4-10 20:44 编辑

近日坛友遇到一个问题。众所周知,发送一个实体生成数据包(Spawn Entity)给客户端,就可以生成一个虚假实体。在服务端内,没有这个实体所对应的对象,只能通过插件发送其他数据包的方式来操作该实体(例如 Entity Metadata 等)。往常,只要把实体生成数据包发送给附近的玩家,就可以保证这些客户端都显示该实体。然而,如果某位玩家最开始接收到了实体生成数据包,此后又向远处跑开一段距离,使得虚假实体所处区块到了服务端所给定的 view distance 之外(或客户端的渲染距离以外,总之使得客户端不再加载也不再渲染该区块),在这样的情况下,如果玩家又回到虚假实体所在的位置,则无法再看到那个虚假实体。简而言之,插件发包生成了虚假实体,玩家一开始能看到,然后走到远方又返回原处,就看不到了。

此时一种比较简单的解决办法是重新发送实体生成数据包。只要原先发送的实体生成数据包中的实体 ID(整数ID,由Entity类内的那个 AtomicInteger 所控制)和第二次发送的数据包内的实体 ID 一致,就不用担心客户端看到两个虚假实体。但是重新发送实体生成数据包的时机很成问题。如果频繁检测玩家的位置然后计算该玩家与虚假实体间的距离,固然可以达到目的,但效率堪忧。

我猜想区块加载应当是这样的流程:玩家移动,然后想要加载远处的某些区块,这个时候向服务器发送一个数据包,请求服务器发来区块信息,服务器接收到这个请求以后,就把区块的有关数据发送给客户端。

如果这个猜想成立,那么,只要能够监听到服务端把区块的有关数据发送给客户端的数据包,截获并添加虚假实体有关的信息,发送给玩家,就可以使得玩家每次加载虚假实体所在的区块时,都一并加载这个虚假实体,不用手动去发送一个额外的实体生成数据包了。

为了寻找相关的数据包,我查阅了 wiki.vg,但是只看到了如下数据包:
https://wiki.vg/Protocol#Chunk_Data_and_Update_Light
这个数据包中,只有区块内的方块信息、亮度信息、TileEntity信息。总之,全都与方块有关,没有除了 TileEntity 以外的实体信息。

我尝试在 SpigotMC 寻找一些相关讨论,发现在 2017 年就有人发出了与我一样的疑惑(#8)
https://www.spigotmc.org/threads/entities-packets.245465/#post-2461309
也就是说,当客户端想要向服务端请求区块信息时,似乎服务端只发送了方块、TileEntity等信息。而区块内的实体信息,则不知道是由哪个数据包传递的。它肯定存在,但是我们未能找到。

我知道肯定有很多坛友会为“发送实体生成数据包的时机”这个问题提供很多宝贵的建议,但是我主要是想了解“区块内实体信息由哪个数据包来传递”这个问题。万望坛友不吝赐教,区区不胜屏营之至,顿首顿首。