from abc import ABC, abstractmethod from typing import List, Tuple, Dict, Optional import sys import os # Agregar el directorio padre al path para importar config sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from config import MEMORY_SEARCH_CONFIG, UI_MESSAGES from core.memory_manager import MemoryManager class PatternSearcher(ABC): """Interfaz base para buscadores de patrones (Strategy Pattern)""" def __init__(self): pass @abstractmethod def get_patterns(self) -> Dict[str, Tuple[bytes, List[str]]]: """Retorna los patrones a buscar""" pass @abstractmethod def search(self, memory_manager: MemoryManager) -> List[Tuple[str, int]]: """Busca los patrones en memoria""" pass def pattern_matches(self, data: bytes, pattern: bytes, mask: List[str], offset: int) -> bool: """Verifica si un patrón coincide en una posición específica""" pattern_len = len(pattern) if offset + pattern_len > len(data): return False data_slice = data[offset:offset + pattern_len] for i, (p_byte, m_char) in enumerate(zip(pattern, mask)): if m_char != '?' and data_slice[i] != p_byte: return False return True class StaminaPatternSearcher(PatternSearcher): """Buscador específico para patrones de stamina""" def get_patterns(self) -> Dict[str, Tuple[bytes, List[str]]]: """Define los patrones específicos para stamina""" return { "stamina_pattern_1": ( bytes([0x75, 0x00, 0xF3, 0x0F, 0x10, 0x44, 0x24, 0x08, 0xF3, 0x0F, 0x5A, 0xC0, 0xF2, 0x0F, 0x5A, 0xE8, 0xF3, 0x0F, 0x11, 0xAE, 0x94, 0x01, 0x00, 0x00]), ['x', '?', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'] ) } def search(self, memory_manager: MemoryManager) -> List[Tuple[str, int]]: """Busca patrones de stamina en memoria""" patterns = self.get_patterns() regions = memory_manager.get_memory_regions() found_addresses = [] print(UI_MESSAGES['info']['searching_patterns'].format(region_count=len(regions))) # Pre-calcular longitudes de patrones pattern_info = {name: (pattern, mask, len(pattern)) for name, (pattern, mask) in patterns.items()} for region_idx, region in enumerate(regions): print(f" Región {region_idx + 1}/{len(regions)}: 0x{region['base']:X} - 0x{region['base'] + region['size']:X}") # Configuración optimizada de chunks desde config chunk_size = MEMORY_SEARCH_CONFIG['chunk_size'] overlap = MEMORY_SEARCH_CONFIG['overlap'] for offset in range(0, region['size'], chunk_size): current_address = region['base'] + offset read_size = min(chunk_size + overlap, region['size'] - offset) data = memory_manager.read_memory(current_address, read_size) if not data: continue # Buscar cada patrón data_len = len(data) for pattern_name, (pattern, mask, pattern_len) in pattern_info.items(): search_limit = data_len - pattern_len + 1 for i in range(search_limit): if self.pattern_matches(data, pattern, mask, i): found_address = current_address + i found_addresses.append((pattern_name, found_address)) print(UI_MESSAGES['info']['pattern_found'].format(pattern_name=pattern_name, address=found_address)) print(" 🛑 Deteniendo búsqueda - primer patrón encontrado") return found_addresses class SpeedPatternSearcher(PatternSearcher): """Buscador específico para patrones de velocidad""" def get_patterns(self) -> Dict[str, Tuple[bytes, List[str]]]: """Define los patrones específicos para velocidad""" return { "speed_pattern_1": ( bytes([0xE0, 0x67, 0x03, 0x36, 0x7B, 0x02, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x41, 0x00, 0x00, 0x80, 0x3F]), ['x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x', 'x'] ) } def search(self, memory_manager: MemoryManager) -> List[Tuple[str, int]]: """Busca patrones de velocidad en memoria""" patterns = self.get_patterns() regions = memory_manager.get_memory_regions() found_addresses = [] print(UI_MESSAGES['info']['searching_patterns'].format(region_count=len(regions))) # Pre-calcular longitudes de patrones pattern_info = {name: (pattern, mask, len(pattern)) for name, (pattern, mask) in patterns.items()} for region_idx, region in enumerate(regions): print(f" Región {region_idx + 1}/{len(regions)}: 0x{region['base']:X} - 0x{region['base'] + region['size']:X}") # Configuración optimizada de chunks desde config chunk_size = MEMORY_SEARCH_CONFIG['chunk_size'] overlap = MEMORY_SEARCH_CONFIG['overlap'] for offset in range(0, region['size'], chunk_size): current_address = region['base'] + offset read_size = min(chunk_size + overlap, region['size'] - offset) data = memory_manager.read_memory(current_address, read_size) if not data: continue # Buscar cada patrón data_len = len(data) for pattern_name, (pattern, mask, pattern_len) in pattern_info.items(): search_limit = data_len - pattern_len + 1 for i in range(search_limit): if self.pattern_matches(data, pattern, mask, i): found_address = current_address + i found_addresses.append((pattern_name, found_address)) print(UI_MESSAGES['info']['pattern_found'].format(pattern_name=pattern_name, address=found_address)) print(" 🛑 Deteniendo búsqueda - primer patrón encontrado") return found_addresses return found_addresses