写了个程序
本帖最后由 洞穴夜莺 于 2024-2-14 23:31 编辑最近服务器打算开正版验证,需要将所有人的离线UUID转为正版UUID。
一开始受服主建议看了贺兰兰的mcserver_player_uuid_modifier,然而这个程序选完目录之后直接无响应,于是阅读源代码,意外发现它只是重命名文件而完全没有修改文件内容的逻辑,这意味这它根本不可能完成转换存档的任务。
于是决定着手自己写一个,逻辑非常简单,是十分简单的查找替换
[*]重命名文件
[*]匹配 NBT 类文件中的 {zzzUUIDMost: xxxxxx, zzzUUIDLeast: xxxxxx}
[*]匹配 NBT 类文件中的
[*]匹配文本文件中的xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
[*]匹配文本文件中的xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
其中 NBT 类文件是指.mca(Anvil区域文件),.mcc(外置区块),.dat(玩家数据),文本文件是指.txt(纯文本),.json(JSON文件),.json5(一种扩展的JSON文件格式,通常用作模组配置文件),至于一些模组使用的.sqlite文件感觉不是很必要了就没弄,还有.properties、.toml虽然也是文本但看着不太像是uuid会出现的地方所以也没管。在开写之前先去服务器上下载了一个比较小的子服的存档,大约13GB,作为测试存档。
Anvil区域文件格式比较复杂,Wiki里面写了一长串。本想着太长不看,直接去找valence_anvil库来读取,然后使用valence_nbt进行反序列化之后深度优先搜索查找匹配,完事再用valence_anvil库写回去。然而实际写出来程序慢得离谱,存档总共约10^7个区块,它的处理速度大约只有3*10^2个区块每秒。[贴吧_泪]
所以只能去Wiki看文件格式,大致看明白了4KiB为一个扇区,第一个扇区是每个区块的数据的位置,第二个扇区是每个区块数据的时间戳,之后是数据。调试了将近一天,其中有一个很离谱的BUG是区块在处理过程中变少,一开始百思不得其解,后来发现是index & 0x1f写成了index & 0xf导致取出来的区块坐标不对,然后写入时相同坐标新的覆盖旧的。。。
至于NBT匹配我选择不序列化成树状表示,而是直接在原始数据上做流式处理,这样或许能节省一些时间,虽然编码量是大大增加了,不过好在我不是第一次编写NBT序列化反序列化了,对格式熟悉得很。。。
[哔哩_OK]
关于多线程处理,我的基本思路是把所有要处理的文件扫描出来。然后列表分段丢给各个线程取处理,由于.dat文件比.mca文件小得多得多,为尽量避免这些轻松的任务全被一个线程占了,所以分配之前进行了打乱处理。
然而在测试存档上跑的时候,它几乎没有替换UUID,发现映射的左边的UUID不对,翻了Minecraft和JDK的源码才发现md5完之后要修改几个数位才能变成UUID,之前一直以为离线UUID就是md5("OfflinePlayer:" + name)的
[哔哩_大哭]
改完之后算是在测试存档上跑通了,放了几只狼,驯化它们,转换存档之后狼主人变成我的正版账号了,而且物品栏也还在,说明转换还算成功。
丢上服务器,关掉那个比较小的子服,备份之后开始转换,然后不出意外的话就要出意外了。程序一直报错External chunks而没有实质性的进展,返工吧。
看一眼存档,我下载存档的时候档里还没有.mcc文件的,然后现在它就有了,程序里Anvil只在正常读取的时候前进了读取指针,遇到错误和外置区块之后就不动了,于是修了这个问题然后有限地实现了外置区块。
[哔哩_灵魂出窍]
最后是在那个子服上跑通了,开了正版验证,从通过Velocity连接改成了直连。我打算如果没有人抱怨存档有问题的话过几天就把所有子服都迁移到正版验证上去,然后再架Velocity跨服。
仓库:https://github.com/CaveNightingale/uuid-remapper
观众席:@xiang_xge 脑子要长了 还是服务器大佬[哔哩_脱单]
页: [1]