Decompiled source of WisplightUpgrades v1.0.2

WisplightUpgrades.dll

Decompiled a day 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 BepInEx.Logging;
using HarmonyLib;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("WisplightUpgrades")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("WisplightUpgrades")]
[assembly: AssemblyTitle("WisplightUpgrades")]
[assembly: AssemblyVersion("1.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 WisplightUpgrades
{
	[BepInPlugin("com.wisplightupgrades", "WisplightUpgrades", "1.0.2")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		internal enum MistModes
		{
			Vanilla,
			SkipWastedWork,
			ThinnedEdge,
			NoEdgeMist
		}

		public const string PluginGUID = "com.wisplightupgrades";

		public const string PluginName = "WisplightUpgrades";

		public const string PluginVersion = "1.0.2";

		internal static ConfigEntry<int> RangeLevel2;

		internal static ConfigEntry<int> RangeLevel3;

		internal static ConfigEntry<int> RangeLevel4;

		internal static ConfigEntry<int> CostPercent;

		internal static ConfigEntry<bool> RequireStationLevel;

		internal static ConfigEntry<MistModes> MistMode;

		internal static ManualLogSource Log;

		private void Awake()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Expected O, but got Unknown
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Expected O, but got Unknown
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Expected O, but got Unknown
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Expected O, but got Unknown
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Expected O, but got Unknown
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			MistMode = ((BaseUnityPlugin)this).Config.Bind<MistModes>("Performance", "MistMode", MistModes.SkipWastedWork, "Mist drawing at the edge of your cleared area. Only affects your screen.\nVanilla: game default. Slowest at high levels.\nSkipWastedWork: same look, a bit faster.\nThinnedEdge: faster, thinner mist at the edge.\nNoEdgeMist: fastest, emptier surroundings.");
			ConfigurationManagerAttributes val = new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			};
			RangeLevel2 = ((BaseUnityPlugin)this).Config.Bind<int>("Range", "Level2Range", 200, new ConfigDescription("Size of the cleared area at level 2, in percent of the normal Wisplight. (Level 1 is 100.)", (AcceptableValueBase)(object)new AcceptableValueRange<int>(100, 1000), new object[1] { val }));
			RangeLevel3 = ((BaseUnityPlugin)this).Config.Bind<int>("Range", "Level3Range", 300, new ConfigDescription("Size of the cleared area at level 3, in percent of the normal Wisplight.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(100, 1000), new object[1] { val }));
			RangeLevel4 = ((BaseUnityPlugin)this).Config.Bind<int>("Range", "Level4Range", 400, new ConfigDescription("Size of the cleared area at level 4, in percent of the normal Wisplight.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(100, 1000), new object[1] { val }));
			CostPercent = ((BaseUnityPlugin)this).Config.Bind<int>("Upgrades", "UpgradeCostPercent", 100, new ConfigDescription("Scales how many materials each upgrade costs. 100 = the default amounts.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 500), new object[1] { val }));
			RequireStationLevel = ((BaseUnityPlugin)this).Config.Bind<bool>("Upgrades", "RequireStationUpgrades", false, new ConfigDescription("Off (default): upgrades only need the crafting station the Wisplight is made at. On: each upgrade level also needs the station to have one more upgrade (the game's usual rule).", (AcceptableValueBase)null, new object[1] { val }));
			new Harmony("com.wisplightupgrades").PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"WisplightUpgrades 1.0.2 loaded");
		}

		private void Update()
		{
			Upgrades.TickRange();
		}
	}
	internal static class Upgrades
	{
		private class Cost
		{
			public string[] Names;

			public int[] PerLevel;

			public Cost(int[] perLevel, params string[] names)
			{
				PerLevel = perLevel;
				Names = names;
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class ObjectDB_Awake_Patch
		{
			private static void Postfix()
			{
				Apply();
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		private static class ZNetScene_Awake_Patch
		{
			private static void Postfix()
			{
				Apply();
			}
		}

		[HarmonyPatch(typeof(Requirement), "GetAmount")]
		private static class Requirement_GetAmount_Patch
		{
			private static void Postfix(Requirement __instance, int qualityLevel, ref int __result)
			{
				if (Schedules.TryGetValue(__instance, out var value))
				{
					int num = value[Mathf.Clamp(qualityLevel - 1, 0, value.Length - 1)];
					if (qualityLevel > 1 && num > 0)
					{
						num = Mathf.Max(1, Mathf.RoundToInt((float)(num * Plugin.CostPercent.Value) / 100f));
					}
					__result = num;
				}
			}
		}

		[HarmonyPatch(typeof(Recipe), "GetRequiredStationLevel")]
		private static class Recipe_GetRequiredStationLevel_Patch
		{
			private static void Postfix(Recipe __instance, ref int __result)
			{
				if (!Plugin.RequireStationLevel.Value && Recipes.Contains(__instance))
				{
					__result = Mathf.Max(1, __instance.m_minStationLevel);
				}
			}
		}

		[HarmonyPatch(typeof(ParticleMist), "Emit")]
		private static class ParticleMist_Emit_Patch
		{
			private static bool Prefix(ParticleMist __instance, Vector3 center, float radius, float thickness)
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				if (Plugin.MistMode.Value == Plugin.MistModes.Vanilla)
				{
					return true;
				}
				return !(Vector3.Distance(((Component)__instance).transform.position, center) - (radius + thickness) > __instance.m_maxDistance);
			}
		}

		private const string ItemPrefab = "Demister";

		private const string ItemSharedName = "$item_demister";

		private const int MaxLevel = 4;

		private static readonly Cost[] Costs = new Cost[4]
		{
			new Cost(new int[4] { 0, 5, 10, 15 }, "Wisp"),
			new Cost(new int[4] { 0, 2, 4, 8 }, "ScaleHide"),
			new Cost(new int[4] { 0, 0, 2, 4 }, "Carapace"),
			new Cost(new int[4] { 0, 0, 0, 4 }, "YggdrasilWood")
		};

		private static readonly Dictionary<Requirement, int[]> Schedules = new Dictionary<Requirement, int[]>();

		private static readonly HashSet<Recipe> Recipes = new HashSet<Recipe>();

		private static readonly FieldRef<Humanoid, ItemData> UtilityItem = AccessTools.FieldRefAccess<Humanoid, ItemData>("m_utilityItem");

		private static readonly FieldRef<SE_Demister, GameObject> BallField = AccessTools.FieldRefAccess<SE_Demister, GameObject>("m_ballInstance");

		private static readonly Dictionary<Demister, float> NormalRange = new Dictionary<Demister, float>();

		private static float _nextTick;

		private static int _loggedLevel = -1;

		private static float _normalEmission = -1f;

		private static float _normalPerUnit;

		internal static void Apply()
		{
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Expected O, but got Unknown
			ObjectDB instance = ObjectDB.instance;
			if ((Object)(object)instance == (Object)null || instance.m_items.Count == 0)
			{
				return;
			}
			foreach (Recipe recipe in instance.m_recipes)
			{
				if ((Object)(object)recipe == (Object)null || (Object)(object)recipe.m_item == (Object)null || ((Object)recipe.m_item).name != "Demister" || Recipes.Contains(recipe))
				{
					continue;
				}
				Recipes.Add(recipe);
				recipe.m_item.m_itemData.m_shared.m_maxQuality = 4;
				List<Requirement> list = new List<Requirement>(recipe.m_resources);
				Cost[] costs = Costs;
				foreach (Cost cost in costs)
				{
					ItemDrop item = null;
					string[] names = cost.Names;
					foreach (string text in names)
					{
						GameObject itemPrefab = instance.GetItemPrefab(text);
						item = (Object.op_Implicit((Object)(object)itemPrefab) ? itemPrefab.GetComponent<ItemDrop>() : null);
						if ((Object)(object)item != (Object)null)
						{
							break;
						}
					}
					if ((Object)(object)item == (Object)null)
					{
						Plugin.Log.LogWarning((object)("Material not found, skipped: " + cost.Names[0]));
						continue;
					}
					int[] array = new int[4];
					Requirement val = list.Find((Requirement r) => (Object)(object)r.m_resItem != (Object)null && ((Object)r.m_resItem).name == ((Object)item).name);
					if (val == null)
					{
						val = new Requirement
						{
							m_resItem = item,
							m_amount = 0,
							m_recover = true
						};
						list.Add(val);
					}
					else
					{
						array[0] = val.m_amount;
					}
					for (int num = 1; num < 4; num++)
					{
						array[num] = cost.PerLevel[num];
					}
					val.m_amountPerLevel = 1;
					Schedules[val] = array;
				}
				recipe.m_resources = list.ToArray();
				Plugin.Log.LogInfo((object)$"Wisplight can now be upgraded to level {4}");
			}
		}

		private static GameObject BallInstance(StatusEffect effect)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Expected O, but got Unknown
			return BallField.Invoke((SE_Demister)effect);
		}

		private static float RangeMultiplier(int level)
		{
			return level switch
			{
				2 => (float)Plugin.RangeLevel2.Value / 100f, 
				3 => (float)Plugin.RangeLevel3.Value / 100f, 
				4 => (float)Plugin.RangeLevel4.Value / 100f, 
				_ => 1f, 
			};
		}

		internal static void TickRange()
		{
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			if (Time.unscaledTime < _nextTick)
			{
				return;
			}
			_nextTick = Time.unscaledTime + 0.5f;
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			ItemData val = null;
			foreach (ItemData equippedItem in ((Humanoid)localPlayer).GetInventory().GetEquippedItems())
			{
				if (equippedItem.m_shared.m_name == "$item_demister")
				{
					val = equippedItem;
					break;
				}
			}
			int num = val?.m_quality ?? 0;
			float num2 = RangeMultiplier(num);
			ParticleMist instance = ParticleMist.instance;
			if ((Object)(object)instance != (Object)null)
			{
				if (_normalEmission < 0f)
				{
					_normalEmission = instance.m_emissionMax;
					_normalPerUnit = instance.m_emissionPerUnit;
				}
				Plugin.MistModes value = Plugin.MistMode.Value;
				float num3 = value switch
				{
					Plugin.MistModes.NoEdgeMist => 0f, 
					Plugin.MistModes.ThinnedEdge => 1f / Mathf.Max(1f, num2), 
					_ => 1f, 
				};
				instance.m_emissionMax = _normalEmission * num3;
				instance.m_emissionPerUnit = _normalPerUnit * ((value == Plugin.MistModes.NoEdgeMist) ? 0f : 1f);
			}
			foreach (StatusEffect statusEffect in ((Character)localPlayer).GetSEMan().GetStatusEffects())
			{
				if (!(statusEffect is SE_Demister))
				{
					continue;
				}
				GameObject val2 = BallInstance(statusEffect);
				Demister val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponentInChildren<Demister>() : null);
				if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3.m_forceField == (Object)null))
				{
					if (!NormalRange.TryGetValue(val3, out var value2))
					{
						value2 = (NormalRange[val3] = val3.m_forceField.endRange);
						Plugin.Log.LogInfo((object)$"Wisplight normal clearing radius: {value2} m");
					}
					val3.m_forceField.endRange = value2 * num2;
					if (num != _loggedLevel)
					{
						_loggedLevel = num;
						Plugin.Log.LogInfo((object)string.Format("Wisplight level {0}: x{1} -> clearing radius {2} m (start {3}, scale {4}, item {5})", num, num2, val3.m_forceField.endRange, val3.m_forceField.startRange, ((Component)val3).transform.lossyScale, (val != null) ? val.m_shared.m_name : "none"));
					}
				}
			}
			if (NormalRange.Count <= 20)
			{
				return;
			}
			List<Demister> list = new List<Demister>();
			foreach (Demister key in NormalRange.Keys)
			{
				if ((Object)(object)key == (Object)null)
				{
					list.Add(key);
				}
			}
			foreach (Demister item in list)
			{
				NormalRange.Remove(item);
			}
		}
	}
}