Decompiled source of RandomizerModifiers v1.0.1

BepInEx/plugins/RandomizerModifiers.dll

Decompiled 6 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
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 Microsoft.CodeAnalysis;
using Pigeon;
using UnityEngine;
using UnityEngine.Events;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Sparroh")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("RandomizerModifiers")]
[assembly: AssemblyTitle("RandomizerModifiers")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[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;
		}
	}
}
public static class ConfigManager
{
	private const float DebounceSeconds = 0.25f;

	private static ConfigFile config;

	private static ManualLogSource logger;

	private static FileSystemWatcher configWatcher;

	private static volatile bool pendingRefresh;

	private static volatile bool reloadPending;

	private static float lastReloadTime;

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

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

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

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

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

	public static void Initialize(ConfigFile configFile, ManualLogSource log)
	{
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Expected O, but got Unknown
		//IL_009d: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Expected O, but got Unknown
		config = configFile;
		logger = log;
		EnableSplitPersonality = config.Bind<bool>("General", "Enable Split Personality", true, "Re-enable the Split Personality modifier (randomize employee/character on revive).");
		EnableButterFingers = config.Bind<bool>("General", "Enable Butter Fingers", true, "Re-enable the Butter Fingers modifier (randomize weapons on revive).");
		SplitPersonalityWeight = config.Bind<int>("Weights", "Split Personality Weight", 1, new ConfigDescription("Spawn weight for Split Personality. Vanilla disabled it with 0; 1 matches a normal modifier.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
		ButterFingersWeight = config.Bind<int>("Weights", "Butter Fingers Weight", 1, new ConfigDescription("Spawn weight for Butter Fingers. Vanilla disabled it with 0; 1 matches a normal modifier.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
		LogModifiersOnLoad = config.Bind<bool>("Debug", "Log Modifiers On Load", false, "Log every mission modifier API name and weight when Global loads.");
		EnableSplitPersonality.SettingChanged += OnSettingChanged;
		EnableButterFingers.SettingChanged += OnSettingChanged;
		SplitPersonalityWeight.SettingChanged += OnSettingChanged;
		ButterFingersWeight.SettingChanged += OnSettingChanged;
		LogModifiersOnLoad.SettingChanged += OnSettingChanged;
		try
		{
			SetupFileWatcher();
		}
		catch (Exception ex)
		{
			logger.LogError((object)("Error setting up config file watcher: " + ex.Message));
		}
	}

	public static void Tick()
	{
		if (!reloadPending || Time.unscaledTime - lastReloadTime < 0.25f)
		{
			return;
		}
		reloadPending = false;
		lastReloadTime = Time.unscaledTime;
		try
		{
			config.Reload();
			pendingRefresh = true;
			logger.LogInfo((object)"Config reloaded from disk.");
		}
		catch (Exception ex)
		{
			logger.LogError((object)("Error reloading config: " + ex.Message));
		}
	}

	public static bool ConsumePendingRefresh()
	{
		if (!pendingRefresh)
		{
			return false;
		}
		pendingRefresh = false;
		return true;
	}

	public static void Dispose()
	{
		if (EnableSplitPersonality != null)
		{
			EnableSplitPersonality.SettingChanged -= OnSettingChanged;
		}
		if (EnableButterFingers != null)
		{
			EnableButterFingers.SettingChanged -= OnSettingChanged;
		}
		if (SplitPersonalityWeight != null)
		{
			SplitPersonalityWeight.SettingChanged -= OnSettingChanged;
		}
		if (ButterFingersWeight != null)
		{
			ButterFingersWeight.SettingChanged -= OnSettingChanged;
		}
		if (LogModifiersOnLoad != null)
		{
			LogModifiersOnLoad.SettingChanged -= OnSettingChanged;
		}
		if (configWatcher != null)
		{
			configWatcher.EnableRaisingEvents = false;
			configWatcher.Changed -= OnConfigFileChanged;
			configWatcher.Created -= OnConfigFileChanged;
			configWatcher.Renamed -= OnConfigFileChanged;
			configWatcher.Dispose();
			configWatcher = null;
		}
	}

	private static void SetupFileWatcher()
	{
		configWatcher = new FileSystemWatcher(Paths.ConfigPath, "sparroh.randomizermodifiers.cfg");
		configWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite;
		configWatcher.Changed += OnConfigFileChanged;
		configWatcher.Created += OnConfigFileChanged;
		configWatcher.Renamed += OnConfigFileChanged;
		configWatcher.EnableRaisingEvents = true;
	}

	private static void OnConfigFileChanged(object sender, FileSystemEventArgs e)
	{
		reloadPending = true;
	}

	private static void OnSettingChanged(object sender, EventArgs e)
	{
		pendingRefresh = true;
	}
}
[HarmonyPatch(typeof(Global), "LoadInstance")]
internal static class GlobalLoadHook
{
	[HarmonyPostfix]
	private static void Postfix()
	{
		ModifierEnabler.TryEnable("Global.LoadInstance");
	}
}
public static class ModifierEnabler
{
	private const string CharacterMethod = "RandomizeCharacterOnRevive";

	private const string GearMethod = "RandomizeGearOnRevive";

	private static readonly string[] CharacterApiFallbacks = new string[4] { "m_split", "m_personality", "m_char", "split_personality" };

	private static readonly string[] GearApiFallbacks = new string[4] { "m_butter", "m_fingers", "m_gear", "butter_fingers" };

	private static bool _applied;

	public static void TryEnable(string reason, bool force = false)
	{
		if (_applied && !force)
		{
			return;
		}
		if ((Object)(object)Global.Instance == (Object)null || Global.Instance.MissionModifiers == null)
		{
			RandomizerModifiersPlugin.Logger.LogDebug((object)("[RandomizerModifiers] Global not ready yet (" + reason + ")."));
			return;
		}
		try
		{
			EnableRandomizerModifiers();
			_applied = true;
		}
		catch (Exception arg)
		{
			RandomizerModifiersPlugin.Logger.LogError((object)$"[RandomizerModifiers] Failed to enable modifiers ({reason}): {arg}");
		}
	}

	private static void EnableRandomizerModifiers()
	{
		WeightedArray<MissionModifier> missionModifiers = Global.Instance.MissionModifiers;
		int length = missionModifiers.Length;
		if (ConfigManager.LogModifiersOnLoad.Value)
		{
			LogAllModifiers(missionModifiers, length);
		}
		int num = -1;
		int num2 = -1;
		for (int i = 0; i < length; i++)
		{
			MissionModifier obj = missionModifiers[i];
			MissionModifierGeneric val = (MissionModifierGeneric)(object)((obj is MissionModifierGeneric) ? obj : null);
			if (val != null && TryGetActionMethodNames(val, out var methods))
			{
				if (num < 0 && methods.Contains("RandomizeCharacterOnRevive"))
				{
					num = i;
				}
				if (num2 < 0 && methods.Contains("RandomizeGearOnRevive"))
				{
					num2 = i;
				}
			}
		}
		if (num < 0)
		{
			num = FindByApiName(missionModifiers, length, CharacterApiFallbacks);
		}
		if (num2 < 0)
		{
			num2 = FindByApiName(missionModifiers, length, GearApiFallbacks);
		}
		bool flag = false;
		if (ConfigManager.EnableSplitPersonality.Value)
		{
			if (num >= 0)
			{
				flag |= SetWeight(missionModifiers, num, ConfigManager.SplitPersonalityWeight.Value, "Split Personality");
			}
			else
			{
				RandomizerModifiersPlugin.Logger.LogWarning((object)"[RandomizerModifiers] Could not find Split Personality (RandomizeCharacterOnRevive). Enable Debug.LogModifiersOnLoad to inspect the pool.");
			}
		}
		else
		{
			RandomizerModifiersPlugin.Logger.LogInfo((object)"[RandomizerModifiers] Split Personality left unchanged (disabled in config).");
		}
		if (ConfigManager.EnableButterFingers.Value)
		{
			if (num2 >= 0)
			{
				flag |= SetWeight(missionModifiers, num2, ConfigManager.ButterFingersWeight.Value, "Butter Fingers");
			}
			else
			{
				RandomizerModifiersPlugin.Logger.LogWarning((object)"[RandomizerModifiers] Could not find Butter Fingers (RandomizeGearOnRevive). Enable Debug.LogModifiersOnLoad to inspect the pool.");
			}
		}
		else
		{
			RandomizerModifiersPlugin.Logger.LogInfo((object)"[RandomizerModifiers] Butter Fingers left unchanged (disabled in config).");
		}
		if (flag)
		{
			missionModifiers.SetupWeightSum();
			RandomizerModifiersPlugin.Logger.LogInfo((object)"[RandomizerModifiers] MissionModifiers weight sum refreshed.");
		}
		else
		{
			RandomizerModifiersPlugin.Logger.LogInfo((object)"[RandomizerModifiers] No weight changes were required.");
		}
	}

	private static bool SetWeight(WeightedArray<MissionModifier> pool, int index, int weight, string label)
	{
		int weight2 = pool.GetWeight(index);
		MissionModifier val = pool[index];
		string text = (((Object)(object)val != (Object)null) ? val.APIName : "?");
		if (weight2 == weight)
		{
			RandomizerModifiersPlugin.Logger.LogInfo((object)$"[RandomizerModifiers] {label} ('{text}') already has weight {weight} (index {index}).");
			return false;
		}
		pool.SetWeight(index, weight);
		RandomizerModifiersPlugin.Logger.LogInfo((object)$"[RandomizerModifiers] {label} ('{text}') weight {weight2} -> {weight} (index {index}).");
		return true;
	}

	private static int FindByApiName(WeightedArray<MissionModifier> pool, int length, string[] candidates)
	{
		for (int i = 0; i < length; i++)
		{
			MissionModifier val = pool[i];
			if ((Object)(object)val == (Object)null || string.IsNullOrEmpty(val.APIName))
			{
				continue;
			}
			string aPIName = val.APIName;
			for (int j = 0; j < candidates.Length; j++)
			{
				if (aPIName.IndexOf(candidates[j], StringComparison.OrdinalIgnoreCase) >= 0)
				{
					return i;
				}
			}
		}
		return -1;
	}

	private static bool TryGetActionMethodNames(MissionModifierGeneric generic, out HashSet<string> methods)
	{
		methods = new HashSet<string>(StringComparer.Ordinal);
		FieldInfo field = typeof(MissionModifierGeneric).GetField("action", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		if (field == null)
		{
			return false;
		}
		object? value = field.GetValue(generic);
		UnityEventBase val = (UnityEventBase)((value is UnityEventBase) ? value : null);
		if (val == null)
		{
			return false;
		}
		int persistentEventCount = val.GetPersistentEventCount();
		for (int i = 0; i < persistentEventCount; i++)
		{
			string persistentMethodName = val.GetPersistentMethodName(i);
			if (!string.IsNullOrEmpty(persistentMethodName))
			{
				methods.Add(persistentMethodName);
			}
		}
		return methods.Count > 0;
	}

	private static void LogAllModifiers(WeightedArray<MissionModifier> pool, int length)
	{
		//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
		RandomizerModifiersPlugin.Logger.LogInfo((object)$"[RandomizerModifiers] Dumping {length} mission modifiers:");
		for (int i = 0; i < length; i++)
		{
			MissionModifier val = pool[i];
			if ((Object)(object)val == (Object)null)
			{
				RandomizerModifiersPlugin.Logger.LogInfo((object)$"  [{i}] <null> weight={pool.GetWeight(i)}");
				continue;
			}
			string arg = "";
			MissionModifierGeneric val2 = (MissionModifierGeneric)(object)((val is MissionModifierGeneric) ? val : null);
			if (val2 != null && TryGetActionMethodNames(val2, out var methods))
			{
				arg = " methods=[" + string.Join(", ", methods) + "]";
			}
			RandomizerModifiersPlugin.Logger.LogInfo((object)($"  [{i}] api='{val.APIName}' type={((object)val).GetType().Name} " + $"weight={pool.GetWeight(i)} flags={val.Flags}{arg}"));
		}
	}
}
[BepInPlugin("sparroh.randomizermodifiers", "RandomizerModifiers", "1.0.1")]
[MycoMod(/*Could not decode attribute arguments.*/)]
public class RandomizerModifiersPlugin : BaseUnityPlugin
{
	public const string PluginGUID = "sparroh.randomizermodifiers";

	public const string PluginName = "RandomizerModifiers";

	public const string PluginVersion = "1.0.1";

	internal static ManualLogSource Logger;

	internal static RandomizerModifiersPlugin Instance;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_0031: Expected O, but got Unknown
		Instance = this;
		Logger = ((BaseUnityPlugin)this).Logger;
		ConfigManager.Initialize(((BaseUnityPlugin)this).Config, Logger);
		_harmony = new Harmony("sparroh.randomizermodifiers");
		try
		{
			_harmony.PatchAll(typeof(GlobalLoadHook));
			Logger.LogInfo((object)"Harmony patches applied.");
		}
		catch (Exception ex)
		{
			Logger.LogError((object)("Error applying patches: " + ex.Message));
		}
		ModifierEnabler.TryEnable("Awake");
		Logger.LogInfo((object)"RandomizerModifiers v1.0.1 loaded.");
	}

	private void Update()
	{
		ConfigManager.Tick();
		if (ConfigManager.ConsumePendingRefresh())
		{
			ModifierEnabler.TryEnable("ConfigChanged", force: true);
		}
	}

	private void OnDestroy()
	{
		ConfigManager.Dispose();
		Harmony harmony = _harmony;
		if (harmony != null)
		{
			harmony.UnpatchSelf();
		}
		_harmony = null;
		Instance = null;
	}
}
namespace RandomizerModifiers
{
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "RandomizerModifiers";

		public const string PLUGIN_NAME = "RandomizerModifiers";

		public const string PLUGIN_VERSION = "1.0.1";
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}