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(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("SkinRandomizer")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SkinRandomizer")] [assembly: AssemblyTitle("SkinRandomizer")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } [BepInPlugin("sparroh.skinrandomizer", "SkinRandomizer", "1.1.0")] [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.0"; internal static ManualLogSource Logger; internal static ConfigEntry enabled; private FileSystemWatcher _configWatcher; private DateTime _lastReloadTime = DateTime.MinValue; private const int ReloadDebounceMs = 500; private void Awake() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) Logger = ((BaseUnityPlugin)this).Logger; enabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "If true, randomly equips favorite skins on mission start."); SetupConfigHotReload(); try { new Harmony("sparroh.skinrandomizer").PatchAll(typeof(DropPodPatches)); } catch (Exception ex) { Logger.LogError((object)("Error applying patches: " + ex.Message)); } Logger.LogInfo((object)"SkinRandomizer loaded successfully."); } private void SetupConfigHotReload() { try { string configFilePath = ((BaseUnityPlugin)this).Config.ConfigFilePath; string directoryName = Path.GetDirectoryName(configFilePath); string fileName = Path.GetFileName(configFilePath); if (string.IsNullOrEmpty(directoryName) || string.IsNullOrEmpty(fileName)) { Logger.LogWarning((object)"Could not set up config hot-reload: invalid config path."); return; } _configWatcher = new FileSystemWatcher(directoryName, fileName) { NotifyFilter = (NotifyFilters.Size | NotifyFilters.LastWrite) }; _configWatcher.Changed += OnConfigFileChanged; _configWatcher.EnableRaisingEvents = true; Logger.LogInfo((object)"Config hot-reload enabled."); } catch (Exception ex) { Logger.LogError((object)("Failed to set up config hot-reload: " + ex.Message)); } } private void OnConfigFileChanged(object sender, FileSystemEventArgs e) { DateTime utcNow = DateTime.UtcNow; if ((utcNow - _lastReloadTime).TotalMilliseconds < 500.0) { return; } _lastReloadTime = utcNow; try { ((BaseUnityPlugin)this).Config.Reload(); Logger.LogInfo((object)$"Config reloaded. Enabled = {enabled.Value}"); } catch (Exception ex) { Logger.LogError((object)("Failed to reload config: " + ex.Message)); } } private void OnDestroy() { if (_configWatcher != null) { _configWatcher.Changed -= OnConfigFileChanged; _configWatcher.EnableRaisingEvents = false; _configWatcher.Dispose(); _configWatcher = null; } } } [HarmonyPatch] public static class DropPodPatches { [HarmonyPostfix] [HarmonyPatch(typeof(DropPod), "StartCountdown_ClientRpc")] public static void StartCountdown_ClientRpc_Postfix() { if (SkinRandomizerPlugin.enabled.Value) { RandomizeFavoriteSkins(); } } private static void RandomizeFavoriteSkins() { if ((Object)(object)Player.LocalPlayer == (Object)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) { RandomizeSkinsForGear(item); } } 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 (typeof(GearData).GetField("equippedSkins", BindingFlags.Instance | BindingFlags.NonPublic)?.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) { val3.Apply(gearPrefab, upgrade.Seed, Player.LocalPlayer, (List)null); } } gearPrefab.OnUpgradesChanged((HexMap)null, (ModuleEquipSlots)null); Player.LocalPlayer.ApplySkins(); } } namespace SkinRandomizer { public static class MyPluginInfo { public const string PLUGIN_GUID = "SkinRandomizer"; public const string PLUGIN_NAME = "SkinRandomizer"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }