Decompiled source of Instant Fertilizer v0.1.1

plugins/InstantFertilizer.dll

Decompiled 6 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
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 HarmonyLib;
using InstantFertilizer.Model;
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.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: AssemblyCompany("InstantFertilizer")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.1.0")]
[assembly: AssemblyInformationalVersion("0.1.1+e30cc8add4f22a2b50c7ca0d66db26e621f72edc")]
[assembly: AssemblyProduct("InstantFertilizer")]
[assembly: AssemblyTitle("InstantFertilizer")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.1.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 InstantFertilizer
{
	[BepInPlugin("nbusseneau.InstantFertilizer", "InstantFertilizer", "0.1.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		private const string ModGUID = "nbusseneau.InstantFertilizer";

		private const string ModName = "InstantFertilizer";

		private const string ModVersion = "0.1.1";

		private static readonly List<Fertilizer> s_defaultFertilizers = new List<Fertilizer>(2)
		{
			new Fertilizer("$item_ancientseed", 3, "defeated_eikthyr"),
			new Fertilizer("$item_ymirremains", 1, "defeated_gdking")
		};

		private static ConfigEntry<string> s_fertilizers;

		internal static ManualLogSource Logger { get; private set; }

		public static List<Fertilizer> Fertilizers { get; private set; }

		private static List<Fertilizer> ParseFertilizers(string serializedFertilizers)
		{
			return (from f in serializedFertilizers.Split(new char[1] { ',' }).Select(Fertilizer.FromString)
				where f != null
				select f).ToList();
		}

		public void Awake()
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Expected O, but got Unknown
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Expected O, but got Unknown
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			Logger = ((BaseUnityPlugin)this).Logger;
			ConfigurationManagerAttributes val = new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			};
			string text = "Comma-separated list of fertilizers that may be used.\nFertilizer format: " + Fertilizer.SerializedFormat + "\nSee https://valheim.fandom.com/wiki/Global_Keys for quick reference of available global keys, or use `none` if you do not want to gate fertilizing behind a global key.\nNote that the mod is not able to determine in advance if an item or global key actually exists. If a fertilizer appears to be ignored, double check item names and global keys.";
			s_fertilizers = ((BaseUnityPlugin)this).Config.Bind<string>("Behaviour", "Fertilizer list", GeneralExtensions.Join<Fertilizer>((IEnumerable<Fertilizer>)s_defaultFertilizers, (Func<Fertilizer, string>)null, ", "), new ConfigDescription(text, (AcceptableValueBase)null, new object[1] { val }));
			Fertilizers = ParseFertilizers(s_fertilizers.Value);
			s_fertilizers.SettingChanged += delegate
			{
				Fertilizers = ParseFertilizers(s_fertilizers.Value);
			};
			SetUpConfigWatcher();
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			new Harmony("nbusseneau.InstantFertilizer").PatchAll(executingAssembly);
		}

		public void OnDestroy()
		{
			((BaseUnityPlugin)this).Config.Save();
		}

		private void SetUpConfigWatcher()
		{
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, Path.GetFileName(((BaseUnityPlugin)this).Config.ConfigFilePath));
			fileSystemWatcher.Changed += ReadConfigValues;
			fileSystemWatcher.Created += ReadConfigValues;
			fileSystemWatcher.Renamed += ReadConfigValues;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(((BaseUnityPlugin)this).Config.ConfigFilePath))
			{
				return;
			}
			try
			{
				Logger.LogDebug((object)"Attempting to reload configuration...");
				((BaseUnityPlugin)this).Config.Reload();
			}
			catch
			{
				Logger.LogError((object)("There was an issue loading " + ((BaseUnityPlugin)this).Config.ConfigFilePath));
			}
		}
	}
}
namespace InstantFertilizer.Patches
{
	[HarmonyPatch(typeof(Pickable))]
	public class PickablePatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("GetHoverText")]
		private static void PickableGetFertilizeHoverText(Pickable __instance, ref string __result)
		{
			if (__instance.m_picked && __instance.m_enabled != 0)
			{
				__result += FertilizerManager.GetFertilizeHoverText();
			}
		}
	}
	[HarmonyPatch(typeof(Plant))]
	public class PlantPatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("GetHoverText")]
		private static void PlantGetFertilizeHoverText(Plant __instance, ref string __result)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if ((int)__instance.m_status == 0)
			{
				__result += FertilizerManager.GetFertilizeHoverText();
			}
		}
	}
	[HarmonyPatch(typeof(Player))]
	public class PlayerPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch("Interact")]
		private static void Fertilize(Player __instance, GameObject go, bool hold, ref bool __runOriginal)
		{
			if (((Character)__instance).InAttack() || ((Character)__instance).InDodge() || hold)
			{
				return;
			}
			bool flag = false;
			Plant componentInParent = go.GetComponentInParent<Plant>();
			if (componentInParent != null)
			{
				flag = FertilizerManager.TryFertilize(__instance, componentInParent);
			}
			else
			{
				Pickable componentInParent2 = go.GetComponentInParent<Pickable>();
				if (componentInParent2 != null)
				{
					flag = FertilizerManager.TryFertilize(__instance, componentInParent2);
				}
			}
			if (flag)
			{
				__runOriginal = false;
			}
		}
	}
	[HarmonyPatch(typeof(ObjectDB))]
	public class ZNetScenePatches
	{
		[HarmonyPostfix]
		[HarmonyPatch("Awake")]
		[HarmonyPatch("CopyOtherDB")]
		private static void ClearCachedGlobalKeys()
		{
			FertilizerManager.ClearCachedGlobalKeys();
		}
	}
}
namespace InstantFertilizer.Model
{
	public class Fertilizer
	{
		public const char Delimiter = ':';

