worldbox-observer-mod/IdleSpectator/ActorStatusPatches.cs

251 lines
5.6 KiB
C#

using System;
using HarmonyLib;
namespace IdleSpectator;
/// <summary>
/// Feeds Activity status gain/loss lines from authoritative WorldBox status transitions.
/// Gain = new dict entry (<see cref="BaseSimObject.addNewStatusEffect"/>).
/// Loss = <see cref="Status.finish"/> (remove, expire, clear) while the actor is still alive.
/// </summary>
[HarmonyPatch]
public static class ActorStatusPatches
{
[HarmonyPatch(typeof(BaseSimObject), "addNewStatusEffect")]
[HarmonyPostfix]
public static void PostfixAddNewStatusEffect(
BaseSimObject __instance,
StatusAsset pStatusAsset,
float pOverrideTimer,
bool pColorEffect,
bool pIsActor,
bool pHasAnyStatus)
{
_ = pOverrideTimer;
_ = pColorEffect;
_ = pHasAnyStatus;
if (__instance == null || pStatusAsset == null)
{
return;
}
Actor actor = ResolveLivingActor(__instance, pIsActor);
if (actor == null)
{
return;
}
ActivityLog.NoteStatusChange(actor, pStatusAsset.id, gained: true);
}
/// <summary>
/// Count timer-refresh reapplications for harness asserts (no Activity line).
/// </summary>
[HarmonyPatch(
typeof(BaseSimObject),
"addStatusEffect",
new Type[] { typeof(StatusAsset), typeof(float), typeof(bool) })]
[HarmonyPrefix]
public static void PrefixAddStatusEffect(
BaseSimObject __instance,
StatusAsset pStatusAsset,
out bool __state)
{
__state = false;
if (__instance == null || pStatusAsset == null || string.IsNullOrEmpty(pStatusAsset.id))
{
return;
}
try
{
if (!__instance.isActor())
{
return;
}
__state = ActorAlreadyHasStatus(__instance, pStatusAsset.id);
}
catch
{
__state = false;
}
}
[HarmonyPatch(
typeof(BaseSimObject),
"addStatusEffect",
new Type[] { typeof(StatusAsset), typeof(float), typeof(bool) })]
[HarmonyPostfix]
public static void PostfixAddStatusEffect(
BaseSimObject __instance,
StatusAsset pStatusAsset,
bool __result,
bool __state)
{
if (!__state || !__result || __instance == null || pStatusAsset == null)
{
return;
}
try
{
if (!__instance.isActor())
{
return;
}
Actor actor = __instance.a;
long actorId = 0;
try
{
if (actor != null)
{
actorId = actor.getID();
}
}
catch
{
actorId = 0;
}
ActivityLog.NoteStatusRefresh(pStatusAsset.id, actorId);
}
catch
{
// ignore
}
}
[HarmonyPatch(typeof(Status), nameof(Status.finish))]
[HarmonyPrefix]
public static void PrefixFinish(Status __instance, out bool __state)
{
__state = false;
try
{
__state = __instance != null && !__instance.is_finished;
}
catch
{
__state = false;
}
}
[HarmonyPatch(typeof(Status), nameof(Status.finish))]
[HarmonyPostfix]
public static void PostfixFinish(Status __instance, bool __state)
{
if (!__state || __instance == null)
{
return;
}
BaseSimObject sim;
StatusAsset asset;
try
{
sim = __instance.sim_object;
asset = __instance.asset;
}
catch
{
return;
}
if (sim == null || asset == null || string.IsNullOrEmpty(asset.id))
{
return;
}
Actor actor;
try
{
if (!sim.isActor())
{
return;
}
actor = sim.a;
}
catch
{
return;
}
if (actor == null)
{
return;
}
// Skip death/dispose cleanup bursts - death milestone covers that moment.
try
{
if (!actor.isAlive())
{
return;
}
}
catch
{
return;
}
ActivityLog.NoteStatusChange(actor, asset.id, gained: false);
}
private static Actor ResolveLivingActor(BaseSimObject sim, bool hintedActor)
{
if (sim == null)
{
return null;
}
try
{
if (!hintedActor && !sim.isActor())
{
return null;
}
Actor actor = sim.a;
if (actor == null || !actor.isAlive())
{
return null;
}
return actor;
}
catch
{
return null;
}
}
private static bool ActorAlreadyHasStatus(BaseSimObject sim, string statusId)
{
try
{
var ids = sim.getStatusesIds();
if (ids == null)
{
return false;
}
foreach (string id in ids)
{
if (!string.IsNullOrEmpty(id)
&& id.Equals(statusId, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
}
catch
{
// fall through
}
return false;
}
}