查看: 9700|回复: 15

测试-记录一些POE相关开发上的东西

[复制链接]
塑型者

121

主题

2166

帖子

6984

积分

版主

Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15

流亡指引者瓦尔之心智慧之书凰炎之印

发表于 2017-11-29 10:41:52 | 显示全部楼层 |阅读模式

WftA_background.jpg

一、 天赋树地址的解析和生成

二、 天赋树信息与珠宝位置


三、REPOE 导出Dat生成json文件。


四、GGPK里的DDS贴图文件
   


五、GGPK里面的SMD模型文件。

待续







本帖最后由 lucifering000 于 2018-3-22 20:23 编辑

2人点赞



【POB】PathOfBuilding国服版
【Tool】国际服Build转国服pob
http://bbs.17173.com/thread-10923378-1-1.html


【Tool】国际服论坛&poe.ninja 装备技能汉化插件
http://bbs.17173.com/thread-10755360-1-1.html

【LabCompass】迷宫插件-国服
http://bbs.17173.com/thread-11248376-1-1.html

【Tool】POE-DDS贴图&SMD模型预览解压导出工具
http://bbs.17173.com/thread-10827920-1-1.html

POE工具开发相关知识点
http://bbs.17173.com/thread-10492236-1-1.html
回复

使用道具 举报

塑型者

121

主题

2166

帖子

6984

积分

版主

Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15

流亡指引者瓦尔之心智慧之书凰炎之印

 楼主| 发表于 2017-11-29 11:22:07 | 显示全部楼层


一、 天赋树地址的解析和生成


1、天赋树地址结构:


例如某个天赋树地址连接是这样的:


https://poe.game.qq.com/fullscreen-passive-skill-tree/3.0.3/AAAABAMDAQQHBLMGSQceCPQN4hEtEZYWbxg8GFYabBzcIvQkqij6KlMqmCycMtE1kjbpOQs6WDrhPC1Bh0QERUdFnUZxR4VHt0iOSU9JUUtXTLNNuU3jU1JUrlXGVdVakV-wYENqQ2qsa9tsC20Zbj1vnnyDfdJ-WX_GgseDCYNfg8yD24TFhTKFYIYCiECPGpAzkyeVLpctmK2a4JuKm7WhL6IAplemrKh9qsSsmLB3snC0DLc-uJO8qrzqvSe-T76AvorAZsDjykrK08y80B_T-9i92QvZXt-K42rr7uyK7-vw1fGz8kX31_no-oD-Cv6B_o8=?accountName=%E5%85%89%E5%BD%B1%E8%B7%AF%E8%A5%BF%E6%B3%95&characterName=%E4%BA%A1%E9%AD%82%E5%B8%88%E5%8D%A1%E5%A1%94%E8%8E%89%E5%A8%9C




·开头的“https://poe.game.qq.com/fullscreen-passive-skill-tree/3.0.3/”是网站路径,不同网站的不一样。


·结尾的“?accountName=%E5%85%89%E5%BD%B1%E8%B7%AF%E8%A5%BF%E6%B3%95&characterName=%E4%BA%A1%E9%AD%82%E5%B8%88%E5%8D%A1%E5%A1%94%E8%8E%89%E5%A8%9C” 是账号名和角色名称,可有可无。一般官网的地址带账号名和角色名称参数的话可以查看对应天赋树带的珠宝。


·中间 的那段是重点:


AAAABAMDAQQHBLMGSQceCPQN4hEtEZYWbxg8GFYabBzcIvQkqij6KlMqmCycMtE1kjbpOQs6WDrhPC1Bh0QERUdFnUZxR4VHt0iOSU9JUUtXTLNNuU3jU1JUrlXGVdVakV-wYENqQ2qsa9tsC20Zbj1vnnyDfdJ-WX_GgseDCYNfg8yD24TFhTKFYIYCiECPGpAzkyeVLpctmK2a4JuKm7WhL6IAplemrKh9qsSsmLB3snC0DLc-uJO8qrzqvSe-T76AvorAZsDjykrK08y80B_T-9i92QvZXt-K42rr7uyK7-vw1fGz8kX31_no-oD-Cv6B_o8=



这个就是天赋树根据一段的规则处理后的字符串。


2、解析


·天赋树地址数据是经过节点通过Base64编码后替换了所有 "-"字符为"+"字符,所有"_"字符为"/"字符后的字符串。


所以处理前需要还原这2种字符,把"+"替换成 "-",把"/"替换成"_",然后进行Base64解码得到一个字节数组。


·天赋树的字节数组前7个字节是有规律的:

字节1:天赋树版本位
字节2:天赋树版本位
字节3:天赋树版本位
字节4:天赋树版本位
字节5:当前角色类型ID:ClassID(可以从接口获得当前角色的ClassID,比如女巫是3)
字节6:当前角色的升华ID:ascendancyClass((0 - 没有升华, 然后 1- 3).可以从接口获得当前角色的ascendancyClass,比如死灵师是3)
字节7:保留位,目前国服是1


前4个字节是当前天赋树的版本号,比如现在的天赋树版本是4,所有前4个字节是:0,0,0,4
从字节8开始,后面每2位代表着天赋树中某点天赋的ID(前一位=天赋树某点ID除以256的商  后一位=天赋树某点ID除以256的余数)。
%5JOS5S85JD5V2OE3`9%~5H.png


例如:
字节8是:4
字节9是:7

那么该点天赋树的ID= 4*256 +7=1031。


ID=1031的天赋点所在地方是:


U~Y7AHM6FQNM%U@`T2S}_RL.png


