From 0bf96b212b603505ad0c4bf3ecebd975134c94c7 Mon Sep 17 00:00:00 2001 From: ryan-mangeno Date: Sat, 4 Jul 2026 14:36:39 -0700 Subject: [PATCH] macos throttle bug, fixed 99% cpu usage and stabilized at ~50%, also fixed save paths --- .gitignore | 14 ++++++++- src/modules/FrontEnd/AnimationMgr.py | 42 ++++++++++++-------------- src/modules/FrontEnd/CanvasMgr.py | 7 ++--- src/modules/FrontEnd/FrontEnd.py | 2 +- src/modules/FrontEnd/ImageButton.py | 27 ++++++++++++----- src/modules/FrontEnd/TextureMgr.py | 31 +++++++++++++------ src/modules/GameManager/FileManager.py | 5 ++- src/modules/load_elements.py | 11 +------ 8 files changed, 79 insertions(+), 60 deletions(-) diff --git a/.gitignore b/.gitignore index 3b0e8eb..5f991d6 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,16 @@ src/run.dist.zip /src/run.dist src/TOTKOptimizer.ini TOTKOptimizer.ini -NX Optimizer.AppImage \ No newline at end of file +NX Optimizer.AppImage +# build/runtime +.venv/ +build/ +dist/ +Extracted Files/ +.DS_Store +__pycache__/ +*.pyc +*.pyo +.idea/ +.vscode/ +*.log diff --git a/src/modules/FrontEnd/AnimationMgr.py b/src/modules/FrontEnd/AnimationMgr.py index 0ceb09f..9a0412d 100644 --- a/src/modules/FrontEnd/AnimationMgr.py +++ b/src/modules/FrontEnd/AnimationMgr.py @@ -1,42 +1,38 @@ -import threading -from time import sleep from modules.logger import log from collections import deque +_INTERVAL_MS = 400 + class AnimationQueue: isInit: bool = False queue = deque() - - __running: bool = True - __lock = threading.Lock() + _master = None @classmethod - def Initialize(cls): - + def Initialize(cls, master): log.warning("Initialize AnimationQueue") - if cls.isInit: raise ("Already Initialized.") - - thread = threading.Thread(name="AnimationQueue", target=cls.UpdateQueue) - thread.daemon = True - thread.start() + cls._master = master + cls._schedule() cls.isInit = True @classmethod def AddToQueue(cls, func): - with cls.__lock: - cls.queue.append(func) + cls.queue.append(func) @classmethod - def UpdateQueue(cls): - while cls.__running: - with cls.__lock: - if len(cls.queue) > 0: - queue = cls.queue.copy() - - for func in queue: - func() + def _schedule(cls): + cls._master.after(_INTERVAL_MS, cls._tick) - sleep(0.15) + @classmethod + def _tick(cls): + if not cls.queue: + cls._schedule() + return + + for func in cls.queue: + func() + + cls._schedule() diff --git a/src/modules/FrontEnd/CanvasMgr.py b/src/modules/FrontEnd/CanvasMgr.py index c5bac25..b6c35fd 100644 --- a/src/modules/FrontEnd/CanvasMgr.py +++ b/src/modules/FrontEnd/CanvasMgr.py @@ -1,5 +1,5 @@ from modules.FrontEnd.ImageButton import * -from PIL import Image, ImageTk, ImageFilter, ImageOps +from PIL import Image as PILImage, ImageTk, ImageFilter, ImageOps from idlelib.tooltip import Hovertip from tkinter import * from configuration.settings import * @@ -257,13 +257,11 @@ def custom_command(): new_variable.trace_add("write", lambda *args: custom_command()) - # create scale box scale_box = ttk.Scale( master=master, from_=scale_from, to=scale_to, - command=lambda e: custom_command(), length=width, style=style, variable=new_variable, @@ -708,7 +706,6 @@ def show_tooltip( x += canvas.winfo_rootx() y += canvas.winfo_rooty() - master.after(50) cls.tooltip = Tk.Toplevel(master=master) cls.tooltip.wm_overrideredirect(True) cls.tooltip.geometry(f"+{x + scale(20)}+{y + scale(25)}") @@ -785,7 +782,7 @@ def Photo_Image( ) -> PhotoImage: UI_path = cls.get_UI_path(image_path) - image = ttk.Image.open(UI_path) + image = PILImage.open(UI_path) if isinstance(img_scale, int) or isinstance(img_scale, float): width = int(width * img_scale) height = int(height * img_scale) diff --git a/src/modules/FrontEnd/FrontEnd.py b/src/modules/FrontEnd/FrontEnd.py index 559e7eb..7021352 100644 --- a/src/modules/FrontEnd/FrontEnd.py +++ b/src/modules/FrontEnd/FrontEnd.py @@ -68,7 +68,7 @@ def __init__(Manager, window): Game_Manager.LoadPatches() FileManager.Initialize(window, Manager) TextureMgr.Initialize() # load all images. - AnimationQueue.Initialize() + AnimationQueue.Initialize(window) Manager.patches = Game_Manager.GetPatches() # Emulator Scaling diff --git a/src/modules/FrontEnd/ImageButton.py b/src/modules/FrontEnd/ImageButton.py index 26cb02d..c9180b2 100644 --- a/src/modules/FrontEnd/ImageButton.py +++ b/src/modules/FrontEnd/ImageButton.py @@ -145,14 +145,27 @@ def AddAnimationToQueue(self): def Animation(self): try: - if self.__IsHovering is False: + if not self.__IsHovering: + return + + if not self._Images: return - if self.__AniIndex + 1 > len(self._Images): - self.__AniIndex = 1 - - self._Canvas.itemconfig(self.Tag, image=self._Images[self.__AniIndex]) - - self.__AniIndex += 1 + if hasattr(self, "_last_drawn_index"): + if self.__AniIndex == self._last_drawn_index: + return + + next_index = self.__AniIndex +1 + if next_index > len(self._Images): + next_index = 0 + + self._Canvas.itemconfig( + self.Tag, + image=self._Images(self.__AniIndex) + ) + + self._last_drawn_index = self.__AniIndex + self.__AniIndex = next_index + except Exception: pass diff --git a/src/modules/FrontEnd/TextureMgr.py b/src/modules/FrontEnd/TextureMgr.py index d13643d..9d788c3 100644 --- a/src/modules/FrontEnd/TextureMgr.py +++ b/src/modules/FrontEnd/TextureMgr.py @@ -1,4 +1,4 @@ -from PIL import ImageTk +from PIL import Image as PILImage, ImageTk from modules.FrontEnd.CanvasMgr import Canvas_Create @@ -28,6 +28,22 @@ def Request(cls, Name: str): raise f"Texture Doesn't exist {Name}" + @classmethod + def CreateCompositeTexture(cls, name, image_paths): + """Precomposite multiple full-canvas RGBA images into one PhotoImage. + Reduces per-frame CoreGraphics RGBA compositing passes on macOS.""" + from modules.scaling import sf + w, h = int(1200 * sf), int(600 * sf) + base = PILImage.new("RGBA", (w, h), (0, 0, 0, 0)) + for path in image_paths: + full_path = Canvas_Create.get_UI_path(path) + img = PILImage.open(full_path).resize((w, h), PILImage.LANCZOS) + if img.mode != "RGBA": + img = img.convert("RGBA") + base = PILImage.alpha_composite(base, img) + photo = ImageTk.PhotoImage(base) + cls.AppendTexture(Texture(name, photo)) + @classmethod def CreateTexture( cls, @@ -191,10 +207,10 @@ def Initialize(cls): width=int(72 * 1.2), height=int(114 * 1.2), ) - TextureMgr.CreateTexture( - image_path="BG_Left_2.png", - width=1200, - height=600, + # ponytail: precomposite static overlays → 1 RGBA pass/frame instead of 2 + TextureMgr.CreateCompositeTexture( + "ui_static_overlay", + ["BG_Left_2.png", "BG_Right_UI.png"], ) TextureMgr.CreateTexture( image_path="BG_Left_Cheats.png", @@ -206,11 +222,6 @@ def Initialize(cls): width=1200, height=600, ) - TextureMgr.CreateTexture( - image_path="BG_Right_UI.png", - width=1200, - height=600, - ) TextureMgr.CreateTexture( image_path="browse.png", width=int(115 * 0.8), diff --git a/src/modules/GameManager/FileManager.py b/src/modules/GameManager/FileManager.py index ba438b2..d883ef7 100644 --- a/src/modules/GameManager/FileManager.py +++ b/src/modules/GameManager/FileManager.py @@ -16,7 +16,6 @@ from run_config import __ROOT__ - class FileManager: _window: ttk.Window = None @@ -221,7 +220,7 @@ def __TransferMods(filemgr): os.makedirs(destination, exist_ok=True) shutil.copytree(source, destination, dirs_exist_ok=True) else: - destination = os.path.join(os.getcwd(), "Extracted Files", patchinfo.ModName) + destination = os.path.join(__ROOT__, "Extracted Files", patchinfo.ModName) os.makedirs(destination, exist_ok=True) shutil.copytree(source, destination, dirs_exist_ok=True) @@ -346,7 +345,7 @@ def UltraCam_ConfigPath(filemgr) -> str: SdCard = filemgr.sdmc if filemgr.is_extracting is True: - Folder = os.path.join(os.getcwd(), "Extracted Files") + Folder = os.path.join(__ROOT__, "Extracted Files") os.makedirs(Folder, exist_ok=True) return os.path.join(Folder, PatchInfo.ModName, PatchInfo.ConfigPath) if PatchInfo.isSDconfig is True: diff --git a/src/modules/load_elements.py b/src/modules/load_elements.py index 8ac0b80..7175961 100644 --- a/src/modules/load_elements.py +++ b/src/modules/load_elements.py @@ -23,16 +23,7 @@ def load_UI_elements(manager, canvas: ttk.Canvas): ) canvas.create_image( - 0, 0, anchor="nw", image=TextureMgr.Request("BG_Left_2.png"), tags="overlay" - ) - - # Benchmark Window. - canvas.create_image( - 0 - scale(20), - 0, - anchor="nw", - image=TextureMgr.Request("BG_Right_UI.png"), - tags="overlay", + 0, 0, anchor="nw", image=TextureMgr.Request("ui_static_overlay"), tags="overlay" ) Offset = 255