389 lines
14 KiB
Python
389 lines
14 KiB
Python
import os
|
||
import tkinter as tk
|
||
from tkinter import messagebox
|
||
import subprocess
|
||
import sys
|
||
import time
|
||
|
||
# =============== 全局命令配置 ===============
|
||
COMMANDS_TEMPLATE = [
|
||
"conda activate aiden-p3d",
|
||
"d:",
|
||
"cd aiden-p3d",
|
||
]
|
||
|
||
# 扫描路径配置(默认F盘根目录)
|
||
SCAN_PATH = "E:\\" # 修改为您需要的默认扫描路径
|
||
|
||
# 新增文件夹检测间隔(秒)
|
||
DETECTION_INTERVAL = 5 # 每5秒检测一次新文件夹
|
||
|
||
# 游戏配置映射
|
||
GAME_COMMANDS = {
|
||
"赛博朋克2077": {
|
||
"command": "python load_point_cloud_saibo_new.py \"{}\"",
|
||
"description": "赛博朋克2077 - python load_point_cloud_saibo_new.py"
|
||
},
|
||
"巫师3": {
|
||
"command": "python load_point_cloud_wushi_new.py \"{}\"",
|
||
"description": "巫师3 - python load_point_cloud_wushi_new.py"
|
||
},
|
||
"孤岛危机": {
|
||
"command": "python load_point_cloud_crysis_new.py \"{}\"",
|
||
"description": "孤岛危机 - python load_point_cloud_crysis_new.py"
|
||
},
|
||
"地平线零之曙光": {
|
||
"command": "python load_point_horizon_new.py \"{}\"",
|
||
"description": "地平线零之曙光 - python load_point_horizon_new.py"
|
||
},
|
||
"原子之心": {
|
||
"command": "python debug_atomicHeart.py -d \"{}\"",
|
||
"description": "原子之心 - python debug_atomicHeart.py -d"
|
||
},
|
||
"巴士模拟18": {
|
||
"command": "python debug_bus18.py -d \"{}\"",
|
||
"description": "巴士模拟18 - python debug_bus18.py -d"
|
||
},
|
||
"超自然车旅": {
|
||
"command": "python debug_pacificdrive.py -d \"{}\"",
|
||
"description": "超自然车旅 - python debug_pacificdrive.py -d"
|
||
},
|
||
"印蒂卡": {
|
||
"command": "python debug_indika.py -d \"{}\"",
|
||
"description": "印蒂卡 - python debug_indika.py -d"
|
||
},
|
||
"黑神话:悟空": {
|
||
"command": "python restruct_b1.py --data-dir \"{}\"",
|
||
"description": "黑神话:悟空 - python restruct_b1.py --data-dir"
|
||
},
|
||
"新游戏选项": {
|
||
"command": "conda activate worldgen && E: && cd datacheck && run.bat \"{}\"",
|
||
"description": "新游戏选项 - E: && cd datacheck && run.bat"
|
||
}
|
||
}
|
||
|
||
# MeshLab路径
|
||
MESHLAB_PATH = r"C:\Program Files\VCG\MeshLab\meshlab.exe"
|
||
|
||
# 输出目录
|
||
OUTPUT_DIR = r"E:\datacheck\outputs"
|
||
|
||
# =============== 结束配置 ===============
|
||
|
||
class FolderPlayerApp:
|
||
def __init__(self, root):
|
||
self.root = root
|
||
self.root.title("CV Saved Folders Player")
|
||
self.root.geometry("700x250") # 增加窗口宽度以适应新按钮
|
||
self.root.resizable(False, False)
|
||
|
||
self.selected_game = tk.StringVar(value="赛博朋克2077")
|
||
self.scan_folders()
|
||
|
||
if not self.folders:
|
||
messagebox.showerror("错误", f"在路径 {SCAN_PATH} 中没有找到以'cv_saved_'或'25'为前缀的文件夹")
|
||
sys.exit(1)
|
||
|
||
self.current_index = 0
|
||
self.process = None
|
||
self.last_scan_time = time.time()
|
||
|
||
self.create_ui()
|
||
self.update_display()
|
||
self.start_detection_timer()
|
||
self._force_focus_timer()
|
||
|
||
def _force_focus_timer(self):
|
||
self.root.focus_force()
|
||
self.root.after(500, self._force_focus_timer)
|
||
|
||
def start_detection_timer(self):
|
||
self.check_new_folders()
|
||
self.root.after(DETECTION_INTERVAL * 1000, self.start_detection_timer)
|
||
|
||
def check_new_folders(self):
|
||
current_dir = SCAN_PATH
|
||
try:
|
||
all_items = os.listdir(current_dir)
|
||
except Exception as e:
|
||
print(f"检测新文件夹时出错: {e}")
|
||
return
|
||
|
||
processed_folders = set()
|
||
for filename in ["passed_files.txt", "rejected_files.txt"]:
|
||
if os.path.exists(filename):
|
||
with open(filename, 'r', encoding='utf-8') as f:
|
||
for line in f:
|
||
line = line.strip()
|
||
if line and not line.startswith('#'):
|
||
processed_folders.add(line)
|
||
|
||
new_folders = [
|
||
os.path.join(current_dir, item)
|
||
for item in all_items
|
||
if ((item.startswith("cv_saved_") or item.startswith("25")) and
|
||
os.path.isdir(os.path.join(current_dir, item)) and
|
||
item not in processed_folders and
|
||
os.path.join(current_dir, item) not in self.folders)
|
||
]
|
||
|
||
if new_folders:
|
||
new_folders.sort()
|
||
was_empty = len(self.folders) == 0
|
||
self.folders.extend(new_folders)
|
||
|
||
if was_empty and self.folders:
|
||
self.current_index = 0
|
||
self.update_display()
|
||
|
||
messagebox.showinfo("提示", f"检测到 {len(new_folders)} 个新文件夹,已添加到列表")
|
||
|
||
def scan_folders(self):
|
||
current_dir = SCAN_PATH
|
||
try:
|
||
all_items = os.listdir(current_dir)
|
||
except FileNotFoundError:
|
||
messagebox.showerror("错误", f"指定的扫描路径不存在: {SCAN_PATH}")
|
||
sys.exit(1)
|
||
except PermissionError:
|
||
messagebox.showerror("错误", f"没有权限访问指定路径: {SCAN_PATH}")
|
||
sys.exit(1)
|
||
|
||
processed_folders = set()
|
||
for filename in ["passed_files.txt", "rejected_files.txt"]:
|
||
if os.path.exists(filename):
|
||
with open(filename, 'r', encoding='utf-8') as f:
|
||
for line in f:
|
||
line = line.strip()
|
||
if line and not line.startswith('#'):
|
||
processed_folders.add(line)
|
||
|
||
self.folders = [
|
||
os.path.join(current_dir, item)
|
||
for item in all_items
|
||
if ((item.startswith("cv_saved_") or item.startswith("25")) and
|
||
os.path.isdir(os.path.join(current_dir, item)) and
|
||
item not in processed_folders)
|
||
]
|
||
self.folders.sort()
|
||
|
||
def create_ui(self):
|
||
game_frame = tk.Frame(self.root)
|
||
game_frame.pack(fill=tk.X, padx=10, pady=5)
|
||
|
||
tk.Label(game_frame, text="选择游戏:", font=("Arial", 10)).pack(side=tk.LEFT)
|
||
game_dropdown = tk.OptionMenu(game_frame, self.selected_game, *GAME_COMMANDS.keys())
|
||
game_dropdown.pack(side=tk.LEFT, padx=5)
|
||
|
||
self.status_label = tk.Label(self.root, text="", pady=5)
|
||
self.status_label.pack()
|
||
|
||
self.folder_label = tk.Label(self.root, text="", font=("Arial", 12), fg="blue")
|
||
self.folder_label.pack()
|
||
|
||
button_frame = tk.Frame(self.root)
|
||
button_frame.pack(side=tk.BOTTOM, pady=20)
|
||
|
||
self.prev_button = tk.Button(
|
||
button_frame,
|
||
text="上一条(<-)",
|
||
width=10,
|
||
command=self.prev_folder,
|
||
state=tk.DISABLED if self.current_index == 0 else tk.NORMAL
|
||
)
|
||
self.prev_button.pack(side=tk.LEFT, padx=5)
|
||
|
||
self.play_button = tk.Button(
|
||
button_frame,
|
||
text="播放(空格)",
|
||
width=10,
|
||
command=self.play_current
|
||
)
|
||
self.play_button.pack(side=tk.LEFT, padx=5)
|
||
|
||
self.pass_button = tk.Button(
|
||
button_frame,
|
||
text="通过(p)",
|
||
width=10,
|
||
command=self.mark_as_passed,
|
||
bg="green",
|
||
fg="white"
|
||
)
|
||
self.pass_button.pack(side=tk.LEFT, padx=5)
|
||
|
||
self.reject_button = tk.Button(
|
||
button_frame,
|
||
text="不通过(r)",
|
||
width=10,
|
||
command=self.mark_as_rejected,
|
||
bg="red",
|
||
fg="white"
|
||
)
|
||
self.reject_button.pack(side=tk.LEFT, padx=5)
|
||
|
||
self.next_button = tk.Button(
|
||
button_frame,
|
||
text="下一条(->)",
|
||
width=10,
|
||
command=self.next_folder,
|
||
state=tk.DISABLED if self.current_index == len(self.folders) - 1 else tk.NORMAL
|
||
)
|
||
self.next_button.pack(side=tk.LEFT, padx=5)
|
||
|
||
# 新增打开pts.ply文件按钮
|
||
self.open_ply_button = tk.Button(
|
||
button_frame,
|
||
text="打开PLY(o)",
|
||
width=10,
|
||
command=self.open_ply_file,
|
||
bg="orange",
|
||
fg="white"
|
||
)
|
||
self.open_ply_button.pack(side=tk.LEFT, padx=5)
|
||
|
||
self.root.bind('<Left>', lambda event: self.prev_folder())
|
||
self.root.bind('<Right>', lambda event: self.next_folder())
|
||
self.root.bind('<space>', lambda event: self.play_current())
|
||
self.root.bind('<p>', lambda event: self.mark_as_passed())
|
||
self.root.bind('<r>', lambda event: self.mark_as_rejected())
|
||
self.root.bind('<o>', lambda event: self.open_ply_file()) # 绑定o键
|
||
|
||
def update_display(self):
|
||
if not self.folders:
|
||
self.status_label.config(text="所有文件夹已处理完毕")
|
||
self.folder_label.config(text="")
|
||
return
|
||
|
||
current_path = self.folders[self.current_index]
|
||
folder_name = os.path.basename(current_path)
|
||
|
||
self.status_label.config(text=f"正在处理: 第 {self.current_index + 1}/{len(self.folders)} 个")
|
||
self.folder_label.config(text=folder_name)
|
||
|
||
self.prev_button.config(state=tk.NORMAL if self.current_index > 0 else tk.DISABLED)
|
||
self.next_button.config(state=tk.NORMAL if self.current_index < len(self.folders) - 1 else tk.DISABLED)
|
||
|
||
def prev_folder(self):
|
||
if self.current_index > 0:
|
||
self.current_index -= 1
|
||
self.update_display()
|
||
|
||
def next_folder(self):
|
||
if self.current_index < len(self.folders) - 1:
|
||
self.current_index += 1
|
||
self.update_display()
|
||
|
||
def play_current(self):
|
||
if not self.folders:
|
||
return
|
||
|
||
current_path = self.folders[self.current_index]
|
||
selected_game_name = self.selected_game.get()
|
||
game_config = GAME_COMMANDS.get(selected_game_name)
|
||
|
||
if not game_config:
|
||
messagebox.showerror("错误", f"未找到游戏 {selected_game_name} 的配置")
|
||
return
|
||
|
||
try:
|
||
self.close_command_prompt()
|
||
time.sleep(0.5)
|
||
|
||
if selected_game_name == "新游戏选项":
|
||
# 执行新游戏选项命令(不使用COMMANDS_TEMPLATE)
|
||
game_command = game_config["command"]
|
||
formatted_command = game_command.format(current_path)
|
||
|
||
# 启动命令(不等待)
|
||
self.process = subprocess.Popen(f'start cmd /k "{formatted_command}"', shell=True)
|
||
else:
|
||
# 其他游戏使用原有的COMMANDS_TEMPLATE
|
||
game_command = game_config["command"]
|
||
formatted_command = game_command.format(current_path)
|
||
commands = COMMANDS_TEMPLATE.copy()
|
||
commands.append(formatted_command)
|
||
full_command = " && ".join(commands)
|
||
self.process = subprocess.Popen(f'start cmd /k "{full_command}"', shell=True)
|
||
|
||
except Exception as e:
|
||
messagebox.showerror("错误", f"执行命令时出错:\n{str(e)}")
|
||
|
||
def open_ply_file(self):
|
||
"""打开output目录中的pts.ply文件"""
|
||
ply_file = os.path.join(OUTPUT_DIR, "pts.ply")
|
||
|
||
if os.path.exists(ply_file):
|
||
try:
|
||
subprocess.Popen([MESHLAB_PATH, ply_file])
|
||
messagebox.showinfo("成功", f"已用MeshLab打开文件: {ply_file}")
|
||
except Exception as e:
|
||
messagebox.showerror("错误", f"打开文件时出错:\n{str(e)}")
|
||
else:
|
||
messagebox.showwarning("警告", f"未找到文件: {ply_file}")
|
||
|
||
def close_command_prompt(self):
|
||
try:
|
||
if self.process:
|
||
self.process.terminate()
|
||
|
||
subprocess.Popen('taskkill /f /im cmd.exe', shell=True,
|
||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||
creationflags=subprocess.CREATE_NO_WINDOW)
|
||
except Exception as e:
|
||
print(f"关闭命令行时出错: {e}")
|
||
|
||
def mark_as_passed(self):
|
||
self._mark_file("passed_files.txt")
|
||
|
||
def mark_as_rejected(self):
|
||
self._mark_file("rejected_files.txt")
|
||
|
||
def _mark_file(self, filename):
|
||
if not self.folders:
|
||
return
|
||
|
||
current_path = self.folders[self.current_index]
|
||
folder_name = os.path.basename(current_path)
|
||
|
||
try:
|
||
if not os.path.exists(filename):
|
||
with open(filename, 'w', encoding='utf-8') as f:
|
||
pass
|
||
|
||
with open(filename, 'a', encoding='utf-8') as f:
|
||
if os.path.getsize(filename) == 0:
|
||
f.write(f"{folder_name}\n")
|
||
else:
|
||
needs_newline = True
|
||
with open(filename, 'rb+') as f_check:
|
||
f_check.seek(-1, os.SEEK_END)
|
||
last_char = f_check.read(1)
|
||
needs_newline = (last_char != b'\n')
|
||
|
||
if needs_newline:
|
||
f.write('\n')
|
||
f.write(f"{folder_name}\n")
|
||
|
||
status = "通过" if filename == "passed_files.txt" else "不通过"
|
||
messagebox.showinfo("成功", f"已标记为{status}: {folder_name}")
|
||
|
||
self.folders.pop(self.current_index)
|
||
|
||
if self.current_index >= len(self.folders):
|
||
if len(self.folders) > 0:
|
||
self.current_index = len(self.folders) - 1
|
||
else:
|
||
messagebox.showinfo("完成", "所有文件夹已处理完毕!")
|
||
self.update_display()
|
||
return
|
||
|
||
self.update_display()
|
||
|
||
except Exception as e:
|
||
messagebox.showerror("错误", f"写入文件时出错:\n{str(e)}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
root = tk.Tk()
|
||
app = FolderPlayerApp(root)
|
||
root.mainloop() |