using BepInEx; using HarmonyLib; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.UI; using TMPro; namespace StrategicMapPlus { [BepInPlugin("com.mod.strategicmapplus", "Strategic Map Plus", "28.0.0")] public class StrategicMapMod : BaseUnityPlugin { private float timer = 0f; private float interval = 0.5f; private bool texturesLoaded = false; public static Dictionary SpriteCache = new Dictionary(); private HashSet reportedMissingKeys = new HashSet(); void Awake() { Logger.LogInfo("Strategic Map Plus v28: Posición 0,0,0."); } void Update() { if (!texturesLoaded && Time.time > 3f) LoadTextures(); timer += Time.deltaTime; if (timer < interval) return; timer = 0f; if (texturesLoaded) ScanStrategicMap(); } void LoadTextures() { Texture2D[] allTextures = Resources.FindObjectsOfTypeAll(); Dictionary textureLookup = new Dictionary(); foreach (var tex in allTextures) { if (tex != null && !string.IsNullOrEmpty(tex.name)) { if (!textureLookup.ContainsKey(tex.name)) textureLookup.Add(tex.name, tex); } } int loadedCount = 0; foreach (var kvp in Textures.TextureMap) { string logicKey = kvp.Key; string texName = kvp.Value; if (textureLookup.ContainsKey(texName)) { Texture2D tex = textureLookup[texName]; Sprite s = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0.5f, 0.5f)); SpriteCache[logicKey] = s; loadedCount++; } } if (loadedCount > 0) texturesLoaded = true; } void ScanStrategicMap() { GameObject regionsRoot = GameObject.Find("UI/2DRoot/Layout/Limit/FrontDialogs/StrategicView/Root/Regions"); if (regionsRoot == null || !regionsRoot.activeInHierarchy) return; foreach (Transform region in regionsRoot.transform) { Transform army = region.Find("Army"); if (army == null) continue; Component defenseRenderer = army.GetComponent("iron.match.renderers.strategicview.DefenseCountRenderer"); Transform visualRoot = army.Find("Root"); Transform targetParent = (visualRoot != null) ? visualRoot : army; if (defenseRenderer != null) ProcessRegion((MonoBehaviour)defenseRenderer, targetParent); } } void ProcessRegion(MonoBehaviour renderer, Transform parentTransform) { var visualizer = parentTransform.GetComponent(); if (visualizer == null) { visualizer = parentTransform.gameObject.AddComponent(); visualizer.Initialize(); } var traverse = Traverse.Create(renderer); var model = traverse.Property("model").GetValue(); if (model == null) { visualizer.Hide(); return; } var children = Traverse.Create(model).Field("Children").GetValue() as IEnumerable; if (children == null) children = Traverse.Create(model).Field("children").GetValue() as IEnumerable; string orderType = ""; bool isSpecial = false; int strength = 0; bool found = false; if (children != null) { foreach (var child in children) { var childTrav = Traverse.Create(child); var attributesObj = childTrav.Field("attributes").GetValue(); if (attributesObj != null) { var valuesDict = Traverse.Create(attributesObj).Field("data").GetValue() as IDictionary; if (valuesDict != null && valuesDict.Contains(400003)) { object typeCont = valuesDict[400003]; object typeVal = Traverse.Create(typeCont).Property("Value").GetValue(); if (typeVal?.ToString() == "Order") { if (valuesDict.Contains(400038)) // OrderType { object oCont = valuesDict[400038]; object oVal = Traverse.Create(oCont).Property("Value").GetValue(); var list = oVal as IList; if (list != null && list.Count > 0) orderType = list[0].ToString(); } if (valuesDict.Contains(400039)) // HasStar { object sCont = valuesDict[400039]; object sVal = Traverse.Create(sCont).Property("Value").GetValue(); if (sVal != null && sVal.ToString().ToLower() == "true") isSpecial = true; } if (valuesDict.Contains(400004)) // Strength { object strCont = valuesDict[400004]; object strVal = Traverse.Create(strCont).Property("Value").GetValue(); int.TryParse(strVal?.ToString(), out strength); } found = true; break; } } } } } if (!found) { visualizer.Hide(); return; } // Generar clave lógica string generatedKey = $"{orderType}_{strength}"; if (isSpecial) generatedKey += "_Star"; if (SpriteCache.ContainsKey(generatedKey)) { visualizer.ShowIcon(SpriteCache[generatedKey]); } else { if (!reportedMissingKeys.Contains(generatedKey)) { Logger.LogWarning($"[FALTA MAPEO] El juego pide: '{generatedKey}'"); reportedMissingKeys.Add(generatedKey); } visualizer.ShowText(generatedKey); } } } // --- VISUALIZADOR --- public class StrategicDisplay : MonoBehaviour { private GameObject displayObj; private Image iconImage; private TextMeshProUGUI debugText; private bool isInitialized = false; public void Initialize() { if (isInitialized && displayObj != null) return; if (displayObj != null) Destroy(displayObj); try { displayObj = new GameObject("OrderIcon_Mod"); displayObj.transform.SetParent(this.transform, false); // POSICIÓN EXACTA 0,0,0 displayObj.transform.localPosition = Vector3.zero; // Aseguramos capa correcta displayObj.layer = this.gameObject.layer; RectTransform rt = displayObj.AddComponent(); rt.sizeDelta = new Vector2(45, 45); // Tamaño del icono iconImage = displayObj.AddComponent(); iconImage.raycastTarget = false; iconImage.color = Color.white; // Backup Text GameObject textObj = new GameObject("BackupText"); textObj.transform.SetParent(displayObj.transform, false); textObj.layer = this.gameObject.layer; RectTransform textRt = textObj.AddComponent(); textRt.anchoredPosition = Vector2.zero; debugText = textObj.AddComponent(); debugText.alignment = TextAlignmentOptions.Center; debugText.fontSize = 14; debugText.fontStyle = FontStyles.Bold; debugText.color = Color.magenta; // CRUCIAL: Ponemos el icono al final de la lista de hijos para que se pinte ENCIMA displayObj.transform.SetAsLastSibling(); isInitialized = true; } catch (System.Exception e) { Debug.LogWarning("Error UI: " + e.Message); if (displayObj != null) Destroy(displayObj); isInitialized = false; } } public void Hide() { if (displayObj != null && displayObj.activeSelf) displayObj.SetActive(false); } public void ShowIcon(Sprite s) { if (!isInitialized) Initialize(); if (!isInitialized) return; // Aseguramos orden de dibujado (Encima de todo) displayObj.transform.SetAsLastSibling(); if (!displayObj.activeSelf) displayObj.SetActive(true); if (s != null) { iconImage.sprite = s; iconImage.enabled = true; if (debugText != null) debugText.text = ""; } } public void ShowText(string t) { if (!isInitialized) Initialize(); if (!isInitialized) return; displayObj.transform.SetAsLastSibling(); if (!displayObj.activeSelf) displayObj.SetActive(true); if (iconImage != null) iconImage.enabled = false; if (debugText != null) debugText.text = t; } } }