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 Enabled { get; private set; } public static void Initialize(ConfigFile configFile, ManualLogSource log) { config = configFile; logger = log; Enabled = config.Bind("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 list = new List { (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 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 list) { list.Clear(); } List list2 = new List(); List list3 = new List(); List list4 = new List(); 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(upgrade.Seed, ref val3, ref flag2); bool flag3 = val2.HasProperty(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 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) { } } }