我的世界服务器玩家UUID生成规则
由于业务需要,研究一下如何将离线版(盗版)minecraft服务器的玩家数据迁移到在线版我的世界服务器上去。
查看minecraft的服务器代码(反编译),如果是在线模式就连接用户验证服务器去获取玩家的uuid,否则就根据规则自动生成。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32//代码片断from: net.minecraft.server.NameReferencingFileConverter
if (minecraftserver.getOnlineMode() || org.spigotmc.SpigotConfig.bungee) {
// Spigot: bungee = online mode, for now.
minecraftserver.getGameProfileRepository().findProfilesByNames(astring, Agent.MINECRAFT, profilelookupcallback);
} else {
String[] astring1 = astring;
int i = astring.length;
for (int j = 0; j < i; ++j) {
String s = astring1[j];
UUID uuid = EntityHuman.a(new GameProfile((UUID) null, s));
GameProfile gameprofile = new GameProfile(uuid, s);
profilelookupcallback.onProfileLookupSucceeded(gameprofile);
}
}
//from:net.minecraft.server.EntityHuman
public static UUID a(GameProfile gameprofile) {
UUID uuid = gameprofile.getId();
if (uuid == null) {
uuid = b(gameprofile.getName());
}
return uuid;
}
public static UUID b(String s) {
return UUID.nameUUIDFromBytes(("OfflinePlayer:" + s).getBytes(Charsets.UTF_8));
}
生成算法是在用户昵称前面加上“OfflinePlayer:”后使用java函数nameUUIDFromBytes来生成。
nameUUIDFromBytes函数代码如下:
1 | // from: java.util.UUID.java |
1、计算出MD5
OfflinePlayer:k1988
-> MD5: 08D699BB6400555E581B678C9441FA75
2、MD5的值和生成的uuid文件名对比
1 | 08d699bb-6400-555e-581b-678c9441fa75 |
== 解析法 ==
还有一种方法就是枚举minecraft服务器中的world\playerdata目录,这个目录下每个文件对应着一个玩家,文件名(不含后缀)就是一个玩家的uuid,文件使用NBT方式储存着一些用户信息,包括用户上一次使用的昵称(可见,在线版服务器是方便更改昵称的),及其它信息。
我fork了一个NBT解析的python代码,并在里面添加了一个python脚本用来枚举playerdata下的所有文件,fork后的代码在https://github.com/k1988/NBT ,脚本在examples/player_print.py,使用时直接player_print.py <playerdata目录路径>
即可,效果如下图: