using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using RoR2;
using RoR2.CameraModes;
using RoR2.UI;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace Local.HealthBar.Viewer
{
[BepInPlugin("local.healthbar.viewer", "HealthBarViewer", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
private class ConfigValue<T> : ConfigValue<T, T>
{
public ConfigValue(ConfigEntry<T> entry)
: base(entry)
{
convert = (T _) => _;
}
public static implicit operator ConfigValue<T>(ConfigEntry<T> entry)
{
return new ConfigValue<T>(entry);
}
}
private class ConfigValue<T, U>
{
private readonly ConfigEntry<T> entry;
public Func<T, U> convert;
public ConfigValue(ConfigEntry<T> entry)
{
this.entry = entry;
base..ctor();
}
public static implicit operator ConfigValue<T, U>(ConfigEntry<T> entry)
{
return new ConfigValue<T, U>(entry);
}
public static implicit operator U(ConfigValue<T, U> configuration)
{
return configuration.convert(configuration.entry.Value);
}
}
public const string version = "1.0.0";
public const string identifier = "local.healthbar.viewer";
private static ConfigValue<uint> duration;
private static ConfigValue<uint> range;
private static ConfigValue<float> threshold;
private static ConfigValue<float> alpha;
private static ConfigValue<bool> ally;
private static ConfigValue<uint, float> delay;
private static ConfigValue<uint, float> interval;
public void Awake()
{
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Expected O, but got Unknown
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
//IL_015a: Expected O, but got Unknown
duration = ((BaseUnityPlugin)this).Config.Bind<uint>("General", "Minimum Duration", 10u, "After damage is dealt, the target's health bar will remain visible for this many seconds.");
threshold = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Health Threshold", 75f, new ConfigDescription("Enemies at this hit point percentage or below remain visible indefinitely.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
threshold.convert = percent;
range = ((BaseUnityPlugin)this).Config.Bind<uint>("General", "Maximum Range", 100u, "Remove health bar regardless of health threshold if distance to target exceeds this value in meters. Set to zero for unlimited range.");
ally = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Allied Targets", true, "Determines whether allies reveal their target upon dealing damage.");
delay = ((BaseUnityPlugin)this).Config.Bind<uint>("Other", "Targeting Delay", 0u, "Aiming directly at an enemy will display their health for this many milliseconds. If target is below the health threshold, minimum duration parameter is used instead.");
delay.convert = milliseconds;
alpha = ((BaseUnityPlugin)this).Config.Bind<float>("Other", "Alpha Channel", 85f, new ConfigDescription("Use this parameter to adjust transparency/opacity of the health bar interface.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>()));
alpha.convert = percent;
interval = ((BaseUnityPlugin)this).Config.Bind<uint>("Other", "Refresh Interval", 500u, "How often to check target health/range, in milliseconds. Note that decreasing this value could negatively affect performance.");
interval.convert = milliseconds;
ReplaceEventHandler();
Harmony.CreateAndPatchAll(typeof(Plugin), (string)null);
static float milliseconds(uint input)
{
return (float)input / 1000f;
}
static float percent(float input)
{
return input / 100f;
}
}
private static void ReplaceEventHandler()
{
try
{
Type typeFromHandle = typeof(CombatHealthBarViewer);
Type typeFromHandle2 = typeof(GlobalEventManager);
string name = "onClientDamageNotified";
RuntimeHelpers.RunClassConstructor(typeFromHandle.TypeHandle);
EventInfo @event = typeFromHandle2.GetEvent(name);
Delegate[] invocationList = (typeFromHandle2.GetField(name, BindingFlags.Static | BindingFlags.NonPublic).GetValue(null) as Delegate).GetInvocationList();
foreach (Delegate @delegate in invocationList)
{
if (typeFromHandle == @delegate.Method.DeclaringType.DeclaringType)
{
@event.RemoveEventHandler(null, @delegate);
return;
}
}
throw new Exception("Unable to locate original health bar event handler.");
}
catch (Exception value)
{
Console.WriteLine(value);
}
finally
{
GlobalEventManager.onClientDamageNotified += ShowHealthBar;
}
}
[HarmonyPatch(typeof(CombatHealthBarViewer), "Awake")]
[HarmonyPostfix]
private static void ApplySettings(CombatHealthBarViewer __instance)
{
__instance.healthBarDuration = (uint)duration;
if ((float)alpha != 1f && Object.op_Implicit((Object)(object)((Component)__instance).gameObject))
{
((Component)__instance).gameObject.AddComponent<CanvasGroup>().alpha = alpha;
}
}
[HarmonyPatch(typeof(CombatHealthBarViewer), "CleanUp")]
[HarmonyPrefix]
private static bool CheckStatus(CombatHealthBarViewer __instance)
{
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
int num = __instance.trackedVictims.Count;
while (--num >= 0)
{
HealthComponent val = __instance.trackedVictims[num];
HealthBarInfo healthBarInfo = __instance.GetHealthBarInfo(val);
if (Object.op_Implicit((Object)(object)val) && val.alive && Object.op_Implicit((Object)(object)val.body))
{
if (healthBarInfo.endTime > Time.time)
{
continue;
}
float num2;
if ((uint)range == 0 || !Object.op_Implicit((Object)(object)__instance.viewerBody))
{
num2 = (uint)range;
}
else
{
Vector3 val2 = __instance.viewerBody.corePosition - val.body.corePosition;
num2 = ((Vector3)(ref val2)).magnitude;
}
float num3 = num2;
if (val.combinedHealthFraction <= (float)threshold && num3 <= (float)(uint)range)
{
healthBarInfo.endTime = Time.time + (float)interval;
continue;
}
}
__instance.Remove(num, healthBarInfo);
}
return false;
}
private static void ShowHealthBar(DamageDealtMessage message)
{
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_008f: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
if (message.isSilent || !Object.op_Implicit((Object)(object)message.victim) || !Object.op_Implicit((Object)(object)message.attacker))
{
return;
}
HealthComponent component = message.victim.GetComponent<HealthComponent>();
if (!Object.op_Implicit((Object)(object)component) || component.dontShowHealthbar)
{
return;
}
foreach (CombatHealthBarViewer instances in CombatHealthBarViewer.instancesList)
{
if (Object.op_Implicit((Object)(object)instances.viewerBodyObject))
{
object obj = instances.viewerBodyObject;
object obj2 = message.attacker;
if ((bool)ally)
{
obj = instances.viewerTeamIndex;
obj2 = TeamComponent.GetObjectTeam(message.attacker);
}
if (obj.Equals(obj2))
{
instances.HandleDamage(component, TeamComponent.GetObjectTeam(message.victim));
}
}
}
}
[HarmonyPatch(typeof(CameraRigController), "SetCameraState")]
[HarmonyPostfix]
private static void UpdateCrosshair(CameraRigController __instance)
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
CameraModeBase cameraMode = __instance.cameraMode;
HurtBox val2 = (__instance.lastCrosshairHurtBox = ((InstanceData)(/*isinst with value type is only supported in some contexts*/?)).lastCrosshairHurtBox);
if (Object.op_Implicit((Object)(object)__instance.hud))
{
CombatHealthBarViewer combatHealthBarViewer = __instance.hud.combatHealthBarViewer;
if (Object.op_Implicit((Object)(object)combatHealthBarViewer))
{
combatHealthBarViewer.crosshairTarget = (Object.op_Implicit((Object)(object)val2) ? val2.healthComponent : null);
}
}
}
[HarmonyPatch(typeof(CombatHealthBarViewer), "Update")]
[HarmonyPrefix]
private static bool ShowCrosshairTarget(CombatHealthBarViewer __instance)
{
if (Object.op_Implicit((Object)(object)__instance.crosshairTarget))
{
float num = delay;
if (__instance.crosshairTarget.combinedHealthFraction <= (float)threshold)
{
num = (uint)duration;
}
if (num > 0f)
{
HealthBarInfo healthBarInfo = __instance.GetHealthBarInfo(__instance.crosshairTarget);
healthBarInfo.endTime = Mathf.Max(healthBarInfo.endTime, Time.time + num);
}
}
__instance.SetDirty();
return false;
}
}
}