Files
got-mod-strategicview-plus/Class1.cs

348 lines
13 KiB
C#
Raw Normal View History

2026-01-06 04:07:34 +01:00
using BepInEx;
2026-01-06 05:22:10 +01:00
using HarmonyLib;
2026-01-06 04:07:34 +01:00
using System.Collections;
using System.Collections.Generic;
2026-01-06 05:22:10 +01:00
using System.Linq;
2026-01-06 04:07:34 +01:00
using UnityEngine;
2026-01-06 05:22:10 +01:00
using UnityEngine.UI;
2026-01-06 04:07:34 +01:00
using TMPro;
namespace StrategicMapPlus
{
2026-01-06 05:22:10 +01:00
[BepInPlugin("com.mod.strategicmapplus", "Strategic Map Plus", "28.0.0")]
2026-01-06 04:07:34 +01:00
public class StrategicMapMod : BaseUnityPlugin
{
private float timer = 0f;
private float interval = 0.5f;
2026-01-06 05:22:10 +01:00
private bool texturesLoaded = false;
public static Dictionary<string, Sprite> SpriteCache = new Dictionary<string, Sprite>();
private HashSet<string> reportedMissingKeys = new HashSet<string>();
2026-01-06 04:07:34 +01:00
void Awake()
{
2026-01-06 05:22:10 +01:00
Logger.LogInfo("Strategic Map Plus v28: Posición 0,0,0.");
2026-01-06 04:07:34 +01:00
}
void Update()
{
2026-01-06 05:22:10 +01:00
if (!texturesLoaded && Time.time > 3f) LoadTextures();
2026-01-06 04:07:34 +01:00
timer += Time.deltaTime;
if (timer < interval) return;
timer = 0f;
2026-01-06 05:22:10 +01:00
if (texturesLoaded) ScanStrategicMap();
}
void LoadTextures()
{
Texture2D[] allTextures = Resources.FindObjectsOfTypeAll<Texture2D>();
Dictionary<string, Texture2D> textureLookup = new Dictionary<string, Texture2D>();
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];
2026-01-06 15:22:22 +01:00
Texture2D roundTex = MakeTextureTransparent(tex);
Sprite s = Sprite.Create(roundTex, new Rect(0, 0, roundTex.width, roundTex.height), new Vector2(0.5f, 0.5f));
2026-01-06 05:22:10 +01:00
SpriteCache[logicKey] = s;
loadedCount++;
}
}
if (loadedCount > 0) texturesLoaded = true;
2026-01-06 04:07:34 +01:00
}
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)
{
2026-01-06 05:22:10 +01:00
var visualizer = parentTransform.GetComponent<StrategicDisplay>();
2026-01-06 04:07:34 +01:00
if (visualizer == null)
{
2026-01-06 05:22:10 +01:00
visualizer = parentTransform.gameObject.AddComponent<StrategicDisplay>();
2026-01-06 04:07:34 +01:00
visualizer.Initialize();
}
var traverse = Traverse.Create(renderer);
var model = traverse.Property("model").GetValue();
2026-01-06 05:22:10 +01:00
if (model == null) { visualizer.Hide(); return; }
2026-01-06 04:07:34 +01:00
var children = Traverse.Create(model).Field("Children").GetValue() as IEnumerable;
if (children == null) children = Traverse.Create(model).Field("children").GetValue() as IEnumerable;
2026-01-06 05:22:10 +01:00
string orderType = "";
bool isSpecial = false;
int strength = 0;
bool found = false;
2026-01-06 04:07:34 +01:00
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;
2026-01-06 05:22:10 +01:00
if (valuesDict != null && valuesDict.Contains(400003))
2026-01-06 04:07:34 +01:00
{
2026-01-06 05:22:10 +01:00
object typeCont = valuesDict[400003];
object typeVal = Traverse.Create(typeCont).Property("Value").GetValue();
2026-01-06 04:07:34 +01:00
2026-01-06 05:22:10 +01:00
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
2026-01-06 04:07:34 +01:00
{
2026-01-06 05:22:10 +01:00
object strCont = valuesDict[400004];
object strVal = Traverse.Create(strCont).Property("Value").GetValue();
int.TryParse(strVal?.ToString(), out strength);
2026-01-06 04:07:34 +01:00
}
2026-01-06 05:22:10 +01:00
found = true;
break;
2026-01-06 04:07:34 +01:00
}
}
}
}
}
2026-01-06 05:22:10 +01:00
if (!found)
{
visualizer.Hide();
return;
}
2026-01-06 04:07:34 +01:00
2026-01-06 05:22:10 +01:00
// Generar clave lógica
string generatedKey = $"{orderType}_{strength}";
if (isSpecial) generatedKey += "_Star";
2026-01-06 04:07:34 +01:00
2026-01-06 05:22:10 +01:00
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);
}
2026-01-06 04:07:34 +01:00
}
2026-01-06 15:22:22 +01:00
// Función auxiliar que podrías llamar desde tu parche de Harmony
public static Texture2D MakeTextureTransparent(Texture originalTexture)
{
if (originalTexture == null) return null;
// 1. Crear una RenderTexture temporal para poder leer la textura original
RenderTexture tmp = RenderTexture.GetTemporary(
originalTexture.width,
originalTexture.height,
0,
RenderTextureFormat.Default,
RenderTextureReadWrite.Linear);
// 2. Copiar la textura original a la RenderTexture (esto "desbloquea" los píxeles)
Graphics.Blit(originalTexture, tmp);
// 3. Activar la RenderTexture para leerla
RenderTexture previous = RenderTexture.active;
RenderTexture.active = tmp;
// 4. Crear una nueva Texture2D leíble
Texture2D newTexture = new Texture2D(originalTexture.width, originalTexture.height);
newTexture.ReadPixels(new Rect(0, 0, tmp.width, tmp.height), 0, 0);
// 5. MODIFICAR LOS PÍXELES (Aquí ocurre la magia)
Color[] pixels = newTexture.GetPixels();
float width = newTexture.width;
float height = newTexture.height;
Vector2 center = new Vector2(width / 2f, height / 2f);
float radius = (Mathf.Min(width, height) / 2f); // Radio máximo
for (int i = 0; i < pixels.Length; i++)
{
// --- Opción A: Máscara Redonda (Matemática) ---
int x = i % newTexture.width;
int y = i / newTexture.width;
float dist = Vector2.Distance(new Vector2(x, y), center);
if (dist > radius)
{
pixels[i] = Color.clear; // Hacemos transparente lo que esté fuera del círculo
}
// --- Opción B: Quitar el negro (Si prefieres por color) ---
// if (pixels[i].r < 0.1f && pixels[i].g < 0.1f && pixels[i].b < 0.1f)
// {
// pixels[i] = Color.clear;
// }
}
newTexture.SetPixels(pixels);
newTexture.Apply();
// 6. Limpieza
RenderTexture.active = previous;
RenderTexture.ReleaseTemporary(tmp);
return newTexture;
}
2026-01-06 04:07:34 +01:00
}
2026-01-06 05:22:10 +01:00
// --- VISUALIZADOR ---
public class StrategicDisplay : MonoBehaviour
2026-01-06 04:07:34 +01:00
{
private GameObject displayObj;
2026-01-06 05:22:10 +01:00
private Image iconImage;
private TextMeshProUGUI debugText;
private bool isInitialized = false;
2026-01-06 05:50:51 +01:00
private bool hasContent = false;
void Update()
{
if (!isInitialized || displayObj == null) return;
bool shouldShow = hasContent && Input.GetKey(KeyCode.V);
if (displayObj.activeSelf != shouldShow)
{
displayObj.SetActive(shouldShow);
}
}
2026-01-06 04:07:34 +01:00
public void Initialize()
{
2026-01-06 05:22:10 +01:00
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<RectTransform>();
rt.sizeDelta = new Vector2(45, 45); // Tamaño del icono
iconImage = displayObj.AddComponent<Image>();
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<RectTransform>();
textRt.anchoredPosition = Vector2.zero;
debugText = textObj.AddComponent<TextMeshProUGUI>();
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();
2026-01-06 05:50:51 +01:00
// Inicialmente oculto
displayObj.SetActive(false);
2026-01-06 05:22:10 +01:00
isInitialized = true;
}
catch (System.Exception e)
{
Debug.LogWarning("Error UI: " + e.Message);
if (displayObj != null) Destroy(displayObj);
isInitialized = false;
}
2026-01-06 04:07:34 +01:00
}
2026-01-06 05:22:10 +01:00
public void Hide()
2026-01-06 04:07:34 +01:00
{
2026-01-06 05:50:51 +01:00
hasContent = false;
2026-01-06 05:22:10 +01:00
if (displayObj != null && displayObj.activeSelf) displayObj.SetActive(false);
}
2026-01-06 04:07:34 +01:00
2026-01-06 05:22:10 +01:00
public void ShowIcon(Sprite s)
{
if (!isInitialized) Initialize();
if (!isInitialized) return;
2026-01-06 04:07:34 +01:00
2026-01-06 05:22:10 +01:00
// Aseguramos orden de dibujado (Encima de todo)
displayObj.transform.SetAsLastSibling();
if (s != null)
2026-01-06 04:07:34 +01:00
{
2026-01-06 05:22:10 +01:00
iconImage.sprite = s;
iconImage.enabled = true;
if (debugText != null) debugText.text = "";
2026-01-06 05:50:51 +01:00
hasContent = true;
2026-01-06 04:07:34 +01:00
}
}
2026-01-06 05:22:10 +01:00
public void ShowText(string t)
{
if (!isInitialized) Initialize();
if (!isInitialized) return;
displayObj.transform.SetAsLastSibling();
if (iconImage != null) iconImage.enabled = false;
if (debugText != null) debugText.text = t;
2026-01-06 05:50:51 +01:00
hasContent = true;
2026-01-06 05:22:10 +01:00
}
2026-01-06 04:07:34 +01:00
}
}