Neige
前情提要: [没什么用的教程] 完全反序列化internal

这个存储方法的确极限压缩的nbt文本的占用体积,恰巧上午我不知道怎么查看.dat文件,还去下了个NBTExplorer玩()
刚才我就突发奇想。。。这.dat文件。。。不会也是这么存的吧?
测了一下发现确实()
测试代码如下:
  1. const ByteArray = Java.type("byte[]")
  2. const IntArray = Java.type("int[]")
  3. const LongArray = Java.type("long[]")
  4. const ArrayList = Packages.java.util.ArrayList
  5. const HashMap = Packages.java.util.HashMap
  6. const GZIPInputStream = Packages.java.util.zip.GZIPInputStream
  7. const BufferedInputStream = Packages.java.io.BufferedInputStream
  8. const DataInputStream = Packages.java.io.DataInputStream
  9. const YamlConfiguration = Packages.org.bukkit.configuration.file.YamlConfiguration
  10. const FileInputStream = Packages.java.io.FileInputStream
  11. const File = Packages.java.io.File

  12. // 这里对应Bukkit的NBTTagTypes
  13. const types = [
  14.     // END类型, 代表已达当前Compound结尾
  15.     function() { return null },
  16.     // Byte类型, 直接读取
  17.     function(dataInputStream) { return dataInputStream.readByte() },
  18.     // Short类型, 直接读取
  19.     function(dataInputStream) { return dataInputStream.readShort() },
  20.     // Int类型, 直接读取
  21.     function(dataInputStream) { return dataInputStream.readInt() },
  22.     // Long类型, 直接读取
  23.     function(dataInputStream) { return dataInputStream.readLong() },
  24.     // Float类型, 直接读取
  25.     function(dataInputStream) { return dataInputStream.readFloat() },
  26.     // Double类型, 直接读取
  27.     function(dataInputStream) { return dataInputStream.readDouble() },
  28.     // ByteArray类型
  29.     function(dataInputStream) {
  30.         // 首位Int用于存储数组长度
  31.         const length = dataInputStream.readInt()
  32.         // 创建相应长度的数组
  33.         const byteArray = new ByteArray(length)
  34.         // byte[]不用整那么多花活儿, 直接readFully就行
  35.         dataInputStream.readFully(byteArray)
  36.         return byteArray
  37.     },
  38.     // String类型, 直接读取
  39.     function(dataInputStream) { return dataInputStream.readUTF() },
  40.     // List类型
  41.     function(dataInputStream) {
  42.         // 用于存储List内容
  43.         const arrayList = new ArrayList()
  44.         // 读取数据类型
  45.         const type = dataInputStream.readByte()
  46.         // 读取列表长度
  47.         const length = dataInputStream.readInt()
  48.         // 如果数据类型是0, 说明这玩意儿有问题; 如果列表长度是0, 直接返回就行
  49.         if (type != 0 && length != 0) {
  50.             // 获取相应类型的读取函数
  51.             const func = types[Number(type)]
  52.             // 逐个读取并存入列表
  53.             for (let index = 0; index < length; index++) {
  54.                 arrayList.add(func(dataInputStream))
  55.             }
  56.         }
  57.         // 返回内容
  58.         return arrayList
  59.     },
  60.     // Compound类型
  61.     function(dataInputStream) {
  62.         // 用于存储Compound内容
  63.         const hashMap = new HashMap()
  64.         // 读取数据类型
  65.         let type = dataInputStream.readByte()
  66.         // 如果尚未达到Compound结尾
  67.         while (type != 0) {
  68.             // 读取数据键
  69.             const key = dataInputStream.readUTF()
  70.             // 存入数据值
  71.             hashMap[key] = types[Number(type)](dataInputStream)
  72.             // 读取下一位数据类型
  73.             type = dataInputStream.readByte()
  74.         }
  75.         // 返回内容
  76.         return hashMap
  77.     },
  78.     // IntArray类型
  79.     function(dataInputStream) {
  80.         // 首位Int用于存储数组长度
  81.         const length = dataInputStream.readInt()
  82.         // 创建相应长度的数组
  83.         const intArray = new IntArray(length)
  84.         // 逐个读取Int并存入数组
  85.         for (let index = 0; index < length; index++) {
  86.             intArray[index] = dataInputStream.readInt()
  87.         }
  88.         return intArray
  89.     },
  90.     // LongArray类型
  91.     function(dataInputStream) {
  92.         // 首位Int用于存储数组长度
  93.         const length = dataInputStream.readInt()
  94.         // 创建相应长度的数组
  95.         const longArray = new LongArray(length)
  96.         // 逐个读取Long并存入数组
  97.         for (let index = 0; index < length; index++) {
  98.             longArray[index] = dataInputStream.readLong()
  99.         }
  100.         return longArray
  101.     }
  102. ]

  103. function readDat(file) {
  104.     const dataInputStream = new DataInputStream(new BufferedInputStream(new GZIPInputStream(new FileInputStream(file))))

  105.     const type = dataInputStream.readByte()
  106.     dataInputStream.readByte()
  107.     dataInputStream.readByte()

  108.     const result = types[Number(type)](dataInputStream)
  109.     dataInputStream.close()

  110.     return result
  111. }

  112. const map = readDat(new File("G:" + File.separator + "Server" + File.separator + "测试用服务端" + File.separator + "1.16.5NI测试" + File.separator + "world" + File.separator + "data" + File.separator + "scoreboard.dat"))
  113. let itemString = new YamlConfiguration()
  114. itemString.set("QAZXSWEDCVFR", map)
  115. itemString = itemString.saveToString().replace("QAZXSWEDCVFR:\n  ", "").replace(/\n  /g, "\n")

  116. print(itemString)
复制代码
我对我服务端内world世界的scoreboard.dat文件进行了解析。
后台返回值如下:
  1. [21:37:04 INFO]: data:
  2. [21:37:04 INFO]:   PlayerScores:
  3. [21:37:04 INFO]:   - Objective: NeigeMana
  4. [21:37:04 INFO]:     Locked: 1
  5. [21:37:04 INFO]:     Score: 20
  6. [21:37:04 INFO]:     Name: Neige
  7. [21:37:04 INFO]:   Objectives:
  8. [21:37:04 INFO]:   - CriteriaName: dummy
  9. [21:37:04 INFO]:     DisplayName: '{"text":"NeigeMana"}'
  10. [21:37:04 INFO]:     RenderType: integer
  11. [21:37:04 INFO]:     Name: NeigeMana
  12. [21:37:04 INFO]:   Teams:
  13. [21:37:04 INFO]:   - CollisionRule: always
  14. [21:37:04 INFO]:     DeathMessageVisibility: always
  15. [21:37:04 INFO]:     AllowFriendlyFire: 1
  16. [21:37:04 INFO]:     MemberNamePrefix: '{"text":""}'
  17. [21:37:04 INFO]:     SeeFriendlyInvisibles: 1
  18. [21:37:04 INFO]:     DisplayName: '{"text":"LD_NoName"}'
  19. [21:37:04 INFO]:     MemberNameSuffix: '{"text":""}'
  20. [21:37:04 INFO]:     NameTagVisibility: never
  21. [21:37:04 INFO]:     Name: LD_NoName
  22. [21:37:04 INFO]:     Players:
  23. [21:37:04 INFO]:     -
  24. [21:37:04 INFO]: DataVersion: 2586
复制代码
很完美对吧()

teddyxlandlee
windows,用中文做目录名……小伙子很勇嘛

Neige
teddyxlandlee 发表于 2022-8-13 20:02
windows,用中文做目录名……小伙子很勇嘛

测试端,遇到问题再看就是了