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)
{
}
}
}