Beispiel #1
0
def load_settings(settings=None):
    if settings is None:
        settings = default_settings

    global g_setting
    g_setting = {}

    for setting in settings:
        with open(setting["path"], "r", encoding="utf-8") as setting_file:
            try:
                g_setting[setting["name"]] = yaml.load(setting_file,
                                                       Loader=yaml.FullLoader)
            except Exception as error:
                notify_error(
                    logger,
                    "配置表={}的格式有问题,具体问题请看下面的报错中的line $行数$ column $列数$来定位\n错误信息:{}\n"
                    .format(setting["name"], error))
                exit(0)

    ok, msg = check_settings(g_setting)
    if not ok:
        notify_error(logger, "配置表填写有误:\n{}".format(msg))
        exit(0)

    logger.info("setting loaded")
    logger.debug("setting={}".format(g_setting))
Beispiel #2
0
def report_bugsnag_in_worker(current_process,
                             error,
                             processed_count,
                             args,
                             show_error_messagebox=True):
    traceback_info = traceback.format_exc()

    # 打印错误日志
    logger.info(
        "work thread {} unhandled exception={} when processing {}th work\nargs={}\n{}"
        .format(current_process, error, processed_count, args, traceback_info))

    # 弹出错误框
    if show_error_messagebox:
        notify_error(
            logger, "工作线程{}在处理第{}个计算项的搜索搭配过程中出现了未处理的异常\n{}".format(
                current_process, processed_count, traceback_info))

    # 上报bugsnag
    cpu_name, physical_cpu_cores, manufacturer = get_hardward_info()
    meta_data = {
        "worker_task_info": {
            "args": args,
        },
        "stacktrace_brief": {
            "info": traceback_info,
        },
        "config": config(),
        "settings": all_settings(),
        "app": {
            "releaseStage": RUN_ENV,
            "version": now_version,
            "release_time": ver_time,
        },
        "device": {
            "uuid": uuid.getnode(),
            "node": platform.node(),
            "osName": platform.system(),
            "osVersion": platform.version(),
            "release": platform.release(),
            "architecture": platform.machine(),
            "processor": platform.processor(),
            "logical_cpu_num": multiprocessing.cpu_count(),
            "physical_cpu_num": physical_cpu_cores,
            "cpu_name": cpu_name,
            "manufacturer": manufacturer,
            "time": time.strftime("%Y-%m-%d %H:%M:%S"),
            "timezone": time.strftime("%z", time.gmtime()),
        },
    }
    bugsnag.notify(
        exception=error,
        context="worker",
        meta_data=meta_data,
        user={
            "id": platform.node(),
            "uuid": uuid.getnode(),
        },
    )
Beispiel #3
0
def producer(*args):
    # if exit_calc.value == 1:
    #     return
    producer_data.work_queue.put((producer_data.calc_index, args))

    producer_data.produced_count += 1
    logger.info("producer put %3dth work into work queue",
                producer_data.produced_count)
Beispiel #4
0
    def on_config_update(self, raw_config: dict):
        consoleHandler.setLevel(self.log_level_map[self.log_level])

        if multiprocessing.current_process().name == "MainProcess":
            logger.info("config loaded")
            logging.info("log level change to %s", self.log_level)
            logging.info("max thread is set to %d", self.multi_threading.max_thread)
            logger.debug("raw_config={}".format(raw_config))
            logger.debug("config={}".format(g_config))
Beispiel #5
0
def get_update_info() -> UpdateInfo:
    update_info = UpdateInfo()

    # 获取github本项目的readme页面内容
    readme_html_text = requests.get(config().readme_page).text
    # 从更新日志中提取所有版本信息
    versions = re.findall("(?<=[vV])[0-9.]+(?=\s+\d+\.\d+\.\d+)",
                          readme_html_text)
    # 找出其中最新的那个版本号
    update_info.latest_version = version_int_list_to_version(
        max(version_to_version_int_list(ver) for ver in versions))

    # 从readme中提取最新网盘信息
    netdisk_address_matches = re.findall(
        '链接: <a[\s\S]+?rel="nofollow">(?P<link>.+?)<\/a> 提取码: (?P<passcode>[a-zA-Z0-9]+)',
        readme_html_text, re.MULTILINE)
    # 先选取首个网盘链接作为默认值
    netdisk_link = netdisk_address_matches[0][0]
    netdisk_passcode = netdisk_address_matches[0][1]
    # 然后随机从仍有效的网盘链接中随机一个作为最终结果
    random.seed(datetime.now())
    random.shuffle(netdisk_address_matches)
    for match in netdisk_address_matches:
        if not is_shared_content_blocked(match[0]):
            update_info.netdisk_link = match[0]
            update_info.netdisk_passcode = match[1]
            break

    # 尝试提取更新信息
    update_message_list_match_groupdict = re.search(
        "(?<=更新公告</h1>)\s*<ol>(?P<update_message_list>(\s|\S)+?)</ol>",
        readme_html_text, re.MULTILINE).groupdict()
    if "update_message_list" in update_message_list_match_groupdict:
        update_message_list_str = update_message_list_match_groupdict[
            "update_message_list"]
        update_messages = re.findall("<li>(?P<update_message>.+?)</li>",
                                     update_message_list_str, re.MULTILINE)
        update_info.update_message = "\n".join(
            "{}. {}".format(idx + 1, message)
            for idx, message in enumerate(update_messages))

    logger.info("netdisk_address_matches={}, selected=({}, {})".format(
        netdisk_address_matches, update_info.netdisk_link,
        update_info.netdisk_passcode))

    return update_info
