Decompiled source of MonsterDropsPatch v1.0.0

MonsterDropsPatch.dll

Decompiled 2 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Text;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Unity.Netcode;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("MonsterDropsPatch")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("MonsterDropsPatch")]
[assembly: AssemblyTitle("MonsterDropsPatch")]
[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 MonsterDropsPatch
{
	[HarmonyPatch]
	internal static class EnemyNameVerifier
	{
		private static bool verified;

		[HarmonyPatch(typeof(StartOfRound), "Start")]
		[HarmonyPostfix]
		private static void StartOfRound_Start_Postfix()
		{
			if (verified || SampleInjector.RegisteredEnemyNames.Count == 0)
			{
				return;
			}
			verified = true;
			ManualLogSource log = MonsterDropsPatchPlugin.Log;
			HashSet<string> hashSet = new HashSet<string>();
			EnemyType[] array = Resources.FindObjectsOfTypeAll<EnemyType>();
			foreach (EnemyType val in array)
			{
				if (!string.IsNullOrEmpty(val.enemyName))
				{
					hashSet.Add(val.enemyName.ToLowerInvariant());
				}
			}
			foreach (string registeredEnemyName in SampleInjector.RegisteredEnemyNames)
			{
				if (hashSet.Contains(registeredEnemyName.ToLowerInvariant()))
				{
					log.LogInfo((object)("Verified enemy \"" + registeredEnemyName + "\" — its sample will drop on kill at the configured level."));
				}
				else
				{
					log.LogWarning((object)("No loaded enemy is named \"" + registeredEnemyName + "\"! Its sample will never drop. Fix the 'Enemy name' entry in BLUJAY.MonsterDropsPatch.cfg to match the enemy's EnemyType.enemyName."));
				}
			}
		}
	}
	[BepInPlugin("BLUJAY.MonsterDropsPatch", "Monster Drops Patch", "1.0.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class MonsterDropsPatchPlugin : BaseUnityPlugin
	{
		public const string Guid = "BLUJAY.MonsterDropsPatch";

		public const string Name = "Monster Drops Patch";

		public const string Version = "1.0.0";

		public const string LguGuid = "com.malco.lethalcompany.moreshipupgrades";

		internal static ManualLogSource Log;

		internal static ConfigEntry<string> AdditionalEnemies;

		internal static readonly List<SampleDefinition> Samples = new List<SampleDefinition>
		{
			new SampleDefinition("Ghost Girl", "Girl", "Ghost girl sample", "GhostGirlSample", "FFB3D9", 120, 180),
			new SampleDefinition("Mimic", "Masked", "Mimic sample", "MimicSample", "FFFFFF", 33, 50),
			new SampleDefinition("Nutcracker", "Nutcracker", "Nutcracker sample", "NutcrackerSample", "C41E3A", 90, 130),
			new SampleDefinition("Butler", "Butler", "Butler sample", "ButlerSample", "FFB000", 80, 120)
		};

		private void Awake()
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			foreach (SampleDefinition sample in Samples)
			{
				sample.BindConfig(((BaseUnityPlugin)this).Config);
			}
			AdditionalEnemies = ((BaseUnityPlugin)this).Config.Bind<string>("Additional Enemies", "Entries", "", "Extra samples for other (e.g. modded) killable enemies, without needing a new plugin build.\nFormat per entry: EnemyName,level,minValue,maxValue,hexColor - separate entries with ';'.\nEnemyName must match the enemy's EnemyType.enemyName (check the log line printed on lobby load).\nExample: Peeper,4,40,60,88FF88;Locker,4,100,150,4444FF");
			new Harmony("BLUJAY.MonsterDropsPatch").PatchAll(typeof(EnemyNameVerifier));
			SampleInjector.InjectAll();
		}
	}
	internal class SampleDefinition
	{
		internal readonly string Section;

		internal readonly string AssetName;

		private readonly string defaultEnemyName;

		private readonly string defaultItemName;

		private readonly string defaultColor;

		private readonly int defaultMin;

		private readonly int defaultMax;

		internal ConfigEntry<bool> Enabled;

		internal ConfigEntry<string> EnemyName;

		internal ConfigEntry<string> ItemName;

		internal ConfigEntry<string> ColorHex;

		internal ConfigEntry<int> MinValue;

		internal ConfigEntry<int> MaxValue;

		internal ConfigEntry<int> HunterLevel;

		internal SampleDefinition(string section, string enemyName, string itemName, string assetName, string color, int min, int max)
		{
			Section = section;
			AssetName = assetName;
			defaultEnemyName = enemyName;
			defaultItemName = itemName;
			defaultColor = color;
			defaultMin = min;
			defaultMax = max;
		}

		internal void BindConfig(ConfigFile config)
		{
			Enabled = config.Bind<bool>(Section, "Enabled", true, "Whether killing this enemy drops a sample once MONSTER DROPS reaches the required level.");
			EnemyName = config.Bind<string>(Section, "Enemy name", defaultEnemyName, "Internal enemy name (EnemyType.enemyName) this sample is tied to. Only change this if the log says the name was not found.");
			ItemName = config.Bind<string>(Section, "Sample item name", defaultItemName, "Display name of the dropped sample (inventory tooltip and scanner).");
			ColorHex = config.Bind<string>(Section, "Sample color", defaultColor, "Tint of the sample jar, as RRGGBB hex.");
			MinValue = config.Bind<int>(Section, "Minimum scrap value", defaultMin, "Minimum scrap value of the sample.");
			MaxValue = config.Bind<int>(Section, "Maximum scrap value", defaultMax, "Maximum scrap value of the sample.");
			HunterLevel = config.Bind<int>(Section, "Required upgrade level", 4, "MONSTER DROPS (Hunter) level required before this sample starts dropping.");
		}
	}
	internal static class SampleInjector
	{
		private const string BaseSampleKey = "mouthdog";

		internal static readonly List<string> RegisteredEnemyNames = new List<string>();

		private static GameObject prefabContainer;

		internal static void InjectAll()
		{
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Expected O, but got Unknown
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			ManualLogSource log = MonsterDropsPatchPlugin.Log;
			try
			{
				Assembly assembly = ((object)Chainloader.PluginInfos["com.malco.lethalcompany.moreshipupgrades"].Instance).GetType().Assembly;
				MethodInfo method = assembly.GetType("MoreShipUpgrades.Misc.AssetBundleHandler").GetMethod("GetItemObject", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
				MethodInfo method2 = assembly.GetType("MoreShipUpgrades.Managers.ItemManager").GetMethod("SetupSampleItem", BindingFlags.Static | BindingFlags.NonPublic);
				Dictionary<string, int> moddedLevels = (Dictionary<string, int>)assembly.GetType("MoreShipUpgrades.API.HunterSamples").GetField("moddedLevels", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null);
				Item val = (Item)method.Invoke(null, new object[1] { "mouthdog" });
				if ((Object)(object)val == (Object)null || (Object)(object)val.spawnPrefab == (Object)null)
				{
					log.LogError((object)"Could not load the base Eyeless Dog sample from Lategame Upgrades; no extra samples registered.");
					return;
				}
				prefabContainer = new GameObject("MonsterDropsPatchPrefabs");
				prefabContainer.SetActive(false);
				((Object)prefabContainer).hideFlags = (HideFlags)61;
				foreach (SampleDefinition sample in MonsterDropsPatchPlugin.Samples)
				{
					if (sample.Enabled.Value)
					{
						RegisterClonedSample(val, sample.EnemyName.Value, sample.ItemName.Value, sample.AssetName, sample.ColorHex.Value, sample.MinValue.Value, sample.MaxValue.Value, sample.HunterLevel.Value, method2, moddedLevels);
					}
				}
				foreach (var item in ParseAdditionalEnemies())
				{
					RegisterClonedSample(val, item.enemyName, item.enemyName + " sample", SanitizeAssetName(item.enemyName) + "Sample", item.colorHex, item.min, item.max, item.level, method2, moddedLevels);
				}
			}
			catch (Exception arg)
			{
				log.LogError((object)$"Failed to register extra monster samples: {arg}");
			}
		}

		private static void RegisterClonedSample(Item baseItem, string enemyName, string itemName, string assetName, string colorHex, int minValue, int maxValue, int hunterLevel, MethodInfo setupSampleItem, Dictionary<string, int> moddedLevels)
		{
			ManualLogSource log = MonsterDropsPatchPlugin.Log;
			if (string.IsNullOrWhiteSpace(enemyName))
			{
				return;
			}
			if (moddedLevels.ContainsKey(enemyName))
			{
				log.LogWarning((object)("A sample for \"" + enemyName + "\" is already registered; skipping duplicate."));
				return;
			}
			if (minValue > maxValue)
			{
				int num = maxValue;
				maxValue = minValue;
				minValue = num;
			}
			GameObject val = Object.Instantiate<GameObject>(baseItem.spawnPrefab, prefabContainer.transform);
			((Object)val).name = assetName;
			NetworkObject component = val.GetComponent<NetworkObject>();
			typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(component, HashFromName("BLUJAY.MonsterDropsPatch:" + assetName));
			Item val2 = Object.Instantiate<Item>(baseItem);
			((Object)val2).hideFlags = (HideFlags)61;
			((Object)val2).name = assetName;
			val2.itemName = itemName;
			val2.minValue = minValue;
			val2.maxValue = maxValue;
			val2.spawnPrefab = val;
			GrabbableObject component2 = val.GetComponent<GrabbableObject>();
			component2.itemProperties = val2;
			component2.grabbable = true;
			component2.grabbableToEnemies = true;
			ScanNodeProperties componentInChildren = val.GetComponentInChildren<ScanNodeProperties>(true);
			if ((Object)(object)componentInChildren != (Object)null)
			{
				componentInChildren.headerText = itemName;
			}
			TintPrefab(val, colorHex);
			setupSampleItem.Invoke(null, new object[4] { val2, true, enemyName, 50.0 });
			moddedLevels[enemyName] = Mathf.Max(hunterLevel, 1) - 1;
			RegisteredEnemyNames.Add(enemyName);
			log.LogInfo((object)$"Registered \"{itemName}\" ({minValue}-{maxValue} credits) for enemy \"{enemyName}\" at MONSTER DROPS level {hunterLevel}.");
		}

		private static void TintPrefab(GameObject prefab, string colorHex)
		{
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			Color val = default(Color);
			if (!ColorUtility.TryParseHtmlString("#" + colorHex.TrimStart('#'), ref val))
			{
				MonsterDropsPatchPlugin.Log.LogWarning((object)("\"" + colorHex + "\" is not a valid RRGGBB color for " + ((Object)prefab).name + "; leaving the default look."));
				return;
			}
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if (val2 is ParticleSystemRenderer)
				{
					continue;
				}
				Material[] materials = val2.materials;
				foreach (Material val3 in materials)
				{
					if (val3.HasProperty("_BaseColor"))
					{
						Color color = val3.GetColor("_BaseColor");
						val3.SetColor("_BaseColor", new Color(val.r, val.g, val.b, color.a));
					}
					else if (val3.HasProperty("_Color"))
					{
						Color color2 = val3.color;
						val3.color = new Color(val.r, val.g, val.b, color2.a);
					}
				}
			}
			ParticleSystem[] componentsInChildren2 = prefab.GetComponentsInChildren<ParticleSystem>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				MainModule main = componentsInChildren2[i].main;
				((MainModule)(ref main)).startColor = new MinMaxGradient(val);
			}
		}

		private static uint HashFromName(string name)
		{
			using MD5 mD = MD5.Create();
			return BitConverter.ToUInt32(mD.ComputeHash(Encoding.UTF8.GetBytes(name)), 0);
		}

		private static string SanitizeAssetName(string enemyName)
		{
			StringBuilder stringBuilder = new StringBuilder();
			foreach (char c in enemyName)
			{
				if (char.IsLetterOrDigit(c))
				{
					stringBuilder.Append(c);
				}
			}
			if (stringBuilder.Length <= 0)
			{
				return "Custom";
			}
			return stringBuilder.ToString();
		}

		private static List<(string enemyName, int level, int min, int max, string colorHex)> ParseAdditionalEnemies()
		{
			List<(string, int, int, int, string)> list = new List<(string, int, int, int, string)>();
			string value = MonsterDropsPatchPlugin.AdditionalEnemies.Value;
			if (string.IsNullOrWhiteSpace(value))
			{
				return list;
			}
			string[] array = value.Split(';');
			foreach (string text in array)
			{
				if (!string.IsNullOrWhiteSpace(text))
				{
					string[] array2 = text.Split(',');
					if (array2.Length != 5 || !int.TryParse(array2[1].Trim(), out var result) || !int.TryParse(array2[2].Trim(), out var result2) || !int.TryParse(array2[3].Trim(), out var result3))
					{
						MonsterDropsPatchPlugin.Log.LogWarning((object)("Could not parse additional enemy entry \"" + text.Trim() + "\" — expected EnemyName,level,minValue,maxValue,hexColor."));
					}
					else
					{
						list.Add((array2[0].Trim(), result, result2, result3, array2[4].Trim()));
					}
				}
			}
			return list;
		}
	}
}