Decompiled source of Valgrind v1.0.1

BepInEx\plugins\Valgrind\Valgrind.dll

Decompiled 11 hours ago
using System;
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 Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using Valgrind.Configuration;
using Valgrind.Logic;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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]
	[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]
	[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 Valgrind
{
	[BepInPlugin("com.bigai.valgrind", "Valgrind", "1.0.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class ValgrindPlugin : BaseUnityPlugin
	{
		public const string PluginGUID = "com.bigai.valgrind";

		public const string PluginName = "Valgrind";

		public const string PluginVersion = "1.0.1";

		private Harmony? _harmony;

		public static ValgrindPlugin Instance { get; private set; }

		public static ManualLogSource Log { get; private set; }

		private void Awake()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			try
			{
				Log.LogInfo((object)"══════════════════════════════════════════");
				Log.LogInfo((object)"  Valgrind v1.0.1 loading...");
				Log.LogInfo((object)"══════════════════════════════════════════");
				ModConfig.Initialize(((BaseUnityPlugin)this).Config);
				_harmony = new Harmony("com.bigai.valgrind");
				_harmony.PatchAll(Assembly.GetExecutingAssembly());
				Log.LogInfo((object)"[Valgrind] All Harmony patches applied successfully.");
				Log.LogInfo((object)"[Valgrind] Ready. Dynamic death penalty active with Jötunn ServerSync.");
			}
			catch (Exception arg)
			{
				Log.LogError((object)string.Format("[{0}] Failed to initialize: {1}", "Valgrind", arg));
			}
		}

		private void OnDestroy()
		{
			Harmony? harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			Log.LogInfo((object)"[Valgrind] Unloaded.");
		}
	}
}
namespace Valgrind.Patches
{
	[HarmonyPatch(typeof(Skills), "OnDeath")]
	public static class SkillsDeathPatch
	{
		[HarmonyPrefix]
		public static bool Prefix(Skills __instance)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return true;
			}
			try
			{
				SkillLossCalculator.ApplyDeathPenalty(__instance);
				return false;
			}
			catch (Exception arg)
			{
				ValgrindPlugin.Log.LogError((object)$"[Valgrind] Error applying dynamic death penalty: {arg}");
				return true;
			}
		}
	}
}
namespace Valgrind.Logic
{
	public static class SkillLossCalculator
	{
		public static void ApplyDeathPenalty(Skills skills)
		{
			if ((Object)(object)skills == (Object)null)
			{
				return;
			}
			List<Skill> skillList = skills.GetSkillList();
			if (skillList != null && skillList.Count != 0)
			{
				CalculationMode value = ModConfig.CalculationModeEntry.Value;
				bool value2 = ModConfig.ResetAccumulatorOnDeath.Value;
				bool value3 = ModConfig.EnableDebugLogging.Value;
				if (value == CalculationMode.PerSkill)
				{
					ApplyPerSkillDeathPenalty(skillList, value2, value3);
				}
				else
				{
					ApplyPlayerWideDeathPenalty(skillList, value, value2, value3);
				}
			}
		}

		private static void ApplyPlayerWideDeathPenalty(List<Skill> skillList, CalculationMode mode, bool resetAccumulator, bool debug)
		{
			float num = CalculateAverageSkillLevel(skillList);
			float num2 = ((mode != CalculationMode.ContinuousCurve) ? GetTierLossPercent(num) : GetCurveLossPercent(num));
			float num3 = Mathf.Clamp01(1f - num2 / 100f);
			if (debug)
			{
				ValgrindPlugin.Log.LogInfo((object)$"[SkillLossCalculator] Mode={mode}, AvgLevel={num:F2}, LossPercent={num2:F2}%, Multiplier={num3:F4}, ResetAccumulator={resetAccumulator}");
			}
			foreach (Skill skill in skillList)
			{
				if (skill != null && skill.m_level > 0f)
				{
					float level = skill.m_level;
					skill.m_level = Mathf.Max(0f, skill.m_level * num3);
					if (resetAccumulator)
					{
						skill.m_accumulator = 0f;
					}
					if (debug)
					{
						ValgrindPlugin.Log.LogInfo((object)string.Format("[SkillLossCalculator] Skill {0}: {1:F2} -> {2:F2}", ((object)Unsafe.As<SkillType, SkillType>(ref skill.m_info?.m_skill)/*cast due to .constrained prefix*/).ToString() ?? "Unknown", level, skill.m_level));
					}
				}
			}
		}