Beispiel #6
0
def check_update_on_start():
    try:
        if not config().check_update_on_start:
            logger.warning("启动时检查更新被禁用,若需启用请在config.toml中设置")
            return

        ui = get_update_info()
        if need_update(now_version, ui.latest_version):
            logger.info("当前版本为{},已有最新版本{},更新内容为{}".format(
                now_version, ui.latest_version, ui.update_message))
            ask_update = tkinter.messagebox.askquestion(
                '更新', ("当前版本为{},已有最新版本{}. 你需要更新吗?\n"
                       "{}".format(now_version, ui.latest_version,
                                   ui.update_message)))
            if ask_update == 'yes':
                if not is_shared_content_blocked(ui.netdisk_link):
                    webbrowser.open(ui.netdisk_link)
                    tkinter.messagebox.showinfo(
                        "蓝奏云网盘提取码",
                        "蓝奏云网盘提取码为: {}".format(ui.netdisk_passcode))
                else:
                    # 如果分享的网盘链接被系统屏蔽了,写日志并弹窗提示
                    logger.warning("网盘链接={}又被系统干掉了=-=".format(ui.netdisk_link))
                    webbrowser.open(
                        "https://github.com/fzls/dnf_calc/releases")
                    tkinter.messagebox.showerror(
                        "不好啦",
                        ("分享的网盘地址好像又被系统给抽掉了呢=。=先暂时使用github的release页面下载吧0-0\n"
                         "请稍作等待~ 风之凌殇看到这个报错后会尽快更新网盘链接的呢\n"
                         "届时再启动程序将自动获取到最新的网盘地址呢~"))
            else:
                tkinter.messagebox.showinfo(
                    "取消启动时自动检查更新方法",
                    "如果想停留在当前版本,不想每次启动都弹出前面这个提醒更新的框框,可以前往config.toml,将check_update_on_start的值设为false即可"
                )
        else:
            logger.info("当前版本{}已是最新版本,无需更新".format(now_version))
    except Exception as err:
        logger.error("更新版本失败, 错误为{}".format(err))
Beispiel #7
0
def load_settings(settings=None):
    if settings is None:
        settings = default_settings

    global g_setting
    g_setting = {}

    for setting in settings:
        try:
            with open(setting["path"], "r", encoding="utf-8") as setting_file:
                g_setting[setting["name"]] = yaml.load(setting_file,
                                                       Loader=yaml.FullLoader)
        except FileNotFoundError as error:
            notify_error(
                logger, "没找到配置表={},你是否直接在压缩包中打开了?\n错误信息:{}\n".format(
                    setting["name"], error))
            sys.exit(0)
        except UnicodeDecodeError as error:
            notify_error(
                logger,
                "配置表={}的编码格式有问题,应为utf-8,如果使用系统自带记事本的话,请下载vscode或notepad++等文本编辑器\n错误信息:{}\n"
                .format(setting["name"], error))
            sys.exit(0)
        except Exception as error:
            notify_error(
                logger,
                "配置表={}的格式有问题,具体问题请看下面的报错中的line $行数$ column $列数$来定位\n错误信息:{}\n"
                .format(setting["name"], error))
            sys.exit(0)

    ok, msg = check_settings(g_setting)
    if not ok:
        notify_error(logger, "配置表填写有误:\n{}".format(msg))
        sys.exit(0)

    if multiprocessing.current_process().name == "MainProcess":
        logger.info("setting loaded")
        logger.debug("setting={}".format(g_setting))