就是该天赋的这个点(注意,这些天赋树id是从小到大排列的,并不是从某个角色出门根据路线排列的):


W9@UZPO[]O]GOP@Q]]R4K.png





所以可以计算出下面天赋树地址的信息


AAAABAMDAQQHBLMGSQceCPQN4hEtEZYWbxg8GFYabBzcIvQkqij6KlMqmCycMtE1kjbpOQs6WDrhPC1Bh0QERUdFnUZxR4VHt0iOSU9JUUtXTLNNuU3jU1JUrlXGVdVakV-wYENqQ2qsa9tsC20Zbj1vnnyDfdJ-WX_GgseDCYNfg8yD24TFhTKFYIYCiECPGpAzkyeVLpctmK2a4JuKm7WhL6IAplemrKh9qsSsmLB3snC0DLc-uJO8qrzqvSe-T76AvorAZsDjykrK08y80B_T-9i92QvZXt-K42rr7uyK7-vw1fGz8kX31_no-oD-Cv6B_o8=




【版本位】》0
【版本位】》0
【版本位】》0
【版本位】》4
【角色id】》3
【升华】》3
【保留】》1



天赋树ID列表(注意,这些天赋树id是从小到大排列的,并不是从某个角色出门根据路线排列的):


1031,1203,1609,1822,2292,3554,4397,4502,5743,6204,6230,6764,7388,8948,9386,10490,10835,10904,11420,13009,13714,14057,14603,14936,15073,15405,16775,17412,17735,17821,18033,18309,18359,18574,18767,18769,19287,19635,19897,19939,21330,21678,21958,21973,23185,24496,24643,27203,27308,27611,27659,27929,28221,28574,31875,32210,32345,32710,33479,33545,33631,33740,33755,33989,34098,34144,34306,34880,36634,36915,37671,38190,38701,39085,39648,39818,39861,41263,41472,42583,42668,43133,43716,44184,45175,45680,46092,46910,47251,48298,48362,48423,48719,48768,48778,49254,49379,51786,51923,52412,53279,54267,55485,55563,55646,57226,58218,60398,60554,61419,61653,61875,62021,63447,63976,64128,65034,65153,65167




3、天赋树的生成


1、获取角色的天赋树点ID列表:由于目前还没有直接通过官方api地址获取天赋树链接的接口,所以只能先获取到该角色的天赋树点,然后自己根据上面的规律生成一个天赋树url地址。



天赋树信息接口地址:character-window/get-passive-skills?reqData=0&character=角色名称&accountName=账号名称

角色和物品信息接口地址:character-window/get-items?character=角色名称&accountName=账号名称


国服例子:

天赋树信息:https://poe.game.qq.com/characte ... F%E8%A5%BF%E6%B3%95

角色和物品:https://poe.game.qq.com/character-window/get-items?&character=%E4%BA%A1%E9%AD%82%E5%B8%88%E5%8D%A1%E5%A1%94%E8%8E%89%E5%A8%9C&accountName=%E5%85%89%E5%BD%B1%E8%B7%AF%E8%A5%BF%E6%B3%95

天赋树信息接口会返回如图的json字符串。

