Fuyumi/炽焰天穹种子求解器说明

Created Wed, 16 Oct 2024 22:40:41 +0800 Modified Wed, 13 Nov 2024 01:20:35 +0000
3840 Words

种子求解器

这是什么?

这是一个暴力猜解词条种子的脚本工具。

这有什么用?

如果你错过了开服的种子公开展示的时机,也可以通过这个工具尝试重新找回种子。

该如何使用?

  • 安装Python3,推荐3.12,是开发时使用的环境。

  • 安装pysat库。

    pip install python-sat
    

    如果在国内出现超时,又不会用VPN的话,可以试试加-i使用镜像源,例如:

    pip install python-sat -i https://pypi.tuna.tsinghua.edu.cn/simple
    

    其它镜像源: 中国科学技术大学 : https://pypi.mirrors.ustc.edu.cn/simple/ 豆瓣:http://pypi.douban.com/simple/ 阿里云:http://mirrors.aliyun.com/pypi/simple/

  • 复制本文下方的python脚本,保存到 HBRGuess.py文件。

  • 复制本文下方的 lottery_data.json,保存到 HBRGuess.py文件同目录,记得使用GBK编码保存。

  • 在 HBRGuess.py文件同目录创建一个名为 config.json的文件,复制下面内容到 config.json中:

    {
    "start_index": 1,
    "search_depth": 20,
    "search_length": 1000,
    "requires": [
            
    ]
    }
  • 阅读上一篇词条计算器说明,可以知道计算词条需要两个必要的值,index和seed。index可以通过已经制作的装备来估算,而seed就是本工具求解的值。index可以通过项链+2,手环+4,耳环+3,粗略估算一下当前index的范围,越精细后续需要计算的越少。

  • 如果估算当前index大概在300-400之间,那么将 config.json中的 start_index改为300,search_length改为100.其它范围以此类推。

  • 连续打造一组装备/连续开孔/连续铣孔,获得一组连续的词条,注意,一定要保持连续!将连续的词条按照顺序填入 requires中。

  • 词条的名称不是按照游戏中的名称来,需要填入 lottery_data.json中 Description的值,比如”灵巧 +2”、”攻击属性变化”。

  • 填写完后的示例,记得使用GBK编码保存:

    {
    "start_index": 450,
    "search_depth": 20,
    "search_length": 100,
    "requires": [
        "幸运 +2",
        "灵巧 +2",
        "DP +30",
        "灵巧 +2",
        "力量 +1",
        "HP +30",
        "灵巧 +2",
        "HP +20",
        "体力 +2",
        "灵巧 +3",
        "灵巧 +1",
        "HP +10",
        "DP +30",
        "幸运 +1",
        "力量 +1",
        "幸运 +1"
    ]
    }
  • 打开控制台,在py脚本目录执行,即可开始计算。

    python HBRGuess.py
    
  • 如果因为意外计算中断,可以使用以下指令继续上次的计算:

    python HBRGuess.py use_cache
    
  • 计算结果除了实时打印,还可以在 HBRGuess.py文件同目录下的 cache.json文件找到,其中键值为index,值为seed。

注意事项

关于脚本

本脚本完全开源,欢迎大家进行改造优化,毕竟python嘛,性能差是预期中的。

填多少词条比较好?

体感装备打造10个以上,打孔/洗词条15个以上,可以比较准确地算出seed。

为什么有的时候可以算出多个seed?

这里的seed只是可能符合你的数据,你可以逐个试试,不能保证结果一定正确。

config.json里的search_depth是什么?

这个是求解工具中的一个估算程度设置,1-32,数值越高计算越详细,但耗时也会增加,可以自己改改找找最快的配置。

洗词条为什么有时候算不出来?

HBR洗词条有一个隐藏逻辑,随机生成词条的时候,如果新词条和当前词条一样,会跳过继续生成下一条。

如果运气比较差,出现了这种情况,估计就只能重新生成一些词条再计算了,毕竟是否发生这个情况是无法感知的。

脚本和数据

HBRGuess.py 文件

import math
import datetime
import json
import sys
from pysat.formula import *
from pysat.solvers import Solver


# 常量推演
class BaseTransform:
    def __init__(self):
        self.box = [
            0b00000111010110111100110100010101,
            0b00010101100110100101010111100101,
            0b00011111000100100011101110110101,
            0b00000000000000000000000000000000,
        ]

    def shift(self):
        tmp = (self.box[0] ^ (self.box[0] << 11)) & 0xFFFFFFFF
        self.box[0] = self.box[1]
        self.box[1] = self.box[2]
        self.box[2] = self.box[3]
        self.box[3] = tmp ^ (tmp >> 8) ^ self.box[3] ^ (self.box[3] >> 19) & 0xFFFFFFFF

    def get_base(self):
        return self.box[3]

    def deepcopy(self):
        new_self = BaseTransform()
        new_self.box[0] = self.box[0]
        new_self.box[1] = self.box[1]
        new_self.box[2] = self.box[2]
        new_self.box[3] = self.box[3]
        return new_self


