Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of LevelUpChoicesFixes v1.0.3
BepInEx/plugins/LevelUpChoicesFixes.dll
Decompiled 11 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using LevelUpChoices; using LevelUpChoices.UI; using Microsoft.CodeAnalysis; using R2API; using R2API.Networking; using R2API.Networking.Interfaces; using R2API.Utils; using RiskOfOptions; using RiskOfOptions.OptionConfigs; using RiskOfOptions.Options; using RoR2; using RoR2.UI; using UnityEngine; using UnityEngine.Networking; [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("LevelUpChoicesFixes")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+879ca4cdc82ba03aa26abcacd4a3f0a7e5677506")] [assembly: AssemblyProduct("LevelUpChoicesFixes")] [assembly: AssemblyTitle("LevelUpChoicesFixes")] [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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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; } } } namespace TeamTayne.LevelUpChoicesFixes { internal static class ConfigState { internal sealed class SyncFixConfig : INetMessage, ISerializableObject { private bool _enableQuality; private bool _removeQualityInteractables; private float _qualityChance; private float _uncommon; private float _rare; private float _epic; private float _legendary; private int _guaranteedQualityEvery; private int _guaranteedQualityChoices; private string _blacklist; private float _creditMultiplier; private static SyncFixConfig _overrides; public SyncFixConfig() { } public SyncFixConfig(bool _) { _enableQuality = EnableQualityIntegration.Value; _removeQualityInteractables = RemoveQualityInteractables.Value; _qualityChance = QualityChance.Value; _uncommon = UncommonQualityWeight.Value; _rare = RareQualityWeight.Value; _epic = EpicQualityWeight.Value; _legendary = LegendaryQualityWeight.Value; _guaranteedQualityEvery = GuaranteedQualityEveryNLevels.Value; _guaranteedQualityChoices = GuaranteedQualityChoiceCount.Value; _blacklist = ItemBlacklist.Value ?? string.Empty; _creditMultiplier = InteractableCreditMultiplier.Value; } public void Serialize(NetworkWriter writer) { writer.Write(_enableQuality); writer.Write(_removeQualityInteractables); writer.Write(_qualityChance); writer.Write(_uncommon); writer.Write(_rare); writer.Write(_epic); writer.Write(_legendary); writer.Write(_guaranteedQualityEvery); writer.Write(_guaranteedQualityChoices); writer.Write(_blacklist ?? string.Empty); writer.Write(_creditMultiplier); } public void Deserialize(NetworkReader reader) { _enableQuality = reader.ReadBoolean(); _removeQualityInteractables = reader.ReadBoolean(); _qualityChance = reader.ReadSingle(); _uncommon = reader.ReadSingle(); _rare = reader.ReadSingle(); _epic = reader.ReadSingle(); _legendary = reader.ReadSingle(); _guaranteedQualityEvery = reader.ReadInt32(); _guaranteedQualityChoices = reader.ReadInt32(); _blacklist = reader.ReadString(); _creditMultiplier = reader.ReadSingle(); } public void OnReceived() { if (!NetworkServer.active) { _hasServerOverride = true; _serverBlacklist = _blacklist ?? string.Empty; _overrides = this; Log.Info("Applied host LevelUpChoicesFixes configuration."); } } internal static T GetOverride<T>(ConfigEntry<T> entry) { return (T)(((ConfigEntryBase)entry).Definition.Key switch { "Enable Quality Integration" => _overrides._enableQuality, "Remove Quality Interactables" => _overrides._removeQualityInteractables, "Quality Chance" => _overrides._qualityChance, "Uncommon Quality Weight" => _overrides._uncommon, "Rare Quality Weight" => _overrides._rare, "Epic Quality Weight" => _overrides._epic, "Legendary Quality Weight" => _overrides._legendary, "Guaranteed Quality Every N Levels" => _overrides._guaranteedQualityEvery, "Guaranteed Quality Choice Count" => _overrides._guaranteedQualityChoices, "Interactable Credit Multiplier" => _overrides._creditMultiplier, _ => entry.Value, }); } internal static void ClearOverride() { _overrides = null; } } private const string ServerSection = "Server"; private static bool _hasServerOverride; private static string _serverBlacklist = string.Empty; internal static ConfigEntry<bool> EnableQualityIntegration { get; private set; } internal static ConfigEntry<bool> RemoveQualityInteractables { get; private set; } internal static ConfigEntry<float> QualityChance { get; private set; } internal static ConfigEntry<float> UncommonQualityWeight { get; private set; } internal static ConfigEntry<float> RareQualityWeight { get; private set; } internal static ConfigEntry<float> EpicQualityWeight { get; private set; } internal static ConfigEntry<float> LegendaryQualityWeight { get; private set; } internal static ConfigEntry<int> GuaranteedQualityEveryNLevels { get; private set; } internal static ConfigEntry<int> GuaranteedQualityChoiceCount { get; private set; } internal static ConfigEntry<string> ItemBlacklist { get; private set; } internal static ConfigEntry<float> InteractableCreditMultiplier { get; private set; } internal static bool QualityEnabled => Value<bool>(EnableQualityIntegration); internal static bool RemoveQualityInteractablesValue => Value<bool>(RemoveQualityInteractables); internal static float QualityChanceValue => ClampPercent(Value<float>(QualityChance)); internal static float[] QualityWeights => new float[4] { Math.Max(0f, Value<float>(UncommonQualityWeight)), Math.Max(0f, Value<float>(RareQualityWeight)), Math.Max(0f, Value<float>(EpicQualityWeight)), Math.Max(0f, Value<float>(LegendaryQualityWeight)) }; internal static int GuaranteedQualityEveryValue => Math.Max(0, Value<int>(GuaranteedQualityEveryNLevels)); internal static int GuaranteedQualityChoicesValue => Math.Max(1, Value<int>(GuaranteedQualityChoiceCount)); internal static string ItemBlacklistValue { get { if (!_hasServerOverride) { return ItemBlacklist.Value; } return _serverBlacklist; } } internal static float InteractableCreditMultiplierValue => Math.Max(0f, Value<float>(InteractableCreditMultiplier)); internal static void Initialize(ConfigFile config) { //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Expected O, but got Unknown //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Expected O, but got Unknown EnableQualityIntegration = config.Bind<bool>("Server", "Enable Quality Integration", true, "Promote LevelUpChoices base items to Item Qualities variants after the original roll."); RemoveQualityInteractables = config.Bind<bool>("Server", "Remove Quality Interactables", true, "Remove Item Qualities item sources (quality chests, printers, the dropped-item barrel, cloaked chest, and equipment barrel) when LevelUpChoices removes item sources."); QualityChance = config.Bind<float>("Server", "Quality Chance", 4f, "Percent chance for a level-up item to receive a quality. Host value is authoritative."); UncommonQualityWeight = config.Bind<float>("Server", "Uncommon Quality Weight", 70f, "Relative weight for Uncommon quality variants."); RareQualityWeight = config.Bind<float>("Server", "Rare Quality Weight", 20f, "Relative weight for Rare quality variants."); EpicQualityWeight = config.Bind<float>("Server", "Epic Quality Weight", 8f, "Relative weight for Epic quality variants."); LegendaryQualityWeight = config.Bind<float>("Server", "Legendary Quality Weight", 2f, "Relative weight for Legendary quality variants."); GuaranteedQualityEveryNLevels = config.Bind<int>("Server", "Guaranteed Quality Every N Levels", 5, new ConfigDescription("Queue one guaranteed-quality choice set at this level interval. Set to 0 to disable.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); GuaranteedQualityChoiceCount = config.Bind<int>("Server", "Guaranteed Quality Choice Count", 3, new ConfigDescription("Number of quality choices in each guaranteed-quality set. Capped by the upstream choice count.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>())); ItemBlacklist = config.Bind<string>("Server", "Item Blacklist", "DefensiveMicrobots", "Comma-separated item names that are removed from every LevelUpChoices player pool."); InteractableCreditMultiplier = config.Bind<float>("Server", "Interactable Credit Multiplier", 1f, "Multiplier applied to the original interactable credit budget; 1 leaves it unchanged."); } internal static void RegisterNetworkMessage() { NetworkingAPI.RegisterMessageType<SyncFixConfig>(); Run.onRunStartGlobal += OnRunStart; Run.onRunDestroyGlobal += OnRunDestroy; SubscribeServerEntries(); } internal static void UnregisterNetworkMessage() { Run.onRunStartGlobal -= OnRunStart; Run.onRunDestroyGlobal -= OnRunDestroy; UnsubscribeServerEntries(); } private static void SubscribeServerEntries() { RemoveQualityInteractables.SettingChanged += OnServerSettingChanged; QualityChance.SettingChanged += OnServerSettingChanged; UncommonQualityWeight.SettingChanged += OnServerSettingChanged; RareQualityWeight.SettingChanged += OnServerSettingChanged; EpicQualityWeight.SettingChanged += OnServerSettingChanged; LegendaryQualityWeight.SettingChanged += OnServerSettingChanged; GuaranteedQualityEveryNLevels.SettingChanged += OnServerSettingChanged; GuaranteedQualityChoiceCount.SettingChanged += OnServerSettingChanged; ItemBlacklist.SettingChanged += OnServerSettingChanged; InteractableCreditMultiplier.SettingChanged += OnServerSettingChanged; } private static void UnsubscribeServerEntries() { RemoveQualityInteractables.SettingChanged -= OnServerSettingChanged; QualityChance.SettingChanged -= OnServerSettingChanged; UncommonQualityWeight.SettingChanged -= OnServerSettingChanged; RareQualityWeight.SettingChanged -= OnServerSettingChanged; EpicQualityWeight.SettingChanged -= OnServerSettingChanged; LegendaryQualityWeight.SettingChanged -= OnServerSettingChanged; GuaranteedQualityEveryNLevels.SettingChanged -= OnServerSettingChanged; GuaranteedQualityChoiceCount.SettingChanged -= OnServerSettingChanged; ItemBlacklist.SettingChanged -= OnServerSettingChanged; InteractableCreditMultiplier.SettingChanged -= OnServerSettingChanged; } private static void OnServerSettingChanged(object sender, EventArgs _) { if (NetworkServer.active && (Object)(object)Run.instance != (Object)null) { SendToClients(); } } private static void SendToClients() { NetMessageExtensions.Send((INetMessage)(object)new SyncFixConfig(_: true), (NetworkDestination)1); } private static void OnRunStart(Run _) { if (NetworkServer.active) { SendToClients(); } } private static void OnRunDestroy(Run _) { _hasServerOverride = false; _serverBlacklist = string.Empty; SyncFixConfig.ClearOverride(); } private static T Value<T>(ConfigEntry<T> entry) { if (!_hasServerOverride) { return entry.Value; } return SyncFixConfig.GetOverride<T>(entry); } private static float ClampPercent(float value) { return Math.Max(0f, Math.Min(100f, value)); } } [BepInPlugin("TeamTayne.LevelUpChoicesFixes", "LevelUpChoicesFixes", "1.0.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency("karaeren.LevelUpChoices", "1.1.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public sealed class LevelUpChoicesFixes : BaseUnityPlugin { internal const string PluginGUID = "TeamTayne.LevelUpChoicesFixes"; internal const string PluginName = "LevelUpChoicesFixes"; internal const string PluginVersion = "1.0.3"; internal const string ItemQualitiesGuid = "com.Gorakh.ItemQualities"; private Harmony _harmony; private void Awake() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown Log.Init(((BaseUnityPlugin)this).Logger); ConfigState.Initialize(((BaseUnityPlugin)this).Config); RiskOfOptionsIntegration.TryRegister(); ConfigState.RegisterNetworkMessage(); _harmony = new Harmony("TeamTayne.LevelUpChoicesFixes"); IntegrationPatches.Install(_harmony); Log.Info("LevelUpChoicesFixes initialized; LevelUpChoices remains the sole level-up system."); } private void OnDestroy() { ConfigState.UnregisterNetworkMessage(); try { GamePauseManager.ForceReset(); } catch (Exception ex) { Log.Warning("Pause cleanup failed during plugin teardown: " + ex.Message); } IntegrationPatches.Uninstall(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal static class Log { private static ManualLogSource _source; internal static void Init(ManualLogSource source) { _source = source; } internal static void Info(object message) { ManualLogSource source = _source; if (source != null) { source.LogInfo(message); } } internal static void Warning(object message) { ManualLogSource source = _source; if (source != null) { source.LogWarning(message); } } internal static void Error(object message) { ManualLogSource source = _source; if (source != null) { source.LogError(message); } } } internal static class IntegrationPatches { private static class ItemBlacklist { internal static bool Contains(string name) { if (string.IsNullOrWhiteSpace(name)) { return false; } return ConfigState.ItemBlacklistValue.Split(',').Any((string raw) => string.Equals(raw.Trim(), name, StringComparison.OrdinalIgnoreCase)); } } private static readonly FieldInfo PlayerStatesField = AccessTools.Field(typeof(LevelUpManager), "playerStates"); private static readonly FieldInfo CurrentOptionsField = AccessTools.Field(typeof(PlayerState), "CurrentOptions"); private static readonly FieldInfo CurrentSynergiesField = AccessTools.Field(typeof(PlayerState), "CurrentSynergies"); private static readonly FieldInfo SelectionTokensField = AccessTools.Field(typeof(PlayerState), "SelectionTokens"); private static readonly FieldInfo DropTableTiersField = AccessTools.Field(typeof(PlayerDropTable), "_tiers"); private static readonly FieldInfo DropTableWeightsField = AccessTools.Field(typeof(PlayerDropTable), "_weights"); private static readonly FieldInfo DropTableTierCountsField = AccessTools.Field(typeof(PlayerDropTable), "_tierCounts"); private static readonly FieldInfo DropTableLastTokensField = AccessTools.Field(typeof(PlayerDropTable), "_lastCalculatedTokens"); private static readonly FieldInfo InteractableCreditField = AccessTools.Field(typeof(SceneDirector), "interactableCredit"); private static readonly FieldInfo ParentBlacklistedSpawnsField = AccessTools.Field(typeof(InteractableSpawnHook), "BlacklistedSpawns"); private static readonly Dictionary<NetworkInstanceId, int> PendingGuaranteedQualityBatches = new Dictionary<NetworkInstanceId, int>(); private static readonly HashSet<string> ReportedRefusals = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private const string EquipmentBarrelName = "iscequipmentbarrel"; private const int EquipmentBarrelLimit = 4; private static int SpawnedEquipmentBarrels; private static readonly string[] ParentCombatShrinesToKeep = new string[3] { "iscshrinecombat", "iscshrinecombatsandy", "iscshrinecombatsnowy" }; private static ItemIndex _rerollBaseItem = (ItemIndex)(-1); private static ItemIndex _rerollOriginalItem = (ItemIndex)(-1); private static Run _pendingQualityRun; internal static void Install(Harmony harmony) { PatchInitialize(harmony); PatchRoll(harmony); PatchRerollAndBanish(harmony); PatchLevelSchedule(harmony); PatchPause(harmony); PatchInteractables(harmony); QualityRuntime.TryInitialize(); } internal static void Uninstall() { DirectorAPI.InteractableActions -= FilterInteractablePool; } private static void PatchInitialize(Harmony harmony) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(PlayerDropTable), "Initialize", new Type[1] { typeof(bool) }, (Type[])null); if (methodInfo == null || DropTableTiersField == null || DropTableWeightsField == null || DropTableTierCountsField == null) { Log.Warning("PlayerDropTable.Initialize seam is unsupported; blacklist and WorldUnique filtering disabled."); } else { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(IntegrationPatches), "PlayerDropTableInitializePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } private static void PatchRoll(Harmony harmony) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown //IL_00a2: Expected O, but got Unknown //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(LevelUpManager), "RollSingleSlot", (Type[])null, (Type[])null); if (!HasParameters(methodInfo, typeof(NetworkInstanceId), typeof(PlayerState), typeof(List<ItemIndex>)) || methodInfo.ReturnType != typeof((ItemIndex, ItemIndex))) { Log.Warning("LevelUpManager.RollSingleSlot seam is unsupported; Quality promotion and canonical exclusions disabled."); return; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(IntegrationPatches), "RollSingleSlotPrefix", (Type[])null), new HarmonyMethod(typeof(IntegrationPatches), "RollSingleSlotPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); MethodInfo methodInfo2 = AccessTools.Method(typeof(LevelUpManager), "RollItemsForPlayer", (Type[])null, (Type[])null); if (HasParameters(methodInfo2, typeof(NetworkInstanceId))) { harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(IntegrationPatches), "RollItemsForPlayerPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { Log.Warning("LevelUpManager.RollItemsForPlayer seam is unsupported; guaranteed quality choices disabled."); } } private static void PatchRerollAndBanish(Harmony harmony) { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown //IL_00da: Expected O, but got Unknown //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(LevelUpManager), "HandlePlayerReroll", (Type[])null, (Type[])null); MethodInfo method = AccessTools.Method(typeof(LevelUpManager), "HandlePlayerBanish", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(PlayerDropTable), "Remove", new Type[1] { typeof(ItemIndex) }, (Type[])null); if (!HasParameters(methodInfo, typeof(NetworkInstanceId), typeof(int)) || !HasParameters(methodInfo2, typeof(ItemIndex))) { Log.Warning("Reroll/banish seams are unsupported; duplicate-item protection disabled."); } else { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(IntegrationPatches), "RerollPrefix", (Type[])null), new HarmonyMethod(typeof(IntegrationPatches), "RerollPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(IntegrationPatches), "RemovePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } if (!HasParameters(method, typeof(NetworkInstanceId), typeof(int))) { Log.Warning("HandlePlayerBanish seam is unsupported; banish canonicalization disabled."); } } private static void PatchLevelSchedule(Harmony harmony) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(LevelUpManager), "OnLevelUp", new Type[1] { typeof(uint) }, (Type[])null); if (!HasParameters(methodInfo, typeof(uint))) { Log.Warning("LevelUpManager.OnLevelUp seam is unsupported; schedule and level reroll refresh disabled."); } else { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(IntegrationPatches), "OnLevelUpPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } private static void PatchPause(Harmony harmony) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(PauseScreenController), "OnEnable", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(PauseScreenController), "OnDisable", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(ItemSelectUI), "Hide", (Type[])null, (Type[])null); if (HasParameters(methodInfo)) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(IntegrationPatches), "PauseScreenEnablePrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } if (HasParameters(methodInfo2)) { harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(IntegrationPatches), "PauseScreenDisablePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } if (HasParameters(methodInfo3)) { harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(IntegrationPatches), "ItemSelectHidePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } if (!HasParameters(methodInfo) || !HasParameters(methodInfo2) || !HasParameters(methodInfo3)) { Log.Warning("Pause/UI seams are unsupported; defensive pause restoration is partially disabled."); } } private static void PatchInteractables(Harmony harmony) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Expected O, but got Unknown //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Expected O, but got Unknown //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Expected O, but got Unknown //IL_0143: Expected O, but got Unknown DirectorAPI.InteractableActions += FilterInteractablePool; PreserveParentCombatShrines(); MethodInfo methodInfo = AccessTools.Method(typeof(SceneDirector), "PopulateScene", (Type[])null, (Type[])null); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(IntegrationPatches), "FilterInteractableCategoriesPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); if (InteractableCreditField != null) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(IntegrationPatches), "InteractableCreditPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } else if (Math.Abs(ConfigState.InteractableCreditMultiplier.Value - 1f) > 0.001f) { Log.Warning("SceneDirector seam is unsupported; final interactable filtering and credit scaling disabled."); } MethodInfo methodInfo2 = AccessTools.Method(typeof(DirectorCore), "TrySpawnObject", new Type[1] { typeof(DirectorSpawnRequest) }, (Type[])null); if (methodInfo2 != null) { harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(IntegrationPatches), "BlockedDirectSpawnPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(IntegrationPatches), "EquipmentBarrelLimitPrefix", (Type[])null), new HarmonyMethod(typeof(IntegrationPatches), "TrackEquipmentBarrelPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } else { Log.Warning("DirectorCore.TrySpawnObject seam is unsupported; item sources spawned outside stage pools (Item Qualities speed barrels and stealth chests, key lockboxes, shipping requests) stay spawnable."); } } private static void PreserveParentCombatShrines() { if (!(ParentBlacklistedSpawnsField?.GetValue(null) is HashSet<string> hashSet)) { Log.Warning("LevelUpChoices interactable blacklist seam is unsupported; Collective Shrine of Combat remains removed."); return; } string[] parentCombatShrinesToKeep = ParentCombatShrinesToKeep; foreach (string item in parentCombatShrinesToKeep) { hashSet.Remove(item); } } private static bool BlockedDirectSpawnPrefix(DirectorSpawnRequest __0) { if (!NetworkServer.active || !ModConfig.IsModEnabled || !ModConfig.EnableInteractableRemoval.Value) { return true; } SpawnCard val = __0?.spawnCard; if ((Object)(object)val == (Object)null || !ItemSources.IsBlocked(((Object)val).name)) { return true; } if (ReportedRefusals.Add(((Object)val).name)) { Log.Info("Refused direct spawn of removed item source " + ((Object)val).name + "."); } return false; } private static bool EquipmentBarrelLimitPrefix(DirectorSpawnRequest __0) { if (!NetworkServer.active || !ModConfig.IsModEnabled || !ModConfig.EnableInteractableRemoval.Value) { return true; } SpawnCard val = __0?.spawnCard; if ((Object)(object)val == (Object)null || !string.Equals(((Object)val).name, "iscequipmentbarrel", StringComparison.OrdinalIgnoreCase) || SpawnedEquipmentBarrels < 4) { return true; } if (ReportedRefusals.Add("iscequipmentbarrel")) { Log.Info($"Refused equipment barrel after reaching the per-stage limit of {4}."); } return false; } private static void TrackEquipmentBarrelPostfix(DirectorSpawnRequest __0, GameObject __result) { if (!((Object)(object)__result == (Object)null) && NetworkServer.active && ModConfig.IsModEnabled && ModConfig.EnableInteractableRemoval.Value) { object a; if (__0 == null) { a = null; } else { SpawnCard spawnCard = __0.spawnCard; a = ((spawnCard != null) ? ((Object)spawnCard).name : null); } if (string.Equals((string?)a, "iscequipmentbarrel", StringComparison.OrdinalIgnoreCase)) { SpawnedEquipmentBarrels++; } } } private static void FilterInteractableCategoriesPrefix() { SpawnedEquipmentBarrels = 0; if (ModConfig.IsModEnabled && ModConfig.EnableInteractableRemoval.Value && Object.op_Implicit((Object)(object)ClassicStageInfo.instance?.interactableCategories)) { FilterInteractableSelection(ClassicStageInfo.instance.interactableCategories); } } private static void FilterInteractablePool(DccsPool interactablesDccsPool, StageInfo _) { if (!ModConfig.IsModEnabled || !ModConfig.EnableInteractableRemoval.Value || !Object.op_Implicit((Object)(object)interactablesDccsPool)) { return; } Helpers.ForEachPoolEntryInDccsPool(interactablesDccsPool, (Action<PoolEntry>)delegate(PoolEntry poolEntry) { if (Object.op_Implicit((Object)(object)poolEntry.dccs)) { FilterInteractableSelection(poolEntry.dccs); } }); } private static void FilterInteractableSelection(DirectorCardCategorySelection selection) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < selection.categories.Length; i++) { Category val = selection.categories[i]; DirectorCard[] array = val.cards.Where((DirectorCard card) => card == null || (Object)(object)card.spawnCard == (Object)null || !ItemSources.IsBlocked(((Object)card.spawnCard).name)).ToArray(); if (array.Length != val.cards.Length) { if (array.Length == 0) { val.selectionWeight = 0f; } val.cards = array; selection.categories[i] = val; } } } private static void PlayerDropTableInitializePostfix(PlayerDropTable __instance) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) try { Dictionary<ItemIndex, ItemTier> dictionary = DropTableTiersField.GetValue(__instance) as Dictionary<ItemIndex, ItemTier>; Dictionary<ItemIndex, float> dictionary2 = DropTableWeightsField.GetValue(__instance) as Dictionary<ItemIndex, float>; Dictionary<ItemTier, int> dictionary3 = DropTableTierCountsField.GetValue(__instance) as Dictionary<ItemTier, int>; if (dictionary == null || dictionary2 == null || dictionary3 == null) { return; } List<ItemIndex> list = new List<ItemIndex>(); ItemIndex[] array = dictionary.Keys.ToArray(); foreach (ItemIndex val in array) { ItemDef itemDef = ItemCatalog.GetItemDef(val); if ((QualityRuntime.IsPluginPresent && (Object)(object)itemDef != (Object)null && itemDef.ContainsTag((ItemTag)9)) || ItemBlacklist.Contains((itemDef != null) ? ((Object)itemDef).name : null)) { list.Add(val); } } foreach (ItemIndex item in list) { if (dictionary.TryGetValue(item, out var value)) { dictionary.Remove(item); dictionary2.Remove(item); if (dictionary3.ContainsKey(value)) { dictionary3[value] = Math.Max(0, dictionary3[value] - 1); } } } DropTableLastTokensField?.SetValue(__instance, -1); __instance.RecalculateWeights(0); } catch (Exception ex) { Log.Error("Player drop table filtering failed closed: " + ex.Message); } } private static void RollSingleSlotPrefix(List<ItemIndex> exclude) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_000f: 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) CanonicalizeInPlace(exclude); if ((int)_rerollBaseItem != -1 && !exclude.Contains(_rerollBaseItem)) { exclude.Add(_rerollBaseItem); } } private static void RollSingleSlotPostfix(NetworkInstanceId netId, ref (ItemIndex, ItemIndex) __result) { //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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Invalid comparison between Unknown and I4 //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) ItemIndex val = QualityRuntime.ToBase(__result.Item1); if ((int)val == -1 && (int)_rerollOriginalItem != -1) { __result = (_rerollOriginalItem, (ItemIndex)(-1)); } else if ((int)val != -1 && ConfigState.QualityEnabled && NetworkServer.active) { __result = (QualityRuntime.Promote(val, GetPlayerLuck(netId)), __result.Item2); } } private static void RollItemsForPlayerPostfix(LevelUpManager __instance, NetworkInstanceId netId) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) if (!ConfigState.QualityEnabled || ConfigState.GuaranteedQualityEveryValue <= 0) { PendingGuaranteedQualityBatches.Remove(netId); } else { if (!PendingGuaranteedQualityBatches.TryGetValue(netId, out var value) || value <= 0) { return; } object playerState = GetPlayerState(__instance, netId); if (playerState == null || !(CurrentOptionsField?.GetValue(playerState) is IList { Count: not 0 } list)) { return; } int guaranteedQualityChoicesValue = ConfigState.GuaranteedQualityChoicesValue; int num = Math.Min(guaranteedQualityChoicesValue, list.Count); float playerLuck = GetPlayerLuck(netId); for (int i = 0; i < num; i++) { if (list[i] is ItemIndex item) { ItemIndex baseItem = QualityRuntime.ToBase(item); list[i] = QualityRuntime.PromoteGuaranteed(baseItem, playerLuck); } } if (num < guaranteedQualityChoicesValue) { Log.Warning($"Guaranteed quality choice count {guaranteedQualityChoicesValue} was capped at {num} by the upstream option count."); } if (value == 1) { PendingGuaranteedQualityBatches.Remove(netId); } else { PendingGuaranteedQualityBatches[netId] = value - 1; } SyncOptions(__instance, netId); UpdateLocalOptions(__instance, netId, list, playerState); } } private static void RerollPrefix(LevelUpManager __instance, NetworkInstanceId netId, int slotIndex) { //IL_0001: 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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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) _rerollBaseItem = (ItemIndex)(-1); _rerollOriginalItem = (ItemIndex)(-1); object playerState = GetPlayerState(__instance, netId); IList list = (IList)(CurrentOptionsField?.GetValue(playerState)); if (list != null && slotIndex >= 0 && slotIndex < list.Count) { _rerollOriginalItem = (ItemIndex)list[slotIndex]; _rerollBaseItem = QualityRuntime.ToBase(_rerollOriginalItem); } } private static void RerollPostfix() { //IL_0001: 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) _rerollBaseItem = (ItemIndex)(-1); _rerollOriginalItem = (ItemIndex)(-1); } private static void RemovePrefix(ref ItemIndex item) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Expected I4, but got Unknown item = (ItemIndex)(int)QualityRuntime.ToBase(item); } private static void OnLevelUpPrefix(LevelUpManager __instance, uint newLevel) { QueueGuaranteedQualityBatch(newLevel); } private static void QueueGuaranteedQualityBatch(uint newLevel) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active) { return; } if ((Object)(object)_pendingQualityRun != (Object)(object)Run.instance) { PendingGuaranteedQualityBatches.Clear(); _pendingQualityRun = Run.instance; } if (!ModConfig.IsModEnabled || !ConfigState.QualityEnabled) { PendingGuaranteedQualityBatches.Clear(); return; } int guaranteedQualityEveryValue = ConfigState.GuaranteedQualityEveryValue; if (guaranteedQualityEveryValue <= 0 || newLevel == 0 || newLevel % (uint)guaranteedQualityEveryValue != 0) { return; } foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { if (Object.op_Implicit((Object)(object)instance.networkUser)) { NetworkInstanceId netId = ((NetworkBehaviour)instance.networkUser).netId; PendingGuaranteedQualityBatches[netId] = ((!PendingGuaranteedQualityBatches.TryGetValue(netId, out var value)) ? 1 : (value + 1)); } } } private static void PauseScreenEnablePrefix() { if (!GamePauseManager.IsPausedByUs) { return; } try { ItemSelectUI instance = ItemSelectUI.Instance; if (instance != null) { instance.Hide(); } GamePauseManager.ForceReset(); } catch (Exception ex) { Log.Warning("Pause handoff cleanup failed: " + ex.Message); GamePauseManager.ForceReset(); } } private static void PauseScreenDisablePostfix() { if (GamePauseManager.IsPausedByUs) { GamePauseManager.ForceReset(); } } private static void ItemSelectHidePostfix() { if (GamePauseManager.IsPausedByUs) { GamePauseManager.ForceReset(); } } private static void InteractableCreditPrefix(SceneDirector __instance) { if (NetworkServer.active && !(Math.Abs(ConfigState.InteractableCreditMultiplierValue - 1f) < 0.001f)) { object value = InteractableCreditField.GetValue(__instance); if (value is float num) { InteractableCreditField.SetValue(__instance, num * ConfigState.InteractableCreditMultiplierValue); } else if (value is int num2) { InteractableCreditField.SetValue(__instance, (int)Math.Max(0f, (float)num2 * ConfigState.InteractableCreditMultiplierValue)); } } } private static bool HasParameters(MethodInfo method, params Type[] expected) { if (method == null) { return false; } ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length != expected.Length) { return false; } for (int i = 0; i < expected.Length; i++) { if (parameters[i].ParameterType != expected[i]) { return false; } } return true; } private static IEnumerable<DictionaryEntry> EnumerateStates(LevelUpManager manager) { if (!(PlayerStatesField?.GetValue(manager) is IDictionary dictionary)) { yield break; } foreach (DictionaryEntry item in dictionary) { yield return item; } } private static object GetPlayerState(LevelUpManager manager, NetworkInstanceId netId) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (PlayerStatesField?.GetValue(manager) is IDictionary dictionary && dictionary.Contains(netId)) { return dictionary[netId]; } return null; } private static void UpdateLocalOptions(LevelUpManager manager, NetworkInstanceId netId, IList options, object state) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (!NetworkUser.readOnlyLocalPlayersList.Any((NetworkUser user) => ((NetworkBehaviour)user).netId == netId)) { return; } List<PickupIndex> list = new List<PickupIndex>(); for (int num = 0; num < options.Count; num++) { if (options[num] is ItemIndex val) { list.Add(PickupCatalog.FindPickupIndex(val)); } } List<ItemIndex> list2 = CurrentSynergiesField?.GetValue(state) as List<ItemIndex>; manager.UpdateAvailableItems(list, list2); } private static float GetPlayerLuck(NetworkInstanceId netId) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) foreach (PlayerCharacterMasterController instance in PlayerCharacterMasterController.instances) { if (Object.op_Implicit((Object)(object)instance.networkUser) && ((NetworkBehaviour)instance.networkUser).netId == netId) { return Object.op_Implicit((Object)(object)instance.master) ? instance.master.luck : 0f; } } return 0f; } private static void SyncState(LevelUpManager manager, NetworkInstanceId id) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) AccessTools.Method(typeof(LevelUpManager), "SyncState", (Type[])null, (Type[])null)?.Invoke(manager, new object[1] { id }); } private static void SyncOptions(LevelUpManager manager, NetworkInstanceId id) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) AccessTools.Method(typeof(LevelUpManager), "SyncOptions", (Type[])null, (Type[])null)?.Invoke(manager, new object[1] { id }); } private static void CanonicalizeInPlace(List<ItemIndex> items) { //IL_0008: 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) for (int i = 0; i < items.Count; i++) { items[i] = QualityRuntime.ToBase(items[i]); } } } internal static class ItemSources { private static readonly string[] Chests = new string[13] { "isccasinochest", "isccategorychestdamage", "isccategorychesthealing", "isccategorychestutility", "iscchest1", "iscchest1stealthed", "iscchest2", "iscgoldchest", "isclunarchest", "isccategorychest2damage", "isccategorychest2healing", "isccategorychest2utility", "isctemporaryitemsshop" }; private static readonly string[] Shops = new string[3] { "isctripleshop", "isctripleshoplarge", "isctripleshopequipment" }; private static readonly string[] Scrappers = new string[2] { "iscscrapper", "iscdronescrapper" }; private static readonly string[] PlayerGrantedSources = new string[3] { "isclockbox", "isclockboxvoid", "iscfreechest" }; internal static readonly string[] Printers = new string[4] { "iscduplicator", "iscduplicatorlarge", "iscduplicatormilitary", "iscduplicatorwild" }; internal static readonly string[] QualityItemSources = new string[10] { "iscQualityChest1", "iscQualityChest2", "iscQualityDuplicator", "iscQualityDuplicatorLarge", "iscQualityDuplicatorMilitary", "iscQualityDuplicatorWild", "iscQualityScrapper", "iscSpeedOnPickupBarrel", "iscChest2Stealthed", "iscQualityEquipmentBarrel" }; private static readonly HashSet<string> Always = Merge(Chests, Shops, Scrappers, Printers, PlayerGrantedSources); private static readonly HashSet<string> QualityOnly = Merge(QualityItemSources); internal static bool IsBlocked(string name) { if (string.IsNullOrWhiteSpace(name)) { return false; } if (Always.Contains(name)) { return true; } if (ConfigState.RemoveQualityInteractablesValue && QualityRuntime.IsPluginPresent) { return QualityOnly.Contains(name); } return false; } private static HashSet<string> Merge(params string[][] groups) { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (string[] array in groups) { foreach (string item in array) { hashSet.Add(item); } } return hashSet; } } internal static class QualityRuntime { private static readonly object Sync = new object(); private static MethodInfo _toBase; private static MethodInfo _getQualityTier; private static Type _qualityTierType; private static bool _usable; private static bool _loggedUnavailable; private static bool _loggedPromotionState; private static bool _loggedNoVariants; private static bool _loggedPromotionEntry; internal static bool IsPluginPresent => Chainloader.PluginInfos.ContainsKey("com.Gorakh.ItemQualities"); internal static bool IsAvailable => _usable; internal static void TryInitialize() { lock (Sync) { if (_usable || !Chainloader.PluginInfos.ContainsKey("com.Gorakh.ItemQualities")) { return; } try { Type type = FindCatalogType(((object)Chainloader.PluginInfos["com.Gorakh.ItemQualities"].Instance).GetType().Assembly); _getQualityTier = type?.GetMethods(BindingFlags.Static | BindingFlags.Public).FirstOrDefault((MethodInfo method) => method.Name == "GetQualityTier" && method.ReturnType.IsEnum && method.GetParameters().Length == 1 && method.GetParameters()[0].ParameterType == typeof(ItemIndex)); _qualityTierType = _getQualityTier?.ReturnType; _toBase = ((_qualityTierType == null) ? null : type?.GetMethod("GetItemIndexOfQuality", BindingFlags.Static | BindingFlags.Public, null, new Type[2] { typeof(ItemIndex), _qualityTierType }, null)); _usable = _toBase != null && _getQualityTier != null && _qualityTierType != null; if (!_usable) { LogUnavailable("ItemQualities API signatures were not found."); } else { Log.Info("ItemQualities QualityCatalog API validated."); } } catch (Exception ex) { _usable = false; LogUnavailable("ItemQualities API validation failed: " + ex.Message); } } } internal static ItemIndex ToBase(ItemIndex item) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) if ((int)item == -1) { return item; } TryInitialize(); if (!_usable) { return item; } try { object obj = Enum.ToObject(_qualityTierType, -1); return (ItemIndex)_toBase.Invoke(null, new object[2] { item, obj }); } catch (Exception ex) { Disable("Canonical item conversion failed: " + ex.Message); return item; } } internal static ItemIndex Promote(ItemIndex baseItem, float luck) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) return Promote(baseItem, luck, guaranteed: false); } internal static ItemIndex PromoteGuaranteed(ItemIndex baseItem, float luck) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) return Promote(baseItem, luck, guaranteed: true); } private static ItemIndex Promote(ItemIndex baseItem, float luck, bool guaranteed) { //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Invalid comparison between Unknown and I4 //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Invalid comparison between Unknown and I4 //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) if (!ConfigState.QualityEnabled || !NetworkServer.active) { return baseItem; } TryInitialize(); if (!_loggedPromotionEntry) { Log.Info($"Quality promotion reached: apiReady={_usable}, enabled={ConfigState.QualityEnabled}, server={NetworkServer.active}."); _loggedPromotionEntry = true; } if (!_usable || (int)baseItem == -1) { return baseItem; } try { float num = QualityRollPolicy.EffectiveChance(ConfigState.QualityChanceValue, luck); if (!guaranteed && !QualityRollPolicy.ShouldPromote(num, Random.value)) { return baseItem; } float[] qualityWeights = ConfigState.QualityWeights; List<int> list = new List<int>(); List<float> list2 = new List<float>(); for (int i = 0; i < qualityWeights.Length; i++) { ItemIndex val = Variant(baseItem, i); if (val != baseItem && (int)val != -1 && qualityWeights[i] > 0f) { list.Add(i); list2.Add(qualityWeights[i]); } } if (!_loggedPromotionState) { Log.Info($"Quality promotion active: chance={num:0.##}%, luck={luck:0.##}, eligible quality tiers={list.Count}."); _loggedPromotionState = true; } if (list.Count == 0) { if (!_loggedNoVariants) { Log.Warning($"ItemQualities returned no variants for base item {baseItem}."); _loggedNoVariants = true; } return baseItem; } int num2 = QualityRollPolicy.SelectWeightedTier(list, list2, Random.value); if (num2 < 0) { return baseItem; } return Variant(baseItem, num2); } catch (Exception ex) { Disable("Quality promotion failed closed: " + ex.Message); return baseItem; } } private static ItemIndex Variant(ItemIndex baseItem, int tier) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) object obj = Enum.ToObject(_qualityTierType, tier); return (ItemIndex)_toBase.Invoke(null, new object[2] { baseItem, obj }); } private static Type FindCatalogType(Assembly preferred) { Type type = preferred?.GetType("ItemQualities.QualityCatalog", throwOnError: false); if (type != null) { return type; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (!(assembly == preferred)) { type = assembly.GetType("ItemQualities.QualityCatalog", throwOnError: false); if (type != null) { return type; } } } return null; } private static void Disable(string message) { _usable = false; LogUnavailable(message); } private static void LogUnavailable(string message) { if (!_loggedUnavailable) { _loggedUnavailable = true; Log.Warning("ItemQualities integration disabled: " + message); } } } internal static class QualityRollPolicy { internal static float EffectiveChance(float configuredChance, float luck) { float num = Math.Max(0f, Math.Min(100f, configuredChance)); int num2 = Math.Max(1, 1 + Mathf.FloorToInt(Math.Max(0f, luck))); return 100f * (1f - Mathf.Pow(1f - num / 100f, (float)num2)); } internal static bool ShouldPromote(float chance, float sample) { if (!(chance >= 100f)) { if (chance > 0f) { return sample < chance / 100f; } return false; } return true; } internal static int SelectWeightedTier(IReadOnlyList<int> tiers, IReadOnlyList<float> weights, float sample) { if (tiers == null || weights == null || tiers.Count == 0 || tiers.Count != weights.Count) { return -1; } float num = 0f; for (int i = 0; i < weights.Count; i++) { num += Math.Max(0f, weights[i]); } if (num <= 0f) { return -1; } float num2 = Math.Max(0f, Math.Min(MathF.PI * 113f / 355f, sample)) * num; for (int j = 0; j < weights.Count; j++) { num2 -= Math.Max(0f, weights[j]); if (num2 < 0f) { return tiers[j]; } } return tiers[tiers.Count - 1]; } } internal static class RiskOfOptionsIntegration { [CompilerGenerated] private static class <>O { public static IsDisabledDelegate <0>__ServerOptionDisabled; } private const string IconResourceName = "TeamTayne.LevelUpChoicesFixes.icon.png"; internal const string PluginGUID = "com.rune580.riskofoptions"; internal static void TryRegister() { if (!Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions")) { return; } try { RegisterOptions(); Log.Info("Risk of Options settings registered."); } catch (Exception ex) { Log.Warning("Risk of Options integration failed; native config remains available: " + ex.Message); } } [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] private static void RegisterOptions() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_00a6: Expected O, but got Unknown //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_0107: Expected O, but got Unknown //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Expected O, but got Unknown //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown //IL_0168: Expected O, but got Unknown //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Expected O, but got Unknown //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Expected O, but got Unknown //IL_01c9: Expected O, but got Unknown //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Expected O, but got Unknown //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Expected O, but got Unknown //IL_022a: Expected O, but got Unknown //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Expected O, but got Unknown //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Expected O, but got Unknown //IL_028b: Expected O, but got Unknown //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Expected O, but got Unknown //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Expected O, but got Unknown //IL_02e5: Expected O, but got Unknown //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Expected O, but got Unknown //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_030e: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Expected O, but got Unknown //IL_033f: Expected O, but got Unknown //IL_033a: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Expected O, but got Unknown //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_034e: Unknown result type (might be due to invalid IL or missing references) //IL_0359: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_036f: Unknown result type (might be due to invalid IL or missing references) //IL_037a: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_032a: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0335: Expected O, but got Unknown //IL_03ab: Expected O, but got Unknown //IL_03a6: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Expected O, but got Unknown //IL_0396: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Expected O, but got Unknown ModSettingsManager.SetModDescription("LevelUpChoices remains the sole level-up system. Host/server settings are authoritative during multiplayer runs."); Sprite val = LoadIcon(); if ((Object)(object)val != (Object)null) { ModSettingsManager.SetModIcon(val); } else { Log.Warning("Risk of Options icon resource was not found or could not be decoded."); } ConfigEntry<bool> enableQualityIntegration = ConfigState.EnableQualityIntegration; CheckBoxConfig val2 = new CheckBoxConfig { category = "Quality" }; object obj = <>O.<0>__ServerOptionDisabled; if (obj == null) { IsDisabledDelegate val3 = ServerOptionDisabled; <>O.<0>__ServerOptionDisabled = val3; obj = (object)val3; } ((BaseOptionConfig)val2).checkIfDisabled = (IsDisabledDelegate)obj; ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(enableQualityIntegration, val2)); ConfigEntry<bool> removeQualityInteractables = ConfigState.RemoveQualityInteractables; CheckBoxConfig val4 = new CheckBoxConfig { category = "Quality" }; object obj2 = <>O.<0>__ServerOptionDisabled; if (obj2 == null) { IsDisabledDelegate val5 = ServerOptionDisabled; <>O.<0>__ServerOptionDisabled = val5; obj2 = (object)val5; } ((BaseOptionConfig)val4).checkIfDisabled = (IsDisabledDelegate)obj2; ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(removeQualityInteractables, val4)); ConfigEntry<float> qualityChance = ConfigState.QualityChance; SliderConfig val6 = new SliderConfig { category = "Quality", min = 0f, max = 100f, FormatString = "{0:0.#}%" }; object obj3 = <>O.<0>__ServerOptionDisabled; if (obj3 == null) { IsDisabledDelegate val7 = ServerOptionDisabled; <>O.<0>__ServerOptionDisabled = val7; obj3 = (object)val7; } ((BaseOptionConfig)val6).checkIfDisabled = (IsDisabledDelegate)obj3; ModSettingsManager.AddOption((BaseOption)new SliderOption(qualityChance, val6)); ConfigEntry<float> uncommonQualityWeight = ConfigState.UncommonQualityWeight; SliderConfig val8 = new SliderConfig { category = "Quality", min = 0f, max = 100f, FormatString = "{0:0.#}" }; object obj4 = <>O.<0>__ServerOptionDisabled; if (obj4 == null) { IsDisabledDelegate val9 = ServerOptionDisabled; <>O.<0>__ServerOptionDisabled = val9; obj4 = (object)val9; } ((BaseOptionConfig)val8).checkIfDisabled = (IsDisabledDelegate)obj4; ModSettingsManager.AddOption((BaseOption)new SliderOption(uncommonQualityWeight, val8)); ConfigEntry<float> rareQualityWeight = ConfigState.RareQualityWeight; SliderConfig val10 = new SliderConfig { category = "Quality", min = 0f, max = 100f, FormatString = "{0:0.#}" }; object obj5 = <>O.<0>__ServerOptionDisabled; if (obj5 == null) { IsDisabledDelegate val11 = ServerOptionDisabled; <>O.<0>__ServerOptionDisabled = val11; obj5 = (object)val11; } ((BaseOptionConfig)val10).checkIfDisabled = (IsDisabledDelegate)obj5; ModSettingsManager.AddOption((BaseOption)new SliderOption(rareQualityWeight, val10)); ConfigEntry<float> epicQualityWeight = ConfigState.EpicQualityWeight; SliderConfig val12 = new SliderConfig { category = "Quality", min = 0f, max = 100f, FormatString = "{0:0.#}" }; object obj6 = <>O.<0>__ServerOptionDisabled; if (obj6 == null) { IsDisabledDelegate val13 = ServerOptionDisabled; <>O.<0>__ServerOptionDisabled = val13; obj6 = (object)val13; } ((BaseOptionConfig)val12).checkIfDisabled = (IsDisabledDelegate)obj6; ModSettingsManager.AddOption((BaseOption)new SliderOption(epicQualityWeight, val12)); ConfigEntry<float> legendaryQualityWeight = ConfigState.LegendaryQualityWeight; SliderConfig val14 = new SliderConfig { category = "Quality", min = 0f, max = 100f, FormatString = "{0:0.#}" }; object obj7 = <>O.<0>__ServerOptionDisabled; if (obj7 == null) { IsDisabledDelegate val15 = ServerOptionDisabled; <>O.<0>__ServerOptionDisabled = val15; obj7 = (object)val15; } ((BaseOptionConfig)val14).checkIfDisabled = (IsDisabledDelegate)obj7; ModSettingsManager.AddOption((BaseOption)new SliderOption(legendaryQualityWeight, val14)); ConfigEntry<int> guaranteedQualityEveryNLevels = ConfigState.GuaranteedQualityEveryNLevels; IntSliderConfig val16 = new IntSliderConfig { category = "Quality", min = 0, max = 100, formatString = "{0}" }; object obj8 = <>O.<0>__ServerOptionDisabled; if (obj8 == null) { IsDisabledDelegate val17 = ServerOptionDisabled; <>O.<0>__ServerOptionDisabled = val17; obj8 = (object)val17; } ((BaseOptionConfig)val16).checkIfDisabled = (IsDisabledDelegate)obj8; ModSettingsManager.AddOption((BaseOption)new IntSliderOption(guaranteedQualityEveryNLevels, val16)); ConfigEntry<int> guaranteedQualityChoiceCount = ConfigState.GuaranteedQualityChoiceCount; IntSliderConfig val18 = new IntSliderConfig { category = "Quality", min = 1, max = 10, formatString = "{0}" }; object obj9 = <>O.<0>__ServerOptionDisabled; if (obj9 == null) { IsDisabledDelegate val19 = ServerOptionDisabled; <>O.<0>__ServerOptionDisabled = val19; obj9 = (object)val19; } ((BaseOptionConfig)val18).checkIfDisabled = (IsDisabledDelegate)obj9; ModSettingsManager.AddOption((BaseOption)new IntSliderOption(guaranteedQualityChoiceCount, val18)); ConfigEntry<float> interactableCreditMultiplier = ConfigState.InteractableCreditMultiplier; StepSliderConfig val20 = new StepSliderConfig { category = "Interactables", min = 0f, max = 5f, increment = 0.1f, FormatString = "{0:0.0}x" }; object obj10 = <>O.<0>__ServerOptionDisabled; if (obj10 == null) { IsDisabledDelegate val21 = ServerOptionDisabled; <>O.<0>__ServerOptionDisabled = val21; obj10 = (object)val21; } ((BaseOptionConfig)val20).checkIfDisabled = (IsDisabledDelegate)obj10; ModSettingsManager.AddOption((BaseOption)new StepSliderOption(interactableCreditMultiplier, val20)); } private static Sprite LoadIcon() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) using Stream stream = typeof(RiskOfOptionsIntegration).Assembly.GetManifestResourceStream("TeamTayne.LevelUpChoicesFixes.icon.png"); if (stream == null) { return null; } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(val, memoryStream.ToArray(), true)) { Object.Destroy((Object)(object)val); return null; } ((Object)val).name = "LevelUpChoicesFixesIcon"; return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); } private static bool ServerOptionDisabled() { if (NetworkClient.active) { return !NetworkServer.active; } return false; } } }