		private static void ApplyPerSkillDeathPenalty(List<Skill> skillList, bool resetAccumulator, bool debug)
		{
			if (debug)
			{
				ValgrindPlugin.Log.LogInfo((object)$"[SkillLossCalculator] Applying Per-Skill death penalty. ResetAccumulator={resetAccumulator}");
			}
			foreach (Skill skill in skillList)
			{
				if (skill != null && skill.m_level > 0f)
				{
					float tierLossPercent = GetTierLossPercent(skill.m_level);
					float num = Mathf.Clamp01(1f - tierLossPercent / 100f);
					float level = skill.m_level;
					skill.m_level = Mathf.Max(0f, skill.m_level * num);
					if (resetAccumulator)
					{
						skill.m_accumulator = 0f;
					}
					if (debug)
					{
						ValgrindPlugin.Log.LogInfo((object)string.Format("[SkillLossCalculator] Skill {0} (Level {1:F2}): Loss {2:F2}% -> New Level {3:F2}", ((object)Unsafe.As<SkillType, SkillType>(ref skill.m_info?.m_skill)/*cast due to .constrained prefix*/).ToString() ?? "Unknown", level, tierLossPercent, skill.m_level));
					}
				}
			}
		}

		public static float CalculateAverageSkillLevel(List<Skill> skillList)
		{
			if (skillList == null || skillList.Count == 0)
			{
				return 0f;
			}
			List<float> list = new List<float>();
			foreach (Skill skill in skillList)
			{
				if (skill != null && skill.m_level > 0f)
				{
					list.Add(skill.m_level);
				}
			}
			if (list.Count == 0)
			{
				return 0f;
			}
			if (ModConfig.UseTopNSkillsOnly.Value)
			{
				int count = Mathf.Clamp(ModConfig.TopNSkillsCount.Value, 1, list.Count);
				return list.OrderByDescending((float l) => l).Take(count).Average();
			}
			return list.Average();
		}

		public static float GetTierLossPercent(float level)
		{
			if (level < 25f)
			{
				return Mathf.Clamp(ModConfig.EarlyGameLossPercent.Value, 0f, 100f);
			}
			if (level < 50f)
			{
				return Mathf.Clamp(ModConfig.MidGameLossPercent.Value, 0f, 100f);
			}
			if (level <= 75f)
			{
				return Mathf.Clamp(ModConfig.LateGameLossPercent.Value, 0f, 100f);
			}
			return Mathf.Clamp(ModConfig.EndgameLossPercent.Value, 0f, 100f);
		}

		public static float GetCurveLossPercent(float level)
		{
			float num = Mathf.Clamp(ModConfig.CurveMaxLossPercent.Value, 0f, 100f);
			float num2 = Mathf.Clamp(ModConfig.CurveMinLossPercent.Value, 0f, 100f);
			float num3 = Mathf.Clamp01(level / 100f);
			return Mathf.Lerp(num, num2, num3);
		}
	}
}
namespace Valgrind.Configuration
{
	public enum CalculationMode
	{
		TieredBrackets,
		ContinuousCurve,
		PerSkill
	}
	public static class ModConfig
	{
		public static ConfigEntry<CalculationMode> CalculationModeEntry { get; private set; }

		public static ConfigEntry<bool> UseTopNSkillsOnly { get; private set; }

		public static ConfigEntry<int> TopNSkillsCount { get; private set; }

		public static ConfigEntry<bool> ResetAccumulatorOnDeath { get; private set; }

		public static ConfigEntry<bool> EnableDebugLogging { get; private set; }

