using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Logging; using HarmonyLib; using TMPro; using TurronishMod.Logger; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Networking; using UnityEngine.SceneManagement; using UnityEngine.UI; using UnityEngine.Video; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("ControlDoblaje")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ControlDoblaje")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("fa4defe9-2a53-4511-a7a4-e9af13103075")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace ControlDoblaje; public class DoblejeUIMarker : MonoBehaviour { } public class CoroutineHolder : MonoBehaviour { private static CoroutineHolder _inst; private static void Ensure() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown if (!((Object)(object)_inst != (Object)null) || !((Object)(object)((Component)_inst).gameObject != (Object)null)) { GameObject val = new GameObject("_CoroutineHolder"); Object.DontDestroyOnLoad((Object)(object)val); _inst = val.AddComponent(); } } public static void Inicia(IEnumerator r) { Ensure(); ((MonoBehaviour)_inst).StartCoroutine(r); } } public static class Layout { public static float FontCabecera = 22f; public static float FontEtiqueta = 20f; public static float FontDropdown = 20f; public static float FontDropItem = 18f; public static float FontDescTitulo = 22f; public static float FontDescTexto = 18f; public static float FontBoton = 18f; public static float FontInput = 18f; public static float FontChevron = 16f; public static float AltoCabecera = 48f; public static float AltoFila = 48f; public static float AltoFilaGrid = 48f; public static float AltoDropdown = 36f; public static float AltoBoton = 36f; public static float AltoInput = 36f; public static float AltoItemPopup = 36f; public static float AnchoEtiqueta = 200f; public static float AnchoEtiquetaGrid = 160f; public static float AnchoDropdownNormal = 400f; public static float AnchoDropdownGrid = 380f; public static float AnchoDropdownPreset = 320f; public static float AnchoBoton = 280f; public static float AnchoBotonBorrar = 220f; public static float AnchoInput = 300f; public static float GridSepWidth = 2f; public static void CalibrateFrom(Transform tabRoot) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Expected O, but got Unknown //IL_009e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)tabRoot == (Object)null) { return; } ScrollRect componentInChildren = ((Component)tabRoot).GetComponentInChildren(true); Transform val = (Transform)(object)((componentInChildren != null) ? componentInChildren.content : null); if ((Object)(object)val == (Object)null) { ControlDoblajePlugin.Log.LogWarning((object)"[Layout] CalibrateFrom: no ScrollRect content"); return; } foreach (Transform item in val) { Transform val2 = item; if (((Object)val2).name.StartsWith("*")) { continue; } RectTransform component = ((Component)val2).GetComponent(); if ((Object)(object)component == (Object)null) { continue; } float y = component.sizeDelta.y; if (y < 20f || y > 200f) { continue; } TMP_Text componentInChildren2 = ((Component)val2).GetComponentInChildren(true); if ((Object)(object)componentInChildren2 != (Object)null) { float fontSize = componentInChildren2.fontSize; FontEtiqueta = Mathf.Round(fontSize * 0.9f); FontDropdown = FontEtiqueta; FontDropItem = Mathf.Round(fontSize * 0.82f); FontCabecera = Mathf.Round(fontSize * 0.9f); FontBoton = Mathf.Round(fontSize * 0.78f); FontInput = Mathf.Round(fontSize * 0.78f); FontDescTitulo = Mathf.Round(fontSize * 1.8f); FontDescTexto = Mathf.Round(fontSize * 1.56f); FontChevron = Mathf.Round(fontSize * 0.6f); AltoFila = Mathf.Clamp(y, 44f, 72f); AltoFilaGrid = AltoFila; AltoCabecera = AltoFila; AltoDropdown = Mathf.Clamp(Mathf.Round(AltoFila * 0.6f), 30f, 44f); AltoBoton = AltoDropdown; AltoInput = AltoDropdown; AltoItemPopup = Mathf.Clamp(Mathf.Round(AltoFila * 0.64f), 32f, 48f); ControlDoblajePlugin.Log.LogInfo((object)$"[Layout] Calibrado desde '{((Object)val2).name}': srcH={y} srcFont={fontSize} -> AltoFila={AltoFila} FontLabel={FontEtiqueta}"); } return; } ControlDoblajePlugin.Log.LogWarning((object)"[Layout] CalibrateFrom: no se encontro fila valida, usando defaults."); } } [BepInPlugin("com.enadoblaje.control", "ENA Control de Doblaje", "1.1.0")] public class ControlDoblajePlugin : BaseUnityPlugin { public static Action InstalarAudioScanners; public static Action PatchAudioExtra; public static Action SceneLoadedAudio; public static Func AplicarModelosCallback; public static Action WandererRadioMute; public static Action ModelosAplicar; public static Action ModelosRestaurar; public static Action SoundPlayRandom; public static Action UIResetarEstado; public static Action UIExtrasTurronishReset; public static Func UIExtrasTurronishInyectar; public static Action UIAttachLogoMonitor; public static Action UITryInstalarPatch; public static Action UIMostrarAvisoActualizacion; public static Action VideoExtrasInicio; public static Action VideoExtrasFin; private static int _frameNum = 0; private static readonly HashSet _carpetasOcultas = new HashSet(StringComparer.OrdinalIgnoreCase) { "Ambiente" }; public static Func> AudioObtenerPersonajesDeBank; public static Action AudioForzarCargaBanks; public static ControlDoblajePlugin Instance { get; private set; } public static ManualLogSource Log { get; private set; } public static string VoicesPath { get; private set; } public static string VideoClipsPath { get; private set; } public static string ImagesPath { get; private set; } public static string MeshPath { get; private set; } public static string BanksPath { get; private set; } public static string AssetsRoot { get; private set; } public static Dictionary PersonajeActivo { get; private set; } = new Dictionary(); public static List PersonajesDisponibles { get; private set; } = new List(); public static bool VideoClipsActivo { get; set; } = true; public static bool ImagenesActivas { get; set; } = true; public static bool ModelosActivos { get; set; } = true; public static int VarianteENA { get; set; } = 0; public static bool VarianteENAMeanie => VarianteENA == 1; public static int VarianteTaxi { get; set; } = 0; public static int VarianteYowadama { get; set; } = 0; public static bool LogVerboso { get; set; } = false; public static bool LogoBtnActivo { get; set; } = true; public static bool BuscarActualizaciones { get; set; } = true; public static string URLVersion { get; set; } = ""; public static bool EnTransicion { get; set; } = false; public static float VideoClipStartTime { get; set; } = -1f; public static Dictionary NombresUI { get; private set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public static Dictionary DescripcionesUI { get; private set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public static Dictionary DescripcionesUI_EN { get; private set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public static Dictionary KeyOverride { get; private set; } = new Dictionary(StringComparer.OrdinalIgnoreCase); public static HashSet VirtualPersonajes { get; private set; } = new HashSet(StringComparer.OrdinalIgnoreCase); private static string PersonajesConfigPath => Path.Combine(Path.GetDirectoryName(typeof(ControlDoblajePlugin).Assembly.Location), "personajes_config.json"); private static string ConfigPath => Path.Combine(Paths.ConfigPath, "ENADoblaje_config.json"); public static string NombreUIDePersonaje(string carpeta) { string value; return NombresUI.TryGetValue(carpeta, out value) ? value : carpeta; } public static string DescripcionUIDePersonaje(string carpeta) { Dictionary dictionary = (Traducciones.TextoEspanolActivo ? DescripcionesUI : DescripcionesUI_EN); if (!dictionary.TryGetValue(carpeta, out var value) || string.IsNullOrEmpty(value)) { DescripcionesUI.TryGetValue(carpeta, out value); } if (string.IsNullOrEmpty(value)) { return null; } return value.Replace("\n\\ ", "\n").Replace("\n\\", "\n"); } public static string KeyDePersonaje(string carpeta) { string value; return KeyOverride.TryGetValue(carpeta, out value) ? value : carpeta; } private void Update() { _frameNum++; float unscaledDeltaTime = Time.unscaledDeltaTime; if (unscaledDeltaTime > 0.1f && _frameNum > 2) { Log.LogWarning((object)$"[PERF] frame lento #{_frameNum}: {(int)(unscaledDeltaTime * 1000f)}ms (~{(int)(1f / unscaledDeltaTime)}fps)"); } } private static string ResolverCarpetaAssets() { string directoryName = Path.GetDirectoryName(typeof(ControlDoblajePlugin).Assembly.Location); string text = Path.Combine(Paths.BepInExRootPath, "Assets"); string[] array = new string[4] { directoryName, Path.Combine(directoryName, "Assets"), text, Path.Combine(Path.GetDirectoryName(Application.dataPath), "BepInEx", "Assets") }; string[] array2 = array; foreach (string text2 in array2) { try { if (File.Exists(Path.Combine(text2, "assets.dat")) || File.Exists(Path.Combine(text2, "audio.dat")) || File.Exists(Path.Combine(text2, "turronish_img.dat"))) { return text2; } } catch { } } return text; } private void Awake() { //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; string text = Path.Combine(Paths.BepInExRootPath, "Logs", "Turronish"); TurronishDiagLogger.Initialize(Log, text, (TLogMode)0); TurronishDiagLogger.Verbose = LogVerboso; try { string text2 = (AssetsRoot = ResolverCarpetaAssets()); Log.LogInfo((object)("[Paths] dataPath='" + Application.dataPath + "' dllDir='" + Path.GetDirectoryName(typeof(ControlDoblajePlugin).Assembly.Location) + "' → bepAssets='" + text2 + "'")); AssetPack.Init(text2); VoicesPath = Path.Combine(text2, "Voices"); VideoClipsPath = Path.Combine(text2, "VideoClips"); ImagesPath = Path.Combine(text2, "Images"); MeshPath = Path.Combine(text2, "Mesh"); BanksPath = Path.Combine(text2, "Banks"); EscanearPersonajes(); CargarConfig(); CargarPersonajesConfig(); Traducciones.CargarDesdeJSON(); Harmony val = new Harmony("com.enadoblaje.control"); val.PatchAll(); UITryInstalarPatch?.Invoke(val); PatchAudioExtra?.Invoke(val); InstalarAudioScanners?.Invoke(); SceneManager.sceneLoaded += SceneLoaded_Handler; TurronishDiagLogger.Info("[Core]", "Awake completado. sceneLoaded registrado."); } catch (Exception ex) { TurronishDiagLogger.Error("[Core]", "EXCEPCION EN AWAKE: " + ex.GetType().Name + " — " + ex.Message + "\n" + ex.StackTrace); Log.LogError((object)("[Turronish] EXCEPCION EN AWAKE: " + ex.Message + "\n" + ex.StackTrace)); } } private void SceneLoaded_Handler(Scene scene, LoadSceneMode mode) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) try { SceneLoaded_Impl(scene, mode); } catch (Exception ex) { Log.LogError((object)("[Turronish] SceneLoaded exception: " + ex.Message + "\n" + ex.StackTrace)); } } private void SceneLoaded_Impl(Scene scene, LoadSceneMode mode) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) Log.LogInfo((object)("[Turronish] sceneLoaded: '" + ((Scene)(ref scene)).name + "'")); TurronishDiagLogger.Info("[Core]", $"sceneLoaded: '{((Scene)(ref scene)).name}' mode={mode}"); EnTransicion = true; UIResetarEstado?.Invoke(); UIExtrasTurronishReset?.Invoke(); SceneLoadedAudio?.Invoke(); if (((Scene)(ref scene)).name == "Boot" && PersonajesDisponibles.Count == 0) { AudioForzarCargaBanks?.Invoke(); if (AudioObtenerPersonajesDeBank != null) { EscanearPersonajes(); CargarPersonajesConfig(); } } if (((Scene)(ref scene)).name.IndexOf("Credit", StringComparison.OrdinalIgnoreCase) >= 0 || ((Scene)(ref scene)).name.IndexOf("Ending", StringComparison.OrdinalIgnoreCase) >= 0 || ((Scene)(ref scene)).name.IndexOf("Grey", StringComparison.OrdinalIgnoreCase) >= 0) { Log.LogInfo((object)("[Credits] Escena detectada: " + ((Scene)(ref scene)).name)); CreditScanner.Escanear(); } try { CoroutineHolder.Inicia(InyectarLogoDespues()); } catch (Exception ex) { Log.LogWarning((object)("[Turronish] CoroutineHolder InyectarLogoDespues: " + ex.Message)); } try { CoroutineHolder.Inicia(DiagnosticarEscena(((Scene)(ref scene)).name)); } catch (Exception ex2) { Log.LogWarning((object)("[Turronish] CoroutineHolder DiagnosticarEscena: " + ex2.Message)); } try { CoroutineHolder.Inicia(EscanearImagenesDespues()); } catch (Exception ex3) { Log.LogWarning((object)("[Turronish] CoroutineHolder EscanearImagenesDespues: " + ex3.Message)); } if (AplicarModelosCallback != null) { try { CoroutineHolder.Inicia(AplicarModelosCallback()); } catch (Exception ex4) { Log.LogWarning((object)("[Turronish] CoroutineHolder AplicarModelos3DDespues: " + ex4.Message)); } } if (((Scene)(ref scene)).name.Equals("Menu", StringComparison.OrdinalIgnoreCase) && UIExtrasTurronishInyectar != null) { try { CoroutineHolder.Inicia(UIExtrasTurronishInyectar()); } catch (Exception ex5) { Log.LogWarning((object)("[Turronish] ExtrasTurronishGestor: " + ex5.Message)); } } } private IEnumerator EscanearImagenesDespues() { for (int i = 0; i < 8; i++) { yield return null; } EnTransicion = false; Log.LogInfo((object)"[IMAGE] Transicion completada — escaneo post-transicion iniciado"); if (!ImagenesActivas) { yield break; } Image[] array = Resources.FindObjectsOfTypeAll(); Scene scene; foreach (Image img in array) { if ((Object)(object)img == (Object)null || (Object)(object)img.sprite == (Object)null) { continue; } scene = ((Component)img).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { Sprite reemplazado = SpriteReemplazador.Reemplazar(img.sprite); if ((Object)(object)reemplazado != (Object)(object)img.sprite) { img.sprite = reemplazado; } } } SpriteRenderer[] array2 = Resources.FindObjectsOfTypeAll(); foreach (SpriteRenderer sr in array2) { if ((Object)(object)sr == (Object)null || (Object)(object)sr.sprite == (Object)null) { continue; } scene = ((Component)sr).gameObject.scene; if (((Scene)(ref scene)).IsValid()) { Sprite reemplazado2 = SpriteReemplazador.Reemplazar(sr.sprite); if ((Object)(object)reemplazado2 != (Object)(object)sr.sprite) { sr.sprite = reemplazado2; } } } Log.LogInfo((object)"[IMAGE] Escaneo post-transicion completado"); } private IEnumerator DiagnosticarEscena(string nombreEscena) { if (LogVerboso) { for (int i = 0; i < 5; i++) { yield return null; } VolcarDiagnostico(nombreEscena, "5f"); for (int j = 0; j < 85; j++) { yield return null; } VolcarDiagnostico(nombreEscena, "90f"); } } private void VolcarDiagnostico(string nombreEscena, string etiqueta) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_0397: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) try { Log.LogInfo((object)$"[DIAG] ═══ {etiqueta} post-carga '{nombreEscena}' tScale={Time.timeScale:F2} ═══"); int num = 0; Canvas[] array = Resources.FindObjectsOfTypeAll(); foreach (Canvas val in array) { if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy) { continue; } Scene scene = ((Component)val).gameObject.scene; object obj; if (!((Scene)(ref scene)).IsValid()) { obj = "DDOL"; } else { scene = ((Component)val).gameObject.scene; obj = ((Scene)(ref scene)).name; } string text = (string)obj; Log.LogInfo((object)("[DIAG] Canvas '" + ((Object)((Component)val).gameObject).name + "' [" + text + "] " + $"mode={val.renderMode} sort={val.sortingOrder} root={val.isRootCanvas}")); Image[] componentsInChildren = ((Component)val).GetComponentsInChildren(false); foreach (Image val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null) && ((Component)val2).gameObject.activeInHierarchy && !(((Graphic)val2).color.a < 0.5f)) { RectTransform component = ((Component)val2).GetComponent(); float num2; Rect rect; if (!((Object)(object)component != (Object)null)) { num2 = 0f; } else { rect = component.rect; num2 = ((Rect)(ref rect)).width; } float num3 = num2; float num4; if (!((Object)(object)component != (Object)null)) { num4 = 0f; } else { rect = component.rect; num4 = ((Rect)(ref rect)).height; } float num5 = num4; Log.LogInfo((object)$"[DIAG] Image '{((Object)((Component)val2).gameObject).name}' color={((Graphic)val2).color} {num3:F0}x{num5:F0}"); } } CanvasGroup[] componentsInChildren2 = ((Component)val).GetComponentsInChildren(true); foreach (CanvasGroup val3 in componentsInChildren2) { if (!((Object)(object)val3 == (Object)null) && !(val3.alpha >= 0.99f)) { Log.LogInfo((object)$"[DIAG] CanvasGroup '{((Object)((Component)val3).gameObject).name}' alpha={val3.alpha:F2}"); } } num++; } if (num == 0) { Log.LogInfo((object)"[DIAG] (ningún Canvas activo encontrado)"); } VideoPlayer[] array2 = Resources.FindObjectsOfTypeAll(); foreach (VideoPlayer val4 in array2) { if (!((Object)(object)val4 == (Object)null)) { Log.LogInfo((object)($"[DIAG] VP '{((Object)((Component)val4).gameObject).name}' playing={val4.isPlaying} " + $"paused={val4.isPaused} mode={val4.renderMode} active={((Component)val4).gameObject.activeInHierarchy}")); } } Camera[] allCameras = Camera.allCameras; foreach (Camera val5 in allCameras) { if (!((Object)(object)val5 == (Object)null)) { Log.LogInfo((object)($"[DIAG] Cam '{((Object)((Component)val5).gameObject).name}' depth={val5.depth} " + $"clear={val5.clearFlags} enabled={((Behaviour)val5).enabled} mask={val5.cullingMask}")); } } Log.LogInfo((object)"[DIAG] ══════════════════════════════════════════════════"); } catch (Exception ex) { Log.LogWarning((object)("[DIAG] Error en volcado: " + ex.Message)); } } private IEnumerator InyectarLogoDespues() { yield return null; yield return null; if (!LogoBtnActivo || (Object)(object)GameObject.Find("_TurronishLogoBtn") != (Object)null) { yield break; } GameObject mainMenuGO = GameObject.Find("Main Menu"); if ((Object)(object)mainMenuGO == (Object)null) { Log.LogWarning((object)"[Turronish] Logo: 'Main Menu' no encontrado"); yield break; } Transform bordersPath = mainMenuGO.transform.Find("Borders (Masked)") ?? mainMenuGO.transform.Find("Content (Masked)/Borders (Masked)") ?? mainMenuGO.transform.Find("Content (Masked)/Borders") ?? mainMenuGO.transform; Transform mainPanelT = mainMenuGO.transform.Find("Content (Masked)/Main") ?? mainMenuGO.transform.Find("Main"); if ((Object)(object)bordersPath == (Object)null) { Log.LogWarning((object)"[Turronish] Logo: transform raíz nula, abortando"); yield break; } Log.LogInfo((object)$"[Turronish] Logo: borders='{((Object)bordersPath).name}' main={(Object)(object)mainPanelT != (Object)null}"); GameObject plantilla = null; Button[] componentsInChildren = mainMenuGO.GetComponentsInChildren