Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of NoStumpLeftBehind v1.0.0
NoStumpLeftBehind.dll
Decompiled a month agousing 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) { } } }