# seed推演
class NormalFormTransform:
    def __init__(self):
        self.bit = [
            [
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
            ],
            [
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
            ],
            [
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
                0,
            ],
            [
                1 << 0,
                1 << 1,
                1 << 2,
                1 << 3,
                1 << 4,
                1 << 5,
                1 << 6,
                1 << 7,
                1 << 8,
                1 << 9,
                1 << 10,
                1 << 11,
                1 << 12,
                1 << 13,
                1 << 14,
                1 << 15,
                1 << 16,
                1 << 17,
                1 << 18,
                1 << 19,
                1 << 20,
                1 << 21,
                1 << 22,
                1 << 23,
                1 << 24,
                1 << 25,
                1 << 26,
                1 << 27,
                1 << 28,
                1 << 29,
                1 << 30,
                1 << 31,
            ],
        ]

    def shift(self):
        # tmp = (self.box[0] ^ (self.box[0] << 11)) & 0xFFFFFFFF
        tmp = [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
        ]
        for i in range(0, 11):
            tmp[i] = self.bit[0][i]
        for i in range(11, 32):
            tmp[i] = self.bit[0][i] ^ self.bit[0][i - 11]

        # self.box[0] = self.box[1]
        for i in range(0, 32):
            self.bit[0][i] = self.bit[1][i]

        # self.box[1] = self.box[2]
        for i in range(0, 32):
            self.bit[1][i] = self.bit[2][i]

        # self.box[2] = self.box[3]
        for i in range(0, 32):
            self.bit[2][i] = self.bit[3][i]

        # self.box[3] = tmp ^ (tmp >> 8) ^ self.box[3] ^ (self.box[3] >> 19) & 0xFFFFFFFF
        tmp2 = [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
        ]
        for i in range(24, 32):
            tmp2[i] = tmp[i]
        for i in range(0, 24):
            tmp2[i] = tmp[i] ^ tmp[i + 8]
        tmp3 = [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
        ]
        for i in range(0, 13):
            tmp3[i] = tmp2[i] ^ self.bit[3][i] ^ self.bit[3][i + 19]
        for i in range(13, 32):
            tmp3[i] = tmp2[i] ^ self.bit[3][i]

        # return self.box[3]
        for i in range(0, 32):
            self.bit[3][i] = tmp3[i]

    def transform_seed(self, seed):
        result = 0
        for i in range(0, 32):
            mask = seed & self.bit[3][i]
            mask = mask ^ (mask >> 1)
            mask = mask ^ (mask >> 2)
            mask = mask ^ (mask >> 4)
            mask = mask ^ (mask >> 8)
            mask = mask ^ (mask >> 16)
            if (mask & 1) != 0:
                result += 1 << i
        return result

    def get_form(self):
        return self.bit[3]

    def deepcopy(self):
        new_self = NormalFormTransform()
        for i in range(0, 32):
            new_self.bit[0][i] = self.bit[0][i]
            new_self.bit[1][i] = self.bit[1][i]
            new_self.bit[2][i] = self.bit[2][i]
            new_self.bit[3][i] = self.bit[3][i]
        return new_self