Beispiel #8
0
def consumer(work_queue, exit_calc, work_func):
    """
    @type work_queue: multiprocessing.JoinableQueue
    """
    current_process = multiprocessing.current_process()
    # 为工作线程配置bugsnag信息
    configure_bugsnag()

    # 启动时先读取config和setting
    load_config()
    load_settings()

    logger.info(
        "work thread={} started, configure_bugsnag done, ready to work".format(
            current_process))
    current_calc_index = 0
    processed_count = 0
    continue_wrok = True
    while continue_wrok:
        try:
            calc_index, args = work_queue.get()
            if calc_index != current_calc_index:
                current_calc_index = calc_index
                processed_count = 0
            processed_count += 1
            logger.info("work thread {} processing {}th work".format(
                current_process, processed_count))

            work_func(*args)
        except BrokenPipeError as error:
            # 这个一般是程序退出的时候发生的,这种情况直接退出
            logger.warning("work thread={} BrokenPipeError quit job".format(
                current_process))
            continue_wrok = False
        except Exception as error:
            args_list = []
            if 'args' in locals():
                args_list = [arg.__dict__ for arg in args]
            report_bugsnag_in_worker(current_process, error, processed_count,
                                     args_list)
        finally:
            work_queue.task_done()

    logger.info("work thread ={} stopped, processed_count={}".format(
        current_process, processed_count))
Beispiel #9
0
def add_bonus_attributes_to_base_array(job_type, base_array, style, creature,
                                       save_name, equip_fixup,
                                       equip_index_to_realname,
                                       huanzhuang_slot_fixup):
    cfg = config()

    original_base_array = base_array.copy()

    guofu_teses = [
        {
            "name": "称号",
            "setting_name": "styles",
            "selected": style
        },
        {
            "name": "宠物",
            "setting_name": "creatures",
            "selected": creature
        },
        {
            "name": "其余特色",
            "setting_name": "account_other_bonus_attributes",
            "selected": "所有账号共用"
        },
        {
            "name": "其余特色",
            "setting_name": "account_other_bonus_attributes",
            "selected": save_name
        },
    ]

    for tese in guofu_teses:
        # 处理每一种特色
        setting = get_setting(tese["setting_name"], tese["selected"])
        if setting is None or setting["entries"] is None:
            continue
        # 增加当前选择的特色的各个词条对应的该类型职业的属性
        logger.info("应用国服特色:{}({})".format(tese["selected"], tese["name"]))
        for entry in setting["entries"]:
            for name, value in entry.items():
                entry_indexes = entry_name_to_indexes[name]
                entry_value = eval(str(value))
                entry_writen = False
                if job_type == "deal":
                    # 处理输出职业的对应属性
                    if "deal" not in entry_indexes:
                        continue
                    for entry_index in entry_indexes["deal"]:
                        if entry_index in deal_multiply_entry_indexes:
                            # 需要乘算
                            base_array[entry_index] = multiply_entry(
                                base_array[entry_index], entry_value)
                        elif entry_index in deal_use_max_entry_indexes:
                            # 输出词条取最高值的词条,如黄字和爆伤,最终效果为所有该词条中最大的那个值
                            base_array[entry_index] = use_max_entry(
                                base_array[entry_index], entry_value)
                        else:
                            # 其余加算
                            if name == "extra_all_job_all_active_skill_lv_1_30" and entry_index == index_deal_extra_active_skill_lv_1_45:
                                # 由于词条[所有职业Lv1~30全部主动技能Lv+X(特性技能除外)]不能直接对应输出职业的1-45主动技能,需要打个折,可以自行配置折扣率
                                base_array[
                                    entry_index] += entry_value * cfg.data_fixup.extra_all_job_all_active_skill_lv_1_30_deal_1_45_rate
                            else:
                                # 正常情况
                                base_array[entry_index] += entry_value
                        if not entry_writen:
                            logger.info("\t词条:{} {}".format(
                                entry_name_to_name[name], entry_value))
                            entry_writen = True
                        logger.info("\t\t{} => {}".format(
                            deal_entry_index_to_name[entry_index],
                            entry_value))
                else:
                    # 处理奶系职业的对应属性
                    if "buf" not in entry_indexes:
                        continue
                    for entry_index in entry_indexes["buf"]:
                        if entry_index in buf_multiply_entry_indexes:
                            # 需要乘算
                            base_array[entry_index] = multiply_entry(
                                base_array[entry_index], entry_value)
                        else:
                            # 全部加算
                            base_array[entry_index] += entry_value
                        if not entry_writen:
                            logger.info("\t词条:{} => {}".format(
                                entry_name_to_name[name], entry_value))
                            entry_writen = True
                        logger.info("\t\t{} => {}".format(
                            buf_entry_index_to_name[entry_index], entry_value))

    diff_base_array = base_array - original_base_array
    logger.info("最终特色加成属性如下:\n{}".format(
        format_base_array(job_type, diff_base_array)))

    save_setting = get_setting("account_other_bonus_attributes", save_name)
    if save_setting is not None:
        # 读取当前存档的装备补正信息
        logger.info("尝试查找装备补正信息")
        fixup_cfg = {
            "deal": ("deal_equip_fixup", deal_entry_index_to_name),
            "buf": ("buf_equip_fixup", buf_entry_index_to_name)
        }[job_type]

        if fixup_cfg[0] in save_setting:
            for equip_index, entries in save_setting[fixup_cfg[0]].items():
                equip_index = str(equip_index)
                for entry in entries:
                    for name, value in entry.items():
                        entry_index = eval(name)
                        entry_value = eval(str(value))

                        if entry_value < 0 and not cfg.misc.use_negative_equip_fixup_setting:
                            # 如果这个补正数据是用来矫正与满属性装备的差距的,且设置了不使用负数的修正数据,则跳过
                            continue

                        if equip_index not in equip_fixup:
                            equip_fixup[equip_index] = np.array(
                                [0.0 for idx in range(len(fixup_cfg[1]))])
                        equip_fixup[equip_index][entry_index] += entry_value

        logger.info("最终装备补正数据为:\n")
        for equip_index, ba in equip_fixup.items():
            logger.info("{}-{}\n{}".format(
                equip_index, equip_index_to_realname[equip_index],
                format_base_array(job_type, ba)))

        if cfg.misc.use_huanzhuang_slot_fixup:
            # 读取当前存档的buff换装槽位补正信息
            logger.info("尝试查找buff换装槽位补正信息")

            if "huanzhuang_slot_fixup" in save_setting:
                for slot_index, entries in save_setting[
                        "huanzhuang_slot_fixup"].items():
                    slot_index = str(slot_index)
                    for entry in entries:
                        for name, value in entry.items():
                            entry_index = eval(name)
                            entry_value = eval(str(value))

                            if slot_index not in huanzhuang_slot_fixup:
                                huanzhuang_slot_fixup[slot_index] = np.array([
                                    0.0 for idx in range(
                                        len(buf_entry_index_to_name))
                                ])
                            huanzhuang_slot_fixup[slot_index][
                                entry_index] += entry_value

            logger.info("最终换装槽位补正数据为:\n")
            for slot_index, ba in huanzhuang_slot_fixup.items():
                logger.info("{}-{}\n{}".format(
                    slot_index, slot_index_to_realname[slot_index],
                    format_base_array(job_type, ba)))
