Python Forum
RimWorld Save Game Manager- Help!
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
RimWorld Save Game Manager- Help!
#1
Hello, I was writing a script for a program to help me and my family on the computer with our RimWorld saves. We all share the computer and I am the only one who knows or has any scripting knowledge so I am trying to make a user friendly program that we can all use even the younger ones (12-14) and it be simple enough. So far everyone understands how to use the features from the first version. I have wrote a really nice second version but the file system isn't actually handling the appropriate actions. It doesn't move all the .RWS files to the folder appropriately but says that they have been moved..

Reddit Note: To Anyone coming here from Reddit to help, yes this is ASolidWorker and my script and code was not ripped from this post, it is my own work. Thank you.

Here is the script that functions properly that everyone is using currently.

import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import os
import shutil
import json

class GameSaveManagerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("RWSG File Manager")

        self.current_folder = None
        self.save_root_folder = None
        self.file_structure = {}

        self.create_widgets()
        self.load_settings()

    def create_widgets(self):
        self.label_selected_folder = tk.Label(self.root, text="")
        self.label_selected_folder.pack()

        self.btn_open_folder = tk.Button(self.root, text="Open Folder", command=self.open_folder_dialog)
        self.btn_open_folder.pack()

        self.btn_move_saves = tk.Button(self.root, text="Move Saves to Folder", command=self.move_saves_to_folder)
        self.btn_move_saves.pack()

        self.btn_restore_files = tk.Button(self.root, text="Restore Files to Original Folders", command=self.restore_files_to_original_folders)
        self.btn_restore_files.pack()

        self.btn_cleanup_saves = tk.Button(self.root, text="Cleanup Saves", command=self.cleanup_saves)
        self.btn_cleanup_saves.pack()

        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)

    def open_folder_dialog(self):
        folder_path = filedialog.askdirectory()
        if folder_path:
            self.current_folder = folder_path
            self.label_selected_folder.config(text=f"Selected Folder: {folder_path}")

    def move_saves_to_folder(self):
        if not self.save_root_folder:
            self.save_root_folder = filedialog.askdirectory(title="Select RimWorld Save Root Folder")
            if not self.save_root_folder:
                return
            self.save_settings()

        if not self.current_folder:
            messagebox.showwarning("Warning", "Please select a folder first.")
            return

        try:
            self.file_structure = {}
            for root, dirs, files in os.walk(self.current_folder):
                for file in files:
                    source_path = os.path.join(root, file)
                    destination_path = os.path.join(self.save_root_folder, file)
                    if source_path != destination_path:
                        shutil.move(source_path, destination_path)
                        self.file_structure[file] = root
            self.save_settings()
            messagebox.showinfo("Success", "Files moved to RimWorld save folder successfully.")
        except Exception as e:
            messagebox.showerror("Error", f"Failed to move files: {str(e)}")

    def restore_files_to_original_folders(self):
        if not self.file_structure:
            messagebox.showwarning("Warning", "No file structure information available.")
            return

        try:
            for file, original_folder in self.file_structure.items():
                source_path = os.path.join(self.save_root_folder, file)
                destination_path = os.path.join(original_folder, file)
                if source_path != destination_path:
                    shutil.move(source_path, destination_path)
            messagebox.showinfo("Success", "Files restored to their original folders successfully.")
        except Exception as e:
            messagebox.showerror("Error", f"Failed to restore files: {str(e)}")

    def cleanup_saves(self):
        folder_path = filedialog.askdirectory(title="Select Folder to Cleanup")
        if not folder_path:
            return

        deleted_files = 0
        try:
            for root, dirs, files in os.walk(folder_path):
                for file in files:
                    if '#§#' in file:
                        os.remove(os.path.join(root, file))
                        deleted_files += 1
            messagebox.showinfo("Cleanup Complete", f"Deleted {deleted_files} files with '#§#' in the name.")
        except Exception as e:
            messagebox.showerror("Error", f"Failed to clean up saves: {str(e)}")

    def save_settings(self):
        settings = {
            'current_folder': self.current_folder,
            'save_root_folder': self.save_root_folder,
            'file_structure': self.file_structure
        }
        with open('settings.json', 'w') as f:
            json.dump(settings, f)

    def load_settings(self):
        try:
            with open('settings.json', 'r') as f:
                settings = json.load(f)
                self.current_folder = settings.get('current_folder')
                self.save_root_folder = settings.get('save_root_folder')
                self.file_structure = settings.get('file_structure', {})
                if self.current_folder:
                    self.label_selected_folder.config(text=f"Selected Folder: {self.current_folder}")
        except FileNotFoundError:
            pass

    def on_closing(self):
        self.save_settings()
        self.root.destroy()

if __name__ == "__main__":
    root = tk.Tk()
    app = GameSaveManagerApp(root)
    root.mainloop()
