Decompiled source of NoStumpLeftBehind v1.0.0

NoStumpLeftBehind.dll

Decompiled a month ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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 Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_utils")]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("NoStumpLeftBehind")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+22ba1801fb28ff5dd8cdd8ac155bf859dda14487")]
[assembly: AssemblyProduct("NoStumpLeftBehind")]
[assembly: AssemblyTitle("NoStumpLeftBehind")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 NoStumpLeftBehind
{
	internal static class CultivatedGround
	{
		internal static bool IsCultivated(Vector3 worldPos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (WorldGenerator.IsDeepnorth(worldPos.x, worldPos.z))
			{
				return false;
			}
			Heightmap val = Heightmap.FindHeightmap(worldPos);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			return val.IsCultivated(worldPos);
		}
	}
	public enum StumpRule
	{
		Always,
		CultivatedOnly,
		Never
	}
	public enum GlobalStumpRule
	{
		PerTree,
		Always,
		CultivatedOnly,
		Never
	}
	[BepInPlugin("rhenn.nostumpleftbehind", "NoStumpLeftBehind", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGUID = "rhenn.nostumpleftbehind";

		public const string PluginName = "NoStumpLeftBehind";

		public const string PluginVersion = "1.0.0";

		internal const string TreesSection = "Trees";

		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<GlobalStumpRule> RemoveStumps;

		private static ConfigFile configFile;

		private static readonly Dictionary<string, ConfigEntry<StumpRule>> treeRules = new Dictionary<string, ConfigEntry<StumpRule>>();

		private static readonly string[] vanillaTrees = new string[23]
		{
			"AshlandsTree1", "AshlandsTree3", "AshlandsTree4", "AshlandsTree5", "AshlandsTree6", "AshlandsTree6_big", "Beech1", "Birch1", "Birch1_aut", "Birch2",
			"Birch2_aut", "FirTree", "FirTree_big", "Oak1", "Pinetree_01", "Pinetree_Snow", "Pinetree_Snow_dead", "SnowFirTree", "SnowFirTree 2", "SwampTree1",
			"YggaShoot1", "YggaShoot2", "YggaShoot3"
		};

		private readonly Harmony harmony = new Harmony("rhenn.nostumpleftbehind");

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			configFile = ((BaseUnityPlugin)this).Config;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. Set to false and the mod does nothing: every tree leaves its stump, whatever the settings below say.");
			RemoveStumps = ((BaseUnityPlugin)this).Config.Bind<GlobalStumpRule>("General", "RemoveStumps", GlobalStumpRule.PerTree, "One rule for every tree type at once. PerTree: each tree type follows its own line in the [Trees] section below; they all start as CultivatedOnly. Always: no tree leaves a stump. CultivatedOnly: a stump is removed only if the tree stood on cultivated ground, as made by the Cultivator. Never: stumps stay, as in the unmodded game. Anything other than PerTree makes the [Trees] section irrelevant.");
			BindTreeRules(vanillaTrees);
			harmony.PatchAll(Assembly.GetExecutingAssembly());
			Log.LogInfo((object)string.Format("{0} {1} loaded. Enabled = {2}, RemoveStumps = {3}", "NoStumpLeftBehind", "1.0.0", Enabled.Value, RemoveStumps.Value));
		}

		private void OnDestroy()
		{
			harmony.UnpatchSelf();
		}

		internal static StumpRule RuleFor(string prefabName)
		{
			StumpRule value = BindTreeRule(prefabName).Value;
			return RemoveStumps.Value switch
			{
				GlobalStumpRule.Always => StumpRule.Always, 
				GlobalStumpRule.CultivatedOnly => StumpRule.CultivatedOnly, 
				GlobalStumpRule.Never => StumpRule.Never, 
				_ => value, 
			};
		}

		internal static ConfigEntry<StumpRule> BindTreeRule(string prefabName)
		{
			if (treeRules.TryGetValue(prefabName, out var value))
			{
				return value;
			}
			value = configFile.Bind<StumpRule>("Trees", prefabName, StumpRule.CultivatedOnly, "Rule for " + prefabName + " trees while General.RemoveStumps is PerTree. Always: never leave a stump. CultivatedOnly: remove the stump only if the tree stood on cultivated ground. Never: leave the stump.");
			treeRules[prefabName] = value;
			return value;
		}

		internal static void BindTreeRules(IEnumerable<string> prefabNames)
		{
			bool saveOnConfigSet = configFile.SaveOnConfigSet;
			configFile.SaveOnConfigSet = false;
			int count = treeRules.Count;
			try
			{
				foreach (string prefabName in prefabNames)
				{
					BindTreeRule(prefabName);
				}
			}
			finally
			{
				configFile.SaveOnConfigSet = saveOnConfigSet;
			}
			if (saveOnConfigSet && treeRules.Count > count)
			{
				configFile.Save();
			}
		}
	}
}
namespace NoStumpLeftBehind.Patches
{
	[HarmonyPatch(typeof(TreeBase), "SpawnLog")]
	internal static class TreeBase_SpawnLog_Patch
	{
		private static void Prefix(TreeBase __instance)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.Enabled.Value && !((Object)(object)__instance.m_stubPrefab == (Object)null))
			{
				string prefabName = Utils.GetPrefabName(((Component)__instance).gameObject);
				StumpRule stumpRule = Plugin.RuleFor(prefabName);
				Vector3 position = ((Component)__instance).transform.position;
				bool flag;
				string text;
				switch (stumpRule)
				{
				case StumpRule.Always:
					flag = true;
					text = "rule Always";
					break;
				case StumpRule.CultivatedOnly:
				{
					bool flag2 = CultivatedGround.IsCultivated(position);
					flag = flag2;
					text = "rule CultivatedOnly, on cultivated ground: " + (flag2 ? "yes" : "no");
					break;
				}
				default:
					flag = false;
					text = "rule Never";
					break;
				}
				Plugin.Log.LogDebug((object)string.Format("{0} felled at {1}: {2}, stump {3}", prefabName, position, text, flag ? "removed" : "kept"));
				if (flag)
				{
					__instance.m_stubPrefab = null;
				}
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class ZNetScene_Awake_Patch
	{
		private static void Postfix(ZNetScene __instance)
		{
			SortedSet<string> sortedSet = new SortedSet<string>(StringComparer.Ordinal);
			foreach (GameObject prefab in __instance.m_prefabs)
			{
				if (!((Object)(object)prefab == (Object)null))
				{
					TreeBase component = prefab.GetComponent<TreeBase>();
					if (!((Object)(object)component == (Object)null) && !((Object)(object)component.m_stubPrefab == (Object)null))
					{
						sortedSet.Add(((Object)prefab).name);
					}
				}
			}
			Plugin.BindTreeRules(sortedSet);
			Plugin.Log.LogDebug((object)string.Format("{0} tree types leave a stump: {1}", sortedSet.Count, string.Join(", ", sortedSet)));
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		public IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}