Beispiel #10
0
            logging.info("log level change to %s", self.log_level)
            logging.info("max thread is set to %d", self.multi_threading.max_thread)
            logger.debug("raw_config={}".format(raw_config))
            logger.debug("config={}".format(g_config))


g_config = Config()


# 读取程序config
def load_config(config_path="config.toml"):
    global g_config
    try:
        raw_config = toml.load(config_path)
        g_config.auto_update_config(raw_config)
    except UnicodeDecodeError as error:
        notify_error(logger, "{}的编码格式有问题,应为utf-8,如果使用系统自带记事本的话,请下载vscode或notepad++等文本编辑器\n错误信息:{}\n".format(config_path, error))
        sys.exit(0)
    except Exception as error:
        notify_error(logger, "读取{}文件出错,是否直接在压缩包中打开了?\n具体出错为:".format(config_path, error))
        sys.exit(-1)


def config():
    return g_config


if __name__ == '__main__':
    load_config("../config.toml")
    logger.info("ui cfg={}".format(g_config.ui))
Beispiel #11
0
def add_bonus_attributes_to_base_array(job_type, base_array, style, creature,
                                       save_name):
    cfg = config()

    original_base_array = base_array.copy()

    guofu_teses = [
        {
            "name": "称号",
            "setting_name": "styles",
            "selected": style
        },
        {
            "name": "宠物",
            "setting_name": "creatures",
            "selected": creature
        },
        {
            "name": "其余特色",
            "setting_name": "account_other_bonus_attributes",
            "selected": "所有账号共用"
        },
        {
            "name": "其余特色",
            "setting_name": "account_other_bonus_attributes",
            "selected": save_name
        },
    ]

    for tese in guofu_teses:
        # 处理每一种特色
        setting = get_setting(tese["setting_name"], tese["selected"])
        if setting is None or setting["entries"] is None:
            continue
        # 增加当前选择的特色的各个词条对应的该类型职业的属性
        logger.info("应用国服特色:{}({})".format(tese["selected"], tese["name"]))
        for entry in setting["entries"]:
            for name, value in entry.items():
                entry_indexes = entry_name_to_indexes[name]
                entry_value = eval(str(value))
                entry_writen = False
                if job_type == "deal":
                    # 处理输出职业的对应属性
                    if "deal" not in entry_indexes:
                        continue
                    for entry_index in entry_indexes["deal"]:
                        if entry_index in deal_multiply_entry_indexes:
                            # 需要乘算
                            base_array[entry_index] = multiply_entry(
                                base_array[entry_index], entry_value)
                        else:
                            # 其余加算
                            if name == "extra_all_job_all_active_skill_lv_1_30" and entry_index == index_deal_extra_active_skill_lv_1_45:
                                # 由于词条[所有职业Lv1~30全部主动技能Lv+X(特性技能除外)]不能直接对应输出职业的1-45主动技能,需要打个折,可以自行配置折扣率
                                base_array[
                                    entry_index] += entry_value * cfg.data_fixup.extra_all_job_all_active_skill_lv_1_30_deal_1_45_rate
                            else:
                                # 正常情况
                                base_array[entry_index] += entry_value
                        if not entry_writen:
                            logger.info("\t词条:{} {}".format(
                                entry_name_to_name[name], entry_value))
                            entry_writen = True
                        logger.info("\t\t{} => {}".format(
                            deal_entry_index_to_name[entry_index],
                            entry_value))
                else:
                    # 处理奶系职业的对应属性
                    if "buf" not in entry_indexes:
                        continue
                    for entry_index in entry_indexes["buf"]:
                        if entry_index in buf_multiply_entry_indexes:
                            # 需要乘算
                            base_array[entry_index] = multiply_entry(
                                base_array[entry_index], entry_value)
                        else:
                            # 全部加算
                            base_array[entry_index] += entry_value
                        if not entry_writen:
                            logger.info("\t词条:{} => {}".format(
                                entry_name_to_name[name], entry_value))
                            entry_writen = True
                        logger.info("\t\t{} => {}".format(
                            buf_entry_index_to_name[entry_index], entry_value))

    all_tese_strs = []

    diff_base_array = base_array - original_base_array
    index_info = job_to_base_array_index_range_and_index_to_name_dict[job_type]
    index_to_name_dict = index_info["index_to_name_dict"]
    for index in range(index_info["index_begin"], index_info["index_end"] + 1):
        name = index_to_name_dict[index]
        if diff_base_array[index] == 0:
            # 跳过没有实际加成的特色词条
            continue
        all_tese_strs.append("{} => {}".format(name, diff_base_array[index]))

    logger.info("最终特色加成属性如下:\n{}".format("\n".join(all_tese_strs)))
