From 1b28b599e51c54ae37d4f1635e482f90571ed112 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Mon, 30 May 2022 10:52:05 -0700 Subject: [PATCH 1/9] removed iml file --- .gitignore | 1 + Auto Maple.iml | 9 --------- 2 files changed, 1 insertion(+), 9 deletions(-) delete mode 100644 Auto Maple.iml diff --git a/.gitignore b/.gitignore index 885f5509..d9f79556 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ __pycache__/ assets/models/ .idea/ .settings/ +*.iml diff --git a/Auto Maple.iml b/Auto Maple.iml deleted file mode 100644 index ad3c0a36..00000000 --- a/Auto Maple.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file From 147b2240ccae94179a419c6f6af0ac8534eb3988 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Fri, 3 Jun 2022 21:45:59 -0700 Subject: [PATCH 2/9] correctly saves Configurable even when new keybinds (dict keys) are added --- resources | 2 +- src/common/interfaces.py | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/resources b/resources index af45bb34..c71cd389 160000 --- a/resources +++ b/resources @@ -1 +1 @@ -Subproject commit af45bb34da12e672b1a230c0de464461ea42729a +Subproject commit c71cd389079ef7d99b1e03f3438ad33895059533 diff --git a/src/common/interfaces.py b/src/common/interfaces.py index ba833aa9..05307941 100644 --- a/src/common/interfaces.py +++ b/src/common/interfaces.py @@ -1,30 +1,32 @@ import os import pickle -SETTINGS_DIR = '.settings' - class Configurable: TARGET = 'default_configurable' + DIRECTORY = '.settings' DEFAULT_CONFIG = { 'Default configuration': 'None' } - def __init__(self, target): + def __init__(self, target, directory='.settings'): + assert self.DEFAULT_CONFIG != Configurable.DEFAULT_CONFIG, 'Must override Configurable.DEFAULT_CONFIG' self.TARGET = target - self.config = self.DEFAULT_CONFIG.copy() + self.DIRECTORY = directory + self.config = self.DEFAULT_CONFIG.copy() # Shallow copy, should only contain primitives self.load_config() def load_config(self): - path = os.path.join(SETTINGS_DIR, self.TARGET) + path = os.path.join(self.DIRECTORY, self.TARGET) if os.path.isfile(path): with open(path, 'rb') as file: - self.config = pickle.load(file) + loaded = pickle.load(file) + self.config = {key: loaded.get(key, '') for key in self.DEFAULT_CONFIG} else: self.save_config() def save_config(self): - path = os.path.join(SETTINGS_DIR, self.TARGET) + path = os.path.join(self.DIRECTORY, self.TARGET) directory = os.path.dirname(path) if not os.path.exists(directory): os.makedirs(directory) From 8017c6973c9237f7958d9e92d0d44f96a511b548 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Fri, 3 Jun 2022 21:56:24 -0700 Subject: [PATCH 3/9] moved keybindings to gui interfaces --- src/common/interfaces.py | 2 +- src/gui/interfaces.py | 129 +++++++++++++++++++++++++++++++ src/gui/settings/keybindings.py | 131 -------------------------------- src/gui/settings/main.py | 2 +- 4 files changed, 131 insertions(+), 133 deletions(-) delete mode 100644 src/gui/settings/keybindings.py diff --git a/src/common/interfaces.py b/src/common/interfaces.py index 05307941..047d6c7d 100644 --- a/src/common/interfaces.py +++ b/src/common/interfaces.py @@ -5,7 +5,7 @@ class Configurable: TARGET = 'default_configurable' DIRECTORY = '.settings' - DEFAULT_CONFIG = { + DEFAULT_CONFIG = { # Must be overridden by subclass 'Default configuration': 'None' } diff --git a/src/gui/interfaces.py b/src/gui/interfaces.py index dbbfc152..d0964b27 100644 --- a/src/gui/interfaces.py +++ b/src/gui/interfaces.py @@ -1,7 +1,10 @@ """Interfaces that are used by various GUI pages.""" import tkinter as tk +import keyboard as kb from tkinter import ttk +from src.common import utils +from src.common.interfaces import Configurable class Frame(tk.Frame): @@ -28,3 +31,129 @@ class MenuBarItem(tk.Menu): def __init__(self, parent, label, **kwargs): super().__init__(parent, **kwargs) parent.add_cascade(label=label, menu=self) + + +class KeyBindings(LabelFrame): + def __init__(self, parent, label, target, **kwargs): + super().__init__(parent, label, **kwargs) + assert isinstance(target, Configurable) + self.target = target + + self.columnconfigure(0, minsize=300) + + self.displays = {} # Holds each action's display variable + self.forward = {} # Maps actions to keys + self.backward = {} # Maps keys to actions + self.prev_a = '' + self.prev_k = '' + + self.contents = None + self.create_edit_ui() + + def create_edit_ui(self): + self.displays = {} + self.forward = {} + self.backward = {} + self.prev_a = '' + self.prev_k = '' + + self.contents = Frame(self) + self.contents.grid(row=0, column=0, sticky=tk.NSEW, padx=5, pady=5) + + if self.target is not None: # For when running GUI only + for action, key in self.target.config.items(): + self.forward[action] = key + self.backward[key] = action + self.create_entry(action, key) + self.focus() + else: + self.create_disabled_entry() + + reset = tk.Button(self.contents, text='Reset', command=self.refresh_edit_ui, takefocus=False) + reset.pack(side=tk.LEFT, pady=5) + + save = tk.Button(self.contents, text='Save', command=self.save, takefocus=False) + save.pack(side=tk.RIGHT, pady=5) + + def refresh_edit_ui(self): + self.contents.destroy() + self.create_edit_ui() + + @utils.run_if_disabled('\n[!] Cannot save key bindings while Auto Maple is enabled') + def save(self): + utils.print_separator() + print(f"[~] Saving key bindings to '{self.target.TARGET}':") + + failures = 0 + for action, key in self.forward.items(): + if key != '': + self.target.config[action] = key + else: + print(f" ! Action '{action}' was not bound to a key") + failures += 1 + + self.target.save_config() + if failures == 0: + print(' ~ Successfully saved all key bindings') + else: + print(f' ~ Successfully saved all except for {failures} key bindings') + self.create_edit_ui() + + def create_entry(self, action, key): + """ + Creates an input row for a single key bind. ACTION is assigned to KEY. + """ + + display_var = tk.StringVar(value=key) + self.displays[action] = display_var + + row = Frame(self.contents, highlightthickness=0) + row.pack(expand=True, fill='x') + + label = tk.Entry(row) + label.grid(row=0, column=0, sticky=tk.EW) + label.insert(0, action) + label.config(state=tk.DISABLED) + + def on_key_press(_): + k = kb.read_key() + if action != self.prev_a: + self.prev_k = '' + self.prev_a = action + if k != self.prev_k: + prev_key = self.forward[action] + self.backward.pop(prev_key, None) + if k in self.backward: + prev_action = self.backward[k] + self.forward[prev_action] = '' + self.displays[prev_action].set('') + display_var.set(k) + self.forward[action] = k + self.backward[k] = action + self.prev_k = k + + def validate(d): + """Blocks user insertion, but allows StringVar set().""" + + if d == '-1': + return True + return False + + reg = (self.register(validate), '%d') + entry = tk.Entry(row, textvariable=display_var, + validate='key', validatecommand=reg, + takefocus=False) + entry.bind('', on_key_press) + entry.grid(row=0, column=1, sticky=tk.EW) + + def create_disabled_entry(self): + row = Frame(self.contents, highlightthickness=0) + row.pack(expand=True, fill='x') + + label = tk.Entry(row) + label.grid(row=0, column=0, sticky=tk.EW) + label.config(state=tk.DISABLED) + + entry = tk.Entry(row) + entry.grid(row=0, column=1, sticky=tk.EW) + entry.config(state=tk.DISABLED) diff --git a/src/gui/settings/keybindings.py b/src/gui/settings/keybindings.py deleted file mode 100644 index 1cb27520..00000000 --- a/src/gui/settings/keybindings.py +++ /dev/null @@ -1,131 +0,0 @@ -import tkinter as tk -import keyboard as kb -from src.gui.interfaces import LabelFrame, Frame -from src.common import utils -from src.common.interfaces import Configurable - - -class KeyBindings(LabelFrame): - def __init__(self, parent, label, target, **kwargs): - super().__init__(parent, label, **kwargs) - assert isinstance(target, Configurable) - self.target = target - - self.columnconfigure(0, minsize=300) - - self.displays = {} # Holds each action's display variable - self.forward = {} # Maps actions to keys - self.backward = {} # Maps keys to actions - self.prev_a = '' - self.prev_k = '' - - self.contents = None - self.create_edit_ui() - - def create_edit_ui(self): - self.displays = {} - self.forward = {} - self.backward = {} - self.prev_a = '' - self.prev_k = '' - - self.contents = Frame(self) - self.contents.grid(row=0, column=0, sticky=tk.NSEW, padx=5, pady=5) - - if self.target is not None: # For when running GUI only - for action, key in self.target.config.items(): - self.forward[action] = key - self.backward[key] = action - self.create_entry(action, key) - self.focus() - else: - self.create_disabled_entry() - - reset = tk.Button(self.contents, text='Reset', command=self.refresh_edit_ui, takefocus=False) - reset.pack(side=tk.LEFT, pady=5) - - save = tk.Button(self.contents, text='Save', command=self.save, takefocus=False) - save.pack(side=tk.RIGHT, pady=5) - - def refresh_edit_ui(self): - self.contents.destroy() - self.create_edit_ui() - - @utils.run_if_disabled('\n[!] Cannot save key bindings while Auto Maple is enabled') - def save(self): - utils.print_separator() - print(f"[~] Saving key bindings to '{self.target.TARGET}':") - - failures = 0 - for action, key in self.forward.items(): - if key != '': - self.target.config[action] = key - else: - print(f" ! Action '{action}' was not bound to a key") - failures += 1 - - self.target.save_config() - if failures == 0: - print(' ~ Successfully saved all key bindings') - else: - print(f' ~ Successfully saved all except for {failures} key bindings') - self.create_edit_ui() - - def create_entry(self, action, key): - """ - Creates an input row for a single key bind. ACTION is assigned to KEY. - """ - - display_var = tk.StringVar(value=key) - self.displays[action] = display_var - - row = Frame(self.contents, highlightthickness=0) - row.pack(expand=True, fill='x') - - label = tk.Entry(row) - label.grid(row=0, column=0, sticky=tk.EW) - label.insert(0, action) - label.config(state=tk.DISABLED) - - def on_key_press(_): - k = kb.read_key() - if action != self.prev_a: - self.prev_k = '' - self.prev_a = action - if k != self.prev_k: - prev_key = self.forward[action] - self.backward.pop(prev_key, None) - if k in self.backward: - prev_action = self.backward[k] - self.forward[prev_action] = '' - self.displays[prev_action].set('') - display_var.set(k) - self.forward[action] = k - self.backward[k] = action - self.prev_k = k - - def validate(d): - """Blocks user insertion, but allows StringVar set().""" - - if d == '-1': - return True - return False - - reg = (self.register(validate), '%d') - entry = tk.Entry(row, textvariable=display_var, - validate='key', validatecommand=reg, - takefocus=False) - entry.bind('', on_key_press) - entry.grid(row=0, column=1, sticky=tk.EW) - - def create_disabled_entry(self): - row = Frame(self.contents, highlightthickness=0) - row.pack(expand=True, fill='x') - - label = tk.Entry(row) - label.grid(row=0, column=0, sticky=tk.EW) - label.config(state=tk.DISABLED) - - entry = tk.Entry(row) - entry.grid(row=0, column=1, sticky=tk.EW) - entry.config(state=tk.DISABLED) diff --git a/src/gui/settings/main.py b/src/gui/settings/main.py index 2bbd9275..cdc09cce 100644 --- a/src/gui/settings/main.py +++ b/src/gui/settings/main.py @@ -1,7 +1,7 @@ """Displays Auto Maple's current settings and allows the user to edit them.""" import tkinter as tk -from src.gui.settings.keybindings import KeyBindings +from src.gui.interfaces import KeyBindings from src.gui.settings.pets import Pets from src.gui.interfaces import Tab, Frame from src.common import config From 52934ee66944cfcef16ca2fffb2bfcb75c785cda Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Fri, 3 Jun 2022 22:04:19 -0700 Subject: [PATCH 4/9] made room for command book keybinds --- src/gui/settings/main.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/gui/settings/main.py b/src/gui/settings/main.py index cdc09cce..c06bc892 100644 --- a/src/gui/settings/main.py +++ b/src/gui/settings/main.py @@ -18,10 +18,12 @@ def __init__(self, parent, **kwargs): column1.grid(row=0, column=1, sticky=tk.N, padx=10, pady=10) self.controls = KeyBindings(column1, 'Auto Maple Controls', config.listener) self.controls.pack(side=tk.TOP, fill='x', expand=True) + self.key_bindings = KeyBindings(column1, 'In-game Keybindings', config.bot) + self.key_bindings.pack(side=tk.TOP, fill='x', expand=True, pady=(10, 0)) + self.pets = Pets(column1) + self.pets.pack(side=tk.TOP, fill='x', expand=True, pady=(10, 0)) column2 = Frame(self) column2.grid(row=0, column=2, sticky=tk.N, padx=10, pady=10) - self.key_bindings = KeyBindings(column2, 'In-game Keybindings', config.bot) - self.key_bindings.pack(side=tk.TOP, fill='x', expand=True) - self.pets = Pets(column2) - self.pets.pack(side=tk.TOP, fill='x', expand=True, pady=(10, 0)) + + From 4fe8fc4f8256aa2a7703ce9639e27dbce8b2f978 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Fri, 3 Jun 2022 23:16:02 -0700 Subject: [PATCH 5/9] finished CommandBook class, implementing keybind gui --- src/command_book/command_book.py | 112 +++++++++++++ src/command_book/resources/keybindings/kanna | Bin 0 -> 6 bytes src/gui/menu/file.py | 2 +- src/gui/settings/main.py | 10 +- src/modules/bot.py | 161 ++++++++++--------- src/routine/components.py | 2 +- src/routine/layout.py | 2 +- src/routine/routine.py | 2 +- 8 files changed, 205 insertions(+), 86 deletions(-) create mode 100644 src/command_book/command_book.py create mode 100644 src/command_book/resources/keybindings/kanna diff --git a/src/command_book/command_book.py b/src/command_book/command_book.py new file mode 100644 index 00000000..6af608f0 --- /dev/null +++ b/src/command_book/command_book.py @@ -0,0 +1,112 @@ +import os +import inspect +import importlib +import traceback +from os.path import basename, splitext +from src.common import config, utils +from src.routine import components +from src.common.interfaces import Configurable + + +CB_KEYBINDING_DIR = os.path.join('resources', 'keybindings') + + +class CommandBook(Configurable): + def __init__(self, file): + self.name = splitext(basename(file))[0] + self.buff = components.Buff() + self.DEFAULT_CONFIG = {} + self.dict = self.load_commands(file) + if self.dict is None: + raise ValueError(f"Invalid command book at '{file}'") + super().__init__(self.name, directory=CB_KEYBINDING_DIR) + + def load_commands(self, file): + """Prompts the user to select a command module to import. Updates config's command book.""" + + utils.print_separator() + print(f"[~] Loading command book '{basename(file)}':") + + ext = splitext(file)[1] + if ext != '.py': + print(f" ! '{ext}' is not a supported file extension.") + return False + + new_step = components.step + new_cb = {} + for c in (components.Wait, components.Walk, components.Fall): + new_cb[c.__name__.lower()] = c + + # Import the desired command book file + target = '.'.join(['resources', 'command_books', self.name]) + try: + module = importlib.import_module(target) + module = importlib.reload(module) + except ImportError: # Display errors in the target Command Book + print(' ! Errors during compilation:\n') + for line in traceback.format_exc().split('\n'): + line = line.rstrip() + if line: + print(' ' * 4 + line) + print(f"\n ! Command book '{self.name}' was not loaded") + return + + # Load key map + if hasattr(module, 'Key'): + default_config = {} + for key, value in module.Key.__dict__.items(): + if not key.startswith('__') and not key.endswith('__'): + default_config[key] = value + self.DEFAULT_CONFIG = default_config + else: + print(f" ! Error loading command book '{self.name}', keymap class 'Key' is missing") + return + + # Check if the 'step' function has been implemented + step_found = False + for name, func in inspect.getmembers(module, inspect.isfunction): + if name.lower() == 'step': + step_found = True + new_step = func + + # Populate the new command book + for name, command in inspect.getmembers(module, inspect.isclass): + if issubclass(command, components.Command): + new_cb[name.lower()] = command + + # Check if required commands have been implemented and overridden + required_found = True + for command in (components.Buff,): + name = command.__name__.lower() + if name not in new_cb: + required_found = False + new_cb[name] = command + print(f" ! Error: Must implement required command '{name}'.") + + # Look for overridden movement commands + movement_found = True + for command in (components.Move, components.Adjust): + name = command.__name__.lower() + if name not in new_cb: + movement_found = False + new_cb[name] = command + + if not step_found and not movement_found: + print(f" ! Error: Must either implement both 'Move' and 'Adjust' commands, " + f"or the function 'step'") + if required_found and (step_found or movement_found): + self.buff = new_cb['buff']() + components.step = new_step + config.gui.menu.file.enable_routine_state() + config.gui.view.status.set_cb(basename(file)) + config.routine.clear() + print(f" ~ Successfully loaded command book '{self.name}'") + return new_cb + else: + print(f" ! Command book '{self.name}' was not loaded") + + def __getitem__(self, item): + return self.dict[item] + + def __contains__(self, item): + return item in self.dict diff --git a/src/command_book/resources/keybindings/kanna b/src/command_book/resources/keybindings/kanna new file mode 100644 index 0000000000000000000000000000000000000000..c5414f5f556649464cc5ea91f72028df5ec88f1d GIT binary patch literal 6 NcmZo*t}SHH0{{k!0iXZ? literal 0 HcmV?d00001 diff --git a/src/gui/menu/file.py b/src/gui/menu/file.py index d82db545..948181a4 100644 --- a/src/gui/menu/file.py +++ b/src/gui/menu/file.py @@ -87,7 +87,7 @@ def _load_commands(): def get_routines_dir(): - target = os.path.join(config.RESOURCES_DIR, 'routines', config.bot.module_name) + target = os.path.join(config.RESOURCES_DIR, 'routines', config.bot.command_book.name) if not os.path.exists(target): os.makedirs(target) return target diff --git a/src/gui/settings/main.py b/src/gui/settings/main.py index c06bc892..ebd28b90 100644 --- a/src/gui/settings/main.py +++ b/src/gui/settings/main.py @@ -18,12 +18,14 @@ def __init__(self, parent, **kwargs): column1.grid(row=0, column=1, sticky=tk.N, padx=10, pady=10) self.controls = KeyBindings(column1, 'Auto Maple Controls', config.listener) self.controls.pack(side=tk.TOP, fill='x', expand=True) - self.key_bindings = KeyBindings(column1, 'In-game Keybindings', config.bot) - self.key_bindings.pack(side=tk.TOP, fill='x', expand=True, pady=(10, 0)) + self.common_bindings = KeyBindings(column1, 'In-game Keybindings', config.bot) + self.common_bindings.pack(side=tk.TOP, fill='x', expand=True, pady=(10, 0)) self.pets = Pets(column1) self.pets.pack(side=tk.TOP, fill='x', expand=True, pady=(10, 0)) column2 = Frame(self) column2.grid(row=0, column=2, sticky=tk.N, padx=10, pady=10) - - + blank_configurable = + class_name = config.bot.command_book.name.capitalize() + self.class_bindings = KeyBindings(column2, f'No Command Book Selected', config.bot.command_book) + self.class_bindings.pack(side=tk.TOP, fill='x', expand=True) diff --git a/src/modules/bot.py b/src/modules/bot.py index dee47e7c..263ce315 100644 --- a/src/modules/bot.py +++ b/src/modules/bot.py @@ -12,6 +12,7 @@ from src.detection import detection from src.routine import components from src.routine.routine import Routine +from src.command_book.command_book import CommandBook from src.routine.components import Point from src.common.vkeys import press, click from src.common.interfaces import Configurable @@ -39,13 +40,14 @@ def __init__(self): self.rune_pos = (0, 0) self.rune_closest_pos = (0, 0) # Location of the Point closest to rune self.submodules = [] - self.module_name = None - self.buff = components.Buff() + self.command_book = None # CommandBook instance + # self.module_name = None + # self.buff = components.Buff() - self.command_book = {} - for c in (components.Wait, components.Walk, components.Fall, - components.Move, components.Adjust, components.Buff): - self.command_book[c.__name__.lower()] = c + # self.command_book = {} + # for c in (components.Wait, components.Walk, components.Fall, + # components.Move, components.Adjust, components.Buff): + # self.command_book[c.__name__.lower()] = c config.routine = Routine() @@ -79,7 +81,7 @@ def _main(self): while True: if config.enabled and len(config.routine) > 0: # Buff and feed pets - self.buff.main() + self.command_book.buff.main() pet_settings = config.gui.settings.pets auto_feed = pet_settings.auto_feed.get() num_pets = pet_settings.num_pets.get() @@ -149,78 +151,81 @@ def _solve_rune(self, model): inferences.append(solution) def load_commands(self, file): - """Prompts the user to select a command module to import. Updates config's command book.""" - - utils.print_separator() - print(f"[~] Loading command book '{basename(file)}':") - - ext = splitext(file)[1] - if ext != '.py': - print(f" ! '{ext}' is not a supported file extension.") - return False - - new_step = components.step - new_cb = {} - for c in (components.Wait, components.Walk, components.Fall): - new_cb[c.__name__.lower()] = c - - # Import the desired command book file - module_name = splitext(basename(file))[0] - target = '.'.join(['resources', 'command_books', module_name]) try: - module = importlib.import_module(target) - module = importlib.reload(module) - except ImportError: # Display errors in the target Command Book - print(' ! Errors during compilation:\n') - for line in traceback.format_exc().split('\n'): - line = line.rstrip() - if line: - print(' ' * 4 + line) - print(f"\n ! Command book '{module_name}' was not loaded") - return - - # Check if the 'step' function has been implemented - step_found = False - for name, func in inspect.getmembers(module, inspect.isfunction): - if name.lower() == 'step': - step_found = True - new_step = func - - # Populate the new command book - for name, command in inspect.getmembers(module, inspect.isclass): - new_cb[name.lower()] = command - - # Check if required commands have been implemented and overridden - required_found = True - for command in [components.Buff]: - name = command.__name__.lower() - if name not in new_cb: - required_found = False - new_cb[name] = command - print(f" ! Error: Must implement required command '{name}'.") - - # Look for overridden movement commands - movement_found = True - for command in (components.Move, components.Adjust): - name = command.__name__.lower() - if name not in new_cb: - movement_found = False - new_cb[name] = command - - if not step_found and not movement_found: - print(f" ! Error: Must either implement both 'Move' and 'Adjust' commands, " - f"or the function 'step'") - if required_found and (step_found or movement_found): - self.module_name = module_name - self.command_book = new_cb - self.buff = new_cb['buff']() - components.step = new_step - config.gui.menu.file.enable_routine_state() - config.gui.view.status.set_cb(basename(file)) - config.routine.clear() - print(f" ~ Successfully loaded command book '{module_name}'") - else: - print(f" ! Command book '{module_name}' was not loaded") + self.command_book = CommandBook(file) + except ValueError: + pass # TODO: UI warning popup, say check cmd for errors + # + # utils.print_separator() + # print(f"[~] Loading command book '{basename(file)}':") + # + # ext = splitext(file)[1] + # if ext != '.py': + # print(f" ! '{ext}' is not a supported file extension.") + # return False + # + # new_step = components.step + # new_cb = {} + # for c in (components.Wait, components.Walk, components.Fall): + # new_cb[c.__name__.lower()] = c + # + # # Import the desired command book file + # module_name = splitext(basename(file))[0] + # target = '.'.join(['resources', 'command_books', module_name]) + # try: + # module = importlib.import_module(target) + # module = importlib.reload(module) + # except ImportError: # Display errors in the target Command Book + # print(' ! Errors during compilation:\n') + # for line in traceback.format_exc().split('\n'): + # line = line.rstrip() + # if line: + # print(' ' * 4 + line) + # print(f"\n ! Command book '{module_name}' was not loaded") + # return + # + # # Check if the 'step' function has been implemented + # step_found = False + # for name, func in inspect.getmembers(module, inspect.isfunction): + # if name.lower() == 'step': + # step_found = True + # new_step = func + # + # # Populate the new command book + # for name, command in inspect.getmembers(module, inspect.isclass): + # new_cb[name.lower()] = command + # + # # Check if required commands have been implemented and overridden + # required_found = True + # for command in [components.Buff]: + # name = command.__name__.lower() + # if name not in new_cb: + # required_found = False + # new_cb[name] = command + # print(f" ! Error: Must implement required command '{name}'.") + # + # # Look for overridden movement commands + # movement_found = True + # for command in (components.Move, components.Adjust): + # name = command.__name__.lower() + # if name not in new_cb: + # movement_found = False + # new_cb[name] = command + # + # if not step_found and not movement_found: + # print(f" ! Error: Must either implement both 'Move' and 'Adjust' commands, " + # f"or the function 'step'") + # if required_found and (step_found or movement_found): + # self.module_name = module_name + # self.command_book = new_cb + # self.buff = new_cb['buff']() + # components.step = new_step + # config.gui.menu.file.enable_routine_state() + # config.gui.view.status.set_cb(basename(file)) + # config.routine.clear() + # print(f" ~ Successfully loaded command book '{module_name}'") + # else: + # print(f" ! Command book '{module_name}' was not loaded") def update_submodules(self, force=False): """ diff --git a/src/routine/components.py b/src/routine/components.py index 4b4d3456..4bdbb96f 100644 --- a/src/routine/components.py +++ b/src/routine/components.py @@ -81,7 +81,7 @@ def main(self): move = config.bot.command_book['move'] move(*self.location).execute() if self.adjust: - adjust = config.bot.command_book.get('adjust') # TODO: adjust using step('up')? + adjust = config.bot.command_book['adjust'] # TODO: adjust using step('up')? adjust(*self.location).execute() for command in self.commands: command.execute() diff --git a/src/routine/layout.py b/src/routine/layout.py index 8a62c47c..30a794b0 100644 --- a/src/routine/layout.py +++ b/src/routine/layout.py @@ -292,4 +292,4 @@ def save(self): def get_layouts_dir(): - return os.path.join(config.RESOURCES_DIR, 'layouts', config.bot.module_name) + return os.path.join(config.RESOURCES_DIR, 'layouts', config.bot.command_book.name) diff --git a/src/routine/routine.py b/src/routine/routine.py index fc2232a9..84e598cf 100644 --- a/src/routine/routine.py +++ b/src/routine/routine.py @@ -274,7 +274,7 @@ def _eval(self, row, i): def get_all_components(): """Returns a dictionary mapping all creatable Components to their names.""" - options = config.bot.command_book.copy() + options = config.bot.command_book.dict.copy() for e in (Point, Label, Jump, Setting): options[e.__name__.lower()] = e return options From 795ab4b3e6bdfdf7338589148deb75e2a82501d2 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Fri, 3 Jun 2022 23:38:22 -0700 Subject: [PATCH 6/9] keybinds display for both adele and kanna --- src/gui/interfaces.py | 14 +++++++------- src/gui/settings/main.py | 22 +++++++++++++--------- src/modules/bot.py | 1 + 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/gui/interfaces.py b/src/gui/interfaces.py index d0964b27..f6b3d6c9 100644 --- a/src/gui/interfaces.py +++ b/src/gui/interfaces.py @@ -36,7 +36,8 @@ def __init__(self, parent, label, **kwargs): class KeyBindings(LabelFrame): def __init__(self, parent, label, target, **kwargs): super().__init__(parent, label, **kwargs) - assert isinstance(target, Configurable) + if target is not None: + assert isinstance(target, Configurable) self.target = target self.columnconfigure(0, minsize=300) @@ -66,15 +67,14 @@ def create_edit_ui(self): self.backward[key] = action self.create_entry(action, key) self.focus() + + reset = tk.Button(self.contents, text='Reset', command=self.refresh_edit_ui, takefocus=False) + reset.pack(side=tk.LEFT, pady=5) + save = tk.Button(self.contents, text='Save', command=self.save, takefocus=False) + save.pack(side=tk.RIGHT, pady=5) else: self.create_disabled_entry() - reset = tk.Button(self.contents, text='Reset', command=self.refresh_edit_ui, takefocus=False) - reset.pack(side=tk.LEFT, pady=5) - - save = tk.Button(self.contents, text='Save', command=self.save, takefocus=False) - save.pack(side=tk.RIGHT, pady=5) - def refresh_edit_ui(self): self.contents.destroy() self.create_edit_ui() diff --git a/src/gui/settings/main.py b/src/gui/settings/main.py index ebd28b90..f84aaa3e 100644 --- a/src/gui/settings/main.py +++ b/src/gui/settings/main.py @@ -14,18 +14,22 @@ def __init__(self, parent, **kwargs): self.columnconfigure(0, weight=1) self.columnconfigure(3, weight=1) - column1 = Frame(self) - column1.grid(row=0, column=1, sticky=tk.N, padx=10, pady=10) - self.controls = KeyBindings(column1, 'Auto Maple Controls', config.listener) + self.column1 = Frame(self) + self.column1.grid(row=0, column=1, sticky=tk.N, padx=10, pady=10) + self.controls = KeyBindings(self.column1, 'Auto Maple Controls', config.listener) self.controls.pack(side=tk.TOP, fill='x', expand=True) - self.common_bindings = KeyBindings(column1, 'In-game Keybindings', config.bot) + self.common_bindings = KeyBindings(self.column1, 'In-game Keybindings', config.bot) self.common_bindings.pack(side=tk.TOP, fill='x', expand=True, pady=(10, 0)) - self.pets = Pets(column1) + self.pets = Pets(self.column1) self.pets.pack(side=tk.TOP, fill='x', expand=True, pady=(10, 0)) - column2 = Frame(self) - column2.grid(row=0, column=2, sticky=tk.N, padx=10, pady=10) - blank_configurable = + self.column2 = Frame(self) + self.column2.grid(row=0, column=2, sticky=tk.N, padx=10, pady=10) + self.class_bindings = KeyBindings(self.column2, f'No Command Book Selected', None) + self.class_bindings.pack(side=tk.TOP, fill='x', expand=True) + + def update_class_bindings(self): + self.class_bindings.destroy() class_name = config.bot.command_book.name.capitalize() - self.class_bindings = KeyBindings(column2, f'No Command Book Selected', config.bot.command_book) + self.class_bindings = KeyBindings(self.column2, f'{class_name} Keybindings', config.bot.command_book) self.class_bindings.pack(side=tk.TOP, fill='x', expand=True) diff --git a/src/modules/bot.py b/src/modules/bot.py index 263ce315..9e3e4bab 100644 --- a/src/modules/bot.py +++ b/src/modules/bot.py @@ -153,6 +153,7 @@ def _solve_rune(self, model): def load_commands(self, file): try: self.command_book = CommandBook(file) + config.gui.settings.update_class_bindings() except ValueError: pass # TODO: UI warning popup, say check cmd for errors # From 9a65bde87de234066f358a9e950a5dc2d062fdb5 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Sat, 4 Jun 2022 00:42:55 -0700 Subject: [PATCH 7/9] got scrolling to work, save no longer works --- src/gui/interfaces.py | 67 ++++++++++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/src/gui/interfaces.py b/src/gui/interfaces.py index f6b3d6c9..539b65af 100644 --- a/src/gui/interfaces.py +++ b/src/gui/interfaces.py @@ -39,8 +39,7 @@ def __init__(self, parent, label, target, **kwargs): if target is not None: assert isinstance(target, Configurable) self.target = target - - self.columnconfigure(0, minsize=300) + self.long = False self.displays = {} # Holds each action's display variable self.forward = {} # Maps actions to keys @@ -49,6 +48,11 @@ def __init__(self, parent, label, target, **kwargs): self.prev_k = '' self.contents = None + self.container = None + self.canvas = None + self.scrollbar = None + self.reset = None + self.save = None self.create_edit_ui() def create_edit_ui(self): @@ -58,27 +62,56 @@ def create_edit_ui(self): self.prev_a = '' self.prev_k = '' - self.contents = Frame(self) - self.contents.grid(row=0, column=0, sticky=tk.NSEW, padx=5, pady=5) + if self.target is None: + self.contents = Frame(self) + self.create_disabled_entry() + self.contents.pack(side=tk.TOP, fill=tk.BOTH, expand=True, padx=5, pady=5) + return + + if len(self.target.config) > 27: + self.long = True + self.container = Frame(self, width=355, height=650) + self.container.pack(side=tk.TOP, fill=tk.BOTH, expand=True) + self.container.pack_propagate(False) + self.canvas = tk.Canvas(self.container, height=2) + self.scrollbar = tk.Scrollbar(self.container, command=self.canvas.yview) + self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) + self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) + self.contents = Frame(self.canvas) + self.contents.bind( + '', + lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all")) + ) + self.canvas.create_window((0, 0), window=self.contents, anchor=tk.NW) + self.canvas.configure(yscrollcommand=self.scrollbar.set) + else: + self.contents = Frame(self) + self.contents.pack(side=tk.TOP, fill=tk.BOTH, expand=True, padx=5, pady=5) - if self.target is not None: # For when running GUI only - for action, key in self.target.config.items(): - self.forward[action] = key - self.backward[key] = action - self.create_entry(action, key) - self.focus() + for action, key in self.target.config.items(): + self.forward[action] = key + self.backward[key] = action + self.create_entry(action, key) + self.focus() - reset = tk.Button(self.contents, text='Reset', command=self.refresh_edit_ui, takefocus=False) - reset.pack(side=tk.LEFT, pady=5) - save = tk.Button(self.contents, text='Save', command=self.save, takefocus=False) - save.pack(side=tk.RIGHT, pady=5) - else: - self.create_disabled_entry() + self.reset = tk.Button(self, text='Reset', command=self.refresh_edit_ui, takefocus=False) + self.reset.pack(side=tk.LEFT, padx=5, pady=5) + self.save = tk.Button(self, text='Save', command=self.save, takefocus=False) + self.save.pack(side=tk.RIGHT, padx=5, pady=5) def refresh_edit_ui(self): - self.contents.destroy() + self.destroy_contents() self.create_edit_ui() + def destroy_contents(self): + self.contents.destroy() + self.reset.destroy() + self.save.destroy() + if self.long: + self.container.destroy() + self.canvas.destroy() + self.scrollbar.destroy() + @utils.run_if_disabled('\n[!] Cannot save key bindings while Auto Maple is enabled') def save(self): utils.print_separator() From 5133745ef7db0da268e18eea8ba1314a9a121ca8 Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Sat, 4 Jun 2022 01:03:13 -0700 Subject: [PATCH 8/9] fixed keybind save issue --- src/gui/interfaces.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gui/interfaces.py b/src/gui/interfaces.py index 539b65af..d52314f2 100644 --- a/src/gui/interfaces.py +++ b/src/gui/interfaces.py @@ -70,10 +70,10 @@ def create_edit_ui(self): if len(self.target.config) > 27: self.long = True - self.container = Frame(self, width=355, height=650) - self.container.pack(side=tk.TOP, fill=tk.BOTH, expand=True) + self.container = Frame(self, width=354, height=650) + self.container.pack(side=tk.TOP, fill=tk.BOTH, expand=True, padx=(5, 0)) self.container.pack_propagate(False) - self.canvas = tk.Canvas(self.container, height=2) + self.canvas = tk.Canvas(self.container, bd=0, highlightthickness=0) self.scrollbar = tk.Scrollbar(self.container, command=self.canvas.yview) self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) @@ -96,7 +96,7 @@ def create_edit_ui(self): self.reset = tk.Button(self, text='Reset', command=self.refresh_edit_ui, takefocus=False) self.reset.pack(side=tk.LEFT, padx=5, pady=5) - self.save = tk.Button(self, text='Save', command=self.save, takefocus=False) + self.save = tk.Button(self, text='Save', command=self.save_keybindings, takefocus=False) self.save.pack(side=tk.RIGHT, padx=5, pady=5) def refresh_edit_ui(self): @@ -113,7 +113,7 @@ def destroy_contents(self): self.scrollbar.destroy() @utils.run_if_disabled('\n[!] Cannot save key bindings while Auto Maple is enabled') - def save(self): + def save_keybindings(self): utils.print_separator() print(f"[~] Saving key bindings to '{self.target.TARGET}':") @@ -130,7 +130,7 @@ def save(self): print(' ~ Successfully saved all key bindings') else: print(f' ~ Successfully saved all except for {failures} key bindings') - self.create_edit_ui() + self.refresh_edit_ui() def create_entry(self, action, key): """ From db1956e610cf88bcdd2357c3462c7b04041da61c Mon Sep 17 00:00:00 2001 From: Jeffrey Tan Date: Thu, 7 Jul 2022 14:51:00 -0700 Subject: [PATCH 9/9] caught error where match template is larger than the screenshot, keybindings now update module Key namespace --- resources | 2 +- src/command_book/command_book.py | 21 +++++++++++++++++---- src/common/utils.py | 2 ++ src/modules/capture.py | 2 +- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/resources b/resources index c71cd389..92c1c7e3 160000 --- a/resources +++ b/resources @@ -1 +1 @@ -Subproject commit c71cd389079ef7d99b1e03f3438ad33895059533 +Subproject commit 92c1c7e31b2c0d7033661dc8f131d7f75b732f2d diff --git a/src/command_book/command_book.py b/src/command_book/command_book.py index 6af608f0..af721add 100644 --- a/src/command_book/command_book.py +++ b/src/command_book/command_book.py @@ -16,9 +16,10 @@ def __init__(self, file): self.name = splitext(basename(file))[0] self.buff = components.Buff() self.DEFAULT_CONFIG = {} - self.dict = self.load_commands(file) - if self.dict is None: + result = self.load_commands(file) + if result is None: raise ValueError(f"Invalid command book at '{file}'") + self.dict, self.module = result super().__init__(self.name, directory=CB_KEYBINDING_DIR) def load_commands(self, file): @@ -30,7 +31,7 @@ def load_commands(self, file): ext = splitext(file)[1] if ext != '.py': print(f" ! '{ext}' is not a supported file extension.") - return False + return new_step = components.step new_cb = {} @@ -101,7 +102,7 @@ def load_commands(self, file): config.gui.view.status.set_cb(basename(file)) config.routine.clear() print(f" ~ Successfully loaded command book '{self.name}'") - return new_cb + return new_cb, module else: print(f" ! Command book '{self.name}' was not loaded") @@ -110,3 +111,15 @@ def __getitem__(self, item): def __contains__(self, item): return item in self.dict + + def load_config(self): + super().load_config() + self._set_keybinds() + + def save_config(self): + self._set_keybinds() + super().save_config() + + def _set_keybinds(self): + for k, v in self.config.items(): + setattr(self.module.Key, k, v) diff --git a/src/common/utils.py b/src/common/utils.py index 71d9957a..8d01dd10 100644 --- a/src/common/utils.py +++ b/src/common/utils.py @@ -97,6 +97,8 @@ def multi_match(frame, template, threshold=0.95): :return: An array of matches that exceed THRESHOLD. """ + if template.shape[0] > frame.shape[0] or template.shape[1] > frame.shape[1]: + return [] gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) result = cv2.matchTemplate(gray, template, cv2.TM_CCOEFF_NORMED) locations = np.where(result >= threshold) diff --git a/src/modules/capture.py b/src/modules/capture.py index 0d8bf0cf..284e3c49 100644 --- a/src/modules/capture.py +++ b/src/modules/capture.py @@ -87,7 +87,7 @@ def _main(self): self.window['width'] = max(rect[2] - rect[0], MMT_WIDTH) self.window['height'] = max(rect[3] - rect[1], MMT_HEIGHT) - # Calibrate by finding the bottom right corner of the minimap + # Calibrate by finding the top-left and bottom-right corners of the minimap with mss.mss() as self.sct: self.frame = self.screenshot() if self.frame is None: