第一百一十章 UUID
在Minecraft JAVA 1.7.10版本更新中,Mojang认为玩家可以更改用户名。但如果玩家可以更改用户名,那么一个用户名就不能完全代表一个玩家。解决这个问题的唯一办法,就是给玩家添加一个从按下注册那一键开始就不能改变的唯一识别码。
使用什么样的识别码呢?Mojang直接就采用了不管是在Minecraft中还是在网络上都十分常用的『Universally Unique Identifier』来作为玩家的不可改变识别码,这就是作者在之前经常提到的UUID,它的中文名叫做『通用唯一识别码』。
一个UUID本质上是一个长达128位的随机生成的二进制数字,但我们不可能直接使用它的二进制形式,而是使用它的『十六进制』或『十进制』形式。
在十六进制中,最常见的形式就是:
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
这是UUID的『十六进制表示形式』。准确的来讲,是『有连字符的十六进制(Hybr /henated hexadecimal)』形式。这种形式的UUID本质上是将UUID转化到十六进制后,再用连字符『-』将其分割成8+4+4+4+12的5段。
当然,把连字符去掉就是纯洁的『十六进制形式(String without hybr /hens)』了:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
只不过去掉连字符的话,你有很大概率会抄错,所以还是建议在抄UUID之前给它加上个连字符。
什么?你不知道十六进制?
那你总知道十进制吧?在十进制中,数字是逢十进一。比如:
5+5=10
所以对于十六进制来讲,数字就是逢十六进一。比如:
(5+5)+7=a+7=11
其中,字母『a』在十六进制中代表『十』这个数字。以此类推,b代表『十一』、c代表『十二』.......f代表『十五』。
这就是十六进制,你懂了吗?
回到正题。我们在第一百零六章时就已经遇到过『有连字符的十六进制』这种形式的UUID了。你还记得吗?让我们回忆一下:
『/attribute @s minecraft:generic.max_health modifier value get 1-1-1-1-1 2.0』
其中,参数『1-1-1-1-1』就是一个『有连字符的十六进制』形式的UUID。等等,为什么这个UUID不是8+4+4+4+12的?
如果你有注意到游戏返回的消息,就会发现,这种UUID在游戏眼中会被视为:
『00000001-0001-0001-0001-000000000001』
也就是说,UUID中数字前面的0可以被省略。比如:
『00000101-0001-0003-0015-000000032300』
上面这串UUID就可以省略成:
『101-1-3-15-32300』
这是一个非常人性化的设计,也非常符合数学。
需要注意,如果是『10000001-1001-1001-1001-100000000001』这样的,可不要想着缩写成:
11-11-11-11-11
不然游戏会以为这个UUID是『00000011-0011-0011-0011-000000000011』的缩写。
这种缩写不仅仅在『有连字符的十六进制』形式中可用,在其他形式中照样可用。
现在你知道了十六进制形式的UUID。那之前的UUIDMost(UUID高位)和UUIDLeast(UUID低位)到底是啥呢?
在解答之前,作者建议你先去找一个进制转换器,以方便现学现做。
以刚才的『00000001-0001-0001-0001-000000000001』举例,现在它是十六进制。
把前面三段(00000001-0001-0001)和后面两段(0001-000000000001)分开,并分别划成10进制,变成:4295032833和281474976710657这两个数。
这两个数就是这个UUID的高位以及低位了。其实高位以及低位就是将十六进制的UUID切成两半然后划成10进制得出的数,说明白点,就是:
xxxxxxxx-xxxx-xxxx 这一段转换成10进制就是UUID Most
xxxx-xxxxxxxxxxxx 这一段转换成10进制就是UUID Least
(在NBT中,这两个标签的数据类型都为Long长整型)
但要注意,如果没有特别指明,你是不知道一个16进制的数字到底是正还是负。
原因的话,百度/谷歌一下,你就知道(毕竟这是Minecraft指令教学,不是计算机课)。
这种高位和低位的UUID形式,被称为『高低位(Most/Least)』。这种形式在Minecraft Java1.16版本更新前几乎遍地都是,但在Java1.16更新中却几乎绝迹了。
为何?因为在1.16版本更新后,NBT中大部分UUID再也不是『高低位』形式,而是使用了一个全新的表现方式:整型数组(int-array)
其样式我们在之前已经碰过好几次了。比如下面这一串:
[I;-678432868,1549618207,-1367000395,-2137777200]
好像这种形式的UUID和其他形式没有太大关系。
但其实这种UUID和其他形式的UUID也可以互相转换,不然正版玩家的UUID就得重新设置。
如果你不想了解的话,可以跳过这一段,去看看UUID到底该如何获取。
但如果你想了解的话,不妨也来看一看。
仔细观察这一串数组,你会发现这4串数字有正负号,并且没有出现字母,加上这是个『整型数组』。这些证据都证明,这四串数,是十进制。
既然是十进制,那就好办了。根据UUID Most以及UUID Least的经验,这四串数,极有可能是十六进制的UUID平均分成4段再分别划成十进制的数。
为了验证我们的猜想,先随机一个UUID:
十六进制——09fa22c0-807d-4a29-b0fa-a6513fab4822
数组形——[I;167387840,-2139272663,-1325750703,1068189730]
将『09fa22c0-807d-4a29-b0fa-a6513fab4822』的连字符去掉,再平均分成4段,并取最前面的那一段,也就是:
09fa22c0
划成十进制就是:167387840!
这种数组形式的UUID本质上就是将16进制形态的UUID平均分成四段再分别划成十进制最后组合成一个数组!
等等,遇到了一个小问题,这个负数问题,该怎么办?
百毒一下,你就知道。
说了这么多UUID,那么UUID该怎么获取?
如果你是一位Java版的腐竹,开着一个服务器,那你就可以到服务器的根目录找到一个名叫usercache.json或usernamecache.json的文件,里面有全部服务器玩家的UUID。
对于Java的正版玩家来说,有许多网站可以通过输入玩家的名字或UUID来查询一个正版玩家的皮肤、UUID等信息,甚至可以知道这个玩家去过哪些服务器,这些服务器现在有多少人在线,他的游戏时长是多少!虽然不知道这些数据是怎么获取的(极有可能是爬虫),但这也方便我们查询自己的UUID(以及别人的)。
比如最常见的mcuuid.net和namemc.com。
但别忘了,实体也有UUID。那实体的UUID如何获取?
有很多种方法,你可以去网上搜。这里只讲一个最方便的:
在Java1.13及以上版本中,使用聊天栏填写指令时,只要你的准心对着一个实体,在填写目标选择器类型的参数时你就可以通过Tab键一键获取到这个实体的UUID(有连字符的十六进制形式)。
对了,正版玩家的UUID还可以通过Mojang给出的abr /i来获取,具体用法为:
abr /i.mojang.com/users/br /rofiles/minecraft/一个正版玩家的用户名
这里拿一个用户名叫做『Minecraft』的正版玩家举例,输入abr /i.mojang.com/users/br /rofiles/minecraft/Minecraft,网页就会返回如下JSON:
{“name“:“Minecraft“,“id“:“b2732392fae140c3b836a066c6debd8f“}
其中的id就是这名玩家的十六进制UUID。
附录:UUID历史
Java
1.16——NBT中的UUID几乎都改成了整形数组的形式,抛弃了原有的高低位形式。