Decompiled source of MaliciouslyCompliantQuotaCalculatorMod v1.0.0

BepinEx/plugins/MaliciouslyCompliantQuotaCalculator.dll

Decompiled 6 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using TerminalApi;
using TerminalApi.Classes;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("MaliciouslyCompliantQuotaCalculator")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MaliciouslyCompliantQuotaCalculator")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("32ab3174-2628-412a-820e-f93f1f5640b9")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace MaliciouslyCompliantQuotaCalculator;

internal class View
{
	private int start;

	private int[] sequence;

	public int this[int i]
	{
		get
		{
			return sequence[start + i];
		}
		set
		{
			sequence[start + i] = value;
		}
	}

	public View(int[] sequence, int start)
	{
		this.sequence = sequence;
		this.start = start;
	}
}
[BepInPlugin("belea.mcqcm", "Maliciously Compliant Quota Calculator Mod", "1.0.0")]
public class MCQCModBase : BaseUnityPlugin
{
	internal class MCQCMConfig
	{
		private readonly ConfigFile _configFile;

		public ConfigEntry<int> OutputSpacing;

		public ConfigEntry<bool> IncreasingOrder;

		public MCQCMConfig(ConfigFile configFile)
		{
			_configFile = configFile;
		}

		public void RegisterOptions()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			OutputSpacing = _configFile.Bind<int>("General", "OutputSpacing", 20, new ConfigDescription("Spacing between scrap name column and scrap value column.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(15, 30), Array.Empty<object>()));
			IncreasingOrder = _configFile.Bind<bool>("General", "IncreasingOrder", true, new ConfigDescription("Ordering of items of the same type.", (AcceptableValueBase)null, Array.Empty<object>()));
		}
	}

	private const string modGUID = "belea.mcqcm";

	private const string modName = "Maliciously Compliant Quota Calculator Mod";

	private const string modVersion = "1.0.0";

	private readonly Harmony harmony = new Harmony("belea.mcqcm");

	private static MCQCModBase Instance;

	private const int formatSpacing = 27;

	internal static MCQCMConfig Config;

	internal ManualLogSource mls;

	private void Awake()
	{
		//IL_0057: Unknown result type (might be due to invalid IL or missing references)
		//IL_005c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Expected O, but got Unknown
		if ((Object)(object)Instance == (Object)null)
		{
			Instance = this;
		}
		mls = Logger.CreateLogSource("belea.mcqcm");
		Config = new MCQCMConfig(((BaseUnityPlugin)this).Config);
		Config.RegisterOptions();
		harmony.PatchAll(typeof(MCQCModBase));
		TerminalApi.AddCommand("mcqc", new CommandInfo
		{
			Category = "other",
			Description = "To calculate the optimal list of scrap to sell to fulfill quota.",
			DisplayTextSupplier = OnCalculateCommand
		}, "today", true);
		mls.LogInfo((object)"The Maliciously Compliant Quota Calculator(TM) add-on has been installed...");
	}

	private int GetTotalValue(List<GrabbableObject> scrapList)
	{
		return scrapList.Sum((GrabbableObject scrap) => scrap.scrapValue);
	}

	private string ShortenItemName(string itemName, int space = 27)
	{
		if (itemName.Length < space - 2)
		{
			return itemName;
		}
		return itemName.Substring(0, space - 5) + "...";
	}

	private string AddDollarSign(int value)
	{
		return "$" + value;
	}

	private string SpaceOut(string left, string right, int space = 27)
	{
		left = ShortenItemName(left, space);
		return left + new string(' ', space - left.Length) + right;
	}

