import sys import os # Agregar el directorio padre al path para importar config sys.path.append(os.path.dirname(os.path.abspath(__file__))) from config import TARGET_PROCESS, UI_MESSAGES from core.memory_manager import MemoryManager from patterns.pattern_searcher import StaminaPatternSearcher, SpeedPatternSearcher from patches.patch_factory import PatchFactory from utils.helpers import HexDumper, BackupManager, UserInterface class AdvancedPatcher: """Clase principal del patcher que coordina todos los módulos (Facade Pattern)""" def __init__(self): self.memory_manager = MemoryManager() self.patch_factory = PatchFactory() self.hex_dumper = HexDumper() self.backup_manager = BackupManager(self.memory_manager) self.ui = UserInterface() self.target_process = TARGET_PROCESS['name'] def show_patch_menu(self) -> tuple: """Muestra el menú de selección de parches""" print("\n🎯 Selecciona el tipo de parche a aplicar:") print("1. Stamina infinita") print("2. Velocidad de movimiento") print("3. Salir") while True: try: choice = input("\n➤ Ingresa tu opción (1-3): ").strip() if choice == '1': return ('stamina', None) elif choice == '2': return self.show_speed_menu() elif choice == '3': return (None, None) else: print("❌ Opción inválida. Por favor ingresa 1, 2 o 3.") except KeyboardInterrupt: return (None, None) def show_speed_menu(self) -> tuple: """Muestra el menú de selección de velocidad""" multipliers = self.patch_factory.get_speed_multipliers() print("\n🏃 Selecciona el multiplicador de velocidad:") for i, mult in enumerate(multipliers, 1): print(f"{i}. {mult}") while True: try: choice = input(f"\n➤ Ingresa tu opción (1-{len(multipliers)}): ").strip() try: index = int(choice) - 1 if 0 <= index < len(multipliers): return ('speed', multipliers[index]) else: print(f"❌ Opción inválida. Por favor ingresa un número entre 1 y {len(multipliers)}.") except ValueError: print("❌ Por favor ingresa un número válido.") except KeyboardInterrupt: return (None, None) def apply_patch(self, patch_type: str, speed_multiplier: str = None) -> bool: """Aplica el parche especificado usando todos los módulos""" # Buscar y abrir el proceso if not self.memory_manager.open_process(self.target_process): print(UI_MESSAGES['error']['process_not_found'].format(process_name=self.target_process)) return False # Seleccionar el buscador de patrones apropiado if patch_type == 'stamina': pattern_searcher = StaminaPatternSearcher() print(UI_MESSAGES['info']['searching_stamina']) elif patch_type == 'speed': pattern_searcher = SpeedPatternSearcher() print(UI_MESSAGES['info']['searching_speed']) else: print(f"❌ Tipo de parche no soportado: {patch_type}") return False # Buscar patrones found_addresses = pattern_searcher.search(self.memory_manager) if not found_addresses: print(UI_MESSAGES['error']['no_patterns_found']) return False # Mostrar direcciones encontradas self.ui.print_found_addresses(found_addresses) # Seleccionar dirección objetivo target_address = self.ui.select_target_address(found_addresses) # Crear el parche if patch_type == 'speed' and speed_multiplier: patch = self.patch_factory.create_patch(patch_type, speed_multiplier=speed_multiplier) else: patch = self.patch_factory.create_patch(patch_type) if not patch: print(f"❌ No se pudo crear el parche de {patch_type}") return False print(f"\n📋 {patch.get_description()}") # Leer código original original_size = patch.get_patch_size() original_code = self.memory_manager.read_memory(target_address, original_size) if not original_code: print("❌ No se pudo leer el código original") return False # Crear backup self.backup_manager.backup_original_code(target_address, len(original_code)) # Mostrar código original print(UI_MESSAGES['info']['original_code']) self.hex_dumper.print_hex_dump(original_code, target_address) # Generar datos del parche patch_data = patch.create_patch(original_code) # Mostrar código del parche print(UI_MESSAGES['info']['patch_to_apply']) self.hex_dumper.print_hex_dump(patch_data) # Confirmar aplicación if not self.ui.confirm_patch(): print(UI_MESSAGES['error']['operation_cancelled']) return False # Aplicar el parche print(UI_MESSAGES['info']['applying_patch']) if self.memory_manager.write_memory(target_address, patch_data): print(UI_MESSAGES['success']['patch_applied']) # Verificar que el patch se escribió correctamente verification_data = self.memory_manager.read_memory(target_address, len(patch_data)) if verification_data == patch_data: print(UI_MESSAGES['success']['verification_successful']) return True else: print(UI_MESSAGES['error']['verification_failed']) return False else: print(UI_MESSAGES['error']['patch_failed']) return False def cleanup(self): """Limpia los recursos utilizados""" self.memory_manager.close_process() def run(self) -> bool: """Ejecuta el proceso completo de patcheo""" print(UI_MESSAGES['info']['starting_patch_process']) success = False try: # Mostrar menú de selección patch_type, speed_multiplier = self.show_patch_menu() if patch_type is None: print(UI_MESSAGES['info']['goodbye']) return False success = self.apply_patch(patch_type, speed_multiplier) if success: print(UI_MESSAGES['success']['patching_completed']) if patch_type == 'stamina': print(UI_MESSAGES['success']['stamina_maintained']) elif patch_type == 'speed': print(UI_MESSAGES['success']['speed_modified']) else: print(UI_MESSAGES['error']['patching_failed']) except Exception as e: print(UI_MESSAGES['error']['patching_error'].format(error=e)) finally: self.cleanup() return success