# 范式构造
class CNFFactory:
    def __init__(self, start_index, ranges):
        self.base = BaseTransform()
        self.form = NormalFormTransform()
        self.index = 0
        self.requires = []
        for i in range(0, start_index):
            self.shift()
        self.index = start_index
        for real_range in ranges:
            interval = math.floor(0xFFFFFFFE / (real_range[1] - real_range[0])) + 1
            real_min = (real_range[2] - real_range[0]) * interval + 1
            real_max = (real_range[3] - real_range[0]) * interval + 1
            self.requires.append([real_min, min(real_max, 0xFFFFFFFF)])

    def shift(self):
        self.base.shift()
        self.form.shift()

    def create_cnf(self, search_depth=32):
        seed = []
        search_depth = max(1, search_depth)
        search_depth = min(32, search_depth)
        for i in range(0, 32):
            v_name = "seed$" + str(i)
            v_a = Atom(v_name)
            v_a._clausify()
            seed.append(v_a)
        tmp_base = self.base.deepcopy()
        tmp_form = self.form.deepcopy()
        const_false = Atom("const_false")
        const_true = Atom("const_true")
        formulas = []
        formulas.append(Neg(const_false))
        formulas.append(const_true)
        for require in self.requires:
            # 向后推演
            tmp_base.shift()
            tmp_form.shift()

            # 无用条件,跳过
            if require[0] == 1 and require[1] == 0xFFFFFFFF:
                continue

            # 构建seed变换范式
            trans_seed = []
            for i in range(0, 32):
                tmp_bit = []
                for bit_i in range(0, 32):
                    bit_flag = (tmp_form.get_form()[i] >> bit_i) & 1 == 1
                    if bit_flag:
                        tmp_bit.append(seed[bit_i])
                bit_formulas = []
                for bit_i in range(0, len(tmp_bit)):
                    bit_formulas.append(tmp_bit[bit_i])
                trans_seed.append(XOr(*bit_formulas, const_false, const_false))

            # 构建位头部相等范式
            bit_term_index = 31
            for i in range(32, 0, -1):
                tmp_bit_term_index = i - 1
                if ((require[0] >> tmp_bit_term_index) & 1) != (
                    (require[1] >> tmp_bit_term_index) & 1
                ):
                    bit_term_index = tmp_bit_term_index
                    break
                rand_bit = (tmp_base.get_base() >> tmp_bit_term_index) & 1
                range_min_bit = (require[0] >> tmp_bit_term_index) & 1
                formulas.append(
                    Equals(
                        const_true if rand_bit ^ range_min_bit == 1 else const_false,
                        trans_seed[tmp_bit_term_index],
                    )
                )

            # 构建位尾部不等范式
            xor_bits_term = [None] * 32
            xor_bits_less = [None] * 32
            xor_bits_greater = [None] * 32
            for ni in range(bit_term_index + 1, 32 - search_depth, -1):
                i = ni - 1
                rand_bit = (tmp_base.get_base() >> i) & 1
                xor_bits_term[i] = XOr(
                    const_true if rand_bit == 1 else const_false, trans_seed[i]
                )
                xor_bits_less[i] = XOr(
                    const_true if ((require[0] >> i) & 1) == 1 else const_false,
                    xor_bits_term[i],
                )
                xor_bits_greater[i] = XOr(
                    const_true if ((require[1] >> i) & 1) == 1 else const_false,
                    xor_bits_term[i],
                )
            bit_less_formulas = []
            bit_greater_formulas = []
            for ni in range(bit_term_index + 1, 32 - search_depth, -1):
                i = ni - 1
                bit_less_formulas.append(
                    XOr(
                        *xor_bits_less[i : bit_term_index + 1], const_false, const_false
                    )
                )
                bit_less_formulas.append(
                    Neg(const_true if ((require[0] >> i) & 1) == 1 else const_false)
                )
                bit_less_formulas.append(xor_bits_term[i])
                bit_greater_formulas.append(
                    XOr(
                        *xor_bits_greater[i : bit_term_index + 1],
                        const_false,
                        const_false
                    )
                )
                bit_greater_formulas.append(Neg(xor_bits_term[i]))
                bit_greater_formulas.append(
                    const_true if ((require[1] >> i) & 1) == 1 else const_false
                )
            formulas.append(Or(*bit_less_formulas, const_false, const_false))
            formulas.append(Or(*bit_greater_formulas, const_false, const_false))

        formula = And(*formulas)
        return formula