	private string FormatOutput(List<GrabbableObject> scrapList, List<GrabbableObject> bestScrapList, int threshold, bool wantsToday = false)
	{
		StringBuilder stringBuilder = new StringBuilder();
		if (wantsToday)
		{
			stringBuilder.AppendLine("Calculating for today's buying rate: " + Mathf.RoundToInt(StartOfRound.Instance.companyBuyingRate * 100f) + "%");
		}
		else
		{
			stringBuilder.AppendLine("Calculating for final day's buying rate: 100%");
		}
		stringBuilder.AppendLine();
		int totalValue = GetTotalValue(scrapList);
		int totalValue2 = GetTotalValue(bestScrapList);
		if (bestScrapList.Count > 0)
		{
			stringBuilder.AppendLine(SpaceOut("Scrap name", "Value", Config.OutputSpacing.Value + totalValue2.ToString().Length - 4));
			stringBuilder.AppendLine(new string('=', Config.OutputSpacing.Value + totalValue2.ToString().Length + 1));
		}
		foreach (GrabbableObject item in SortScrapList(bestScrapList))
		{
			stringBuilder.AppendLine(SpaceOut(item.itemProperties.itemName, AddDollarSign(item.scrapValue), Config.OutputSpacing.Value));
		}
		if (bestScrapList.Count == 0)
		{
			stringBuilder.Append("Quota cannot be fulfilled ");
			if (wantsToday)
			{
				stringBuilder.Append("today ");
			}
			stringBuilder.AppendLine("with current scrap!");
		}
		else
		{
			stringBuilder.AppendLine();
			stringBuilder.AppendLine(SpaceOut("Subtotal", AddDollarSign(totalValue2), Config.OutputSpacing.Value));
			stringBuilder.AppendLine(new string('=', Config.OutputSpacing.Value + totalValue2.ToString().Length + 1));
		}
		stringBuilder.AppendLine();
		stringBuilder.AppendLine(SpaceOut("Quota left", AddDollarSign(threshold)));
		if (wantsToday)
		{
			stringBuilder.AppendLine(SpaceOut("In today's rate", AddDollarSign(ReadjustForCompanyRate(threshold, wantsToday))));
		}
		stringBuilder.AppendLine();
		stringBuilder.AppendLine(SpaceOut("Total value on ship", AddDollarSign(totalValue)));
		if (bestScrapList.Count > 0)
		{
			stringBuilder.AppendLine(SpaceOut("Total value after sale", AddDollarSign(totalValue - totalValue2)));
		}
		else
		{
			stringBuilder.AppendLine(SpaceOut("Total value needed", AddDollarSign(ReadjustForCompanyRate(threshold - AdjustForCompanyRate(totalValue, wantsToday), wantsToday))));
		}
		return stringBuilder.ToString();
	}

	private List<GrabbableObject> SortScrapList(List<GrabbableObject> scrapList)
	{
		scrapList.Sort((GrabbableObject left, GrabbableObject right) => (left.itemProperties.itemName == right.itemProperties.itemName) ? (left.scrapValue.CompareTo(right.scrapValue) * (Config.IncreasingOrder.Value ? 1 : (-1))) : left.itemProperties.itemName.CompareTo(right.itemProperties.itemName));
		return scrapList;
	}

	private string OnCalculateCommand()
	{
		string terminalInput = TerminalApi.GetTerminalInput();
		mls.LogInfo((object)("MCQC input: " + terminalInput));
		List<GrabbableObject> scrapInShip = GetScrapInShip();
		foreach (GrabbableObject item in scrapInShip)
		{
			mls.LogDebug((object)("MCQC Found scrap in ship: " + item.itemProperties.itemName + " - " + item.scrapValue + "..."));
		}
		bool wantsToday = terminalInput.ToLower().Split(new string[1] { " " }, StringSplitOptions.RemoveEmptyEntries).Contains("today");
		int threshold = TimeOfDay.Instance.profitQuota - TimeOfDay.Instance.quotaFulfilled;
		return FormatOutput(scrapInShip, Pisinger(scrapInShip, threshold, wantsToday), threshold, wantsToday);
	}

	private int AdjustForCompanyRate(int scrapValue, bool wantsToday)
	{
		if (!wantsToday)
		{
			return scrapValue;
		}
		return Mathf.FloorToInt((float)scrapValue * StartOfRound.Instance.companyBuyingRate);
	}

	private int ReadjustForCompanyRate(int scrapValue, bool wantsToday)
	{
		if (!wantsToday)
		{
			return scrapValue;
		}
		return Mathf.CeilToInt((float)scrapValue / StartOfRound.Instance.companyBuyingRate);
	}