		public static ConfigEntry<float> EarlyGameLossPercent { get; private set; }

		public static ConfigEntry<float> MidGameLossPercent { get; private set; }

		public static ConfigEntry<float> LateGameLossPercent { get; private set; }

		public static ConfigEntry<float> EndgameLossPercent { get; private set; }

		public static ConfigEntry<float> CurveMaxLossPercent { get; private set; }

		public static ConfigEntry<float> CurveMinLossPercent { get; private set; }

		public static void Initialize(ConfigFile config)
		{
			//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_0027: Expected O, but got Unknown
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Expected O, but got Unknown
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Expected O, but got Unknown
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Expected O, but got Unknown
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Expected O, but got Unknown
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Expected O, but got Unknown
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Expected O, but got Unknown
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Expected O, but got Unknown
			//IL_0196: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Expected O, but got Unknown
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Expected O, but got Unknown
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Expected O, but got Unknown
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Expected O, but got Unknown
			//IL_0226: Unknown result type (might be due to invalid IL or missing references)
			//IL_0230: Expected O, but got Unknown
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Expected O, but got Unknown
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0278: Expected O, but got Unknown
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Expected O, but got Unknown
			//IL_02b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c0: Expected O, but got Unknown
			CalculationModeEntry = config.Bind<CalculationMode>("1 - General", "CalculationMode", CalculationMode.TieredBrackets, new ConfigDescription("Method used to calculate dynamic skill loss on death:\n- TieredBrackets: Discrete loss % based on overall average skill level.\n- ContinuousCurve: Smooth linear/curved scaling between Max and Min loss % based on average skill.\n- PerSkill: Evaluates each skill independently against the Tiered Brackets based on its own level (instead of character average).", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			UseTopNSkillsOnly = config.Bind<bool>("1 - General", "UseTopNSkillsOnly", false, new ConfigDescription("If true, average skill level is computed using only the player's top N highest skills (reflecting primary build). If false, averages all discovered skills (level > 0).", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			TopNSkillsCount = config.Bind<int>("1 - General", "TopNSkillsCount", 5, new ConfigDescription("Number of top skills to factor into the average when UseTopNSkillsOnly is enabled.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			ResetAccumulatorOnDeath = config.Bind<bool>("1 - General", "ResetAccumulatorOnDeath", true, new ConfigDescription("If true, partial XP progress toward the next skill level is wiped to 0 on death (vanilla behavior). If false, progress toward the next level is preserved.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			EnableDebugLogging = config.Bind<bool>("1 - General", "EnableDebugLogging", false, new ConfigDescription("Enable verbose logging of skill loss calculations to the BepInEx console.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = false
			} }));
			EarlyGameLossPercent = config.Bind<float>("2 - Tiered Brackets", "EarlyGameLossPercent", 8f, new ConfigDescription("Skill loss % for skill/average levels < 25. (Vanilla baseline is 5.0%)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			MidGameLossPercent = config.Bind<float>("2 - Tiered Brackets", "MidGameLossPercent", 5f, new ConfigDescription("Skill loss % for skill/average levels between 25 and 50. (Vanilla baseline is 5.0%)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			LateGameLossPercent = config.Bind<float>("2 - Tiered Brackets", "LateGameLossPercent", 2.5f, new ConfigDescription("Skill loss % for skill/average levels between 50 and 75.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			EndgameLossPercent = config.Bind<float>("2 - Tiered Brackets", "EndgameLossPercent", 1f, new ConfigDescription("Skill loss % for skill/average levels > 75.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			CurveMaxLossPercent = config.Bind<float>("3 - Continuous Curve", "CurveMaxLossPercent", 8f, new ConfigDescription("Maximum skill loss percentage (applied at skill level 0).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
			CurveMinLossPercent = config.Bind<float>("3 - Continuous Curve", "CurveMinLossPercent", 1f, new ConfigDescription("Minimum skill loss percentage (applied at skill level 100).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), new object[1] { (object)new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			} }));
		}
	}
}