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 LumberCamp v1.0.1
plugins/LumberCamp.dll
Decompiled 2 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: IgnoresAccessChecksTo("assembly_guiutils")] [assembly: IgnoresAccessChecksTo("assembly_utils")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("LumberCamp")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1+41a28710e50ebc4b01e3eb323e64ae679234eb71")] [assembly: AssemblyProduct("LumberCamp")] [assembly: AssemblyTitle("LumberCamp")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.1.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 LumberCampMod { internal static class CampPanel { private class Control { public Toggle Widget; public Text Label; public void SetEnabled(bool enabled) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Widget != (Object)null) { ((Selectable)Widget).interactable = enabled; } if ((Object)(object)Label != (Object)null) { ((Graphic)Label).color = (enabled ? GUIManager.Instance.ValheimOrange : Greyed); } } } private class PanelBehaviour : MonoBehaviour { private void Update() { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Current == (Object)null) { return; } if (!Current.IsValid || Input.GetKeyDown((KeyCode)27)) { Hide(); return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || Vector3.Distance(((Component)localPlayer).transform.position, ((Component)Current).transform.position) > 12f) { Hide(); } else if (Time.time >= s_refreshAt) { Refresh(); } } private void OnDestroy() { if ((Object)(object)Current != (Object)null) { GUIManager.BlockInput(false); } Current = null; s_root = null; s_families.Clear(); } } [CompilerGenerated] private static class <>O { public static UnityAction <0>__Hide; } [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static UnityAction <>9__22_0; public static UnityAction <>9__22_1; public static UnityAction <>9__22_2; public static UnityAction <>9__22_3; public static UnityAction <>9__22_4; public static UnityAction <>9__22_5; public static UnityAction <>9__22_6; public static UnityAction <>9__22_7; public static UnityAction<bool> <>9__22_8; internal void <EnsureBuilt>b__22_0() { Current?.RequestSetPaused(!Current.Paused); } internal void <EnsureBuilt>b__22_1() { Current?.RequestAddWorker(); } internal void <EnsureBuilt>b__22_2() { Current?.RequestRemoveWorker(); } internal void <EnsureBuilt>b__22_3() { Current?.RequestDepositNow(); } internal void <EnsureBuilt>b__22_4() { Current?.RequestAddChest(); } internal void <EnsureBuilt>b__22_5() { Current?.RequestClearChests(); } internal void <EnsureBuilt>b__22_6() { Adjust(-10f); } internal void <EnsureBuilt>b__22_7() { Adjust(10f); } internal void <EnsureBuilt>b__22_8(bool on) { if (!s_syncing) { Current?.RequestSetReplant(on); } } } private const float Width = 480f; private const float RowStep = 36f; private static readonly Color Greyed = new Color(0.55f, 0.52f, 0.47f, 0.7f); private static GameObject s_root; private static Text s_status; private static Text s_gateNote; private static Text s_pauseLabel; private static Text s_radiusLabel; private static Control s_replant; private static readonly Dictionary<string, Control> s_families = new Dictionary<string, Control>(); private static bool s_syncing; private static float s_refreshAt; public static LumberCamp Current { get; private set; } public static void Show(LumberCamp camp) { if (!((Object)(object)camp == (Object)null) && !GUIManager.IsHeadless()) { EnsureBuilt(); if ((Object)(object)s_root == (Object)null) { LumberCampPlugin.Log.LogWarning((object)"Camp panel could not be built; Jotunn's GUI is not ready."); return; } Current = camp; s_root.SetActive(true); GUIManager.BlockInput(true); Refresh(); } } public static void Hide() { if ((Object)(object)s_root != (Object)null) { s_root.SetActive(false); } if ((Object)(object)Current != (Object)null) { Current = null; GUIManager.BlockInput(false); } } private static void Refresh() { if ((Object)(object)Current == (Object)null || (Object)(object)s_root == (Object)null) { return; } s_refreshAt = Time.time + 0.5f; s_status.text = Current.StatusSummary(); s_pauseLabel.text = (Current.Paused ? "Resume work" : "Pause work"); s_radiusLabel.text = $"Radius: {Current.Radius:0} m"; s_syncing = true; s_replant.Widget.isOn = Current.Replant; List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>(); foreach (KeyValuePair<string, Control> s_family in s_families) { bool flag = LumberCampConfig.BossDefeated(s_family.Key); s_family.Value.Widget.isOn = flag && Current.IsFamilyChecked(s_family.Key); s_family.Value.SetEnabled(flag); if (!flag) { list.Add(new KeyValuePair<string, string>(TreeFamilies.DisplayName(s_family.Key), LumberCampConfig.BossName(LumberCampConfig.BossFor(s_family.Key)))); } } s_syncing = false; s_gateNote.text = GateNote(list); } private static string GateNote(List<KeyValuePair<string, string>> locked) { if (locked.Count == 0) { return string.Empty; } List<string> list = new List<string>(); Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>(); foreach (KeyValuePair<string, string> item in locked) { if (!dictionary.TryGetValue(item.Value, out var value)) { value = new List<string>(); dictionary[item.Value] = value; list.Add(item.Value); } value.Add(item.Key); } StringBuilder stringBuilder = new StringBuilder(); foreach (string item2 in list) { if (stringBuilder.Length > 0) { stringBuilder.Append(" "); } List<string> list2 = dictionary[item2]; stringBuilder.Append(string.Join(", ", list2.ToArray()) + " " + ((list2.Count == 1) ? "waits" : "wait") + " on " + item2 + "."); } return stringBuilder.ToString(); } private static void EnsureBuilt() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Expected O, but got Unknown //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Expected O, but got Unknown //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Expected O, but got Unknown //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Expected O, but got Unknown //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Expected O, but got Unknown //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Expected O, but got Unknown //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Expected O, but got Unknown //IL_0320: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Unknown result type (might be due to invalid IL or missing references) //IL_032b: Expected O, but got Unknown //IL_0458: Unknown result type (might be due to invalid IL or missing references) //IL_04ba: Unknown result type (might be due to invalid IL or missing references) //IL_0490: Unknown result type (might be due to invalid IL or missing references) //IL_0495: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Expected O, but got Unknown if ((Object)(object)s_root != (Object)null || GUIManager.Instance == null || (Object)(object)GUIManager.CustomGUIFront == (Object)null) { return; } s_root = GUIManager.Instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), Vector2.zero, 480f, 100f, true); s_root.SetActive(false); s_root.AddComponent<PanelBehaviour>(); Transform transform = s_root.transform; s_families.Clear(); float num = -34f; AddText(transform, "Lumber Camp", 0f, num, 440f, 30f, 22, (TextAnchor)4); num -= 40f; s_status = AddText(transform, string.Empty, 0f, num - 44f, 430f, 110f, 14, (TextAnchor)0); num -= 118f; Section(transform, "Lumberjacks", ref num); float y = num; object obj = <>c.<>9__22_0; if (obj == null) { UnityAction val = delegate { Current?.RequestSetPaused(!Current.Paused); }; <>c.<>9__22_0 = val; obj = (object)val; } s_pauseLabel = AddButton(transform, "Pause work", -110f, y, 205f, 30f, (UnityAction)obj); float y2 = num; object obj2 = <>c.<>9__22_1; if (obj2 == null) { UnityAction val2 = delegate { Current?.RequestAddWorker(); }; <>c.<>9__22_1 = val2; obj2 = (object)val2; } AddButton(transform, "Hire a lumberjack", 110f, y2, 205f, 30f, (UnityAction)obj2); num -= 36f; float y3 = num; object obj3 = <>c.<>9__22_2; if (obj3 == null) { UnityAction val3 = delegate { Current?.RequestRemoveWorker(); }; <>c.<>9__22_2 = val3; obj3 = (object)val3; } AddButton(transform, "Send one home", -110f, y3, 205f, 30f, (UnityAction)obj3); float y4 = num; object obj4 = <>c.<>9__22_3; if (obj4 == null) { UnityAction val4 = delegate { Current?.RequestDepositNow(); }; <>c.<>9__22_3 = val4; obj4 = (object)val4; } AddButton(transform, "Store wood now", 110f, y4, 205f, 30f, (UnityAction)obj4); num -= 36f; Section(transform, "Storage", ref num); float y5 = num; object obj5 = <>c.<>9__22_4; if (obj5 == null) { UnityAction val5 = delegate { Current?.RequestAddChest(); }; <>c.<>9__22_4 = val5; obj5 = (object)val5; } AddButton(transform, "Add nearest chest", -110f, y5, 205f, 30f, (UnityAction)obj5); float y6 = num; object obj6 = <>c.<>9__22_5; if (obj6 == null) { UnityAction val6 = delegate { Current?.RequestClearChests(); }; <>c.<>9__22_5 = val6; obj6 = (object)val6; } AddButton(transform, "Clear chests", 110f, y6, 205f, 30f, (UnityAction)obj6); num -= 36f; Section(transform, "Work area", ref num); float y7 = num; object obj7 = <>c.<>9__22_6; if (obj7 == null) { UnityAction val7 = delegate { Adjust(-10f); }; <>c.<>9__22_6 = val7; obj7 = (object)val7; } AddButton(transform, "-", -150f, y7, 44f, 30f, (UnityAction)obj7); s_radiusLabel = AddText(transform, string.Empty, 0f, num, 200f, 30f, 15, (TextAnchor)4); float y8 = num; object obj8 = <>c.<>9__22_7; if (obj8 == null) { UnityAction val8 = delegate { Adjust(10f); }; <>c.<>9__22_7 = val8; obj8 = (object)val8; } AddButton(transform, "+", 150f, y8, 44f, 30f, (UnityAction)obj8); num -= 36f; s_replant = AddToggle(transform, "Replant a sapling after clearing a stump", -206f, num, delegate(bool on) { if (!s_syncing) { Current?.RequestSetReplant(on); } }); num -= 36f; Section(transform, "Trees to cut", ref num); int num2 = 0; for (int num3 = 0; num3 < TreeFamilies.All.Length; num3++) { string family = TreeFamilies.All[num3]; int num4 = num3 % 3; int num5 = num3 / 3; num2 = Mathf.Max(num2, num5 + 1); float x = -206f + (float)num4 * 150f; float y9 = num - (float)num5 * 30f; s_families[family] = AddToggle(transform, TreeFamilies.DisplayName(family), x, y9, delegate(bool on) { if (!s_syncing) { Current?.RequestSetFamily(family, on); } }); } num -= (float)num2 * 30f + 4f; s_gateNote = AddText(transform, string.Empty, 0f, num - 14f, 430f, 54f, 13, (TextAnchor)0); ((Graphic)s_gateNote).color = Greyed; num -= 64f; float y10 = num; object obj9 = <>O.<0>__Hide; if (obj9 == null) { UnityAction val9 = Hide; <>O.<0>__Hide = val9; obj9 = (object)val9; } AddButton(transform, "Close", 0f, y10, 205f, 30f, (UnityAction)obj9); num -= 42f; s_root.GetComponent<RectTransform>().sizeDelta = new Vector2(480f, 0f - num); } private static void Adjust(float delta) { if ((Object)(object)Current != (Object)null) { Current.RequestSetRadius(Current.Radius + delta); } } private static void Section(Transform parent, string title, ref float y) { y -= 4f; AddText(parent, title, 0f, y, 440f, 24f, 16, (TextAnchor)4); y -= 30f; } private static void Place(GameObject go, float x, float y, float width, float height, Vector2 pivot) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: 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) RectTransform component = go.GetComponent<RectTransform>(); if (!((Object)(object)component == (Object)null)) { component.anchorMin = new Vector2(0.5f, 1f); component.anchorMax = new Vector2(0.5f, 1f); component.pivot = pivot; component.anchoredPosition = new Vector2(x, y); component.sizeDelta = new Vector2(width, height); } } private static Text AddText(Transform parent, string text, float x, float y, float width, float height, int size, TextAnchor alignment) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GUIManager.Instance.CreateText(text, parent, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(x, y), GUIManager.Instance.AveriaSerifBold, size, GUIManager.Instance.ValheimOrange, true, Color.black, width, height, false); Text componentInChildren = obj.GetComponentInChildren<Text>(true); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.alignment = alignment; componentInChildren.horizontalOverflow = (HorizontalWrapMode)0; componentInChildren.verticalOverflow = (VerticalWrapMode)1; } Place(obj, x, y, width, height, new Vector2(0.5f, 0.5f)); return componentInChildren; } private static Text AddButton(Transform parent, string label, float x, float y, float width, float height, UnityAction action) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GUIManager.Instance.CreateButton(label, parent, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(x, y), width, height); Place(obj, x, y, width, height, new Vector2(0.5f, 0.5f)); Button componentInChildren = obj.GetComponentInChildren<Button>(true); if ((Object)(object)componentInChildren != (Object)null) { ((UnityEvent)componentInChildren.onClick).AddListener(action); } return obj.GetComponentInChildren<Text>(true); } private static Control AddToggle(Transform parent, string label, float x, float y, UnityAction<bool> onChanged) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0080: 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_009c: 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) GameObject obj = GUIManager.Instance.CreateToggle(parent, 26f, 26f); Place(obj, x, y, 26f, 26f, new Vector2(0.5f, 0.5f)); Toggle componentInChildren = obj.GetComponentInChildren<Toggle>(true); if ((Object)(object)componentInChildren != (Object)null) { ((UnityEvent<bool>)(object)componentInChildren.onValueChanged).AddListener(onChanged); } GameObject obj2 = GUIManager.Instance.CreateText(label, parent, new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(x + 18f, y), GUIManager.Instance.AveriaSerifBold, 13, GUIManager.Instance.ValheimOrange, true, Color.black, 400f, 26f, false); Text componentInChildren2 = obj2.GetComponentInChildren<Text>(true); if ((Object)(object)componentInChildren2 != (Object)null) { componentInChildren2.alignment = (TextAnchor)3; componentInChildren2.horizontalOverflow = (HorizontalWrapMode)1; } Place(obj2, x + 18f, y, 400f, 26f, new Vector2(0f, 0.5f)); return new Control { Widget = componentInChildren, Label = componentInChildren2 }; } } public class LumberAI : BaseAI { private enum State { Idle, Chop, Collect, Deposit, GoHome } private const float IdleRethinkSeconds = 3f; private const float OrphanGraceSeconds = 30f; private const float StuckSeconds = 8f; private const float ReplantDelaySeconds = 1f; private const float ChopJobTimeoutSeconds = 90f; private const float ApproachStallSeconds = 2.5f; private static readonly RaycastHit[] s_swingHits = (RaycastHit[])(object)new RaycastHit[32]; private static int s_swingMask; private static int s_swingMaskTerrain; private const float MissGraceSeconds = 0.75f; private LumberWorker m_worker; private Humanoid m_humanoid; private State m_state; private float m_thinkTimer; private bool m_wasOwner; private bool m_depositSynced; private int m_lastDepositRequest; private bool m_forceDeposit; private float m_orphanSince = -1f; private float m_axeTimer; private float m_gearTimer; private Choppable m_target; private Vector3 m_targetLastPos; private float m_targetHealth = -1f; private int m_swingsWithoutProgress; private bool m_swingInProgress; private bool m_swingWillMiss; private float m_judgeSwingAt = -1f; private float m_jobSince; private float m_closestApproach = float.MaxValue; private float m_approachStallSince = -1f; private ItemDrop m_drop; private Container m_chest; private Vector3 m_lastChopPos; private bool m_hasChopPos; private float m_replantAt = -1f; private Vector3 m_replantPos; private string m_replantFamily; private bool m_holdingPosition; private Vector3 m_stuckPos; private float m_stuckTimer; private readonly Dictionary<int, float> m_blacklist = new Dictionary<int, float>(); private readonly List<Choppable> m_scratch = new List<Choppable>(); private float m_nextBlacklistPrune; public override void Awake() { ((BaseAI)this).Awake(); m_worker = ((Component)this).GetComponent<LumberWorker>(); ref Humanoid humanoid = ref m_humanoid; Character character = base.m_character; humanoid = (Humanoid)(object)((character is Humanoid) ? character : null); } public override bool UpdateAI(float dt) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) if (!((BaseAI)this).UpdateAI(dt)) { if (m_wasOwner) { m_wasOwner = false; if ((Object)(object)m_worker != (Object)null) { m_worker.ForgetBag(); } } return false; } if ((Object)(object)m_worker == (Object)null || (Object)(object)m_humanoid == (Object)null) { return true; } if (!m_wasOwner) { m_wasOwner = true; m_worker.LoadBag(); m_worker.Claim = ZDOID.None; m_state = State.Idle; m_thinkTimer = 0f; } m_holdingPosition = false; LumberCamp lumberCamp = m_worker.ResolveCamp(); if ((Object)(object)lumberCamp == (Object)null) { TickOrphan(); return true; } m_orphanSince = -1f; m_axeTimer -= dt; if (m_axeTimer <= 0f) { m_axeTimer = 2f; m_worker.EnsureAxe(); } m_gearTimer -= dt; if (m_gearTimer <= 0f) { m_gearTimer = 2f; m_worker.EnsureGear(); } TickReplant(lumberCamp); if (lumberCamp.Paused) { ClearJob(); m_state = State.Idle; StayNear(dt, ((Component)lumberCamp).transform.position, 4f); m_worker.SetStatus("Paused"); return true; } int depositRequest = lumberCamp.DepositRequest; if (!m_depositSynced) { m_depositSynced = true; m_lastDepositRequest = depositRequest; } else if (depositRequest != m_lastDepositRequest) { m_lastDepositRequest = depositRequest; if (m_worker.DepositableItems(m_worker.KeepSeeds).Count > 0) { m_forceDeposit = true; ClearJob(); m_state = State.Idle; m_thinkTimer = 0f; } } m_thinkTimer -= dt; if (m_thinkTimer <= 0f) { m_thinkTimer = LumberCampConfig.ThinkInterval.Value; Think(lumberCamp); } switch (m_state) { case State.Chop: TickChop(dt, lumberCamp); break; case State.Collect: TickCollect(dt); break; case State.Deposit: TickDeposit(dt); break; case State.GoHome: TickHome(dt, lumberCamp); break; default: ((BaseAI)this).StopMoving(); m_holdingPosition = true; break; } TickStuck(dt); return true; } private void Think(LumberCamp camp) { //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_03e6: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Unknown result type (might be due to invalid IL or missing references) PruneBlacklist(); switch (m_state) { case State.Chop: if (m_target != null && m_target.IsAlive && camp.IsFamilyEnabled(m_target.Family)) { return; } break; case State.Collect: if ((Object)(object)m_drop != (Object)null && (Object)(object)m_drop.m_nview != (Object)null && m_drop.m_nview.IsValid()) { return; } break; case State.Deposit: if ((Object)(object)m_chest != (Object)null && (Object)(object)m_chest.m_nview != (Object)null && m_chest.m_nview.IsValid()) { return; } break; } ClearJob(); Vector3 position = ((Component)camp).transform.position; Vector3 position2 = ((Component)this).transform.position; float radius = camp.Radius; List<ItemData> list = m_worker.DepositableItems(m_worker.KeepSeeds); int count = list.Count; bool bagFull = m_worker.BagFull; if (count > 0 && (bagFull || m_forceDeposit)) { Container val = camp.FindChestFor(list, position2, IsBlacklisted); if ((Object)(object)val != (Object)null) { StartDeposit(val); return; } if (bagFull) { m_forceDeposit = false; StartHome((camp.ChestCount == 0) ? "Bag full and no chest assigned" : "Bag full and every chest is full"); return; } } m_forceDeposit = false; Vector3 val2 = (m_hasChopPos ? m_lastChopPos : position2); ItemDrop val3 = WorldQuery.FindNearestDrop(position, WorldQuery.CleanupRadius(radius) + 6f, val2, (ItemDrop d) => !IsBlacklisted(((Object)d).GetInstanceID()) && m_worker.CanCarry(d.m_itemData) && !LumberWorker.IsClaimedByAnother(d.m_nview.GetZDO().m_uid, m_worker)); if ((Object)(object)val3 != (Object)null) { m_drop = val3; m_worker.Claim = val3.m_nview.GetZDO().m_uid; m_jobSince = Time.time; SetState(State.Collect); m_worker.SetStatus("Picking up " + Localization.instance.Localize(val3.m_itemData.m_shared.m_name)); return; } WorldQuery.FindChoppables(position, radius, m_scratch); Choppable choppable = null; float num = float.MaxValue; int value = LumberCampConfig.ToolTier.Value; foreach (Choppable item in m_scratch) { if (camp.IsFamilyEnabled(item.Family) && item.MinToolTier <= value && !IsBlacklisted(item.Id) && !LumberWorker.IsClaimedByAnother(item.NetView.GetZDO().m_uid, m_worker)) { float num2 = (float)item.Kind * 1000f + Vector3.Distance(position2, item.Position); if (num2 < num) { num = num2; choppable = item; } } } if (choppable != null) { m_target = choppable; m_worker.Claim = choppable.NetView.GetZDO().m_uid; m_targetLastPos = choppable.Position; m_targetHealth = choppable.Health(-1f); m_swingsWithoutProgress = 0; m_swingInProgress = false; m_swingWillMiss = false; m_closestApproach = float.MaxValue; m_approachStallSince = -1f; m_jobSince = Time.time; SetState(State.Chop); m_worker.SetStatus(VerbFor(choppable) + " a " + choppable.Describe()); Log("job: " + m_target.Name + " (" + m_target.Kind.ToString() + ")"); return; } if (count > 0) { Container val4 = camp.FindChestFor(list, position2, IsBlacklisted); if ((Object)(object)val4 != (Object)null) { StartDeposit(val4); return; } } StartHome((count > 0) ? "Nothing left to cut; holding wood" : "Nothing left to cut"); } private void StartDeposit(Container chest) { m_chest = chest; m_jobSince = Time.time; SetState(State.Deposit); m_worker.SetStatus("Carrying wood to a chest"); } private void StartHome(string status) { SetState(State.GoHome); m_thinkTimer = 3f; m_worker.SetStatus(status); } private void SetState(State state) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) m_state = state; m_stuckTimer = 0f; m_stuckPos = ((Component)this).transform.position; } private void ClearJob() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) m_target = null; m_drop = null; m_chest = null; m_swingInProgress = false; m_swingWillMiss = false; m_judgeSwingAt = -1f; m_closestApproach = float.MaxValue; m_approachStallSince = -1f; m_worker.Claim = ZDOID.None; } private static string VerbFor(Choppable c) { if (c.Kind == ChopKind.Log) { return "Splitting"; } if (c.IsStump) { return "Clearing"; } return "Felling"; } private void TickChop(float dt, LumberCamp camp) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_0135: 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_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) if (m_target == null || !m_target.IsAlive) { OnTargetGone(camp); return; } if (Time.time - m_jobSince > 90f) { Blacklist(m_target.Id, 120f, "could not finish"); ClearJob(); m_state = State.Idle; m_thinkTimer = 0f; return; } Vector3 position = ((Component)this).transform.position; m_targetLastPos = m_target.Position; Vector3 origin; float range; float rayWidth; bool flag = AttackCast(out origin, out range, out rayWidth); Vector3 val = m_target.ClosestPoint(flag ? origin : (position + Vector3.up)); float num = Utils.DistanceXZ(position, val); float num2 = CloseQuarters(); bool flag2 = SwingWouldLand(val); bool flag3 = num <= Mathf.Max(num2, range) && (num <= num2 || ApproachStalled(num)); if (!flag2 && !flag3) { ((BaseAI)this).MoveTo(dt, val, num2 * 0.8f, num > 12f); m_swingInProgress = false; m_swingWillMiss = false; m_judgeSwingAt = -1f; return; } m_holdingPosition = true; ((BaseAI)this).StopMoving(); ((BaseAI)this).LookAt(val); bool flag4 = ((Character)m_humanoid).InAttack(); if (m_swingInProgress && !flag4) { m_swingInProgress = false; m_judgeSwingAt = Time.time + 0.75f; m_hasChopPos = true; m_lastChopPos = m_target.Position; } if (m_judgeSwingAt >= 0f) { if (Time.time < m_judgeSwingAt) { return; } m_judgeSwingAt = -1f; float num3 = m_target.Health(-1f); if ((num3 >= 0f && m_targetHealth < 0f) || (num3 >= 0f && m_targetHealth >= 0f && num3 < m_targetHealth)) { m_swingsWithoutProgress = 0; } else { m_swingsWithoutProgress++; if (m_swingWillMiss || m_swingsWithoutProgress >= 2) { DirectHit(); } } m_swingWillMiss = false; m_targetHealth = m_target.Health(-1f); } if (!flag4 && !(base.m_character.GetTimeSinceLastAttack() < AttackInterval()) && ((BaseAI)this).IsLookingAt(val, AttackAngle(), false)) { if (((Character)m_humanoid).StartAttack((Character)null, false)) { m_swingInProgress = true; m_swingWillMiss = !flag2; m_targetHealth = m_target.Health(m_targetHealth); } else if (++m_swingsWithoutProgress >= 6) { DirectHit(); } } } private void DirectHit() { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009b: 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_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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_00bc: Unknown result type (might be due to invalid IL or missing references) if (m_target != null && m_target.IsAlive) { IDestructible val = m_target.Target.GetComponent<IDestructible>() ?? m_target.Target.GetComponentInParent<IDestructible>(); if (val != null) { Vector3 val2 = m_target.ClosestPoint(((Component)this).transform.position + Vector3.up); HitData val3 = new HitData(); val3.m_damage.m_chop = LumberCampConfig.ChopDamage.Value; val3.m_toolTier = (short)LumberCampConfig.ToolTier.Value; val3.m_point = val2; Vector3 val4 = val2 - ((Component)this).transform.position; val3.m_dir = ((Vector3)(ref val4)).normalized; val3.m_hitType = (HitType)1; val3.m_skill = (SkillType)13; val3.SetAttacker(base.m_character); val.Damage(val3); m_swingsWithoutProgress = 0; Log("swing did not register on " + m_target.Name + "; chopped it directly"); } } } private void OnTargetGone(LumberCamp camp) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) Choppable target = m_target; m_target = null; m_swingInProgress = false; m_worker.Claim = ZDOID.None; if (target != null) { m_hasChopPos = true; m_lastChopPos = m_targetLastPos; if (target.IsStump && camp.Replant) { m_replantAt = Time.time + 1f; m_replantPos = m_targetLastPos; m_replantFamily = target.Family; } } m_state = State.Idle; m_thinkTimer = 0f; } private float CloseQuarters() { return base.m_character.GetRadius() + 0.6f; } private bool ApproachStalled(float dist) { if (dist < m_closestApproach - 0.15f || dist > m_closestApproach + 1.5f) { m_closestApproach = dist; m_approachStallSince = Time.time; return false; } if (m_approachStallSince < 0f) { m_approachStallSince = Time.time; return false; } return Time.time - m_approachStallSince > 2.5f; } private bool AttackCast(out Vector3 origin, out float range, out float rayWidth) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) origin = ((Component)this).transform.position + Vector3.up * 1.2f; range = 1.5f; rayWidth = 0f; Attack val = m_humanoid.GetCurrentWeapon()?.m_shared?.m_attack; if (val == null) { return false; } Transform val2 = ((Component)this).transform; if (!string.IsNullOrEmpty(val.m_attackOriginJoint)) { GameObject visual = base.m_character.GetVisual(); Transform val3 = (((Object)(object)visual != (Object)null) ? Utils.FindChild(visual.transform, val.m_attackOriginJoint, (IterativeSearchType)0) : null); if ((Object)(object)val3 != (Object)null) { val2 = val3; } } origin = val2.position + Vector3.up * val.m_attackHeight + ((Component)this).transform.right * val.m_attackOffset; range = Mathf.Max(0.1f, val.m_attackRange); rayWidth = Mathf.Max(0f, val.m_attackRayWidth); return true; } private bool SwingWouldLand(Vector3 aim) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0094: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) if (m_target == null || !m_target.IsAlive || !AttackCast(out var origin, out var range, out var rayWidth)) { return false; } Vector3 val = aim - origin; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude < 0.0001f) { return true; } ((Vector3)(ref val)).Normalize(); int num = SwingMask(m_humanoid.GetCurrentWeapon()?.m_shared?.m_attack); int num2 = ((rayWidth > 0f) ? Physics.SphereCastNonAlloc(origin, rayWidth, val, s_swingHits, Mathf.Max(0f, range - rayWidth), num, (QueryTriggerInteraction)1) : Physics.RaycastNonAlloc(origin, val, s_swingHits, range, num, (QueryTriggerInteraction)1)); GameObject gameObject = ((Component)base.m_character).gameObject; GameObject val2 = null; float num3 = float.MaxValue; for (int i = 0; i < num2 && i < s_swingHits.Length; i++) { Collider collider = ((RaycastHit)(ref s_swingHits[i])).collider; if (!((Object)(object)collider == (Object)null) && !((Object)(object)((Component)collider).gameObject == (Object)(object)gameObject)) { GameObject val3 = Projectile.FindHitObject(collider); if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3 == (Object)(object)gameObject) && ((RaycastHit)(ref s_swingHits[i])).distance < num3) { num3 = ((RaycastHit)(ref s_swingHits[i])).distance; val2 = val3; } } } if ((Object)(object)val2 != (Object)null) { return (Object)(object)val2 == (Object)(object)m_target.Target.gameObject; } return false; } private static int SwingMask(Attack attack) { if (s_swingMask == 0) { s_swingMask = LayerMask.GetMask(new string[11] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "character", "character_net", "character_ghost", "hitbox", "character_noenv", "vehicle" }); s_swingMaskTerrain = s_swingMask | LayerMask.GetMask(new string[1] { "terrain" }); } if (attack == null || !attack.m_hitTerrain) { return s_swingMask; } return s_swingMaskTerrain; } private float AttackInterval() { ItemData currentWeapon = m_humanoid.GetCurrentWeapon(); return Mathf.Clamp((currentWeapon?.m_shared != null) ? currentWeapon.m_shared.m_aiAttackInterval : 1f, 0.4f, 3f); } private float AttackAngle() { ItemData currentWeapon = m_humanoid.GetCurrentWeapon(); float num = ((currentWeapon?.m_shared != null) ? currentWeapon.m_shared.m_aiAttackMaxAngle : 0f); if (!(num > 0f)) { return 20f; } return num; } private void TickReplant(LumberCamp camp) { //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) if (m_replantAt < 0f || Time.time < m_replantAt) { return; } m_replantAt = -1f; if (!camp.Replant) { return; } SaplingInfo saplingInfo = TreeFamilies.SaplingFor(m_replantFamily); if (saplingInfo == null) { Log("no sapling exists for " + m_replantFamily); return; } Inventory inventory = m_humanoid.GetInventory(); ItemData val = null; bool value = LumberCampConfig.FreeReplant.Value; if (!value) { foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem.m_shared != null && allItem.m_shared.m_name == saplingInfo.SeedToken && allItem.m_stack > 0) { val = allItem; break; } } } if (val == null && !value) { LumberCampPlugin.Log.LogInfo((object)("Lumberjack cleared a " + m_replantFamily.ToLowerInvariant() + " stump but carries no " + Localization.instance.Localize(saplingInfo.SeedToken) + " to replant it.")); m_worker.SetStatus("No seed to replant a " + TreeFamilies.DisplayName(m_replantFamily).ToLowerInvariant()); return; } GameObject val2 = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(saplingInfo.SaplingPrefab) : null); if ((Object)(object)val2 == (Object)null) { return; } Vector3 val3 = WorldQuery.SnapToGround(m_replantPos); GameObject val4 = Object.Instantiate<GameObject>(val2, val3, Quaternion.Euler(0f, Random.Range(0f, 360f), 0f)); if (!((Object)(object)val4 == (Object)null)) { if (val != null) { inventory.RemoveOneItem(val); } Piece component = val4.GetComponent<Piece>(); if ((Object)(object)component != (Object)null && component.m_placeEffect != null) { component.m_placeEffect.Create(val3, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } m_worker.SetStatus("Planted a " + TreeFamilies.DisplayName(m_replantFamily).ToLowerInvariant() + " sapling"); Log("replanted " + saplingInfo.SaplingPrefab); } } private void TickCollect(float dt) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_drop == (Object)null || (Object)(object)m_drop.m_nview == (Object)null || !m_drop.m_nview.IsValid()) { m_drop = null; m_state = State.Idle; m_thinkTimer = 0f; return; } Vector3 position = ((Component)m_drop).transform.position; float num = Utils.DistanceXZ(((Component)this).transform.position, position); if (num > 1.6f) { ((BaseAI)this).MoveTo(dt, position, 1.2f, num > 12f); return; } m_holdingPosition = true; ((BaseAI)this).StopMoving(); ((BaseAI)this).LookAt(position); if (!m_drop.m_nview.IsOwner()) { m_drop.RequestOwn(); } if (m_humanoid.Pickup(((Component)m_drop).gameObject, false, false)) { m_drop = null; m_state = State.Idle; m_thinkTimer = 0f; } else if (Time.time - m_jobSince > 6f) { Blacklist(((Object)m_drop).GetInstanceID(), 60f, "could not pick up"); m_drop = null; m_state = State.Idle; m_thinkTimer = 0f; } } private void TickDeposit(float dt) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_chest == (Object)null || (Object)(object)m_chest.m_nview == (Object)null || !m_chest.m_nview.IsValid()) { m_chest = null; m_state = State.Idle; m_thinkTimer = 0f; return; } Vector3 position = ((Component)m_chest).transform.position; float num = Utils.DistanceXZ(((Component)this).transform.position, position); if (num > 2.4f) { ((BaseAI)this).MoveTo(dt, position, 1.8f, num > 12f); return; } m_holdingPosition = true; ((BaseAI)this).StopMoving(); ((BaseAI)this).LookAt(position); if (WorldQuery.ChestInUse(m_chest)) { m_worker.SetStatus("Waiting for someone to close the chest"); if (Time.time - m_jobSince > 30f) { Blacklist(((Object)m_chest).GetInstanceID(), 20f, "chest stayed open"); m_chest = null; m_state = State.Idle; m_thinkTimer = 0f; } return; } if (!m_chest.m_nview.IsOwner()) { m_chest.m_nview.ClaimOwnership(); } Inventory inventory = m_chest.GetInventory(); Inventory inventory2 = m_humanoid.GetInventory(); int num2 = 0; foreach (ItemData item in m_worker.DepositableItems(m_worker.KeepSeeds)) { if (inventory.CanAddItem(item, item.m_stack)) { inventory.MoveItemToThis(inventory2, item); num2++; } } if (num2 == 0) { Blacklist(((Object)m_chest).GetInstanceID(), 30f, "no room in"); } else { m_worker.SaveBag(); Log("stored " + num2 + " stack(s)"); } m_chest = null; m_state = State.Idle; m_thinkTimer = 0f; } private void TickHome(float dt, LumberCamp camp) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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) Vector3 position = ((Component)camp).transform.position; float num = Utils.DistanceXZ(((Component)this).transform.position, position); if (num > 3f) { ((BaseAI)this).MoveTo(dt, position, 2.5f, num > 15f); return; } ((BaseAI)this).StopMoving(); m_holdingPosition = true; m_state = State.Idle; } private void StayNear(float dt, Vector3 point, float dist) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (Utils.DistanceXZ(((Component)this).transform.position, point) > dist) { ((BaseAI)this).MoveTo(dt, point, dist * 0.8f, false); return; } ((BaseAI)this).StopMoving(); m_holdingPosition = true; } private void TickOrphan() { ((BaseAI)this).StopMoving(); m_holdingPosition = true; m_worker.SetStatus("Waiting for its camp"); if (m_orphanSince < 0f) { m_orphanSince = Time.time; } else if (Time.time - m_orphanSince > 30f && m_worker.CampIsGone()) { LumberCampPlugin.Log.LogInfo((object)"A lumberjack's camp no longer exists; sending it home."); m_worker.Dismiss(); } } private void TickStuck(float dt) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) if (m_state == State.Idle || m_holdingPosition || ((Character)m_humanoid).InAttack()) { m_stuckTimer = 0f; m_stuckPos = ((Component)this).transform.position; return; } if (Vector3.Distance(((Component)this).transform.position, m_stuckPos) > 0.3f) { m_stuckPos = ((Component)this).transform.position; m_stuckTimer = 0f; return; } m_stuckTimer += dt; if (!(m_stuckTimer < 8f)) { int num = m_target?.Id ?? (((Object)(object)m_drop != (Object)null) ? ((Object)m_drop).GetInstanceID() : (((Object)(object)m_chest != (Object)null) ? ((Object)m_chest).GetInstanceID() : 0)); if (num != 0) { Blacklist(num, 60f, "could not reach"); } ClearJob(); m_state = State.Idle; m_thinkTimer = 0f; m_stuckTimer = 0f; } } private bool IsBlacklisted(int id) { if (m_blacklist.TryGetValue(id, out var value)) { return Time.time < value; } return false; } private void Blacklist(int id, float seconds, string why) { m_blacklist[id] = Time.time + seconds; Log(why + " target " + id + "; ignoring it for " + seconds + "s"); } private void PruneBlacklist() { if (Time.time < m_nextBlacklistPrune || m_blacklist.Count == 0) { return; } m_nextBlacklistPrune = Time.time + 30f; List<int> list = new List<int>(); foreach (KeyValuePair<int, float> item in m_blacklist) { if (Time.time >= item.Value) { list.Add(item.Key); } } foreach (int item2 in list) { m_blacklist.Remove(item2); } } private void Log(string message) { if (LumberCampConfig.DebugLogging.Value) { LumberCampPlugin.Log.LogInfo((object)$"[lumberjack {((Object)this).GetInstanceID()}] {message}"); } } } internal static class LumberAxe { public const string NameToken = "$lc_axe"; public const string PrefabName = "lumbercamp_axe"; private const string VisualSource = "AxeIron"; public static GameObject Prefab { get; private set; } public static bool IsAxe(ItemData item) { if (item?.m_shared != null) { return item.m_shared.m_name == "$lc_axe"; } return false; } public static ItemDrop FindMeleeTemplate(Humanoid humanoid) { //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Invalid comparison between Unknown and I4 //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Invalid comparison between Unknown and I4 //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Invalid comparison between Unknown and I4 List<GameObject> list = new List<GameObject>(); if (humanoid.m_defaultItems != null) { list.AddRange(humanoid.m_defaultItems); } if (humanoid.m_randomWeapon != null) { list.AddRange(humanoid.m_randomWeapon); } if (humanoid.m_randomSets != null) { ItemSet[] randomSets = humanoid.m_randomSets; foreach (ItemSet val in randomSets) { if (val?.m_items != null) { list.AddRange(val.m_items); } } } foreach (GameObject item in list) { ItemDrop val2 = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null); SharedData val3 = val2?.m_itemData?.m_shared; if (val3 != null) { bool num = (int)val3.m_itemType == 3 || (int)val3.m_itemType == 14; bool flag = val3.m_attack != null && ((int)val3.m_attack.m_attackType == 0 || (int)val3.m_attack.m_attackType == 1) && !string.IsNullOrEmpty(val3.m_attack.m_attackAnimation); if (num && flag) { return val2; } } } return null; } public static GameObject Build(ItemDrop template) { //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Expected O, but got Unknown GameObject val = null; if ((Object)(object)template != (Object)null) { val = PrefabManager.Instance.CreateClonedPrefab("lumbercamp_axe", ((Component)template).gameObject); } else { GameObject prefab = PrefabManager.Instance.GetPrefab("AxeIron"); if ((Object)(object)prefab != (Object)null) { LumberCampPlugin.Log.LogWarning((object)"No melee weapon on the source creature; using an iron axe model."); val = PrefabManager.Instance.CreateClonedPrefab("lumbercamp_axe", prefab); } } if ((Object)(object)val == (Object)null) { LumberCampPlugin.Log.LogError((object)"Could not build the lumberjack's axe: no source prefab."); return null; } ItemDrop component = val.GetComponent<ItemDrop>(); SharedData shared = component.m_itemData.m_shared; shared.m_name = "$lc_axe"; shared.m_description = "$lc_axe_desc"; if ((Object)(object)template != (Object)null) { SharedData shared2 = template.m_itemData.m_shared; shared.m_attack = shared2.m_attack.Clone(); shared.m_secondaryAttack = ((shared2.m_secondaryAttack != null) ? shared2.m_secondaryAttack.Clone() : shared.m_secondaryAttack); shared.m_animationState = shared2.m_animationState; shared.m_itemType = shared2.m_itemType; shared.m_attachOverride = shared2.m_attachOverride; shared.m_equipDuration = shared2.m_equipDuration; shared.m_aiAttackRange = shared2.m_aiAttackRange; shared.m_aiAttackRangeMin = shared2.m_aiAttackRangeMin; shared.m_aiAttackInterval = shared2.m_aiAttackInterval; shared.m_aiAttackMaxAngle = shared2.m_aiAttackMaxAngle; shared.m_aiWhenWalking = shared2.m_aiWhenWalking; shared.m_aiWhenFlying = shared2.m_aiWhenFlying; shared.m_aiWhenSwiming = shared2.m_aiWhenSwiming; Attack attack = shared.m_attack; LumberCampPlugin.Log.LogInfo((object)("Lumberjack axe swings like '" + ((Object)((Component)template).gameObject).name + "' " + $"(animation '{attack.m_attackAnimation}', range {attack.m_attackRange:0.00}m, " + $"ray width {attack.m_attackRayWidth:0.00}m, height {attack.m_attackHeight:0.00}m, " + "origin '" + (string.IsNullOrEmpty(attack.m_attackOriginJoint) ? "body" : attack.m_attackOriginJoint) + "').")); } else { LumberCampPlugin.Log.LogWarning((object)"No melee weapon on the source creature; the axe keeps a player axe's attack, which the creature's animator may not play."); } shared.m_aiTargetType = (AiTarget)0; shared.m_aiPrioritized = true; if (shared.m_aiAttackRange <= 0f) { shared.m_aiAttackRange = 2.5f; } if (shared.m_aiAttackMaxAngle <= 0f) { shared.m_aiAttackMaxAngle = 20f; } Prefab = val; ApplyStats(); shared.m_damagesPerLevel = default(DamageTypes); shared.m_skillType = (SkillType)13; shared.m_backstabBonus = 1f; shared.m_useDurability = false; shared.m_maxDurability = 100f; shared.m_maxStackSize = 1; shared.m_weight = 0f; shared.m_teleportable = true; shared.m_questItem = false; shared.m_dlc = string.Empty; component.m_autoPickup = false; ItemManager.Instance.AddItem(new CustomItem(val, false)); return val; } public static void ApplyStats() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) SharedData val = (((Object)(object)Prefab != (Object)null) ? Prefab.GetComponent<ItemDrop>().m_itemData.m_shared : null); if (val != null) { val.m_damages = new DamageTypes { m_chop = LumberCampConfig.ChopDamage.Value }; val.m_toolTier = LumberCampConfig.ToolTier.Value; } } } public class LumberCamp : MonoBehaviour, Hoverable, Interactable { private const string ZdoPaused = "lc_paused"; private const string ZdoRadius = "lc_radius"; private const string ZdoReplant = "lc_replant"; private const string ZdoDisabled = "lc_disabled"; private const string ZdoChests = "lc_chests"; private const string ZdoDeposit = "lc_deposit"; private const string ZdoSpawned = "lc_spawned"; private const string ZdoKey = "lc_key"; private const string RpcSetPaused = "LC_SetPaused"; private const string RpcSetRadius = "LC_SetRadius"; private const string RpcSetReplant = "LC_SetReplant"; private const string RpcSetFamily = "LC_SetFamily"; private const string RpcAddWorker = "LC_AddWorker"; private const string RpcRemoveWorker = "LC_RemoveWorker"; private const string RpcAddChest = "LC_AddChest"; private const string RpcClearChests = "LC_ClearChests"; private const string RpcDepositNow = "LC_DepositNow"; private const string RpcMessage = "LC_Message"; public static readonly List<LumberCamp> Instances = new List<LumberCamp>(); [Tooltip("Metres above the piece origin to float the hover text.")] public float m_hoverOffset = 0.6f; private ZNetView m_nview; private WearNTear m_wear; private bool m_ready; private string m_disabledRaw; private readonly HashSet<string> m_disabled = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private float m_nextSweep; private const float ChestMatchRadius = 0.6f; private const float ChestPruneSeconds = 30f; private readonly HashSet<int> m_chestsChecked = new HashSet<int>(); private readonly List<KeyValuePair<Vector3, Container>> m_chestCache = new List<KeyValuePair<Vector3, Container>>(); private readonly Dictionary<Vector3, float> m_chestMissingSince = new Dictionary<Vector3, float>(); private readonly Dictionary<Vector3, float> m_chestNextLookup = new Dictionary<Vector3, float>(); public bool IsValid { get { if (m_ready && (Object)(object)m_nview != (Object)null) { return m_nview.IsValid(); } return false; } } public long Key { get { if (!IsValid) { return 0L; } return Zdo.GetLong("lc_key", 0L); } } private ZDO Zdo => m_nview.GetZDO(); public bool Paused { get { if (IsValid) { return Zdo.GetBool("lc_paused", false); } return false; } } public float Radius => ClampRadius(IsValid ? Zdo.GetFloat("lc_radius", LumberCampConfig.DefaultWorkRadius.Value) : LumberCampConfig.DefaultWorkRadius.Value); public bool Replant { get { if (IsValid) { return Zdo.GetBool("lc_replant", LumberCampConfig.DefaultReplant.Value); } return false; } } public int DepositRequest { get { if (!IsValid) { return 0; } return Zdo.GetInt("lc_deposit", 0); } } public int WorkerCount => Workers().Count; public int ChestCount => ChestPositions().Count; private bool Owner { get { if (IsValid) { return m_nview.IsOwner(); } return false; } } private void Awake() { m_nview = ((Component)this).GetComponent<ZNetView>(); if (!((Object)(object)m_nview == (Object)null) && m_nview.IsValid()) { m_ready = true; Instances.Add(this); m_nview.Register<bool>("LC_SetPaused", (Action<long, bool>)RPC_SetPaused); m_nview.Register<float>("LC_SetRadius", (Action<long, float>)RPC_SetRadius); m_nview.Register<bool>("LC_SetReplant", (Action<long, bool>)RPC_SetReplant); m_nview.Register<string, bool>("LC_SetFamily", (Action<long, string, bool>)RPC_SetFamily); m_nview.Register("LC_AddWorker", (Action<long>)RPC_AddWorker); m_nview.Register("LC_RemoveWorker", (Action<long>)RPC_RemoveWorker); m_nview.Register<Vector3>("LC_AddChest", (Action<long, Vector3>)RPC_AddChest); m_nview.Register("LC_ClearChests", (Action<long>)RPC_ClearChests); m_nview.Register("LC_DepositNow", (Action<long>)RPC_DepositNow); m_nview.Register<string>("LC_Message", (Action<long, string>)RPC_Message); m_wear = ((Component)this).GetComponent<WearNTear>(); if ((Object)(object)m_wear != (Object)null) { WearNTear wear = m_wear; wear.m_onDestroyed = (Action)Delegate.Combine(wear.m_onDestroyed, new Action(OnPieceDestroyed)); } } } private void Start() { if (IsValid && m_nview.IsOwner()) { EnsureKey(); if (!Zdo.GetBool("lc_spawned", false)) { Zdo.Set("lc_spawned", true); Zdo.Set("lc_radius", LumberCampConfig.DefaultWorkRadius.Value); Zdo.Set("lc_replant", LumberCampConfig.DefaultReplant.Value); SpawnWorker(); } } } private void Update() { if (m_ready && m_nview.IsValid() && m_nview.IsOwner()) { if (Key == 0L) { EnsureKey(); } if (Time.time >= m_nextSweep) { m_nextSweep = Time.time + 3f; SweepStrayGear(); } } } private void SweepStrayGear() { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNetScene.instance == (Object)null) { return; } float num = LumberCampConfig.ChestAssignRange.Value + 40f; List<ItemDrop> list = null; foreach (ItemDrop s_instance in ItemDrop.s_instances) { if (!((Object)(object)s_instance == (Object)null) && !((Object)(object)s_instance.m_nview == (Object)null) && s_instance.m_nview.IsValid() && ((Object)((Component)s_instance).gameObject).name.StartsWith("Dverger", StringComparison.Ordinal) && IsCreatureGear(s_instance.m_itemData) && !(Utils.DistanceXZ(((Component)s_instance).transform.position, ((Component)this).transform.position) > num)) { (list ?? (list = new List<ItemDrop>())).Add(s_instance); } } if (list == null) { return; } foreach (ItemDrop item in list) { if (!item.m_nview.IsOwner()) { item.m_nview.ClaimOwnership(); } ZNetScene.instance.Destroy(((Component)item).gameObject); } LumberCampPlugin.Log.LogInfo((object)($"Cleared {list.Count} stray piece(s) of Dvergr gear near a lumber camp " + $"(first at {((Component)list[0]).transform.position}).")); } public static bool IsCreatureGear(ItemData item) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Invalid comparison between Unknown and I4 if (item?.m_shared != null && (int)item.m_shared.m_itemType != 1) { if (item.m_shared.m_icons != null) { return item.m_shared.m_icons.Length == 0; } return true; } return false; } public static int RemoveCreatureGear(Container chest) { Inventory val = (((Object)(object)chest != (Object)null) ? chest.GetInventory() : null); if (val == null || (Object)(object)chest.m_nview == (Object)null || !chest.m_nview.IsValid()) { return 0; } List<ItemData> list = null; foreach (ItemData allItem in val.GetAllItems()) { if (IsCreatureGear(allItem)) { (list ?? (list = new List<ItemData>())).Add(allItem); } } if (list == null) { return 0; } if (!chest.m_nview.IsOwner()) { chest.m_nview.ClaimOwnership(); } foreach (ItemData item in list) { val.RemoveItem(item); } LumberCampPlugin.Log.LogInfo((object)$"Removed {list.Count} piece(s) of creature gear from a chest a lumberjack had used."); return list.Count; } private void EnsureKey() { if (Key == 0L) { long num; do { num = ((long)Random.Range(int.MinValue, int.MaxValue) << 32) ^ (uint)Random.Range(int.MinValue, int.MaxValue) ^ DateTime.UtcNow.Ticks; } while (num == 0L); Zdo.Set("lc_key", num); } } private void OnDestroy() { Instances.Remove(this); if ((Object)(object)CampPanel.Current == (Object)(object)this) { CampPanel.Hide(); } } public static float ClampRadius(float r) { return Mathf.Clamp(r, 10f, LumberCampConfig.MaxWorkRadius.Value); } public bool IsFamilyEnabled(string family) { if (IsFamilyChecked(family)) { return LumberCampConfig.BossDefeated(family ?? "Other"); } return false; } public bool IsFamilyChecked(string family) { return !DisabledFamilies().Contains(family ?? "Other"); } private HashSet<string> DisabledFamilies() { string text = (IsValid ? Zdo.GetString("lc_disabled", string.Empty) : string.Empty); if (text != m_disabledRaw) { m_disabledRaw = text; m_disabled.Clear(); string[] array = text.Split(new char[1] { ',' }); foreach (string text2 in array) { if (text2.Trim().Length > 0) { m_disabled.Add(text2.Trim()); } } } return m_disabled; } public List<LumberWorker> Workers() { return LumberWorker.ForCamp(Key); } public List<Vector3> ChestPositions() { //IL_00cb: Unknown result type (might be due to invalid IL or missing references) List<Vector3> list = new List<Vector3>(); string[] array = (IsValid ? Zdo.GetString("lc_chests", string.Empty) : string.Empty).Split(new char[1] { ';' }); foreach (string text in array) { string text2 = text; int num = text.IndexOf('@'); if (num >= 0) { text2 = text.Substring(num + 1); } string[] array2 = text2.Split(new char[1] { ',' }); if (array2.Length == 3 && float.TryParse(array2[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array2[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array2[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3)) { list.Add(new Vector3(result, result2, result3)); } } return list; } private static string EncodeChests(List<Vector3> positions) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); foreach (Vector3 position in positions) { if (stringBuilder.Length > 0) { stringBuilder.Append(';'); } float x = position.x; stringBuilder.Append(x.ToString("F2", CultureInfo.InvariantCulture)).Append(','); x = position.y; stringBuilder.Append(x.ToString("F2", CultureInfo.InvariantCulture)).Append(','); x = position.z; stringBuilder.Append(x.ToString("F2", CultureInfo.InvariantCulture)); } return stringBuilder.ToString(); } private static bool SamePlace(Vector3 a, Vector3 b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) return Vector3.Distance(a, b) <= 0.6f; } private Container ContainerAt(Vector3 pos) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) for (int num = m_chestCache.Count - 1; num >= 0; num--) { KeyValuePair<Vector3, Container> keyValuePair = m_chestCache[num]; if (!(keyValuePair.Key != pos)) { Container value = keyValuePair.Value; if ((Object)(object)value != (Object)null && (Object)(object)value.m_nview != (Object)null && value.m_nview.IsValid() && SamePlace(((Component)value).transform.position, pos)) { return value; } m_chestCache.RemoveAt(num); } } if (m_chestNextLookup.TryGetValue(pos, out var value2) && Time.time < value2) { return null; } m_chestNextLookup[pos] = Time.time + 1f; foreach (Container item in WorldQuery.FindContainers(pos, 1.6f)) { if (SamePlace(((Component)item).transform.position, pos)) { m_chestCache.Add(new KeyValuePair<Vector3, Container>(pos, item)); return item; } } return null; } public List<Container> Containers() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) List<Container> list = new List<Container>(); List<Vector3> list2 = ChestPositions(); bool flag = false; bool flag2 = IsValid && m_nview.IsOwner(); for (int num = list2.Count - 1; num >= 0; num--) { Vector3 val = list2[num]; Container val2 = ContainerAt(val); if ((Object)(object)val2 != (Object)null) { list.Add(val2); m_chestMissingSince.Remove(val); if (flag2 && m_chestsChecked.Add(((Object)val2).GetInstanceID())) { RemoveCreatureGear(val2); } } else if (flag2) { float value; if (!((Object)(object)ZNetScene.instance != (Object)null) || ZNetScene.instance.OutsideActiveArea(val)) { m_chestMissingSince.Remove(val); } else if (!m_chestMissingSince.TryGetValue(val, out value)) { m_chestMissingSince[val] = Time.time; } else if (Time.time - value >= 30f) { m_chestMissingSince.Remove(val); list2.RemoveAt(num); flag = true; } } } if (flag) { Zdo.Set("lc_chests", EncodeChests(list2)); } return list; } public int ChestFreeSlots() { int num = 0; foreach (Container item in Containers()) { Inventory inventory = item.GetInventory(); if (inventory != null) { num += inventory.GetEmptySlots(); } } return num; } public Container FindChestFor(List<ItemData> items, Vector3 from, Func<int, bool> blacklisted) { //IL_008f: 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) Container result = null; float num = float.MaxValue; foreach (Container item in Containers()) { if (WorldQuery.ChestInUse(item) || (blacklisted != null && blacklisted(((Object)item).GetInstanceID()))) { continue; } Inventory inventory = item.GetInventory(); bool flag = false; foreach (ItemData item2 in items) { if (inventory.CanAddItem(item2, item2.m_stack)) { flag = true; break; } } if (flag) { float num2 = Vector3.Distance(from, ((Component)item).transform.position); if (num2 < num) { num = num2; result = item; } } } return result; } private bool IsAssigned(Vector3 pos) { //IL_0010: 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) foreach (Vector3 item in ChestPositions()) { if (SamePlace(item, pos)) { return true; } } return false; } private Container FindNearestUnassignedChest() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) foreach (Container item in WorldQuery.FindContainers(((Component)this).transform.position, LumberCampConfig.ChestAssignRange.Value)) { if (!IsAssigned(((Component)item).transform.position)) { return item; } } return null; } private void Send(string rpc, params object[] args) { if (IsValid) { if (!m_nview.HasOwner()) { m_nview.ClaimOwnership(); } m_nview.InvokeRPC(rpc, args); } } public void RequestSetPaused(bool paused) { Send("LC_SetPaused", paused); } public void RequestSetRadius(float radius) { Send("LC_SetRadius", ClampRadius(radius)); } public void RequestSetReplant(bool replant) { Send("LC_SetReplant", replant); } public void RequestSetFamily(string family, bool enabled) { Send("LC_SetFamily", family, enabled); } public void RequestAddWorker() { Send("LC_AddWorker"); } public void RequestRemoveWorker() { Send("LC_RemoveWorker"); } public void RequestClearChests() { Send("LC_ClearChests"); } public void RequestDepositNow() { Send("LC_DepositNow"); } public void RequestAddChest() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) Container val = FindNearestUnassignedChest(); if ((Object)(object)val == (Object)null) { Notify($"No unassigned chest within {LumberCampConfig.ChestAssignRange.Value:0} m of the camp"); return; } Send("LC_AddChest", ((Component)val).transform.position); } private void RPC_SetPaused(long sender, bool paused) { if (Owner) { Zdo.Set("lc_paused", paused); Tell(sender, paused ? "Camp paused" : "Camp back at work"); } } private void RPC_SetRadius(long sender, float radius) { if (Owner) { radius = ClampRadius(radius); Zdo.Set("lc_radius", radius); Tell(sender, $"Work radius set to {radius:0} m"); } } private void RPC_SetReplant(long sender, bool replant) { if (Owner) { Zdo.Set("lc_replant", replant); Tell(sender, replant ? "Lumberjacks will replant saplings" : "Lumberjacks will leave stumps bare"); } } private void RPC_SetFamily(long sender, string family, bool enabled) { if (Owner && !string.IsNullOrEmpty(family)) { HashSet<string> hashSet = new HashSet<string>(DisabledFamilies(), StringComparer.OrdinalIgnoreCase); if (enabled) { hashSet.Remove(family); } else { hashSet.Add(family); } Zdo.Set("lc_disabled", string.Join(",", hashSet)); } } private void RPC_AddWorker(long sender) { if (Owner) { int workerCount = WorkerCount; int value = LumberCampConfig.MaxWorkersPerCamp.Value; if (workerCount >= value) { Tell(sender, (value == 1) ? "This camp employs one lumberjack" : $"This camp employs at most {value} lumberjacks"); } else if (LumberWorker.CountAll() >= LumberCampConfig.MaxWorkersTotal.Value) { Tell(sender, "Every lumberjack in the world is already hired"); } else { Tell(sender, SpawnWorker() ? $"Lumberjack hired ({workerCount + 1} at this camp)" : "Could not hire a lumberjack; see the log"); } } } private void RPC_RemoveWorker(long sender) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) if (!Owner) { return; } List<LumberWorker> list = Workers(); if (list.Count == 0) { Tell(sender, "No lumberjack to send home"); return; } LumberWorker lumberWorker = list[0]; float num = -1f; foreach (LumberWorker item in list) { float num2 = Vector3.Distance(((Component)item).transform.position, ((Component)this).transform.position); if (num2 > num) { num = num2; lumberWorker = item; } } lumberWorker.Dismiss(); Tell(sender, $"Lumberjack sent home ({list.Count - 1} left). It dropped what it carried."); } private void RPC_AddChest(long sender, Vector3 pos) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) if (!Owner) { return; } Container val = null; foreach (Container item in WorldQuery.FindContainers(pos, 1.6f)) { if (SamePlace(((Component)item).transform.position, pos)) { val = item; break; } } if ((Object)(object)val == (Object)null) { Tell(sender, "That chest cannot be assigned"); return; } if (Vector3.Distance(((Component)val).transform.position, ((Component)this).transform.position) > LumberCampConfig.ChestAssignRange.Value + 1f) { Tell(sender, "That chest is too far from the camp"); return; } if (IsAssigned(((Component)val).transform.position)) { Tell(sender, "That chest is already assigned"); return; } List<Vector3> list = ChestPositions(); list.Add(((Component)val).transform.position); Zdo.Set("lc_chests", EncodeChests(list)); Tell(sender, $"Chest assigned ({list.Count} in use)"); } private void RPC_ClearChests(long sender) { if (Owner) { Zdo.Set("lc_chests", string.Empty); Tell(sender, "Chest assignments cleared; nothing was taken out of them"); } } private void RPC_DepositNow(long sender) { if (Owner) { Zdo.Set("lc_deposit", DepositRequest + 1); Tell(sender, "Lumberjacks will store what they carry"); } } private void RPC_Message(long sender, string message) { Notify(message); } private void Tell(long peer, string message) { if (ZRoutedRpc.instance == null || peer == ZRoutedRpc.instance.m_id) { Notify(message); return; } m_nview.InvokeRPC(peer, "LC_Message", new object[1] { message }); } private static void Notify(string message) { if ((Object)(object)Player.m_localPlayer != (Object)null && !string.IsNullOrEmpty(message)) { ((Character)Player.m_localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false); } } private bool SpawnWorker() { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab("lumbercamp_worker") : null); if ((Object)(object)val == (Object)null) { LumberCampPlugin.Log.LogError((object)"The lumberjack prefab is not registered; nothing can be hired."); return false; } int workerCount = WorkerCount; float num = ((workerCount % 2 == 0) ? 1f : (-1f)) * (float)((workerCount + 1) / 2) * 1.2f; Vector3 p = ((Component)this).transform.position + ((Component)this).transform.forward * 1.6f + ((Component)this).transform.right * num; p = WorldQuery.SnapToGround(p) + Vector3.up * 0.1f; GameObject val2 = Object.Instantiate<GameObject>(val, p, ((Component)this).transform.rotation); LumberWorker component = val2.GetComponent<LumberWorker>(); if ((Object)(object)component == (Object)null) { LumberCampPlugin.Log.LogError((object)"Spawned lumberjack has no LumberWorker component."); ZNetScene.instance.Destroy(val2); return false; } component.BindCamp(this); return true; } private void OnPieceDestroyed() { foreach (LumberWorker item in Workers()) { item.Dismiss(); } } public float GetHoverOffset() { return m_hoverOffset; } public string GetHoverName() { return Localization.instance.Localize("$piece_lumbercamp"); } public string GetHoverText() { if (!IsValid) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("$piece_lumbercamp\n"); stringBuilder.Append(Paused ? "Paused" : "Working"); stringBuilder.Append($" · Lumberjacks: {WorkerCount} · Chests: {ChestCount} · Radius: {Radius:0} m"); stringBuilder.Append("\n[<color=yellow><b>$KEY_Use</b></color>] Open camp"); return Localization.instance.Localize(stringBuilder.ToString()); } public bool Interact(Humanoid user, bool hold, bool alt) { if (hold || !IsValid) { return false; } CampPanel.Show(this); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public string StatusSummary() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(Paused ? "Paused." : "Working."); stringBuilder.Append(string.Format(" Radius {0:0} m. Replanting {1}.\n", Radius, Replant ? "on" : "off")); List<LumberWorker> list = Workers(); stringBuilder.Append($"Lumberjacks: {list.Count} of {LumberCampConfig.MaxWorkersPerCamp.Value}"); foreach (LumberWorker item in list) { string status = item.Status; stringBuilder.Append("\n • "); stringBuilder.Append(string.IsNullOrEmpty(status) ? "Idle" : status); int num = item.CarriedStacks(); if (num > 0) { stringBuilder.Append(string.Format(" (carrying {0} stack{1})", num, (num == 1) ? "" : "s")); } } int chestCount = ChestCount; stringBuilder.Append($"\nChests: {chestCount} assigned"); if (chestCount > 0) { stringBuilder.Append($", {ChestFreeSlots()} empty slots"); } return stringBuilder.ToString(); } } internal static class LumberCampConfig { public static readonly string[] BossKeys = new string[9] { "--", "defeated_eikthyr", "defeated_gdking", "defeated_bonemass", "defeated_dragon", "defeated_goblinking", "defeated_queen", "defeated_frozenking", "defeated_fader" }; public static ConfigEntry<bool> AdminOnlyPlacement; public static ConfigEntry<int> MaxWorkersPerCamp; public static ConfigEntry<int> MaxWorkersTotal; public static ConfigEntry<float> DefaultWorkRadius; public static ConfigEntry<float> MaxWorkRadius; public static ConfigEntry<float> CleanupOvershootPercent; public static ConfigEntry<float> ChestAssignRange; public static ConfigEntry<int> BagSlots; public static ConfigEntry<bool> DefaultReplant; public static ConfigEntry<bool> FreeReplant; public static ConfigEntry<bool> PickupOnlyTreeDrops; public static ConfigEntry<float> ChopDamage; public static ConfigEntry<int> ToolTier; public static ConfigEntry<float> ThinkInterval; public static ConfigEntry<string> BuildCost; public static ConfigEntry<string> CraftingStation; public static ConfigEntry<bool> BossGating; public static ConfigEntry<bool> MapMarkers; public static ConfigEntry<bool> DebugLogging; private static readonly Dictionary<string, ConfigEntry<string>> s_familyBoss = new Dictionary<string, ConfigEntry<string>>(StringComparer.OrdinalIgnoreCase); public static void Bind(ConfigFile config) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Expected O, but got Unknown //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Expected O, but got Unknown //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Expected O, but got Unknown //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Expected O, but got Unknown //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Expected O, but got Unknown //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Expected O, but got Unknown //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Expected O, but got Unknown //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Expected O, but got Unknown //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Expected O, but got Unknown //IL_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Expected O, but got Unknown //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Expected O, but got Unknown //IL_033c: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Expected O, but got Unknown //IL_036f: Unknown result type (might be due to invalid IL or missing references) //IL_0379: Expected O, but got Unknown //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Expected O, but got Unknown //IL_0428: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Expected O, but got Unknown AdminOnlyPlacement = config.Bind<bool>("General", "AdminOnlyPlacement", false, new ConfigDescription("Only server admins may build or remove a Lumber Camp. It is the only thing admin rights cover: a camp that exists is run by whoever walks up to it, so anyone can hire, pause, set the radius, pick the trees and move the chests about.", (AcceptableValueBase)null, new object[1] { Admin() })); MaxWorkersPerCamp = config.Bind<int>("General", "MaxWorkersPerCamp", 2, new ConfigDescription("How many lumberjacks one camp can employ.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 8), new object[1] { Admin() })); MaxWorkersTotal = config.Bind<int>("General", "MaxWorkersTotal", 8, new ConfigDescription("Hard cap on lumberjacks across the whole world. Counts the ones currently loaded, which is all of them for a single player.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 64), new object[1] { Admin() })); DefaultWorkRadius = config.Bind<float>("Work", "DefaultWorkRadius", 40f, new ConfigDescription("Work radius in metres a new camp starts with. Each camp can change its own radius from the panel.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 100f), new object[1] { Admin() })); MaxWorkRadius = config.Bind<float>("Work", "MaxWorkRadius", 100f, new ConfigDescription("The largest work radius a camp's panel will allow.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 100f), new object[1] { Admin() })); CleanupOvershootPercent = config.Bind<float>("Work", "CleanupOvershootPercent", 25f, new ConfigDescription("How far past the work radius, as a percentage of it, a lumberjack will still finish a felled log or clear a stump. A tree on the edge falls outward, so its log lands outside; without this the mess is left there forever. Standing trees are never taken from outside the radius, whatever this is set to.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), new object[1] { Admin() })); ChestAssignRange = config.Bind<float>("Work", "ChestAssignRange", 20f, new ConfigDescription("How far from the camp a chest may be for 'Add nearest chest' to pick it up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 64f), new object[1] { Admin() })); BagSlots = config.Bind<int>("Work", "BagSlots", 6, new ConfigDescription("How many stacks a lumberjack carries before walking them to a chest. A stack of wood is 50. Cargo only: his axe, his suit and the seed stack he keeps back for replanting are none of them.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 30), new object[1] { Admin() })); DefaultReplant = config.Bind<bool>("Work", "DefaultReplant", true, new ConfigDescription("Whether a new camp replants saplings after clearing a stump. Unless FreeReplant is on, it needs the matching seed or cone in the lumberjack's bag. Each camp can toggle this.", (AcceptableValueBase)null, new object[1] { Admin() })); FreeReplant = config.Bind<bool>("Work", "FreeReplant", true, new ConfigDescription("Replant without spending anything: a cleared stump gets its sapling whether or not the lumberjack carries the seed, and seeds are stored with the rest of the wood instead of kept in the bag. Off makes each sapling cost its seed or cone, as it would a player.", (AcceptableValueBase)null, new object[1] { Admin() })); PickupOnlyTreeDrops = config.Bind<bool>("Work", "PickupOnlyTreeDrops", true, new ConfigDescription("Lumberjacks pick up only what trees, logs and stumps drop: wood, resin, feathers, seeds and cones. Off makes them gather any loose item inside the work radius, including things you dropped.", (AcceptableValueBase)null, new object[1] { Admin() })); ChopDamage = config.Bind<float>("Worker", "ChopDamage", 60f, new ConfigDescription("Chop damage per swing of the lumberjack's axe. A beech has 80 health, an oak 200, a fir 60. The axe does nothing but chop.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 1000f), new object[1] { Admin() })); ToolTier = config.Bind<int>("Worker", "ToolTier", 4, new ConfigDescription("Tool tier of the lumberjack's axe. 0 is a stone axe, 2 bronze, 3 iron and can fell oaks, 4 blackmetal and beyond.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 6), new object[1] { Admin() })); ThinkInterval = config.Bind<float>("Worker", "ThinkInterval", 0.5f, new ConfigDescription("Seconds between a lumberjack's decisions. Lower is snappier and costs a little more CPU per lumberjack.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), new object[1] { Admin() })); BuildCost = config.Bind<string>("Cost", "BuildCost", "Wood:20,Stone:10,Resin:5", new ConfigDescription("What the camp costs to build: item prefab and amount, comma separated.", (AcceptableValueBase)null, new object[1] { Admin() })); CraftingStation = config.Bind<string>("Cost", "CraftingStation", "piece_workbench", new ConfigDescription("Crafting station that must be nearby to build a camp, by prefab name. Empty means none.", (AcceptableValueBase)null, new object[1] { Admin() })); BossGating = config.Bind<bool>("Progression", "BossGating", true, new ConfigDescription("Gate each kind of tree behind a boss. Until the boss that opens the tree's biome is dead, that tree cannot be ticked in a camp's panel and lumberjacks leave it standing. Out of the box a camp is always one biome ahead of the boss you last killed, because that is as far as you can walk to fetch a cone anyway. Off lets a camp cut everything from the day it is built.", (AcceptableValueBase)null, new object[1] { Admin() })); string[] all = TreeFamilies.All; foreach (string text in all) { s_familyBoss[text] = config.Bind<string>("Progression", text + "Boss", TreeFamilies.DefaultBoss(text), new ConfigDescription("Key of the boss that must be defeated before a camp will cut " + TreeFamilies.DisplayName(text) + ". '--' means no boss is required. The vanilla keys, the same ones Portal Progression uses, are " + string.Join(", ", VanillaBossKeys()) + "; a key another mod sets works too. Only read while BossGating is on.", (AcceptableValueBase)null, new object[1] { Admin() })); } WarnAboutUnknownBossKeys(); MapMarkers = config.Bind<bool>("Map", "MapMarkers", true, "Show every lumberjack on the minimap and the map as a blue arrow pointing the way he faces. Your own setting; a server does not change it."); DebugLogging = config.Bind<bool>("Debug", "DebugLogging", false, "Log every decision a lumberjack makes. Noisy; for bug reports."); } private static string[] VanillaBossKeys() { List<string> list = new List<string>(); string[] bossKeys = BossKeys; foreach (string text in bossKeys) { if (text != "--") { list.Add(text); } } return list.ToArray(); } private static void WarnAboutUnknownBossKeys() { HashSet<string> hashSet = new HashSet<string>(BossKeys, StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair<string, ConfigEntry<string>> item in s_familyBoss) { string text = item.Value?.Value?.Trim(); if (!string.IsNullOrEmpty(text) && !hashSet.Contains(text)) { LumberCampPlugin.Log.LogWarning((object)(item.Key + "Boss is set to '" + text + "', which is not one of the game's own boss keys. If no other mod sets that key, this kind of tree stays locked.")); } } } private static ConfigurationManagerAttributes Admin() { return new ConfigurationManagerAttributes { IsAdminOnly = true }; } public static bool LocalPlayerIsAdmin() { try { return SynchronizationManager.Instance != null && SynchronizationManager.Instance.PlayerIsAdmin; } catch { return false; } } public static bool CanPlaceCamp() { if (AdminOnlyPlacement.Value) { return LocalPlayerIsAdmin(); } return true; } public static string BossFor(string family) { if (family != null && s_familyBoss.TryGetValue(family, out var value)) { string text = value?.Value?.Trim(); if (!string.IsNullOrEmpty(text)) { return text; } } return "--"; } public static bool BossDefeated(string family) { if (BossGating == null || !BossGating.Value) { return true; } string text = BossFor(family); if (text == "--") { return true; } if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey(text)) { return true; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null) { return ((Humanoid)localPlayer).HaveUniqueKey(text); } return false; } public static string BossName(string key) { return key switch { "defeated_eikthyr" => "Eikthyr", "defeated_gdking" => "The Elder", "defeated_bonemass" => "Bonemass", "defeated_dragon" => "Moder", "defeated_goblinking" => "Yagluth", "defeated_queen" => "The Queen", "defeated_frozenking" => "the Deep North boss", "defeated_fader" => "Fader", _ => key, }; } public static RequirementConfig[] ParseCost(string cost) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown List<RequirementConfig> list = new List<RequirementConfig>(); if (string.IsNullOrEmpty(cost)) { return list.ToArray(); } string[] array = cost.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length != 0) { string[] array2 = text.Split(new char[1] { ':' }); if (array2.Length != 2 || !int.TryParse(array2[1].Trim(), out var result) || result <= 0) { LumberCampPlugin.Log.LogWarning((object)("BuildCost entry '" + text + "' is not item:amount;