Decompiled source of SADnothingleft v1.0.2

BepInEx/plugins/SADnaki-SADnothingleft/SADnothingleft.dll

Decompiled a day ago
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<bool> CfgEnabled { get; private set; }

		internal static ConfigEntry<float> CfgCheckInterval { get; private set; }

		internal static ConfigEntry<int> CfgBufferMin { get; private set; }

		internal static ConfigEntry<int> CfgBufferMax { get; private set; }

		internal static ConfigEntry<int> CfgMaxSpawnCount { get; private set; }

		internal static ConfigEntry<bool> CfgSpawnNearExtraction { get; private set; }

		internal static ConfigEntry<float> CfgSpawnNearExtractionRadius { get; private set; }

		internal static ConfigEntry<bool> 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<bool>("General", "Enabled", true, "Disable to turn the mod off without uninstalling.");
			CfgCheckInterval = ((BaseUnityPlugin)this).Config.Bind<float>("General", "CheckInterval", 60f, "Seconds between value checks.");
			CfgBufferMin = ((BaseUnityPlugin)this).Config.Bind<int>("Spawning", "BufferMin", 1000, "Min extra value to add on top of the quota gap.");
			CfgBufferMax = ((BaseUnityPlugin)this).Config.Bind<int>("Spawning", "BufferMax", 5000, "Max extra value to add on top of the quota gap.");
			CfgMaxSpawnCount = ((BaseUnityPlugin)this).Config.Bind<int>("Spawning", "MaxSpawnCount", 5, "Max number of valuables to spawn per check.");
			CfgSpawnNearExtraction = ((BaseUnityPlugin)this).Config.Bind<bool>("Spawning", "SpawnNearExtraction", true, "Limit spawn points to within SpawnNearExtractionRadius of the active extraction point.");
			CfgSpawnNearExtractionRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Spawning", "SpawnNearExtractionRadius", 100f, "Radius in meters. Only used when SpawnNearExtraction is true.");
			CfgVerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("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<QuotaFiller>();
			Log.LogInfo((object)"SAD Nothing Left v1.0.2 loaded.");
		}
	}
	public class QuotaFiller : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <CheckLoop>d__9 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public QuotaFiller <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <CheckLoop>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<ValuableObject, float> _dollarValueOriginal = AccessTools.FieldRefAccess<ValuableObject, float>("dollarValueOriginal");

		private static readonly FieldRef<ValuableObject, bool> _dollarValueSet = AccessTools.FieldRefAccess<ValuableObject, bool>("dollarValueSet");

		private static readonly FieldRef<ExtractionPoint, int> _haulGoal = AccessTools.FieldRefAccess<ExtractionPoint, int>("haulGoal");

		private static readonly FieldRef<ExtractionPoint, int> _haulCurrent = AccessTools.FieldRefAccess<ExtractionPoint, int>("haulCurrent");

		private static readonly FieldRef<ExtractionPoint, bool> _haulGoalFetched = AccessTools.FieldRefAccess<ExtractionPoint, bool>("haulGoalFetched");

		private static readonly FieldRef<ExtractionPoint, bool> _isShop = AccessTools.FieldRefAccess<ExtractionPoint, bool>("isShop");

		private static readonly FieldRef<ExtractionPoint, State> _currentState = AccessTools.FieldRefAccess<ExtractionPoint, State>("currentState");

		private int _lastLevelInstanceId = -1;

		private void Start()
		{
			((MonoBehaviour)this).StartCoroutine(CheckLoop());
		}

		[IteratorStateMachine(typeof(<CheckLoop>d__9))]
		private IEnumerator CheckLoop()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <CheckLoop>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<ValuableObject>(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<LevelPoint> 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<LevelPoint> list2 = list.FindAll((LevelPoint p) => Vector3.Distance(((Component)p).transform.position, extractionPos.Value) <= radius);
				if (list2.Count > 0)
				{
					list = list2;
				}
			}
			IReadOnlyList<PrefabRef> 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<ExtractionPoint>(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<ExtractionPoint>(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;
		}
	}
}