	private List<GrabbableObject> Pisinger(List<GrabbableObject> scrapList, int threshold, bool wantsToday)
	{
		int totalValue = GetTotalValue(scrapList);
		threshold = ReadjustForCompanyRate(AdjustForCompanyRate(totalValue, wantsToday) - threshold, wantsToday);
		if (threshold < 0)
		{
			return new List<GrabbableObject>();
		}
		if (threshold == 0)
		{
			return scrapList;
		}
		int num = 0;
		int num2 = 0;
		foreach (GrabbableObject scrap in scrapList)
		{
			num += scrap.scrapValue;
			num2 = Math.Max(num2, scrap.scrapValue);
		}
		int num3 = 0;
		int i;
		for (i = 0; num3 + scrapList[i].scrapValue <= threshold; i++)
		{
			num3 += scrapList[i].scrapValue;
		}
		int[][] array = new int[scrapList.Count - i + 1][];
		for (int j = 0; j < array.Length; j++)
		{
			array[j] = new int[2 * num2];
			for (int k = 0; k < array[j].Length; k++)
			{
				array[j][k] = 0;
			}
		}
		View view = new View(array[0], num2 - 1);
		for (int l = -num2 + 1; l <= 0; l++)
		{
			view[l] = -1;
		}
		for (int m = 1; m <= num2; m++)
		{
			view[m] = 0;
		}
		view[num3 - threshold] = i;
		for (int n = i; n < scrapList.Count; n++)
		{
			View view2 = new View(array[n - i], num2 - 1);
			View view3 = new View(array[n - i + 1], num2 - 1);
			for (int num4 = -num2 + 1; num4 < num2 + 1; num4++)
			{
				view3[num4] = view2[num4];
			}
			for (int num5 = -num2 + 1; num5 <= 0; num5++)
			{
				int i2 = num5 + scrapList[n].scrapValue;
				view3[i2] = Math.Max(view3[i2], view2[num5]);
			}
			for (int num6 = scrapList[n].scrapValue; num6 > 0; num6--)
			{
				for (int num7 = view3[num6] - 1; num7 > view2[num6] - 1; num7--)
				{
					int i3 = num6 - scrapList[num7].scrapValue;
					view3[i3] = Math.Max(view3[i3], num7);
				}
			}
		}
		bool flag = false;
		View view4 = new View(array[scrapList.Count - i], num2 - 1);
		int num8;
		for (num8 = 0; num8 >= -num2 + 1; num8--)
		{
			if (view4[num8] >= 0)
			{
				flag = true;
				break;
			}
		}
		if (flag)
		{
			bool[] array2 = new bool[scrapList.Count];
			for (int num9 = 0; num9 < array2.Length; num9++)
			{
				array2[num9] = false;
			}
			for (int num10 = 0; num10 < i; num10++)
			{
				array2[num10] = true;
			}
			for (int num11 = scrapList.Count - 1; num11 > i - 1; num11--)
			{
				View view5 = new View(array[num11 - i + 1], num2 - 1);
				View view6 = new View(array[num11 - i], num2 - 1);
				int num13;
				while (true)
				{
					int num12 = view5[num8];
					num13 = num8 + scrapList[num12].scrapValue;
					if (num13 > num2 || num12 >= view5[num13])
					{
						break;
					}
					num8 = num13;
					array2[num12] = false;
				}
				num13 = num8 - scrapList[num11].scrapValue;
				if (num13 >= -num2 + 1 && view6[num13] >= view5[num8])
				{
					num8 = num13;
					array2[num11] = true;
				}
			}
			List<GrabbableObject> list = new List<GrabbableObject>();
			for (int num14 = 0; num14 < scrapList.Count; num14++)
			{
				if (!array2[num14])
				{
					list.Add(scrapList[num14]);
				}
			}
			return list;
		}
		return new List<GrabbableObject>();
	}

	private List<GrabbableObject> GetScrapInShip()
	{
		List<GrabbableObject> list = new List<GrabbableObject>();
		GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>();
		foreach (GrabbableObject val in array)
		{
			if (val.isInShipRoom && val.itemProperties.isScrap && !(val is RagdollGrabbableObject))
			{
				list.Add(val);
			}
		}
		return list;
	}
}