		public static readonly string SerializedFormat = $"itemName{':'}requiredAmount{':'}requiredGlobalKey";

		public string ItemName { get; }

		public int RequiredAmount { get; }

		public string RequiredGlobalKey { get; }

		public string HoverText { get; }

		public Fertilizer(string itemName, int requiredAmount, string requiredGlobalKey)
		{
			ItemName = itemName;
			RequiredAmount = requiredAmount;
			RequiredGlobalKey = requiredGlobalKey;
			HoverText = $"{requiredAmount} {itemName}";
			base..ctor();
		}

		public override string ToString()
		{
			return $"{ItemName}{':'}{RequiredAmount}{':'}{RequiredGlobalKey}";
		}

		public static Fertilizer FromString(string serializedFertilizer)
		{
			string[] array = serializedFertilizer.Trim().Split(new char[1] { ':' });
			if (array.Length != 3)
			{
				Plugin.Logger.LogError((object)("Could not deserialize the following fertilizer entry: " + serializedFertilizer + "\r\nInvalid format: must be `" + SerializedFormat + "`"));
				return null;
			}
			string text = array[0];
			string s = array[1];
			string requiredGlobalKey = array[2];
			string itemName = text;
			if (!int.TryParse(s, out var result))
			{
				Plugin.Logger.LogError((object)("Could not deserialize the following fertilizer entry: " + serializedFertilizer + "\r\nInvalid amount: must be a valid integer"));
				return null;
			}
			return new Fertilizer(itemName, result, requiredGlobalKey);
		}
	}
	public static class FertilizerManager
	{
		public const string GlobalKeyIgnore = "none";

		private static readonly Dictionary<string, bool> s_cachedGlobalKeys = new Dictionary<string, bool>();

		public static void ClearCachedGlobalKeys()
		{
			s_cachedGlobalKeys.Clear();
		}

		private static bool HasGlobalKey(string globalKey)
		{
			if (globalKey == "none")
			{
				return true;
			}
			if (s_cachedGlobalKeys.TryGetValue(globalKey, out var value))
			{
				return value;
			}
			value = ZoneSystem.instance.GetGlobalKey(globalKey);
			if (value)
			{
				s_cachedGlobalKeys[globalKey] = true;
			}
			return value;
		}

		public static string GetFertilizeHoverText()
		{
			IEnumerable<string> enumerable = from fertilizer in Plugin.Fertilizers
				where HasGlobalKey(fertilizer.RequiredGlobalKey)
				select fertilizer.HoverText;
			if (!enumerable.Any())
			{
				return string.Empty;
			}
			string text = "\n[<color=yellow><b>$KEY_Use</b></color>] $InstantFertilizer_Fertilize (" + string.Join(" / ", enumerable) + ")";
			return Localization.instance.Localize(text);
		}

		public static bool TryFertilize(Player player, Pickable pickable)
		{
			if (!pickable.m_nview.IsValid() || !pickable.m_picked || pickable.m_enabled == 0)
			{
				return false;
			}
			return TryFertilizeInternal(player, (Component)(object)pickable, delegate
			{
				pickable.m_nview.ClaimOwnership();
				pickable.m_nview.InvokeRPC(ZNetView.Everybody, "RPC_SetPicked", new object[1] { false });
			});
		}

		public static bool TryFertilize(Player player, Plant plant)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (!plant.m_nview.IsValid() || (int)plant.m_status != 0)
			{
				return false;
			}
			return TryFertilizeInternal(player, (Component)(object)plant, delegate
			{
				plant.m_nview.ClaimOwnership();
				plant.Grow();
			});
		}

		private static bool TryFertilizeInternal(Player player, Component component, Action onFertilize)
		{
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			player.m_lastHoverInteractTime = Time.time;
			IEnumerable<Fertilizer> enumerable = Plugin.Fertilizers.Where((Fertilizer fertilizer) => HasGlobalKey(fertilizer.RequiredGlobalKey));
			if (!enumerable.Any())
			{
				return false;
			}
			bool flag = false;
			foreach (Fertilizer item2 in enumerable)
			{
				ItemData item = ((Humanoid)player).m_inventory.GetItem(item2.ItemName, -1, false);
				flag = item != null && ((Humanoid)player).m_inventory.CountItems(item2.ItemName, -1, true) >= item2.RequiredAmount && ((Humanoid)player).m_inventory.RemoveItem(item, item2.RequiredAmount);
				if (flag)
				{
					break;
				}
			}
			if (!flag)
			{
				((Character)player).Message((MessageType)2, "$InstantFertilizer_FertilizerRequired", 0, (Sprite)null);
				return false;
			}
			onFertilize();
			((Humanoid)player).DoInteractAnimation(component.transform.position);
			return true;
		}
	}
}