using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using UnityEngine; namespace IdleSpectator; /// /// Polls live WarManager state and registers ongoing war interest candidates. /// public static class WarInterestFeed { public static void EmitFromWarObject(object war, string phase = "active") { if (war == null || AgentHarness.Busy) { return; } TryRegisterWar(war, phase); } public static void Tick() { if (AgentHarness.Busy) { return; } object warsManager = ResolveWarsManager(); if (warsManager == null) { return; } IEnumerable active = InvokeEnumerable(warsManager, "getActiveWars") ?? InvokeEnumerable(warsManager, "getWars"); if (active == null) { return; } int registered = 0; foreach (object war in active) { if (war == null || registered >= 6) { break; } if (TryRegisterWar(war, "active")) { registered++; } } } private static bool TryRegisterWar(object war, string phase) { string warTypeId = ReadWarTypeId(war); WarTypeInterestEntry entry = WarTypeInterestCatalog.GetOrFallback(warTypeId); if (!entry.CreatesInterest) { return false; } object attacker = ReadPropOrField(war, "main_attacker") ?? Invoke(war, "get_main_attacker"); object defender = ReadPropOrField(war, "main_defender") ?? Invoke(war, "get_main_defender"); string attackerName = ReadMetaName(attacker); string defenderName = ReadMetaName(defender); string labelPair = string.IsNullOrEmpty(defenderName) ? attackerName : attackerName + " vs " + defenderName; if (string.IsNullOrEmpty(labelPair)) { labelPair = ReadString(war, "name") ?? warTypeId ?? "war"; } Vector3 position = Vector3.zero; Actor follow = null; if (!TryLocateWar(attacker, defender, out position, out follow)) { return false; } string phaseKey = string.IsNullOrEmpty(phase) ? "active" : phase; string key = "war:" + phaseKey + ":" + (ReadString(war, "id") ?? labelPair) + ":" + (warTypeId ?? "normal"); string label = WarTypeInterestCatalog.MakeLabel(entry, labelPair); if (phaseKey == "new") { label = "War begins: " + labelPair; } else if (phaseKey == "end") { label = "War ends: " + labelPair; } float strength = entry.EventStrength; if (phaseKey == "end") { strength = Mathf.Max(60f, strength - 10f); } InterestOwnership owns = InterestOwnership.Signal; EventFeedUtil.Register( key, "war", entry.Category, label, warTypeId ?? "war", strength, owns, position, follow, minWatch: 6f, maxWatch: 30f); return true; } private static bool TryLocateWar(object attacker, object defender, out Vector3 position, out Actor follow) { position = Vector3.zero; follow = null; if (TryKingdomAnchor(attacker, out position, out follow)) { return true; } if (TryKingdomAnchor(defender, out position, out follow)) { return true; } // No kingdom unit found - location-only if we have a capital position is handled above. // Never invent a global random unit as war subject. return false; } private static bool TryKingdomAnchor(object kingdom, out Vector3 position, out Actor follow) { position = Vector3.zero; follow = null; if (kingdom == null) { return false; } try { object capital = ReadPropOrField(kingdom, "capital") ?? Invoke(kingdom, "getCapital"); if (capital != null) { object posObj = ReadPropOrField(capital, "current_position") ?? ReadPropOrField(capital, "city_center"); if (posObj is Vector3 v && v != Vector3.zero) { position = v; } else if (posObj is Vector2 v2) { position = new Vector3(v2.x, v2.y, 0f); } } object king = ReadPropOrField(kingdom, "king"); if (king is Actor actorKing && actorKing.isAlive()) { follow = actorKing; position = actorKing.current_position; return true; } if (position != Vector3.zero) { return true; } } catch { // ignore } return false; } private static object ResolveWarsManager() { try { object world = World.world; if (world == null) { return null; } object wars = ReadPropOrField(world, "wars"); if (wars != null) { return wars; } return typeof(AssetManager).Assembly.GetType("WarManager"); } catch { return null; } } private static string ReadWarTypeId(object war) { try { object warType = ReadPropOrField(war, "war_type") ?? Invoke(war, "get_war_type"); if (warType == null) { return "normal"; } if (warType is string s) { return s; } string id = ReadString(warType, "id"); return string.IsNullOrEmpty(id) ? "normal" : id; } catch { return "normal"; } } private static string ReadMetaName(object meta) { if (meta == null) { return ""; } try { object name = Invoke(meta, "getName") ?? ReadPropOrField(meta, "name") ?? ReadString(meta, "name"); return name as string ?? ""; } catch { return ""; } } private static IEnumerable InvokeEnumerable(object target, string methodName) { try { MethodInfo method = target.GetType().GetMethod(methodName, Type.EmptyTypes); object result = method?.Invoke(target, null); return result as IEnumerable; } catch { return null; } } private static object Invoke(object target, string methodName) { if (target == null || string.IsNullOrEmpty(methodName)) { return null; } try { MethodInfo method = target.GetType().GetMethod(methodName, Type.EmptyTypes); return method?.Invoke(target, null); } catch { return null; } } private static object ReadPropOrField(object target, string name) { if (target == null || string.IsNullOrEmpty(name)) { return null; } try { Type type = target.GetType(); PropertyInfo prop = type.GetProperty(name); if (prop != null) { return prop.GetValue(target, null); } FieldInfo field = type.GetField(name); return field?.GetValue(target); } catch { return null; } } private static string ReadString(object target, string name) { return ReadPropOrField(target, name) as string; } private static long SafeActorId(Actor actor) { if (actor == null) { return 0; } try { return actor.getID(); } catch { return 0; } } }