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 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)) { registered++; } } } private static bool TryRegisterWar(object war) { 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 key = "war:" + (ReadString(war, "id") ?? labelPair) + ":" + (warTypeId ?? "normal"); string label = WarTypeInterestCatalog.MakeLabel(entry, labelPair); var candidate = new InterestCandidate { Key = key, LeadKind = InterestLeadKind.EventLed, Category = entry.Category, Source = "war", EventStrength = entry.EventStrength, VisualConfidence = follow != null ? 0.65f : 0.35f, Position = position, FollowUnit = follow, SubjectId = follow != null ? SafeActorId(follow) : 0, Label = label, AssetId = warTypeId ?? "war", KingdomKey = attackerName, CreatedAt = Time.unscaledTime, LastSeenAt = Time.unscaledTime, ExpiresAt = Time.unscaledTime + 25f, MinWatch = 6f, MaxWatch = 30f, Completion = InterestCompletionKind.FixedDwell }; InterestScoring.ScoreCheap(candidate); InterestRegistry.Upsert(candidate); 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; } // Fall back to any living unit. try { if (World.world?.units != null) { foreach (Actor actor in World.world.units) { if (actor == null || !actor.isAlive()) { continue; } follow = actor; position = actor.current_position; return true; } } } catch { // ignore } 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; } } }