Here is the updated python script that I am having problems with and is not properly doing the actual moving of the files but the interface seems to function properly.. I was working on this really late and probably got sleepy, I have looked over it today and just can't seem to find the problem.. Maybe fresh eyes will help. Thank you to anyone willing to take their personal time to help me with our crazy RimWorld nonsense xP

import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import os
import shutil
import json

class GameSaveManagerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("RWSG File Manager")
        self.root.geometry("600x210")
        self.root.resizable(False, False)  # Make the window non-resizable

        self.personal_saves_folder = None
        self.save_root_folder = None
        self.file_structure = {}
        self.move_completed = False
        self.pop_up_dsaves = False
        self.pop_up_psaves = False

        self.create_widgets()
        self.load_settings()
        self.update_button_states()  # Initialize button states based on settings

    def create_widgets(self):
        self.label_selected_folder = tk.Label(self.root, text="")
        self.label_selected_folder.pack()

        self.btn_select_folder = tk.Button(self.root, text="Select Your Folder", command=self.open_folder_dialog)
        self.btn_select_folder.pack()
        self.create_tooltip(self.btn_select_folder, "This is where you select the personal folder of the user who is going to play this session. This is the folder you keep your .RWS saved games in while anyone other than you is playing. You can have multiple folders inside your personal folder and the program will keep track of this and remember the place of all your saves and keep its organization when they get moved back.")

        self.btn_move_saves = tk.Button(self.root, text="Move .RWS Files", command=self.move_saves_to_folder, state=tk.DISABLED)
        self.btn_move_saves.pack()
        self.create_tooltip(self.btn_move_saves, "Move any .RWS files from inside the personal folder selected and all of its sub-directories to the default RimWorld Saves Folder you selected.")

        self.btn_restore_files = tk.Button(self.root, text="Restore .RWS Files", command=self.restore_files_to_original_folders, state=tk.DISABLED)
        self.btn_restore_files.pack()

        self.btn_cleanup_saves = tk.Button(self.root, text="Cleanup Saves", command=self.cleanup_saves)
        self.btn_cleanup_saves.pack()

        self.tooltip_label = tk.Label(self.root, text="", wraplength=580, justify=tk.LEFT)
        self.tooltip_label.pack(side=tk.BOTTOM, fill=tk.X, padx=10, pady=10)

        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)

    def create_tooltip(self, widget, text):
        def enter(event):
            self.tooltip_label.config(text=text)

        def leave(event):
            self.tooltip_label.config(text="")

        widget.bind("<Enter>", enter)
        widget.bind("<Leave>", leave)

    def open_folder_dialog(self):
        if not self.pop_up_dsaves:
            messagebox.showinfo("Select Folder", "Please find the default saves folder. This is the folder that the save game files are saved to by default when you save a game inside of RimWorld.")
            self.save_root_folder = filedialog.askdirectory(title="Find Your Default RimWorld Save Folder")
            self.pop_up_dsaves = True
            self.save_settings()
            if not self.save_root_folder:
                self.pop_up_dsaves = False  # Reset if user cancels
                return

        if not self.pop_up_psaves:
            messagebox.showinfo("Select Folder", "Please find your personal saves folder. This is the folder that you keep all of your .RWS files in when a friend or family member is playing RimWorld. It can contain many other folders inside of it for example. In the RimWorld Saves default directory you could have your own folders inside named whatever you want i.e: 'User 1', 'User 2' and within those folders you can have all of your personal game saves for each user and they can each be organized however the user wants. The program remembers this information within the settings file. If something ever goes wrong make sure all .RWS files are back in their own personal folders making sure the Default Save folder is empty. Then delete the settings file and run the program again as if it is running for the first time. Now, please select your personal saves folder.")
            self.personal_saves_folder = filedialog.askdirectory(title="Select Your Personal Saves Folder")
            self.pop_up_psaves = True
            self.save_settings()
            if not self.personal_saves_folder:
                self.pop_up_psaves = False  # Reset if user cancels
                return

        if self.personal_saves_folder:
            self.label_selected_folder.config(text=f"Selected Folder: {self.personal_saves_folder}")
            self.update_button_states()

    def move_saves_to_folder(self):
        if not self.personal_saves_folder or not self.save_root_folder:
            messagebox.showwarning("Warning", "Please select the personal folder and RimWorld saves folder first.")
            return

        try:
            self.file_structure = {}
            for root, dirs, files in os.walk(self.personal_saves_folder):
                for file in files:
                    if file.endswith(".RWS"):
                        source_path = os.path.join(root, file)
                        destination_path = os.path.join(self.save_root_folder, file)
                        if source_path != destination_path:
                            shutil.move(source_path, destination_path)
                            self.file_structure[file] = root
                            print(f"Moved: {source_path} to {destination_path}")  # Debugging statement
            self.move_completed = True
            self.save_settings()
            self.update_button_states()
            messagebox.showinfo("Success", "Files moved to RimWorld save folder successfully.")
        except Exception as e:
            messagebox.showerror("Error", f"Failed to move files: {str(e)}")

    def restore_files_to_original_folders(self):
        if not self.file_structure:
            messagebox.showwarning("Warning", "No file structure information available.")
            return

        try:
            for file, original_folder in self.file_structure.items():
                source_path = os.path.join(self.save_root_folder, file)
                destination_path = os.path.join(original_folder, file)
                if source_path != destination_path:
                    shutil.move(source_path, destination_path)
                    print(f"Restored: {source_path} to {destination_path}")  # Debugging statement
            self.move_completed = False
            self.save_settings()
            self.update_button_states()
            messagebox.showinfo("Success", "Files restored to their original folders successfully.")
        except Exception as e:
            messagebox.showerror("Error", f"Failed to restore files: {str(e)}")

    def cleanup_saves(self):
        folder_path = filedialog.askdirectory(title="Select Folder to Cleanup")
        if not folder_path:
            return

        deleted_files = 0
        try:
            for root, dirs, files in os.walk(folder_path):
                for file in files:
                    if '#§#' in file:
                        os.remove(os.path.join(root, file))
                        deleted_files += 1
            messagebox.showinfo("Cleanup Complete", f"Deleted {deleted_files} files with '#§#' in the name.")
        except Exception as e:
            messagebox.showerror("Error", f"Failed to clean up saves: {str(e)}")

    def update_button_states(self):
        if self.pop_up_dsaves and self.pop_up_psaves and self.personal_saves_folder:
            self.btn_move_saves.config(state=tk.NORMAL)
        else:
            self.btn_move_saves.config(state=tk.DISABLED)

        if self.move_completed:
            self.btn_move_saves.config(state=tk.DISABLED)
            self.btn_restore_files.config(state=tk.NORMAL)
            self.btn_select_folder.config(state=tk.DISABLED)
        else:
            self.btn_restore_files.config(state=tk.DISABLED)
            self.btn_select_folder.config(state=tk.NORMAL)
        self.save_settings()

    def save_settings(self):
        settings = {
            'personal_saves_folder': self.personal_saves_folder,
            'save_root_folder': self.save_root_folder,
            'file_structure': self.file_structure,
            'move_completed': self.move_completed,
            'pop_up_dsaves': self.pop_up_dsaves,
            'pop_up_psaves': self.pop_up_psaves
        }
        with open('settings.json', 'w') as f:
            json.dump(settings, f)

    def load_settings(self):
        try:
            with open('settings.json', 'r') as f:
                settings = json.load(f)
                self.personal_saves_folder = settings.get('personal_saves_folder')
                self.save_root_folder = settings.get('save_root_folder')
                self.file_structure = settings.get('file_structure', {})
                self.move_completed = settings.get('move_completed', False)
                self.pop_up_dsaves = settings.get('pop_up_dsaves', False)
                self.pop_up_psaves = settings.get('pop_up_psaves', False)
                if self.personal_saves_folder:
                    self.label_selected_folder.config(text=f"Selected Folder: {self.personal_saves_folder}")
                self.update_button_states()
        except FileNotFoundError:
            pass

    def on_closing(self):
        self.save_settings()
        self.root.destroy()

