using System; using System.Collections.Generic; using System.Diagnostics; 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 Microsoft.CodeAnalysis; using UnityEngine; [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("MoreStackables")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("MoreStackables")] [assembly: AssemblyTitle("MoreStackables")] [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.morestackables", "MoreStackables", "1.0.1")] [MycoMod(/*Could not decode attribute arguments.*/)] public class SparrohPlugin : BaseUnityPlugin { public const string PluginGUID = "sparroh.morestackables"; public const string PluginName = "MoreStackables"; public const string PluginVersion = "1.0.1"; internal static ManualLogSource Logger; internal static SparrohPlugin Instance; private static ConfigEntry enableMod; private static ConfigEntry logPromotedUpgrades; private static PropertyInfo flagsProperty; private static FieldInfo flagsBackingField; private static bool writePathResolved; private static bool applied; private void Awake() { Instance = this; Logger = ((BaseUnityPlugin)this).Logger; enableMod = ((BaseUnityPlugin)this).Config.Bind("General", "Enable", true, "When enabled, upgrades that are stackable in Ouroboros (CanStackInMission) become stackable in the base game as well (CanStack)."); logPromotedUpgrades = ((BaseUnityPlugin)this).Config.Bind("Debug", "Log Promoted Upgrades", false, "Log each upgrade that receives the CanStack flag."); PlayerData.AddRegisterUpgradesCallback((Action)OnUpgradesRegistered); try { if (!applied && (Object)(object)Global.Instance != (Object)null) { OnUpgradesRegistered(); } } catch (Exception ex) { Logger.LogDebug((object)("[MoreStackables] Early apply skipped: " + ex.Message)); } Logger.LogInfo((object)"MoreStackables v1.0.1 loaded."); } private void OnDestroy() { Instance = null; } private static void OnUpgradesRegistered() { if (applied) { return; } if (enableMod == null || !enableMod.Value) { Logger.LogInfo((object)"[MoreStackables] Disabled in config; no flags changed."); applied = true; return; } try { if ((Object)(object)Global.Instance == (Object)null) { Logger.LogWarning((object)"[MoreStackables] Global.Instance is null; will retry on next registration callback."); return; } int num = ApplyStackFlags(); applied = true; Logger.LogInfo((object)$"[MoreStackables] Promoted {num} upgrade(s) from CanStackInMission to CanStack."); } catch (Exception arg) { Logger.LogError((object)$"[MoreStackables] Failed to apply stack flags: {arg}"); } } private static int ApplyStackFlags() { ResolveWritePath(); HashSet seen = new HashSet(); int num = 0; if (Global.Instance.AllGear != null) { IUpgradable[] allGear = Global.Instance.AllGear; foreach (IUpgradable gear in allGear) { num += PromoteGearUpgrades(gear, seen); } } if (Global.Instance.Characters != null) { Character[] characters = Global.Instance.Characters; foreach (Character gear2 in characters) { num += PromoteGearUpgrades((IUpgradable)(object)gear2, seen); } } return num + PromoteGearUpgrades((IUpgradable)(object)Global.Instance, seen); } private static int PromoteGearUpgrades(IUpgradable gear, HashSet seen) { object obj; if (gear == null) { obj = null; } else { GearInfo info = gear.Info; obj = ((info != null) ? info.Upgrades : null); } if (obj == null) { return 0; } int num = 0; List upgrades = gear.Info.Upgrades; for (int i = 0; i < upgrades.Count; i++) { Upgrade val = upgrades[i]; if (!((Object)(object)val == (Object)null) && seen.Add(val) && TryPromote(val)) { num++; } } return num; } private static bool TryPromote(Upgrade upgrade) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) UpgradeFlags flags = upgrade.Flags; if ((flags & 0x4000) == 0) { return false; } if ((flags & 8) != 0) { return false; } UpgradeFlags value = (UpgradeFlags)(flags | 8); if (!TrySetFlags(upgrade, value)) { Logger.LogWarning((object)("[MoreStackables] Could not write Flags on '" + SafeName(upgrade) + "'.")); return false; } if (logPromotedUpgrades != null && logPromotedUpgrades.Value) { string arg = "unknown"; try { GearInfo val = PlayerData.FindGearInfo(upgrade); if ((Object)(object)val != (Object)null) { arg = val.Name ?? val.APIName ?? "unknown"; } } catch { } Logger.LogInfo((object)$"[MoreStackables] +CanStack: {SafeName(upgrade)} (gear={arg}, id={upgrade.NumberID})"); } return true; } private static void ResolveWritePath() { if (!writePathResolved) { writePathResolved = true; Type typeFromHandle = typeof(Upgrade); flagsBackingField = typeFromHandle.GetField("k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic) ?? typeFromHandle.GetField("Flags", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); flagsProperty = typeFromHandle.GetProperty("Flags", BindingFlags.Instance | BindingFlags.Public); } } private static bool TrySetFlags(Upgrade upgrade, UpgradeFlags value) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (flagsProperty != null && flagsProperty.CanWrite) { try { flagsProperty.SetValue(upgrade, value); return upgrade.Flags == value; } catch { } } if (flagsBackingField != null) { try { flagsBackingField.SetValue(upgrade, value); return upgrade.Flags == value; } catch (Exception ex) { Logger.LogError((object)("[MoreStackables] Backing-field write failed: " + ex.Message)); } } return false; } private static string SafeName(Upgrade upgrade) { try { return upgrade.Name ?? upgrade.APIName ?? ((object)upgrade).ToString(); } catch { return ((upgrade != null) ? upgrade.APIName : null) ?? "???"; } } } namespace MoreStackables { public static class MyPluginInfo { public const string PLUGIN_GUID = "MoreStackables"; public const string PLUGIN_NAME = "MoreStackables"; 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) { } } }