Decompiled source of SkinRandomizer v1.1.2

BepInEx/plugins/SkinRandomizer.dll

Decompiled a month 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.Movement;
using UnityEngine;

[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("Sparroh")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.2.0")]
[assembly: AssemblyInformationalVersion("1.1.2")]
[assembly: AssemblyProduct("SkinRandomizer")]
[assembly: AssemblyTitle("SkinRandomizer")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.2.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 reloadPending;

	private static float lastReloadTime;

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

	public static void Initialize(ConfigFile configFile, ManualLogSource log)
	{
		config = configFile;
		logger = log;
		Enabled = config.Bind<bool>("General", "Enable Randomizer", true, "If true, randomly equips favorite skins on mission start.");
		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();
			logger.LogInfo((object)$"Config reloaded. Enabled = {Enabled.Value}");
		}
		catch (Exception ex)
		{
			logger.LogError((object)("Error reloading config: " + ex.Message));
		}
	}

	public static void Dispose()
	{
		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.skinrandomizer.cfg");
		configWatcher.NotifyFilter = NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite;
		configWatcher.Changed += OnConfigFileChanged;
		configWatcher.Created += OnConfigFileChanged;
		configWatcher.Renamed += OnConfigFileChanged;
		configWatcher.EnableRaisingEvents = true;
		logger.LogInfo((object)"Config hot-reload enabled.");
	}

	private static void OnConfigFileChanged(object sender, FileSystemEventArgs e)
	{
		reloadPending = true;
	}
}
[HarmonyPatch]
public static class DropPodPatches
{
	[HarmonyPostfix]
	[HarmonyPatch(typeof(DropPod), "StartCountdown_ClientRpc")]
	public static void StartCountdown_ClientRpc_Postfix()
	{
		if (ConfigManager.Enabled.Value)
		{
			SkinRandomizerService.RandomizeFavoriteSkins();
		}
	}
}
[BepInPlugin("sparroh.skinrandomizer", "SkinRandomizer", "1.1.2")]
[MycoMod(/*Could not decode attribute arguments.*/)]
public class SkinRandomizerPlugin : BaseUnityPlugin
{
	public const string PluginGUID = "sparroh.skinrandomizer";

	public const string PluginName = "SkinRandomizer";

	public const string PluginVersion = "1.1.2";

	internal static ManualLogSource Logger;

	private Harmony harmony;

	private void Awake()
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Expected O, but got Unknown
		Logger = ((BaseUnityPlugin)this).Logger;
		ConfigManager.Initialize(((BaseUnityPlugin)this).Config, Logger);
		harmony = new Harmony("sparroh.skinrandomizer");
		try
		{
			harmony.PatchAll(typeof(DropPodPatches));
			Logger.LogInfo((object)"Harmony patches applied.");
		}
		catch (Exception ex)
		{
			Logger.LogError((object)("Error applying patches: " + ex.Message));
		}
		Logger.LogInfo((object)"SkinRandomizer v1.1.2 loaded successfully.");
	}

	private void Update()
	{
		ConfigManager.Tick();
	}

	private void OnDestroy()
	{
		ConfigManager.Dispose();
		Harmony obj = harmony;
		if (obj != null)
		{
			obj.UnpatchSelf();
		}
	}
}
public static class SkinRandomizerService
{
	private static readonly FieldInfo EquippedSkinsField = typeof(GearData).GetField("equippedSkins", BindingFlags.Instance | BindingFlags.NonPublic);

	private static MethodInfo skinUpgradeApplyMethod;

	private static bool skinUpgradeApplyResolved;

	private static int skinUpgradeApplyParamCount;

	public static void RandomizeFavoriteSkins()
	{
		try
		{
			if ((Object)(object)Player.LocalPlayer == (Object)null || PlayerData.Instance == null)
			{
				return;
			}
			List<IUpgradable> list = new List<IUpgradable> { (IUpgradable)(object)Player.LocalPlayer.Character };
			if ((Object)(object)DropPod.Instance != (Object)null)
			{
				list.Add((IUpgradable)(((object)DropPod.Instance.Prefab) ?? ((object)DropPod.Instance)));
			}
			TryAddWeaponGear(list, PlayerData.Instance.weapon1ID);
			TryAddWeaponGear(list, PlayerData.Instance.weapon2ID);
			foreach (IUpgradable item in list)
			{
				try
				{
					RandomizeSkinsForGear(item);
				}
				catch (Exception ex)
				{
					ManualLogSource logger = SkinRandomizerPlugin.Logger;
					if (logger != null)
					{
						object obj;
						if (item == null)
						{
							obj = null;
						}
						else
						{
							GearInfo info = item.Info;
							obj = ((info != null) ? info.Name : null);
						}
						if (obj == null)
						{
							obj = "unknown";
						}
						logger.LogError((object)("Failed randomizing skins for gear '" + (string?)obj + "': " + ex.Message));
					}
				}
			}
		}
		catch (Exception ex2)
		{
			ManualLogSource logger2 = SkinRandomizerPlugin.Logger;
			if (logger2 != null)
			{
				logger2.LogError((object)("Failed randomizing favorite skins: " + ex2.Message));
			}
		}
	}

	private static void TryAddWeaponGear(List<IUpgradable> gears, int weaponId)
	{
		if (weaponId != 0)
		{
			IUpgradable gearFromID = PlayerData.GetGearFromID(weaponId);
			if (gearFromID != null)
			{
				gears.Add(gearFromID);
			}
		}
	}

	private static void RandomizeSkinsForGear(IUpgradable gear)
	{
		if (gear == null)
		{
			return;
		}
		GearData gearData = PlayerData.GetGearData(gear);
		if (gearData == null)
		{
			return;
		}
		if (EquippedSkinsField?.GetValue(gearData) is List<UpgradeEquipData> list)
		{
			list.Clear();
		}
		List<UpgradeInstance> list2 = new List<UpgradeInstance>();
		List<UpgradeInstance> list3 = new List<UpgradeInstance>();
		List<UpgradeInstance> list4 = new List<UpgradeInstance>();
		SkinEnumerator val = default(SkinEnumerator);
		((SkinEnumerator)(ref val))..ctor(gear);
		SkinUpgradeProperty_VFXCrab val3 = default(SkinUpgradeProperty_VFXCrab);
		bool flag2 = default(bool);
		SkinUpgradeProperty_GunCrab val4 = default(SkinUpgradeProperty_GunCrab);
		while (((SkinEnumerator)(ref val)).MoveNext())
		{
			UpgradeInstance upgrade = ((SkinEnumerator)(ref val)).Upgrade;
			if (!upgrade.Favorite)
			{
				continue;
			}
			Upgrade upgrade2 = upgrade.Upgrade;
			SkinUpgrade val2 = (SkinUpgrade)(object)((upgrade2 is SkinUpgrade) ? upgrade2 : null);
			if (!((Object)(object)val2 == (Object)null))
			{
				bool flag = val2.HasProperty<SkinUpgradeProperty_VFXCrab>(upgrade.Seed, ref val3, ref flag2);
				bool flag3 = val2.HasProperty<SkinUpgradeProperty_GunCrab>(upgrade.Seed, ref val4, ref flag2);
				if (flag)
				{
					list4.Add(upgrade);
				}
				else if (flag3)
				{
					list3.Add(upgrade);
				}
				else
				{
					list2.Add(upgrade);
				}
			}
		}
		if ((0u | (SelectAndEquipRandom(list2, gearData) ? 1u : 0u) | (SelectAndEquipRandom(list3, gearData) ? 1u : 0u) | (SelectAndEquipRandom(list4, gearData) ? 1u : 0u)) != 0)
		{
			ApplySkinsToGear(gear);
		}
	}

	private static bool SelectAndEquipRandom(List<UpgradeInstance> skins, GearData gearData)
	{
		if (skins.Count == 0)
		{
			return false;
		}
		int index = Random.Range(0, skins.Count);
		UpgradeInstance val = skins[index];
		gearData.EquipUpgrade(val, (sbyte)0, (sbyte)0, (byte)0, true);
		return true;
	}

	private static void ApplySkinsToGear(IUpgradable gearPrefab)
	{
		if ((object)gearPrefab == Player.LocalPlayer.Character)
		{
			Player.LocalPlayer.ApplySkins();
			return;
		}
		if ((Object)(object)DropPod.Instance != (Object)null && ((object)gearPrefab == DropPod.Instance || gearPrefab == DropPod.Instance.Prefab || gearPrefab is DropPod))
		{
			DropPod.Instance.ApplyGearSkins();
			return;
		}
		IGear[] gear = Player.LocalPlayer.Gear;
		if (gear != null)
		{
			foreach (IGear val in gear)
			{
				if (val != null && (((IUpgradable)val).Prefab == gearPrefab || (object)val == gearPrefab || ((Object)(object)((IUpgradable)val).Info != (Object)null && (Object)(object)gearPrefab.Info != (Object)null && ((IUpgradable)val).Info.ID == gearPrefab.Info.ID)))
				{
					val.ApplyUpgrades();
					return;
				}
			}
		}
		EquippedSkinEnumerator val2 = default(EquippedSkinEnumerator);
		((EquippedSkinEnumerator)(ref val2))..ctor(gearPrefab);
		while (((EquippedSkinEnumerator)(ref val2)).MoveNext())
		{
			UpgradeInstance upgrade = ((EquippedSkinEnumerator)(ref val2)).Upgrade;
			Upgrade obj = ((upgrade != null) ? upgrade.Upgrade : null);
			SkinUpgrade val3 = (SkinUpgrade)(object)((obj is SkinUpgrade) ? obj : null);
			if (val3 != null)
			{
				ApplySkinUpgrade(val3, gearPrefab, upgrade.Seed, Player.LocalPlayer);
			}
		}
		gearPrefab.OnUpgradesChanged((HexMap)null, (ModuleEquipSlots)null);
		Player.LocalPlayer.ApplySkins();
	}

	private static void ApplySkinUpgrade(SkinUpgrade skinUpgrade, IUpgradable gear, int seed, Player owner)
	{
		if ((Object)(object)skinUpgrade == (Object)null)
		{
			return;
		}
		EnsureSkinUpgradeApplyMethod();
		if (skinUpgradeApplyMethod == null)
		{
			ManualLogSource logger = SkinRandomizerPlugin.Logger;
			if (logger != null)
			{
				logger.LogError((object)"Could not resolve SkinUpgrade.Apply for this game build.");
			}
			return;
		}
		object[] parameters = ((skinUpgradeApplyParamCount < 5) ? new object[4] { gear, seed, owner, null } : new object[5] { gear, seed, owner, null, false });
		skinUpgradeApplyMethod.Invoke(skinUpgrade, parameters);
	}

	private static void EnsureSkinUpgradeApplyMethod()
	{
		if (skinUpgradeApplyResolved)
		{
			return;
		}
		skinUpgradeApplyResolved = true;
		MethodInfo[] methods = typeof(SkinUpgrade).GetMethods(BindingFlags.Instance | BindingFlags.Public);
		foreach (MethodInfo methodInfo in methods)
		{
			if (!(methodInfo.Name != "Apply"))
			{
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length >= 3 && !(parameters[0].ParameterType != typeof(IUpgradable)) && !(parameters[1].ParameterType != typeof(int)) && !(parameters[2].ParameterType != typeof(Player)) && (skinUpgradeApplyMethod == null || parameters.Length > skinUpgradeApplyParamCount))
				{
					skinUpgradeApplyMethod = methodInfo;
					skinUpgradeApplyParamCount = parameters.Length;
				}
			}
		}
	}
}
namespace SkinRandomizer
{
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "SkinRandomizer";

		public const string PLUGIN_NAME = "SkinRandomizer";

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