if __name__ == "__main__":
    root = tk.Tk()
    app = GameSaveManagerApp(root)
    root.mainloop()
Run both scripts to get an idea of what has changed between the interface. Also if you have RimWorld on your computer you can just run the software and bug test it yourself if you have coding knowledge and want to see what is up and how it works yourself. Besides that, if you make your own files with the .RWS extension then you can just select your own two folders for the software and it will work the same way for a coder testing it on their computer in a test environment without RimWorld being on the computer.. Just take a notepad file and save it as, change from text-document to all files and save it as file_name.rws and it will allow the program to function for you as if the files are RimWorld Saves and you can see how the program functions yourself.
Reply
#2
(Jul-27-2024, 09:44 PM)LastStopDEVS Wrote: Here is the updated python script that I am having problems with and is not properly doing the actual moving of the files but the interface seems to function properly..
What is the program doing and what should it do instead? Can you give an example of a populated personal folder and a saves folder and describe the actions that you do with the buttons and their actual result and the result that you are expecting? It would help if we could reproduce the bug.
« We can solve any problem by introducing an extra level of indirection »
Reply
#3
Sure thing, I will have to get on tomorrow and setup a good description for you guys. Thanks for the input and willingness to help.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  how to save to multiple locations during save cubangt 1 1,309 Oct-23-2023, 10:16 PM
Last Post: deanhystad
  How do I make a game save? BliepMonster 6 2,788 Oct-09-2022, 08:59 AM
Last Post: Gribouillis
  How to create an app manager _ShevaKadu 8 5,460 Nov-01-2020, 12:47 PM
Last Post: _ShevaKadu
  Context Manager (with) wyattbiker 3 4,802 Jul-23-2018, 03:19 PM
Last Post: snippsat

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020