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 VargheimLumberjacking v1.0.4
VargheimLumberjacking.dll
Decompiled 10 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using VargheimProfessions; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.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 VargheimLumberjacking { [BepInPlugin("digi.vargheim.lumberjacking", "VargheimLumberjacking", "1.0.4")] [BepInDependency("digi.vargheim.professions", "0.4.0")] public class Plugin : BaseUnityPlugin { [HarmonyPatch] internal static class Patches { [HarmonyPatch(typeof(ObjectDB), "Awake")] [HarmonyPostfix] [HarmonyPriority(0)] private static void DbAwake() { try { ApplyShipCosts(); } catch { } } [HarmonyPatch(typeof(Player), "OnSpawned")] [HarmonyPostfix] private static void Spawned() { try { ApplyShipCosts(); } catch { } } [HarmonyPatch(typeof(TreeBase), "Damage")] [HarmonyPrefix] private static void TreeDamage(TreeBase __instance, HitData hit) { try { Refund(hit); Felling(__instance, hit); } catch { } } [HarmonyPatch(typeof(TreeLog), "Damage")] [HarmonyPrefix] private static void LogDamage(HitData hit) { try { Refund(hit); OneHit(hit); } catch { } } [HarmonyPatch(typeof(Destructible), "Damage")] [HarmonyPrefix] private static void StubDamage(Destructible __instance, HitData hit) { try { if (IsStub(((Component)__instance).gameObject)) { Refund(hit); OneHit(hit); } } catch { } } [HarmonyPatch(typeof(TreeBase), "RPC_Damage")] [HarmonyPrefix] private static void TreeRpcPre(HitData hit) { s_cutter = ((hit != null) ? hit.GetAttacker() : null); } [HarmonyPatch(typeof(TreeBase), "RPC_Damage")] [HarmonyFinalizer] private static void TreeRpcPost() { s_cutter = null; } [HarmonyPatch(typeof(TreeLog), "Destroy")] [HarmonyPrefix] private static void LogDestroyPre(HitData hitData) { s_cutter = ((hitData != null) ? hitData.GetAttacker() : null); } [HarmonyPatch(typeof(TreeLog), "Destroy")] [HarmonyFinalizer] private static void LogDestroyPost() { s_cutter = null; } [HarmonyPatch(typeof(TreeBase), "SpawnLog")] [HarmonyPrefix] private static void SpawnLog(ref Vector3 hitDir) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) Character s_cutter = Plugin.s_cutter; Player val = (Player)(object)((s_cutter is Player) ? s_cutter : null); if ((Object)(object)val != (Object)null && Api.PerkLevelOf(val, "Lumberjacking") >= TimberLevel.Value) { Vector3 forward = ((Component)val).transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude > 0.01f) { hitDir = ((Vector3)(ref forward)).normalized; } } } [HarmonyPatch(typeof(DropTable), "GetDropList", new Type[] { })] [HarmonyPostfix] private static void Drops(List<GameObject> __result) { Character s_cutter = Plugin.s_cutter; Player val = (Player)(object)((s_cutter is Player) ? s_cutter : null); if ((Object)(object)val == (Object)null || __result == null || Api.PerkLevelOf(val, "Lumberjacking") < CleanLevel.Value) { return; } List<GameObject> list = new List<GameObject>(); foreach (GameObject item in __result) { if ((Object)(object)item != (Object)null && CleanSet.Contains(((Object)item).name) && Random.value < CleanChance.Value) { list.Add(item); } } __result.AddRange(list); } } public const string Guid = "digi.vargheim.lumberjacking"; public const string Version = "1.0.4"; private const string Prof = "Lumberjacking"; internal const string Timber = "VP_SeasonedTimber"; internal static ConfigEntry<int> TimberLevel; internal static ConfigEntry<int> CleanLevel; internal static ConfigEntry<int> ShipLevel; internal static ConfigEntry<int> StumpLevel; internal static ConfigEntry<int> SteadyLevel; internal static ConfigEntry<int> CrewLevel; internal static ConfigEntry<float> CleanChance; internal static ConfigEntry<float> CrewRange; internal static ConfigEntry<string> CleanItems; internal static ConfigEntry<string> TimberRecipe; internal static ConfigEntry<string> ShipCosts; internal static HashSet<string> CleanSet = new HashSet<string>(StringComparer.Ordinal); private static readonly Dictionary<string, int> s_shipCost = new Dictionary<string, int>(StringComparer.Ordinal); private static MethodInfo s_gateOf; private static FieldInfo s_gateLevel; private static bool s_gateLookup; [ThreadStatic] internal static Character s_cutter; private static float s_lastRefund; private static bool s_felling; private static readonly FieldRef<Humanoid, Attack> s_curAttack = AccessTools.FieldRefAccess<Humanoid, Attack>("m_currentAttack"); private static readonly FieldRef<Humanoid, Attack> s_prevAttack = AccessTools.FieldRefAccess<Humanoid, Attack>("m_previousAttack"); private static readonly FieldRef<Attack, ItemData> s_attackWeapon = AccessTools.FieldRefAccess<Attack, ItemData>("m_weapon"); private static readonly MethodInfo s_getStamina = AccessTools.Method(typeof(Attack), "GetAttackStamina", new Type[0], (Type[])null); private void Awake() { //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Expected O, but got Unknown //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Expected O, but got Unknown //IL_02ad: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Expected O, but got Unknown //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Expected O, but got Unknown //IL_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Expected O, but got Unknown //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Expected O, but got Unknown //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Expected O, but got Unknown //IL_0349: Unknown result type (might be due to invalid IL or missing references) TimberLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Perks", "TimberLevel", 25, "Timber: trees you cut fall in the direction you face."); CleanLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Perks", "CleanCutsLevel", 35, "Clean cuts level."); CleanChance = ((BaseUnityPlugin)this).Config.Bind<float>("Perks", "CleanCutsChance", 0.25f, "Clean cuts: chance of one extra fine wood / core wood per drop."); CleanItems = ((BaseUnityPlugin)this).Config.Bind<string>("Perks", "CleanCutsItems", "FineWood,RoundLog,YggdrasilWood,Blackwood", "Items that Clean cuts can double."); ShipLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Perks", "ShipGradeTimberLevel", 45, "Ship-grade timber: level to craft Seasoned Timber."); TimberRecipe = ((BaseUnityPlugin)this).Config.Bind<string>("Perks", "SeasonedTimberRecipe", "FineWood:4,Resin:2", "Materials for one Seasoned Timber (crafted at the workbench)."); ShipCosts = ((BaseUnityPlugin)this).Config.Bind<string>("Perks", "SeasonedTimberShips", "BigCargoShip:6,CargoShip:4,WarShip:6,MercantShip:4,HerculeShip:6,BBA_Knarr:4,KnarrBal:4,BBA_LargeRaft:2", "Big modded ships that need Seasoned Timber: 'ShipPrefab:amount', separated by ','. Ships that aren't installed are skipped."); StumpLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Perks", "StumpPullerLevel", 60, "Stump puller: stumps and logs break in one hit."); SteadyLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Perks", "SteadyAxeLevel", 75, "Steady axe: axe swings that hit a tree, log or stump cost no stamina."); CrewLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Perks", "FellingCrewLevel", 100, "Felling crew: once per in-game day, crouch and hit a tree to fell every tree around you."); CrewRange = ((BaseUnityPlugin)this).Config.Bind<float>("Perks", "FellingCrewRange", 10f, "Felling crew range in metres."); CleanSet = new HashSet<string>(CleanItems.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries), StringComparer.Ordinal); ((BaseUnityPlugin)this).Config.SettingChanged += delegate { CleanSet = new HashSet<string>(CleanItems.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries), StringComparer.Ordinal); }; Content.AddItem("FineWood", "VP_SeasonedTimber", "Seasoned Timber", "Dried, straight-grained timber from a skilled lumberjack. Needed for the big ships.", (Action<SharedData>)delegate(SharedData s) { s.m_weight = 3f; s.m_maxStackSize = 50; }); Content.AddRecipe("VP_SeasonedTimber", "piece_workbench", 2, 1, TimberRecipe.Value, "Lumberjacking", ShipLevel.Value); Api.RegisterLadder("Lumberjacking", "VargheimLumberjacking 1.0.4", "Smoothbrain Lumberjacking: up to x2 yield and x3 damage at 100, less damage from falling trees, faster in forests.", (Perk[])(object)new Perk[7] { new Perk(10, "Tier timber", "Make the Lumberjack's tier material at a workbench, one per biome from that biome's wood (Seasoned Wood at 10, Core Timber at 25, Ancient Bark Plank at 35 ...). Weaponsmiths need it for every modded bow, crossbow, spear, polearm, shield and ammo of that tier."), new Perk(TimberLevel.Value, "Timber", "Trees you cut fall in the direction you face."), new Perk(CleanLevel.Value, "Clean cuts", Mathf.RoundToInt(CleanChance.Value * 100f) + "% chance of extra fine wood or core wood."), new Perk(ShipLevel.Value, "Ship-grade timber", "Craft Seasoned Timber at the workbench. The big modded ships need it."), new Perk(StumpLevel.Value, "Stump puller", "Stumps and logs break in one hit."), new Perk(SteadyLevel.Value, "Steady axe", "Chopping trees, logs and stumps costs no stamina."), new Perk(CrewLevel.Value, "Felling crew", "Once per in-game day: crouch and hit a tree to fell every tree within " + CrewRange.Value + " m.") }); new Harmony("digi.vargheim.lumberjacking").PatchAll(typeof(Patches)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"VargheimLumberjacking 1.0.4 loaded."); } internal static void ApplyShipCosts() { //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Expected O, but got Unknown ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null) { return; } GameObject itemPrefab = instance.GetItemPrefab("VP_SeasonedTimber"); if ((Object)(object)itemPrefab == (Object)null) { return; } s_shipCost.Clear(); string[] array = ShipCosts.Value.Split(','); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(':'); if (array2.Length == 2 && int.TryParse(array2[1].Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { s_shipCost[array2[0].Trim()] = result; } } HashSet<GameObject> hashSet = new HashSet<GameObject>(); List<string> list = new List<string>(); List<string> list2 = new List<string>(); foreach (GameObject item in instance.m_items) { ItemDrop val = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null); PieceTable val2 = (((Object)(object)val != (Object)null) ? val.m_itemData.m_shared.m_buildPieces : null); if ((Object)(object)val2 == (Object)null) { continue; } foreach (GameObject piece in val2.m_pieces) { if ((Object)(object)piece == (Object)null || !hashSet.Add(piece) || !s_shipCost.TryGetValue(((Object)piece).name, out var value)) { continue; } Piece component = piece.GetComponent<Piece>(); if ((Object)(object)component == (Object)null) { continue; } List<Requirement> list3 = new List<Requirement>((IEnumerable<Requirement>)(((object)component.m_resources) ?? ((object)new Requirement[0]))); Requirement val3 = list3.Find((Requirement r) => r != null && (Object)(object)r.m_resItem != (Object)null && ((Object)((Component)r.m_resItem).gameObject).name == "VP_SeasonedTimber"); int num = ShipGate(component); if (num >= 0 && num < ShipLevel.Value) { if (val3 != null) { list3.Remove(val3); component.m_resources = list3.ToArray(); } list2.Add(((Object)piece).name + "(" + num + ")"); continue; } list.Add(((Object)piece).name + "(" + num + ")"); if (val3 != null) { val3.m_amount = value; } else { list3.Add(new Requirement { m_resItem = itemPrefab.GetComponent<ItemDrop>(), m_amount = value, m_recover = true }); } component.m_resources = list3.ToArray(); } } if (list.Count + list2.Count > 0) { Debug.Log((object)("[VargheimLumberjacking] Seasoned Timber on ships " + string.Join(", ", list.ToArray()) + "; not needed (gate below " + ShipLevel.Value + ") on " + string.Join(", ", list2.ToArray()) + ".")); } } internal static int ShipGate(Piece pc) { try { if (!s_gateLookup) { s_gateLookup = true; Type type = AccessTools.TypeByName("VargheimProfessions.Plugin"); s_gateOf = ((type != null) ? AccessTools.Method(type, "GateOf", new Type[1] { typeof(Piece) }, (Type[])null) : null); Type type2 = AccessTools.TypeByName("VargheimProfessions.Plugin+Gate"); s_gateLevel = ((type2 != null) ? AccessTools.Field(type2, "Level") : null); } object obj = ((s_gateOf != null) ? s_gateOf.Invoke(null, new object[1] { pc }) : null); return (obj != null && s_gateLevel != null) ? ((int)s_gateLevel.GetValue(obj)) : (-1); } catch { return -1; } } private static bool IsStub(GameObject go) { if ((Object)(object)go != (Object)null) { return ((Object)go).name.IndexOf("stub", StringComparison.OrdinalIgnoreCase) >= 0; } return false; } private static bool LocalAttacker(HitData hit) { if (hit != null && (Object)(object)Player.m_localPlayer != (Object)null) { return (Object)(object)hit.GetAttacker() == (Object)(object)Player.m_localPlayer; } return false; } private static void OneHit(HitData hit) { if (LocalAttacker(hit) && Api.HasPerk("Lumberjacking", StumpLevel.Value)) { hit.m_damage.m_chop = Mathf.Max(hit.m_damage.m_chop, 100000f); } } private static void Refund(HitData hit) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Invalid comparison between Unknown and I4 Player localPlayer = Player.m_localPlayer; if (LocalAttacker(hit) && Api.HasPerk("Lumberjacking", SteadyLevel.Value) && !(Time.time - s_lastRefund < 0.4f)) { ItemData currentWeapon = ((Humanoid)localPlayer).GetCurrentWeapon(); if (currentWeapon != null && (int)currentWeapon.m_shared.m_skillType == 7) { s_lastRefund = Time.time; ((Character)localPlayer).AddStamina(SwingStamina(localPlayer, currentWeapon)); } } } private static float SwingStamina(Player p, ItemData w) { try { Attack val = s_curAttack.Invoke((Humanoid)(object)p); if (val == null || s_attackWeapon.Invoke(val) != w) { val = s_prevAttack.Invoke((Humanoid)(object)p); } if (val != null && s_attackWeapon.Invoke(val) == w && s_getStamina != null) { return Mathf.Max(0f, (float)s_getStamina.Invoke(val, null)); } } catch { } return w.m_shared.m_attack.m_attackStamina; } private static void Felling(TreeBase first, HitData hit) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (s_felling || !LocalAttacker(hit) || !((Character)localPlayer).IsCrouching() || !Api.HasPerk("Lumberjacking", CrewLevel.Value) || Content.UsedToday("felling")) { return; } Content.MarkUsedToday("felling"); s_felling = true; int num = 0; try { TreeBase[] array = Object.FindObjectsOfType<TreeBase>(); foreach (TreeBase val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)first) && !(Vector3.Distance(((Component)val).transform.position, ((Component)localPlayer).transform.position) > CrewRange.Value)) { HitData val2 = new HitData(); val2.m_damage.m_chop = 100000f; val2.m_toolTier = hit.m_toolTier; val2.m_point = ((Component)val).transform.position + Vector3.up; Vector3 val3 = ((Component)val).transform.position - ((Component)localPlayer).transform.position; val2.m_dir = ((Vector3)(ref val3)).normalized; val2.SetAttacker((Character)(object)localPlayer); val.Damage(val2); num++; } } } finally { s_felling = false; } Api.Message("Felling crew! " + num + " tree" + ((num == 1) ? "" : "s") + " come down. (Once per day.)"); } } }