251 lines
8 KiB
C#
251 lines
8 KiB
C#
using UnityEngine;
|
|
|
|
namespace IdleSpectator;
|
|
|
|
/// <summary>Registers relationship lifecycle interest candidates under the ownership contract.</summary>
|
|
public static class RelationshipInterestFeed
|
|
{
|
|
private const float FoundingMergeSeconds = 0.35f;
|
|
private static float _foundingAt = -999f;
|
|
private static long _foundingActorId;
|
|
|
|
public static void Emit(string eventId, Actor subject, Actor related, string labelOverride = null)
|
|
{
|
|
if (!AgentHarness.LiveFeedsAllowed
|
|
|| subject == null
|
|
|| !subject.isAlive())
|
|
{
|
|
return;
|
|
}
|
|
|
|
DiscreteEventEntry entry = EventCatalog.Relationship.GetOrFallback(eventId);
|
|
if (!EventCatalog.IsCameraWorthy(entry))
|
|
{
|
|
InterestDropLog.Record("createsInterest=false", "relationship:" + (eventId ?? ""));
|
|
return;
|
|
}
|
|
|
|
Actor relatedAlive = related != null && related.isAlive() ? related : null;
|
|
|
|
bool claimsPeer = eventId == "family_group_new"
|
|
|| eventId == "family_group_join"
|
|
|| eventId == "family_group_leave"
|
|
|| eventId == "set_lover"
|
|
|| eventId == "add_child";
|
|
if (claimsPeer && relatedAlive == null)
|
|
{
|
|
relatedAlive = ActorRelation.ResolvePackRelated(subject);
|
|
}
|
|
|
|
string label = !string.IsNullOrEmpty(labelOverride)
|
|
? labelOverride
|
|
: TypedLabel(eventId, subject, relatedAlive);
|
|
|
|
// BehFamilyGroupNew always calls newFamily first - keep family_group_new on but
|
|
// share the founding interest key so one orange reason wins for that beat.
|
|
if (eventId == "family_group_new" && IsRecentFounding(subject))
|
|
{
|
|
string foundingKey = FoundingKey(subject);
|
|
if (InterestRegistry.TryGet(foundingKey, out _))
|
|
{
|
|
return;
|
|
}
|
|
|
|
EventFeedUtil.Register(
|
|
foundingKey,
|
|
"relationship",
|
|
entry.Category,
|
|
label,
|
|
entry.Id,
|
|
entry.EventStrength,
|
|
subject.current_position,
|
|
subject,
|
|
related: relatedAlive);
|
|
return;
|
|
}
|
|
|
|
if (claimsPeer && relatedAlive == null)
|
|
{
|
|
string soloKey = "rel:" + entry.Id + ":" + EventFeedUtil.SafeId(subject) + ":solo";
|
|
EventFeedUtil.Register(
|
|
soloKey,
|
|
"relationship",
|
|
entry.Category,
|
|
label,
|
|
entry.Id,
|
|
Mathf.Min(entry.EventStrength, 40f),
|
|
subject.current_position,
|
|
subject);
|
|
return;
|
|
}
|
|
|
|
string key = "rel:" + entry.Id + ":" + EventFeedUtil.SafeId(subject) + ":" + EventFeedUtil.SafeId(relatedAlive);
|
|
EventFeedUtil.Register(
|
|
key,
|
|
"relationship",
|
|
entry.Category,
|
|
label,
|
|
entry.Id,
|
|
entry.EventStrength,
|
|
subject.current_position,
|
|
subject,
|
|
related: relatedAlive);
|
|
}
|
|
|
|
public static void EmitFamily(string eventId, object family, Actor anchor)
|
|
{
|
|
if (!AgentHarness.LiveFeedsAllowed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
DiscreteEventEntry entry = EventCatalog.Relationship.GetOrFallback(eventId);
|
|
Actor follow = anchor != null && anchor.isAlive() ? anchor : null;
|
|
if (follow == null)
|
|
{
|
|
follow = FirstFamilyMember(family);
|
|
}
|
|
|
|
if (follow == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Actor related = ActorRelation.FirstFamilyPeer(follow);
|
|
string label = TypedLabel(eventId, follow, related);
|
|
string key = "rel:" + entry.Id + ":" + EventFeedUtil.SafeId(follow);
|
|
if (eventId == "new_family")
|
|
{
|
|
NoteFounding(follow);
|
|
key = FoundingKey(follow);
|
|
}
|
|
|
|
EventFeedUtil.Register(
|
|
key,
|
|
"relationship",
|
|
entry.Category,
|
|
label,
|
|
entry.Id,
|
|
entry.EventStrength,
|
|
follow.current_position,
|
|
follow,
|
|
related: related);
|
|
}
|
|
|
|
private static void NoteFounding(Actor anchor)
|
|
{
|
|
_foundingAt = Time.unscaledTime;
|
|
_foundingActorId = EventFeedUtil.SafeId(anchor);
|
|
}
|
|
|
|
private static bool IsRecentFounding(Actor subject)
|
|
{
|
|
if (subject == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
long id = EventFeedUtil.SafeId(subject);
|
|
if (id == 0 || id != _foundingActorId)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return Time.unscaledTime - _foundingAt <= FoundingMergeSeconds;
|
|
}
|
|
|
|
private static string FoundingKey(Actor anchor) =>
|
|
"rel:new_family:" + EventFeedUtil.SafeId(anchor);
|
|
|
|
private static string TypedLabel(string eventId, Actor subject, Actor related)
|
|
{
|
|
switch (eventId)
|
|
{
|
|
case "set_lover":
|
|
return EventReason.Lovers(subject, related);
|
|
case "clear_lover":
|
|
return EventReason.LoverParted(subject);
|
|
case "find_lover":
|
|
return EventReason.SeekingLover(subject);
|
|
case "become_alpha":
|
|
return EventReason.BecomeAlpha(subject);
|
|
case "add_child":
|
|
return EventReason.NewChild(subject, related);
|
|
case "baby_created":
|
|
return EventReason.BabyBorn(subject);
|
|
case "new_family":
|
|
return EventReason.NewFamily(subject);
|
|
case "family_removed":
|
|
return EventReason.FamilyEnded(subject);
|
|
case "family_group_new":
|
|
return EventReason.FamilyPack(subject, related, "form");
|
|
case "family_group_join":
|
|
return EventReason.FamilyPack(subject, related, "join");
|
|
case "family_group_leave":
|
|
return EventReason.FamilyPack(subject, related, "leave");
|
|
default:
|
|
return EventReason.Apply(
|
|
EventCatalog.Relationship.GetOrFallback(eventId).LabelTemplate,
|
|
subject,
|
|
related,
|
|
eventId);
|
|
}
|
|
}
|
|
|
|
private static Actor FirstFamilyMember(object family)
|
|
{
|
|
if (family == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
try
|
|
{
|
|
foreach (Actor member in ActorRelation.EnumerateFamilyMembers(
|
|
ActorRelation.ResolveActor(
|
|
family.GetType().GetField("founder")?.GetValue(family)
|
|
?? family.GetType().GetProperty("founder")?.GetValue(family, null))
|
|
?? null,
|
|
max: 1))
|
|
{
|
|
return member;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// fall through
|
|
}
|
|
|
|
try
|
|
{
|
|
object list = family.GetType().GetField("units")?.GetValue(family)
|
|
?? family.GetType().GetProperty("units")?.GetValue(family, null)
|
|
?? family.GetType().GetMethod("getUnits")?.Invoke(family, null)
|
|
?? family.GetType().GetMethod("getSimpleList")?.Invoke(family, null);
|
|
if (list is System.Collections.IEnumerable enumerable)
|
|
{
|
|
foreach (object raw in enumerable)
|
|
{
|
|
Actor a = ActorRelation.ResolveActor(raw);
|
|
if (a != null && a.isAlive())
|
|
{
|
|
return a;
|
|
}
|
|
}
|
|
}
|
|
|
|
Actor founder = family.GetType().GetField("founder")?.GetValue(family) as Actor
|
|
?? family.GetType().GetProperty("founder")?.GetValue(family, null) as Actor;
|
|
if (founder != null && founder.isAlive())
|
|
{
|
|
return founder;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// ignore
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|