mirror of
https://github.com/hyb-oyqq/FRAISEMOE-Addons-Installer-NEXT.git
synced 2025-12-18 13:00:29 +00:00
feat(core): 优化游戏目录识别和补丁卸载流程
- 改进游戏目录识别算法,支持大小写不敏感和特殊字符处理 - 增加递归搜索可执行文件的功能,提高识别准确率 - 优化补丁卸载流程,支持更灵活的文件路径和名称 - 增加调试模式下的日志输出,便于问题排查 - 重构部分代码结构,提高可维护性和可扩展性
This commit is contained in:
@@ -3,6 +3,7 @@ import requests
|
|||||||
import json
|
import json
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
import re # Added for recursive search
|
||||||
|
|
||||||
from PySide6 import QtWidgets, QtCore
|
from PySide6 import QtWidgets, QtCore
|
||||||
from PySide6.QtCore import Qt
|
from PySide6.QtCore import Qt
|
||||||
@@ -42,10 +43,29 @@ class DownloadManager:
|
|||||||
|
|
||||||
def get_install_paths(self):
|
def get_install_paths(self):
|
||||||
"""获取所有游戏版本的安装路径"""
|
"""获取所有游戏版本的安装路径"""
|
||||||
return {
|
# 使用改进的目录识别功能
|
||||||
game: os.path.join(self.selected_folder, info["install_path"])
|
game_dirs = self.main_window.identify_game_directories_improved(self.selected_folder)
|
||||||
for game, info in GAME_INFO.items()
|
install_paths = {}
|
||||||
}
|
|
||||||
|
debug_mode = self.is_debug_mode()
|
||||||
|
|
||||||
|
for game, info in GAME_INFO.items():
|
||||||
|
if game in game_dirs:
|
||||||
|
# 如果找到了游戏目录,使用它
|
||||||
|
game_dir = game_dirs[game]
|
||||||
|
install_path = os.path.join(game_dir, os.path.basename(info["install_path"]))
|
||||||
|
install_paths[game] = install_path
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 使用识别到的游戏目录 {game}: {game_dir}")
|
||||||
|
print(f"DEBUG: 安装路径设置为: {install_path}")
|
||||||
|
else:
|
||||||
|
# 回退到原始路径计算方式
|
||||||
|
install_path = os.path.join(self.selected_folder, info["install_path"])
|
||||||
|
install_paths[game] = install_path
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 未识别到游戏目录 {game}, 使用默认路径: {install_path}")
|
||||||
|
|
||||||
|
return install_paths
|
||||||
|
|
||||||
def is_debug_mode(self):
|
def is_debug_mode(self):
|
||||||
"""检查是否处于调试模式"""
|
"""检查是否处于调试模式"""
|
||||||
@@ -145,6 +165,26 @@ class DownloadManager:
|
|||||||
# 清空下载历史记录
|
# 清空下载历史记录
|
||||||
self.main_window.download_queue_history = []
|
self.main_window.download_queue_history = []
|
||||||
|
|
||||||
|
# 使用改进的目录识别功能
|
||||||
|
game_dirs = self.main_window.identify_game_directories_improved(self.selected_folder)
|
||||||
|
|
||||||
|
debug_mode = self.is_debug_mode()
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 开始下载流程, 识别到 {len(game_dirs)} 个游戏目录")
|
||||||
|
|
||||||
|
# 检查是否找到任何游戏目录
|
||||||
|
if not game_dirs:
|
||||||
|
if debug_mode:
|
||||||
|
print("DEBUG: 未识别到任何游戏目录,设置目录未找到错误")
|
||||||
|
# 设置特定的错误类型,以便在按钮点击处理中区分处理
|
||||||
|
self.main_window.last_error_message = "directory_not_found"
|
||||||
|
QtWidgets.QMessageBox.warning(
|
||||||
|
self.main_window,
|
||||||
|
f"目录错误 - {APP_NAME}",
|
||||||
|
"\n未能识别到任何游戏目录。\n\n请确认您选择的是游戏的上级目录,并且该目录中包含NEKOPARA系列游戏文件夹。\n"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
# 显示哈希检查窗口
|
# 显示哈希检查窗口
|
||||||
self.main_window.hash_msg_box = self.main_window.hash_manager.hash_pop_window(check_type="pre")
|
self.main_window.hash_msg_box = self.main_window.hash_manager.hash_pop_window(check_type="pre")
|
||||||
|
|
||||||
@@ -227,6 +267,13 @@ class DownloadManager:
|
|||||||
# 创建下载历史记录列表,用于跟踪本次安装的游戏
|
# 创建下载历史记录列表,用于跟踪本次安装的游戏
|
||||||
if not hasattr(self.main_window, 'download_queue_history'):
|
if not hasattr(self.main_window, 'download_queue_history'):
|
||||||
self.main_window.download_queue_history = []
|
self.main_window.download_queue_history = []
|
||||||
|
|
||||||
|
# 获取所有识别到的游戏目录
|
||||||
|
game_dirs = self.main_window.identify_game_directories_improved(self.selected_folder)
|
||||||
|
|
||||||
|
debug_mode = self.is_debug_mode()
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 填充下载队列, 识别到的游戏目录: {game_dirs}")
|
||||||
|
|
||||||
# 添加nekopara 1-4
|
# 添加nekopara 1-4
|
||||||
for i in range(1, 5):
|
for i in range(1, 5):
|
||||||
@@ -234,7 +281,18 @@ class DownloadManager:
|
|||||||
if not self.main_window.installed_status.get(game_version, False):
|
if not self.main_window.installed_status.get(game_version, False):
|
||||||
url = config.get(f"vol{i}")
|
url = config.get(f"vol{i}")
|
||||||
if not url: continue
|
if not url: continue
|
||||||
game_folder = os.path.join(self.selected_folder, f"NEKOPARA Vol. {i}")
|
|
||||||
|
# 确定游戏文件夹路径
|
||||||
|
if game_version in game_dirs:
|
||||||
|
game_folder = game_dirs[game_version]
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 使用识别到的游戏目录 {game_version}: {game_folder}")
|
||||||
|
else:
|
||||||
|
# 回退到传统方式
|
||||||
|
game_folder = os.path.join(self.selected_folder, f"NEKOPARA Vol. {i}")
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 使用默认游戏目录 {game_version}: {game_folder}")
|
||||||
|
|
||||||
_7z_path = os.path.join(PLUGIN, f"vol.{i}.7z")
|
_7z_path = os.path.join(PLUGIN, f"vol.{i}.7z")
|
||||||
plugin_path = os.path.join(PLUGIN, GAME_INFO[game_version]["plugin_path"])
|
plugin_path = os.path.join(PLUGIN, GAME_INFO[game_version]["plugin_path"])
|
||||||
self.download_queue.append((url, game_folder, game_version, _7z_path, plugin_path))
|
self.download_queue.append((url, game_folder, game_version, _7z_path, plugin_path))
|
||||||
@@ -246,7 +304,16 @@ class DownloadManager:
|
|||||||
if not self.main_window.installed_status.get(game_version, False):
|
if not self.main_window.installed_status.get(game_version, False):
|
||||||
url = config.get("after")
|
url = config.get("after")
|
||||||
if url:
|
if url:
|
||||||
game_folder = os.path.join(self.selected_folder, "NEKOPARA After")
|
# 确定After的游戏文件夹路径
|
||||||
|
if game_version in game_dirs:
|
||||||
|
game_folder = game_dirs[game_version]
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 使用识别到的游戏目录 {game_version}: {game_folder}")
|
||||||
|
else:
|
||||||
|
game_folder = os.path.join(self.selected_folder, "NEKOPARA After")
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 使用默认游戏目录 {game_version}: {game_folder}")
|
||||||
|
|
||||||
_7z_path = os.path.join(PLUGIN, "after.7z")
|
_7z_path = os.path.join(PLUGIN, "after.7z")
|
||||||
plugin_path = os.path.join(PLUGIN, GAME_INFO[game_version]["plugin_path"])
|
plugin_path = os.path.join(PLUGIN, GAME_INFO[game_version]["plugin_path"])
|
||||||
self.download_queue.append((url, game_folder, game_version, _7z_path, plugin_path))
|
self.download_queue.append((url, game_folder, game_version, _7z_path, plugin_path))
|
||||||
@@ -402,21 +469,109 @@ class DownloadManager:
|
|||||||
_7z_path: 7z文件保存路径
|
_7z_path: 7z文件保存路径
|
||||||
plugin_path: 插件路径
|
plugin_path: 插件路径
|
||||||
"""
|
"""
|
||||||
game_exe = {
|
# 使用改进的目录识别获取安装路径
|
||||||
game: os.path.join(
|
install_paths = self.get_install_paths()
|
||||||
self.selected_folder, info["install_path"].split("/")[0], info["exe"]
|
|
||||||
|
debug_mode = self.is_debug_mode()
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 准备下载游戏 {game_version}")
|
||||||
|
print(f"DEBUG: 游戏文件夹: {game_folder}")
|
||||||
|
|
||||||
|
# 获取游戏可执行文件路径
|
||||||
|
game_dirs = self.main_window.identify_game_directories_improved(self.selected_folder)
|
||||||
|
game_exe_exists = False
|
||||||
|
|
||||||
|
if game_version in game_dirs:
|
||||||
|
game_dir = game_dirs[game_version]
|
||||||
|
# 游戏目录已经通过可执行文件验证了,可以直接认为存在
|
||||||
|
game_exe_exists = True
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 游戏目录已验证: {game_dir}")
|
||||||
|
print(f"DEBUG: 游戏可执行文件存在: {game_exe_exists}")
|
||||||
|
else:
|
||||||
|
# 回退到传统方法检查游戏是否存在
|
||||||
|
# 尝试多种可能的文件名格式
|
||||||
|
expected_exe = GAME_INFO[game_version]["exe"]
|
||||||
|
traditional_folder = os.path.join(
|
||||||
|
self.selected_folder,
|
||||||
|
GAME_INFO[game_version]["install_path"].split("/")[0]
|
||||||
)
|
)
|
||||||
for game, info in GAME_INFO.items()
|
|
||||||
}
|
# 定义多种可能的可执行文件变体
|
||||||
|
exe_variants = [
|
||||||
|
expected_exe, # 标准文件名
|
||||||
|
expected_exe + ".nocrack", # Steam加密版本
|
||||||
|
expected_exe.replace(".exe", ""), # 无扩展名版本
|
||||||
|
expected_exe.replace("NEKOPARA", "nekopara").lower(), # 全小写变体
|
||||||
|
expected_exe.lower(), # 小写变体
|
||||||
|
expected_exe.lower() + ".nocrack", # 小写变体的Steam加密版本
|
||||||
|
]
|
||||||
|
|
||||||
|
# 对于Vol.3可能有特殊名称
|
||||||
|
if "Vol.3" in game_version:
|
||||||
|
# 增加可能的卷3特定的变体
|
||||||
|
exe_variants.extend([
|
||||||
|
"NEKOPARAVol3.exe",
|
||||||
|
"NEKOPARAVol3.exe.nocrack",
|
||||||
|
"nekoparavol3.exe",
|
||||||
|
"nekoparavol3.exe.nocrack",
|
||||||
|
"nekopara_vol3.exe",
|
||||||
|
"nekopara_vol3.exe.nocrack",
|
||||||
|
"vol3.exe",
|
||||||
|
"vol3.exe.nocrack"
|
||||||
|
])
|
||||||
|
|
||||||
|
# 检查所有可能的文件名
|
||||||
|
for exe_variant in exe_variants:
|
||||||
|
exe_path = os.path.join(traditional_folder, exe_variant)
|
||||||
|
if os.path.exists(exe_path):
|
||||||
|
game_exe_exists = True
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 找到游戏可执行文件: {exe_path}")
|
||||||
|
break
|
||||||
|
|
||||||
|
# 如果仍未找到,尝试递归搜索
|
||||||
|
if not game_exe_exists and os.path.exists(traditional_folder):
|
||||||
|
# 提取卷号或检查是否是After
|
||||||
|
vol_match = re.search(r"Vol\.(\d+)", game_version)
|
||||||
|
vol_num = None
|
||||||
|
if vol_match:
|
||||||
|
vol_num = vol_match.group(1)
|
||||||
|
|
||||||
|
is_after = "After" in game_version
|
||||||
|
|
||||||
|
# 遍历游戏目录及其子目录
|
||||||
|
for root, dirs, files in os.walk(traditional_folder):
|
||||||
|
for file in files:
|
||||||
|
file_lower = file.lower()
|
||||||
|
if file.endswith('.exe') or file.endswith('.exe.nocrack'):
|
||||||
|
# 检查文件名中是否包含卷号或关键词
|
||||||
|
if ((vol_num and (f"vol{vol_num}" in file_lower or
|
||||||
|
f"vol.{vol_num}" in file_lower or
|
||||||
|
f"vol {vol_num}" in file_lower)) or
|
||||||
|
(is_after and "after" in file_lower)):
|
||||||
|
game_exe_exists = True
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 通过递归搜索找到游戏可执行文件: {os.path.join(root, file)}")
|
||||||
|
break
|
||||||
|
if game_exe_exists:
|
||||||
|
break
|
||||||
|
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 使用传统方法检查游戏目录: {traditional_folder}")
|
||||||
|
print(f"DEBUG: 游戏可执行文件存在: {game_exe_exists}")
|
||||||
|
|
||||||
# 检查游戏是否已安装
|
# 检查游戏是否已安装
|
||||||
if (
|
if (
|
||||||
game_version not in game_exe
|
not game_exe_exists
|
||||||
or not os.path.exists(game_exe[game_version])
|
|
||||||
or self.main_window.installed_status[game_version]
|
or self.main_window.installed_status[game_version]
|
||||||
):
|
):
|
||||||
self.main_window.installed_status[game_version] = False
|
if debug_mode:
|
||||||
self.main_window.show_result()
|
print(f"DEBUG: 跳过下载游戏 {game_version}")
|
||||||
|
print(f"DEBUG: 游戏存在: {game_exe_exists}")
|
||||||
|
print(f"DEBUG: 已安装补丁: {self.main_window.installed_status[game_version]}")
|
||||||
|
self.main_window.installed_status[game_version] = False if not game_exe_exists else True
|
||||||
|
self.next_download_task()
|
||||||
return
|
return
|
||||||
|
|
||||||
# 创建进度窗口并开始下载
|
# 创建进度窗口并开始下载
|
||||||
|
|||||||
@@ -283,13 +283,16 @@ class MainWindow(QMainWindow):
|
|||||||
data: 获取到的配置数据
|
data: 获取到的配置数据
|
||||||
error_message: 错误信息,如果有
|
error_message: 错误信息,如果有
|
||||||
"""
|
"""
|
||||||
|
# 定义debug_mode变量在方法开头
|
||||||
|
debug_mode = self.ui_manager.debug_action.isChecked() if hasattr(self.ui_manager, 'debug_action') and self.ui_manager.debug_action else False
|
||||||
|
|
||||||
if error_message:
|
if error_message:
|
||||||
# 标记配置无效
|
# 标记配置无效
|
||||||
self.config_valid = False
|
self.config_valid = False
|
||||||
# 记录错误信息,用于按钮点击时显示
|
|
||||||
self.last_error_message = error_message
|
|
||||||
|
|
||||||
|
# 记录错误信息,用于按钮点击时显示
|
||||||
if error_message == "update_required":
|
if error_message == "update_required":
|
||||||
|
self.last_error_message = "update_required"
|
||||||
msg_box = msgbox_frame(
|
msg_box = msgbox_frame(
|
||||||
f"更新提示 - {APP_NAME}",
|
f"更新提示 - {APP_NAME}",
|
||||||
"\n当前版本过低,请及时更新。\n",
|
"\n当前版本过低,请及时更新。\n",
|
||||||
@@ -302,6 +305,7 @@ class MainWindow(QMainWindow):
|
|||||||
self.shutdown_app(force_exit=True)
|
self.shutdown_app(force_exit=True)
|
||||||
return
|
return
|
||||||
elif "missing_keys" in error_message:
|
elif "missing_keys" in error_message:
|
||||||
|
self.last_error_message = "missing_keys"
|
||||||
missing_versions = error_message.split(":")[1]
|
missing_versions = error_message.split(":")[1]
|
||||||
msg_box = msgbox_frame(
|
msg_box = msgbox_frame(
|
||||||
f"配置缺失 - {APP_NAME}",
|
f"配置缺失 - {APP_NAME}",
|
||||||
@@ -312,8 +316,10 @@ class MainWindow(QMainWindow):
|
|||||||
# 对于部分缺失,仍然允许使用,因为可能只影响部分游戏版本
|
# 对于部分缺失,仍然允许使用,因为可能只影响部分游戏版本
|
||||||
self.config_valid = True
|
self.config_valid = True
|
||||||
else:
|
else:
|
||||||
|
# 设置网络错误标记
|
||||||
|
self.last_error_message = "network_error"
|
||||||
|
|
||||||
# 显示通用错误消息,只在debug模式下显示详细错误
|
# 显示通用错误消息,只在debug模式下显示详细错误
|
||||||
debug_mode = self.ui_manager.debug_action.isChecked() if self.ui_manager.debug_action else False
|
|
||||||
error_msg = "访问云端配置失败,请检查网络状况或稍后再试。"
|
error_msg = "访问云端配置失败,请检查网络状况或稍后再试。"
|
||||||
if debug_mode and "详细错误:" in error_message:
|
if debug_mode and "详细错误:" in error_message:
|
||||||
msg_box = msgbox_frame(
|
msg_box = msgbox_frame(
|
||||||
@@ -337,7 +343,6 @@ class MainWindow(QMainWindow):
|
|||||||
# 清除错误信息
|
# 清除错误信息
|
||||||
self.last_error_message = ""
|
self.last_error_message = ""
|
||||||
|
|
||||||
debug_mode = self.ui_manager.debug_action.isChecked() if self.ui_manager.debug_action else False
|
|
||||||
if debug_mode:
|
if debug_mode:
|
||||||
print("--- Cloud config fetched successfully ---")
|
print("--- Cloud config fetched successfully ---")
|
||||||
print(json.dumps(data, indent=2))
|
print(json.dumps(data, indent=2))
|
||||||
@@ -585,7 +590,7 @@ class MainWindow(QMainWindow):
|
|||||||
根据按钮当前状态决定是显示错误还是执行安装
|
根据按钮当前状态决定是显示错误还是执行安装
|
||||||
"""
|
"""
|
||||||
if not self.install_button_enabled:
|
if not self.install_button_enabled:
|
||||||
# 按钮处于"无法安装"状态,显示上次错误消息
|
# 按钮处于"无法安装"状态
|
||||||
if self.last_error_message == "update_required":
|
if self.last_error_message == "update_required":
|
||||||
msg_box = msgbox_frame(
|
msg_box = msgbox_frame(
|
||||||
f"更新提示 - {APP_NAME}",
|
f"更新提示 - {APP_NAME}",
|
||||||
@@ -593,17 +598,31 @@ class MainWindow(QMainWindow):
|
|||||||
QMessageBox.StandardButton.Ok,
|
QMessageBox.StandardButton.Ok,
|
||||||
)
|
)
|
||||||
msg_box.exec()
|
msg_box.exec()
|
||||||
else:
|
elif self.last_error_message == "directory_not_found":
|
||||||
# 默认显示网络错误
|
# 目录识别失败的特定错误信息
|
||||||
msg_box = msgbox_frame(
|
reply = msgbox_frame(
|
||||||
f"错误 - {APP_NAME}",
|
f"目录错误 - {APP_NAME}",
|
||||||
"\n访问云端配置失败,请检查网络状况或稍后再试。\n",
|
"\n未能识别游戏目录,请确认选择的是游戏的上级目录,并且目录中包含Nekopara游戏文件夹。\n\n是否重新选择目录?\n",
|
||||||
QMessageBox.StandardButton.Ok,
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
||||||
)
|
)
|
||||||
msg_box.exec()
|
if reply.exec() == QMessageBox.StandardButton.Yes:
|
||||||
|
# 重新启用按钮并允许用户选择目录
|
||||||
|
self.set_start_button_enabled(True)
|
||||||
|
# 直接调用文件对话框
|
||||||
|
self.download_manager.file_dialog()
|
||||||
|
else:
|
||||||
|
# 网络错误或其他错误
|
||||||
|
reply = msgbox_frame(
|
||||||
|
f"错误 - {APP_NAME}",
|
||||||
|
"\n访问云端配置失败,请检查网络状况或稍后再试。\n\n是否重新尝试连接?\n",
|
||||||
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
||||||
|
)
|
||||||
|
if reply.exec() == QMessageBox.StandardButton.Yes:
|
||||||
|
# 重试获取配置
|
||||||
|
self.fetch_cloud_config()
|
||||||
else:
|
else:
|
||||||
# 按钮处于"开始安装"状态,正常执行安装流程
|
# 按钮处于"开始安装"状态,正常执行安装流程
|
||||||
self.download_manager.file_dialog()
|
self.download_manager.file_dialog()
|
||||||
|
|
||||||
def handle_uninstall_button_click(self):
|
def handle_uninstall_button_click(self):
|
||||||
"""处理卸载补丁按钮点击事件
|
"""处理卸载补丁按钮点击事件
|
||||||
@@ -612,33 +631,81 @@ class MainWindow(QMainWindow):
|
|||||||
# 获取游戏目录
|
# 获取游戏目录
|
||||||
from PySide6.QtWidgets import QFileDialog
|
from PySide6.QtWidgets import QFileDialog
|
||||||
|
|
||||||
# 打开文件选择对话框
|
debug_mode = self.ui_manager.debug_action.isChecked() if hasattr(self.ui_manager, 'debug_action') and self.ui_manager.debug_action else False
|
||||||
game_dir = QFileDialog.getExistingDirectory(
|
|
||||||
self,
|
|
||||||
"选择游戏目录",
|
|
||||||
""
|
|
||||||
)
|
|
||||||
|
|
||||||
if not game_dir or game_dir == "":
|
# 提示用户选择目录
|
||||||
|
file_dialog_info = "选择游戏上级目录" if debug_mode else "选择游戏目录"
|
||||||
|
selected_folder = QFileDialog.getExistingDirectory(self, file_dialog_info, "")
|
||||||
|
|
||||||
|
if not selected_folder or selected_folder == "":
|
||||||
return # 用户取消了选择
|
return # 用户取消了选择
|
||||||
|
|
||||||
# 验证所选目录是否为有效的游戏目录
|
|
||||||
game_version = self.identify_game_version(game_dir)
|
|
||||||
|
|
||||||
if not game_version:
|
if debug_mode:
|
||||||
msg_box = msgbox_frame(
|
print(f"DEBUG: 卸载功能 - 用户选择了目录: {selected_folder}")
|
||||||
f"错误 - {APP_NAME}",
|
|
||||||
"\n所选目录不是有效的NEKOPARA游戏目录。\n请选择包含游戏可执行文件的目录。\n",
|
# 首先尝试将选择的目录视为上级目录,使用增强的目录识别功能
|
||||||
QMessageBox.StandardButton.Ok,
|
game_dirs = self.identify_game_directories_improved(selected_folder)
|
||||||
)
|
|
||||||
msg_box.exec()
|
if game_dirs and len(game_dirs) > 0:
|
||||||
return
|
# 找到了游戏目录,显示选择对话框
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 卸载功能 - 在上级目录中找到以下游戏: {list(game_dirs.keys())}")
|
||||||
|
|
||||||
|
# 如果只有一个游戏,直接选择它
|
||||||
|
if len(game_dirs) == 1:
|
||||||
|
game_version = list(game_dirs.keys())[0]
|
||||||
|
game_dir = game_dirs[game_version]
|
||||||
|
self._confirm_and_uninstall(game_dir, game_version)
|
||||||
|
else:
|
||||||
|
# 有多个游戏,让用户选择
|
||||||
|
from PySide6.QtWidgets import QInputDialog
|
||||||
|
game_versions = list(game_dirs.keys())
|
||||||
|
selected_game, ok = QInputDialog.getItem(
|
||||||
|
self, "选择游戏", "选择要卸载补丁的游戏:",
|
||||||
|
game_versions, 0, False
|
||||||
|
)
|
||||||
|
|
||||||
|
if ok and selected_game:
|
||||||
|
game_version = selected_game
|
||||||
|
game_dir = game_dirs[game_version]
|
||||||
|
self._confirm_and_uninstall(game_dir, game_version)
|
||||||
|
else:
|
||||||
|
# 未找到游戏目录,尝试将选择的目录作为游戏目录
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 卸载功能 - 未在上级目录找到游戏,尝试将选择的目录视为游戏目录")
|
||||||
|
|
||||||
|
game_version = self.identify_game_version(selected_folder)
|
||||||
|
|
||||||
|
if game_version:
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 卸载功能 - 识别为游戏: {game_version}")
|
||||||
|
self._confirm_and_uninstall(selected_folder, game_version)
|
||||||
|
else:
|
||||||
|
# 两种方式都未识别到游戏
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 卸载功能 - 无法识别游戏")
|
||||||
|
|
||||||
|
msg_box = msgbox_frame(
|
||||||
|
f"错误 - {APP_NAME}",
|
||||||
|
"\n所选目录不是有效的NEKOPARA游戏目录。\n请选择包含游戏可执行文件的目录或其上级目录。\n",
|
||||||
|
QMessageBox.StandardButton.Ok,
|
||||||
|
)
|
||||||
|
msg_box.exec()
|
||||||
|
|
||||||
|
def _confirm_and_uninstall(self, game_dir, game_version):
|
||||||
|
"""确认并卸载补丁
|
||||||
|
|
||||||
|
Args:
|
||||||
|
game_dir: 游戏目录
|
||||||
|
game_version: 游戏版本
|
||||||
|
"""
|
||||||
|
debug_mode = self.ui_manager.debug_action.isChecked() if hasattr(self.ui_manager, 'debug_action') and self.ui_manager.debug_action else False
|
||||||
|
|
||||||
# 确认卸载
|
# 确认卸载
|
||||||
reply = QMessageBox.question(
|
reply = QMessageBox.question(
|
||||||
self,
|
self,
|
||||||
f"确认卸载 - {APP_NAME}",
|
f"确认卸载 - {APP_NAME}",
|
||||||
f"\n确定要卸载 {game_version} 的补丁吗?\n",
|
f"\n确定要卸载 {game_version} 的补丁吗?\n游戏目录: {game_dir}\n",
|
||||||
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
|
||||||
QMessageBox.StandardButton.No
|
QMessageBox.StandardButton.No
|
||||||
)
|
)
|
||||||
@@ -648,7 +715,7 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
# 开始卸载补丁
|
# 开始卸载补丁
|
||||||
self.uninstall_patch(game_dir, game_version)
|
self.uninstall_patch(game_dir, game_version)
|
||||||
|
|
||||||
def identify_game_version(self, game_dir):
|
def identify_game_version(self, game_dir):
|
||||||
"""识别游戏版本
|
"""识别游戏版本
|
||||||
|
|
||||||
@@ -659,31 +726,279 @@ class MainWindow(QMainWindow):
|
|||||||
str: 游戏版本名称,如果不是有效的游戏目录则返回None
|
str: 游戏版本名称,如果不是有效的游戏目录则返回None
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
# 调试模式
|
||||||
|
debug_mode = self.ui_manager.debug_action.isChecked() if hasattr(self.ui_manager, 'debug_action') and self.ui_manager.debug_action else False
|
||||||
|
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 尝试识别游戏版本: {game_dir}")
|
||||||
|
|
||||||
|
# 先通过目录名称进行初步推测(这将作为递归搜索的提示)
|
||||||
|
dir_name = os.path.basename(game_dir).lower()
|
||||||
|
potential_version = None
|
||||||
|
vol_num = None
|
||||||
|
|
||||||
|
# 提取卷号或判断是否是After
|
||||||
|
if "vol" in dir_name or "vol." in dir_name:
|
||||||
|
vol_match = re.search(r"vol(?:\.|\s*)?(\d+)", dir_name)
|
||||||
|
if vol_match:
|
||||||
|
vol_num = vol_match.group(1)
|
||||||
|
potential_version = f"NEKOPARA Vol.{vol_num}"
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 从目录名推测游戏版本: {potential_version}, 卷号: {vol_num}")
|
||||||
|
elif "after" in dir_name:
|
||||||
|
potential_version = "NEKOPARA After"
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 从目录名推测游戏版本: NEKOPARA After")
|
||||||
|
|
||||||
# 检查是否为NEKOPARA游戏目录
|
# 检查是否为NEKOPARA游戏目录
|
||||||
# 通过检查游戏可执行文件来识别游戏版本
|
# 通过检查游戏可执行文件来识别游戏版本
|
||||||
for game_version, info in GAME_INFO.items():
|
for game_version, info in GAME_INFO.items():
|
||||||
exe_path = os.path.join(game_dir, info["exe"])
|
# 尝试多种可能的可执行文件名变体
|
||||||
if os.path.exists(exe_path):
|
exe_variants = [
|
||||||
return game_version
|
info["exe"], # 标准文件名
|
||||||
|
info["exe"] + ".nocrack", # Steam加密版本
|
||||||
# 如果没有直接匹配,尝试通过目录名称推断
|
info["exe"].replace(".exe", ""), # 无扩展名版本
|
||||||
dir_name = os.path.basename(game_dir).lower()
|
info["exe"].replace("NEKOPARA", "nekopara").lower(), # 全小写变体
|
||||||
|
info["exe"].lower(), # 小写变体
|
||||||
|
info["exe"].lower() + ".nocrack", # 小写变体的Steam加密版本
|
||||||
|
]
|
||||||
|
|
||||||
|
# 对于Vol.3可能有特殊名称
|
||||||
|
if "Vol.3" in game_version:
|
||||||
|
# 增加可能的卷3特定的变体
|
||||||
|
exe_variants.extend([
|
||||||
|
"NEKOPARAVol3.exe",
|
||||||
|
"NEKOPARAVol3.exe.nocrack",
|
||||||
|
"nekoparavol3.exe",
|
||||||
|
"nekoparavol3.exe.nocrack",
|
||||||
|
"nekopara_vol3.exe",
|
||||||
|
"nekopara_vol3.exe.nocrack",
|
||||||
|
"vol3.exe",
|
||||||
|
"vol3.exe.nocrack"
|
||||||
|
])
|
||||||
|
|
||||||
|
for exe_variant in exe_variants:
|
||||||
|
exe_path = os.path.join(game_dir, exe_variant)
|
||||||
|
if os.path.exists(exe_path):
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 通过可执行文件确认游戏版本: {game_version}, 文件: {exe_variant}")
|
||||||
|
return game_version
|
||||||
|
|
||||||
if "vol" in dir_name or "vol." in dir_name:
|
# 如果没有直接匹配,尝试递归搜索
|
||||||
# 尝试提取卷号
|
if potential_version:
|
||||||
if "vol 1" in dir_name or "vol.1" in dir_name or "vol1" in dir_name:
|
# 从预测的版本中获取卷号或确认是否是After
|
||||||
return "NEKOPARA Vol.1"
|
is_after = "After" in potential_version
|
||||||
elif "vol 2" in dir_name or "vol.2" in dir_name or "vol2" in dir_name:
|
if not vol_num and not is_after:
|
||||||
return "NEKOPARA Vol.2"
|
vol_match = re.search(r"Vol\.(\d+)", potential_version)
|
||||||
elif "vol 3" in dir_name or "vol.3" in dir_name or "vol3" in dir_name:
|
if vol_match:
|
||||||
return "NEKOPARA Vol.3"
|
vol_num = vol_match.group(1)
|
||||||
elif "vol 4" in dir_name or "vol.4" in dir_name or "vol4" in dir_name:
|
|
||||||
return "NEKOPARA Vol.4"
|
# 递归搜索可执行文件
|
||||||
elif "after" in dir_name:
|
for root, dirs, files in os.walk(game_dir):
|
||||||
return "NEKOPARA After"
|
for file in files:
|
||||||
|
file_lower = file.lower()
|
||||||
|
if file.endswith('.exe') or file.endswith('.exe.nocrack'):
|
||||||
|
# 检查文件名中是否包含卷号或关键词
|
||||||
|
if ((vol_num and (f"vol{vol_num}" in file_lower or
|
||||||
|
f"vol.{vol_num}" in file_lower or
|
||||||
|
f"vol {vol_num}" in file_lower)) or
|
||||||
|
(is_after and "after" in file_lower)):
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 通过递归搜索确认游戏版本: {potential_version}, 文件: {file}")
|
||||||
|
return potential_version
|
||||||
|
|
||||||
|
# 如果仍然没有找到,基于目录名的推测返回结果
|
||||||
|
if potential_version:
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 基于目录名返回推测的游戏版本: {potential_version}")
|
||||||
|
return potential_version
|
||||||
|
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 无法识别游戏版本: {game_dir}")
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def identify_game_directories_improved(self, selected_folder):
|
||||||
|
"""改进的游戏目录识别,支持大小写不敏感和特殊字符处理
|
||||||
|
|
||||||
|
Args:
|
||||||
|
selected_folder: 选择的上级目录
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: 游戏版本到游戏目录的映射
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
# 添加debug日志
|
||||||
|
debug_mode = self.ui_manager.debug_action.isChecked() if hasattr(self.ui_manager, 'debug_action') and self.ui_manager.debug_action else False
|
||||||
|
|
||||||
|
if debug_mode:
|
||||||
|
print(f"--- 开始识别目录: {selected_folder} ---")
|
||||||
|
|
||||||
|
game_paths = {}
|
||||||
|
|
||||||
|
# 获取上级目录中的所有文件夹
|
||||||
|
try:
|
||||||
|
all_dirs = [d for d in os.listdir(selected_folder) if os.path.isdir(os.path.join(selected_folder, d))]
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 找到以下子目录: {all_dirs}")
|
||||||
|
except Exception as e:
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 无法读取目录 {selected_folder}: {str(e)}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
for game, info in GAME_INFO.items():
|
||||||
|
expected_dir = info["install_path"].split("/")[0] # 例如 "NEKOPARA Vol. 1"
|
||||||
|
expected_exe = info["exe"] # 标准可执行文件名
|
||||||
|
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 搜索游戏 {game}, 预期目录: {expected_dir}, 预期可执行文件: {expected_exe}")
|
||||||
|
|
||||||
|
# 尝试不同的匹配方法
|
||||||
|
found_dir = None
|
||||||
|
|
||||||
|
# 1. 精确匹配
|
||||||
|
if expected_dir in all_dirs:
|
||||||
|
found_dir = expected_dir
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 精确匹配成功: {expected_dir}")
|
||||||
|
|
||||||
|
# 2. 大小写不敏感匹配
|
||||||
|
if not found_dir:
|
||||||
|
for dir_name in all_dirs:
|
||||||
|
if expected_dir.lower() == dir_name.lower():
|
||||||
|
found_dir = dir_name
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 大小写不敏感匹配成功: {dir_name}")
|
||||||
|
break
|
||||||
|
|
||||||
|
# 3. 更模糊的匹配(允许特殊字符差异)
|
||||||
|
if not found_dir:
|
||||||
|
# 准备用于模糊匹配的正则表达式模式
|
||||||
|
# 替换空格为可选空格或连字符,替换点为可选点
|
||||||
|
pattern_text = expected_dir.replace(" ", "[ -]?").replace(".", "\\.?")
|
||||||
|
pattern = re.compile(f"^{pattern_text}$", re.IGNORECASE)
|
||||||
|
|
||||||
|
for dir_name in all_dirs:
|
||||||
|
if pattern.match(dir_name):
|
||||||
|
found_dir = dir_name
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 模糊匹配成功: {dir_name} 匹配模式 {pattern_text}")
|
||||||
|
break
|
||||||
|
|
||||||
|
# 4. 如果还是没找到,尝试更宽松的匹配
|
||||||
|
if not found_dir:
|
||||||
|
vol_match = re.search(r"vol(?:\.|\s*)?(\d+)", expected_dir, re.IGNORECASE)
|
||||||
|
vol_num = None
|
||||||
|
if vol_match:
|
||||||
|
vol_num = vol_match.group(1)
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 提取卷号: {vol_num}")
|
||||||
|
|
||||||
|
is_after = "after" in expected_dir.lower()
|
||||||
|
|
||||||
|
for dir_name in all_dirs:
|
||||||
|
dir_lower = dir_name.lower()
|
||||||
|
|
||||||
|
# 对于After特殊处理
|
||||||
|
if is_after and "after" in dir_lower:
|
||||||
|
found_dir = dir_name
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: After特殊匹配成功: {dir_name}")
|
||||||
|
break
|
||||||
|
|
||||||
|
# 对于Vol特殊处理
|
||||||
|
if vol_num:
|
||||||
|
# 查找目录名中的卷号
|
||||||
|
dir_vol_match = re.search(r"vol(?:\.|\s*)?(\d+)", dir_lower)
|
||||||
|
if dir_vol_match and dir_vol_match.group(1) == vol_num:
|
||||||
|
found_dir = dir_name
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 卷号匹配成功: {dir_name} 卷号 {vol_num}")
|
||||||
|
break
|
||||||
|
|
||||||
|
# 如果找到匹配的目录,验证exe文件是否存在
|
||||||
|
if found_dir:
|
||||||
|
potential_path = os.path.join(selected_folder, found_dir)
|
||||||
|
|
||||||
|
# 尝试多种可能的可执行文件名变体
|
||||||
|
# 包括Steam加密版本和其他可能的变体
|
||||||
|
exe_variants = [
|
||||||
|
expected_exe, # 标准文件名
|
||||||
|
expected_exe + ".nocrack", # Steam加密版本
|
||||||
|
expected_exe.replace(".exe", ""),# 无扩展名版本
|
||||||
|
# Vol.3的特殊变体,因为它的文件名可能不一样
|
||||||
|
expected_exe.replace("NEKOPARA", "nekopara").lower(), # 全小写变体
|
||||||
|
expected_exe.lower(), # 小写变体
|
||||||
|
expected_exe.lower() + ".nocrack", # 小写变体的Steam加密版本
|
||||||
|
]
|
||||||
|
|
||||||
|
# 对于Vol.3可能有特殊名称
|
||||||
|
if "Vol.3" in game:
|
||||||
|
# 增加可能的卷3特定的变体
|
||||||
|
exe_variants.extend([
|
||||||
|
"NEKOPARAVol3.exe",
|
||||||
|
"NEKOPARAVol3.exe.nocrack",
|
||||||
|
"nekoparavol3.exe",
|
||||||
|
"nekoparavol3.exe.nocrack",
|
||||||
|
"nekopara_vol3.exe",
|
||||||
|
"nekopara_vol3.exe.nocrack",
|
||||||
|
"vol3.exe",
|
||||||
|
"vol3.exe.nocrack"
|
||||||
|
])
|
||||||
|
|
||||||
|
exe_exists = False
|
||||||
|
found_exe = None
|
||||||
|
|
||||||
|
# 尝试所有可能的变体
|
||||||
|
for exe_variant in exe_variants:
|
||||||
|
exe_path = os.path.join(potential_path, exe_variant)
|
||||||
|
if os.path.exists(exe_path):
|
||||||
|
exe_exists = True
|
||||||
|
found_exe = exe_variant
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 验证成功,找到游戏可执行文件: {exe_variant}")
|
||||||
|
break
|
||||||
|
|
||||||
|
# 如果没有直接找到,尝试递归搜索当前目录下的所有可执行文件
|
||||||
|
if not exe_exists:
|
||||||
|
# 遍历当前目录下的所有文件和文件夹
|
||||||
|
for root, dirs, files in os.walk(potential_path):
|
||||||
|
for file in files:
|
||||||
|
file_lower = file.lower()
|
||||||
|
# 检查是否是游戏可执行文件(根据关键字)
|
||||||
|
if file.endswith('.exe') or file.endswith('.exe.nocrack'):
|
||||||
|
# 检查文件名中是否包含卷号或关键词
|
||||||
|
if (f"vol{vol_num}" in file_lower or
|
||||||
|
f"vol.{vol_num}" in file_lower or
|
||||||
|
f"vol {vol_num}" in file_lower or
|
||||||
|
(is_after and "after" in file_lower)):
|
||||||
|
exe_path = os.path.join(root, file)
|
||||||
|
exe_exists = True
|
||||||
|
found_exe = os.path.relpath(exe_path, potential_path)
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 通过递归搜索找到游戏可执行文件: {found_exe}")
|
||||||
|
break
|
||||||
|
if exe_exists:
|
||||||
|
break
|
||||||
|
|
||||||
|
# 如果找到了可执行文件,将该目录添加到游戏目录列表
|
||||||
|
if exe_exists:
|
||||||
|
game_paths[game] = potential_path
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 验证成功,将 {potential_path} 添加为 {game} 的目录")
|
||||||
|
else:
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 未找到任何可执行文件变体,游戏 {game} 在 {potential_path} 未找到")
|
||||||
|
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 最终识别的游戏目录: {game_paths}")
|
||||||
|
print(f"--- 目录识别结束 ---")
|
||||||
|
|
||||||
|
return game_paths
|
||||||
|
|
||||||
def uninstall_patch(self, game_dir, game_version):
|
def uninstall_patch(self, game_dir, game_version):
|
||||||
"""卸载补丁
|
"""卸载补丁
|
||||||
@@ -695,6 +1010,8 @@ class MainWindow(QMainWindow):
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
|
debug_mode = self.ui_manager.debug_action.isChecked() if hasattr(self.ui_manager, 'debug_action') and self.ui_manager.debug_action else False
|
||||||
|
|
||||||
if game_version not in GAME_INFO:
|
if game_version not in GAME_INFO:
|
||||||
QMessageBox.critical(
|
QMessageBox.critical(
|
||||||
self,
|
self,
|
||||||
@@ -703,54 +1020,110 @@ class MainWindow(QMainWindow):
|
|||||||
QMessageBox.StandardButton.Ok,
|
QMessageBox.StandardButton.Ok,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 开始卸载 {game_version} 补丁,目录: {game_dir}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 获取补丁文件路径
|
files_removed = 0
|
||||||
patch_file_path = os.path.join(game_dir, os.path.basename(GAME_INFO[game_version]["install_path"]))
|
|
||||||
|
|
||||||
# 检查补丁文件是否存在
|
# 获取可能的补丁文件路径
|
||||||
if os.path.exists(patch_file_path):
|
install_path_base = os.path.basename(GAME_INFO[game_version]["install_path"])
|
||||||
os.remove(patch_file_path)
|
patch_file_path = os.path.join(game_dir, install_path_base)
|
||||||
print(f"已删除补丁文件: {patch_file_path}")
|
|
||||||
|
# 尝试查找补丁文件,支持不同大小写
|
||||||
|
patch_files_to_check = [
|
||||||
|
patch_file_path,
|
||||||
|
patch_file_path.lower(),
|
||||||
|
patch_file_path.upper(),
|
||||||
|
patch_file_path.replace("_", ""),
|
||||||
|
patch_file_path.replace("_", "-"),
|
||||||
|
]
|
||||||
|
|
||||||
|
# 查找并删除补丁文件
|
||||||
|
patch_file_found = False
|
||||||
|
for patch_path in patch_files_to_check:
|
||||||
|
if os.path.exists(patch_path):
|
||||||
|
patch_file_found = True
|
||||||
|
os.remove(patch_path)
|
||||||
|
files_removed += 1
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 已删除补丁文件: {patch_path}")
|
||||||
|
|
||||||
|
if not patch_file_found and debug_mode:
|
||||||
|
print(f"DEBUG: 未找到补丁文件,检查了以下路径: {patch_files_to_check}")
|
||||||
|
|
||||||
# 检查是否有额外的签名文件 (.sig)
|
# 检查是否有额外的签名文件 (.sig)
|
||||||
if game_version == "NEKOPARA After":
|
if game_version == "NEKOPARA After":
|
||||||
sig_file_path = f"{patch_file_path}.sig"
|
for patch_path in patch_files_to_check:
|
||||||
|
sig_file_path = f"{patch_path}.sig"
|
||||||
if os.path.exists(sig_file_path):
|
if os.path.exists(sig_file_path):
|
||||||
os.remove(sig_file_path)
|
os.remove(sig_file_path)
|
||||||
print(f"已删除签名文件: {sig_file_path}")
|
files_removed += 1
|
||||||
|
if debug_mode:
|
||||||
# 删除patch文件夹
|
print(f"DEBUG: 已删除签名文件: {sig_file_path}")
|
||||||
patch_folder = os.path.join(game_dir, "patch")
|
|
||||||
|
# 删除patch文件夹
|
||||||
|
patch_folders_to_check = [
|
||||||
|
os.path.join(game_dir, "patch"),
|
||||||
|
os.path.join(game_dir, "Patch"),
|
||||||
|
os.path.join(game_dir, "PATCH"),
|
||||||
|
]
|
||||||
|
|
||||||
|
for patch_folder in patch_folders_to_check:
|
||||||
if os.path.exists(patch_folder):
|
if os.path.exists(patch_folder):
|
||||||
shutil.rmtree(patch_folder)
|
shutil.rmtree(patch_folder)
|
||||||
print(f"已删除补丁文件夹: {patch_folder}")
|
files_removed += 1
|
||||||
|
if debug_mode:
|
||||||
# 删除game/patch文件夹
|
print(f"DEBUG: 已删除补丁文件夹: {patch_folder}")
|
||||||
game_patch_folder = os.path.join(game_dir, "game", "patch")
|
|
||||||
if os.path.exists(game_patch_folder):
|
# 删除game/patch文件夹
|
||||||
shutil.rmtree(game_patch_folder)
|
game_folders = ["game", "Game", "GAME"]
|
||||||
print(f"已删除game/patch文件夹: {game_patch_folder}")
|
patch_folders = ["patch", "Patch", "PATCH"]
|
||||||
|
|
||||||
# 删除配置文件
|
for game_folder in game_folders:
|
||||||
config_file = os.path.join(game_dir, "game", "config.json")
|
for patch_folder in patch_folders:
|
||||||
if os.path.exists(config_file):
|
game_patch_folder = os.path.join(game_dir, game_folder, patch_folder)
|
||||||
os.remove(config_file)
|
if os.path.exists(game_patch_folder):
|
||||||
print(f"已删除配置文件: {config_file}")
|
shutil.rmtree(game_patch_folder)
|
||||||
|
files_removed += 1
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 已删除game/patch文件夹: {game_patch_folder}")
|
||||||
|
|
||||||
|
# 删除配置文件
|
||||||
|
config_files = ["config.json", "Config.json", "CONFIG.JSON"]
|
||||||
|
script_files = ["scripts.json", "Scripts.json", "SCRIPTS.JSON"]
|
||||||
|
|
||||||
|
for game_folder in game_folders:
|
||||||
|
game_path = os.path.join(game_dir, game_folder)
|
||||||
|
if os.path.exists(game_path):
|
||||||
|
# 删除配置文件
|
||||||
|
for config_file in config_files:
|
||||||
|
config_path = os.path.join(game_path, config_file)
|
||||||
|
if os.path.exists(config_path):
|
||||||
|
os.remove(config_path)
|
||||||
|
files_removed += 1
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 已删除配置文件: {config_path}")
|
||||||
|
|
||||||
scripts_file = os.path.join(game_dir, "game", "scripts.json")
|
# 删除脚本文件
|
||||||
if os.path.exists(scripts_file):
|
for script_file in script_files:
|
||||||
os.remove(scripts_file)
|
script_path = os.path.join(game_path, script_file)
|
||||||
print(f"已删除脚本文件: {scripts_file}")
|
if os.path.exists(script_path):
|
||||||
|
os.remove(script_path)
|
||||||
# 更新安装状态
|
files_removed += 1
|
||||||
self.installed_status[game_version] = False
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 已删除脚本文件: {script_path}")
|
||||||
# 显示卸载成功消息
|
|
||||||
|
# 更新安装状态
|
||||||
|
self.installed_status[game_version] = False
|
||||||
|
|
||||||
|
# 显示卸载成功消息
|
||||||
|
if files_removed > 0:
|
||||||
QMessageBox.information(
|
QMessageBox.information(
|
||||||
self,
|
self,
|
||||||
f"卸载完成 - {APP_NAME}",
|
f"卸载完成 - {APP_NAME}",
|
||||||
f"\n{game_version} 补丁卸载成功!\n",
|
f"\n{game_version} 补丁卸载成功!\n共删除 {files_removed} 个文件/文件夹。\n",
|
||||||
QMessageBox.StandardButton.Ok,
|
QMessageBox.StandardButton.Ok,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@@ -763,10 +1136,14 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# 显示卸载失败消息
|
# 显示卸载失败消息
|
||||||
|
error_message = f"\n卸载 {game_version} 补丁时出错:\n\n{str(e)}\n"
|
||||||
|
if debug_mode:
|
||||||
|
print(f"DEBUG: 卸载错误 - {str(e)}")
|
||||||
|
|
||||||
QMessageBox.critical(
|
QMessageBox.critical(
|
||||||
self,
|
self,
|
||||||
f"卸载失败 - {APP_NAME}",
|
f"卸载失败 - {APP_NAME}",
|
||||||
f"\n卸载 {game_version} 补丁时出错:\n\n{str(e)}\n",
|
error_message,
|
||||||
QMessageBox.StandardButton.Ok,
|
QMessageBox.StandardButton.Ok,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -188,6 +188,7 @@ class AdminPrivileges:
|
|||||||
"nekopara_vol1.exe",
|
"nekopara_vol1.exe",
|
||||||
"nekopara_vol2.exe",
|
"nekopara_vol2.exe",
|
||||||
"NEKOPARAvol3.exe",
|
"NEKOPARAvol3.exe",
|
||||||
|
"NEKOPARAvol3.exe.nocrack",
|
||||||
"nekopara_vol4.exe",
|
"nekopara_vol4.exe",
|
||||||
"nekopara_after.exe",
|
"nekopara_after.exe",
|
||||||
]
|
]
|
||||||
@@ -230,33 +231,40 @@ class AdminPrivileges:
|
|||||||
|
|
||||||
def check_and_terminate_processes(self):
|
def check_and_terminate_processes(self):
|
||||||
for proc in psutil.process_iter(["pid", "name"]):
|
for proc in psutil.process_iter(["pid", "name"]):
|
||||||
if proc.info["name"] in self.required_exes:
|
proc_name = proc.info["name"].lower() if proc.info["name"] else ""
|
||||||
msg_box = msgbox_frame(
|
|
||||||
f"进程检测 - {APP_NAME}",
|
# 检查进程名是否匹配任何需要终止的游戏进程
|
||||||
f"\n检测到游戏正在运行: {proc.info['name']} \n\n是否终止?\n",
|
for exe in self.required_exes:
|
||||||
QtWidgets.QMessageBox.StandardButton.Yes | QtWidgets.QMessageBox.StandardButton.No,
|
if exe.lower() == proc_name:
|
||||||
)
|
# 获取不带.nocrack的游戏名称用于显示
|
||||||
reply = msg_box.exec()
|
display_name = exe.replace(".nocrack", "")
|
||||||
if reply == QtWidgets.QMessageBox.StandardButton.Yes:
|
|
||||||
try:
|
msg_box = msgbox_frame(
|
||||||
proc.terminate()
|
f"进程检测 - {APP_NAME}",
|
||||||
proc.wait(timeout=3)
|
f"\n检测到游戏正在运行: {display_name} \n\n是否终止?\n",
|
||||||
except psutil.AccessDenied:
|
QtWidgets.QMessageBox.StandardButton.Yes | QtWidgets.QMessageBox.StandardButton.No,
|
||||||
|
)
|
||||||
|
reply = msg_box.exec()
|
||||||
|
if reply == QtWidgets.QMessageBox.StandardButton.Yes:
|
||||||
|
try:
|
||||||
|
proc.terminate()
|
||||||
|
proc.wait(timeout=3)
|
||||||
|
except psutil.AccessDenied:
|
||||||
|
msg_box = msgbox_frame(
|
||||||
|
f"错误 - {APP_NAME}",
|
||||||
|
f"\n无法关闭游戏: {display_name} \n\n请手动关闭后重启应用\n",
|
||||||
|
QtWidgets.QMessageBox.StandardButton.Ok,
|
||||||
|
)
|
||||||
|
msg_box.exec()
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
msg_box = msgbox_frame(
|
msg_box = msgbox_frame(
|
||||||
f"错误 - {APP_NAME}",
|
f"进程检测 - {APP_NAME}",
|
||||||
f"\n无法关闭游戏: {proc.info['name']} \n\n请手动关闭后重启应用\n",
|
f"\n未关闭的游戏: {display_name} \n\n请手动关闭后重启应用\n",
|
||||||
QtWidgets.QMessageBox.StandardButton.Ok,
|
QtWidgets.QMessageBox.StandardButton.Ok,
|
||||||
)
|
)
|
||||||
msg_box.exec()
|
msg_box.exec()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
else:
|
|
||||||
msg_box = msgbox_frame(
|
|
||||||
f"进程检测 - {APP_NAME}",
|
|
||||||
f"\n未关闭的游戏: {proc.info['name']} \n\n请手动关闭后重启应用\n",
|
|
||||||
QtWidgets.QMessageBox.StandardButton.Ok,
|
|
||||||
)
|
|
||||||
msg_box.exec()
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
class HostsManager:
|
class HostsManager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user