class SolverManager:
    solver_name = "cadical153"

    def __init__(
        self,
        config_path="config.json",
        cache_path="cache.json",
        lottery_data_path="lottery_data.json",
        use_cache=False,
    ):
        # 加载配置文件
        self.config_path = config_path
        self.cache_path = cache_path
        self.lottery_data_path = lottery_data_path
        with open(self.config_path, "r", encoding="gbk") as config_file:
            self.config_data = json.load(config_file)
        if use_cache:
            with open(self.cache_path, "r", encoding="gbk") as cache_file:
                self.cache_data = json.load(cache_file)
        else:
            self.cache_data = json.loads('{"result":{}}')
        with open(self.lottery_data_path, "r", encoding="gbk") as lottery_data_file:
            self.lottery_data = json.load(lottery_data_file)
        assert "start_index" in self.config_data
        assert "requires" in self.config_data
        assert "search_depth" in self.config_data
        assert "search_length" in self.config_data
        assert "Labels" in self.lottery_data
        assert "result" in self.cache_data
        # 预处理条件数据
        self.requires = []
        for r in self.config_data["requires"]:
            self.requires.append(self.get_require_from(r))

    # 不要吐槽为什么这里计算这么绕,我只是还原原逻辑
    def get_require_from(self, require_name):
        require = None
        for data in self.lottery_data["Labels"]:
            if data["Description"] == require_name:
                require = data
                break
        if require == None:
            return [0, 100, 0, 100]
        group_ratio = 0
        for data in self.lottery_data["Labels"]:
            if data["GroupLabel"] == require["GroupLabel"]:
                group_ratio += data["Ratio"]
        before_ratio = 0
        for data in self.lottery_data["Labels"]:
            if data["Description"] == require_name:
                break
            if data["GroupLabel"] == require["GroupLabel"]:
                before_ratio += data["Ratio"]
        return [
            0,
            group_ratio,
            before_ratio,
            before_ratio + require["Ratio"],
        ]

    # 写出结果文件
    def flush(self):
        with open(self.cache_path, "w", encoding="gbk") as cache_file:
            json.dump(self.cache_data, cache_file)
            cache_file.close()

    def solve(self, index):
        if str(index) not in self.cache_data["result"]:
            self.cache_data["result"][str(index)] = []
        else:
            return self.cache_data["result"][str(index)]
        factory = CNFFactory(index, self.requires)
        formulas = factory.create_cnf(self.config_data["search_depth"])
        cnf = CNF()
        for clause in formulas:
            cnf.append(clause)
        # cnf.to_file("test_out.cnf")
        with Solver(name=self.solver_name, bootstrap_with=cnf) as solver:
            while solver.solve():
                model = solver.get_model()
                seed = 0
                for i in range(0, 32):
                    if model[i] > 0:
                        seed += 1 << i
                print("seed:" + str(seed))
                self.cache_data["result"][str(index)].append(seed)
                solver.add_clause([-l for l in model[0:32]])
        return self.cache_data["result"][str(index)]

    def run(self):
        for i in range(
            self.config_data["start_index"],
            self.config_data["start_index"] + self.config_data["search_length"],
        ):
            starttime = datetime.datetime.now()
            print("index:" + str(self.solve(i)))
            self.flush()
            endtime = datetime.datetime.now()
            print(
                str(i)
                + " use times {0:.2f}s".format((endtime - starttime).total_seconds())
            )


def main(argv):
    use_cache = len(argv) >= 2 and argv[1] == "use_cache"
    manager = SolverManager(use_cache=use_cache)
    manager.run()


if __name__ == "__main__":
    main(sys.argv)

lottery_data.json文件

{
    "Labels": [
        {
            "GroupLabel": "Earring.001",
            "Description": "第一词条+10%",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.001",
            "Description": "第一词条+12%",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.001",
            "Description": "第一词条+15%",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.002",
            "Description": "DP +400",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.002",
            "Description": "DP +450",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.002",
            "Description": "DP +500",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.002",
            "Description": "DP +550",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.002",
            "Description": "DP +600",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.002",
            "Description": "DP +700",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.002",
            "Description": "DP +800",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.002",
            "Description": "DP +900",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.002",
            "Description": "DP +1200",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.003",
            "Description": "智慧 +32",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.003",
            "Description": "智慧 +33",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.003",
            "Description": "智慧 +34",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.003",
            "Description": "智慧 +35",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.003",
            "Description": "智慧 +37",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.003",
            "Description": "智慧 +39",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.003",
            "Description": "智慧 +41",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.003",
            "Description": "智慧 +43",
            "Ratio": 100
        },
        {
            "GroupLabel": "Earring.003",
            "Description": "智慧 +48",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.001",
            "Description": "通常攻击攻击力+100%",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.001",
            "Description": "通常攻击攻击力+150%",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.001",
            "Description": "通常攻击攻击力+200%",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.002",
            "Description": "攻击属性变化",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.003",
            "Description": "体力 +29",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.003",
            "Description": "体力 +30",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.003",
            "Description": "体力 +31",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.003",
            "Description": "体力 +32",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.003",
            "Description": "体力 +34",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.003",
            "Description": "体力 +36",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.003",
            "Description": "体力 +38",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.003",
            "Description": "体力 +40",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.003",
            "Description": "体力 +45",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.004",
            "Description": "精神 +29",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.004",
            "Description": "精神 +30",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.004",
            "Description": "精神 +31",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.004",
            "Description": "精神 +32",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.004",
            "Description": "精神 +34",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.004",
            "Description": "精神 +36",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.004",
            "Description": "精神 +38",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.004",
            "Description": "精神 +40",
            "Ratio": 100
        },
        {
            "GroupLabel": "Bracelet.004",
            "Description": "精神 +45",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "DP +30",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "DP +20",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "HP +20",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "力量 +2",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "灵巧 +2",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "体力 +2",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "精神 +2",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "智慧 +2",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "幸运 +2",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "DP +10",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "HP +10",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "HP +30",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "力量 +1",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "灵巧 +1",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "体力 +1",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "精神 +1",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "智慧 +1",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "幸运 +1",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "力量 +3",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "灵巧 +3",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "体力 +3",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "精神 +3",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "智慧 +3",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "幸运 +3",
            "Ratio": 100
        },
        {
            "GroupLabel": "LotteryTable.Common1",
            "Description": "暴击率 +0.2%",
            "Ratio": 100
        }
    ]
}