using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using REPOLib.Modules; 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("SADnothingleft")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SADnothingleft")] [assembly: AssemblyTitle("SADnothingleft")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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 SADnothingleft { internal static class MyPluginInfo { public const string PLUGIN_GUID = "SADnothingleft"; public const string PLUGIN_NAME = "SAD Nothing Left"; public const string PLUGIN_VERSION = "1.0.2"; } [BepInPlugin("SADnothingleft", "SAD Nothing Left", "1.0.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } internal static ConfigEntry CfgEnabled { get; private set; } internal static ConfigEntry CfgCheckInterval { get; private set; } internal static ConfigEntry CfgBufferMin { get; private set; } internal static ConfigEntry CfgBufferMax { get; private set; } internal static ConfigEntry CfgMaxSpawnCount { get; private set; } internal static ConfigEntry CfgSpawnNearExtraction { get; private set; } internal static ConfigEntry CfgSpawnNearExtractionRadius { get; private set; } internal static ConfigEntry CfgVerboseLogging { get; private set; } private void Awake() { //IL_0126: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; CfgEnabled = ((BaseUnityPlugin)this).Config.Bind("General", "Enabled", true, "Disable to turn the mod off without uninstalling."); CfgCheckInterval = ((BaseUnityPlugin)this).Config.Bind("General", "CheckInterval", 60f, "Seconds between value checks."); CfgBufferMin = ((BaseUnityPlugin)this).Config.Bind("Spawning", "BufferMin", 1000, "Min extra value to add on top of the quota gap."); CfgBufferMax = ((BaseUnityPlugin)this).Config.Bind("Spawning", "BufferMax", 5000, "Max extra value to add on top of the quota gap."); CfgMaxSpawnCount = ((BaseUnityPlugin)this).Config.Bind("Spawning", "MaxSpawnCount", 5, "Max number of valuables to spawn per check."); CfgSpawnNearExtraction = ((BaseUnityPlugin)this).Config.Bind("Spawning", "SpawnNearExtraction", true, "Limit spawn points to within SpawnNearExtractionRadius of the active extraction point."); CfgSpawnNearExtractionRadius = ((BaseUnityPlugin)this).Config.Bind("Spawning", "SpawnNearExtractionRadius", 100f, "Radius in meters. Only used when SpawnNearExtraction is true."); CfgVerboseLogging = ((BaseUnityPlugin)this).Config.Bind("Debug", "VerboseLogging", false, "Extra log output each check cycle."); try { new Harmony("SADnothingleft").PatchAll(); } catch (Exception arg) { Log.LogError((object)$"Harmony patching failed: {arg}"); } ((Component)this).gameObject.AddComponent(); Log.LogInfo((object)"SAD Nothing Left v1.0.2 loaded."); } } public class QuotaFiller : MonoBehaviour { [CompilerGenerated] private sealed class d__9 : IEnumerator, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public QuotaFiller <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__9(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown int num = <>1__state; QuotaFiller quotaFiller = <>4__this; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; if (Plugin.CfgEnabled.Value && IsLevelReady()) { int instanceID = ((Object)LevelGenerator.Instance).GetInstanceID(); if (instanceID != quotaFiller._lastLevelInstanceId) { quotaFiller._lastLevelInstanceId = instanceID; if (Plugin.CfgVerboseLogging.Value) { Plugin.Log.LogDebug((object)"[SADnothingleft] New level detected, resetting state."); } } if (SemiFunc.IsMasterClientOrSingleplayer()) { quotaFiller.TryFillQuota(); } } } else { <>1__state = -1; } <>2__current = (object)new WaitForSeconds(Plugin.CfgCheckInterval.Value); <>1__state = 1; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static readonly FieldRef _dollarValueOriginal = AccessTools.FieldRefAccess("dollarValueOriginal"); private static readonly FieldRef _dollarValueSet = AccessTools.FieldRefAccess("dollarValueSet"); private static readonly FieldRef _haulGoal = AccessTools.FieldRefAccess("haulGoal"); private static readonly FieldRef _haulCurrent = AccessTools.FieldRefAccess("haulCurrent"); private static readonly FieldRef _haulGoalFetched = AccessTools.FieldRefAccess("haulGoalFetched"); private static readonly FieldRef _isShop = AccessTools.FieldRefAccess("isShop"); private static readonly FieldRef _currentState = AccessTools.FieldRefAccess("currentState"); private int _lastLevelInstanceId = -1; private void Start() { ((MonoBehaviour)this).StartCoroutine(CheckLoop()); } [IteratorStateMachine(typeof(d__9))] private IEnumerator CheckLoop() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__9(0) { <>4__this = this }; } private static bool IsLevelReady() { if ((Object)(object)RunManager.instance != (Object)null && (Object)(object)LevelGenerator.Instance != (Object)null && LevelGenerator.Instance.Generated && (Object)(object)ValuableDirector.instance != (Object)null && (Object)(object)Map.Instance != (Object)null) { return SemiFunc.RunIsLevel(); } return false; } private void TryFillQuota() { //IL_01e9: 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_020c: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) ValuableObject[] array = Object.FindObjectsOfType(false); float num = 0f; ValuableObject[] array2 = array; foreach (ValuableObject val in array2) { if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeInHierarchy && _dollarValueSet.Invoke(val)) { float num2 = _dollarValueOriginal.Invoke(val); if (num2 > 0f) { num += num2; } } } int remainingQuota = GetRemainingQuota(); if (Plugin.CfgVerboseLogging.Value) { Plugin.Log.LogDebug((object)$"[SADnothingleft] mapValue={num:F0} quota={remainingQuota}"); } if (remainingQuota <= 0) { return; } float num3 = (float)remainingQuota - num; if (num3 <= 0f) { return; } int num4 = Mathf.Max(0, Plugin.CfgBufferMin.Value); int num5 = Mathf.Max(num4, Plugin.CfgBufferMax.Value); float num6 = Random.Range(num4, num5); Plugin.Log.LogInfo((object)$"[SADnothingleft] gap={num3:F0} buffer={num6:F0}"); Vector3? extractionPos = GetActiveExtractionPosition(); List list = SemiFunc.LevelPointsGetAll(); if (list == null || list.Count == 0) { Plugin.Log.LogWarning((object)"[SADnothingleft] no LevelPoints on map"); return; } float radius = Plugin.CfgSpawnNearExtractionRadius.Value; if (Plugin.CfgSpawnNearExtraction.Value && extractionPos.HasValue && radius > 0f) { List list2 = list.FindAll((LevelPoint p) => Vector3.Distance(((Component)p).transform.position, extractionPos.Value) <= radius); if (list2.Count > 0) { list = list2; } } IReadOnlyList allValuables = Valuables.AllValuables; if (allValuables == null || allValuables.Count == 0) { Plugin.Log.LogWarning((object)"[SADnothingleft] AllValuables is empty"); return; } int num7 = Mathf.Max(1, Plugin.CfgMaxSpawnCount.Value); int num8 = 0; while (num8 < num7) { int index = Random.Range(0, list.Count); Vector3 position = ((Component)list[index]).transform.position; int index2 = Random.Range(0, allValuables.Count); PrefabRef val2 = allValuables[index2]; try { Valuables.SpawnValuable(val2, position, Quaternion.identity); num8++; if (Plugin.CfgVerboseLogging.Value) { Plugin.Log.LogDebug((object)$"[SADnothingleft] spawned #{num8} at {position}"); } } catch (Exception ex) { Plugin.Log.LogError((object)("[SADnothingleft] spawn failed: " + ex.Message)); break; } } Plugin.Log.LogInfo((object)$"[SADnothingleft] spawned {num8}"); } private Vector3? GetActiveExtractionPosition() { //IL_0052: 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_0055: Invalid comparison between Unknown and I4 //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Invalid comparison between Unknown and I4 ExtractionPoint[] array = Object.FindObjectsOfType(false); foreach (ExtractionPoint val in array) { if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy) { continue; } try { if (!_isShop.Invoke(val) && _haulGoalFetched.Invoke(val)) { State val2 = _currentState.Invoke(val); if ((int)val2 == 1 || (int)val2 == 2) { return ((Component)val).transform.position; } } } catch { } } return null; } private int GetRemainingQuota() { ExtractionPoint[] array = Object.FindObjectsOfType(false); int num = 0; bool flag = false; ExtractionPoint[] array2 = array; foreach (ExtractionPoint val in array2) { if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy) { continue; } try { bool num2 = _isShop.Invoke(val); bool flag2 = _haulGoalFetched.Invoke(val); if (!num2 && flag2) { int num3 = _haulGoal.Invoke(val); int num4 = _haulCurrent.Invoke(val); int num5 = Mathf.Max(0, num3 - num4); num += num5; flag = true; } } catch (Exception ex) { Plugin.Log.LogError((object)("[SADnothingleft] Error reading ExtractionPoint fields: " + ex.Message)); } } if (!flag && Plugin.CfgVerboseLogging.Value) { Plugin.Log.LogDebug((object)"[SADnothingleft] No valid ExtractionPoint found."); } return num; } } }