Decompiled source of DpsMeter v0.2.5

DpsMeter.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using InControl;
using Microsoft.CodeAnalysis;
using NineSolsAPI;
using NineSolsAPI.Utils;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("DpsMeter")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.2.2.0")]
[assembly: AssemblyInformationalVersion("0.2.2+df8d39406b40794ef117da5e46f6c30bf3b4d0c8")]
[assembly: AssemblyProduct("DpsMeter")]
[assembly: AssemblyTitle("DpsMeter")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.2.2.0")]
[module: UnverifiableCode]
[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 DpsMeter
{
	public class DpsDisplay
	{
		[CompilerGenerated]
		private DpsTracker <tracker>P;

		[CompilerGenerated]
		private ConfigEntry<bool> <configShowDamageNumbers>P;

		[CompilerGenerated]
		private ConfigEntry<bool> <updateOnHits>P;

		[CompilerGenerated]
		private TMP_Text <statsPanel>P;

		private const float MoveAmount = 50f;

		private const float FadeDuration = 2f;

		private const float ScaleFactor = 1.2f;

		private List<TMP_Text> objects;

		public DpsDisplay(DpsTracker tracker, ConfigEntry<bool> configShowDamageNumbers, ConfigEntry<bool> updateOnHits, TMP_Text statsPanel)
		{
			<tracker>P = tracker;
			<configShowDamageNumbers>P = configShowDamageNumbers;
			<updateOnHits>P = updateOnHits;
			<statsPanel>P = statsPanel;
			objects = new List<TMP_Text>();
			base..ctor();
		}

		public IEnumerator OnDamage(EffectHitData data, float value, bool internalDamage)
		{
			if (<configShowDamageNumbers>P.Value)
			{
				Color color = (Color)(internalDamage ? new Color(0.5f, 1f, 1f, 1f) : Color.white);
				yield return SpawnText(data.hitPos, $"{value:0.##}", color);
			}
		}

		public IEnumerator OnInaccurateParry(EffectHitData data, float parryTime, float requiredParryTime, float spamLevel)
		{
			if (<configShowDamageNumbers>P.Value)
			{
				float num = parryTime - requiredParryTime;
				string text = $"Missed by {num * 1000f:F0}ms";
				if (spamLevel > 0f)
				{
					text += $" (Spam {spamLevel})";
				}
				if (requiredParryTime == 0f)
				{
					text = "Parry Spam";
				}
				yield return SpawnText(data.hitPos, text, new Color(1f, 0f, 0.28f, 1f));
			}
		}

		private IEnumerator SpawnText(Vector3 pos, string str, Color color)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			TMP_Text text = CreateDamageText(str, color);
			objects.Add(text);
			yield return AnimateText(text, pos);
			objects.Remove(text);
		}

		public void Update()
		{
			List<HitData> recentHits = <tracker>P.RecentHits;
			if (recentHits.Count == 0)
			{
				<statsPanel>P.text = "";
				return;
			}
			float num = recentHits.Sum((HitData hit) => hit.Value);
			float totalDamage = recentHits.Sum((HitData hit) => hit.Value);
			List<(string, float, float, int)> list = (from x in recentHits.GroupBy((HitData hit) => hit.Type, (HitData hit) => hit.Value, delegate(string type, IEnumerable<float> @group)
				{
					float num4 = @group.Sum();
					float num5 = num4 / totalDamage * 100f;
					int item2 = (int)num5;
					return (type, num4, num5, item2);
				})
				where x.groupSum > 0f
				select x).ToList();
			int count = 100 - list.Sum<(string, float, float, int)>(((string type, float groupSum, float percentage, int percentageFloored) x) => x.percentageFloored);
			foreach (var item3 in (from x in list.Select<(string, float, float, int), (int, float)>(((string type, float groupSum, float percentage, int percentageFloored) x, int index) => (index, x.percentage - (float)x.percentageFloored))
				orderby x.fract descending
				select x).Take(count))
			{
				int item = item3.Item1;
				(string, float, float, int) value = list[item];
				value.Item4 = list[item].Item4 + 1;
				list[item] = value;
			}
			string arg = GeneralExtensions.Join<string>(from x in list
				orderby x.groupSum descending
				select $"{x.type}: {x.groupSum:0.##} {x.percentageFloored}%", (Func<string, string>)null, "\n");
			<statsPanel>P.text = $"Total: {totalDamage:0.##} 100%\n{arg}";
			float num2 = ((!<updateOnHits>P.Value) ? <tracker>P.RunningTime : ((recentHits.Count <= 0) ? 0f : (ListExtensions.Last<HitData>(recentHits).Time - ListExtensions.First<HitData>(recentHits).Time)));
			if (num2 != 0f)
			{
				float num3 = num / num2;
				TMP_Text obj = <statsPanel>P;
				obj.text += $"\nDPS: {num3:F1}";
			}
		}

		public void OnDestroy()
		{
			foreach (TMP_Text @object in objects)
			{
				Object.Destroy((Object)(object)((Component)@object).gameObject);
			}
		}

		private static Vector2 WorldToCanvas(Vector3 worldPosition)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)NineSolsAPICore.FullscreenCanvas).transform;
			Vector3 val = SingletonBehaviour<CameraManager>.Instance.camera2D.GameCamera.WorldToScreenPoint(worldPosition);
			Vector2 result = default(Vector2);
			RectTransformUtility.ScreenPointToLocalPointInRectangle(((Component)transform).GetComponent<RectTransform>(), Vector2.op_Implicit(val), (Camera)null, ref result);
			return result;
		}

		private static TMP_Text CreateDamageText(string str, Color color)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)NineSolsAPICore.FullscreenCanvas).transform;
			GameObject val = new GameObject();
			val.transform.SetParent(transform);
			TextMeshProUGUI obj = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)obj).fontSize = 25f;
			((TMP_Text)obj).alignment = (TextAlignmentOptions)1026;
			((TMP_Text)obj).fontWeight = (FontWeight)700;
			((TMP_Text)obj).text = str;
			((Graphic)obj).color = color;
			RectTransform component = ((Component)obj).GetComponent<RectTransform>();
			component.pivot = new Vector2(0.5f, 0f);
			component.sizeDelta = new Vector2(200f, 10f);
			return (TMP_Text)(object)obj;
		}

		private static IEnumerator AnimateText(TMP_Text text, Vector3 worldPosition)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			Vector2 anchoredPosition = WorldToCanvas(worldPosition);
			RectTransform rectTransform = ((Component)text).GetComponent<RectTransform>();
			rectTransform.anchoredPosition = anchoredPosition;
			Vector3 targetPositionWorld = worldPosition + new Vector3(0f, 50f, 0f);
			float elapsedTime = 0f;
			Color originalColor = ((Graphic)text).color;
			float originalScale = ((Transform)rectTransform).localScale.x;
			while (elapsedTime < 2f)
			{
				rectTransform.anchoredPosition = WorldToCanvas(Vector3.Lerp(worldPosition, targetPositionWorld, elapsedTime / 2f));
				Color color = ((Graphic)text).color;
				color.a = Mathf.Lerp(1f, 0f, elapsedTime / 2f);
				((Graphic)text).color = color;
				float num = Mathf.Lerp(originalScale, 1.2f, elapsedTime / 1f);
				if (elapsedTime > 1f)
				{
					num = Mathf.Lerp(1.2f, originalScale, (elapsedTime - 1f) / 1f);
				}
				((Transform)rectTransform).localScale = new Vector3(num, num, num);
				elapsedTime += Time.deltaTime;
				yield return null;
			}
			((Graphic)text).color = new Color(originalColor.r, originalColor.g, originalColor.b, 0f);
			Object.Destroy((Object)(object)((Component)text).gameObject);
		}
	}
	internal static class Extensions
	{
		public static string Name(this EffectType type)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			if ((type & 0x40000) != 0)
			{
				return "Heavy";
			}
			if ((type & 0x20) != 0)
			{
				return "Talisman Attach";
			}
			if ((type & 0x2000000) != 0)
			{
				return "Talisman Explode";
			}
			if ((type & 0x200) != 0)
			{
				return "Tai-Chi";
			}
			return ((object)(EffectType)(ref type)).ToString();
		}
	}
	public enum DpsResetMode
	{
		ManualResets,
		ResetOnEnemyChange,
		LockToFirstEnemy
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("DpsMeter", "DpsMeter", "0.2.2")]
	public class DpsMeterMod : BaseUnityPlugin
	{
		private ConfigEntry<DpsResetMode> configResetMode;

		private ConfigEntry<bool> configUpdateOnHits;

		private ConfigEntry<bool> configShowDamageNumbers;

		private ConfigEntry<KeyboardShortcut> configShortcutPause;

		private ConfigEntry<KeyboardShortcut> configShortcutReset;

		public static DpsMeterMod Instance;

		private Harmony harmony;

		private DpsTracker dpsTracker;

		private DpsDisplay dpsDisplay;

		private GameObject dummy;

		public TMP_Text statsPanel;

		private void Awake()
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log.Init(((BaseUnityPlugin)this).Logger);
			RCGLifeCycle.DontDestroyForever(((Component)this).gameObject);
			try
			{
				configResetMode = ((BaseUnityPlugin)this).Config.Bind<DpsResetMode>("General", "Reset Mode", DpsResetMode.LockToFirstEnemy, "When to reset the DPS tracking.\nManual Resets = You have to hit the reset shortcut manually\nLock To First Enemy = After hitting an enemy, only damage to that enemy will be tracked (until manually reset)\nReset On Enemy Change = Switching the enemy automatically resets the DPS tracking");
				configUpdateOnHits = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Only update DPS on hits", true, "When enabled, the DPS value is only calculated on every hit. Otherwise, it will continuously adapt as time goes on.");
				configShowDamageNumbers = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show damage numbers", true, "Show floating popup texts when you deal damage");
				configShortcutPause = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Shortcuts", "Pause DPS Tracking", KeyboardShortcut.Empty, "Temporarily disable DPS tracking");
				configShortcutReset = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Shortcuts", "Reset DPS Tracking", KeyboardShortcut.Empty, "Reset the DPS statistics. Also clears locked in enemy if reset mode is 'Lock To First Enemy'");
				statsPanel = CreateStatsPanel();
				harmony = Harmony.CreateAndPatchAll(typeof(DpsMeterMod).Assembly, (string)null);
				dpsTracker = new DpsTracker(configResetMode);
				dpsDisplay = new DpsDisplay(dpsTracker, configShowDamageNumbers, configUpdateOnHits, statsPanel);
				KeybindManager.Add((MonoBehaviour)(object)this, (Action)delegate
				{
					dpsTracker.Pause();
				}, (Func<KeyboardShortcut>)(() => configShortcutPause.Value));
				KeybindManager.Add((MonoBehaviour)(object)this, (Action)delegate
				{
					dpsTracker.Reset();
				}, (Func<KeyboardShortcut>)(() => configShortcutReset.Value));
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin DpsMeter is loaded!");
			}
			catch (Exception ex)
			{
				ToastManager.Toast((object)ex);
			}
		}

		private static TMP_Text CreateStatsPanel()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("Stats");
			val.transform.SetParent(((Component)NineSolsAPICore.FullscreenCanvas).transform);
			TextMeshProUGUI obj = val.AddComponent<TextMeshProUGUI>();
			((TMP_Text)obj).alignment = (TextAlignmentOptions)1028;
			((TMP_Text)obj).fontSize = 20f;
			((Graphic)obj).color = Color.white;
			((TMP_Text)obj).text = "";
			RectTransform component = ((Component)obj).GetComponent<RectTransform>();
			component.anchorMin = new Vector2(1f, 0.5f);
			component.anchorMax = new Vector2(1f, 0.5f);
			component.pivot = new Vector2(1f, 0f);
			component.anchoredPosition = new Vector2(-10f, 10f);
			component.sizeDelta = new Vector2((float)Screen.width, 0f);
			return (TMP_Text)(object)obj;
		}

		private void Update()
		{
			dpsTracker.Update();
			dpsDisplay.Update();
		}

		private void SpawnTrainingDummy()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			Player i = Player.i;
			if (i != null)
			{
				Object.Instantiate<GameObject>(dummy, ((Component)Instance).gameObject.transform).transform.position = ((Component)i).transform.position;
			}
		}

		private void OnDestroy()
		{
			harmony.UnpatchSelf();
			dpsDisplay.OnDestroy();
			if (Object.op_Implicit((Object)(object)dummy))
			{
				Object.Destroy((Object)(object)dummy);
			}
			if (Object.op_Implicit((Object)(object)statsPanel))
			{
				Object.Destroy((Object)(object)((Component)statsPanel).gameObject);
			}
		}

		public void OnDamage(EffectHitData hitData, Patches.CurrentHealth before, Patches.CurrentHealth after)
		{
			float num = before.HealthValue - after.HealthValue;
			float num2 = after.InternalInjury - before.InternalInjury;
			float num3 = before.TotalHealth - after.TotalHealth;
			Log.Info($"Health Before: {before}");
			Log.Info($"Health After: {after}");
			Log.Info($"Damage: base {num} / internal {num2} / procced {num3}");
			if (num3 > 0f)
			{
				((MonoBehaviour)this).StartCoroutine(dpsDisplay.OnDamage(hitData, num3, internalDamage: false));
			}
			if (num2 > 0f)
			{
				((MonoBehaviour)this).StartCoroutine(dpsDisplay.OnDamage(hitData, num2, internalDamage: true));
			}
			dpsTracker.OnDamage(hitData, num);
		}

		public void OnInaccurateParry(EffectHitData hitData, float parryTime, float requiredParryTime, float spamLevel)
		{
			((MonoBehaviour)this).StartCoroutine(dpsDisplay.OnInaccurateParry(hitData, parryTime, requiredParryTime, spamLevel));
		}

		private static GameObject LoadObjectFromResources(string resourceName, string scenePath, string objectName)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = null;
			AssetBundle embeddedAssetBundle = AssemblyUtils.GetEmbeddedAssetBundle(resourceName);
			SceneManager.LoadScene(scenePath, (LoadSceneMode)1);
			Scene sceneByPath = SceneManager.GetSceneByPath(scenePath);
			GameObject[] rootGameObjects = ((Scene)(ref sceneByPath)).GetRootGameObjects();
			foreach (GameObject val2 in rootGameObjects)
			{
				if (((Object)val2).name == objectName)
				{
					val = Object.Instantiate<GameObject>(val2);
					((Object)val).name = "Training Dummy";
					RCGLifeCycle.DontDestroyForever(val);
					break;
				}
				Object.Destroy((Object)(object)val2);
			}
			SceneManager.UnloadSceneAsync(sceneByPath);
			embeddedAssetBundle.Unload(true);
			if (val == null)
			{
				ToastManager.Toast((object)embeddedAssetBundle);
				ToastManager.Toast((object)sceneByPath);
				ToastManager.Toast((object)((Scene)(ref sceneByPath)).GetRootGameObjects().Length);
				throw new Exception(objectName + " not found in " + resourceName + "/" + scenePath);
			}
			return val;
		}
	}
	public record struct HitData(float Time, float Value, string Type, GameObject Owner);
	public class DpsTracker
	{
		[CompilerGenerated]
		private ConfigEntry<DpsResetMode> <resetMode>P;

		public readonly List<HitData> RecentHits;

		public bool Running;

		public float RunningTime;

		private GameObject? lockedInToOwner;

		private readonly Dictionary<string, string> dealerNames;

		public DpsTracker(ConfigEntry<DpsResetMode> resetMode)
		{
			<resetMode>P = resetMode;
			RecentHits = new List<HitData>();
			Running = true;
			dealerNames = new Dictionary<string, string>
			{
				{ "AttackFront", "Attack" },
				{ "Third Attack", "Third Attack" },
				{ "ChargedAttackFront", "Charge Attack" },
				{ "Foo", "Talisman Attach" },
				{ "FooExplode", "Talisman Explode" },
				{ "JumpSpinKick", "Tai Chi" },
				{ "[Dealer] Internal Damage", "UC" },
				{ "--ReflectNode", "Reflect Projectile" },
				{ "NormalArrow Shoot 穿雲 Lv1(Clone)", "Bow" },
				{ "NormalArrow Shoot 穿雲 Lv2(Clone)", "Bow" },
				{ "NormalArrow Shoot 穿雲 Lv3(Clone)", "Bow" },
				{ "rayCastDetector", "Bow Arrow" },
				{ "Explosion Damage 爆破箭 閃電 lv2(Clone)", "Bow Explosion" },
				{ "[最新爆炸]Boom Explosion DamageEffect Sting 鐵蒺藜爆炸傷害(Clone)", "Jiequan Explosion" },
				{ "[Jade]AccurateParryReflect", "Hedgehog Jade" }
			};
			base..ctor();
		}

		public void Pause()
		{
			Running = !Running;
			ToastManager.Toast((object)$"DPS tracking enabled: {Running}");
		}

		public void Reset()
		{
			RecentHits.Clear();
			RunningTime = 0f;
			lockedInToOwner = null;
			ToastManager.Toast((object)"DPS tracking reset");
		}

		public void Update()
		{
			if (Running)
			{
				RunningTime += Time.deltaTime;
			}
		}

		public void OnDamage(EffectHitData data, float value)
		{
			if (!Running)
			{
				return;
			}
			GameObject gameObject = data.receiver.OwnerComponent.gameObject;
			switch (<resetMode>P.Value)
			{
			case DpsResetMode.ResetOnEnemyChange:
				if (RecentHits.Count > 0 && (Object)(object)ListExtensions.Last<HitData>(RecentHits).Owner != (Object)(object)gameObject)
				{
					Reset();
					ToastManager.Toast((object)"New enemy, resetting DPS stats");
				}
				break;
			case DpsResetMode.LockToFirstEnemy:
				if (lockedInToOwner == null)
				{
					lockedInToOwner = gameObject;
				}
				else if ((Object)(object)gameObject != (Object)(object)lockedInToOwner)
				{
					return;
				}
				break;
			default:
				throw new ArgumentOutOfRangeException();
			case DpsResetMode.ManualResets:
				break;
			}
			string value2 = null;
			Transform val = ((Component)data.dealer).transform;
			while (Object.op_Implicit((Object)(object)val) && !dealerNames.TryGetValue(((Object)val).name, out value2))
			{
				val = val.parent;
			}
			if (value2 == null)
			{
				Log.Warning("Unknown attack name: " + ObjectUtils.ObjectPath(((Component)data.dealer).gameObject));
				value2 = ((Object)data.dealer).name;
			}
			RecentHits.Add(new HitData(Time.time, value, value2, gameObject));
		}
	}
	internal static class Log
	{
		private static ManualLogSource logSource;

		internal static void Init(ManualLogSource logSource)
		{
			Log.logSource = logSource;
		}

		internal static void Debug(object data)
		{
			logSource.LogDebug(data);
		}

		internal static void Error(object data)
		{
			logSource.LogError(data);
		}

		internal static void Fatal(object data)
		{
			logSource.LogFatal(data);
		}

		internal static void Info(object data)
		{
			logSource.LogInfo(data);
		}

		internal static void Message(object data)
		{
			logSource.LogMessage(data);
		}

		internal static void Warning(object data)
		{
			logSource.LogWarning(data);
		}
	}
	[HarmonyPatch]
	public class Patches
	{
		public record struct CurrentHealth(float HealthValue, float InternalInjury, bool wasLockPostureInvincible)
		{
			public float TotalHealth => HealthValue + InternalInjury;

			internal static CurrentHealth From(PostureSystem health)
			{
				return new CurrentHealth(health.CurrentHealthValue, health.CurrentInternalInjury, health.BindMonster.monsterStat.IsLockPostureInvincible);
			}

			internal void Restore(PostureSystem health)
			{
				if (wasLockPostureInvincible)
				{
					health.PostureValue = health.MaxPostureValue;
					health.CurrentInternalInjury = 0f;
					health.BindMonster.monsterStat.IsLockPostureInvincible = true;
				}
			}
		}

		private static FieldRef<PlayerInputCommandQueue, Dictionary<PlayerAction, List<float>>> actionDict = AccessTools.FieldRefAccess<PlayerInputCommandQueue, Dictionary<PlayerAction, List<float>>>("actionDict");

		private static FieldRef<PlayerParryState, float[]> spamDatas = AccessTools.FieldRefAccess<PlayerParryState, float[]>("spamDatas");

		[HarmonyPatch(typeof(PlayerParryState), "Parried")]
		[HarmonyPrefix]
		public static void Parried(ref PlayerParryState __instance, EffectHitData hitData)
		{
			Player i = Player.i;
			List<float> list = actionDict.Invoke(i.inputCommandQueue)[i.playerInput.gameplayActions.Parry];
			float num;
			if (list.Count <= 0)
			{
				num = -1f;
			}
			else
			{
				num = list[list.Count - 1];
			}
			float num2 = num;
			float[] array = spamDatas.Invoke(__instance);
			int spamLevel = __instance.spamLevel;
			float num3 = Time.time - num2;
			if (!__instance.IsAlwaysAccurate && !i.IsInQTETutorial && !(num3 < array[spamLevel]))
			{
				DpsMeterMod.Instance.OnInaccurateParry(hitData, num3, array[spamLevel], spamLevel);
			}
		}

		[HarmonyPatch(typeof(MonsterBase), "HittedByPlayerDecreasePosture")]
		[HarmonyPrefix]
		private static void OnDamagePrefix(MonsterBase __instance, out CurrentHealth __state)
		{
			__state = CurrentHealth.From(__instance.postureSystem);
			if (__instance.monsterStat.IsLockPostureInvincible)
			{
				__instance.monsterStat.IsLockPostureInvincible = false;
			}
		}

		[HarmonyPatch(typeof(MonsterBase), "HittedByPlayerDecreasePosture")]
		[HarmonyPostfix]
		private static void OnDamage(MonsterBase __instance, CurrentHealth __state, EffectHitData hitData)
		{
			CurrentHealth after = CurrentHealth.From(__instance.postureSystem);
			__state.Restore(__instance.postureSystem);
			DpsMeterMod.Instance.OnDamage(hitData, __state, after);
		}

		[HarmonyPatch(typeof(MonsterBase), "InternalInjuryVirtual")]
		[HarmonyPrefix]
		private static void OnDamageInternalPrefix(MonsterBase __instance, out CurrentHealth __state)
		{
			__state = CurrentHealth.From(__instance.postureSystem);
		}

		[HarmonyPatch(typeof(MonsterBase), "InternalInjuryVirtual")]
		[HarmonyPrefix]
		private static void OnDamageInternal(MonsterBase __instance, CurrentHealth __state, EffectHitData data)
		{
			CurrentHealth after = CurrentHealth.From(__instance.postureSystem);
			__state.Restore(__instance.postureSystem);
			DpsMeterMod.Instance.OnDamage(data, __state, after);
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "DpsMeter";

		public const string PLUGIN_NAME = "DpsMeter";

		public const string PLUGIN_VERSION = "0.2.2";
	}
}