worldbox-observer-mod/IdleSpectator/MutationDiscoveryHarness.cs

829 lines
32 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using UnityEngine;
namespace IdleSpectator;
public sealed class MutationDiscoveryResult
{
public bool Passed;
public string Detail = "";
public int Managers;
public int ManagerMethods;
public int ActorMethods;
public int BehTypes;
public int Libraries;
public int LibraryAssets;
public int Gaps;
}
/// <summary>
/// Discovers event-relevant mutation paths from live game assemblies and AssetManager.
/// Writes TSVs under .harness/ for the idle-camera coverage plan.
/// </summary>
public static class MutationDiscoveryHarness
{
private static readonly string[] ManagerNameNeedles =
{
"Manager", "Keeper"
};
private static readonly string[] MethodPrefixNeedles =
{
"new", "add", "remove", "set", "become", "start", "finish", "cancel",
"create", "destroy", "die", "kill", "birth", "clear", "leave", "join",
"make", "end", "load", "spawn", "generate", "burn", "write"
};
private static readonly string[] ActorMethodNeedles =
{
"lover", "friend", "family", "child", "parent", "baby", "born", "birth",
"mate", "breed", "social", "clan", "king", "leader", "trait", "status",
"happiness", "plot", "army", "war", "alliance", "culture", "religion",
"language", "book", "item", "boat", "home", "house", "city", "kingdom",
"die", "kill", "task", "job"
};
private static readonly string[] BehNeedles =
{
"Lover", "Friend", "Family", "Social", "Child", "Baby", "Birth", "Plot",
"Clan", "Army", "War", "Book", "Build", "Boat", "Trade", "Era", "Age",
"Trait", "Religion", "Culture", "Language", "Alliance", "King", "Marry"
};
private static readonly string[] LibraryFields =
{
"actor_library", "status", "happiness_library", "world_log_library",
"disasters", "war_types_library", "traits", "plots_library", "plot_category_library",
"era_library", "buildings", "architecture_library", "city_build_orders",
"culture_traits", "religion_traits", "clan_traits", "language_traits",
"subspecies_traits", "kingdoms_traits", "book_types", "items", "items_modifiers",
"spells", "powers", "combat_action_library", "decisions_library",
"loyalty_library", "opinion_library", "knowledge_library", "gene_library",
"phenotype_library", "communication_library", "story_library",
"world_laws_library", "biome_library", "citizen_job_library", "professions",
"personalities", "tasks_actor"
};
private static readonly HashSet<string> AlreadyWired =
new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"Actor.changeHappiness",
"Actor.checkHappinessChangeFromDeathEvent",
"Actor.birthEvent",
"Actor.becomeLoversWith",
"Actor.setBestFriend",
"Actor.newKillAction",
"Actor.die",
"Actor.setTask",
"WorldLogMessageExtensions.add",
"BaseSimObject.addNewStatusEffect",
"Status.finish",
"SubspeciesManager.newSpecies",
"BehPollinate.execute",
"BehUnloadResources.execute",
"BehAttackActorHuntingTarget.execute",
"BehCityActorRemoveFire.execute",
"BehTryToSocialize.execute",
"BehPlantCrops.execute",
"BehCityActorFertilizeCrop.execute",
"BehThrowResources.execute",
"BehBuildTarget.execute",
"BehPoopOutside.execute",
"BehPoopInside.execute",
"BehBoatFishing.execute",
"BehBoatCollectFish.execute",
"BehClaimZoneForCityActorBorder.execute",
"InterestFeeds.OnWorldLogMessage",
"InterestFeeds.OnStatusChange",
"InterestFeeds.OnActivityNote",
"InterestFeeds.OnChronicleMilestone",
"WarInterestFeed.Tick",
"WorldActivityScanner.FindHottestBattle",
"SpeciesDiscovery"
};
public static MutationDiscoveryResult Run(string outputDirectory)
{
Assembly gameAsm = typeof(Actor).Assembly;
var managersTsv = new StringBuilder();
managersTsv.AppendLine("type\tmethod\tarity\tstatic\tkind_guess\talready_wired\tnotes");
var actorTsv = new StringBuilder();
actorTsv.AppendLine("type\tmethod\tarity\tstatic\tneedle\talready_wired\tnotes");
var behTsv = new StringBuilder();
behTsv.AppendLine("type\tmethod\tarity\tneedle\talready_wired\tnotes");
var libTsv = new StringBuilder();
libTsv.AppendLine("field\tcount\tsample_ids\tnotes");
var gapsTsv = new StringBuilder();
gapsTsv.AppendLine(
"kind\ttype\tmethod_or_field\tevent_worthy\tsuggested_ownership\talready_wired\treason");
int managerCount = 0;
int managerMethods = 0;
int actorMethods = 0;
int behTypes = 0;
int libraries = 0;
int libraryAssets = 0;
int gaps = 0;
Type[] types;
try
{
types = gameAsm.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
types = ex.Types ?? Array.Empty<Type>();
}
var managerTypes = new List<Type>();
var behTypesList = new List<Type>();
Type actorType = typeof(Actor);
Type baseSimType = typeof(BaseSimObject);
for (int i = 0; i < types.Length; i++)
{
Type t = types[i];
if (t == null || string.IsNullOrEmpty(t.Name))
{
continue;
}
string name = t.Name;
if (IsManagerish(name))
{
managerTypes.Add(t);
}
if (name.StartsWith("Beh", StringComparison.Ordinal) && MatchesAny(name, BehNeedles))
{
behTypesList.Add(t);
}
}
managerTypes.Sort((a, b) => string.CompareOrdinal(a.FullName, b.FullName));
for (int i = 0; i < managerTypes.Count; i++)
{
Type t = managerTypes[i];
managerCount++;
MethodInfo[] methods = SafeMethods(t);
for (int m = 0; m < methods.Length; m++)
{
MethodInfo method = methods[m];
if (method == null || method.IsSpecialName)
{
continue;
}
if (!MethodLooksMutating(method.Name))
{
continue;
}
managerMethods++;
string key = t.Name + "." + method.Name;
bool wired = AlreadyWired.Contains(key);
string kind = GuessManagerKind(t.Name, method.Name);
managersTsv.Append(t.Name).Append('\t')
.Append(method.Name).Append('\t')
.Append(method.GetParameters().Length).Append('\t')
.Append(method.IsStatic ? "1" : "0").Append('\t')
.Append(kind).Append('\t')
.Append(wired ? "1" : "0").Append('\t')
.Append(Escape(method.ToString())).AppendLine();
if (!wired && IsEventWorthyManager(t.Name, method.Name))
{
gaps++;
gapsTsv.Append("ManagerGenesis").Append('\t')
.Append(t.Name).Append('\t')
.Append(method.Name).Append('\t')
.Append("Yes").Append('\t')
.Append(SuggestOwnership(t.Name, method.Name)).Append('\t')
.Append("0").Append('\t')
.Append("unwired_manager_mutation").AppendLine();
}
}
}
DumpTypeMethods(actorType, ActorMethodNeedles, actorTsv, gapsTsv, ref actorMethods, ref gaps);
DumpTypeMethods(baseSimType, ActorMethodNeedles, actorTsv, gapsTsv, ref actorMethods, ref gaps);
// Also scan Actor for lover/friend clear-style methods even if needle-filtered narrowly.
DumpExtraActorRelationMethods(actorType, actorTsv, gapsTsv, ref actorMethods, ref gaps);
behTypesList.Sort((a, b) => string.CompareOrdinal(a.Name, b.Name));
for (int i = 0; i < behTypesList.Count; i++)
{
Type t = behTypesList[i];
behTypes++;
string needle = FirstMatch(t.Name, BehNeedles);
MethodInfo exec = t.GetMethod("execute", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
string methodName = exec != null ? "execute" : "";
string key = t.Name + (string.IsNullOrEmpty(methodName) ? "" : "." + methodName);
bool wired = AlreadyWired.Contains(key);
int arity = exec != null ? exec.GetParameters().Length : 0;
behTsv.Append(t.Name).Append('\t')
.Append(methodName).Append('\t')
.Append(arity).Append('\t')
.Append(needle).Append('\t')
.Append(wired ? "1" : "0").Append('\t')
.Append("BehPulse").AppendLine();
if (!wired && IsEventWorthyBeh(t.Name))
{
gaps++;
gapsTsv.Append("BehPulse").Append('\t')
.Append(t.Name).Append('\t')
.Append(methodName).Append('\t')
.Append(BehSoft(t.Name) ? "Soft" : "Yes").Append('\t')
.Append(BehSoft(t.Name) ? "Ambient" : "Signal").Append('\t')
.Append("0").Append('\t')
.Append("unwired_beh").AppendLine();
}
}
for (int i = 0; i < LibraryFields.Length; i++)
{
string field = LibraryFields[i];
List<string> ids = EnumerateLibraryIds(field);
libraries++;
libraryAssets += ids.Count;
string sample = "";
int sampleN = Math.Min(5, ids.Count);
for (int s = 0; s < sampleN; s++)
{
if (s > 0)
{
sample += ",";
}
sample += ids[s];
}
bool known = field == "actor_library"
|| field == "status"
|| field == "happiness_library"
|| field == "world_log_library"
|| field == "disasters"
|| field == "war_types_library"
|| field == "traits"
|| field == "tasks_actor";
libTsv.Append(field).Append('\t')
.Append(ids.Count).Append('\t')
.Append(Escape(sample)).Append('\t')
.Append(known ? "partially_or_fully_wired" : "library_unwired_for_events").AppendLine();
if (!known && ids.Count > 0)
{
gaps++;
gapsTsv.Append("LibraryAsset").Append('\t')
.Append("AssetManager").Append('\t')
.Append(field).Append('\t')
.Append("Yes").Append('\t')
.Append("Signal").Append('\t')
.Append("0").Append('\t')
.Append("count=" + ids.Count).AppendLine();
}
// Full id lists for priority event catalogs.
if (!string.IsNullOrEmpty(outputDirectory)
&& (field == "plots_library"
|| field == "plot_category_library"
|| field == "era_library"
|| field == "book_types"
|| field == "traits"
|| field == "buildings"))
{
try
{
var full = new StringBuilder();
full.AppendLine("id");
for (int s = 0; s < ids.Count; s++)
{
full.AppendLine(ids[s]);
}
File.WriteAllText(
Path.Combine(outputDirectory, "library-" + field + ".tsv"),
full.ToString());
}
catch
{
// ignore
}
}
}
// World / MapBox live manager fields
AppendWorldFields(gapsTsv, managersTsv, ref gaps, ref managerMethods);
try
{
if (!string.IsNullOrEmpty(outputDirectory))
{
Directory.CreateDirectory(outputDirectory);
File.WriteAllText(Path.Combine(outputDirectory, "mutation_managers.tsv"), managersTsv.ToString());
File.WriteAllText(Path.Combine(outputDirectory, "mutation_actor.tsv"), actorTsv.ToString());
File.WriteAllText(Path.Combine(outputDirectory, "mutation_beh.tsv"), behTsv.ToString());
File.WriteAllText(Path.Combine(outputDirectory, "mutation_libraries.tsv"), libTsv.ToString());
File.WriteAllText(Path.Combine(outputDirectory, "mutation_gaps.tsv"), gapsTsv.ToString());
}
}
catch (Exception ex)
{
Debug.LogWarning("[IdleSpectator] mutation discovery write failed: " + ex.Message);
}
return new MutationDiscoveryResult
{
Passed = managerCount > 0 && libraries > 0,
Managers = managerCount,
ManagerMethods = managerMethods,
ActorMethods = actorMethods,
BehTypes = behTypes,
Libraries = libraries,
LibraryAssets = libraryAssets,
Gaps = gaps,
Detail =
$"managers={managerCount} managerMethods={managerMethods} actorMethods={actorMethods} "
+ $"beh={behTypes} libraries={libraries} libraryAssets={libraryAssets} gaps={gaps}"
};
}
private static void AppendWorldFields(
StringBuilder gapsTsv,
StringBuilder managersTsv,
ref int gaps,
ref int managerMethods)
{
object world = null;
try
{
world = World.world;
}
catch
{
// ignore
}
if (world == null)
{
return;
}
string[] fields =
{
"plots", "wars", "alliances", "clans", "cultures", "religions", "languages",
"families", "armies", "books", "buildings", "items", "subspecies", "cities",
"kingdoms", "diplomacy", "era_manager", "earthquake_manager", "units"
};
Type worldType = world.GetType();
for (int i = 0; i < fields.Length; i++)
{
string name = fields[i];
object value = null;
try
{
FieldInfo f = worldType.GetField(name);
PropertyInfo p = worldType.GetProperty(name);
value = f != null ? f.GetValue(world) : p?.GetValue(world, null);
}
catch
{
// ignore
}
string typeName = value != null ? value.GetType().Name : "null";
managersTsv.Append("World.").Append(name).Append('\t')
.Append("(instance)").Append('\t')
.Append("0").Append('\t')
.Append("0").Append('\t')
.Append("PollState").Append('\t')
.Append(name == "wars" || name == "units" || name == "subspecies" ? "1" : "0").Append('\t')
.Append(typeName).AppendLine();
managerMethods++;
bool wired = name == "wars" || name == "units" || name == "subspecies";
if (!wired && value != null)
{
gaps++;
gapsTsv.Append("PollState").Append('\t')
.Append("World").Append('\t')
.Append(name).Append('\t')
.Append("Yes").Append('\t')
.Append("Signal").Append('\t')
.Append("0").Append('\t')
.Append("world_field=" + typeName).AppendLine();
}
}
}
private static void DumpTypeMethods(
Type type,
string[] needles,
StringBuilder actorTsv,
StringBuilder gapsTsv,
ref int actorMethods,
ref int gaps)
{
MethodInfo[] methods = SafeMethods(type);
for (int i = 0; i < methods.Length; i++)
{
MethodInfo method = methods[i];
if (method == null || method.IsSpecialName)
{
continue;
}
string needle = FirstMatch(method.Name, needles);
if (string.IsNullOrEmpty(needle) && !MethodLooksMutating(method.Name))
{
continue;
}
if (string.IsNullOrEmpty(needle))
{
needle = "mutate";
}
actorMethods++;
string key = type.Name + "." + method.Name;
bool wired = AlreadyWired.Contains(key);
actorTsv.Append(type.Name).Append('\t')
.Append(method.Name).Append('\t')
.Append(method.GetParameters().Length).Append('\t')
.Append(method.IsStatic ? "1" : "0").Append('\t')
.Append(needle).Append('\t')
.Append(wired ? "1" : "0").Append('\t')
.Append(Escape(method.ToString())).AppendLine();
if (!wired && IsEventWorthyActor(method.Name))
{
gaps++;
gapsTsv.Append("ActorMutation").Append('\t')
.Append(type.Name).Append('\t')
.Append(method.Name).Append('\t')
.Append("Yes").Append('\t')
.Append(SuggestOwnership("Actor", method.Name)).Append('\t')
.Append("0").Append('\t')
.Append("unwired_actor_mutation").AppendLine();
}
}
}
private static void DumpExtraActorRelationMethods(
Type actorType,
StringBuilder actorTsv,
StringBuilder gapsTsv,
ref int actorMethods,
ref int gaps)
{
string[] extra =
{
"removeLover", "clearLover", "setLover", "getLover", "hasLover",
"removeBestFriend", "clearBestFriend", "getBestFriend",
"addChild", "removeChild", "makeBaby", "haveChild",
"addTrait", "removeTrait", "setPlot", "leavePlot", "finishPlot"
};
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
MethodInfo[] found = actorType.GetMethods(
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
for (int m = 0; m < found.Length; m++)
{
MethodInfo method = found[m];
if (method == null || method.IsSpecialName)
{
continue;
}
bool match = false;
for (int i = 0; i < extra.Length; i++)
{
if (method.Name.Equals(extra[i], StringComparison.OrdinalIgnoreCase)
|| method.Name.StartsWith(extra[i], StringComparison.OrdinalIgnoreCase))
{
match = true;
break;
}
}
if (!match || !seen.Add(method.Name))
{
continue;
}
actorMethods++;
string key = actorType.Name + "." + method.Name;
bool wired = AlreadyWired.Contains(key);
actorTsv.Append(actorType.Name).Append('\t')
.Append(method.Name).Append('\t')
.Append(method.GetParameters().Length).Append('\t')
.Append(method.IsStatic ? "1" : "0").Append('\t')
.Append("relation").Append('\t')
.Append(wired ? "1" : "0").Append('\t')
.Append("extra_relation_scan").AppendLine();
if (!wired && !method.Name.StartsWith("get", StringComparison.OrdinalIgnoreCase)
&& !method.Name.StartsWith("has", StringComparison.OrdinalIgnoreCase))
{
gaps++;
gapsTsv.Append("ActorMutation").Append('\t')
.Append(actorType.Name).Append('\t')
.Append(method.Name).Append('\t')
.Append("Yes").Append('\t')
.Append("Signal").Append('\t')
.Append("0").Append('\t')
.Append("relation_lifecycle").AppendLine();
}
}
}
private static List<string> EnumerateLibraryIds(string fieldName)
{
var ids = new List<string>();
try
{
object lib = typeof(AssetManager).GetField(fieldName)?.GetValue(null);
if (lib == null)
{
return ids;
}
object listObj = lib.GetType().GetField("list")?.GetValue(lib)
?? lib.GetType().GetProperty("list")?.GetValue(lib, null);
System.Collections.IList list = listObj as System.Collections.IList;
if (list == null)
{
return ids;
}
for (int i = 0; i < list.Count; i++)
{
object asset = list[i];
object idObj = asset?.GetType().GetField("id")?.GetValue(asset)
?? asset?.GetType().GetProperty("id")?.GetValue(asset, null);
string id = idObj as string;
if (!string.IsNullOrEmpty(id))
{
ids.Add(id);
}
}
}
catch
{
// Library missing in this build.
}
return ids;
}
private static MethodInfo[] SafeMethods(Type type)
{
try
{
return type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly);
}
catch
{
return Array.Empty<MethodInfo>();
}
}
private static bool IsManagerish(string name)
{
for (int i = 0; i < ManagerNameNeedles.Length; i++)
{
if (name.IndexOf(ManagerNameNeedles[i], StringComparison.OrdinalIgnoreCase) >= 0)
{
return true;
}
}
return false;
}
private static bool MethodLooksMutating(string name)
{
string n = name ?? "";
for (int i = 0; i < MethodPrefixNeedles.Length; i++)
{
if (n.StartsWith(MethodPrefixNeedles[i], StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}
private static bool MatchesAny(string value, string[] needles)
{
return !string.IsNullOrEmpty(FirstMatch(value, needles));
}
private static string FirstMatch(string value, string[] needles)
{
if (string.IsNullOrEmpty(value) || needles == null)
{
return "";
}
for (int i = 0; i < needles.Length; i++)
{
if (value.IndexOf(needles[i], StringComparison.OrdinalIgnoreCase) >= 0)
{
return needles[i];
}
}
return "";
}
private static string GuessManagerKind(string typeName, string methodName)
{
if (methodName.StartsWith("new", StringComparison.OrdinalIgnoreCase)
|| methodName.StartsWith("create", StringComparison.OrdinalIgnoreCase)
|| methodName.StartsWith("generate", StringComparison.OrdinalIgnoreCase))
{
return "ManagerGenesis";
}
if (methodName.StartsWith("remove", StringComparison.OrdinalIgnoreCase)
|| methodName.StartsWith("destroy", StringComparison.OrdinalIgnoreCase)
|| methodName.StartsWith("finish", StringComparison.OrdinalIgnoreCase)
|| methodName.StartsWith("cancel", StringComparison.OrdinalIgnoreCase)
|| methodName.StartsWith("end", StringComparison.OrdinalIgnoreCase))
{
return "ManagerEnd";
}
return "ManagerMutation";
}
private static bool IsEventWorthyManager(string typeName, string methodName)
{
string t = typeName ?? "";
string m = methodName ?? "";
if (t.IndexOf("Debug", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("UI", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Save", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Upload", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Tooltip", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Nameplate", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Locale", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Asset", StringComparison.OrdinalIgnoreCase) >= 0 && t.IndexOf("Manager", StringComparison.OrdinalIgnoreCase) >= 0
&& t != "AssetManager")
{
// Keep AssetManager out of genesis gaps; libraries handled separately.
if (t.IndexOf("ActorManager", StringComparison.OrdinalIgnoreCase) < 0
&& t.IndexOf("BuildingManager", StringComparison.OrdinalIgnoreCase) < 0
&& t.IndexOf("WarManager", StringComparison.OrdinalIgnoreCase) < 0
&& t.IndexOf("PlotManager", StringComparison.OrdinalIgnoreCase) < 0
&& t.IndexOf("ClanManager", StringComparison.OrdinalIgnoreCase) < 0
&& t.IndexOf("CultureManager", StringComparison.OrdinalIgnoreCase) < 0
&& t.IndexOf("ReligionManager", StringComparison.OrdinalIgnoreCase) < 0
&& t.IndexOf("LanguageManager", StringComparison.OrdinalIgnoreCase) < 0
&& t.IndexOf("FamilyManager", StringComparison.OrdinalIgnoreCase) < 0
&& t.IndexOf("ArmyManager", StringComparison.OrdinalIgnoreCase) < 0
&& t.IndexOf("BookManager", StringComparison.OrdinalIgnoreCase) < 0
&& t.IndexOf("ItemManager", StringComparison.OrdinalIgnoreCase) < 0
&& t.IndexOf("AllianceManager", StringComparison.OrdinalIgnoreCase) < 0
&& t.IndexOf("CityManager", StringComparison.OrdinalIgnoreCase) < 0
&& t.IndexOf("KingdomManager", StringComparison.OrdinalIgnoreCase) < 0
&& t.IndexOf("DiplomacyManager", StringComparison.OrdinalIgnoreCase) < 0
&& t.IndexOf("WorldAgeManager", StringComparison.OrdinalIgnoreCase) < 0
&& t.IndexOf("SubspeciesManager", StringComparison.OrdinalIgnoreCase) < 0
&& t.IndexOf("BattleKeeper", StringComparison.OrdinalIgnoreCase) < 0)
{
return false;
}
}
// Focus on sim managers
bool simManager =
t.IndexOf("Plot", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("War", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Clan", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Culture", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Religion", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Language", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Family", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Army", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Book", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Item", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Building", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Alliance", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("City", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Kingdom", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Diplomacy", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("WorldAge", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Subspecies", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("ActorManager", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("BattleKeeper", StringComparison.OrdinalIgnoreCase) >= 0;
if (!simManager)
{
return false;
}
return m.StartsWith("new", StringComparison.OrdinalIgnoreCase)
|| m.StartsWith("create", StringComparison.OrdinalIgnoreCase)
|| m.StartsWith("generate", StringComparison.OrdinalIgnoreCase)
|| m.StartsWith("add", StringComparison.OrdinalIgnoreCase)
|| m.StartsWith("remove", StringComparison.OrdinalIgnoreCase)
|| m.StartsWith("destroy", StringComparison.OrdinalIgnoreCase)
|| m.StartsWith("finish", StringComparison.OrdinalIgnoreCase)
|| m.StartsWith("cancel", StringComparison.OrdinalIgnoreCase)
|| m.StartsWith("start", StringComparison.OrdinalIgnoreCase)
|| m.StartsWith("set", StringComparison.OrdinalIgnoreCase)
|| m.StartsWith("end", StringComparison.OrdinalIgnoreCase)
|| m.StartsWith("burn", StringComparison.OrdinalIgnoreCase)
|| m.IndexOf("War", StringComparison.OrdinalIgnoreCase) >= 0
|| m.IndexOf("Age", StringComparison.OrdinalIgnoreCase) >= 0
|| m.IndexOf("Plot", StringComparison.OrdinalIgnoreCase) >= 0
|| m.IndexOf("Friend", StringComparison.OrdinalIgnoreCase) >= 0;
}
private static bool IsEventWorthyActor(string methodName)
{
string m = methodName ?? "";
return m.IndexOf("lover", StringComparison.OrdinalIgnoreCase) >= 0
|| m.IndexOf("friend", StringComparison.OrdinalIgnoreCase) >= 0
|| m.IndexOf("child", StringComparison.OrdinalIgnoreCase) >= 0
|| m.IndexOf("birth", StringComparison.OrdinalIgnoreCase) >= 0
|| m.IndexOf("baby", StringComparison.OrdinalIgnoreCase) >= 0
|| m.IndexOf("trait", StringComparison.OrdinalIgnoreCase) >= 0
|| m.IndexOf("plot", StringComparison.OrdinalIgnoreCase) >= 0
|| m.IndexOf("die", StringComparison.OrdinalIgnoreCase) >= 0
|| m.IndexOf("kill", StringComparison.OrdinalIgnoreCase) >= 0
|| m.IndexOf("king", StringComparison.OrdinalIgnoreCase) >= 0
|| m.IndexOf("clan", StringComparison.OrdinalIgnoreCase) >= 0
|| m.IndexOf("army", StringComparison.OrdinalIgnoreCase) >= 0
|| m.IndexOf("book", StringComparison.OrdinalIgnoreCase) >= 0
|| m.IndexOf("home", StringComparison.OrdinalIgnoreCase) >= 0
|| m.IndexOf("house", StringComparison.OrdinalIgnoreCase) >= 0;
}
private static bool IsEventWorthyBeh(string typeName)
{
string t = typeName ?? "";
// Skip pure navigation helpers
if (t.IndexOf("FindTile", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("GoTo", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("LookAt", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("CheckExistence", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("CheckLimit", StringComparison.OrdinalIgnoreCase) >= 0)
{
return false;
}
return true;
}
private static bool BehSoft(string typeName)
{
string t = typeName ?? "";
return t.IndexOf("Social", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Talk", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Check", StringComparison.OrdinalIgnoreCase) >= 0
|| t.IndexOf("Follow", StringComparison.OrdinalIgnoreCase) >= 0;
}
private static string SuggestOwnership(string typeName, string methodName)
{
string blob = (typeName ?? "") + "." + (methodName ?? "");
if (blob.IndexOf("War", StringComparison.OrdinalIgnoreCase) >= 0
|| blob.IndexOf("Plot", StringComparison.OrdinalIgnoreCase) >= 0
|| blob.IndexOf("Age", StringComparison.OrdinalIgnoreCase) >= 0
|| blob.IndexOf("die", StringComparison.OrdinalIgnoreCase) >= 0
|| blob.IndexOf("kill", StringComparison.OrdinalIgnoreCase) >= 0
|| blob.IndexOf("lover", StringComparison.OrdinalIgnoreCase) >= 0
|| blob.IndexOf("destroy", StringComparison.OrdinalIgnoreCase) >= 0
|| blob.IndexOf("new", StringComparison.OrdinalIgnoreCase) >= 0)
{
return "Signal";
}
return "Ambient";
}
private static string Escape(string value)
{
if (string.IsNullOrEmpty(value))
{
return "";
}
return value.Replace('\t', ' ').Replace('\n', ' ').Replace('\r', ' ');
}
}