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('', lambda event: self.prev_folder()) self.root.bind('', lambda event: self.next_folder()) self.root.bind('', lambda event: self.play_current()) self.root.bind('

', lambda event: self.mark_as_passed()) self.root.bind('', lambda event: self.mark_as_rejected()) self.root.bind('', 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()