Beispiel #12
0
                                   ui.update_message)))
            if ask_update == 'yes':
                if not is_shared_content_blocked(ui.netdisk_link):
                    webbrowser.open(ui.netdisk_link)
                    tkinter.messagebox.showinfo(
                        "蓝奏云网盘提取码",
                        "蓝奏云网盘提取码为: {}".format(ui.netdisk_passcode))
                else:
                    # 如果分享的网盘链接被系统屏蔽了,写日志并弹窗提示
                    logger.warning("网盘链接={}又被系统干掉了=-=".format(ui.netdisk_link))
                    webbrowser.open(
                        "https://github.com/fzls/dnf_calc/releases")
                    tkinter.messagebox.showerror(
                        "不好啦",
                        ("分享的网盘地址好像又被系统给抽掉了呢=。=先暂时使用github的release页面下载吧0-0\n"
                         "请稍作等待~ 风之凌殇看到这个报错后会尽快更新网盘链接的呢\n"
                         "届时再启动程序将自动获取到最新的网盘地址呢~"))
            else:
                tkinter.messagebox.showinfo(
                    "取消启动时自动检查更新方法",
                    "如果想停留在当前版本,不想每次启动都弹出前面这个提醒更新的框框,可以前往config.toml,将check_update_on_start的值设为false即可"
                )
        else:
            logger.info("当前版本{}已是最新版本,无需更新".format(now_version))
    except Exception as err:
        logger.error("更新版本失败, 错误为{}".format(err))


if __name__ == '__main__':
    logger.info(get_update_info().update_message)