Decompiled source of CalculateScrapForQuota v1.1.0

CalculateScrapForQuota.dll

Decompiled 10 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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.Configuration;
using BepInEx.Logging;
using CalculateScrapForQuota.Scripts;
using CalculateScrapForQuota.Utils;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.InputSystem;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("CalculateScrapForQuota")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("A template for Lethal Company")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("CalculateScrapForQuota")]
[assembly: AssemblyTitle("CalculateScrapForQuota")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.0.0")]
[module: UnverifiableCode]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace CalculateScrapForQuota
{
	public class Config
	{
		private readonly ConfigEntry<bool> _isVerbose;

		public readonly Color highlightColor;

		private readonly ConfigEntry<string> _highlightColor;

		public bool isVerbose => _isVerbose.Value;

		public Config(ConfigFile cfg)
		{
			_isVerbose = cfg.Bind<bool>("General.Debug", "isVerbose", false, "To display plugin logs in console.");
			_highlightColor = cfg.Bind<string>("General.Settings", "highlightColor", "#00FF00", "The hex color of the highlight material.");
			ColorUtility.TryParseHtmlString(_highlightColor.Value, ref highlightColor);
		}
	}
	[BepInPlugin("CalculateScrapForQuota", "CalculateScrapForQuota", "1.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		private static ManualLogSource _logger;

		private static Config MyConfig { get; set; }

		private void Awake()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			((BaseUnityPlugin)this).Logger.LogInfo((object)"CalculateScrapForQuota v1.1.0 is loaded!");
			_logger = ((BaseUnityPlugin)this).Logger;
			MyConfig = new Config(((BaseUnityPlugin)this).Config);
			MaterialSwapper.swapColor = MyConfig.highlightColor;
			Harmony val = new Harmony("CalculateScrapForQuota");
			val.PatchAll(Assembly.GetExecutingAssembly());
		}

		internal static void Log(string m)
		{
			if (MyConfig.isVerbose)
			{
				_logger.LogMessage((object)m);
			}
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "CalculateScrapForQuota";

		public const string PLUGIN_NAME = "CalculateScrapForQuota";

		public const string PLUGIN_VERSION = "1.1.0";
	}
}
namespace CalculateScrapForQuota.Utils
{
	public static class DebugUtil
	{
		private const BindingFlags FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

		public static string GetGameObjectDetails(GameObject gameObject, bool ignoreProperties = false, bool ignoreFields = false)
		{
			string text = "--- GameObject Info";
			text = text + "\nName: " + ((Object)gameObject).name;
			Component[] components = gameObject.GetComponents<Component>();
			foreach (Component val in components)
			{
				text = text + "\n  Component: " + ((object)val).GetType().Name;
				if (!ignoreProperties)
				{
					PropertyInfo[] properties = ((object)val).GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					PropertyInfo[] array = properties;
					foreach (PropertyInfo propertyInfo in array)
					{
						text += $"\n    Property: {propertyInfo.Name}, Value: {propertyInfo.GetValue(val, null)}";
					}
				}
				if (!ignoreFields)
				{
					FieldInfo[] fields = ((object)val).GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					FieldInfo[] array2 = fields;
					foreach (FieldInfo fieldInfo in array2)
					{
						text += $"\n    Field: {fieldInfo.Name}, Value: {fieldInfo.GetValue(val)}";
					}
				}
			}
			return text;
		}
	}
	public class MathUtil
	{
		public static (List<T> combination, int totalValue) FindBestCombination<T>(List<T> items, int quota, Func<T, int> valueSelector)
		{
			if (items == null)
			{
				throw new ArgumentNullException("items");
			}
			if (valueSelector == null)
			{
				throw new ArgumentNullException("valueSelector");
			}
			if (quota < 0)
			{
				throw new ArgumentException("Quota cannot be negative.", "quota");
			}
			int count = items.Count;
			int num = items.Sum((T item) => valueSelector(item));
			int[,] array = new int[count + 1, num + 1];
			for (int i = 0; i <= count; i++)
			{
				for (int j = 0; j <= num; j++)
				{
					if (i == 0 || j == 0)
					{
						array[i, j] = 0;
						continue;
					}
					int num2 = valueSelector(items[i - 1]);
					if (num2 <= j)
					{
						array[i, j] = Math.Max(array[i - 1, j], array[i - 1, j - num2] + num2);
					}
					else
					{
						array[i, j] = array[i - 1, j];
					}
				}
			}
			int num3 = 0;
			for (int k = quota; k <= num; k++)
			{
				if (array[count, k] >= quota)
				{
					num3 = k;
					break;
				}
			}
			List<T> list = new List<T>();
			int num4 = count;
			int num5 = num3;
			while (num4 > 0 && num5 > 0)
			{
				if (array[num4, num5] != array[num4 - 1, num5])
				{
					list.Add(items[num4 - 1]);
					num5 -= valueSelector(items[num4 - 1]);
				}
				num4--;
			}
			list.Reverse();
			return (list, num3);
		}
	}
}
namespace CalculateScrapForQuota.Scripts
{
	public static class Materials
	{
		private static Shader HDRP_LIT_SHADER = Shader.Find("HDRP/Lit");

		private static Material _highlightMaterialHDRP;

		private static Shader SRP_SHADER = Shader.Find("Standard");

		private static Material _highlightMaterialSRP;

		public static Material HighlightMaterial
		{
			get
			{
				if (Object.op_Implicit((Object)(object)HDRP_LIT_SHADER))
				{
					return HighlightMaterialHDRP;
				}
				if (Object.op_Implicit((Object)(object)SRP_SHADER))
				{
					return HighlightMaterialSRP;
				}
				throw new Exception();
			}
		}

		private static Material HighlightMaterialHDRP
		{
			get
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Expected O, but got Unknown
				if ((Object)(object)_highlightMaterialHDRP != (Object)null)
				{
					return _highlightMaterialHDRP;
				}
				_highlightMaterialHDRP = new Material(HDRP_LIT_SHADER);
				_highlightMaterialHDRP.shader = HDRP_LIT_SHADER;
				_highlightMaterialHDRP.SetFloat("_SurfaceType", 1f);
				_highlightMaterialHDRP.SetFloat("_BlendMode", 0f);
				_highlightMaterialHDRP.SetFloat("_AlphaCutoffEnable", 0f);
				_highlightMaterialHDRP.SetFloat("_DstBlend", 10f);
				_highlightMaterialHDRP.SetFloat("_ZWrite", 0f);
				_highlightMaterialHDRP.SetFloat("_TransparentZWrite", 0f);
				_highlightMaterialHDRP.SetFloat("_TransparentCullMode", 0f);
				_highlightMaterialHDRP.SetFloat("_TransparentSortPriority", 0f);
				_highlightMaterialHDRP.SetFloat("_CullModeForward", 0f);
				return _highlightMaterialHDRP;
			}
		}

		private static Material HighlightMaterialSRP
		{
			get
			{
				//IL_0020: Unknown result type (might be due to invalid IL or missing references)
				//IL_002a: Expected O, but got Unknown
				if ((Object)(object)_highlightMaterialSRP != (Object)null)
				{
					return _highlightMaterialSRP;
				}
				_highlightMaterialSRP = new Material(SRP_SHADER);
				_highlightMaterialSRP.shader = SRP_SHADER;
				_highlightMaterialSRP.SetFloat("_Mode", 3f);
				_highlightMaterialSRP.SetInt("_SrcBlend", 1);
				_highlightMaterialSRP.SetInt("_DstBlend", 10);
				_highlightMaterialSRP.SetInt("_ZWrite", 0);
				_highlightMaterialSRP.DisableKeyword("_ALPHATEST_ON");
				_highlightMaterialSRP.EnableKeyword("_ALPHABLEND_ON");
				_highlightMaterialSRP.DisableKeyword("_ALPHAPREMULTIPLY_ON");
				_highlightMaterialSRP.renderQueue = 3000;
				return _highlightMaterialSRP;
			}
		}
	}
	public static class MaterialSwapper
	{
		private class Visuals
		{
			private readonly List<Component> _rootOtherComponents;

			private List<Transform> Transforms { get; } = new List<Transform>();


			private List<MeshFilter> MeshFilters { get; } = new List<MeshFilter>();


			private List<MeshRenderer> MeshRenderers { get; } = new List<MeshRenderer>();


			private List<SkinnedMeshRenderer> SkinnedMeshRenderers { get; } = new List<SkinnedMeshRenderer>();


			public List<Renderer> Renderers
			{
				get
				{
					List<Renderer> list = new List<Renderer>((IEnumerable<Renderer>)MeshRenderers);
					list.AddRange((IEnumerable<Renderer>)SkinnedMeshRenderers);
					return list;
				}
			}

			public Visuals(GameObject gameObject)
			{
				_rootOtherComponents = gameObject.GetComponentsInChildren<Component>().ToList();
				Transform[] componentsInChildren = gameObject.GetComponentsInChildren<Transform>();
				foreach (Transform item in componentsInChildren)
				{
					Transforms.Add(item);
					_rootOtherComponents.Remove((Component)(object)item);
				}
				MeshFilter[] componentsInChildren2 = gameObject.GetComponentsInChildren<MeshFilter>();
				foreach (MeshFilter item2 in componentsInChildren2)
				{
					MeshFilters.Add(item2);
					_rootOtherComponents.Remove((Component)(object)item2);
				}
				MeshRenderer[] componentsInChildren3 = gameObject.GetComponentsInChildren<MeshRenderer>();
				foreach (MeshRenderer item3 in componentsInChildren3)
				{
					MeshRenderers.Add(item3);
					_rootOtherComponents.Remove((Component)(object)item3);
				}
				SkinnedMeshRenderer[] componentsInChildren4 = gameObject.GetComponentsInChildren<SkinnedMeshRenderer>();
				foreach (SkinnedMeshRenderer item4 in componentsInChildren4)
				{
					SkinnedMeshRenderers.Add(item4);
					_rootOtherComponents.Remove((Component)(object)item4);
				}
				foreach (MeshFilter meshFilter in MeshFilters)
				{
					Plugin.Log("Preserving mesh '" + ((Object)meshFilter.mesh).name + "'");
				}
			}

			public void DestroyNonVisuals()
			{
				foreach (Component rootOtherComponent in _rootOtherComponents)
				{
					Object.Destroy((Object)(object)rootOtherComponent);
				}
				_rootOtherComponents.Clear();
			}
		}

		private class SwapObject
		{
			private readonly Visuals _rootVisuals;

			private readonly GameObject _cloneGO;

			private readonly Visuals _cloneVisuals;

			public SwapObject(GameObject original)
			{
				_cloneGO = Clone(original);
				_rootVisuals = new Visuals(original);
				_cloneVisuals = new Visuals(_cloneGO);
				CleanUpClone();
			}

			private void CleanUpClone()
			{
				//IL_0062: Unknown result type (might be due to invalid IL or missing references)
				_cloneVisuals.DestroyNonVisuals();
				foreach (Renderer renderer in _cloneVisuals.Renderers)
				{
					for (int i = 0; i < renderer.materials.Length; i++)
					{
						renderer.materials[i] = swapMaterial;
						renderer.materials[i].color = new Color(swapColor.r, swapColor.g, swapColor.b);
					}
				}
			}

			public void Swap(bool on)
			{
				foreach (Renderer renderer in _rootVisuals.Renderers)
				{
					renderer.enabled = !on;
				}
				foreach (Renderer renderer2 in _cloneVisuals.Renderers)
				{
					renderer2.enabled = on;
					renderer2.rendererPriority = (on ? 69420 : (-69420));
				}
			}

			public void Dispose()
			{
				if ((Object)(object)_cloneGO != (Object)null)
				{
					Object.Destroy((Object)(object)_cloneGO);
				}
			}
		}

		public static Material swapMaterial = Materials.HighlightMaterial;

		public static Color swapColor = Color.green;

		private static Dictionary<GameObject, SwapObject> pool = new Dictionary<GameObject, SwapObject>();

		public static void SwapOn(List<GameObject> gameObjects)
		{
			foreach (GameObject gameObject in gameObjects)
			{
				Add(gameObject);
				pool[gameObject].Swap(on: true);
			}
		}

		public static void SwapOff()
		{
			foreach (KeyValuePair<GameObject, SwapObject> item in pool)
			{
				if ((Object)(object)item.Key == (Object)null)
				{
					item.Value.Dispose();
					pool.Remove(item.Key);
				}
				else
				{
					item.Value.Swap(on: false);
				}
			}
		}

		private static void Add(GameObject original)
		{
			if (!pool.ContainsKey(original))
			{
				pool.Add(original, new SwapObject(original));
			}
		}

		public static void Clear()
		{
			SwapOff();
			foreach (SwapObject value in pool.Values)
			{
				value.Dispose();
			}
			pool.Clear();
		}

		private static GameObject Clone(GameObject parent)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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)
			GameObject val = Object.Instantiate<GameObject>(parent, parent.transform.position, parent.transform.rotation);
			val.transform.localScale = parent.transform.localScale;
			val.transform.SetParent(parent.transform);
			((Object)val).name = ((Object)parent).name + " (Clone for swap)";
			Plugin.Log("Made '" + ((Object)val).name + "' \nAnd parented it to " + ((Object)parent).name);
			return val;
		}
	}
}
namespace CalculateScrapForQuota.Patches
{
	[HarmonyPatch]
	public class GrabbableObjectPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(GrabbableObject), "EnableItemMeshes")]
		private static void EnableItemMeshes(GrabbableObject __instance, bool enable)
		{
			Plugin.Log("EnableItemMeshes() called.");
			GameObject gameObject = ((Component)__instance).gameObject;
			if (HudManagerPatch.CurrentHighlight.Contains(gameObject) && enable)
			{
				List<GameObject> list = new List<GameObject>();
				list.Add(gameObject);
				MaterialSwapper.SwapOn(list);
			}
		}
	}
	[HarmonyPatch]
	public class HudManagerPatch
	{
		public static List<GameObject> CurrentHighlight = new List<GameObject>();

		public static bool toggled = false;

		private static GameObject _textGO;

		private static TextMeshProUGUI _textMesh;

		private static GameObject shipGO => GameObject.Find("/Environment/HangarShip");

		private static GameObject valueCounterGO => GameObject.Find("/Systems/UI/Canvas/IngamePlayerHUD/BottomMiddle/ValueCounter");

		private static int unmetQuota => Math.Max(0, TimeOfDay.Instance.profitQuota - TimeOfDay.Instance.quotaFulfilled);

		private static double buyingRate => isAtCompany ? ((double)StartOfRound.Instance.companyBuyingRate) : 1.0;

		private static bool isAtCompany => StartOfRound.Instance.currentLevel.levelID == 3;

		private static bool isInShip => GameNetworkManager.Instance.localPlayerController.isInHangarShipRoom;

		private static bool isScanning(HUDManager instance)
		{
			return (double)(float)typeof(HUDManager).GetField("playerPingingScan", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(instance) > -1.0;
		}

		private static bool canPlayerScan(HUDManager instance)
		{
			return (bool)typeof(HUDManager).GetMethod("CanPlayerScan", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(instance, null);
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(HUDManager), "PingScan_performed")]
		private static void OnScan(HUDManager __instance, CallbackContext context)
		{
			Plugin.Log("OnScan() called.");
			if (!((CallbackContext)(ref context)).performed || isScanning(__instance) || !canPlayerScan(__instance) || (Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null)
			{
				return;
			}
			Plugin.Log("OnScan() is valid.");
			CurrentHighlight.Clear();
			toggled = !toggled;
			if (toggled)
			{
				List<GrabbableObject> items;
				if (isInShip && !isAtCompany)
				{
					items = GetSellableGrabbablesInChildren(shipGO);
				}
				else
				{
					if (!isAtCompany)
					{
						return;
					}
					items = GetAllSellableObjects();
				}
				(List<GrabbableObject>, int) tuple = MathUtil.FindBestCombination(items, unmetQuota, ValueCalculation);
				if (tuple.Item2 >= unmetQuota)
				{
					CurrentHighlight = tuple.Item1.Select((GrabbableObject g) => ((Component)g).gameObject).ToList();
					SetupText(tuple.Item2);
					MaterialSwapper.SwapOn(CurrentHighlight);
				}
			}
			else
			{
				SetupText();
				MaterialSwapper.SwapOff();
				MaterialSwapper.Clear();
			}
			static int ValueCalculation(GrabbableObject grabbable)
			{
				return isAtCompany ? ((int)((double)grabbable.scrapValue * buyingRate)) : grabbable.scrapValue;
			}
		}

		private static List<GrabbableObject> GetAllSellableObjects()
		{
			GrabbableObject[] source = Object.FindObjectsOfType<GrabbableObject>();
			return source.Where(IsGrabbableSellable).ToList();
		}

		private static List<GrabbableObject> GetSellableGrabbablesInChildren(GameObject GO)
		{
			GrabbableObject[] componentsInChildren = GO.GetComponentsInChildren<GrabbableObject>();
			return componentsInChildren.Where(IsGrabbableSellable).ToList();
		}

		private static bool IsGrabbableSellable(GrabbableObject grabbable)
		{
			return grabbable.itemProperties.isScrap && !grabbable.isPocketed && grabbable.scrapValue > 0 && ((Object)grabbable).name != "ClipboardManual" && ((Object)grabbable).name != "StickyNoteItem" && ((Object)grabbable).name != "Gift" && ((Object)grabbable).name != "Shotgun" && ((Object)grabbable).name != "Ammo";
		}

		private static void SetupText(int totalValue = -1)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: 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_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)_textGO))
			{
				_textGO = Object.Instantiate<GameObject>(valueCounterGO.gameObject, valueCounterGO.transform.parent, false);
				_textGO.transform.Translate(0f, 1f, 0f);
				Vector3 localPosition = _textGO.transform.localPosition;
				_textGO.transform.localPosition = new Vector3(localPosition.x + 50f, -100f, localPosition.z);
				_textMesh = _textGO.GetComponentInChildren<TextMeshProUGUI>();
				((TMP_Text)_textMesh).fontSize = 12f;
			}
			if (totalValue > 0)
			{
				_textGO.SetActive(true);
				((TMP_Text)_textMesh).text = $"Optimal: {totalValue}";
			}
			else
			{
				_textGO.SetActive(false);
			}
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}