commit f07411be998e67b4792740512eb23b70c7a41c5a Author: AzenKain Date: Mon Apr 21 13:50:48 2025 +0700 init diff --git a/.history/main_20250124231320.py b/.history/main_20250124231320.py new file mode 100644 index 0000000..f2f6268 --- /dev/null +++ b/.history/main_20250124231320.py @@ -0,0 +1,152 @@ +import os +import subprocess +import json +import customtkinter as ctk +from tkinter import filedialog, messagebox + +ctk.set_appearance_mode("System") +ctk.set_default_color_theme("blue") +# Initialize global variables +game_folder = None + +# Create the customtkinter window +app = ctk.CTk() +app.title("Firefly HDiff Tool") +app.geometry("335x470") +app.resizable(False, False) +current_dir = os.path.dirname(os.path.abspath(__file__)) +app.iconbitmap(os.path.join(current_dir, 'image.ico')) +app.grid_columnconfigure((0), weight=1) + +# Set appearance mode and theme + + +# Main frame for better organization +main_frame = ctk.CTkFrame(app) +main_frame.pack(fill=ctk.BOTH, expand=True) + +# Folder selection button with modern style +folder_button = ctk.CTkButton(main_frame, text="Select Game Folder", command=lambda: select_folder(), width=300, anchor='center') +folder_button.grid(row=0, column=0, padx=20, pady=20, sticky="ew", columnspan=10) + +# Folder label to display selected folder +folder_label = ctk.CTkLabel(main_frame, text="No folder selected", width=200, anchor="center", text_color="gray") +folder_label.grid(row=1, column=0, padx=20, pady=20, sticky="ew", columnspan=2) + +# Apply Patch button with modern style +apply_button = ctk.CTkButton(main_frame, text="Apply Patch", command=lambda: apply_patch_action(), state=ctk.DISABLED, width=300, anchor='center') +apply_button.grid(row=2, column=0, padx=10, pady=10) + +# Output text area with scroll functionality +output_frame = ctk.CTkFrame(main_frame, width=300) +output_frame.grid(row=3, column=0, padx=10, pady=5) + +output_text = ctk.CTkTextbox(output_frame, height=8, width=300) +output_text.grid(row=0, column=0, sticky="nsew") + +# Scrollbar for the text area +scrollbar = ctk.CTkScrollbar(output_frame, command=output_text.yview) +scrollbar.grid(row=0, column=1, sticky="ns") + +output_text.configure(yscrollcommand=scrollbar.set, state=ctk.DISABLED) + +# Progress bar +progress_label = ctk.CTkLabel(main_frame, text="Progress", width=300, anchor='center') +progress_label.grid(row=4, column=0, padx=10) + +progress_bar = ctk.CTkProgressBar(main_frame, orientation="horizontal") +progress_bar.grid(row=5, column=0, pady=10) +progress_bar.set(0) + +def select_folder(): + """Select a folder to set as the game folder.""" + global game_folder + folder_path = filedialog.askdirectory() + if folder_path: + game_folder = folder_path + folder_label.configure(text=f"Selected Folder: {folder_path}") + apply_button.configure(state=ctk.NORMAL) + else: + messagebox.showwarning("Warning", "No folder selected.") + apply_button.configure(state=ctk.DISABLED) + +def apply_patch_action(): + """Apply patch to the selected game folder.""" + if not game_folder: + messagebox.showwarning("Warning", "Please select a game folder!") + return + apply_patch(game_folder) + +def apply_patch(game_folder): + """Main function to apply patch based on selected folder.""" + folder_button.configure(state=ctk.DISABLED) + delete_files_path = os.path.join(game_folder, 'deletefiles.txt') + if not os.path.exists(delete_files_path): + folder_button.configure(state=ctk.NORMAL) + log_output('deletefiles.txt does not exist in the game directory!') + return + + hdiff_map_path = os.path.join(game_folder, 'hdiffmap.json') + if not os.path.exists(hdiff_map_path): + folder_button.configure(state=ctk.NORMAL) + log_output('hdiffmap.json does not exist in the game directory!') + return + + # Read deletefiles.txt and delete the specified files + with open(delete_files_path, 'r') as delete_files: + for file in delete_files.read().split('\n'): + if len(file) < 1: + continue + file_path = os.path.join(game_folder, file) + if os.path.exists(file_path): + log_output(f'Deleting {file_path}') + os.remove(file_path) + + # Check if hpatchz is available in the system path + hzpatchz = os.path.join(current_dir, 'hpatchz.exe') + if not os.path.exists(hzpatchz): + folder_button.configure(state=ctk.NORMAL) + log_output(f"HDiffPatch not found in the current directory ({current_dir})!\nPlease make sure hpatchz.exe is in the same folder as the script.") + return + + # Read hdiffmap.json + with open(hdiff_map_path, 'r') as hdiff_json: + data = json.load(hdiff_json) + + total_patches = len(data['diff_map']) + progress_bar.set(0) + + # Apply patches + for i, entry in enumerate(data['diff_map']): + source_file_name = os.path.join(game_folder, entry['source_file_name']) + patch_file_name = os.path.join(game_folder, entry['patch_file_name']) + target_file_name = os.path.join(game_folder, entry['target_file_name']) + + # Check if files exist + if not os.path.exists(source_file_name): + log_output(f"Source file missing: {source_file_name}") + continue + if not os.path.exists(patch_file_name): + log_output(f"Patch file missing: {patch_file_name}") + continue + + log_output(f"Applying patch: {patch_file_name} -> {target_file_name} using {source_file_name}") + subprocess.run([hzpatchz, source_file_name, patch_file_name, target_file_name]) + + # Update progress bar + progress_percentage = float((i + 1) / total_patches) + progress_bar.set(progress_percentage) + app.update_idletasks() + + log_output("Patch application complete.") + + folder_button.configure(state=ctk.NORMAL) + +def log_output(message): + """Log the output in the Text widget.""" + output_text.configure(state=ctk.NORMAL) + output_text.insert(ctk.END, message + "\n\n") + output_text.yview(ctk.END) + output_text.configure(state=ctk.DISABLED) + +app.mainloop() diff --git a/.history/main_20250421135009.py b/.history/main_20250421135009.py new file mode 100644 index 0000000..f2f6268 --- /dev/null +++ b/.history/main_20250421135009.py @@ -0,0 +1,152 @@ +import os +import subprocess +import json +import customtkinter as ctk +from tkinter import filedialog, messagebox + +ctk.set_appearance_mode("System") +ctk.set_default_color_theme("blue") +# Initialize global variables +game_folder = None + +# Create the customtkinter window +app = ctk.CTk() +app.title("Firefly HDiff Tool") +app.geometry("335x470") +app.resizable(False, False) +current_dir = os.path.dirname(os.path.abspath(__file__)) +app.iconbitmap(os.path.join(current_dir, 'image.ico')) +app.grid_columnconfigure((0), weight=1) + +# Set appearance mode and theme + + +# Main frame for better organization +main_frame = ctk.CTkFrame(app) +main_frame.pack(fill=ctk.BOTH, expand=True) + +# Folder selection button with modern style +folder_button = ctk.CTkButton(main_frame, text="Select Game Folder", command=lambda: select_folder(), width=300, anchor='center') +folder_button.grid(row=0, column=0, padx=20, pady=20, sticky="ew", columnspan=10) + +# Folder label to display selected folder +folder_label = ctk.CTkLabel(main_frame, text="No folder selected", width=200, anchor="center", text_color="gray") +folder_label.grid(row=1, column=0, padx=20, pady=20, sticky="ew", columnspan=2) + +# Apply Patch button with modern style +apply_button = ctk.CTkButton(main_frame, text="Apply Patch", command=lambda: apply_patch_action(), state=ctk.DISABLED, width=300, anchor='center') +apply_button.grid(row=2, column=0, padx=10, pady=10) + +# Output text area with scroll functionality +output_frame = ctk.CTkFrame(main_frame, width=300) +output_frame.grid(row=3, column=0, padx=10, pady=5) + +output_text = ctk.CTkTextbox(output_frame, height=8, width=300) +output_text.grid(row=0, column=0, sticky="nsew") + +# Scrollbar for the text area +scrollbar = ctk.CTkScrollbar(output_frame, command=output_text.yview) +scrollbar.grid(row=0, column=1, sticky="ns") + +output_text.configure(yscrollcommand=scrollbar.set, state=ctk.DISABLED) + +# Progress bar +progress_label = ctk.CTkLabel(main_frame, text="Progress", width=300, anchor='center') +progress_label.grid(row=4, column=0, padx=10) + +progress_bar = ctk.CTkProgressBar(main_frame, orientation="horizontal") +progress_bar.grid(row=5, column=0, pady=10) +progress_bar.set(0) + +def select_folder(): + """Select a folder to set as the game folder.""" + global game_folder + folder_path = filedialog.askdirectory() + if folder_path: + game_folder = folder_path + folder_label.configure(text=f"Selected Folder: {folder_path}") + apply_button.configure(state=ctk.NORMAL) + else: + messagebox.showwarning("Warning", "No folder selected.") + apply_button.configure(state=ctk.DISABLED) + +def apply_patch_action(): + """Apply patch to the selected game folder.""" + if not game_folder: + messagebox.showwarning("Warning", "Please select a game folder!") + return + apply_patch(game_folder) + +def apply_patch(game_folder): + """Main function to apply patch based on selected folder.""" + folder_button.configure(state=ctk.DISABLED) + delete_files_path = os.path.join(game_folder, 'deletefiles.txt') + if not os.path.exists(delete_files_path): + folder_button.configure(state=ctk.NORMAL) + log_output('deletefiles.txt does not exist in the game directory!') + return + + hdiff_map_path = os.path.join(game_folder, 'hdiffmap.json') + if not os.path.exists(hdiff_map_path): + folder_button.configure(state=ctk.NORMAL) + log_output('hdiffmap.json does not exist in the game directory!') + return + + # Read deletefiles.txt and delete the specified files + with open(delete_files_path, 'r') as delete_files: + for file in delete_files.read().split('\n'): + if len(file) < 1: + continue + file_path = os.path.join(game_folder, file) + if os.path.exists(file_path): + log_output(f'Deleting {file_path}') + os.remove(file_path) + + # Check if hpatchz is available in the system path + hzpatchz = os.path.join(current_dir, 'hpatchz.exe') + if not os.path.exists(hzpatchz): + folder_button.configure(state=ctk.NORMAL) + log_output(f"HDiffPatch not found in the current directory ({current_dir})!\nPlease make sure hpatchz.exe is in the same folder as the script.") + return + + # Read hdiffmap.json + with open(hdiff_map_path, 'r') as hdiff_json: + data = json.load(hdiff_json) + + total_patches = len(data['diff_map']) + progress_bar.set(0) + + # Apply patches + for i, entry in enumerate(data['diff_map']): + source_file_name = os.path.join(game_folder, entry['source_file_name']) + patch_file_name = os.path.join(game_folder, entry['patch_file_name']) + target_file_name = os.path.join(game_folder, entry['target_file_name']) + + # Check if files exist + if not os.path.exists(source_file_name): + log_output(f"Source file missing: {source_file_name}") + continue + if not os.path.exists(patch_file_name): + log_output(f"Patch file missing: {patch_file_name}") + continue + + log_output(f"Applying patch: {patch_file_name} -> {target_file_name} using {source_file_name}") + subprocess.run([hzpatchz, source_file_name, patch_file_name, target_file_name]) + + # Update progress bar + progress_percentage = float((i + 1) / total_patches) + progress_bar.set(progress_percentage) + app.update_idletasks() + + log_output("Patch application complete.") + + folder_button.configure(state=ctk.NORMAL) + +def log_output(message): + """Log the output in the Text widget.""" + output_text.configure(state=ctk.NORMAL) + output_text.insert(ctk.END, message + "\n\n") + output_text.yview(ctk.END) + output_text.configure(state=ctk.DISABLED) + +app.mainloop() diff --git a/.history/requirements_20250421134451.txt b/.history/requirements_20250421134451.txt new file mode 100644 index 0000000..e69de29 diff --git a/.history/requirements_20250421134748.txt b/.history/requirements_20250421134748.txt new file mode 100644 index 0000000..3477701 --- /dev/null +++ b/.history/requirements_20250421134748.txt @@ -0,0 +1 @@ +customtkinter diff --git a/.history/requirements_20250421134815.txt b/.history/requirements_20250421134815.txt new file mode 100644 index 0000000..3477701 --- /dev/null +++ b/.history/requirements_20250421134815.txt @@ -0,0 +1 @@ +customtkinter diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/FireflyHdiff.iml b/.idea/FireflyHdiff.iml new file mode 100644 index 0000000..9a323b0 --- /dev/null +++ b/.idea/FireflyHdiff.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/discord.xml b/.idea/discord.xml new file mode 100644 index 0000000..30bab2a --- /dev/null +++ b/.idea/discord.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/git_toolbox_blame.xml b/.idea/git_toolbox_blame.xml new file mode 100644 index 0000000..7dc1249 --- /dev/null +++ b/.idea/git_toolbox_blame.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/material_theme_project_new.xml b/.idea/material_theme_project_new.xml new file mode 100644 index 0000000..4356175 --- /dev/null +++ b/.idea/material_theme_project_new.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..ac208ee --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..a4df3fe --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/hdiffz.exe b/hdiffz.exe new file mode 100644 index 0000000..38c092d Binary files /dev/null and b/hdiffz.exe differ diff --git a/hpatchz.exe b/hpatchz.exe new file mode 100644 index 0000000..d3fe650 Binary files /dev/null and b/hpatchz.exe differ diff --git a/image.ico b/image.ico new file mode 100644 index 0000000..2f424b6 Binary files /dev/null and b/image.ico differ diff --git a/main.py b/main.py new file mode 100644 index 0000000..f2f6268 --- /dev/null +++ b/main.py @@ -0,0 +1,152 @@ +import os +import subprocess +import json +import customtkinter as ctk +from tkinter import filedialog, messagebox + +ctk.set_appearance_mode("System") +ctk.set_default_color_theme("blue") +# Initialize global variables +game_folder = None + +# Create the customtkinter window +app = ctk.CTk() +app.title("Firefly HDiff Tool") +app.geometry("335x470") +app.resizable(False, False) +current_dir = os.path.dirname(os.path.abspath(__file__)) +app.iconbitmap(os.path.join(current_dir, 'image.ico')) +app.grid_columnconfigure((0), weight=1) + +# Set appearance mode and theme + + +# Main frame for better organization +main_frame = ctk.CTkFrame(app) +main_frame.pack(fill=ctk.BOTH, expand=True) + +# Folder selection button with modern style +folder_button = ctk.CTkButton(main_frame, text="Select Game Folder", command=lambda: select_folder(), width=300, anchor='center') +folder_button.grid(row=0, column=0, padx=20, pady=20, sticky="ew", columnspan=10) + +# Folder label to display selected folder +folder_label = ctk.CTkLabel(main_frame, text="No folder selected", width=200, anchor="center", text_color="gray") +folder_label.grid(row=1, column=0, padx=20, pady=20, sticky="ew", columnspan=2) + +# Apply Patch button with modern style +apply_button = ctk.CTkButton(main_frame, text="Apply Patch", command=lambda: apply_patch_action(), state=ctk.DISABLED, width=300, anchor='center') +apply_button.grid(row=2, column=0, padx=10, pady=10) + +# Output text area with scroll functionality +output_frame = ctk.CTkFrame(main_frame, width=300) +output_frame.grid(row=3, column=0, padx=10, pady=5) + +output_text = ctk.CTkTextbox(output_frame, height=8, width=300) +output_text.grid(row=0, column=0, sticky="nsew") + +# Scrollbar for the text area +scrollbar = ctk.CTkScrollbar(output_frame, command=output_text.yview) +scrollbar.grid(row=0, column=1, sticky="ns") + +output_text.configure(yscrollcommand=scrollbar.set, state=ctk.DISABLED) + +# Progress bar +progress_label = ctk.CTkLabel(main_frame, text="Progress", width=300, anchor='center') +progress_label.grid(row=4, column=0, padx=10) + +progress_bar = ctk.CTkProgressBar(main_frame, orientation="horizontal") +progress_bar.grid(row=5, column=0, pady=10) +progress_bar.set(0) + +def select_folder(): + """Select a folder to set as the game folder.""" + global game_folder + folder_path = filedialog.askdirectory() + if folder_path: + game_folder = folder_path + folder_label.configure(text=f"Selected Folder: {folder_path}") + apply_button.configure(state=ctk.NORMAL) + else: + messagebox.showwarning("Warning", "No folder selected.") + apply_button.configure(state=ctk.DISABLED) + +def apply_patch_action(): + """Apply patch to the selected game folder.""" + if not game_folder: + messagebox.showwarning("Warning", "Please select a game folder!") + return + apply_patch(game_folder) + +def apply_patch(game_folder): + """Main function to apply patch based on selected folder.""" + folder_button.configure(state=ctk.DISABLED) + delete_files_path = os.path.join(game_folder, 'deletefiles.txt') + if not os.path.exists(delete_files_path): + folder_button.configure(state=ctk.NORMAL) + log_output('deletefiles.txt does not exist in the game directory!') + return + + hdiff_map_path = os.path.join(game_folder, 'hdiffmap.json') + if not os.path.exists(hdiff_map_path): + folder_button.configure(state=ctk.NORMAL) + log_output('hdiffmap.json does not exist in the game directory!') + return + + # Read deletefiles.txt and delete the specified files + with open(delete_files_path, 'r') as delete_files: + for file in delete_files.read().split('\n'): + if len(file) < 1: + continue + file_path = os.path.join(game_folder, file) + if os.path.exists(file_path): + log_output(f'Deleting {file_path}') + os.remove(file_path) + + # Check if hpatchz is available in the system path + hzpatchz = os.path.join(current_dir, 'hpatchz.exe') + if not os.path.exists(hzpatchz): + folder_button.configure(state=ctk.NORMAL) + log_output(f"HDiffPatch not found in the current directory ({current_dir})!\nPlease make sure hpatchz.exe is in the same folder as the script.") + return + + # Read hdiffmap.json + with open(hdiff_map_path, 'r') as hdiff_json: + data = json.load(hdiff_json) + + total_patches = len(data['diff_map']) + progress_bar.set(0) + + # Apply patches + for i, entry in enumerate(data['diff_map']): + source_file_name = os.path.join(game_folder, entry['source_file_name']) + patch_file_name = os.path.join(game_folder, entry['patch_file_name']) + target_file_name = os.path.join(game_folder, entry['target_file_name']) + + # Check if files exist + if not os.path.exists(source_file_name): + log_output(f"Source file missing: {source_file_name}") + continue + if not os.path.exists(patch_file_name): + log_output(f"Patch file missing: {patch_file_name}") + continue + + log_output(f"Applying patch: {patch_file_name} -> {target_file_name} using {source_file_name}") + subprocess.run([hzpatchz, source_file_name, patch_file_name, target_file_name]) + + # Update progress bar + progress_percentage = float((i + 1) / total_patches) + progress_bar.set(progress_percentage) + app.update_idletasks() + + log_output("Patch application complete.") + + folder_button.configure(state=ctk.NORMAL) + +def log_output(message): + """Log the output in the Text widget.""" + output_text.configure(state=ctk.NORMAL) + output_text.insert(ctk.END, message + "\n\n") + output_text.yview(ctk.END) + output_text.configure(state=ctk.DISABLED) + +app.mainloop() diff --git a/output/FireflyHdiffTool.exe b/output/FireflyHdiffTool.exe new file mode 100644 index 0000000..e263284 Binary files /dev/null and b/output/FireflyHdiffTool.exe differ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..3477701 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +customtkinter