Decompiled source of VeinsUtilizationBooster v1.4.0

BepInEx\plugins\VeinsUtilizationBooster\VeinsUtilizationBooster.dll

Decompiled 20 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("0.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[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 VeinsUtilizationBoosterMod
{
	[BepInPlugin("godvector.dysonsphereprogram.veinsutilizationbooster", "VeinsUtilizationBooster", "1.4.0")]
	[BepInProcess("DSPGAME.exe")]
	public sealed class VeinsUtilizationBoosterPlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "godvector.dysonsphereprogram.veinsutilizationbooster";

		public const string PluginName = "VeinsUtilizationBooster";

		public const string PluginVersion = "1.4.0";

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<int> TargetLevel;

		internal static ConfigEntry<int> TechIdOverride;

		private GameHistoryData _lastHistory;

		private bool _applied;

		private float _nextCheck;

		private void Awake()
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Expected O, but got Unknown
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable the Veins Utilization booster.");
			TargetLevel = ((BaseUnityPlugin)this).Config.Bind<int>("General", "TargetLevel", 10000, new ConfigDescription("Target Veins Utilization level. Default is 10000. Values are clamped to the repeatable technology's current MaxLevel, including limits raised by other mods.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(6, 1000000000), Array.Empty<object>()));
			TechIdOverride = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "TechIdOverride", 0, "0 = automatic detection. Only change this for troubleshooting.");
			((BaseUnityPlugin)this).Logger.LogInfo((object)"VeinsUtilizationBooster 1.4.0 loaded.");
		}

		private void Update()
		{
			if (!Enabled.Value || Time.realtimeSinceStartup < _nextCheck)
			{
				return;
			}
			_nextCheck = Time.realtimeSinceStartup + 1f;
			GameHistoryData history = GameMain.history;
			if (history == null)
			{
				_lastHistory = null;
				_applied = false;
				return;
			}
			if (history != _lastHistory)
			{
				_lastHistory = history;
				_applied = false;
			}
			if (_applied || (Object)(object)LDB.techs == (Object)null || ((ProtoSet<TechProto>)(object)LDB.techs).dataArray == null || history.techStates == null)
			{
				return;
			}
			try
			{
				Apply(history);
				_applied = true;
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Veins Utilization synchronization failed.");
				((BaseUnityPlugin)this).Logger.LogError((object)ex);
				_nextCheck = Time.realtimeSinceStartup + 3f;
			}
		}

		private void Apply(GameHistoryData history)
		{
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0418: Unknown result type (might be due to invalid IL or missing references)
			//IL_04ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_04f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0521: Unknown result type (might be due to invalid IL or missing references)
			//IL_052e: Unknown result type (might be due to invalid IL or missing references)
			List<TechProto> list = FindCandidates();
			if (list.Count == 0)
			{
				throw new Exception("Veins Utilization technology could not be detected.");
			}
			TechProto val = SelectRepeatable(list);
			if (val == null)
			{
				throw new Exception("Repeatable Veins Utilization technology could not be selected.");
			}
			int iD = ((Proto)val).ID;
			int maxLevel = val.MaxLevel;
			if (maxLevel < 6)
			{
				throw new Exception("Detected repeatable Veins Utilization MaxLevel is invalid: " + maxLevel);
			}
			int num = Math.Max(6, Math.Min(TargetLevel.Value, maxLevel));
			if (num != TargetLevel.Value)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Configured TargetLevel " + TargetLevel.Value + " was clamped to the game's repeatable-tech maximum " + maxLevel + "."));
			}
			int num2 = EstimateAppliedLevelFromMiningSpeed(history.miningSpeedScale);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("VU state before repair: tech target=" + num + ", miningSpeedScale=" + history.miningSpeedScale + ", estimated actually-applied level=" + num2));
			List<TechProto> list2 = new List<TechProto>();
			foreach (TechProto item in list)
			{
				if (((Proto)item).ID != iD)
				{
					list2.Add(item);
				}
			}
			list2.Sort(delegate(TechProto a, TechProto b)
			{
				int num12 = a.Level.CompareTo(b.Level);
				return (num12 != 0) ? num12 : ((Proto)a).ID.CompareTo(((Proto)b).ID);
			});
			int num3 = Math.Min(5, list2.Count);
			if (num3 < 5)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Only " + num3 + " finite Veins Utilization stages were found; expected I-V."));
			}
			for (int num4 = 0; num4 < num3; num4++)
			{
				TechProto val2 = list2[num4];
				int iD2 = ((Proto)val2).ID;
				int num5 = num4 + 1;
				if (history.techStates.TryGetValue(iD2, out var value))
				{
					int num6 = Math.Max(val2.Level, val2.MaxLevel);
					if (value.curLevel < num6 || !value.unlocked)
					{
						value.curLevel = num6;
						value.maxLevel = Math.Max(value.maxLevel, num6);
						value.unlocked = true;
						history.techStates[iD2] = value;
					}
				}
				if (num2 < num5)
				{
					ApplyFunctions(history, val2, num5);
					num2 = EstimateAppliedLevelFromMiningSpeed(history.miningSpeedScale);
					((BaseUnityPlugin)this).Logger.LogInfo((object)("Applied Veins Utilization finite stage " + num5 + "; miningSpeedScale=" + history.miningSpeedScale + "; estimated level=" + num2));
				}
			}
			if (!history.techStates.TryGetValue(iD, out var value2))
			{
				throw new Exception("Repeatable Veins Utilization TechState not found.");
			}
			int curLevel = value2.curLevel;
			int maxLevel2 = value2.maxLevel;
			bool unlocked = value2.unlocked;
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Repeatable VU state before synchronization: curLevel=" + curLevel + ", maxLevel=" + maxLevel2 + ", unlocked=" + unlocked));
			int num7 = num;
			if (num2 < 5)
			{
				num2 = EstimateAppliedLevelFromMiningSpeed(history.miningSpeedScale);
			}
			int num8 = Math.Max(6, num2 + 1);
			if (num8 <= num7)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Replaying Veins Utilization effects from level " + num8 + " through target level " + num7 + "."));
				for (int num9 = num8; num9 <= num7; num9++)
				{
					ApplyFunctions(history, val, num9);
				}
			}
			int num10 = Math.Max(curLevel, num);
			if (num10 > maxLevel)
			{
				num10 = maxLevel;
			}
			value2.curLevel = num10;
			value2.maxLevel = maxLevel;
			value2.unlocked = num10 >= maxLevel;
			history.techStates[iD] = value2;
			int num11 = EstimateAppliedLevelFromMiningSpeed(history.miningSpeedScale);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Repeatable VU state after synchronization: curLevel=" + value2.curLevel + ", maxLevel=" + value2.maxLevel + ", unlocked=" + value2.unlocked));
			((BaseUnityPlugin)this).Logger.LogInfo((object)("VU synchronization complete. Target=" + num + ", EffectLevel≈" + num11 + ", miningSpeedScale=" + history.miningSpeedScale + ", miningCostRate=" + history.miningCostRate));
			if (value2.curLevel < value2.maxLevel)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Repeatable VU remains below the real maximum. The next level should remain researchable.");
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Repeatable VU is at the real maximum and is marked unlocked/completed.");
			}
			if (num11 < value2.curLevel - 1 || num11 > value2.curLevel + 1)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"The resulting mining-speed effect does not closely match curLevel. Another mod or a game update may be changing miningSpeedScale.");
			}
		}

		private static int EstimateAppliedLevelFromMiningSpeed(float miningSpeedScale)
		{
			if (miningSpeedScale <= 1.0001f)
			{
				return 0;
			}
			double num = ((double)miningSpeedScale - 1.0) / 0.1;
			if (num < 0.0)
			{
				return 0;
			}
			if (num > 1000000.0)
			{
				return 1000000;
			}
			return (int)Math.Round(num, MidpointRounding.AwayFromZero);
		}

		private static void ApplyFunctions(GameHistoryData history, TechProto tech, int level)
		{
			int[] unlockFunctions = tech.UnlockFunctions;
			double[] unlockValues = tech.UnlockValues;
			if (unlockFunctions == null || unlockValues == null || unlockFunctions.Length == 0 || unlockFunctions.Length != unlockValues.Length)
			{
				throw new Exception("Invalid UnlockFunctions/UnlockValues for Tech ID " + ((Proto)tech).ID);
			}
			for (int i = 0; i < unlockFunctions.Length; i++)
			{
				history.UnlockTechFunction(unlockFunctions[i], unlockValues[i], level);
			}
		}

		private List<TechProto> FindCandidates()
		{
			List<TechProto> list = new List<TechProto>();
			if (TechIdOverride.Value > 0)
			{
				TechProto val = ((ProtoSet<TechProto>)(object)LDB.techs).Select(TechIdOverride.Value);
				if (val != null)
				{
					list.Add(val);
				}
				return list;
			}
			TechProto[] dataArray = ((ProtoSet<TechProto>)(object)LDB.techs).dataArray;
			foreach (TechProto val2 in dataArray)
			{
				if (val2 == null)
				{
					continue;
				}
				string text = ((Proto)val2).Name ?? "";
				string s = text;
				try
				{
					if (Localization.CanTranslate(text))
					{
						s = Localization.Translate(text);
					}
				}
				catch
				{
				}
				if (LooksLikeVU(text) || LooksLikeVU(s))
				{
					list.Add(val2);
				}
			}
			return list;
		}

		private static bool LooksLikeVU(string s)
		{
			if (string.IsNullOrEmpty(s))
			{
				return false;
			}
			string text = s.ToLowerInvariant();
			if (!text.Contains("veins utilization") && !text.Contains("vein utilization") && !s.Contains("광맥 활용") && !s.Contains("矿物利用"))
			{
				return s.Contains("礦物利用");
			}
			return true;
		}

		private static TechProto SelectRepeatable(List<TechProto> all)
		{
			TechProto val = null;
			foreach (TechProto item in all)
			{
				if (val == null || item.MaxLevel > val.MaxLevel || (item.MaxLevel == val.MaxLevel && item.Level > val.Level))
				{
					val = item;
				}
			}
			return val;
		}
	}
}