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)
{
}
}
}