U3AYKM5EGQ3C_AE6AP}[(@U.png

hashes 一个数字数组,里面的数字代表着每一个天赋点的ID 如:1031
items 该角色天赋中的珠宝列表 如:{
            "verified":false,
            "w":1,
            "h":1,
            "ilvl":76,
            "icon":"
/image/Art/2DItems/Jewels/
BlueJewel4.png?
scale=1&scaleIndex=0&w=1&h=1
&v=54bd8e65c7b738
e3f678ac1afb635dd43"
,
            "league":"先驱者",
            "id":"1216d06caea04b8b35
3b92f88956cb255
3907e59eb271903
3bf06a4282de271e"
,
            "sockets":[

            ]
,
            "name":"<<set:MS>><<set:M>><<set:S>>坚守军团",
            "typeLine":"钴蓝珠宝",
            "identified":true,
            "corrupted":false,
            "lockedToCharacter":false,
            "properties":[
                {
                    "name":"仅限",
                    "values":[
                        [
                            "1",
                            0
                        ]
                    ],
                    "displayMode":0
                }
            ]
,
            "explicitMods":[
                "召唤生物的最大生命增加 11%",
                "召唤生物格挡时回复它 2% 最大生命"
            ]
,
            "descrText":"放置到一个天赋树
的珠宝插槽中以产生效果.
右键点击以移出插槽. "
,
            "flavourText":[
                "掷此铁械, 击彼铁壁",
                "深陷不拔, 徒厚其壁. "
            ]
,
            "frameType":3,
            "x":1,
            "y":0,
            "inventoryId":"PassiveJewels",
            "type":"JewelInt",
            "socketedItems":[

            ]

        },
jewel_slots 该角色天赋中珠宝对应插槽的位置 如:{
            "id":"jewel_slot1957",
            "passiveSkill":{
                "id":"jewel_slot1957",
                "hash":"36634",
                "name":"珠宝插槽"
            }
        },

角色和物品信息接口会返回如图的json字符串。


E@SVP5U12}6W%OUSCQGVBT5.png


items角色装备的物品和技能信息
character 当前角色信息 如:"character":{
        "name":"亡魂师卡塔莉娜",
        "league":"先驱者",
        "classId":3,
        "ascendancyClass":3,
        "class":"Necromancer",
        "level":89
    }



这次我们主要看天赋树中的 hashes字段,它是一个数值数组,代表了该角色的所有天赋树的ID。

"hashes":[1031,1203,1609,1822,2292,3554,4397,4502,5743,6204,6230,6764,7388,8948,9386,10490,10835,10904,11420,13009,13714,14057,14603,14936,15073,15405,16775,17412,17735,17821,18033,18309,18359,18574,18767,18769,19287,19635,19897,19939,21330,21678,21958,21973,23185,24496,24643,27203,27308,27611,27659,27929,28221,28574,31875,32210,32345,32710,33479,33545,33631,33740,33755,33989,34098,34144,34306,34880,36634,36915,37671,38190,38701,39085,39648,39818,39861,41263,41472,42583,42668,43133,43716,44184,45175,45680,46092,46910,47251,48298,48362,48423,48719,48768,48778,49254,49379,51786,51923,52412,53279,54267,55485,55563,55646,57226,58218,60398,60554,61419,61653,61875,62021,63447,63976,64128,65034,65153,65167]

2、计算出URL


从1中获取的天赋树ID,那么根据角色和物品信息接口得到当前角色的


·当前角色类型ID:ClassID=3
·当前角色的升华ID:ascendancyClass=3

另外当前天赋树的版本是4.
那么前7个字节为:
  1.   byte[] a = new byte[hashs.Count*2+7];
  2.             a[0] = 0;
  3.             a[1] = 0;
  4.             a[2] = 0;
  5.             a[3] = 4;
  6.             a[4] = intToByte(character.classId); //ClassId
  7.             a[5] = intToByte(int.Parse(character.ascendancyClass));//AscendClassId
  8.             a[6] = 1;
复制代码


然后根据天赋树信息接口返回的hashes数组,计算后面的字节(前一位=天赋树某点ID除以256的商  后一位=天赋树某点ID除以256的余数)。


  1. int start = 7;
  2.   for (int i = 0; i < hashs.Count; i++)
  3.                 {
  4.                     int tmp0 = hashs[i] / 256;
  5.                     int tmp1 = hashs[i] % 256;
  6.                     a[start++] = (intToByte(tmp0));
  7.                     a[start++] = (intToByte(tmp1));
  8.                 }
复制代码


接着把字节数组进行Base64的加密,然后替换所有"+"字符为 "-" 字符,替换所有"/"字符为 "_" 字符,拼装头部地址“https://poe.game.qq.com/fullscreen-passive-skill-tree/3.0.3/ ”,
即可得到天赋树的加密连接:


https://poe.game.qq.com/fullscreen-passive-skill-tree/3.0.3/AAAABAMDAQQHBLMGSQceCPQN4hEtEZYWbxg8GFYabBzcIvQkqij6KlMqmCycMtE1kjbpOQs6WDrhPC1Bh0QERUdFnUZxR4VHt0iOSU9JUUtXTLNNuU3jU1JUrlXGVdVakV-wYENqQ2qsa9tsC20Zbj1vnnyDfdJ-WX_GgseDCYNfg8yD24TFhTKFYIYCiECPGpAzkyeVLpctmK2a4JuKm7WhL6IAplemrKh9qsSsmLB3snC0DLc-uJO8qrzqvSe-T76AvorAZsDjykrK08y80B_T-9i92QvZXt-K42rr7uyK7-vw1fGz8kX31_no-oD-Cv6B_o8=














本帖最后由 lucifering000 于 2017-12-4 22:33 编辑



【POB】PathOfBuilding国服版
【Tool】国际服Build转国服pob
http://bbs.17173.com/thread-10923378-1-1.html


【Tool】国际服论坛&poe.ninja 装备技能汉化插件
http://bbs.17173.com/thread-10755360-1-1.html

【LabCompass】迷宫插件-国服
http://bbs.17173.com/thread-11248376-1-1.html

【Tool】POE-DDS贴图&SMD模型预览解压导出工具
http://bbs.17173.com/thread-10827920-1-1.html

POE工具开发相关知识点
http://bbs.17173.com/thread-10492236-1-1.html
回复

使用道具 举报

塑型者

121

主题

2166

帖子

6984

积分

版主

Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15

流亡指引者瓦尔之心智慧之书凰炎之印

 楼主| 发表于 2017-11-29 14:28:54 | 显示全部楼层
二、 天赋树信息与珠宝位置




从《一、天赋树地址的解析和生成》中获取的天赋树信息接口可以拿到某个角色的天赋点ID列表、珠宝列表和天赋中所有珠宝插槽位置



天赋中所有珠宝插槽位置的列表 jewel_slots是一个数组("jewel_slots":[插槽1,插槽2,插槽3...]),它 的每个子项目是这样的:

{
            "id":"jewel_slot1957",
            "passiveSkill":{
                "id":"jewel_slot1957",
                "hash":"36634",
                "name":"珠宝插槽"
            }
        }

其中的hash”代表着这个珠宝插槽的天赋点的ID




"items"里面是该角色的所有珠宝的信息("items":[珠宝1,珠宝2,珠宝3...]):
{
            "verified":false,
            "w":1,
            "h":1,
            "ilvl":76,
            "icon":"
/image/Art/2DItems/Jewels/
BlueJewel4.png?
scale=1&scaleIndex=0&w=1&h=1
&v=54bd8e65c7b738
e3f678ac1afb635dd43",
            "league":"先驱者",
            "id":"1216d06caea04b8b35
3b92f88956cb255
3907e59eb271903
3bf06a4282de271e",
            "sockets":[

            ],
            "name":"<<set:MS>><<set:M>><<set:S>>坚守军团",
            "typeLine":"钴蓝珠宝",
            "identified":true,
            "corrupted":false,
            "lockedToCharacter":false,
            "properties":[
                {
                    "name":"仅限",
                    "values":[
                        [
                            "1",
                            0
                        ]
                    ],
                    "displayMode":0
                }
            ],
            "explicitMods":[
                "召唤生物的最大生命增加 11%",
                "召唤生物格挡时回复它 2% 最大生命"
            ],
            "descrText":"放置到一个天赋树
的珠宝插槽中以产生效果.
右键点击以移出插槽. ",
            "flavourText":[
                "掷此铁械, 击彼铁壁",
                "深陷不拔, 徒厚其壁. "
            ],
            "frameType":3,
            "x":1,
            "y":0,
            "inventoryId":"PassiveJewels",
            "type":"JewelInt",
            "socketedItems":[

            ]
        }

我们需要把珠宝信息和天赋点中的插槽信息关联起来:


珠宝信息中的“x”字段表示 该珠宝在 珠宝插槽列表的第几个。


比如上面的坚守军团·钴蓝珠宝】的 "x":1,也就是珠宝插槽列表的第 x+1=2 个(数组下标为1)。


Y4LQ]P`LL}M@3A0GT2HK%]Q.png






如上图,第2个,"hash":"36634" 也就是说【坚守军团·钴蓝珠宝插在了ID为36634的天赋点上面(该点为珠宝插槽)

}O1LG}{9Y4GCS)GI~%{4ZQD.png _1OPEU2YWOSBW]0U7GDT{PS.png

如此,遍历每一个珠宝信息,然后根据它的“x”属性,对应jewel_slots所在位置的插槽的id即可关联到天赋树。






本帖最后由 lucifering000 于 2017-11-29 14:40 编辑



【POB】PathOfBuilding国服版
【Tool】国际服Build转国服pob
http://bbs.17173.com/thread-10923378-1-1.html


【Tool】国际服论坛&poe.ninja 装备技能汉化插件
http://bbs.17173.com/thread-10755360-1-1.html

【LabCompass】迷宫插件-国服
http://bbs.17173.com/thread-11248376-1-1.html

【Tool】POE-DDS贴图&SMD模型预览解压导出工具
http://bbs.17173.com/thread-10827920-1-1.html

POE工具开发相关知识点
http://bbs.17173.com/thread-10492236-1-1.html
回复

使用道具 举报

0

主题

21

帖子

53

积分

Lv.2

Rank: 2Rank: 2

发表于 2017-12-11 21:31:30 | 显示全部楼层
支持!
回复

使用道具 举报

塑型者

121

主题

2166

帖子

6984

积分

版主

Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15

流亡指引者瓦尔之心智慧之书凰炎之印

 楼主| 发表于 2017-12-28 17:11:27 | 显示全部楼层
三、REPOE 导出Dat生成json文件。


repoe是基于pypoe项目的物品词缀导出工具,可以将ggpk文件中的dat文件解析并生成对应的json文件。


Github地址:
REPOE:https://github.com/brather1ng/RePoE
PYPOE:https://github.com/OmegaK2/PyPoE


天赋树模拟器上用到的一种处理物品词缀的方式,通过调用repoe导出的json文件:

mods.json:映射了物品和词缀ID
stat_translations.json: 提供词缀ID和对应词缀的显示文本(翻译)。
npc_master.json :大师词缀映射(词缀范围)
crafting_bench_options.json:大师词缀ID和可上词缀物品的映射

1、安装RePOE和环境配置。


(1),


下载pypoe压缩包:https://github.com/OmegaK2/PyPoE/archive/dev.zip
下载repoe压缩包:https://github.com/brather1ng/RePoE/archive/master.zip


解压到同一个目录下面,类似这样:


TUTIK2FZDA_SRI_IAE[E{20.png


(2):下载并安装 python 3.4https://www.python.org/ftp/python/3.4.4/python-3.4.4.amd64.msi),安装过程如果没有选到加入系统环境变量,那么需要安装后加入到系统环境变量上。
(百度一下:“python 加入环境变量”)。


N0Z%6]K[S1NV{WG2NQTSEFR.png
(记得选择加入环境变量)


打开CMD,输入:python -V
即可查看python版本,如下就是安装和配置环境变量成功。
TCW1D{N}S3KQY5ALP4A8_G3.png




(3)cmd上 CD到你解压的目录下,运行
  1. pip3 install -e .
复制代码
安装简化版的pypoe。


~TMIPA3]Q@C@2E$)O$$BA87.png




(4)。安装Repoe所需要的第三方包,执行下面命令:


  1. pip install --upgrade pip colorama
  2. pip install --upgrade pip graphviz
  3. pip install --upgrade pip configobj
  4. pip install --upgrade pip colorama
复制代码


然后直接运行


  1. python RePoE.py -h
复制代码


即可查看 Repoe的使用方式:


usage: RePoE.py [-h] [-f FILE] module [module ...]

Convert GGPK files to Json using PyPoE

positional arguments:
  module                the converter modules to run (choose from
                        'npc_master', 'gem_tags', 'gems', 'stat_translations',
                        'crafting_bench_options', 'mods', 'stats')

optional arguments:
  -h, --help            show this help message and exit
  -f FILE, --file FILE  path to your Content.ggpk file



也就是可以运行:


  1. RePoE.py -f 你的ggpk的文件路径 模块名称
复制代码
例子:python RePoE.py -f D:\POE\Content.ggpk npc_master


E(Y6%UHLTNT__5[IHRW}KKQ.png


来生成对应的 npc_master.json文件


模块名称可以替换为 'npc_master', 'gem_tags', 'gems', 'stat_translations',
'crafting_bench_options', 'mods', 'stats' 之类的来生成对应的json文件)






2、代码修改本地化


(1)、GGPK的Data文件有多个语言的支持,比如国服的 Data\Simplified Chinese\ 下面的就是国服本地化的Data文件,如果你想要从这里提取Data文件来生成json文件,那么可以修改:
RePoE\__init__.py 里面的代码:


  1. def main(data_path='../data/'):
复制代码

  1. def main(data_path='../data/Simplified Chinese/'):
复制代码




N3L[S~FFGFS{R0R8{OVCY.png





(2)、修改repoe项目的代码让stat_translations.json (词缀显示文本)来显示不同国家的语言。


用文本编辑器打开 Repoe项目中的 RePoE\stat_translations.py 文件,在_convert函数中有如下代码:
  1. def _convert(tr, tag_set):
  2.     ids = tr.ids
  3.     n_ids = len(ids)
  4.     english = []
  5.     for s in tr.get_language('English').strings:
  6.         tags = _convert_tags(n_ids, s.tags, s.tags_types)
  7.         tag_set.update(tags)
  8.         english.append({
  9.             'condition': _convert_range(s.range),
  10.             'string': s.as_format_string,
  11.             'format': tags,
  12.             'index_handlers': _convert_handlers(n_ids, s.quantifier.index_handlers)
  13.         })
  14.     return {
  15.         'ids': ids,
  16.         'English': english
  17.     }
复制代码
其中的 for s in tr.get_language('English').strings: 中的“English”就是从 GGPK文件的 Metadata/tatDescriptions/stat_descriptions.txt里面读取“English”语言的词缀。


Metadata/tatDescriptions/stat_descriptions.txt中某个词缀如下:)
  1. description
  2.         1 item_generation_cannot_change_prefixes
  3.         1
  4.                 # "Prefixes Cannot Be Changed"
  5.         lang "Portuguese"
  6.         1
  7.                 # "Prefixos Não Podem Ser Modificados"
  8.         lang "Traditional Chinese"
  9.         1
  10.                 # "前綴無法被變更"
  11.         lang "Simplified Chinese"
  12.         1
  13.                 # "前缀无法被改变"
  14.         lang "Thai"
  15.         1
  16.                 # "ไม่สามารถเปลี่ยน Prefix ได้"
  17.         lang "Russian"
  18.         1
  19.                 # "Префиксы нельзя изменить"
  20.         lang "French"
  21.         1
  22.                 # "Les Préfixes ne peuvent pas être changés"
  23.         lang "German"
  24.         1
  25.                 # "Präfixe können nicht verändert werden"
  26.         lang "Spanish"
  27.         1
  28.                 # "Los Prefijos no Pueden Ser Modificados"

复制代码
如果我们需要提取简体中文版的词缀,那么就是"Simplified Chinese"。
也就是把 RePoE\stat_translations.py 文件的_convert函数修改为(下面的return 那里的‘English’可以不改也可以修改,只是生成的json文件的某个key):

  1. def _convert(tr, tag_set):
  2. ids = tr.ids
  3. n_ids = len(ids)
  4. english = []
  5. for s in tr.get_language('<font color="#ff0000">Simplified Chinese'</font>).strings:
  6. tags = _convert_tags(n_ids, s.tags, s.tags_types)
  7. tag_set.update(tags)
  8. english.append({
  9. 'condition': _convert_range(s.range),
  10. 'string': s.as_format_string,
  11. 'format': tags,
  12. 'index_handlers': _convert_handlers(n_ids, s.quantifier.index_handlers)
  13. })
  14. return {
  15. 'ids': ids,
  16. 'English': english
  17. }
复制代码


然后正常运行导出json文件即可获得中文版本的词缀翻译文件。



3、版本处理


GGG的Dat文件没有提供固定的格式,但是可以经过尝试来确定某个dat文件的结构。(文件长度,每个字段的类型等)
所以一般都是尝试测试之后定义好给程序去解析调用。
并且大版本的更新Dat文件的格式一般都会变动,这个时候如果pypoe的作者们没有更新项目代码,那么可能需要自己去测试然后修改pypoe的文件(找到报错的dat文件名,然后秀海stable.py里面的对应定义,增加、修改或减少字段 然后尝试解析直到该dat文件解析正常)。


\PyPoE\poe\file\specification\data\stable.py 定义了dat文件内容结构



例如BaseItemTypes.dat的定义如下:
  1. 'BaseItemTypes.dat': File(
  2.         fields=OrderedDict((
  3.             ('Id', Field(
  4.                 type='ref|string',
  5.                 unique=True,
  6.                 file_path=True,
  7.             )),
  8.             ('ItemClassesKey', Field(
  9.                 type='ulong',
  10.                 key='ItemClasses.dat',
  11.             )),
  12.             ('Width', Field(
  13.                 type='int',
  14.             )),
  15.             ('Height', Field(
  16.                 type='int',
  17.             )),
  18.             ('Name', Field(
  19.                 type='ref|string',
  20.             )),
  21.             ('InheritsFrom', Field(
  22.                 type='ref|string',
  23.                 file_path=True,
  24.             )),
  25.             ('DropLevel', Field(
  26.                 type='int',
  27.             )),
  28.             ('FlavourTextKey', Field(
  29.                 type='ulong',
  30.                 key='FlavourText.dat',
  31.             )),
  32.             ('Implicit_ModsKeys', Field(
  33.                 type='ref|list|ulong',
  34.                 key='Mods.dat',
  35.             )),
  36.             ('Unknown1', Field(
  37.                 type='int',
  38.             )),
  39.             ('SoundEffectsKey', Field(
  40.                 type='ulong',
  41.                 key='SoundEffects.dat',
  42.             )),
  43.             ('NormalPurchase_BaseItemTypesKeys', Field(
  44.                 type='ref|list|uint',
  45.                 key='BaseItemTypes.dat',
  46.             )),
  47.             ('NormalPurchase_Costs', Field(
  48.                 type='ref|list|int',
  49.             )),
  50.             ('MagicPurchase_BaseItemTypesKeys', Field(
  51.                 type='ref|list|uint',
  52.                 key='BaseItemTypes.dat',
  53.             )),
  54.             ('MagicPurchase_Costs', Field(
  55.                 type='ref|list|int',
  56.             )),
  57.             ('TagsKeys', Field(
  58.                 type='ref|list|ulong',
  59.                 key='Tags.dat',
  60.             )),
  61.             # Relating displaystyle it seems
  62.             ('Unknown2', Field(
  63.                 type='int',
  64.             )),
  65.             ('Flag0', Field(
  66.                 type='bool',
  67.             )),
  68.             ('ItemVisualIdentityKey', Field(
  69.                 type='ulong',
  70.                 key='ItemVisualIdentity.dat',
  71.             )),
  72.             ('UnknownUnique', Field(
  73.                 type='uint',
  74.                 unique=True,
  75.             )),
  76.             #display_type = 0x{0:X}
  77.             ('VendorRecipe_AchievementItemsKeys', Field(
  78.                 type='ref|list|ulong',
  79.                 key='AchievementItems.dat',
  80.                 description='Achievement check when selling this item to vendors',
  81.             )),
  82.             ('RarePurchase_BaseItemTypesKeys', Field(
  83.                 type='ref|list|uint',
  84.                 key='BaseItemTypes.dat',
  85.             )),
  86.             ('RarePurchase_Costs', Field(
  87.                 type='ref|list|int',
  88.             )),
  89.             ('UniquePurchase_BaseItemTypesKeys', Field(
  90.                 type='ref|list|uint',
  91.                 key='BaseItemTypes.dat',
  92.             )),
  93.             ('UniquePurchase_Costs', Field(
  94.                 type='ref|list|int',
  95.             )),
  96.             ('Unknown3', Field(
  97.                 type='ref|string',
  98.             )),
  99.             ('Equip_AchievementItemsKey', Field(
  100.                 type='ulong',
  101.                 key='AchievementItems.dat',
  102.                 description='Achievement check when equipping this item',
  103.             )),
  104.             ('IsPickedUpByMonsters', Field(
  105.                 type='bool',
  106.             )),
  107.             ('IdentifyRare_AchievementItemsKeys', Field(
  108.                 type='ref|list|ulong',
  109.                 key='AchievementItems.dat',
  110.             )),
  111.             ('ItemThemesKey', Field(
  112.                 type='ulong',
  113.                 key='ItemThemes.dat',
  114.             )),
  115.             ('IdentifyMagic_AchievementItemsKeys', Field(
  116.                 type='ref|list|ulong',
  117.                 key='AchievementItems.dat',
  118.             )),
  119.         )),
复制代码
















本帖最后由 lucifering000 于 2017-12-28 17:15 编辑



【POB】PathOfBuilding国服版
【Tool】国际服Build转国服pob
http://bbs.17173.com/thread-10923378-1-1.html


【Tool】国际服论坛&poe.ninja 装备技能汉化插件
http://bbs.17173.com/thread-10755360-1-1.html

【LabCompass】迷宫插件-国服
http://bbs.17173.com/thread-11248376-1-1.html

【Tool】POE-DDS贴图&SMD模型预览解压导出工具
http://bbs.17173.com/thread-10827920-1-1.html

POE工具开发相关知识点
http://bbs.17173.com/thread-10492236-1-1.html
回复

使用道具 举报

0

主题

72

帖子

282

积分

Lv.2

Rank: 2Rank: 2

圣物之盾

发表于 2018-1-12 09:45:54 | 显示全部楼层
谢谢分享
回复

使用道具 举报

0

主题

42

帖子

82

积分

Lv.2

Rank: 2Rank: 2

发表于 2018-2-3 23:27:19 | 显示全部楼层
把抗去了试一试
回复

使用道具 举报

塑型者

121

主题

2166

帖子

6984

积分

版主

Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15

流亡指引者瓦尔之心智慧之书凰炎之印

 楼主| 发表于 2018-3-3 18:01:40 | 显示全部楼层
四、GGPK里面的DDS贴图文件。


GGG的DDS贴图文件有很多种类,有普通的DDS也有经过 Brotli算法压缩过的,甚至还有重定向的DDS文件(内容是TXT文本,指向GGPK的某张dds贴图)。
所以对于一张DDS,首先要做的就是判断文件头。

普通DDS文件头4个字节:
字节1:68 对应字符:“D”
字节2:68 对应字符:“D”
字节3:83 对应字符:“S”
字节4:32 对应字符:空格

如果一个poe的DDS文件开头是这4个字节,那么就不用经过Brotli算法解压。

对于Brotli算法压缩的文件,文件头的前4个字节会有很多种可能,4个字节之后的是Brotli压缩数据,所以一般以字节的新式读取整张DDS文件,然后去掉前4个字节,剩下的进行Brotli解压缩。

使用Brotli.Net 解压缩:
  1.   public Byte[] Decode(Byte[] input)
  2.         {
  3.             Byte[] output = null;
  4.             using (System.IO.MemoryStream msInput = new System.IO.MemoryStream(input))
  5.             using (BrotliStream bs = new BrotliStream(msInput, System.IO.Compression.CompressionMode.Decompress))
  6.             using (System.IO.MemoryStream msOutput = new System.IO.MemoryStream())
  7.             {
  8.                 bs.CopyTo(msOutput);
  9.                 msOutput.Seek(0, System.IO.SeekOrigin.Begin);
  10.                 output = msOutput.ToArray();
  11.                 return output;
  12.             }

  13.         }
复制代码



另外对于DXT1、DXT3模式的DDS文件可以通过PS、paint.net之类的工具直接预览和修改 ,但是我在打开 DXT4图片的时候看到的是黑色背景(这个是由于这些工具不支持DXT4)。
(DXT纹理压缩格式介绍:http://blog.csdn.net/puppet_master/article/details/50186613

C# 关于DXT4 图片解析处理(项目可以生成Dll文件,需要时引用即可):

DDSReader.zip (14.22 KB, 下载次数: 303)


【POB】PathOfBuilding国服版
【Tool】国际服Build转国服pob
http://bbs.17173.com/thread-10923378-1-1.html


【Tool】国际服论坛&poe.ninja 装备技能汉化插件
http://bbs.17173.com/thread-10755360-1-1.html

【LabCompass】迷宫插件-国服
http://bbs.17173.com/thread-11248376-1-1.html

【Tool】POE-DDS贴图&SMD模型预览解压导出工具
http://bbs.17173.com/thread-10827920-1-1.html

POE工具开发相关知识点
http://bbs.17173.com/thread-10492236-1-1.html
回复

使用道具 举报

塑型者

121

主题

2166

帖子

6984

积分

版主

Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15

流亡指引者瓦尔之心智慧之书凰炎之印

 楼主| 发表于 2018-3-22 19:31:33 | 显示全部楼层
五、GGPK里面的SMD模型文件。

SMD模型文件是一种经过算法和压缩的obj模型文件。


SMD的加密构成:前7个字节是文件头(具体是代表什么不清楚,我使用程序暴力穷举的方法发现smd文件只要移除前7个字节之后就能够进行Brotli解压缩),后面是字节数据是通过Brotli算法压缩过的



进行Brotli解压缩后的字节数据,是GGG自定义的一种SMD格式。

感谢Tzeentchful提供的开源代码,我们可以从中了解到GGG自定义的SMD格式是怎么样的。


Tzeentchful提供的SMD转obj项目的源码(Go语言):https://github.com/Tzeentchful/transmute




临时学习了GO语言,参考该项目用C#重写后可以得到,SMD其构成为:


40字节的文件头+多个网格(Mesh)头+多个网格名称+多个面(Face)数据+多个贴图坐标点、顶点法线结构体


注:
*3d图形处理中,一个模型(model)通常由一个或者多个Mesh(网格)组成,一个Mesh是可绘制的独立实体。




1、40字节的文件头构成:


  1. struct Header
  2.         {

  3.             public byte Version;
  4.             public UInt32 NumIdx;
  5.             public UInt32 NumVert;
  6.             public byte Unk1 ;
  7.             public byte NumMeshs;
  8.             public byte Unk2  ;
  9.             public UInt32 TotalStringLen ;
  10.             public float[] BoundingBox  ;//6

  11.         }
复制代码


分别为:
第0字节:版本号
第1~4字节:NumIdx 面数量,每个面数据3个值,所以乘以3之后就是面数据的字节总量。第5~8字节:NumVert 顶点数量。
第9字节:Unk1  保留。
第10字节:NumMeshs 网格头的数量
第11字节:Unk2 保留。
第12~15字节:TotalStringLen  所有网格名称占用的长度。
第16~39字节:6个float类似的数值,表示模型的最小边界框/包围盒(boundingbox)(https://blog.csdn.net/wishchin/article/details/11713919

如 Master_44721a45.smd 的文件头:


=======================【头部】============================
Version=1
NumIdx=4091
NumVert=3228
Unk1=4
NumMeshs=12
Unk2=0
TotalStringLen=474
BoundingBox[0]=-67.19155
BoundingBox[4]=67.19135
BoundingBox[8]=-16.39053
BoundingBox[12]=20.32394
BoundingBox[16]=-159.9244
BoundingBox[20]=0.004701194



2、多个网格(Mesh

每一个网格头的构成为: 4个字节的网格名称长度+4个字节的网格偏移量

  1.   struct MeshDefinition
  2.         {

  3.             public UInt32 NameLen;

  4.             public UInt32 FaceOffset ;
  5.         }
复制代码

可以根据40字节文件头中的NumMeshs(网格头的数量)的值,进行循环读取(每次循环读取8字节)。

如 Master_44721a45.smd 的网格(Mesh)头:


=======================【MeshDefinition】数量12============================
MeshDefinition[0].NameLen=20
MeshDefinition[0].FaceOffset=0
MeshDefinition[1].NameLen=18
MeshDefinition[1].FaceOffset=274
MeshDefinition[2].NameLen=40
MeshDefinition[2].FaceOffset=1026
MeshDefinition[3].NameLen=40
MeshDefinition[3].FaceOffset=1165
MeshDefinition[4].NameLen=48
MeshDefinition[4].FaceOffset=1331
MeshDefinition[5].NameLen=40
MeshDefinition[5].FaceOffset=1603
MeshDefinition[6].NameLen=42
MeshDefinition[6].FaceOffset=2643
MeshDefinition[7].NameLen=40
MeshDefinition[7].FaceOffset=3063
MeshDefinition[8].NameLen=52
MeshDefinition[8].FaceOffset=3527
MeshDefinition[9].NameLen=40
MeshDefinition[9].FaceOffset=3833
MeshDefinition[10].NameLen=42
MeshDefinition[10].FaceOffset=3904
MeshDefinition[11].NameLen=52
MeshDefinition[11].FaceOffset=3951





3、多个网格名称

40字节文件头中的NumMeshs代表网格头的数量,也代表着网格名称的数量。读取完网格头后循环读取NumMeshs次,即可获得所有网格名称。每个网格名称的长度存储在对应网格头的NameLen里面。


所以循环 NumMeshs次,每次读取长度为:对应网格头里NameLen的值相同。


如 Master_44721a45.smd 的网格名称:
=======================【Names】数量12============================
Names[0]=addonShape
Names[1]=baseShape
Names[2]=adventurer_armsShape
Names[3]=adventurer_feetShape
Names[4]=adventurer_forearmsShape
Names[5]=adventurer_hairShape
Names[6]=adventurer_handsShape
Names[7]=adventurer_headShape
Names[8]=adventurer_lower_legsShape
Names[9]=adventurer_neckShape
Names[10]=adventurer_skirtShape
Names[11]=adventurer_upper_legsShape

4、多个面(Face)数据

每个面数据的值是一个UInt16,占用2个字节。

40字节文件头中的NumIdx代表面数量,每个面数据3个值,所以乘以3之后就是面数据的字节总量。所以接着循环读取 Header.NumIdx*3*2 个字节。

如 Master_44721a45.smd 的面(Face)数据:

=======================【IndexBuffer】数量12273============================
第一个:
IndexBuffer[0]=82
IndexBuffer[1]=102
IndexBuffer[2]=46
故该面数据为:f 83/83/83 103/103/103 47/47/47

5、多个贴图坐标点、顶点法线结构体


40字节文件头中的NumVert代表着顶点数量。每个顶点结构体位32字节。


  1. struct SMDVertex
  2.         {

  3.             public float X ;

  4.             public float Y ;

  5.             public float Z ;

  6.             public Int16[] Unk1;//4个

  7.             public int U;//2个Float16                        

  8.             public int V; //2个Float16

  9.             public byte[] BoneIndex;// 4个

  10.             public byte[] BoneWeight;// 4个
  11. }
复制代码


如 Master_44721a45.smd 的顶点数据:


=======================【SMDVertex】数量3228============================
第一个:
X=14.738
Y=13.926
Z=-112.065
  sMDVertex.Unk1[0]=649
  sMDVertex.Unk1[1]=-32630
  sMDVertex.Unk1[2]=29209
  sMDVertex.Unk1[3]=-202
  sMDVertex.U=0.2264404
  sMDVertex.V=0.0001070499
  sMDVertex.BoneIndex=System.Byte[]
  sMDVertex.BoneWeight=System.Byte[]

这些数据的X、Y、Z构成了 obj文件的:“ v 几何体顶点(Geometric vertices)”


  1. streamwriter.Write(string.Format("v {0:0.000000} {1:0.000000} {2:0.000000}\n", vert.X, vert.Y, vert.Z));
复制代码



这些数据的U、V构成了obj文件的  “vt 贴图坐标点(Texture vertices)”


  1. streamwriter.Write(string.Format("vt {0:0.0000} {1:0.0000}  1.0000\n", toFloat2(vert.U), toFloat2( vert.V)));
复制代码


以上,就可以解析GGG的SMD格式 然后根据需要生成Obj文件,用其他工具打开预览。不过目前还有很多问题顶点法线,贴图,材质,骨骼等都没有(对obj不熟悉)。

本帖最后由 lucifering000 于 2018-3-22 20:24 编辑



【POB】PathOfBuilding国服版
【Tool】国际服Build转国服pob
http://bbs.17173.com/thread-10923378-1-1.html


【Tool】国际服论坛&poe.ninja 装备技能汉化插件
http://bbs.17173.com/thread-10755360-1-1.html

【LabCompass】迷宫插件-国服
http://bbs.17173.com/thread-11248376-1-1.html

【Tool】POE-DDS贴图&SMD模型预览解压导出工具
http://bbs.17173.com/thread-10827920-1-1.html

POE工具开发相关知识点
http://bbs.17173.com/thread-10492236-1-1.html
回复

使用道具 举报

32

主题

522

帖子

2135

积分

Lv.5

Rank: 5Rank: 5

发表于 2018-5-3 17:00:44 | 显示全部楼层
感谢,正在给你的PoeCn2En3.2.0.3  做繁体中文Patch,需要名字对应关系
回复

使用道具 举报

莫维尔

1

主题

31

帖子

138

积分

Lv.2

Rank: 2Rank: 2

发表于 2018-12-9 05:37:40 | 显示全部楼层
嘿 楼主 你以为这么详细我就看得懂了?太天真了
回复

使用道具 举报

0

主题

41

帖子

127

积分

Lv.2

Rank: 2Rank: 2

发表于 2019-5-20 12:44:49 | 显示全部楼层

楼主辛苦了
回复

使用道具 举报

莫维尔

0

主题

25

帖子

127

积分

Lv.2

Rank: 2Rank: 2

发表于 2019-6-13 21:59:06 | 显示全部楼层
楼主太厉害了,膜拜
回复

使用道具 举报

0

主题

26

帖子

101

积分

Lv.2

Rank: 2Rank: 2

发表于 2019-8-30 22:50:45 | 显示全部楼层
辛苦了……  感谢分享!!!
回复

使用道具 举报

0

主题

43

帖子

200

积分

Lv.2

Rank: 2Rank: 2

发表于 2020-3-7 11:19:39 | 显示全部楼层
lucifering000 发表于 2017-11-29 14:28
二、 天赋树信息与珠宝位置

厉害
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

论坛合作、疑问请点击给我发信息 点击链接加入群聊【17173有料社区】