using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("AutomationByGoblins")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("AutomationByGoblins")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("78b94844-bf74-4318-b728-1f83ab5873b3")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace AutomationByGoblins; [BepInPlugin("mintmango.automationbygoblins", "AutomationByGoblins", "0.7.0")] public sealed class AutomationByGoblinsPlugin : BaseUnityPlugin { public const string ModGuid = "mintmango.automationbygoblins"; public const string ModName = "AutomationByGoblins"; public const string ModVersion = "0.7.0"; internal static ManualLogSource ModLog; internal static ConfigEntry WoodWorkerChance; internal static ConfigEntry StoneWorkerChance; internal static ConfigEntry GathererWorkerChance; internal static ConfigEntry TamingTimeSeconds; private Harmony _harmony; private void Awake() { //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown ModLog = ((BaseUnityPlugin)this).Logger; WoodWorkerChance = ((BaseUnityPlugin)this).Config.Bind("Spawning", "WoodWorkerChance", 10f, "Chance in percent for a normal melee Goblin to become the beige intelligent wood-worker type."); StoneWorkerChance = ((BaseUnityPlugin)this).Config.Bind("Spawning", "StoneWorkerChance", 10f, "Chance in percent for a normal melee Goblin to become the gray intelligent stone-worker type."); GathererWorkerChance = ((BaseUnityPlugin)this).Config.Bind("Spawning", "GathererWorkerChance", 10f, "Chance in percent for a normal melee Goblin to become the green intelligent gatherer type."); TamingTimeSeconds = ((BaseUnityPlugin)this).Config.Bind("Taming", "TamingTimeSeconds", 3600f, "Taming time in seconds. 3600 seconds is twice the normal 30 minute taming time."); _harmony = new Harmony("mintmango.automationbygoblins"); _harmony.PatchAll(); ModLog.LogInfo((object)"AutomationByGoblins 0.7.0 loaded."); } private void OnDestroy() { if (_harmony != null) { _harmony.UnpatchSelf(); } } } internal enum GoblinWorkerType { Unassigned, Wood, Stone, Normal, Gatherer } public sealed class GoblinWorkerController : MonoBehaviour { private const string WorkerTypeZdoKey = "AutomationByGoblins.WorkerType"; private const string TamingFoodPrefab = "PungentPebbles"; private static readonly Color WoodClothingColor = new Color(0.96f, 0.78f, 0.48f, 1f); private static readonly Color StoneClothingColor = new Color(0.32f, 0.36f, 0.43f, 1f); private static readonly Color GathererClothingColor = new Color(0.4f, 0.68f, 0.3f, 1f); private readonly HashSet _alreadyTinted = new HashSet(); private ZNetView _nview; private Character _character; private GoblinWorkerType _workerType = GoblinWorkerType.Unassigned; internal bool IsIntelligent => _workerType == GoblinWorkerType.Wood || _workerType == GoblinWorkerType.Stone || _workerType == GoblinWorkerType.Gatherer; internal GoblinWorkerType WorkerType => _workerType; private void Start() { _character = ((Component)this).GetComponent(); _nview = ((Component)this).GetComponent(); ((MonoBehaviour)this).StartCoroutine(InitializeWhenNetworkReady()); } private IEnumerator InitializeWhenNetworkReady() { while ((Object)(object)_nview == (Object)null || _nview.GetZDO() == null) { if ((Object)(object)_nview == (Object)null) { _nview = ((Component)this).GetComponent(); } yield return null; } while (_workerType == GoblinWorkerType.Unassigned) { int storedType = _nview.GetZDO().GetInt("AutomationByGoblins.WorkerType", 0); if (storedType >= 1 && storedType <= 4) { _workerType = (GoblinWorkerType)storedType; break; } if (_nview.IsOwner()) { _workerType = RollWorkerType(); _nview.GetZDO().Set("AutomationByGoblins.WorkerType", (int)_workerType); break; } yield return (object)new WaitForSeconds(0.25f); } if (IsIntelligent) { ConfigureTaming(); AutomationByGoblinsPlugin.ModLog.LogDebug((object)("Configured intelligent " + _workerType.ToString() + " Goblin.")); while ((Object)(object)this != (Object)null && (Object)(object)((Component)this).gameObject != (Object)null) { ApplyWorkerClothingColor(); yield return (object)new WaitForSeconds(2f); } } } private GoblinWorkerType RollWorkerType() { float num = Mathf.Clamp(AutomationByGoblinsPlugin.WoodWorkerChance.Value, 0f, 100f); float num2 = Mathf.Clamp(AutomationByGoblinsPlugin.StoneWorkerChance.Value, 0f, 100f); float num3 = Mathf.Clamp(AutomationByGoblinsPlugin.GathererWorkerChance.Value, 0f, 100f); float num4 = num + num2 + num3; if (num4 > 100f) { float num5 = 100f / num4; num *= num5; num2 *= num5; num3 *= num5; } float num6 = Random.Range(0f, 100f); if (num6 < num) { return GoblinWorkerType.Wood; } if (num6 < num + num2) { return GoblinWorkerType.Stone; } if (num6 < num + num2 + num3) { return GoblinWorkerType.Gatherer; } return GoblinWorkerType.Normal; } private void ConfigureTaming() { Tameable val = ((Component)this).GetComponent(); if ((Object)(object)val == (Object)null) { val = ((Component)this).gameObject.AddComponent(); } MonsterAI component = ((Component)this).GetComponent(); if ((Object)(object)component == (Object)null) { AutomationByGoblinsPlugin.ModLog.LogWarning((object)"Intelligent Goblin has no MonsterAI; taming cannot be configured."); return; } ApplyBoarTamingConfiguration(val, component); SetFieldIfPresent(val, "m_commandable", true); SetFieldIfPresent(component, "m_tamable", val); SetFieldIfPresent(component, "m_tameable", val); ((MonoBehaviour)this).StartCoroutine(ConfigureTamingFoodWhenReady(component)); } private void ApplyBoarTamingConfiguration(Tameable targetTameable, MonsterAI targetMonsterAI) { Tameable val = null; MonsterAI val2 = null; if ((Object)(object)ZNetScene.instance != (Object)null) { GameObject prefab = ZNetScene.instance.GetPrefab("Boar"); if ((Object)(object)prefab != (Object)null) { val = prefab.GetComponent(); val2 = prefab.GetComponent(); } } if ((Object)(object)val == (Object)null) { AutomationByGoblinsPlugin.ModLog.LogWarning((object)"Vanilla Boar Tameable was not found. Falling back to a 3600 second intelligent Goblin taming time."); SetFieldIfPresent(targetTameable, "m_tamingTime", Mathf.Max(1f, AutomationByGoblinsPlugin.TamingTimeSeconds.Value)); return; } CopyPublicTamingSettings(val, targetTameable); if (!TryGetFloatField(val, "m_tamingTime", out var value)) { value = 1800f; } float num = Mathf.Max(1f, value * 2f); SetFieldIfPresent(targetTameable, "m_tamingTime", num); if ((Object)(object)val2 != (Object)null) { CopyBoarConsumeSettings(val2, targetMonsterAI); } AutomationByGoblinsPlugin.ModLog.LogDebug((object)("Intelligent Goblin uses vanilla Boar taming configuration; duration = " + num + " seconds.")); } private static void CopyPublicTamingSettings(Tameable source, Tameable target) { FieldInfo[] fields = typeof(Tameable).GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { if (!fieldInfo.IsStatic && !fieldInfo.IsInitOnly && !(fieldInfo.Name == "m_tamingTime") && !(fieldInfo.Name == "m_commandable") && !fieldInfo.Name.StartsWith("m_command", StringComparison.OrdinalIgnoreCase) && !typeof(Component).IsAssignableFrom(fieldInfo.FieldType) && !typeof(GameObject).IsAssignableFrom(fieldInfo.FieldType) && !typeof(Delegate).IsAssignableFrom(fieldInfo.FieldType)) { try { fieldInfo.SetValue(target, fieldInfo.GetValue(source)); } catch (Exception ex) { AutomationByGoblinsPlugin.ModLog.LogDebug((object)("Skipped Boar Tameable field " + fieldInfo.Name + ": " + ex.Message)); } } } } private static void CopyBoarConsumeSettings(MonsterAI source, MonsterAI target) { FieldInfo[] fields = typeof(MonsterAI).GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { if (!fieldInfo.IsStatic && !fieldInfo.IsInitOnly && fieldInfo.Name.StartsWith("m_consume", StringComparison.OrdinalIgnoreCase) && !(fieldInfo.Name == "m_consumeItems")) { try { fieldInfo.SetValue(target, fieldInfo.GetValue(source)); } catch (Exception ex) { AutomationByGoblinsPlugin.ModLog.LogDebug((object)("Skipped Boar MonsterAI field " + fieldInfo.Name + ": " + ex.Message)); } } } } private static bool TryGetFloatField(object target, string fieldName, out float value) { value = 0f; if (target == null) { return false; } FieldInfo fieldInfo = AccessTools.Field(target.GetType(), fieldName); if (fieldInfo == null) { return false; } try { object value2 = fieldInfo.GetValue(target); if (value2 == null) { return false; } value = Convert.ToSingle(value2); return true; } catch { return false; } } private IEnumerator ConfigureTamingFoodWhenReady(MonsterAI monsterAI) { GameObject foodPrefab = null; while (true) { int num; if (!((Object)(object)ObjectDB.instance == (Object)null)) { GameObject itemPrefab; foodPrefab = (itemPrefab = ObjectDB.instance.GetItemPrefab("PungentPebbles")); num = (((Object)(object)itemPrefab == (Object)null) ? 1 : 0); } else { num = 1; } if (num == 0) { break; } yield return (object)new WaitForSeconds(1f); } ItemDrop itemDrop = foodPrefab.GetComponent(); if ((Object)(object)itemDrop == (Object)null) { AutomationByGoblinsPlugin.ModLog.LogWarning((object)"PungentPebbles exists but has no ItemDrop component."); yield break; } FieldInfo consumeItemsField = AccessTools.Field(((object)monsterAI).GetType(), "m_consumeItems"); if (consumeItemsField == null) { consumeItemsField = AccessTools.Field(typeof(MonsterAI), "m_consumeItems"); } if (consumeItemsField == null) { AutomationByGoblinsPlugin.ModLog.LogError((object)"MonsterAI.m_consumeItems was not found; cannot register PungentPebbles."); yield break; } IList consumeItems = consumeItemsField.GetValue(monsterAI) as IList; if (consumeItems == null) { try { consumeItems = Activator.CreateInstance(consumeItemsField.FieldType) as IList; consumeItemsField.SetValue(monsterAI, consumeItems); } catch (Exception ex) { Exception ex2 = ex; AutomationByGoblinsPlugin.ModLog.LogError((object)("Could not create Goblin consume-items list: " + ex2.Message)); yield break; } } if (consumeItems != null) { consumeItems.Clear(); consumeItems.Add(itemDrop); } AutomationByGoblinsPlugin.ModLog.LogDebug((object)"PungentPebbles registered as intelligent Goblin taming food."); } private void ApplyWorkerClothingColor() { //IL_0011: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) Color color = ((_workerType == GoblinWorkerType.Wood) ? WoodClothingColor : ((_workerType != GoblinWorkerType.Stone) ? GathererClothingColor : StoneClothingColor)); Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); List list = new List(); for (int i = 0; i < componentsInChildren.Length; i++) { if (string.Equals(((Object)componentsInChildren[i]).name, "attach_skin(Clone)", StringComparison.OrdinalIgnoreCase)) { list.Add(componentsInChildren[i]); } } if (list.Count < 2) { return; } int num = list.Count - 2; for (int j = num; j < list.Count; j++) { Renderer[] componentsInChildren2 = ((Component)list[j]).GetComponentsInChildren(true); for (int k = 0; k < componentsInChildren2.Length; k++) { TintRendererOnce(componentsInChildren2[k], color); } } } private void TintRendererOnce(Renderer renderer, Color color) { //IL_0060: 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) if ((Object)(object)renderer == (Object)null || _alreadyTinted.Contains(renderer)) { return; } _alreadyTinted.Add(renderer); Material[] materials = renderer.materials; foreach (Material val in materials) { if (!((Object)(object)val == (Object)null)) { if (val.HasProperty("_Color")) { val.color = color; } if (val.HasProperty("_BaseColor")) { val.SetColor("_BaseColor", color); } } } } private static void SetFieldIfPresent(object target, string fieldName, object value) { if (target == null) { return; } FieldInfo fieldInfo = AccessTools.Field(target.GetType(), fieldName); if (fieldInfo == null) { return; } try { fieldInfo.SetValue(target, value); } catch (Exception ex) { AutomationByGoblinsPlugin.ModLog.LogWarning((object)("Could not set " + target.GetType().Name + "." + fieldName + ": " + ex.Message)); } } } [HarmonyPatch(typeof(Character), "Awake")] internal static class CharacterAwakePatch { private static void Postfix(Character __instance) { if (!((Object)(object)__instance == (Object)null) && IsVanillaMeleeGoblin(((Component)__instance).gameObject) && (Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } } private static bool IsVanillaMeleeGoblin(GameObject gameObject) { if ((Object)(object)gameObject == (Object)null) { return false; } string text = ((Object)gameObject).name; if (text.EndsWith("(Clone)", StringComparison.Ordinal)) { text = text.Substring(0, text.Length - "(Clone)".Length); } return string.Equals(text, "Goblin", StringComparison.Ordinal); } } [HarmonyPatch(typeof(Tameable), "GetHoverText")] internal static class TameableGetHoverTextPatch { private static void Postfix(Tameable __instance, ref string __result) { if ((Object)(object)__instance == (Object)null) { return; } GoblinWorkerController component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsIntelligent) { return; } Character component2 = ((Component)__instance).GetComponent(); if ((Object)(object)component2 == (Object)null || string.IsNullOrEmpty(__result)) { return; } int num = __result.IndexOf('\n'); string text = ((num >= 0) ? __result.Substring(0, num) : __result); string text2 = ((num >= 0) ? __result.Substring(num) : string.Empty); int num2 = text.LastIndexOf(" (", StringComparison.Ordinal); string text3 = ((num2 >= 0) ? text.Substring(0, num2) : text); if (component2.IsTamed()) { __result = text3 + " (Разумный/Приручен)" + text2; return; } string text4 = string.Empty; if (num2 >= 0 && text.EndsWith(")", StringComparison.Ordinal)) { int num3 = num2 + 2; text4 = text.Substring(num3, text.Length - num3 - 1); } if (string.IsNullOrEmpty(text4)) { __result = text3 + " (Разумный/Можно задобрить)" + text2; return; } string text5 = text4; text5 = text5.Replace("Привязанность: ", "Задобрен на "); text5 = text5.Replace("Привязанность ", "Задобрен на "); text5 = text5.Replace("Дикий, Голоден", "Можно задобрить"); text5 = text5.Replace("Дикий", string.Empty).Trim(); text5 = text5.TrimStart(',', ' '); text5 = ((!string.IsNullOrEmpty(text5) && !(text5 == "Голоден")) ? text5.Replace("Голоден", "Можно задобрить") : "Можно задобрить"); __result = text3 + " (Разумный/" + text5 + ")" + text2; } } public sealed class GoblinWorkerJob : MonoBehaviour { private const float UpgradeWorkRequirement = 1800f; private const int StorageUpgradeCostAmount = 10; private const float TreeContentWidth = 760f; private const float TreeContentHeight = 690f; private const float TreeNodeWidth = 228f; private const float TreeNodeHeight = 116f; private const float TreeNodeStartY = 140f; private const float TreeNodeStepY = 140f; private const float LoadedAssignmentValidationDistance = 100f; private const string LevelZdoKey = "AutomationByGoblins.Job.Level"; private const string StoredZdoKey = "AutomationByGoblins.Job.Stored"; private const string WorkSecondsZdoKey = "AutomationByGoblins.Job.WorkSeconds"; private const string ProductionSecondsZdoKey = "AutomationByGoblins.Job.ProductionSeconds"; private const string YieldLevelZdoKey = "AutomationByGoblins.Job.YieldLevel"; private const string YieldWorkSecondsZdoKey = "AutomationByGoblins.Job.YieldWorkSeconds"; private const string StorageLevelZdoKey = "AutomationByGoblins.Job.StorageLevel"; private const string StorageWorkSecondsZdoKey = "AutomationByGoblins.Job.StorageWorkSeconds"; private const string OfflineEligibleZdoKey = "AutomationByGoblins.Job.OfflineEligible"; private const string OfflineSessionZdoKey = "AutomationByGoblins.Job.OfflineSession"; private const string OfflineDayClockZdoKey = "AutomationByGoblins.Job.OfflineDayClock"; private static readonly float[] ProductionIntervals = new float[5] { 900f, 720f, 600f, 420f, 300f }; private static readonly string[] UpgradeCostPrefabs = new string[4] { "Flint", "Bronze", "Iron", "Silver" }; private static readonly string[] UpgradeCostRussianNames = new string[4] { "Кремень", "Бронза", "Железо", "Серебро" }; private static readonly int[] ProductionAmounts = new int[5] { 1, 2, 3, 4, 5 }; private static readonly string[] YieldUpgradeCostPrefabs = new string[4] { "FineWood", "SerpentScale", "ElderBark", "DragonTear" }; private static readonly int[] YieldUpgradeCostAmounts = new int[4] { 10, 5, 20, 5 }; private static readonly string[] YieldUpgradeCostRussianNames = new string[4] { "Ценная древесина", "Змеиная чешуя", "Древняя кора", "Драконья слеза" }; private static readonly int[] StorageCapacities = new int[5] { 50, 75, 100, 125, 150 }; private static readonly string[] StorageUpgradeCostPrefabs = new string[4] { "DeerHide", "BjornHide", "Root", "WolfPelt" }; private static readonly string[] StorageUpgradeCostRussianNames = new string[4] { "Оленья шкура", "Шкура бьёрна", "Корень", "Волчья шкура" }; private GoblinWorkerController _controller; private GoblinWoodcutterWorkBehaviour _workBehaviour; private Character _character; private Tameable _tameable; private ZNetView _nview; private ZDO _workerZdo; private int _level; private int _yieldLevel; private int _storageLevel; private int _stored; private float _workSeconds; private float _yieldWorkSeconds; private float _storageWorkSeconds; private float _productionSeconds; private float _saveTimer; private float _remoteSyncTimer; private float _offlineCheckpointTimer; private float _lastUpdateRealtime; private bool _ready; private bool _wasActivelyWorking; private bool _offlineEligible; private bool _ownsWorkerState; private bool _wasTamed; private bool _knownDead; private float _offlineInvalidSeconds; private bool _upgradeWindowOpen; private bool _storageWindowOpen; private Player _windowPlayer; private string _uiMessage = string.Empty; private float _speedMaterialCountCheckedAt = -1000f; private string _speedMaterialCountPrefab = string.Empty; private int _speedMaterialCountCached; private float _yieldMaterialCountCheckedAt = -1000f; private string _yieldMaterialCountPrefab = string.Empty; private int _yieldMaterialCountCached; private float _storageMaterialCountCheckedAt = -1000f; private string _storageMaterialCountPrefab = string.Empty; private int _storageMaterialCountCached; private bool _cursorStateSaved; private bool _previousCursorVisible; private CursorLockMode _previousCursorLockMode; private Rect _upgradeWindowRect = new Rect(0f, 0f, 820f, 720f); private Rect _storageWindowRect = new Rect(0f, 0f, 300f, 260f); private Vector2 _upgradeScrollPosition = Vector2.zero; private GUIStyle _treeRootStyle; private GUIStyle _treeBranchStyle; private GUIStyle _treeNodeTitleStyle; private GUIStyle _treeNodeDetailStyle; internal static GoblinWorkerJob ActiveWindow; internal bool IsUsableWorker => _ready && (Object)(object)_controller != (Object)null && (_controller.WorkerType == GoblinWorkerType.Wood || _controller.WorkerType == GoblinWorkerType.Stone) && (Object)(object)_character != (Object)null && _character.IsTamed(); internal string ProfessionName { get { if ((Object)(object)_controller == (Object)null) { return "Неизвестно"; } return (_controller.WorkerType == GoblinWorkerType.Wood) ? "Лесоруб" : "Каменщик"; } } internal string ResourcePrefabName { get { if ((Object)(object)_controller == (Object)null) { return string.Empty; } return (_controller.WorkerType == GoblinWorkerType.Wood) ? "Wood" : "Stone"; } } internal string ResourceRussianName => (ResourcePrefabName == "Wood") ? "Древесина" : "Камень"; internal int StorageCapacity => StorageCapacities[Mathf.Clamp(_storageLevel, 0, StorageCapacities.Length - 1)]; private void Start() { _controller = ((Component)this).GetComponent(); _character = ((Component)this).GetComponent(); _tameable = ((Component)this).GetComponent(); _nview = ((Component)this).GetComponent(); ((MonoBehaviour)this).StartCoroutine(InitializeWhenReady()); } private IEnumerator InitializeWhenReady() { while ((Object)(object)_controller == (Object)null || _controller.WorkerType == GoblinWorkerType.Unassigned || (Object)(object)_nview == (Object)null || _nview.GetZDO() == null) { if ((Object)(object)_controller == (Object)null) { _controller = ((Component)this).GetComponent(); } if ((Object)(object)_character == (Object)null) { _character = ((Component)this).GetComponent(); } if ((Object)(object)_tameable == (Object)null) { _tameable = ((Component)this).GetComponent(); } if ((Object)(object)_nview == (Object)null) { _nview = ((Component)this).GetComponent(); } yield return null; } if (_controller.WorkerType != GoblinWorkerType.Wood && _controller.WorkerType != GoblinWorkerType.Stone) { ((Behaviour)this).enabled = false; yield break; } while ((Object)(object)_tameable == (Object)null) { _tameable = ((Component)this).GetComponent(); yield return null; } GoblinWorkerOfflineProductionManager.EnsureAttached(); _workerZdo = _nview.GetZDO(); _ownsWorkerState = _nview.IsOwner(); _wasTamed = (Object)(object)_character != (Object)null && _character.IsTamed(); _knownDead = (Object)(object)_character != (Object)null && _character.IsDead(); LoadStateFromZdo(); _workBehaviour = ((Component)this).GetComponent(); _ready = true; ApplyOfflineCatchUp(); _lastUpdateRealtime = Time.realtimeSinceStartup; if (_ownsWorkerState && _wasTamed && !_knownDead) { GoblinWorkerOfflineProduction.TrackLoaded(_workerZdo, this, _offlineEligible); } } private void Update() { if (!_ready || (Object)(object)_controller == (Object)null || !_controller.IsIntelligent || (Object)(object)_character == (Object)null) { return; } if ((_upgradeWindowOpen || _storageWindowOpen) && Input.GetKeyDown((KeyCode)27)) { CloseWindows(); } float realtimeSinceStartup = Time.realtimeSinceStartup; if (_lastUpdateRealtime > 0f && realtimeSinceStartup - _lastUpdateRealtime > 2f) { ApplyOfflineCatchUp(); } _lastUpdateRealtime = realtimeSinceStartup; _wasTamed = _character.IsTamed(); _knownDead = _character.IsDead(); if (!_wasTamed || _knownDead) { GoblinWorkerOfflineProduction.Remove(_workerZdo, this); } else { if ((Object)(object)_nview == (Object)null || _nview.GetZDO() == null) { return; } _workerZdo = _nview.GetZDO(); _ownsWorkerState = _nview.IsOwner(); if (!_ownsWorkerState) { GoblinWorkerOfflineProduction.Remove(_workerZdo, this); _remoteSyncTimer += Time.deltaTime; if (_remoteSyncTimer >= 1f) { _remoteSyncTimer = 0f; LoadStateFromZdo(); } return; } GoblinWorkerOfflineProduction.TrackLoaded(_workerZdo, this, _offlineEligible); _offlineCheckpointTimer += Time.deltaTime; if (_offlineCheckpointTimer >= 10f) { _offlineCheckpointTimer = 0f; SaveOfflineCheckpoint(); } if (!GoblinNightRestJob.IsNightRestActive(_character) && (!((Object)(object)EnvMan.instance != (Object)null) || !EnvMan.IsNight())) { RefreshOfflineEligibility(); if (_stored >= StorageCapacity) { return; } float deltaTime = Time.deltaTime; if ((Object)(object)_workBehaviour == (Object)null) { _workBehaviour = ((Component)this).GetComponent(); } if (!((Object)(object)_workBehaviour != (Object)null) || !_workBehaviour.IsPerformingActiveWork) { StopActiveWorkTracking(); return; } _wasActivelyWorking = true; _workSeconds += deltaTime; _yieldWorkSeconds += deltaTime; _storageWorkSeconds += deltaTime; _productionSeconds += deltaTime; float num = ProductionIntervals[Mathf.Clamp(_level, 0, ProductionIntervals.Length - 1)]; if (_productionSeconds >= num) { _productionSeconds -= num; int num2 = ProductionAmounts[Mathf.Clamp(_yieldLevel, 0, ProductionAmounts.Length - 1)]; _stored = Mathf.Min(StorageCapacity, _stored + num2); SaveStateToZdo(); } _saveTimer += deltaTime; if (_saveTimer >= 5f) { _saveTimer = 0f; SaveStateToZdo(); } } else { StopActiveWorkTracking(); } } } private void OnDestroy() { ZDO val = ResolveWorkerZdo(); if ((Object)(object)_character != (Object)null) { _wasTamed = _character.IsTamed(); _knownDead = _character.IsDead(); } if (_ready && val != null && _ownsWorkerState && _offlineEligible && _stored < StorageCapacity && _wasTamed && !_knownDead) { GoblinWorkerOfflineProduction.MarkUnloaded(val, this, eligible: true); } else { GoblinWorkerOfflineProduction.Remove(val, this); } if ((Object)(object)ActiveWindow == (Object)(object)this) { CloseWindows(); } } private void LoadStateFromZdo() { ZDO val = ResolveWorkerZdo(); if (val != null) { _level = Mathf.Clamp(val.GetInt("AutomationByGoblins.Job.Level", 0), 0, ProductionIntervals.Length - 1); _yieldLevel = Mathf.Clamp(val.GetInt("AutomationByGoblins.Job.YieldLevel", 0), 0, ProductionAmounts.Length - 1); _storageLevel = Mathf.Clamp(val.GetInt("AutomationByGoblins.Job.StorageLevel", 0), 0, StorageCapacities.Length - 1); _stored = Mathf.Clamp(val.GetInt("AutomationByGoblins.Job.Stored", 0), 0, StorageCapacity); _workSeconds = Mathf.Max(0f, val.GetFloat("AutomationByGoblins.Job.WorkSeconds", 0f)); _yieldWorkSeconds = Mathf.Max(0f, val.GetFloat("AutomationByGoblins.Job.YieldWorkSeconds", 0f)); _storageWorkSeconds = Mathf.Max(0f, val.GetFloat("AutomationByGoblins.Job.StorageWorkSeconds", 0f)); _productionSeconds = Mathf.Max(0f, val.GetFloat("AutomationByGoblins.Job.ProductionSeconds", 0f)); _offlineEligible = val.GetInt("AutomationByGoblins.Job.OfflineEligible", 0) != 0; } } private void SaveStateToZdo() { ZDO val = ResolveWorkerZdo(); if (val != null && _ownsWorkerState) { val.Set("AutomationByGoblins.Job.Level", _level); val.Set("AutomationByGoblins.Job.YieldLevel", _yieldLevel); val.Set("AutomationByGoblins.Job.StorageLevel", _storageLevel); val.Set("AutomationByGoblins.Job.Stored", _stored); val.Set("AutomationByGoblins.Job.WorkSeconds", _workSeconds); val.Set("AutomationByGoblins.Job.YieldWorkSeconds", _yieldWorkSeconds); val.Set("AutomationByGoblins.Job.StorageWorkSeconds", _storageWorkSeconds); val.Set("AutomationByGoblins.Job.ProductionSeconds", _productionSeconds); val.Set("AutomationByGoblins.Job.OfflineEligible", _offlineEligible ? 1 : 0); WriteOfflineCheckpoint(val); } } private void SaveOfflineCheckpoint() { ZDO val = ResolveWorkerZdo(); if (val != null && _ownsWorkerState) { WriteOfflineCheckpoint(val); } } internal static void WriteOfflineCheckpoint(ZDO zdo) { if (zdo != null && GoblinWorkerOfflineProduction.TryGetDayClock(out var sessionId, out var dayClock)) { zdo.Set("AutomationByGoblins.Job.OfflineSession", sessionId); zdo.Set("AutomationByGoblins.Job.OfflineDayClock", dayClock); } } private void ApplyOfflineCatchUp() { if (!_ready || !_ownsWorkerState || !_wasTamed || _knownDead) { return; } ZDO val = ResolveWorkerZdo(); if (val != null && GoblinWorkerOfflineProduction.TryGetDayClock(out var sessionId, out var dayClock)) { int num = val.GetInt("AutomationByGoblins.Job.OfflineSession", 0); float num2 = Mathf.Max(0f, val.GetFloat("AutomationByGoblins.Job.OfflineDayClock", dayClock)); float num3 = ((num == sessionId) ? Mathf.Max(0f, dayClock - num2) : 0f); if (_offlineEligible && num3 > 0.5f) { int num4 = AdvanceOfflineState(val, num3 * 0.8f); LoadStateFromZdo(); AutomationByGoblinsPlugin.ModLog.LogDebug((object)("Offline catch-up credited " + Mathf.RoundToInt(num3) + " daylight second(s); produced " + num4 + ".")); } val.Set("AutomationByGoblins.Job.OfflineSession", sessionId); val.Set("AutomationByGoblins.Job.OfflineDayClock", dayClock); _offlineCheckpointTimer = 0f; } } private ZDO ResolveWorkerZdo() { if ((Object)(object)_nview != (Object)null) { ZDO zDO = _nview.GetZDO(); if (zDO != null) { _workerZdo = zDO; _ownsWorkerState = _nview.IsOwner(); } } return _workerZdo; } private void RefreshOfflineEligibility() { //IL_0070: 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_0085: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_workBehaviour == (Object)null) { _workBehaviour = ((Component)this).GetComponent(); } bool flag = (Object)(object)_workBehaviour != (Object)null && _workBehaviour.HasOfflineWorkAssignment; if (flag) { _offlineInvalidSeconds = 0f; } else { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } Vector3 val = ((Component)localPlayer).transform.position - ((Component)this).transform.position; if (((Vector3)(ref val)).sqrMagnitude > 10000f) { return; } _offlineInvalidSeconds += Time.deltaTime; if (_offlineInvalidSeconds < 5f) { return; } } if (_offlineEligible != flag) { _offlineEligible = flag; _saveTimer = 0f; SaveStateToZdo(); AutomationByGoblinsPlugin.ModLog.LogDebug((object)("Worker offline assignment: " + (_offlineEligible ? "ready" : "not ready") + ".")); GoblinWorkerOfflineProduction.TrackLoaded(_workerZdo, this, _offlineEligible); } } private void StopActiveWorkTracking() { if (_wasActivelyWorking) { _wasActivelyWorking = false; _saveTimer = 0f; SaveStateToZdo(); } } internal static int AdvanceOfflineState(ZDO zdo, float productiveSeconds) { if (zdo == null || productiveSeconds <= 0f || zdo.GetInt("AutomationByGoblins.Job.OfflineEligible", 0) == 0) { return 0; } int num = Mathf.Clamp(zdo.GetInt("AutomationByGoblins.Job.Level", 0), 0, ProductionIntervals.Length - 1); int num2 = Mathf.Clamp(zdo.GetInt("AutomationByGoblins.Job.YieldLevel", 0), 0, ProductionAmounts.Length - 1); int num3 = Mathf.Clamp(zdo.GetInt("AutomationByGoblins.Job.StorageLevel", 0), 0, StorageCapacities.Length - 1); int num4 = StorageCapacities[num3]; int num5 = Mathf.Clamp(zdo.GetInt("AutomationByGoblins.Job.Stored", 0), 0, num4); if (num5 >= num4) { return 0; } int num6 = num5; float num7 = ProductionIntervals[num]; int num8 = ProductionAmounts[num2]; float num9 = Mathf.Clamp(zdo.GetFloat("AutomationByGoblins.Job.ProductionSeconds", 0f), 0f, num7); int num10 = Mathf.CeilToInt((float)(num4 - num5) / (float)num8); float num11 = Mathf.Max(0f, (float)num10 * num7 - num9); float num12 = Mathf.Min(productiveSeconds, num11); if (num12 <= 0f) { return 0; } float num13 = num9 + num12; int num14 = Mathf.FloorToInt(num13 / num7); if (num14 > 0) { num5 = Mathf.Min(num4, num5 + num14 * num8); num13 -= (float)num14 * num7; } if (num5 >= num4) { num13 = 0f; } zdo.Set("AutomationByGoblins.Job.Stored", num5); zdo.Set("AutomationByGoblins.Job.WorkSeconds", Mathf.Max(0f, zdo.GetFloat("AutomationByGoblins.Job.WorkSeconds", 0f)) + num12); zdo.Set("AutomationByGoblins.Job.YieldWorkSeconds", Mathf.Max(0f, zdo.GetFloat("AutomationByGoblins.Job.YieldWorkSeconds", 0f)) + num12); zdo.Set("AutomationByGoblins.Job.StorageWorkSeconds", Mathf.Max(0f, zdo.GetFloat("AutomationByGoblins.Job.StorageWorkSeconds", 0f)) + num12); zdo.Set("AutomationByGoblins.Job.ProductionSeconds", Mathf.Max(0f, num13)); return num5 - num6; } internal void OpenUpgradeWindow(Player player) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) if (IsUsableWorker && !((Object)(object)player == (Object)null)) { MakeThisTheActiveWindow(); _windowPlayer = player; _storageWindowOpen = false; _upgradeWindowOpen = true; _uiMessage = string.Empty; _speedMaterialCountCheckedAt = -1000f; _speedMaterialCountPrefab = string.Empty; _yieldMaterialCountCheckedAt = -1000f; _yieldMaterialCountPrefab = string.Empty; _storageMaterialCountCheckedAt = -1000f; _storageMaterialCountPrefab = string.Empty; _upgradeScrollPosition = Vector2.zero; CenterWindow(ref _upgradeWindowRect); SetCursorForWindow(open: true); if (_level >= 0 && _level < UpgradeCostPrefabs.Length) { string text = UpgradeCostPrefabs[_level]; int cachedUpgradeMaterialCount = GetCachedUpgradeMaterialCount(player, text, force: true, ref _speedMaterialCountCheckedAt, ref _speedMaterialCountPrefab, ref _speedMaterialCountCached); LogInventorySnapshot(player, text, cachedUpgradeMaterialCount); } if (_yieldLevel >= 0 && _yieldLevel < YieldUpgradeCostPrefabs.Length) { string text2 = YieldUpgradeCostPrefabs[_yieldLevel]; int cachedUpgradeMaterialCount2 = GetCachedUpgradeMaterialCount(player, text2, force: true, ref _yieldMaterialCountCheckedAt, ref _yieldMaterialCountPrefab, ref _yieldMaterialCountCached); LogInventorySnapshot(player, text2, cachedUpgradeMaterialCount2); } if (_storageLevel >= 0 && _storageLevel < StorageUpgradeCostPrefabs.Length) { string text3 = StorageUpgradeCostPrefabs[_storageLevel]; int cachedUpgradeMaterialCount3 = GetCachedUpgradeMaterialCount(player, text3, force: true, ref _storageMaterialCountCheckedAt, ref _storageMaterialCountPrefab, ref _storageMaterialCountCached); LogInventorySnapshot(player, text3, cachedUpgradeMaterialCount3); } } } internal void OpenStorageWindow(Player player) { if (IsUsableWorker && !((Object)(object)player == (Object)null)) { MakeThisTheActiveWindow(); _windowPlayer = player; _upgradeWindowOpen = false; _storageWindowOpen = true; _uiMessage = string.Empty; CenterWindow(ref _storageWindowRect); SetCursorForWindow(open: true); } } private void MakeThisTheActiveWindow() { if ((Object)(object)ActiveWindow != (Object)null && (Object)(object)ActiveWindow != (Object)(object)this) { ActiveWindow.CloseWindows(); } ActiveWindow = this; } internal void CloseWindows() { _upgradeWindowOpen = false; _storageWindowOpen = false; _windowPlayer = null; _uiMessage = string.Empty; if ((Object)(object)ActiveWindow == (Object)(object)this) { ActiveWindow = null; } SetCursorForWindow(open: false); } private static void CenterWindow(ref Rect rect) { ((Rect)(ref rect)).x = ((float)Screen.width - ((Rect)(ref rect)).width) * 0.5f; ((Rect)(ref rect)).y = ((float)Screen.height - ((Rect)(ref rect)).height) * 0.5f; } private void SetCursorForWindow(bool open) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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) if (open) { if (!_cursorStateSaved) { _previousCursorVisible = Cursor.visible; _previousCursorLockMode = Cursor.lockState; _cursorStateSaved = true; } Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; } else if (_cursorStateSaved) { Cursor.visible = _previousCursorVisible; Cursor.lockState = _previousCursorLockMode; _cursorStateSaved = false; } } private void OnGUI() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_0076: 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) if (!((Object)(object)ActiveWindow != (Object)(object)this)) { if (_upgradeWindowOpen) { _upgradeWindowRect = GUI.Window(((Object)this).GetInstanceID(), _upgradeWindowRect, new WindowFunction(DrawUpgradeWindow), "Разумный фулинг — развитие"); } if (_storageWindowOpen) { _storageWindowRect = GUI.Window(((Object)this).GetInstanceID() ^ 0x2739, _storageWindowRect, new WindowFunction(DrawStorageWindow), "Хранилище рабочего"); } } } private void DrawUpgradeWindow(int windowId) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: 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_0134: 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_0179: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) EnsureTreeStyles(); GUI.Label(new Rect(18f, 28f, 784f, 22f), "Профессия: " + ProfessionName, _treeBranchStyle); GUI.Label(new Rect(18f, 50f, 784f, 22f), "Сейчас: " + ProductionAmounts[_yieldLevel] + " ед. / " + FormatMinutes(ProductionIntervals[_level]) + " • Хранилище: " + _stored + "/" + StorageCapacity, _treeNodeDetailStyle); Rect val = default(Rect); ((Rect)(ref val))..ctor(18f, 78f, ((Rect)(ref _upgradeWindowRect)).width - 36f, ((Rect)(ref _upgradeWindowRect)).height - 190f); Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(0f, 0f, 760f, 690f); _upgradeScrollPosition = GUI.BeginScrollView(val, _upgradeScrollPosition, val2); DrawUpgradeTree(); GUI.EndScrollView(); if (!string.IsNullOrEmpty(_uiMessage)) { GUI.Label(new Rect(20f, ((Rect)(ref _upgradeWindowRect)).height - 108f, 780f, 34f), _uiMessage, _treeNodeDetailStyle); } if (GUI.Button(new Rect(20f, ((Rect)(ref _upgradeWindowRect)).height - 68f, 380f, 30f), "Приказать следовать / стоять")) { WorkerStorageInteractPatch.RunVanillaTameableInteraction(_tameable, _windowPlayer); } if (GUI.Button(new Rect(620f, ((Rect)(ref _upgradeWindowRect)).height - 68f, 180f, 30f), "Закрыть")) { CloseWindows(); } GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref _upgradeWindowRect)).width, 24f)); } private void EnsureTreeStyles() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown if (_treeRootStyle == null) { _treeRootStyle = new GUIStyle(GUI.skin.box); _treeRootStyle.alignment = (TextAnchor)4; _treeRootStyle.fontSize = 15; _treeRootStyle.fontStyle = (FontStyle)1; _treeRootStyle.wordWrap = true; _treeBranchStyle = new GUIStyle(GUI.skin.label); _treeBranchStyle.alignment = (TextAnchor)4; _treeBranchStyle.fontSize = 14; _treeBranchStyle.fontStyle = (FontStyle)1; _treeNodeTitleStyle = new GUIStyle(GUI.skin.label); _treeNodeTitleStyle.alignment = (TextAnchor)1; _treeNodeTitleStyle.fontSize = 12; _treeNodeTitleStyle.fontStyle = (FontStyle)1; _treeNodeTitleStyle.wordWrap = true; _treeNodeDetailStyle = new GUIStyle(GUI.skin.label); _treeNodeDetailStyle.alignment = (TextAnchor)1; _treeNodeDetailStyle.fontSize = 11; _treeNodeDetailStyle.wordWrap = true; } } private void DrawUpgradeTree() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_0041: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: 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_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0125: 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) //IL_015f: Unknown result type (might be due to invalid IL or missing references) Rect val = default(Rect); ((Rect)(ref val))..ctor(220f, 8f, 320f, 76f); Color color = GUI.color; GUI.color = new Color(0.55f, 0.72f, 0.38f, 1f); GUI.Box(val, "РАЗУМНЫЙ ФУЛИНГ\n" + ProfessionName + "\nВсе ветки развиваются независимо", _treeRootStyle); GUI.color = color; DrawTreeConnections(10f, 266f, 522f, val); GUI.Label(new Rect(10f, 106f, 228f, 26f), "СКОРОСТЬ", _treeBranchStyle); GUI.Label(new Rect(266f, 106f, 228f, 26f), "КОЛИЧЕСТВО", _treeBranchStyle); GUI.Label(new Rect(522f, 106f, 228f, 26f), "ХРАНИЛИЩЕ", _treeBranchStyle); for (int i = 0; i < 4; i++) { float num = 140f + (float)i * 140f; DrawSpeedTreeNode(i, new Rect(10f, num, 228f, 116f)); DrawYieldTreeNode(i, new Rect(266f, num, 228f, 116f)); DrawStorageTreeNode(i, new Rect(522f, num, 228f, 116f)); } } private void DrawTreeConnections(float leftX, float middleX, float rightX, Rect rootRect) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) float num = leftX + 114f; float num2 = middleX + 114f; float num3 = rightX + 114f; float num4 = ((Rect)(ref rootRect)).x + ((Rect)(ref rootRect)).width * 0.5f; DrawTreeLine(new Rect(num4 - 1f, ((Rect)(ref rootRect)).yMax, 2f, 96f - ((Rect)(ref rootRect)).yMax)); DrawTreeLine(new Rect(num, 96f, num3 - num, 2f)); DrawTreeLine(new Rect(num - 1f, 96f, 2f, 44f)); DrawTreeLine(new Rect(num2 - 1f, 96f, 2f, 44f)); DrawTreeLine(new Rect(num3 - 1f, 96f, 2f, 44f)); for (int i = 0; i < 3; i++) { float num5 = i switch { 1 => num2, 0 => num, _ => num3, }; for (int j = 0; j < 3; j++) { float num6 = 140f + (float)j * 140f + 116f; float num7 = 140f + (float)(j + 1) * 140f; DrawTreeLine(new Rect(num5 - 1f, num6, 2f, num7 - num6)); } } } private static void DrawTreeLine(Rect rect) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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_0032: Unknown result type (might be due to invalid IL or missing references) Color color = GUI.color; GUI.color = new Color(0.68f, 0.58f, 0.32f, 0.9f); GUI.DrawTexture(rect, (Texture)(object)Texture2D.whiteTexture); GUI.color = color; } private void DrawSpeedTreeNode(int upgradeIndex, Rect rect) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) int num = upgradeIndex + 1; bool flag = _level > upgradeIndex; bool flag2 = _level < upgradeIndex; float num2 = Mathf.Max(0f, 1800f - _workSeconds); int materialCount = 0; if (!flag && !flag2) { materialCount = GetCachedUpgradeMaterialCount(_windowPlayer, UpgradeCostPrefabs[upgradeIndex], force: false, ref _speedMaterialCountCheckedAt, ref _speedMaterialCountPrefab, ref _speedMaterialCountCached); } DrawTreeNodeBackground(rect, flag, flag2, num2); GUI.Label(new Rect(((Rect)(ref rect)).x + 5f, ((Rect)(ref rect)).y + 5f, ((Rect)(ref rect)).width - 10f, 20f), "Уровень " + (num + 1) + " • " + FormatMinutes(ProductionIntervals[num]), _treeNodeTitleStyle); GUI.Label(new Rect(((Rect)(ref rect)).x + 6f, ((Rect)(ref rect)).y + 28f, ((Rect)(ref rect)).width - 12f, 51f), BuildTreeNodeDetails(flag, flag2, num2, materialCount, 5, UpgradeCostRussianNames[upgradeIndex]), _treeNodeDetailStyle); if (!flag && !flag2) { bool enabled = GUI.enabled; GUI.enabled = num2 <= 0f; if (GUI.Button(new Rect(((Rect)(ref rect)).x + 12f, ((Rect)(ref rect)).y + 83f, ((Rect)(ref rect)).width - 24f, 26f), "Улучшить")) { TrySpeedUpgrade(_windowPlayer); } GUI.enabled = enabled; } } private void DrawYieldTreeNode(int upgradeIndex, Rect rect) { //IL_0076: 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_012f: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) int num = upgradeIndex + 1; int costAmount = YieldUpgradeCostAmounts[upgradeIndex]; bool flag = _yieldLevel > upgradeIndex; bool flag2 = _yieldLevel < upgradeIndex; float num2 = Mathf.Max(0f, 1800f - _yieldWorkSeconds); int materialCount = 0; if (!flag && !flag2) { materialCount = GetCachedUpgradeMaterialCount(_windowPlayer, YieldUpgradeCostPrefabs[upgradeIndex], force: false, ref _yieldMaterialCountCheckedAt, ref _yieldMaterialCountPrefab, ref _yieldMaterialCountCached); } DrawTreeNodeBackground(rect, flag, flag2, num2); GUI.Label(new Rect(((Rect)(ref rect)).x + 5f, ((Rect)(ref rect)).y + 5f, ((Rect)(ref rect)).width - 10f, 20f), "Уровень " + (num + 1) + " • " + ProductionAmounts[num] + " ед.", _treeNodeTitleStyle); GUI.Label(new Rect(((Rect)(ref rect)).x + 6f, ((Rect)(ref rect)).y + 28f, ((Rect)(ref rect)).width - 12f, 51f), BuildTreeNodeDetails(flag, flag2, num2, materialCount, costAmount, YieldUpgradeCostRussianNames[upgradeIndex]), _treeNodeDetailStyle); if (!flag && !flag2) { bool enabled = GUI.enabled; GUI.enabled = num2 <= 0f; if (GUI.Button(new Rect(((Rect)(ref rect)).x + 12f, ((Rect)(ref rect)).y + 83f, ((Rect)(ref rect)).width - 24f, 26f), "Улучшить")) { TryYieldUpgrade(_windowPlayer); } GUI.enabled = enabled; } } private void DrawStorageTreeNode(int upgradeIndex, Rect rect) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) int num = upgradeIndex + 1; bool flag = _storageLevel > upgradeIndex; bool flag2 = _storageLevel < upgradeIndex; float num2 = Mathf.Max(0f, 1800f - _storageWorkSeconds); int materialCount = 0; if (!flag && !flag2) { materialCount = GetCachedUpgradeMaterialCount(_windowPlayer, StorageUpgradeCostPrefabs[upgradeIndex], force: false, ref _storageMaterialCountCheckedAt, ref _storageMaterialCountPrefab, ref _storageMaterialCountCached); } DrawTreeNodeBackground(rect, flag, flag2, num2); GUI.Label(new Rect(((Rect)(ref rect)).x + 5f, ((Rect)(ref rect)).y + 5f, ((Rect)(ref rect)).width - 10f, 20f), "Уровень " + (num + 1) + " • " + StorageCapacities[num] + " мест", _treeNodeTitleStyle); GUI.Label(new Rect(((Rect)(ref rect)).x + 6f, ((Rect)(ref rect)).y + 28f, ((Rect)(ref rect)).width - 12f, 51f), BuildTreeNodeDetails(flag, flag2, num2, materialCount, 10, StorageUpgradeCostRussianNames[upgradeIndex]), _treeNodeDetailStyle); if (!flag && !flag2) { bool enabled = GUI.enabled; GUI.enabled = num2 <= 0f; if (GUI.Button(new Rect(((Rect)(ref rect)).x + 12f, ((Rect)(ref rect)).y + 83f, ((Rect)(ref rect)).width - 24f, 26f), "Улучшить")) { TryStorageUpgrade(_windowPlayer); } GUI.enabled = enabled; } } private static string BuildTreeNodeDetails(bool completed, bool locked, float remaining, int materialCount, int costAmount, string materialName) { if (completed) { return "✓ Улучшено\n" + costAmount + " × " + materialName; } if (locked) { return "Заблокировано\n" + costAmount + " × " + materialName; } string text = ((remaining > 0f) ? ("Работать: " + FormatClock(remaining)) : "Готово к улучшению"); return text + "\nМатериалы: " + materialCount + "/" + costAmount + " × " + materialName; } private static void DrawTreeNodeBackground(Rect rect, bool completed, bool locked, float remaining) { //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_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) Color color = default(Color); if (completed) { ((Color)(ref color))..ctor(0.3f, 0.62f, 0.32f, 0.95f); } else if (locked) { ((Color)(ref color))..ctor(0.28f, 0.28f, 0.28f, 0.88f); } else if (remaining <= 0f) { ((Color)(ref color))..ctor(0.78f, 0.6f, 0.18f, 0.98f); } else { ((Color)(ref color))..ctor(0.34f, 0.46f, 0.68f, 0.95f); } Color color2 = GUI.color; GUI.color = color; GUI.Box(rect, GUIContent.none); GUI.color = color2; } private void DrawStorageWindow(int windowId) { GUILayout.Space(10f); GUILayout.Label("Профессия: " + ProfessionName, Array.Empty()); GUILayout.Label("Один слот, максимум " + StorageCapacity + " ед.", Array.Empty()); GUILayout.Label("За цикл: " + ProductionAmounts[_yieldLevel] + " ед.", Array.Empty()); GUILayout.Space(12f); GUILayout.Box(ResourceRussianName + "\n" + _stored + " / " + StorageCapacity, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(72f) }); if (GUILayout.Button("Забрать ресурсы", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(36f) })) { int num = CollectResources(_windowPlayer); _uiMessage = ((num > 0) ? ("Получено: " + num + " × " + ResourceRussianName) : ((_stored <= 0) ? "Хранилище пусто" : "В инвентаре нет места")); } if (!string.IsNullOrEmpty(_uiMessage)) { GUILayout.Label(_uiMessage, Array.Empty()); } GUILayout.FlexibleSpace(); if (GUILayout.Button("Закрыть", Array.Empty())) { CloseWindows(); } GUI.DragWindow(); } private void TrySpeedUpgrade(Player player) { if ((Object)(object)player == (Object)null || _level >= ProductionIntervals.Length - 1) { return; } if (_workSeconds < 1800f) { _uiMessage = "Сначала гоблин должен отработать 30 минут на текущем уровне."; return; } if (!EnsureOwnership()) { _uiMessage = "Не удалось получить доступ к состоянию этого гоблина."; return; } string text = UpgradeCostPrefabs[_level]; int num = (_speedMaterialCountCached = CountPrefabInInventory(player, text)); _speedMaterialCountPrefab = text; _speedMaterialCountCheckedAt = Time.unscaledTime; LogInventorySnapshot(player, text, num); if (num < 5) { _uiMessage = "Недостаточно: найдено " + num + "/5 × " + UpgradeCostRussianNames[_level] + "."; } else if (!RemovePrefabFromInventory(player, text, 5)) { _uiMessage = "Не удалось списать материалы улучшения."; LogInventorySnapshot(player, text, CountPrefabInInventory(player, text)); } else { _level++; _workSeconds = 0f; _productionSeconds = 0f; SaveStateToZdo(); _speedMaterialCountCheckedAt = -1000f; _speedMaterialCountPrefab = string.Empty; _uiMessage = "Скорость улучшена. Новое время добычи: " + FormatMinutes(ProductionIntervals[_level]) + "."; } } private void TryYieldUpgrade(Player player) { if ((Object)(object)player == (Object)null || _yieldLevel >= ProductionAmounts.Length - 1) { return; } if (_yieldWorkSeconds < 1800f) { _uiMessage = "Сначала гоблин должен отработать 30 минут для улучшения количества."; return; } if (!EnsureOwnership()) { _uiMessage = "Не удалось получить доступ к состоянию этого гоблина."; return; } string text = YieldUpgradeCostPrefabs[_yieldLevel]; int num = YieldUpgradeCostAmounts[_yieldLevel]; int num2 = (_yieldMaterialCountCached = CountPrefabInInventory(player, text)); _yieldMaterialCountPrefab = text; _yieldMaterialCountCheckedAt = Time.unscaledTime; LogInventorySnapshot(player, text, num2); if (num2 < num) { _uiMessage = "Недостаточно: найдено " + num2 + "/" + num + " × " + YieldUpgradeCostRussianNames[_yieldLevel] + "."; } else if (!RemovePrefabFromInventory(player, text, num)) { _uiMessage = "Не удалось списать материалы улучшения."; LogInventorySnapshot(player, text, CountPrefabInInventory(player, text)); } else { _yieldLevel++; _yieldWorkSeconds = 0f; SaveStateToZdo(); _yieldMaterialCountCheckedAt = -1000f; _yieldMaterialCountPrefab = string.Empty; _uiMessage = "Количество улучшено. Теперь за цикл добывается " + ProductionAmounts[_yieldLevel] + " ед."; } } private void TryStorageUpgrade(Player player) { if ((Object)(object)player == (Object)null || _storageLevel >= StorageCapacities.Length - 1) { return; } if (_storageWorkSeconds < 1800f) { _uiMessage = "Сначала гоблин должен отработать 30 минут для улучшения хранилища."; return; } if (!EnsureOwnership()) { _uiMessage = "Не удалось получить доступ к состоянию этого гоблина."; return; } string text = StorageUpgradeCostPrefabs[_storageLevel]; int num = (_storageMaterialCountCached = CountPrefabInInventory(player, text)); _storageMaterialCountPrefab = text; _storageMaterialCountCheckedAt = Time.unscaledTime; LogInventorySnapshot(player, text, num); if (num < 10) { _uiMessage = "Недостаточно: найдено " + num + "/" + 10 + " × " + StorageUpgradeCostRussianNames[_storageLevel] + "."; } else if (!RemovePrefabFromInventory(player, text, 10)) { _uiMessage = "Не удалось списать материалы улучшения."; LogInventorySnapshot(player, text, CountPrefabInInventory(player, text)); } else { _storageLevel++; _storageWorkSeconds = 0f; SaveStateToZdo(); _storageMaterialCountCheckedAt = -1000f; _storageMaterialCountPrefab = string.Empty; _uiMessage = "Хранилище улучшено. Новая вместимость: " + StorageCapacity + " ед."; } } private int GetCachedUpgradeMaterialCount(Player player, string prefabName, bool force, ref float checkedAt, ref string cachedPrefab, ref int cachedCount) { if ((Object)(object)player == (Object)null || string.IsNullOrEmpty(prefabName)) { return 0; } if (force || !string.Equals(cachedPrefab, prefabName, StringComparison.Ordinal) || Time.unscaledTime - checkedAt >= 0.5f) { cachedCount = CountPrefabInInventory(player, prefabName); cachedPrefab = prefabName; checkedAt = Time.unscaledTime; } return cachedCount; } private int CollectResources(Player player) { if ((Object)(object)player == (Object)null || _stored <= 0 || string.IsNullOrEmpty(ResourcePrefabName)) { return 0; } if (!EnsureOwnership()) { return 0; } if ((Object)(object)ObjectDB.instance == (Object)null) { return 0; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(ResourcePrefabName); if ((Object)(object)itemPrefab == (Object)null) { return 0; } ItemDrop component = itemPrefab.GetComponent(); if ((Object)(object)component == (Object)null) { return 0; } Inventory inventory = ((Humanoid)player).GetInventory(); MethodInfo methodInfo = AccessTools.Method(typeof(Inventory), "AddItem", new Type[1] { typeof(ItemData) }, (Type[])null); if (inventory == null || methodInfo == null) { return 0; } int num = 0; int stored = _stored; for (int i = 0; i < stored; i++) { ItemData val = component.m_itemData.Clone(); val.m_stack = 1; bool flag; try { object obj = methodInfo.Invoke(inventory, new object[1] { val }); flag = ((methodInfo.ReturnType == typeof(bool)) ? (obj != null && (bool)obj) : (methodInfo.ReturnType == typeof(void) || obj != null)); } catch { flag = false; } if (!flag) { break; } num++; _stored--; } if (num > 0) { SaveStateToZdo(); } return num; } private bool EnsureOwnership() { if ((Object)(object)_nview == (Object)null || _nview.GetZDO() == null) { return false; } if (_nview.IsOwner()) { return true; } try { MethodInfo methodInfo = AccessTools.Method(typeof(ZNetView), "ClaimOwnership", (Type[])null, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(_nview, null); } } catch { return false; } if (_nview.IsOwner()) { LoadStateFromZdo(); return true; } return false; } private static int CountPrefabInInventory(Player player, string prefabName) { if ((Object)(object)player == (Object)null) { return 0; } try { Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return 0; } string text = "$item_" + prefabName.ToLowerInvariant(); int num = 0; int num2 = 0; try { num = inventory.CountItems(prefabName, -1, true); } catch { } try { num2 = inventory.CountItems(text, -1, true); } catch { } return num + num2; } catch { return 0; } } private static bool RemovePrefabFromInventory(Player player, string prefabName, int amount) { if ((Object)(object)player == (Object)null || amount <= 0) { return false; } try { Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return false; } string text = "$item_" + prefabName.ToLowerInvariant(); int num = 0; int num2 = 0; try { num = inventory.CountItems(prefabName, -1, true); } catch { } try { num2 = inventory.CountItems(text, -1, true); } catch { } if (num + num2 < amount) { return false; } int num3 = amount; try { int num4 = Math.Min(num, num3); if (num4 > 0) { inventory.RemoveItem(prefabName, num4, -1, true); num3 -= num4; } } catch { } if (num3 > 0) { try { int val = inventory.CountItems(text, -1, true); int num5 = Math.Min(val, num3); if (num5 > 0) { inventory.RemoveItem(text, num5, -1, true); num3 -= num5; } } catch { } } return num3 <= 0; } catch { return false; } } private static void LogInventorySnapshot(Player player, string wantedPrefab, int counted) { if ((Object)(object)player == (Object)null) { return; } try { Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory != null) { string text = "$item_" + wantedPrefab.ToLowerInvariant(); int num = 0; int num2 = 0; try { num = inventory.CountItems(wantedPrefab, -1, true); } catch { } try { num2 = inventory.CountItems(text, -1, true); } catch { } AutomationByGoblinsPlugin.ModLog.LogWarning((object)("Upgrade inventory check: Wanted=" + wantedPrefab + ", Counted=" + counted + ", CountItems(\"" + wantedPrefab + "\")=" + num + ", CountItems(\"" + text + "\")=" + num2)); } } catch { AutomationByGoblinsPlugin.ModLog.LogWarning((object)("Upgrade inventory check failed for " + wantedPrefab + ".")); } } private static string FormatMinutes(float seconds) { return Mathf.RoundToInt(seconds / 60f) + " мин."; } private static string FormatClock(float seconds) { int num = Mathf.Max(0, Mathf.CeilToInt(seconds)); int num2 = num / 60; int num3 = num % 60; return num2.ToString("00") + ":" + num3.ToString("00"); } } internal static class GoblinWorkerOfflineProduction { private sealed class WorkerRecord { internal ZDO Zdo; internal GoblinWorkerJob LoadedJob; internal bool Eligible; internal bool BackgroundAnnounced; } internal const float ProductiveWorkFraction = 0.8f; private static readonly Dictionary Workers = new Dictionary(); private static readonly List InvalidWorkers = new List(); private static bool _managerAvailable; private static int _sessionId; private static float _dayClock; internal static bool HasWorkers => Workers.Count != 0; internal static void BeginSession() { Workers.Clear(); InvalidWorkers.Clear(); _sessionId = (int)DateTime.UtcNow.Ticks; if (_sessionId == 0) { _sessionId = 1; } _dayClock = 0f; _managerAvailable = true; AutomationByGoblinsPlugin.ModLog.LogDebug((object)"Background production clock started."); } internal static void EndSession() { _managerAvailable = false; Workers.Clear(); InvalidWorkers.Clear(); _sessionId = 0; _dayClock = 0f; } internal static bool TryGetDayClock(out int sessionId, out float dayClock) { sessionId = _sessionId; dayClock = _dayClock; return _managerAvailable && sessionId != 0; } internal static void AdvanceDayClock(float elapsedSeconds, bool isDaylight) { if (_managerAvailable && isDaylight && !(elapsedSeconds <= 0f)) { _dayClock += elapsedSeconds; } } internal static void TrackLoaded(ZDO zdo, GoblinWorkerJob job, bool eligible) { if (_managerAvailable && zdo != null && !((Object)(object)job == (Object)null)) { if (!Workers.TryGetValue(zdo, out var value)) { value = new WorkerRecord { Zdo = zdo }; Workers.Add(zdo, value); } value.LoadedJob = job; value.Eligible = eligible; value.BackgroundAnnounced = false; } } internal static void MarkUnloaded(ZDO zdo, GoblinWorkerJob job, bool eligible) { if (!_managerAvailable || zdo == null) { return; } if (!eligible) { Workers.Remove(zdo); return; } if (!Workers.TryGetValue(zdo, out var value)) { value = new WorkerRecord { Zdo = zdo }; Workers.Add(zdo, value); } if ((Object)(object)value.LoadedJob == (Object)null || (Object)(object)value.LoadedJob == (Object)(object)job) { value.LoadedJob = null; } value.Eligible = true; } internal static void Remove(ZDO zdo, GoblinWorkerJob job) { if (zdo != null && (!Workers.TryGetValue(zdo, out var value) || (Object)(object)value.LoadedJob == (Object)null || (Object)(object)value.LoadedJob == (Object)(object)job)) { Workers.Remove(zdo); } } internal static void Advance(float elapsedDaySeconds) { if (elapsedDaySeconds <= 0f || Workers.Count == 0) { return; } float productiveSeconds = elapsedDaySeconds * 0.8f; InvalidWorkers.Clear(); foreach (KeyValuePair worker in Workers) { WorkerRecord value = worker.Value; if (value == null || value.Zdo == null || !value.Eligible) { InvalidWorkers.Add(worker.Key); } else { if ((Object)(object)value.LoadedJob != (Object)null) { continue; } try { if (!value.BackgroundAnnounced) { value.BackgroundAnnounced = true; AutomationByGoblinsPlugin.ModLog.LogDebug((object)"Worker entered background production."); } int num = GoblinWorkerJob.AdvanceOfflineState(value.Zdo, productiveSeconds); GoblinWorkerJob.WriteOfflineCheckpoint(value.Zdo); if (num > 0) { AutomationByGoblinsPlugin.ModLog.LogDebug((object)("Background worker produced " + num + " resource(s).")); } } catch { InvalidWorkers.Add(worker.Key); } } } for (int i = 0; i < InvalidWorkers.Count; i++) { Workers.Remove(InvalidWorkers[i]); } InvalidWorkers.Clear(); } } internal sealed class GoblinWorkerOfflineProductionManager : MonoBehaviour { private const float TickInterval = 10f; private static readonly WaitForSeconds TickDelay = new WaitForSeconds(10f); internal static GoblinWorkerOfflineProductionManager Instance; internal static void EnsureAttached() { if (!((Object)(object)Instance != (Object)null) && !((Object)(object)ZNetScene.instance == (Object)null)) { GoblinWorkerOfflineProductionManager component = ((Component)ZNetScene.instance).GetComponent(); if ((Object)(object)component != (Object)null) { Instance = component; } else { ((Component)ZNetScene.instance).gameObject.AddComponent(); } } } private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)this); return; } Instance = this; GoblinWorkerOfflineProduction.BeginSession(); } private IEnumerator Start() { float lastTickTime = Time.time; while (true) { yield return TickDelay; float now = Time.time; float elapsedSeconds = Mathf.Max(0f, now - lastTickTime); lastTickTime = now; bool isDaylight = (Object)(object)EnvMan.instance != (Object)null && !EnvMan.IsNight(); GoblinWorkerOfflineProduction.AdvanceDayClock(elapsedSeconds, isDaylight); if (GoblinWorkerOfflineProduction.HasWorkers && isDaylight) { GoblinWorkerOfflineProduction.Advance(elapsedSeconds); } } } private void OnDestroy() { if (!((Object)(object)Instance != (Object)(object)this)) { Instance = null; GoblinWorkerOfflineProduction.EndSession(); } } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class GoblinWorkerOfflineProductionAttachPatch { private static void Postfix() { GoblinWorkerOfflineProductionManager.EnsureAttached(); } } [HarmonyPatch(typeof(GoblinWorkerController), "Start")] internal static class GoblinWorkerJobAttachPatch { private static void Postfix(GoblinWorkerController __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).GetComponent() != (Object)null)) { ((Component)__instance).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(Tameable), "GetHoverText")] internal static class WorkerHoverCapturePatch { internal static GoblinWorkerJob HoveredWorker; internal static int HoveredFrame = -100; private static void Postfix(Tameable __instance) { if (!((Object)(object)__instance == (Object)null)) { GoblinWorkerJob component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null) && component.IsUsableWorker) { HoveredWorker = component; HoveredFrame = Time.frameCount; GathererHoverCapturePatch.HoveredGatherer = null; GathererHoverCapturePatch.HoveredFrame = -100; } } } } [HarmonyPatch(typeof(Player), "Update")] internal static class WorkerMenuHotkeyPatch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && (Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307)) && Input.GetKeyDown((KeyCode)121)) { GoblinWorkerJob hoveredWorker = WorkerHoverCapturePatch.HoveredWorker; if (!((Object)(object)hoveredWorker == (Object)null) && hoveredWorker.IsUsableWorker && Time.frameCount - WorkerHoverCapturePatch.HoveredFrame <= 5) { hoveredWorker.OpenUpgradeWindow(__instance); } } } } [HarmonyPatch(typeof(InventoryGui), "IsVisible")] internal static class WorkerWindowVanillaInputBlockPatch { private static void Postfix(ref bool __result) { if ((Object)(object)GoblinWorkerJob.ActiveWindow != (Object)null) { __result = true; } } } [HarmonyPatch(typeof(Tameable), "Interact")] internal static class WorkerStorageInteractPatch { private static bool _allowVanillaInteraction; internal static bool IsVanillaInteractionAllowed => _allowVanillaInteraction; private static bool Prefix(Tameable __instance, Humanoid user, bool hold, bool alt, ref bool __result) { if (_allowVanillaInteraction || (Object)(object)__instance == (Object)null) { return true; } GoblinWorkerJob component = ((Component)__instance).GetComponent(); Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)component == (Object)null || !component.IsUsableWorker || (Object)(object)val == (Object)null) { return true; } if (alt) { return true; } if (hold) { __result = false; return false; } component.OpenStorageWindow(val); __result = true; return false; } internal static void RunVanillaTameableInteraction(Tameable tameable, Player player) { if ((Object)(object)tameable == (Object)null || (Object)(object)player == (Object)null) { return; } MethodInfo methodInfo = AccessTools.Method(typeof(Tameable), "Interact", new Type[3] { typeof(Humanoid), typeof(bool), typeof(bool) }, (Type[])null); if (methodInfo == null) { return; } try { _allowVanillaInteraction = true; methodInfo.Invoke(tameable, new object[3] { player, false, false }); } finally { _allowVanillaInteraction = false; } } } public sealed class GoblinWorkerEquipment : MonoBehaviour { private const string WoodToolPrefabName = "AxeFlint"; private const string StoneToolPrefabName = "PickaxeAntler"; private GoblinWorkerController _controller; private Humanoid _humanoid; private VisEquipment _visEquipment; private ItemData _toolItem; private string _toolPrefabName = string.Empty; private bool _isProfessionWorker; private bool _forceEmptyHands; private bool _actualToolEquipped; private static readonly MethodInfo[] LeftItemVisualMethods = ResolveLeftItemVisualMethods(); internal bool ShouldForceToolVisual => _isProfessionWorker && (_forceEmptyHands || !string.IsNullOrEmpty(_toolPrefabName)); internal string ForcedRightItemPrefab => _forceEmptyHands ? string.Empty : _toolPrefabName; internal bool ShouldForceEmptyHands => _isProfessionWorker && _forceEmptyHands; internal static IEnumerable GetLeftItemVisualMethods() { int i = 0; while (i < LeftItemVisualMethods.Length) { yield return LeftItemVisualMethods[i]; int num = i + 1; i = num; } } private void Start() { _controller = ((Component)this).GetComponent(); _humanoid = ((Component)this).GetComponent(); _visEquipment = ((Component)this).GetComponent(); if ((Object)(object)_visEquipment == (Object)null) { _visEquipment = ((Component)this).GetComponentInChildren(true); } ((MonoBehaviour)this).StartCoroutine(InitializeEquipment()); } private IEnumerator InitializeEquipment() { while ((Object)(object)_controller != (Object)null && _controller.WorkerType == GoblinWorkerType.Unassigned) { yield return null; } if ((Object)(object)_controller == (Object)null) { yield break; } if (_controller.WorkerType == GoblinWorkerType.Wood) { _toolPrefabName = "AxeFlint"; } else { if (_controller.WorkerType != GoblinWorkerType.Stone) { if (_controller.WorkerType == GoblinWorkerType.Gatherer) { _isProfessionWorker = true; _forceEmptyHands = true; ApplyToolVisual(); } yield break; } _toolPrefabName = "PickaxeAntler"; } _isProfessionWorker = true; GameObject toolPrefab = null; while (true) { int num; if ((Object)(object)this != (Object)null) { if (!((Object)(object)ObjectDB.instance == (Object)null)) { GameObject itemPrefab; toolPrefab = (itemPrefab = ObjectDB.instance.GetItemPrefab(_toolPrefabName)); num = (((Object)(object)itemPrefab == (Object)null) ? 1 : 0); } else { num = 1; } } else { num = 0; } if (num == 0) { break; } yield return (object)new WaitForSeconds(0.25f); } if ((Object)(object)this == (Object)null || (Object)(object)toolPrefab == (Object)null) { yield break; } ItemDrop itemDrop = toolPrefab.GetComponent(); if ((Object)(object)itemDrop == (Object)null || itemDrop.m_itemData == null) { AutomationByGoblinsPlugin.ModLog.LogWarning((object)("Worker equipment: " + _toolPrefabName + " has no ItemDrop data.")); yield break; } _toolItem = itemDrop.m_itemData.Clone(); _actualToolEquipped = TryEquipActualTool(_toolItem); ApplyToolVisual(); if (_actualToolEquipped) { AutomationByGoblinsPlugin.ModLog.LogDebug((object)(_controller.WorkerType.ToString() + " Goblin equipped " + _toolPrefabName + " as its combat weapon.")); } else { AutomationByGoblinsPlugin.ModLog.LogWarning((object)(_controller.WorkerType.ToString() + " Goblin could not equip " + _toolPrefabName + " as ItemData; using its visual with vanilla Goblin combat fallback.")); } } private bool TryEquipActualTool(ItemData toolItem) { if ((Object)(object)_humanoid == (Object)null || toolItem == null) { return false; } Inventory val = null; try { val = _humanoid.GetInventory(); } catch { return false; } if (val == null) { return false; } MethodInfo methodInfo = AccessTools.Method(typeof(Inventory), "AddItem", new Type[1] { typeof(ItemData) }, (Type[])null); if (methodInfo == null) { return false; } try { object obj2 = methodInfo.Invoke(val, new object[1] { toolItem }); if (methodInfo.ReturnType == typeof(bool) && (obj2 == null || !(bool)obj2)) { return false; } } catch (Exception exception) { AutomationByGoblinsPlugin.ModLog.LogWarning((object)("Worker equipment: could not add " + _toolPrefabName + " to Goblin inventory: " + GetInnermostMessage(exception))); return false; } bool flag = InvokeEquipItem(_humanoid, toolItem); if (!flag) { RemoveInventoryItem(val, toolItem); } return flag; } private static void RemoveInventoryItem(Inventory inventory, ItemData item) { if (inventory == null || item == null) { return; } try { MethodInfo methodInfo = AccessTools.Method(typeof(Inventory), "RemoveItem", new Type[1] { typeof(ItemData) }, (Type[])null); if (methodInfo != null) { methodInfo.Invoke(inventory, new object[1] { item }); } } catch { } } private static bool InvokeEquipItem(Humanoid humanoid, ItemData item) { try { MethodInfo[] methods = typeof(Humanoid).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (!string.Equals(methodInfo.Name, "EquipItem", StringComparison.Ordinal)) { continue; } ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length == 0 || parameters[0].ParameterType != typeof(ItemData)) { continue; } object[] array = new object[parameters.Length]; array[0] = item; bool flag = true; for (int j = 1; j < parameters.Length; j++) { Type parameterType = parameters[j].ParameterType; if (parameters[j].HasDefaultValue && parameters[j].DefaultValue != DBNull.Value && parameters[j].DefaultValue != Type.Missing) { array[j] = parameters[j].DefaultValue; continue; } if (parameterType == typeof(bool)) { array[j] = false; continue; } if (parameterType.IsValueType) { array[j] = Activator.CreateInstance(parameterType); continue; } flag = false; break; } if (flag) { object obj = methodInfo.Invoke(humanoid, array); if (methodInfo.ReturnType == typeof(bool)) { return obj != null && (bool)obj; } return true; } } } catch (Exception exception) { AutomationByGoblinsPlugin.ModLog.LogWarning((object)("Worker equipment: Humanoid.EquipItem failed: " + GetInnermostMessage(exception))); } return false; } private void ApplyToolVisual() { if (!_isProfessionWorker || (!_forceEmptyHands && string.IsNullOrEmpty(_toolPrefabName))) { return; } if ((Object)(object)_visEquipment == (Object)null) { _visEquipment = ((Component)this).GetComponent(); if ((Object)(object)_visEquipment == (Object)null) { _visEquipment = ((Component)this).GetComponentInChildren(true); } } if ((Object)(object)_visEquipment == (Object)null) { return; } try { _visEquipment.SetRightItem(_forceEmptyHands ? string.Empty : _toolPrefabName); if (_forceEmptyHands) { ClearLeftHandVisual(); } } catch (Exception exception) { AutomationByGoblinsPlugin.ModLog.LogWarning((object)("Worker equipment: VisEquipment.SetRightItem failed for " + _toolPrefabName + ": " + GetInnermostMessage(exception))); _isProfessionWorker = false; } } private void ClearLeftHandVisual() { for (int i = 0; i < LeftItemVisualMethods.Length; i++) { MethodInfo methodInfo = LeftItemVisualMethods[i]; ParameterInfo[] parameters = methodInfo.GetParameters(); object[] array = new object[parameters.Length]; array[0] = string.Empty; bool flag = true; for (int j = 1; j < parameters.Length; j++) { Type parameterType = parameters[j].ParameterType; if (parameterType == typeof(int)) { array[j] = 0; continue; } if (parameterType == typeof(bool)) { array[j] = false; continue; } if (parameterType.IsValueType) { array[j] = Activator.CreateInstance(parameterType); continue; } flag = false; break; } if (flag) { try { methodInfo.Invoke(_visEquipment, array); break; } catch { } } } } private static MethodInfo[] ResolveLeftItemVisualMethods() { List list = new List(); MethodInfo[] methods = typeof(VisEquipment).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (string.Equals(methodInfo.Name, "SetLeftItem", StringComparison.Ordinal)) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length != 0 && parameters[0].ParameterType == typeof(string)) { list.Add(methodInfo); } } } return list.ToArray(); } private static string GetInnermostMessage(Exception exception) { Exception ex = exception; while (ex.InnerException != null) { ex = ex.InnerException; } return ex.Message; } } [HarmonyPatch(typeof(GoblinWorkerController), "Start")] internal static class GoblinWorkerEquipmentAttachPatch { private static void Postfix(GoblinWorkerController __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).GetComponent() != (Object)null)) { ((Component)__instance).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(VisEquipment), "SetRightItem", new Type[] { typeof(string) })] internal static class GoblinWorkerRightItemVisualPatch { private static void Prefix(VisEquipment __instance, ref string __0) { if (!((Object)(object)__instance == (Object)null)) { GoblinWorkerEquipment componentInParent = ((Component)__instance).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null) && componentInParent.ShouldForceToolVisual) { __0 = componentInParent.ForcedRightItemPrefab; } } } } [HarmonyPatch] internal static class GoblinGathererLeftItemVisualPatch { private static IEnumerable TargetMethods() { return GoblinWorkerEquipment.GetLeftItemVisualMethods(); } private static void Prefix(VisEquipment __instance, object[] __args) { if ((Object)(object)__instance == (Object)null || __args == null || __args.Length == 0) { return; } GoblinWorkerEquipment componentInParent = ((Component)__instance).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null) && componentInParent.ShouldForceEmptyHands) { __args[0] = string.Empty; if (__args.Length > 1 && __args[1] is int) { __args[1] = 0; } } } } internal enum GoblinWardZoneType { None, Woodcutter, Stoneworker, Gatherer, Sleeping } public sealed class GoblinWardWorkZone : MonoBehaviour { private const string ZoneTypeZdoKey = "AutomationByGoblins.Ward.ZoneType"; private const float DefaultWardRadius = 32f; private const float ZoneTypeCacheDuration = 0.5f; private static readonly List Instances = new List(); private static readonly FieldInfo WardRadiusField = AccessTools.Field(typeof(PrivateArea), "m_radius"); private static readonly MethodInfo ClaimOwnershipMethod = AccessTools.Method(typeof(ZNetView), "ClaimOwnership", (Type[])null, (Type[])null); private PrivateArea _ward; private ZNetView _nview; private Vector3 _center; private float _radius = 32f; private GoblinWardZoneType _cachedZoneType = GoblinWardZoneType.None; private float _nextZoneTypeRefreshTime; private bool _menuOpen; private Player _menuPlayer; private string _uiMessage = string.Empty; private Rect _windowRect = new Rect(0f, 0f, 430f, 405f); private bool _cursorStateSaved; private bool _previousCursorVisible; private CursorLockMode _previousCursorLockMode; internal static GoblinWardWorkZone ActiveMenu; internal Vector3 Center => _center; internal float Radius => _radius; private void Awake() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) _ward = ((Component)this).GetComponent(); _nview = ((Component)this).GetComponent(); _center = ((Component)this).transform.position; _radius = ReadWardRadius(_ward); Instances.Add(this); ((Behaviour)this).enabled = false; } private static float ReadWardRadius(PrivateArea ward) { if ((Object)(object)ward == (Object)null) { return 32f; } try { if (WardRadiusField != null) { object value = WardRadiusField.GetValue(ward); if (value is float) { return Mathf.Max(1f, (float)value); } } } catch { } return 32f; } private void OnDestroy() { Instances.Remove(this); if ((Object)(object)ActiveMenu == (Object)(object)this) { CloseMenu(); } } internal GoblinWardZoneType GetZoneType() { float time = Time.time; if (time < _nextZoneTypeRefreshTime) { return _cachedZoneType; } _nextZoneTypeRefreshTime = time + 0.5f; if ((Object)(object)_nview == (Object)null) { _nview = ((Component)this).GetComponent(); } if ((Object)(object)_nview == (Object)null || _nview.GetZDO() == null) { _cachedZoneType = GoblinWardZoneType.None; return _cachedZoneType; } int num = _nview.GetZDO().GetInt("AutomationByGoblins.Ward.ZoneType", 0); if (num < 0 || num > 4) { _cachedZoneType = GoblinWardZoneType.None; return _cachedZoneType; } _cachedZoneType = (GoblinWardZoneType)num; return _cachedZoneType; } internal bool Contains(Vector3 worldPosition) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) Vector3 val = worldPosition - Center; val.y = 0f; float radius = Radius; return ((Vector3)(ref val)).sqrMagnitude <= radius * radius; } internal static GoblinWardWorkZone FindNearest(Vector3 from, GoblinWardZoneType requestedType) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_0062: Unknown result type (might be due to invalid IL or missing references) GoblinWardWorkZone result = null; float num = float.MaxValue; for (int num2 = Instances.Count - 1; num2 >= 0; num2--) { GoblinWardWorkZone goblinWardWorkZone = Instances[num2]; if ((Object)(object)goblinWardWorkZone == (Object)null) { Instances.RemoveAt(num2); } else if (goblinWardWorkZone.GetZoneType() == requestedType) { Vector3 val = goblinWardWorkZone.Center - from; val.y = 0f; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = goblinWardWorkZone; } } } return result; } internal void OpenMenu(Player player) { if (!((Object)(object)player == (Object)null)) { if ((Object)(object)ActiveMenu != (Object)null && (Object)(object)ActiveMenu != (Object)(object)this) { ActiveMenu.CloseMenu(); } if ((Object)(object)GoblinWorkerJob.ActiveWindow != (Object)null) { GoblinWorkerJob.ActiveWindow.CloseWindows(); } if ((Object)(object)GoblinGathererJob.ActiveWindow != (Object)null) { GoblinGathererJob.ActiveWindow.CloseWindows(); } ActiveMenu = this; _menuPlayer = player; _menuOpen = true; ((Behaviour)this).enabled = true; _uiMessage = string.Empty; ((Rect)(ref _windowRect)).x = ((float)Screen.width - ((Rect)(ref _windowRect)).width) * 0.5f; ((Rect)(ref _windowRect)).y = ((float)Screen.height - ((Rect)(ref _windowRect)).height) * 0.5f; SetCursorForMenu(open: true); } } internal void CloseMenu() { _menuOpen = false; _menuPlayer = null; _uiMessage = string.Empty; if ((Object)(object)ActiveMenu == (Object)(object)this) { ActiveMenu = null; } SetCursorForMenu(open: false); ((Behaviour)this).enabled = false; } private void OnGUI() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) if (_menuOpen && !((Object)(object)ActiveMenu != (Object)(object)this)) { _windowRect = GUI.Window(((Object)this).GetInstanceID() ^ 0x4A41, _windowRect, new WindowFunction(DrawWindow), "Рабочая зона фулингов"); } } private void DrawWindow(int windowId) { GUILayout.Space(8f); GUILayout.Label("Радиус Ward: " + Mathf.RoundToInt(Radius) + " м", Array.Empty()); GUILayout.Label("Текущее назначение: " + GetZoneTypeRussianName(GetZoneType()), Array.Empty()); GUILayout.Space(12f); GUILayout.Label("Выберите назначение этой зоны:", Array.Empty()); GUILayout.Space(8f); if (GUILayout.Button("Назначить зону лесорубам", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(36f) })) { SetZoneTypeFromMenu(GoblinWardZoneType.Woodcutter); } if (GUILayout.Button("Назначить зону каменщикам", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(36f) })) { SetZoneTypeFromMenu(GoblinWardZoneType.Stoneworker); } if (GUILayout.Button("Назначить зону собирателям", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(36f) })) { SetZoneTypeFromMenu(GoblinWardZoneType.Gatherer); } if (GUILayout.Button("Назначить спальную зону", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(36f) })) { SetZoneTypeFromMenu(GoblinWardZoneType.Sleeping); } if (GUILayout.Button("Убрать назначение", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) })) { SetZoneTypeFromMenu(GoblinWardZoneType.None); } if (!string.IsNullOrEmpty(_uiMessage)) { GUILayout.Space(8f); GUILayout.Label(_uiMessage, Array.Empty()); } GUILayout.FlexibleSpace(); if (GUILayout.Button("Закрыть", Array.Empty())) { CloseMenu(); } GUI.DragWindow(); } private void SetZoneTypeFromMenu(GoblinWardZoneType zoneType) { if (!((Object)(object)_menuPlayer == (Object)null)) { if (!EnsureOwnership()) { _uiMessage = "Не удалось получить доступ к Ward."; return; } _nview.GetZDO().Set("AutomationByGoblins.Ward.ZoneType", (int)zoneType); _cachedZoneType = zoneType; _nextZoneTypeRefreshTime = Time.time + 0.5f; _uiMessage = ((zoneType == GoblinWardZoneType.None) ? "Назначение рабочей зоны удалено." : ("Зона назначена: " + GetZoneTypeRussianName(zoneType) + ".")); } } private bool EnsureOwnership() { if ((Object)(object)_nview == (Object)null) { _nview = ((Component)this).GetComponent(); } if ((Object)(object)_nview == (Object)null || _nview.GetZDO() == null) { return false; } if (_nview.IsOwner()) { return true; } try { if (ClaimOwnershipMethod != null) { ClaimOwnershipMethod.Invoke(_nview, null); } } catch { return false; } return _nview.IsOwner(); } private void SetCursorForMenu(bool open) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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) if (open) { if (!_cursorStateSaved) { _previousCursorVisible = Cursor.visible; _previousCursorLockMode = Cursor.lockState; _cursorStateSaved = true; } Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; } else if (_cursorStateSaved) { Cursor.visible = _previousCursorVisible; Cursor.lockState = _previousCursorLockMode; _cursorStateSaved = false; } } internal static string GetZoneTypeRussianName(GoblinWardZoneType zoneType) { return zoneType switch { GoblinWardZoneType.Woodcutter => "Лесоруб", GoblinWardZoneType.Stoneworker => "Каменщик", GoblinWardZoneType.Gatherer => "Собиратель", GoblinWardZoneType.Sleeping => "Спальная зона", _ => "Не назначена", }; } } public sealed class GoblinBeechWorkTarget : MonoBehaviour { private const float DefaultTrunkRadius = 0.45f; private const float MinimumTrunkRadius = 0.2f; private const float MaximumTrunkRadius = 0.8f; private static readonly List Instances = new List(); private TreeBase _tree; private Vector3 _position; private float _trunkRadius = 0.45f; private int _registryIndex = -1; internal TreeBase Tree => _tree; internal Vector3 Position => _position; internal float TrunkRadius => _trunkRadius; private void Awake() { //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) _tree = ((Component)this).GetComponent(); _position = ((Component)this).transform.position; _trunkRadius = ResolveTrunkRadius(); _registryIndex = Instances.Count; Instances.Add(this); } private float ResolveTrunkRadius() { //IL_003f: 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) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) CapsuleCollider[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); float num = 0f; foreach (CapsuleCollider val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && val.direction == 1) { Vector3 lossyScale = ((Component)val).transform.lossyScale; float num2 = Mathf.Max(Mathf.Abs(lossyScale.x), Mathf.Abs(lossyScale.z)); num = Mathf.Max(num, val.radius * num2); } } return (num > 0f) ? Mathf.Clamp(num, 0.2f, 0.8f) : 0.45f; } private void OnDestroy() { Unregister(); } private void Unregister() { int registryIndex = _registryIndex; if (registryIndex >= 0 && registryIndex < Instances.Count && Instances[registryIndex] == this) { RemoveAtSwap(registryIndex); return; } registryIndex = Instances.IndexOf(this); if (registryIndex >= 0) { RemoveAtSwap(registryIndex); } _registryIndex = -1; } private static void RemoveAtSwap(int index) { int num = Instances.Count - 1; GoblinBeechWorkTarget goblinBeechWorkTarget = Instances[index]; if (index != num) { GoblinBeechWorkTarget goblinBeechWorkTarget2 = Instances[num]; Instances[index] = goblinBeechWorkTarget2; if (goblinBeechWorkTarget2 != null) { goblinBeechWorkTarget2._registryIndex = index; } } Instances.RemoveAt(num); if (goblinBeechWorkTarget != null) { goblinBeechWorkTarget._registryIndex = -1; } } internal static GoblinBeechWorkTarget FindNearest(Vector3 workerPosition, GoblinWardWorkZone ward) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_008e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ward == (Object)null) { return null; } GoblinBeechWorkTarget result = null; float num = float.MaxValue; for (int num2 = Instances.Count - 1; num2 >= 0; num2--) { GoblinBeechWorkTarget goblinBeechWorkTarget = Instances[num2]; if ((Object)(object)goblinBeechWorkTarget == (Object)null || (Object)(object)goblinBeechWorkTarget._tree == (Object)null) { RemoveAtSwap(num2); } else { Vector3 position = goblinBeechWorkTarget._position; if (ward.Contains(position)) { Vector3 val = position - workerPosition; val.y = 0f; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = goblinBeechWorkTarget; } } } } return result; } internal static bool IsBeech(TreeBase tree) { if ((Object)(object)tree == (Object)null || (Object)(object)((Component)tree).gameObject == (Object)null) { return false; } string name = ((Object)((Component)tree).gameObject).name; return name.StartsWith("Beech", StringComparison.OrdinalIgnoreCase); } } public sealed class GoblinStonePileWorkTarget : MonoBehaviour { private static readonly List Instances = new List(); private Piece _piece; private Vector3 _position; private int _registryIndex = -1; internal Piece TargetPiece => _piece; internal Vector3 Position => _position; private void Awake() { //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) _piece = ((Component)this).GetComponent(); _position = ((Component)this).transform.position; _registryIndex = Instances.Count; Instances.Add(this); } private void OnDestroy() { Unregister(); } private void Unregister() { int registryIndex = _registryIndex; if (registryIndex >= 0 && registryIndex < Instances.Count && Instances[registryIndex] == this) { RemoveAtSwap(registryIndex); return; } registryIndex = Instances.IndexOf(this); if (registryIndex >= 0) { RemoveAtSwap(registryIndex); } _registryIndex = -1; } private static void RemoveAtSwap(int index) { int num = Instances.Count - 1; GoblinStonePileWorkTarget goblinStonePileWorkTarget = Instances[index]; if (index != num) { GoblinStonePileWorkTarget goblinStonePileWorkTarget2 = Instances[num]; Instances[index] = goblinStonePileWorkTarget2; if (goblinStonePileWorkTarget2 != null) { goblinStonePileWorkTarget2._registryIndex = index; } } Instances.RemoveAt(num); if (goblinStonePileWorkTarget != null) { goblinStonePileWorkTarget._registryIndex = -1; } } internal static GoblinStonePileWorkTarget FindNearest(Vector3 workerPosition, GoblinWardWorkZone ward) { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_008e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ward == (Object)null) { return null; } GoblinStonePileWorkTarget result = null; float num = float.MaxValue; for (int num2 = Instances.Count - 1; num2 >= 0; num2--) { GoblinStonePileWorkTarget goblinStonePileWorkTarget = Instances[num2]; if ((Object)(object)goblinStonePileWorkTarget == (Object)null || (Object)(object)goblinStonePileWorkTarget._piece == (Object)null) { RemoveAtSwap(num2); } else { Vector3 position = goblinStonePileWorkTarget._position; if (ward.Contains(position)) { Vector3 val = position - workerPosition; val.y = 0f; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = goblinStonePileWorkTarget; } } } } return result; } internal static bool IsStonePile(Piece piece) { if ((Object)(object)piece == (Object)null || (Object)(object)((Component)piece).gameObject == (Object)null) { return false; } string name = ((Object)((Component)piece).gameObject).name; return string.Equals(name, "stone_pile", StringComparison.OrdinalIgnoreCase) || string.Equals(name, "stone_pile(Clone)", StringComparison.OrdinalIgnoreCase); } } public sealed class GoblinWoodcutterWorkBehaviour : MonoBehaviour { private enum WorkState { Searching, Moving, Working, Resting } private const float LogicInterval = 1f / 30f; private const float MaximumLogicDelta = 0.25f; private const float WardRefreshInterval = 3f; private const float TargetRefreshInterval = 3f; private const float WoodSurfaceInteractionDistance = 1.55f; private const float DefaultWoodTrunkRadius = 0.45f; private const float StoneInteractionDistance = 1.9f; private const float MovementResumeMargin = 0.4f; private const float WorkDuration = 60f; private const float RestDuration = 15f; private const float SuccessfulAttackInterval = 1.35f; private const float FailedAttackRetryInterval = 0.25f; private const string WorkAttackTrigger = "swing_longsword"; private static readonly HashSet ControlledMonsterAiIds = new HashSet(); private static readonly Dictionary WorkByCharacterId = new Dictionary(); private static readonly WaitForSeconds TamePollDelay = new WaitForSeconds(1f); private static readonly MethodInfo BaseAiMoveToMethod = AccessTools.Method(typeof(BaseAI), "MoveTo", new Type[4] { typeof(float), typeof(Vector3), typeof(float), typeof(bool) }, (Type[])null); private static readonly MethodInfo StartAttackMethod = AccessTools.Method(typeof(Humanoid), "StartAttack", new Type[2] { typeof(Character), typeof(bool) }, (Type[])null); private static readonly MethodInfo CharacterSetLookDirMethod = AccessTools.Method(typeof(Character), "SetLookDir", new Type[1] { typeof(Vector3) }, (Type[])null); private static readonly MethodInfo ZSyncSetTriggerMethod = AccessTools.Method(typeof(ZSyncAnimation), "SetTrigger", new Type[1] { typeof(string) }, (Type[])null); private static readonly object[] WorkTriggerArguments = new object[1] { "swing_longsword" }; private static readonly object[] WorkAttackArguments = new object[2] { null, false }; private GoblinWorkerController _controller; private Character _character; private Humanoid _humanoid; private BaseAI _baseAi; private MonsterAI _monsterAi; private ZNetView _nview; private ZSyncAnimation _zanim; private Animator _animator; private Transform _cachedTransform; private GoblinWardWorkZone _ward; private GoblinBeechWorkTarget _woodTarget; private GoblinStonePileWorkTarget _stoneTarget; private GoblinWorkerType _workerType = GoblinWorkerType.Unassigned; private WorkState _state; private object[] _moveToArguments; private object[] _setLookDirArguments; private float _logicAccumulator; private float _wardRefreshTimer; private float _targetRefreshTimer; private float _phaseTimer; private float _attackTimer; private float _interactionDistance; private float _interactionDistanceSqr; private float _resumeMovementDistanceSqr; private int _characterInstanceId; private int _monsterAiInstanceId; private bool _registeredCharacter; private bool _ready; private bool _hasWorkControl; private bool _isMoving; private bool _useBaseAiMoveTo; private bool _useCharacterSetLookDir; private bool _useZSyncTrigger; private bool _loggedAttackProblem; internal bool IsPerformingActiveWork => _ready && _hasWorkControl && _state == WorkState.Working && HasTarget(); internal bool HasOfflineWorkAssignment => _ready && (Object)(object)_character != (Object)null && _character.IsTamed() && (Object)(object)_ward != (Object)null && IsCurrentTargetValid(); internal static bool IsMonsterAiWorkControlled(MonsterAI monsterAi) { return ControlledMonsterAiIds.Count != 0 && (Object)(object)monsterAi != (Object)null && ControlledMonsterAiIds.Contains(((Object)monsterAi).GetInstanceID()); } private void Start() { _controller = ((Component)this).GetComponent(); _character = ((Component)this).GetComponent(); _humanoid = ((Component)this).GetComponent(); _baseAi = ((Component)this).GetComponent(); _monsterAi = ((Component)this).GetComponent(); _nview = ((Component)this).GetComponent(); _cachedTransform = ((Component)this).transform; ((MonoBehaviour)this).StartCoroutine(InitializeWhenReady()); } private IEnumerator InitializeWhenReady() { while ((Object)(object)_controller != (Object)null && _controller.WorkerType == GoblinWorkerType.Unassigned) { yield return null; } if ((Object)(object)_controller == (Object)null || (_controller.WorkerType != GoblinWorkerType.Wood && _controller.WorkerType != GoblinWorkerType.Stone)) { ((Behaviour)this).enabled = false; yield break; } _workerType = _controller.WorkerType; _interactionDistance = ((_workerType == GoblinWorkerType.Stone) ? 1.9f : 2f); RefreshInteractionDistance(); ((Behaviour)this).enabled = false; while ((Object)(object)_nview == (Object)null || _nview.GetZDO() == null) { if ((Object)(object)_nview == (Object)null) { _nview = ((Component)this).GetComponent(); } yield return null; } while ((Object)(object)_character != (Object)null && !_character.IsTamed()) { yield return TamePollDelay; } if (!((Object)(object)_character == (Object)null)) { _zanim = ((Component)this).GetComponent(); if ((Object)(object)_zanim == (Object)null) { _zanim = ((Component)this).GetComponentInChildren(true); } _animator = ((Component)this).GetComponentInChildren(true); _useBaseAiMoveTo = (Object)(object)_baseAi != (Object)null && BaseAiMoveToMethod != null; _useCharacterSetLookDir = (Object)(object)_character != (Object)null && CharacterSetLookDirMethod != null; _useZSyncTrigger = (Object)(object)_zanim != (Object)null && ZSyncSetTriggerMethod != null; if (_useBaseAiMoveTo) { _moveToArguments = new object[4]; _moveToArguments[2] = _interactionDistance * 0.75f; _moveToArguments[3] = false; } if (_useCharacterSetLookDir) { _setLookDirArguments = new object[1]; } _characterInstanceId = ((Object)_character).GetInstanceID(); _monsterAiInstanceId = (((Object)(object)_monsterAi != (Object)null) ? ((Object)_monsterAi).GetInstanceID() : 0); WorkByCharacterId[_characterInstanceId] = this; _registeredCharacter = true; _state = WorkState.Searching; _wardRefreshTimer = 0f; _targetRefreshTimer = 0f; _logicAccumulator = 1f / 30f; _ready = true; ((Behaviour)this).enabled = true; } } private void OnDestroy() { if (_monsterAiInstanceId != 0) { ControlledMonsterAiIds.Remove(_monsterAiInstanceId); } if (_registeredCharacter) { WorkByCharacterId.Remove(_characterInstanceId); _registeredCharacter = false; } } private void Update() { _logicAccumulator += Time.deltaTime; if (!(_logicAccumulator < 1f / 30f)) { float logicAccumulator = _logicAccumulator; _logicAccumulator = 0f; TickWork(logicAccumulator); } } private void TickWork(float delta) { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) if (!_ready || (Object)(object)_character == (Object)null || (Object)(object)_nview == (Object)null || _nview.GetZDO() == null || !_nview.IsOwner()) { ReleaseWorkControl(); return; } if (GoblinNightRestJob.IsNightRestActive(_character) || ((Object)(object)EnvMan.instance != (Object)null && EnvMan.IsNight())) { ReleaseWorkControl(); return; } _wardRefreshTimer -= delta; if (_wardRefreshTimer <= 0f) { _wardRefreshTimer = 3f; GoblinWardWorkZone goblinWardWorkZone = GoblinWardWorkZone.FindNearest(_cachedTransform.position, GetRequiredWardZoneType()); if ((Object)(object)goblinWardWorkZone != (Object)(object)_ward) { _ward = goblinWardWorkZone; ClearTarget(); _targetRefreshTimer = 0f; _state = WorkState.Searching; } } if ((Object)(object)_ward == (Object)null) { ReleaseWorkControl(); return; } SetWorkControl(active: true); _targetRefreshTimer -= delta; if (!IsCurrentTargetValid()) { ClearTarget(); } if (!HasTarget() && _targetRefreshTimer <= 0f) { _targetRefreshTimer = 3f; FindTarget(); _state = (HasTarget() ? WorkState.Moving : WorkState.Searching); } if (!HasTarget()) { StopMoving(); return; } Vector3 targetPosition = GetTargetPosition(); Vector3 val = targetPosition - _cachedTransform.position; val.y = 0f; float num = ((_state == WorkState.Working || _state == WorkState.Resting) ? _resumeMovementDistanceSqr : _interactionDistanceSqr); if (((Vector3)(ref val)).sqrMagnitude > num) { _state = WorkState.Moving; MoveToTree(targetPosition, Mathf.Min(delta, 0.25f)); return; } StopMoving(); if (_state != WorkState.Working && _state != WorkState.Resting) { FaceTargetImmediately(targetPosition); BeginWorkPhase(); } if (_state == WorkState.Working) { UpdateWorkPhase(delta); } else if (_state == WorkState.Resting) { _phaseTimer -= delta; if (_phaseTimer <= 0f) { BeginWorkPhase(); } } } private bool IsCurrentTargetValid() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_ward == (Object)null) { return false; } if (_workerType == GoblinWorkerType.Wood) { return (Object)(object)_woodTarget != (Object)null && (Object)(object)_woodTarget.Tree != (Object)null && _ward.Contains(_woodTarget.Position); } if (_workerType == GoblinWorkerType.Stone) { return (Object)(object)_stoneTarget != (Object)null && (Object)(object)_stoneTarget.TargetPiece != (Object)null && _ward.Contains(_stoneTarget.Position); } return false; } private GoblinWardZoneType GetRequiredWardZoneType() { return (_workerType != GoblinWorkerType.Stone) ? GoblinWardZoneType.Woodcutter : GoblinWardZoneType.Stoneworker; } private bool HasTarget() { return (_workerType == GoblinWorkerType.Wood) ? ((Object)(object)_woodTarget != (Object)null) : ((Object)(object)_stoneTarget != (Object)null); } private Vector3 GetTargetPosition() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) return (_workerType == GoblinWorkerType.Wood) ? _woodTarget.Position : _stoneTarget.Position; } private void FindTarget() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) ClearTarget(); if (_workerType == GoblinWorkerType.Wood) { _woodTarget = GoblinBeechWorkTarget.FindNearest(_cachedTransform.position, _ward); } else if (_workerType == GoblinWorkerType.Stone) { _stoneTarget = GoblinStonePileWorkTarget.FindNearest(_cachedTransform.position, _ward); } RefreshInteractionDistance(); } private void ClearTarget() { _woodTarget = null; _stoneTarget = null; RefreshInteractionDistance(); } private void RefreshInteractionDistance() { if (_workerType == GoblinWorkerType.Stone) { _interactionDistance = 1.9f; } else { float num = (((Object)(object)_woodTarget != (Object)null) ? _woodTarget.TrunkRadius : 0.45f); _interactionDistance = 1.55f + num; } _interactionDistanceSqr = _interactionDistance * _interactionDistance; float num2 = _interactionDistance + 0.4f; _resumeMovementDistanceSqr = num2 * num2; if (_moveToArguments != null) { _moveToArguments[2] = _interactionDistance * 0.75f; } } private void MoveToTree(Vector3 targetPosition, float delta) { //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_006e: 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_0029: Unknown result type (might be due to invalid IL or missing references) _isMoving = true; if (_useBaseAiMoveTo) { try { _moveToArguments[0] = delta; _moveToArguments[1] = targetPosition; BaseAiMoveToMethod.Invoke(_baseAi, _moveToArguments); return; } catch { _useBaseAiMoveTo = false; _moveToArguments = null; } } Vector3 moveDir = targetPosition - _cachedTransform.position; moveDir.y = 0f; if (((Vector3)(ref moveDir)).sqrMagnitude > 0.001f) { ((Vector3)(ref moveDir)).Normalize(); _character.SetMoveDir(moveDir); } } private void StopMoving() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (_isMoving && !((Object)(object)_character == (Object)null)) { _character.SetMoveDir(Vector3.zero); _isMoving = false; } } private void FaceTargetImmediately(Vector3 targetPosition) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_003f: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) Vector3 val = targetPosition - _cachedTransform.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude <= 0.001f) { return; } ((Vector3)(ref val)).Normalize(); Quaternion rotation = Quaternion.LookRotation(val); _cachedTransform.rotation = rotation; if (!_useCharacterSetLookDir) { return; } try { _setLookDirArguments[0] = val; CharacterSetLookDirMethod.Invoke(_character, _setLookDirArguments); } catch { _useCharacterSetLookDir = false; _setLookDirArguments = null; } } private void BeginWorkPhase() { _state = WorkState.Working; _phaseTimer = 60f; _attackTimer = 0f; } private void UpdateWorkPhase(float delta) { _phaseTimer -= delta; _attackTimer -= delta; if (_attackTimer <= 0f) { bool flag = TryPerformWorkAttack(); if (_state != WorkState.Working) { return; } _attackTimer = (flag ? 1.35f : 0.25f); } if (_phaseTimer <= 0f) { _state = WorkState.Resting; _phaseTimer = 15f; StopMoving(); } } private bool TryPerformWorkAttack() { if (!PrepareForWorkAttack()) { return false; } bool flag = false; if ((Object)(object)_humanoid != (Object)null && StartAttackMethod != null) { try { object obj = StartAttackMethod.Invoke(_humanoid, WorkAttackArguments); flag = StartAttackMethod.ReturnType != typeof(bool) || (obj != null && (bool)obj); } catch (Exception exception) { LogAttackProblemOnce("Worker real attack failed: " + GetInnermostMessage(exception)); } } bool flag2 = TryPlayWorkSwing(); return flag || flag2; } private bool PrepareForWorkAttack() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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) //IL_0085: Unknown result type (might be due to invalid IL or missing references) if (!IsCurrentTargetValid()) { ClearTarget(); _targetRefreshTimer = 0f; _state = WorkState.Searching; return false; } Vector3 targetPosition = GetTargetPosition(); Vector3 val = targetPosition - _cachedTransform.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude > _interactionDistanceSqr) { _state = WorkState.Moving; _attackTimer = 0f; return false; } StopMoving(); FaceTargetImmediately(targetPosition); return true; } private bool TryPlayWorkSwing() { bool flag = false; if (_useZSyncTrigger) { try { ZSyncSetTriggerMethod.Invoke(_zanim, WorkTriggerArguments); flag = true; } catch (Exception exception) { _useZSyncTrigger = false; LogAttackProblemOnce("Worker synchronized swing failed: " + GetInnermostMessage(exception)); } } if ((Object)(object)_animator != (Object)null) { _animator.SetTrigger("swing_longsword"); flag = true; } if (!flag) { LogAttackProblemOnce("Worker Goblin has no usable animation component."); return false; } return true; } private void SetWorkControl(bool active) { if (_hasWorkControl == active) { return; } _hasWorkControl = active; if (_monsterAiInstanceId != 0) { if (active) { ControlledMonsterAiIds.Add(_monsterAiInstanceId); _isMoving = true; } else { ControlledMonsterAiIds.Remove(_monsterAiInstanceId); } } } private void ReleaseWorkControl() { if (_hasWorkControl) { StopMoving(); SetWorkControl(active: false); } _state = WorkState.Searching; ClearTarget(); } private void LogAttackProblemOnce(string message) { if (!_loggedAttackProblem) { _loggedAttackProblem = true; AutomationByGoblinsPlugin.ModLog.LogWarning((object)message); } } private static string GetInnermostMessage(Exception exception) { Exception ex = exception; while (ex.InnerException != null) { ex = ex.InnerException; } return ex.Message; } } [HarmonyPatch(typeof(PrivateArea), "Awake")] internal static class WardWorkZoneAttachPatch { private static void Postfix(PrivateArea __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).GetComponent() != (Object)null)) { ((Component)__instance).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(PrivateArea), "GetHoverText")] internal static class WardWorkZoneHoverPatch { internal static GoblinWardWorkZone HoveredZone; internal static int HoveredFrame = -100; private static void Postfix(PrivateArea __instance, ref string __result) { if (!((Object)(object)__instance == (Object)null)) { GoblinWardWorkZone component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null)) { HoveredZone = component; HoveredFrame = Time.frameCount; WorkerHoverCapturePatch.HoveredWorker = null; WorkerHoverCapturePatch.HoveredFrame = -100; GathererHoverCapturePatch.HoveredGatherer = null; GathererHoverCapturePatch.HoveredFrame = -100; __result = __result + "\nРабочая зона: " + GoblinWardWorkZone.GetZoneTypeRussianName(component.GetZoneType()) + "\n[Alt+Y] Настроить рабочую зону"; } } } } [HarmonyPatch(typeof(Tameable), "GetHoverText")] internal static class WardHoverClearWhenWorkerHoveredPatch { private static void Postfix(Tameable __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).GetComponent() == (Object)null)) { WardWorkZoneHoverPatch.HoveredZone = null; WardWorkZoneHoverPatch.HoveredFrame = -100; } } } [HarmonyPatch(typeof(Player), "Update")] internal static class WardWorkZoneHotkeyPatch { private static void Postfix(Player __instance) { if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } if ((Object)(object)GoblinWardWorkZone.ActiveMenu != (Object)null && Input.GetKeyDown((KeyCode)27)) { GoblinWardWorkZone.ActiveMenu.CloseMenu(); } else if ((Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307)) && Input.GetKeyDown((KeyCode)121)) { GoblinWardWorkZone hoveredZone = WardWorkZoneHoverPatch.HoveredZone; if (!((Object)(object)hoveredZone == (Object)null) && Time.frameCount - WardWorkZoneHoverPatch.HoveredFrame <= 5) { hoveredZone.OpenMenu(__instance); } } } } [HarmonyPatch(typeof(InventoryGui), "IsVisible")] internal static class WardWorkZoneInputBlockPatch { private static void Postfix(ref bool __result) { if ((Object)(object)GoblinWardWorkZone.ActiveMenu != (Object)null) { __result = true; } } } [HarmonyPatch(typeof(TreeBase), "Awake")] internal static class BeechWorkTargetAttachPatch { private static void Postfix(TreeBase __instance) { if (!((Object)(object)__instance == (Object)null) && GoblinBeechWorkTarget.IsBeech(__instance) && !((Object)(object)((Component)__instance).GetComponent() != (Object)null)) { ((Component)__instance).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(Piece), "Awake")] internal static class StonePileWorkTargetAttachPatch { private static void Postfix(Piece __instance) { if (!((Object)(object)__instance == (Object)null) && GoblinStonePileWorkTarget.IsStonePile(__instance) && (Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(GoblinWorkerController), "Start")] internal static class WorkerWorkBehaviourAttachPatch { private static void Postfix(GoblinWorkerController __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).GetComponent() != (Object)null)) { ((Component)__instance).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(MonsterAI), "UpdateAI")] internal static class WorkerMonsterAiControlPatch { private static bool Prefix(MonsterAI __instance) { return !GoblinWoodcutterWorkBehaviour.IsMonsterAiWorkControlled(__instance); } } [HarmonyPatch(typeof(Attack), "OnAttackTrigger")] internal static class TamedGoblinHarmlessAttackPatch { private struct SuppressionState { internal bool TerrainChanged; internal bool WeaponChanged; internal Attack Attack; internal bool OriginalHitTerrain; internal SharedData SharedData; internal DamageTypes OriginalDamages; internal DamageTypes OriginalDamagesPerLevel; internal float OriginalAttackForce; internal GameObject OriginalSpawnOnHitTerrain; } private static readonly FieldInfo AttackCharacterField = AccessTools.Field(typeof(Attack), "m_character"); private static readonly FieldInfo AttackWeaponField = AccessTools.Field(typeof(Attack), "m_weapon"); private static readonly FieldInfo AttackHitTerrainField = AccessTools.Field(typeof(Attack), "m_hitTerrain"); private static void Prefix(Attack __instance, ref SuppressionState __state) { //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) if (__instance == null || AttackCharacterField == null || AttackHitTerrainField == null) { return; } object? value = AttackCharacterField.GetValue(__instance); Character attacker = (Character)((value is Character) ? value : null); if (!TamedGoblinDamageGuard.IsProtected(attacker)) { return; } __state.Attack = __instance; __state.OriginalHitTerrain = (bool)AttackHitTerrainField.GetValue(__instance); AttackHitTerrainField.SetValue(__instance, false); __state.TerrainChanged = true; if (!(AttackWeaponField == null)) { object? value2 = AttackWeaponField.GetValue(__instance); ItemData val = (ItemData)((value2 is ItemData) ? value2 : null); if (val != null && val.m_shared != null) { SharedData val2 = (__state.SharedData = val.m_shared); __state.OriginalDamages = val2.m_damages; __state.OriginalDamagesPerLevel = val2.m_damagesPerLevel; __state.OriginalAttackForce = val2.m_attackForce; __state.OriginalSpawnOnHitTerrain = val2.m_spawnOnHitTerrain; val2.m_damages = default(DamageTypes); val2.m_damagesPerLevel = default(DamageTypes); val2.m_attackForce = 0f; val2.m_spawnOnHitTerrain = null; __state.WeaponChanged = true; } } } private static Exception Finalizer(Exception __exception, SuppressionState __state) { //IL_0021: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) if (__state.WeaponChanged && __state.SharedData != null) { __state.SharedData.m_damages = __state.OriginalDamages; __state.SharedData.m_damagesPerLevel = __state.OriginalDamagesPerLevel; __state.SharedData.m_attackForce = __state.OriginalAttackForce; __state.SharedData.m_spawnOnHitTerrain = __state.OriginalSpawnOnHitTerrain; } if (__state.TerrainChanged && __state.Attack != null && AttackHitTerrainField != null) { AttackHitTerrainField.SetValue(__state.Attack, __state.OriginalHitTerrain); } return __exception; } } internal static class TamedGoblinDamageGuard { internal static bool IsProtected(Character attacker) { if ((Object)(object)attacker == (Object)null || !attacker.IsTamed()) { return false; } string text = ((Object)((Component)attacker).gameObject).name; if (text.EndsWith("(Clone)", StringComparison.Ordinal)) { text = text.Substring(0, text.Length - "(Clone)".Length); } return string.Equals(text, "Goblin", StringComparison.Ordinal); } internal static void Suppress(HitData hit) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) if (hit != null && IsProtected(hit.GetAttacker())) { hit.m_damage = default(DamageTypes); hit.m_pushForce = 0f; } } } [HarmonyPatch] internal static class TamedGoblinZeroReceivedDamagePatch { private static IEnumerable TargetMethods() { HashSet targets = new HashSet(); Type[] gameTypes; try { gameTypes = typeof(Character).Assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { ReflectionTypeLoadException exception = ex; gameTypes = exception.Types; } Type[] parameterTypes = new Type[1] { typeof(HitData) }; int i = 0; while (i < gameTypes.Length) { Type gameType = gameTypes[i]; if (!(gameType == null) && !gameType.IsInterface) { MethodInfo damageMethod = gameType.GetMethod("Damage", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null); if (!(damageMethod == null) && !damageMethod.IsAbstract && targets.Add(damageMethod)) { yield return damageMethod; } } int num = i + 1; i = num; } } private static void Prefix(HitData hit) { TamedGoblinDamageGuard.Suppress(hit); } } [Flags] internal enum GathererSelection { None = 0, Raspberry = 1, Blueberry = 2, Cloudberry = 4, All = 7 } internal enum GathererFruitType { Raspberry = 1, Blueberry, Cloudberry } public sealed class GoblinBerryBushTarget : MonoBehaviour { private static readonly List Instances = new List(); private static readonly FieldInfo PickedField = AccessTools.Field(typeof(Pickable), "m_picked"); private static readonly MethodInfo CanBePickedMethod = AccessTools.Method(typeof(Pickable), "CanBePicked", Type.EmptyTypes, (Type[])null); private Pickable _pickable; private GathererFruitType _fruitType; private Vector3 _position; private int _registryIndex = -1; private bool _isPicked; internal GathererFruitType FruitType => _fruitType; internal Vector3 Position => _position; internal int YieldAmount => ((Object)(object)_pickable == (Object)null) ? 1 : Mathf.Max(1, _pickable.m_amount); internal bool IsRipe => (Object)(object)_pickable != (Object)null && ((Behaviour)_pickable).enabled && !_isPicked; private void Awake() { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) _pickable = ((Component)this).GetComponent(); if ((Object)(object)_pickable == (Object)null || !TryResolveFruitType(((Object)((Component)this).gameObject).name, out _fruitType)) { ((Behaviour)this).enabled = false; return; } _position = ((Component)this).transform.position; _isPicked = ReadPickedState(_pickable); _registryIndex = Instances.Count; Instances.Add(this); } private void OnDestroy() { Unregister(); } private void Unregister() { int registryIndex = _registryIndex; if (registryIndex >= 0 && registryIndex < Instances.Count && Instances[registryIndex] == this) { RemoveAtSwap(registryIndex); return; } registryIndex = Instances.IndexOf(this); if (registryIndex >= 0) { RemoveAtSwap(registryIndex); } _registryIndex = -1; } private static void RemoveAtSwap(int index) { int num = Instances.Count - 1; GoblinBerryBushTarget goblinBerryBushTarget = Instances[index]; if (index != num) { GoblinBerryBushTarget goblinBerryBushTarget2 = Instances[num]; Instances[index] = goblinBerryBushTarget2; if (goblinBerryBushTarget2 != null) { goblinBerryBushTarget2._registryIndex = index; } } Instances.RemoveAt(num); if (goblinBerryBushTarget != null) { goblinBerryBushTarget._registryIndex = -1; } } internal bool TryHarvest() { if (!IsRipe) { return false; } try { _pickable.SetPicked(true); _isPicked = true; return true; } catch (Exception ex) { AutomationByGoblinsPlugin.ModLog.LogWarning((object)("Gatherer could not mark " + ((Object)((Component)this).gameObject).name + " as picked: " + ex.Message)); return false; } } internal void UpdatePickedState(bool picked) { _isPicked = picked; } private static bool ReadPickedState(Pickable pickable) { if ((Object)(object)pickable == (Object)null) { return true; } if (PickedField != null) { try { if (PickedField.GetValue(pickable) is bool result) { return result; } } catch { } } if (CanBePickedMethod != null) { try { object obj2 = CanBePickedMethod.Invoke(pickable, null); if (obj2 is bool) { return !(bool)obj2; } } catch { } } return false; } internal static GoblinBerryBushTarget FindNearest(Vector3 workerPosition, GoblinWardWorkZone ward, GathererSelection selection, GoblinGathererJob job) { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: 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_00d2: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ward == (Object)null || selection == GathererSelection.None || (Object)(object)job == (Object)null) { return null; } GoblinBerryBushTarget result = null; float num = float.MaxValue; for (int num2 = Instances.Count - 1; num2 >= 0; num2--) { GoblinBerryBushTarget goblinBerryBushTarget = Instances[num2]; if ((Object)(object)goblinBerryBushTarget == (Object)null || (Object)(object)goblinBerryBushTarget._pickable == (Object)null) { RemoveAtSwap(num2); } else if (goblinBerryBushTarget.IsRipe && IsSelected(selection, goblinBerryBushTarget._fruitType) && ward.Contains(goblinBerryBushTarget._position) && job.CanStore(goblinBerryBushTarget._fruitType, goblinBerryBushTarget.YieldAmount)) { Vector3 val = goblinBerryBushTarget._position - workerPosition; val.y = 0f; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = goblinBerryBushTarget; } } } return result; } internal static bool IsSupportedBush(Pickable pickable) { GathererFruitType fruitType; return (Object)(object)pickable != (Object)null && TryResolveFruitType(((Object)((Component)pickable).gameObject).name, out fruitType); } internal static bool IsSelected(GathererSelection selection, GathererFruitType fruitType) { GathererSelection gathererSelection = ToSelection(fruitType); return gathererSelection != GathererSelection.None && (selection & gathererSelection) != 0; } private static GathererSelection ToSelection(GathererFruitType fruitType) { return fruitType switch { GathererFruitType.Raspberry => GathererSelection.Raspberry, GathererFruitType.Blueberry => GathererSelection.Blueberry, GathererFruitType.Cloudberry => GathererSelection.Cloudberry, _ => GathererSelection.None, }; } private static bool TryResolveFruitType(string objectName, out GathererFruitType fruitType) { fruitType = GathererFruitType.Raspberry; if (string.IsNullOrEmpty(objectName)) { return false; } int num = objectName.IndexOf("(Clone)", StringComparison.Ordinal); if (num >= 0) { objectName = objectName.Substring(0, num); } objectName = objectName.Trim(); if (string.Equals(objectName, "RaspberryBush", StringComparison.OrdinalIgnoreCase)) { fruitType = GathererFruitType.Raspberry; return true; } if (string.Equals(objectName, "BlueberryBush", StringComparison.OrdinalIgnoreCase)) { fruitType = GathererFruitType.Blueberry; return true; } if (string.Equals(objectName, "CloudberryBush", StringComparison.OrdinalIgnoreCase)) { fruitType = GathererFruitType.Cloudberry; return true; } return false; } } public sealed class GoblinGathererJob : MonoBehaviour { private enum GathererState { Searching, MovingToBush, Harvesting, WanderWaiting, Wandering } private const string SelectionZdoKey = "AutomationByGoblins.Gatherer.Selection"; private const string RaspberryStoredZdoKey = "AutomationByGoblins.Gatherer.Raspberry"; private const string BlueberryStoredZdoKey = "AutomationByGoblins.Gatherer.Blueberry"; private const string CloudberryStoredZdoKey = "AutomationByGoblins.Gatherer.Cloudberry"; private const int SlotCapacity = 50; private const float LogicInterval = 0.1f; private const float WardRefreshInterval = 3f; private const float TargetRefreshInterval = 2f; private const float ApproachDistance = 1.35f; private const float ApproachDistanceSqr = 1.8225001f; private const float HarvestDelay = 1f; private const float PostHarvestSearchDelay = 0.8f; private const float WanderStopDistance = 1.4f; private const float WanderStopDistanceSqr = 1.9599999f; private const float WanderPointLifetime = 12f; private static readonly HashSet ControlledMonsterAiIds = new HashSet(); private static readonly Dictionary WorkByCharacterId = new Dictionary(); private static readonly WaitForSeconds TamePollDelay = new WaitForSeconds(1f); private static readonly MethodInfo BaseAiMoveToMethod = AccessTools.Method(typeof(BaseAI), "MoveTo", new Type[4] { typeof(float), typeof(Vector3), typeof(float), typeof(bool) }, (Type[])null); private static readonly MethodInfo CharacterSetLookDirMethod = AccessTools.Method(typeof(Character), "SetLookDir", new Type[1] { typeof(Vector3) }, (Type[])null); private static readonly MethodInfo InventoryAddItemMethod = AccessTools.Method(typeof(Inventory), "AddItem", new Type[1] { typeof(ItemData) }, (Type[])null); private static readonly MethodInfo ClaimOwnershipMethod = AccessTools.Method(typeof(ZNetView), "ClaimOwnership", (Type[])null, (Type[])null); private GoblinWorkerController _controller; private Character _character; private Humanoid _humanoid; private Tameable _tameable; private BaseAI _baseAi; private MonsterAI _monsterAi; private ZNetView _nview; private Transform _cachedTransform; private Transform _gatherPoseBone; private GoblinWardWorkZone _ward; private GoblinBerryBushTarget _target; private GathererSelection _selection = GathererSelection.All; private GathererState _state = GathererState.Searching; private Vector3 _wanderPoint; private object[] _moveToArguments; private object[] _setLookDirArguments; private float _logicAccumulator; private float _wardRefreshTimer; private float _targetRefreshTimer; private float _stateTimer; private float _remoteSyncTimer; private float _suppressDamageUntil; private int _raspberryStored; private int _blueberryStored; private int _cloudberryStored; private int _monsterAiInstanceId; private int _characterInstanceId; private bool _ready; private bool _hasWorkControl; private bool _isMoving; private bool _useBaseAiMoveTo; private bool _useCharacterSetLookDir; private bool _registeredCharacter; private bool _settingsWindowOpen; private bool _storageWindowOpen; private Player _windowPlayer; private string _uiMessage = string.Empty; private Rect _settingsWindowRect = new Rect(0f, 0f, 480f, 390f); private Rect _storageWindowRect = new Rect(0f, 0f, 570f, 340f); private bool _cursorStateSaved; private bool _previousCursorVisible; private CursorLockMode _previousCursorLockMode; internal static GoblinGathererJob ActiveWindow; internal bool IsUsableGatherer => _ready && (Object)(object)_controller != (Object)null && _controller.WorkerType == GoblinWorkerType.Gatherer && (Object)(object)_character != (Object)null && _character.IsTamed(); internal static bool IsMonsterAiWorkControlled(MonsterAI monsterAi) { return (Object)(object)monsterAi != (Object)null && ControlledMonsterAiIds.Contains(((Object)monsterAi).GetInstanceID()); } internal static bool ShouldSuppressGathererDamage(Character attacker) { if ((Object)(object)attacker == (Object)null || WorkByCharacterId.Count == 0) { return false; } GoblinGathererJob value; return WorkByCharacterId.TryGetValue(((Object)attacker).GetInstanceID(), out value) && (Object)(object)value != (Object)null && value._hasWorkControl && (value._state == GathererState.Harvesting || Time.time < value._suppressDamageUntil); } private void Start() { _controller = ((Component)this).GetComponent(); _character = ((Component)this).GetComponent(); _humanoid = ((Component)this).GetComponent(); _tameable = ((Component)this).GetComponent(); _baseAi = ((Component)this).GetComponent(); _monsterAi = ((Component)this).GetComponent(); _nview = ((Component)this).GetComponent(); _cachedTransform = ((Component)this).transform; ((MonoBehaviour)this).StartCoroutine(InitializeWhenReady()); } private IEnumerator InitializeWhenReady() { while ((Object)(object)_controller == (Object)null || _controller.WorkerType == GoblinWorkerType.Unassigned || (Object)(object)_nview == (Object)null || _nview.GetZDO() == null) { if ((Object)(object)_controller == (Object)null) { _controller = ((Component)this).GetComponent(); } if ((Object)(object)_nview == (Object)null) { _nview = ((Component)this).GetComponent(); } yield return null; } if (_controller.WorkerType != GoblinWorkerType.Gatherer) { ((Behaviour)this).enabled = false; yield break; } LoadStateFromZdo(); ((Behaviour)this).enabled = false; while ((Object)(object)_character != (Object)null && !_character.IsTamed()) { if ((Object)(object)_tameable == (Object)null) { _tameable = ((Component)this).GetComponent(); } yield return TamePollDelay; } if (!((Object)(object)_character == (Object)null)) { _gatherPoseBone = FindChildByName("spine2"); _useBaseAiMoveTo = (Object)(object)_baseAi != (Object)null && BaseAiMoveToMethod != null; _useCharacterSetLookDir = (Object)(object)_character != (Object)null && CharacterSetLookDirMethod != null; if (_useBaseAiMoveTo) { _moveToArguments = new object[4]; _moveToArguments[3] = false; } if (_useCharacterSetLookDir) { _setLookDirArguments = new object[1]; } _monsterAiInstanceId = (((Object)(object)_monsterAi != (Object)null) ? ((Object)_monsterAi).GetInstanceID() : 0); _characterInstanceId = ((Object)_character).GetInstanceID(); WorkByCharacterId[_characterInstanceId] = this; _registeredCharacter = true; _logicAccumulator = 0.1f; _wardRefreshTimer = 0f; _targetRefreshTimer = 0f; _ready = true; ((Behaviour)this).enabled = true; } } private void Update() { if ((_settingsWindowOpen || _storageWindowOpen) && Input.GetKeyDown((KeyCode)27)) { CloseWindows(); } if (!_ready || (Object)(object)_character == (Object)null || !_character.IsTamed()) { ReleaseWorkControl(); } else if ((Object)(object)_nview == (Object)null || _nview.GetZDO() == null) { ReleaseWorkControl(); } else if (!_nview.IsOwner()) { ReleaseWorkControl(); _remoteSyncTimer += Time.deltaTime; if (_remoteSyncTimer >= 1f) { _remoteSyncTimer = 0f; LoadStateFromZdo(); } } else if (GoblinNightRestJob.IsNightRestActive(_character)) { ReleaseWorkControl(); } else { _logicAccumulator += Time.deltaTime; if (!(_logicAccumulator < 0.1f)) { float delta = Mathf.Min(_logicAccumulator, 0.25f); _logicAccumulator = 0f; TickGatherer(delta); } } } private void TickGatherer(float delta) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_017e: 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_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) _wardRefreshTimer -= delta; if (_wardRefreshTimer <= 0f) { _wardRefreshTimer = 3f; GoblinWardWorkZone goblinWardWorkZone = GoblinWardWorkZone.FindNearest(_cachedTransform.position, GoblinWardZoneType.Gatherer); if ((Object)(object)goblinWardWorkZone != (Object)(object)_ward) { _ward = goblinWardWorkZone; ClearTarget(); _state = GathererState.Searching; _targetRefreshTimer = 0f; } } if ((Object)(object)_ward == (Object)null) { ReleaseWorkControl(); return; } SetWorkControl(controlled: true); if (_state == GathererState.Harvesting) { UpdateHarvest(delta); return; } _targetRefreshTimer -= delta; if (!IsCurrentTargetValid()) { ClearTarget(); } if ((Object)(object)_target == (Object)null && _targetRefreshTimer <= 0f) { _targetRefreshTimer = 2f; _target = GoblinBerryBushTarget.FindNearest(_cachedTransform.position, _ward, _selection, this); if ((Object)(object)_target != (Object)null) { _state = GathererState.MovingToBush; } } if ((Object)(object)_target == (Object)null) { UpdateWandering(delta); return; } Vector3 position = _target.Position; Vector3 val = position - _cachedTransform.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude > 1.8225001f) { _state = GathererState.MovingToBush; MoveTo(position, 0.945f, delta); return; } StopMoving(); FaceTarget(position); _state = GathererState.Harvesting; _stateTimer = 1f; _suppressDamageUntil = Time.time + 1f + 0.5f; } private void UpdateHarvest(float delta) { //IL_0048: 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_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_008a: Unknown result type (might be due to invalid IL or missing references) _stateTimer -= delta; if (_stateTimer > 0f) { return; } GoblinBerryBushTarget target = _target; if ((Object)(object)target != (Object)null && IsCurrentTargetValid()) { Vector3 val = target.Position - _cachedTransform.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude > 1.8225001f) { _state = GathererState.MovingToBush; return; } FaceTarget(target.Position); int yieldAmount = target.YieldAmount; if (CanStore(target.FruitType, yieldAmount) && target.TryHarvest()) { AddStored(target.FruitType, yieldAmount); SaveStateToZdo(); } } ClearTarget(); _state = GathererState.Searching; _targetRefreshTimer = 0.8f; } private bool IsCurrentTargetValid() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) return (Object)(object)_target != (Object)null && (Object)(object)_ward != (Object)null && _target.IsRipe && _ward.Contains(_target.Position) && GoblinBerryBushTarget.IsSelected(_selection, _target.FruitType) && CanStore(_target.FruitType, _target.YieldAmount); } private void ClearTarget() { _target = null; } private void UpdateWandering(float delta) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_0100: Unknown result type (might be due to invalid IL or missing references) if (_state != GathererState.Wandering && _state != GathererState.WanderWaiting) { StopMoving(); _state = GathererState.WanderWaiting; _stateTimer = Random.Range(2f, 5f); } if (_state == GathererState.WanderWaiting) { _stateTimer -= delta; if (_stateTimer <= 0f) { ChooseWanderPoint(); } return; } Vector3 val = _wanderPoint - _cachedTransform.position; val.y = 0f; _stateTimer -= delta; if (((Vector3)(ref val)).sqrMagnitude <= 1.9599999f || _stateTimer <= 0f) { StopMoving(); _state = GathererState.WanderWaiting; _stateTimer = Random.Range(2f, 6f); } else { MoveTo(_wanderPoint, 1.4f, delta); } } private void ChooseWanderPoint() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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) float num = Mathf.Max(2f, _ward.Radius * 0.78f); float num2 = Random.Range(0f, (float)Math.PI * 2f); float num3 = Mathf.Sqrt(Random.value) * num; Vector3 center = _ward.Center; _wanderPoint = new Vector3(center.x + Mathf.Cos(num2) * num3, _cachedTransform.position.y, center.z + Mathf.Sin(num2) * num3); _state = GathererState.Wandering; _stateTimer = 12f; } private void MoveTo(Vector3 destination, float stopDistance, float delta) { //IL_006b: 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_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_0029: Unknown result type (might be due to invalid IL or missing references) _isMoving = true; if (_useBaseAiMoveTo) { try { _moveToArguments[0] = delta; _moveToArguments[1] = destination; _moveToArguments[2] = stopDistance; BaseAiMoveToMethod.Invoke(_baseAi, _moveToArguments); return; } catch { _useBaseAiMoveTo = false; _moveToArguments = null; } } Vector3 val = destination - _cachedTransform.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude > 0.001f) { _character.SetMoveDir(((Vector3)(ref val)).normalized); } } private void StopMoving() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (_isMoving && !((Object)(object)_character == (Object)null)) { _character.SetMoveDir(Vector3.zero); _isMoving = false; } } private void FaceTarget(Vector3 targetPosition) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_0045: 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_0064: Unknown result type (might be due to invalid IL or missing references) Vector3 val = targetPosition - _cachedTransform.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude <= 0.001f) { return; } ((Vector3)(ref val)).Normalize(); _cachedTransform.rotation = Quaternion.LookRotation(val); if (!_useCharacterSetLookDir) { return; } try { _setLookDirArguments[0] = val; CharacterSetLookDirMethod.Invoke(_character, _setLookDirArguments); } catch { _useCharacterSetLookDir = false; _setLookDirArguments = null; } } private Transform FindChildByName(string wantedName) { Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (Transform val in componentsInChildren) { if ((Object)(object)val != (Object)null && string.Equals(((Object)val).name, wantedName, StringComparison.OrdinalIgnoreCase)) { return val; } } return null; } private void LateUpdate() { //IL_006c: 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_0081: Unknown result type (might be due to invalid IL or missing references) if (_ready && !GoblinNightRestJob.IsNightRestActive(_character) && _state == GathererState.Harvesting && !((Object)(object)_gatherPoseBone == (Object)null)) { float num = Mathf.Clamp01(1f - _stateTimer / 1f); float num2 = Mathf.Sin(num * (float)Math.PI) * 22f; _gatherPoseBone.localRotation *= Quaternion.Euler(num2, 0f, 0f); } } private void SetWorkControl(bool controlled) { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (_hasWorkControl == controlled) { return; } _hasWorkControl = controlled; if (controlled && (Object)(object)_character != (Object)null) { _character.SetMoveDir(Vector3.zero); _isMoving = false; } if (_monsterAiInstanceId != 0) { if (controlled) { ControlledMonsterAiIds.Add(_monsterAiInstanceId); } else { ControlledMonsterAiIds.Remove(_monsterAiInstanceId); } } } private void ReleaseWorkControl() { StopMoving(); SetWorkControl(controlled: false); _ward = null; ClearTarget(); _state = GathererState.Searching; } internal bool CanStore(GathererFruitType fruitType, int amount) { int num = Mathf.Max(1, amount); return GetStored(fruitType) <= 50 - num; } private int GetStored(GathererFruitType fruitType) { return fruitType switch { GathererFruitType.Raspberry => _raspberryStored, GathererFruitType.Blueberry => _blueberryStored, _ => _cloudberryStored, }; } private void AddStored(GathererFruitType fruitType, int amount) { switch (fruitType) { case GathererFruitType.Raspberry: _raspberryStored = Mathf.Min(50, _raspberryStored + amount); break; case GathererFruitType.Blueberry: _blueberryStored = Mathf.Min(50, _blueberryStored + amount); break; default: _cloudberryStored = Mathf.Min(50, _cloudberryStored + amount); break; } } private void LoadStateFromZdo() { if (!((Object)(object)_nview == (Object)null) && _nview.GetZDO() != null) { ZDO zDO = _nview.GetZDO(); int num = zDO.GetInt("AutomationByGoblins.Gatherer.Selection", 7); _selection = (GathererSelection)(num & 7); _raspberryStored = Mathf.Clamp(zDO.GetInt("AutomationByGoblins.Gatherer.Raspberry", 0), 0, 50); _blueberryStored = Mathf.Clamp(zDO.GetInt("AutomationByGoblins.Gatherer.Blueberry", 0), 0, 50); _cloudberryStored = Mathf.Clamp(zDO.GetInt("AutomationByGoblins.Gatherer.Cloudberry", 0), 0, 50); } } private void SaveStateToZdo() { if (!((Object)(object)_nview == (Object)null) && _nview.GetZDO() != null && _nview.IsOwner()) { ZDO zDO = _nview.GetZDO(); zDO.Set("AutomationByGoblins.Gatherer.Selection", (int)_selection); zDO.Set("AutomationByGoblins.Gatherer.Raspberry", _raspberryStored); zDO.Set("AutomationByGoblins.Gatherer.Blueberry", _blueberryStored); zDO.Set("AutomationByGoblins.Gatherer.Cloudberry", _cloudberryStored); } } internal void OpenSettingsWindow(Player player) { if (IsUsableGatherer && !((Object)(object)player == (Object)null)) { MakeThisTheActiveWindow(); _windowPlayer = player; _storageWindowOpen = false; _settingsWindowOpen = true; _uiMessage = string.Empty; CenterWindow(ref _settingsWindowRect); SetCursorForWindow(open: true); } } internal void OpenStorageWindow(Player player) { if (IsUsableGatherer && !((Object)(object)player == (Object)null)) { MakeThisTheActiveWindow(); _windowPlayer = player; _settingsWindowOpen = false; _storageWindowOpen = true; _uiMessage = string.Empty; CenterWindow(ref _storageWindowRect); SetCursorForWindow(open: true); } } private void MakeThisTheActiveWindow() { if ((Object)(object)ActiveWindow != (Object)null && (Object)(object)ActiveWindow != (Object)(object)this) { ActiveWindow.CloseWindows(); } if ((Object)(object)GoblinWorkerJob.ActiveWindow != (Object)null) { GoblinWorkerJob.ActiveWindow.CloseWindows(); } if ((Object)(object)GoblinWardWorkZone.ActiveMenu != (Object)null) { GoblinWardWorkZone.ActiveMenu.CloseMenu(); } ActiveWindow = this; } internal void CloseWindows() { _settingsWindowOpen = false; _storageWindowOpen = false; _windowPlayer = null; _uiMessage = string.Empty; if ((Object)(object)ActiveWindow == (Object)(object)this) { ActiveWindow = null; } SetCursorForWindow(open: false); } private static void CenterWindow(ref Rect rect) { ((Rect)(ref rect)).x = ((float)Screen.width - ((Rect)(ref rect)).width) * 0.5f; ((Rect)(ref rect)).y = ((float)Screen.height - ((Rect)(ref rect)).height) * 0.5f; } private void SetCursorForWindow(bool open) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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) if (open) { if (!_cursorStateSaved) { _previousCursorVisible = Cursor.visible; _previousCursorLockMode = Cursor.lockState; _cursorStateSaved = true; } Cursor.visible = true; Cursor.lockState = (CursorLockMode)0; } else if (_cursorStateSaved) { Cursor.visible = _previousCursorVisible; Cursor.lockState = _previousCursorLockMode; _cursorStateSaved = false; } } private void OnGUI() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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_0081: Expected O, but got Unknown //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)ActiveWindow != (Object)(object)this)) { if (_settingsWindowOpen) { _settingsWindowRect = GUI.Window(((Object)this).GetInstanceID() ^ 0x651A, _settingsWindowRect, new WindowFunction(DrawSettingsWindow), "Разумный фулинг — собиратель"); } if (_storageWindowOpen) { _storageWindowRect = GUI.Window(((Object)this).GetInstanceID() ^ 0x651B, _storageWindowRect, new WindowFunction(DrawStorageWindow), "Корзины собирателя"); } } } private void DrawSettingsWindow(int windowId) { GUILayout.Space(10f); GUILayout.Label("Профессия: Собиратель", Array.Empty()); GUILayout.Label("Отметьте один или несколько видов ягод. Гоблин будет искать только зрелые кусты внутри своего Ward.", Array.Empty()); GUILayout.Space(12f); GathererSelection gathererSelection = GathererSelection.None; if (GUILayout.Toggle((_selection & GathererSelection.Raspberry) != 0, "RaspberryBush — малина", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) })) { gathererSelection |= GathererSelection.Raspberry; } if (GUILayout.Toggle((_selection & GathererSelection.Blueberry) != 0, "BlueberryBush — черника", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) })) { gathererSelection |= GathererSelection.Blueberry; } if (GUILayout.Toggle((_selection & GathererSelection.Cloudberry) != 0, "CloudberryBush — морошка", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(32f) })) { gathererSelection |= GathererSelection.Cloudberry; } if (gathererSelection != _selection) { if (EnsureOwnership()) { _selection = gathererSelection; SaveStateToZdo(); ClearTarget(); _targetRefreshTimer = 0f; _state = GathererState.Searching; _uiMessage = ((_selection == GathererSelection.None) ? "Сбор отключён: собиратель будет только бродить." : "Выбор ягод сохранён."); } else { _uiMessage = "Не удалось сохранить выбор ягод."; } } GUILayout.Space(10f); GUILayout.Label("Хранилище: малина " + _raspberryStored + "/" + 50 + " • черника " + _blueberryStored + "/" + 50 + " • морошка " + _cloudberryStored + "/" + 50, Array.Empty()); if (!string.IsNullOrEmpty(_uiMessage)) { GUILayout.Label(_uiMessage, Array.Empty()); } GUILayout.FlexibleSpace(); GUILayout.BeginHorizontal(Array.Empty()); if (GUILayout.Button("Приказать следовать / стоять", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(34f) })) { WorkerStorageInteractPatch.RunVanillaTameableInteraction(_tameable, _windowPlayer); } if (GUILayout.Button("Закрыть", (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(130f), GUILayout.Height(34f) })) { CloseWindows(); } GUILayout.EndHorizontal(); GUI.DragWindow(); } private void DrawStorageWindow(int windowId) { GUILayout.Space(10f); GUILayout.Label("Три независимых слота, максимум по 50 ягод каждого вида.", Array.Empty()); GUILayout.Space(10f); GUILayout.BeginHorizontal(Array.Empty()); DrawStorageSlot(GathererFruitType.Raspberry, "Малина", _raspberryStored); DrawStorageSlot(GathererFruitType.Blueberry, "Черника", _blueberryStored); DrawStorageSlot(GathererFruitType.Cloudberry, "Морошка", _cloudberryStored); GUILayout.EndHorizontal(); GUILayout.Space(12f); if (GUILayout.Button("Забрать всё", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(36f) })) { int num = CollectAll(_windowPlayer); _uiMessage = ((num > 0) ? ("Получено ягод: " + num + ".") : "Корзины пусты или в инвентаре нет места."); } if (!string.IsNullOrEmpty(_uiMessage)) { GUILayout.Label(_uiMessage, Array.Empty()); } GUILayout.FlexibleSpace(); if (GUILayout.Button("Закрыть", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) })) { CloseWindows(); } GUI.DragWindow(); } private void DrawStorageSlot(GathererFruitType fruitType, string russianName, int stored) { GUILayout.BeginVertical(GUI.skin.box, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(170f) }); GUILayout.Label(russianName, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(24f) }); GUILayout.Box(stored + " / " + 50, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.ExpandWidth(true), GUILayout.Height(54f) }); if (GUILayout.Button("Забрать", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) })) { int num = CollectFruit(_windowPlayer, fruitType); _uiMessage = ((num > 0) ? ("Получено: " + num + " × " + russianName + ".") : ((stored <= 0) ? "Этот слот пуст." : "В инвентаре нет места.")); } GUILayout.EndVertical(); } private int CollectAll(Player player) { int num = 0; num += CollectFruit(player, GathererFruitType.Raspberry); num += CollectFruit(player, GathererFruitType.Blueberry); return num + CollectFruit(player, GathererFruitType.Cloudberry); } private int CollectFruit(Player player, GathererFruitType fruitType) { int stored = GetStored(fruitType); if ((Object)(object)player == (Object)null || stored <= 0 || !EnsureOwnership()) { return 0; } string fruitPrefabName = GetFruitPrefabName(fruitType); if ((Object)(object)ObjectDB.instance == (Object)null || InventoryAddItemMethod == null) { return 0; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(fruitPrefabName); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent() : null); Inventory inventory = ((Humanoid)player).GetInventory(); if ((Object)(object)val == (Object)null || inventory == null) { return 0; } int num = 0; for (int i = 0; i < stored; i++) { ItemData val2 = val.m_itemData.Clone(); val2.m_stack = 1; bool flag = false; try { object obj = InventoryAddItemMethod.Invoke(inventory, new object[1] { val2 }); flag = ((InventoryAddItemMethod.ReturnType == typeof(bool)) ? (obj != null && (bool)obj) : (InventoryAddItemMethod.ReturnType == typeof(void) || obj != null)); } catch { flag = false; } if (!flag) { break; } num++; } if (num > 0) { SetStored(fruitType, stored - num); SaveStateToZdo(); } return num; } private void SetStored(GathererFruitType fruitType, int value) { value = Mathf.Clamp(value, 0, 50); switch (fruitType) { case GathererFruitType.Raspberry: _raspberryStored = value; break; case GathererFruitType.Blueberry: _blueberryStored = value; break; default: _cloudberryStored = value; break; } } private static string GetFruitPrefabName(GathererFruitType fruitType) { return fruitType switch { GathererFruitType.Raspberry => "Raspberry", GathererFruitType.Blueberry => "Blueberries", _ => "Cloudberry", }; } private bool EnsureOwnership() { if ((Object)(object)_nview == (Object)null || _nview.GetZDO() == null) { return false; } if (_nview.IsOwner()) { return true; } try { if (ClaimOwnershipMethod != null) { ClaimOwnershipMethod.Invoke(_nview, null); } } catch { return false; } if (!_nview.IsOwner()) { return false; } LoadStateFromZdo(); return true; } private void OnDestroy() { if (_ready && (Object)(object)_nview != (Object)null && _nview.GetZDO() != null && _nview.IsOwner()) { SaveStateToZdo(); } if (_monsterAiInstanceId != 0) { ControlledMonsterAiIds.Remove(_monsterAiInstanceId); } if (_registeredCharacter) { WorkByCharacterId.Remove(_characterInstanceId); _registeredCharacter = false; } if ((Object)(object)ActiveWindow == (Object)(object)this) { CloseWindows(); } } } [HarmonyPatch(typeof(Pickable), "Awake")] internal static class GathererBerryBushAttachPatch { private static void Postfix(Pickable __instance) { if (!((Object)(object)__instance == (Object)null) && GoblinBerryBushTarget.IsSupportedBush(__instance) && !((Object)(object)((Component)__instance).GetComponent() != (Object)null)) { ((Component)__instance).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(Pickable), "SetPicked", new Type[] { typeof(bool) })] internal static class GathererBerryPickedStatePatch { private static void Postfix(Pickable __instance, bool __0) { if (!((Object)(object)__instance == (Object)null)) { GoblinBerryBushTarget component = ((Component)__instance).GetComponent(); if ((Object)(object)component != (Object)null) { component.UpdatePickedState(__0); } } } } [HarmonyPatch(typeof(GoblinWorkerController), "Start")] internal static class GathererJobAttachPatch { private static void Postfix(GoblinWorkerController __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).GetComponent() != (Object)null)) { ((Component)__instance).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(MonsterAI), "UpdateAI")] internal static class GathererMonsterAiControlPatch { private static bool Prefix(MonsterAI __instance) { return !GoblinGathererJob.IsMonsterAiWorkControlled(__instance); } } [HarmonyPatch(typeof(Destructible), "Damage", new Type[] { typeof(HitData) })] internal static class GathererZeroBushDamagePatch { private static void Prefix(HitData hit) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (hit != null) { Character attacker = hit.GetAttacker(); if (GoblinGathererJob.ShouldSuppressGathererDamage(attacker)) { hit.m_damage = default(DamageTypes); } } } } [HarmonyPatch(typeof(Tameable), "GetHoverText")] internal static class GathererHoverCapturePatch { internal static GoblinGathererJob HoveredGatherer; internal static int HoveredFrame = -100; private static void Postfix(Tameable __instance, ref string __result) { if (!((Object)(object)__instance == (Object)null)) { GoblinGathererJob component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null) && component.IsUsableGatherer) { HoveredGatherer = component; HoveredFrame = Time.frameCount; WorkerHoverCapturePatch.HoveredWorker = null; WorkerHoverCapturePatch.HoveredFrame = -100; WardWorkZoneHoverPatch.HoveredZone = null; WardWorkZoneHoverPatch.HoveredFrame = -100; __result += "\n[Alt+Y] Настроить сбор ягод\n[E] Открыть корзины"; } } } } [HarmonyPatch(typeof(Player), "Update")] internal static class GathererMenuHotkeyPatch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && (Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307)) && Input.GetKeyDown((KeyCode)121)) { GoblinGathererJob hoveredGatherer = GathererHoverCapturePatch.HoveredGatherer; if (!((Object)(object)hoveredGatherer == (Object)null) && hoveredGatherer.IsUsableGatherer && Time.frameCount - GathererHoverCapturePatch.HoveredFrame <= 5) { hoveredGatherer.OpenSettingsWindow(__instance); } } } } [HarmonyPatch(typeof(InventoryGui), "IsVisible")] internal static class GathererWindowVanillaInputBlockPatch { private static void Postfix(ref bool __result) { if ((Object)(object)GoblinGathererJob.ActiveWindow != (Object)null) { __result = true; } } } [HarmonyPatch(typeof(Tameable), "Interact")] internal static class GathererStorageInteractPatch { private static bool Prefix(Tameable __instance, Humanoid user, bool hold, bool alt, ref bool __result) { if (WorkerStorageInteractPatch.IsVanillaInteractionAllowed || (Object)(object)__instance == (Object)null) { return true; } GoblinGathererJob component = ((Component)__instance).GetComponent(); Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)component == (Object)null || !component.IsUsableGatherer || (Object)(object)val == (Object)null) { return true; } if (alt) { return true; } if (hold) { __result = false; return false; } component.OpenStorageWindow(val); __result = true; return false; } } internal static class GoblinShelterProbe { private static readonly Type CoverType = AccessTools.TypeByName("Cover"); private static readonly MethodInfo GetCoverForPointMethod = ResolveGetCoverForPointMethod(); private static readonly ParameterInfo[] CoverParameters = ((GetCoverForPointMethod != null) ? GetCoverForPointMethod.GetParameters() : null); private static readonly object[] CoverArguments = ((CoverParameters != null) ? new object[CoverParameters.Length] : null); private static bool _loggedFailure; internal static bool IsSheltered(Vector3 worldPoint, float requiredCover) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) if (GetCoverForPointMethod == null || CoverParameters == null || CoverArguments == null) { LogFailureOnce("Cover.GetCoverForPoint was not found."); return false; } try { for (int i = 0; i < CoverParameters.Length; i++) { Type parameterType = CoverParameters[i].ParameterType; Type type = (parameterType.IsByRef ? parameterType.GetElementType() : parameterType); if (i == 0 && type == typeof(Vector3)) { CoverArguments[i] = worldPoint; } else if (type == typeof(float)) { CoverArguments[i] = (parameterType.IsByRef ? 0f : 0.5f); } else if (type == typeof(bool)) { CoverArguments[i] = false; } else if (type != null && type.IsValueType) { CoverArguments[i] = Activator.CreateInstance(type); } else { CoverArguments[i] = null; } } GetCoverForPointMethod.Invoke(null, CoverArguments); float num = 0f; bool flag = false; for (int j = 0; j < CoverParameters.Length; j++) { Type parameterType2 = CoverParameters[j].ParameterType; if (parameterType2.IsByRef) { Type elementType = parameterType2.GetElementType(); if (elementType == typeof(float) && CoverArguments[j] is float) { num = (float)CoverArguments[j]; } else if (elementType == typeof(bool) && CoverArguments[j] is bool) { flag = (bool)CoverArguments[j]; } } } return flag && num >= requiredCover; } catch (Exception exception) { LogFailureOnce("Cover.GetCoverForPoint failed: " + GetInnermostMessage(exception)); return false; } } private static MethodInfo ResolveGetCoverForPointMethod() { if (CoverType == null) { return null; } MethodInfo[] methods = CoverType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (!string.Equals(methodInfo.Name, "GetCoverForPoint", StringComparison.Ordinal)) { continue; } ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length < 3 || parameters[0].ParameterType != typeof(Vector3)) { continue; } bool flag = false; bool flag2 = false; for (int j = 1; j < parameters.Length; j++) { Type parameterType = parameters[j].ParameterType; if (parameterType.IsByRef) { Type elementType = parameterType.GetElementType(); flag |= elementType == typeof(float); flag2 |= elementType == typeof(bool); } } if (flag && flag2) { return methodInfo; } } return null; } private static void LogFailureOnce(string message) { if (!_loggedFailure) { _loggedFailure = true; AutomationByGoblinsPlugin.ModLog.LogWarning((object)message); } } private static string GetInnermostMessage(Exception exception) { Exception ex = exception; while (ex.InnerException != null) { ex = ex.InnerException; } return ex.Message; } } public sealed class GoblinRestBed : MonoBehaviour { private const float ShelterCacheDuration = 5f; private const float ShelterCheckHeight = 1.2f; private const float RequiredCover = 0.8f; private const float ApproachProbeStartHeight = 1.25f; private const float ApproachProbeDepth = 4f; private const float MaximumApproachSurfaceAboveBed = 0.2f; private const float MaximumApproachSurfaceBelowBed = 1.35f; private const float ApproachCapsuleRadius = 0.28f; private const float ApproachCapsuleBottom = 0.34f; private const float ApproachCapsuleTop = 1.45f; private const float ConnectionProbeHeight = 0.75f; private const float ConnectionProbeRadius = 0.18f; private const float ApproachSideClearance = 0.42f; private const float ApproachLongitudinalOffset = 0.32f; private const float MissingApproachScorePenalty = 4096f; private const float UnshelteredScorePenalty = 16384f; private static readonly float[] ApproachLongitudinalOffsets = new float[3] { 0f, 0.32f, -0.32f }; private static readonly List Instances = new List(); private static readonly Dictionary Reservations = new Dictionary(); private Bed _bed; private readonly RaycastHit[] _surfaceHits = (RaycastHit[])(object)new RaycastHit[24]; private readonly RaycastHit[] _connectionHits = (RaycastHit[])(object)new RaycastHit[24]; private readonly Collider[] _clearanceHits = (Collider[])(object)new Collider[24]; private Vector3 _restPosition; private Vector3 _bedLongAxis; private Vector3 _bedSideAxis; private Quaternion _restRotation; private float _bedHalfWidth = 0.5f; private float _nextShelterCheckTime; private bool _sheltered; private bool _registered; private bool _geometryResolved; internal Vector3 RestPosition { get { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) ResolveGeometry(); return _restPosition; } } internal Quaternion RestRotation { get { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) ResolveGeometry(); return _restRotation; } } internal static int RegisteredCount => Instances.Count; private void Start() { //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) Scene scene = ((Component)this).gameObject.scene; if (!((Scene)(ref scene)).IsValid()) { return; } _bed = ((Component)this).GetComponent(); if (!((Object)(object)_bed == (Object)null)) { ResolveGeometry(); if (!Instances.Contains(this)) { Instances.Add(this); } _registered = true; } } private void OnDestroy() { if (_registered) { Instances.Remove(this); _registered = false; } Reservations.Remove(((Object)this).GetInstanceID()); } internal bool IsValidFor(GoblinWardWorkZone sleepingZone) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) return (Object)(object)_bed != (Object)null && ((Component)this).gameObject.activeInHierarchy && (Object)(object)sleepingZone != (Object)null && sleepingZone.GetZoneType() == GoblinWardZoneType.Sleeping && sleepingZone.Contains(RestPosition); } internal static GoblinRestBed FindAndReserveNearest(GoblinNightRestJob requester, Vector3 workerPosition, GoblinWardWorkZone sleepingZone, out Vector3 reservedApproachPosition, out bool hasReservedApproachPosition) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0108: 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_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) reservedApproachPosition = Vector3.zero; hasReservedApproachPosition = false; if ((Object)(object)requester == (Object)null || (Object)(object)sleepingZone == (Object)null) { return null; } GoblinRestBed goblinRestBed = null; Vector3 val = Vector3.zero; float num = float.MaxValue; bool flag = false; for (int num2 = Instances.Count - 1; num2 >= 0; num2--) { GoblinRestBed goblinRestBed2 = Instances[num2]; if ((Object)(object)goblinRestBed2 == (Object)null) { Instances.RemoveAt(num2); } else { if (!goblinRestBed2.IsValidFor(sleepingZone)) { continue; } int instanceID = ((Object)goblinRestBed2).GetInstanceID(); if (Reservations.TryGetValue(instanceID, out var value)) { if ((Object)(object)value == (Object)null) { Reservations.Remove(instanceID); } else if ((Object)(object)value != (Object)(object)requester) { continue; } } Vector3 approachPosition; bool flag2 = goblinRestBed2.TryGetApproachPosition(workerPosition, out approachPosition); Vector3 val2 = (flag2 ? approachPosition : goblinRestBed2.RestPosition); Vector3 val3 = val2 - workerPosition; val3.y = 0f; float num3 = ((Vector3)(ref val3)).sqrMagnitude + (flag2 ? 0f : 4096f) + (goblinRestBed2.IsSheltered() ? 0f : 16384f); if (num3 < num) { num = num3; goblinRestBed = goblinRestBed2; val = val2; flag = flag2; } } } if ((Object)(object)goblinRestBed != (Object)null) { Reservations[((Object)goblinRestBed).GetInstanceID()] = requester; reservedApproachPosition = val; hasReservedApproachPosition = flag; } return goblinRestBed; } internal static bool IsReservedBy(GoblinRestBed bed, GoblinNightRestJob requester) { if ((Object)(object)bed == (Object)null || (Object)(object)requester == (Object)null) { return false; } GoblinNightRestJob value; return Reservations.TryGetValue(((Object)bed).GetInstanceID(), out value) && (Object)(object)value == (Object)(object)requester; } internal static void Release(GoblinRestBed bed, GoblinNightRestJob requester) { if (!((Object)(object)bed == (Object)null) && !((Object)(object)requester == (Object)null)) { int instanceID = ((Object)bed).GetInstanceID(); if (Reservations.TryGetValue(instanceID, out var value) && (Object)(object)value == (Object)(object)requester) { Reservations.Remove(instanceID); } } } internal bool TryGetApproachPosition(Vector3 workerPosition, out Vector3 approachPosition) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0130: 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_011e: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008f: 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_00a7: 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_00be: 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_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) Vector3 restPosition = RestPosition; Vector3 val = Vector3.zero; float num = float.MaxValue; bool flag = false; float num2 = _bedHalfWidth + 0.42f; for (int i = 0; i < 2; i++) { float num3 = ((i == 0) ? 1f : (-1f)); for (int j = 0; j < ApproachLongitudinalOffsets.Length; j++) { float num4 = ApproachLongitudinalOffsets[j]; Vector3 horizontalPoint = restPosition + _bedSideAxis * (num2 * num3) + _bedLongAxis * num4; if (TryProjectToStandingSurface(horizontalPoint, restPosition.y, out var surfacePoint) && HasStandingClearance(surfacePoint)) { Vector3 val2 = surfacePoint - workerPosition; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude < num && HasOpenConnection(workerPosition, surfacePoint) && HasOpenConnectionToBed(surfacePoint)) { num = sqrMagnitude; val = surfacePoint; flag = true; } } } } if (flag) { approachPosition = val; return true; } approachPosition = ((Component)this).transform.position; return false; } internal bool CanMountFrom(Vector3 workerPosition, Transform workerRoot) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return HasOpenConnectionToBed(workerPosition, workerRoot); } private bool TryProjectToStandingSurface(Vector3 horizontalPoint, float bedHeight, out Vector3 surfacePoint) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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_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_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_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0117: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) Vector3 val = horizontalPoint; val.y = bedHeight + 1.25f; int num = Physics.RaycastNonAlloc(val, Vector3.down, _surfaceHits, 4f, -5, (QueryTriggerInteraction)1); float num2 = float.MaxValue; Vector3 val2 = Vector3.zero; bool result = false; for (int i = 0; i < num; i++) { RaycastHit val3 = _surfaceHits[i]; if (!((Object)(object)((RaycastHit)(ref val3)).collider == (Object)null) && !IsPartOfThisBed(((Component)((RaycastHit)(ref val3)).collider).transform) && !(Vector3.Dot(((RaycastHit)(ref val3)).normal, Vector3.up) < 0.55f)) { float num3 = ((RaycastHit)(ref val3)).point.y - bedHeight; if (!(num3 > 0.2f) && !(num3 < -1.35f) && ((RaycastHit)(ref val3)).distance < num2) { num2 = ((RaycastHit)(ref val3)).distance; val2 = ((RaycastHit)(ref val3)).point + Vector3.up * 0.04f; result = true; } } } surfacePoint = val2; return result; } private bool HasStandingClearance(Vector3 floorPoint) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: 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_0011: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) Vector3 val = floorPoint + Vector3.up * 0.34f; Vector3 val2 = floorPoint + Vector3.up * 1.45f; int num = Physics.OverlapCapsuleNonAlloc(val, val2, 0.28f, _clearanceHits, -5, (QueryTriggerInteraction)1); for (int i = 0; i < num; i++) { Collider val3 = _clearanceHits[i]; if (!((Object)(object)val3 == (Object)null)) { Transform transform = ((Component)val3).transform; if (!IsPartOfThisBed(transform) && !((Object)(object)((Component)val3).GetComponentInParent() != (Object)null)) { return false; } } } return true; } private bool HasOpenConnectionToBed(Vector3 floorPoint, Transform ignoredRoot = null) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) return HasOpenConnection(floorPoint, RestPosition, ignoredRoot); } private bool HasOpenConnection(Vector3 fromFloorPoint, Vector3 toFloorPoint, Transform ignoredRoot = null) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: 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_0011: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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_0065: Unknown result type (might be due to invalid IL or missing references) Vector3 val = fromFloorPoint + Vector3.up * 0.75f; Vector3 val2 = toFloorPoint + Vector3.up * 0.75f; Vector3 val3 = val2 - val; float magnitude = ((Vector3)(ref val3)).magnitude; if (magnitude <= 0.1f) { return true; } val3 /= magnitude; int num = Physics.SphereCastNonAlloc(val, 0.18f, val3, _connectionHits, Mathf.Max(0.05f, magnitude - 0.15f), -5, (QueryTriggerInteraction)1); for (int i = 0; i < num; i++) { Collider collider = ((RaycastHit)(ref _connectionHits[i])).collider; if (!((Object)(object)collider == (Object)null) && !IsPartOfThisBed(((Component)collider).transform) && !IsPartOfRoot(((Component)collider).transform, ignoredRoot) && !((Object)(object)((Component)collider).GetComponentInParent() != (Object)null)) { return false; } } return true; } private static bool IsPartOfRoot(Transform candidate, Transform root) { return (Object)(object)candidate != (Object)null && (Object)(object)root != (Object)null && ((Object)(object)candidate == (Object)(object)root || candidate.IsChildOf(root)); } private bool IsPartOfThisBed(Transform candidate) { return (Object)(object)candidate != (Object)null && ((Object)(object)candidate == (Object)(object)((Component)this).transform || candidate.IsChildOf(((Component)this).transform)); } private void ResolveGeometry() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0105: 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_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_025e: 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) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02be: 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_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_016c: 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_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_0399: Unknown result type (might be due to invalid IL or missing references) //IL_039b: Unknown result type (might be due to invalid IL or missing references) //IL_03a5: Unknown result type (might be due to invalid IL or missing references) //IL_03aa: Unknown result type (might be due to invalid IL or missing references) //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_0322: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Unknown result type (might be due to invalid IL or missing references) if (_geometryResolved) { return; } _geometryResolved = true; if ((Object)(object)_bed == (Object)null) { _bed = ((Component)this).GetComponent(); } Vector3 val = Vector3.ProjectOnPlane(((Component)this).transform.forward, Vector3.up); if (((Vector3)(ref val)).sqrMagnitude <= 0.001f) { val = Vector3.forward; } _restRotation = Quaternion.LookRotation(((Vector3)(ref val)).normalized, Vector3.up); _restPosition = ((Component)this).transform.position; Collider[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); Bounds val2 = default(Bounds); Bounds val3 = default(Bounds); Collider surfaceCollider = null; bool flag = false; bool flag2 = false; float num = 0f; foreach (Collider val4 in componentsInChildren) { if (!((Object)(object)val4 == (Object)null) && val4.enabled && !val4.isTrigger) { if (!flag) { val2 = val4.bounds; flag = true; } else { ((Bounds)(ref val2)).Encapsulate(val4.bounds); } Bounds bounds = val4.bounds; Vector3 size = ((Bounds)(ref bounds)).size; float num2 = size.x * size.z; float num3 = num2 / Mathf.Max(0.1f, size.y); if (num3 > num) { num = num3; val3 = bounds; surfaceCollider = val4; flag2 = true; } } } if (!flag) { Renderer[] componentsInChildren2 = ((Component)this).GetComponentsInChildren(true); foreach (Renderer val5 in componentsInChildren2) { if (!((Object)(object)val5 == (Object)null) && val5.enabled) { if (!flag) { val2 = val5.bounds; flag = true; } else { ((Bounds)(ref val2)).Encapsulate(val5.bounds); } } } } if (!flag) { _restPosition = ((Component)this).transform.position + Vector3.up * 0.45f; return; } Bounds surfaceBounds = (flag2 ? val3 : val2); ResolveBedAxes(surfaceCollider, surfaceBounds); Vector3 center = ((Bounds)(ref surfaceBounds)).center; Vector3 val6 = default(Vector3); ((Vector3)(ref val6))..ctor(center.x, ((Bounds)(ref val2)).max.y + 0.5f, center.z); int num4 = Physics.RaycastNonAlloc(val6, Vector3.down, _surfaceHits, ((Bounds)(ref val2)).size.y + 1.5f, -5, (QueryTriggerInteraction)1); float num5 = float.MaxValue; Vector3 point = default(Vector3); ((Vector3)(ref point))..ctor(center.x, ((Bounds)(ref val2)).center.y, center.z); bool flag3 = false; for (int k = 0; k < num4; k++) { RaycastHit val7 = _surfaceHits[k]; if (!((Object)(object)((RaycastHit)(ref val7)).collider == (Object)null) && IsPartOfThisBed(((Component)((RaycastHit)(ref val7)).collider).transform) && !(Vector3.Dot(((RaycastHit)(ref val7)).normal, Vector3.up) < 0.65f) && !(((RaycastHit)(ref val7)).distance >= num5)) { num5 = ((RaycastHit)(ref val7)).distance; point = ((RaycastHit)(ref val7)).point; flag3 = true; } } if (!flag3) { point.y = ((Bounds)(ref surfaceBounds)).max.y; } _restPosition = point + Vector3.up * 0.04f; } private void ResolveBedAxes(Collider surfaceCollider, Bounds surfaceBounds) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0058: 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_0077: 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_009e: 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_00a6: 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_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) Transform val = (((Object)(object)surfaceCollider != (Object)null) ? ((Component)surfaceCollider).transform : ((Component)this).transform); Vector3 val2 = Vector3.ProjectOnPlane(val.right, Vector3.up); Vector3 val3 = Vector3.ProjectOnPlane(val.forward, Vector3.up); if (((Vector3)(ref val2)).sqrMagnitude <= 0.001f) { val2 = Vector3.right; } if (((Vector3)(ref val3)).sqrMagnitude <= 0.001f) { val3 = Vector3.forward; } ((Vector3)(ref val2)).Normalize(); ((Vector3)(ref val3)).Normalize(); if (!TryGetOrientedHalfSizes(surfaceCollider, out var halfX, out var halfZ)) { halfX = ProjectBoundsExtent(surfaceBounds, val2); halfZ = ProjectBoundsExtent(surfaceBounds, val3); } if (halfX >= halfZ) { _bedLongAxis = val2; _bedSideAxis = val3; _bedHalfWidth = halfZ; } else { _bedLongAxis = val3; _bedSideAxis = val2; _bedHalfWidth = halfX; } _bedHalfWidth = Mathf.Clamp(_bedHalfWidth, 0.35f, 0.75f); _restRotation = Quaternion.LookRotation(_bedLongAxis, Vector3.up); } private static float ProjectBoundsExtent(Bounds bounds, Vector3 axis) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) Vector3 extents = ((Bounds)(ref bounds)).extents; return Mathf.Abs(axis.x) * extents.x + Mathf.Abs(axis.y) * extents.y + Mathf.Abs(axis.z) * extents.z; } private static bool TryGetOrientedHalfSizes(Collider surfaceCollider, out float halfX, out float halfZ) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: 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_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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) halfX = 0f; halfZ = 0f; if ((Object)(object)surfaceCollider == (Object)null) { return false; } Vector3 lossyScale = ((Component)surfaceCollider).transform.lossyScale; BoxCollider val = (BoxCollider)(object)((surfaceCollider is BoxCollider) ? surfaceCollider : null); if ((Object)(object)val != (Object)null) { halfX = Mathf.Abs(val.size.x * lossyScale.x) * 0.5f; halfZ = Mathf.Abs(val.size.z * lossyScale.z) * 0.5f; return halfX > 0.01f && halfZ > 0.01f; } MeshCollider val2 = (MeshCollider)(object)((surfaceCollider is MeshCollider) ? surfaceCollider : null); if ((Object)(object)val2 != (Object)null && (Object)(object)val2.sharedMesh != (Object)null) { Bounds bounds = val2.sharedMesh.bounds; Vector3 size = ((Bounds)(ref bounds)).size; halfX = Mathf.Abs(size.x * lossyScale.x) * 0.5f; halfZ = Mathf.Abs(size.z * lossyScale.z) * 0.5f; return halfX > 0.01f && halfZ > 0.01f; } return false; } private bool IsSheltered() { //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_003e: 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) if (Time.time < _nextShelterCheckTime) { return _sheltered; } _nextShelterCheckTime = Time.time + 5f; _sheltered = GoblinShelterProbe.IsSheltered(RestPosition + Vector3.up * 1.2f, 0.8f); return _sheltered; } } public sealed class GoblinRestDoor : MonoBehaviour { private const float DoorWaypointDistance = 1.15f; private const float DoorGroundProbeHeight = 1.4f; private const float DoorGroundProbeDepth = 3.5f; private const float MaximumDoorSurfaceAboveCenter = 0.35f; private const float MaximumDoorSurfaceBelowCenter = 1.5f; private const float MaximumStoredWaypointDistance = 2.25f; private const float MaximumStoredWaypointDistanceSqr = 5.0625f; private const float MaximumDoorDistanceFromBed = 16f; private const float MaximumDoorDistanceFromBedSqr = 256f; private const float MaximumExitDoorDistanceFromBed = 8f; private const float MaximumExitDoorDistanceFromBedSqr = 64f; private const float NonSeparatingDoorPenalty = 32f; private const float DisconnectedDoorPenalty = 256f; private static readonly List Instances = new List(); private static readonly FieldInfo KeyItemField = typeof(Door).GetField("m_keyItem", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private readonly HashSet _nightUsers = new HashSet(); private readonly HashSet _insideNightUsers = new HashSet(); private readonly RaycastHit[] _groundHits = (RaycastHit[])(object)new RaycastHit[16]; private Door _door; private ZNetView _nview; private Vector3 _doorCenter; private Vector3 _doorForward; private bool _openedByGoblins; private bool _registered; internal Vector3 DoorCenter => _doorCenter; private void Start() { //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_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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_00c2: Unknown result type (might be due to invalid IL or missing references) Scene scene = ((Component)this).gameObject.scene; if (!((Scene)(ref scene)).IsValid() || !IsVanillaWoodDoor()) { return; } _door = ((Component)this).GetComponent(); _nview = ((Component)this).GetComponent(); if (!((Object)(object)_door == (Object)null) && !((Object)(object)_nview == (Object)null) && !HasKeyRequirement()) { _doorCenter = ((Component)this).transform.position; _doorForward = ((Component)this).transform.forward; _doorForward.y = 0f; if (((Vector3)(ref _doorForward)).sqrMagnitude <= 0.001f) { _doorForward = Vector3.forward; } else { ((Vector3)(ref _doorForward)).Normalize(); } Instances.Add(this); _registered = true; } } private void OnDestroy() { if (_registered) { Instances.Remove(this); _registered = false; } _nightUsers.Clear(); _insideNightUsers.Clear(); } internal static GoblinRestDoor FindForRoute(Vector3 workerPosition, GoblinRestBed bed, GoblinWardWorkZone sleepingZone) { //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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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_00b3: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: 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_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)bed == (Object)null) { return null; } Vector3 restPosition = bed.RestPosition; GoblinRestDoor result = null; float num = float.MaxValue; for (int num2 = Instances.Count - 1; num2 >= 0; num2--) { GoblinRestDoor goblinRestDoor = Instances[num2]; if ((Object)(object)goblinRestDoor == (Object)null) { Instances.RemoveAt(num2); } else if (goblinRestDoor.IsValidFor(sleepingZone)) { Vector3 val = restPosition - goblinRestDoor._doorCenter; val.y = 0f; if (!(((Vector3)(ref val)).sqrMagnitude > 256f)) { Vector3 val2 = workerPosition - goblinRestDoor._doorCenter; val2.y = 0f; float num3 = Vector3.Dot(val2, goblinRestDoor._doorForward); float num4 = Vector3.Dot(val, goblinRestDoor._doorForward); bool flag = Mathf.Abs(num4) > 0.15f && num3 * num4 <= 0f; goblinRestDoor.GetRoutePoints(restPosition, out var outsidePoint, out var insidePoint); bool flag2 = bed.CanMountFrom(insidePoint, null); float num5 = FlatDistance(workerPosition, outsidePoint) + FlatDistance(insidePoint, restPosition) + (flag ? 0f : 32f) + (flag2 ? 0f : 256f); if (!(num5 >= num)) { num = num5; result = goblinRestDoor; } } } } return result; } internal static GoblinRestDoor FindExitForBed(Vector3 workerPosition, GoblinRestBed bed, GoblinWardWorkZone sleepingZone) { //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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0074: 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_008c: 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_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: 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) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)bed == (Object)null) { return null; } Vector3 restPosition = bed.RestPosition; GoblinRestDoor result = null; float num = float.MaxValue; for (int num2 = Instances.Count - 1; num2 >= 0; num2--) { GoblinRestDoor goblinRestDoor = Instances[num2]; if ((Object)(object)goblinRestDoor == (Object)null) { Instances.RemoveAt(num2); } else if (goblinRestDoor.IsValidFor(sleepingZone) && goblinRestDoor.IsOnBedSide(workerPosition, restPosition)) { Vector3 val = restPosition - goblinRestDoor._doorCenter; val.y = 0f; if (!(((Vector3)(ref val)).sqrMagnitude > 64f)) { goblinRestDoor.GetRoutePoints(restPosition, out var _, out var insidePoint); if (bed.CanMountFrom(insidePoint, null)) { float num3 = FlatDistance(workerPosition, insidePoint) + FlatDistance(insidePoint, restPosition); if (num3 < num) { num = num3; result = goblinRestDoor; } } } } } return result; } internal static GoblinRestDoor FindNearestTo(Vector3 position, float maximumDistance) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: 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_004b: Unknown result type (might be due to invalid IL or missing references) GoblinRestDoor result = null; float num = maximumDistance * maximumDistance; for (int num2 = Instances.Count - 1; num2 >= 0; num2--) { GoblinRestDoor goblinRestDoor = Instances[num2]; if ((Object)(object)goblinRestDoor == (Object)null) { Instances.RemoveAt(num2); } else { Vector3 val = goblinRestDoor._doorCenter - position; if (((Vector3)(ref val)).sqrMagnitude <= num) { num = ((Vector3)(ref val)).sqrMagnitude; result = goblinRestDoor; } } } return result; } private static float FlatDistance(Vector3 first, Vector3 second) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) Vector3 val = second - first; val.y = 0f; return ((Vector3)(ref val)).magnitude; } internal bool IsValidFor(GoblinWardWorkZone sleepingZone) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) return (Object)(object)_door != (Object)null && (Object)(object)_nview != (Object)null && _nview.GetZDO() != null && ((Component)this).gameObject.activeInHierarchy && (Object)(object)sleepingZone != (Object)null && sleepingZone.GetZoneType() == GoblinWardZoneType.Sleeping && sleepingZone.Contains(_doorCenter); } internal void RegisterNightUser(int characterInstanceId) { if (_nightUsers.Count == 0) { _openedByGoblins = false; _insideNightUsers.Clear(); } _nightUsers.Add(characterInstanceId); } internal void MarkNightUserInside(int characterInstanceId, Vector3 userPosition) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) _nightUsers.Add(characterInstanceId); _insideNightUsers.Add(characterInstanceId); if (_insideNightUsers.Count >= _nightUsers.Count) { RequestClosed(userPosition); _openedByGoblins = false; } } internal void ReleaseNightUser(int characterInstanceId, Vector3 userPosition) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) _nightUsers.Remove(characterInstanceId); _insideNightUsers.Remove(characterInstanceId); if (_nightUsers.Count == 0) { if (_openedByGoblins) { RequestClosed(userPosition); } _openedByGoblins = false; } } internal bool EnsureOpen(Vector3 userPosition) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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) if (!IsUsableNetworkObject()) { return false; } if (IsOpen()) { _openedByGoblins = true; return true; } bool flag = Vector3.Dot(_doorForward, userPosition - _doorCenter) < 0f; _nview.InvokeRPC("UseDoor", new object[1] { flag }); _openedByGoblins = true; return true; } internal bool IsOnBedSide(Vector3 workerPosition, Vector3 bedPosition) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: 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_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_0026: Unknown result type (might be due to invalid IL or missing references) float num = Vector3.Dot(workerPosition - _doorCenter, _doorForward); float num2 = Vector3.Dot(bedPosition - _doorCenter, _doorForward); return Mathf.Abs(num2) > 0.15f && num * num2 > 0f; } internal void GetRoutePoints(Vector3 bedPosition, out Vector3 outsidePoint, out Vector3 insidePoint) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) float insideSide = ((Vector3.Dot(bedPosition - _doorCenter, _doorForward) >= 0f) ? 1f : (-1f)); GetRoutePointsForInsideSide(insideSide, out outsidePoint, out insidePoint); } internal void GetExitRoutePoints(Vector3 insideReference, out Vector3 outsidePoint, out Vector3 insidePoint) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) float insideSide = ((Vector3.Dot(insideReference - _doorCenter, _doorForward) >= 0f) ? 1f : (-1f)); GetRoutePointsForInsideSide(insideSide, out outsidePoint, out insidePoint); } internal bool AreRoutePointsPlausible(Vector3 outsidePoint, Vector3 insidePoint) { //IL_0002: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) if (!IsRoutePointPlausible(outsidePoint) || !IsRoutePointPlausible(insidePoint)) { return false; } float num = Vector3.Dot(outsidePoint - _doorCenter, _doorForward); float num2 = Vector3.Dot(insidePoint - _doorCenter, _doorForward); return num * num2 < -0.01f; } internal static Vector3 SanitizeUnloadedOutsidePoint(Vector3 doorCenter, Vector3 storedOutsidePoint, Vector3 currentPosition) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: 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_00ce: 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_005d: 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_005f: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0119: 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_0136: 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) Vector3 val = storedOutsidePoint - doorCenter; val.y = 0f; if (!IsFinite(val.x) || !IsFinite(val.z) || !(((Vector3)(ref val)).sqrMagnitude >= 0.16f) || !(((Vector3)(ref val)).sqrMagnitude <= 5.0625f)) { val = currentPosition - doorCenter; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude <= 0.001f || !IsFinite(val.x) || !IsFinite(val.z)) { val = Vector3.forward; } ((Vector3)(ref val)).Normalize(); val *= 1.15f; } Vector3 result = doorCenter + val; float num = storedOutsidePoint.y - doorCenter.y; if (IsFinite(storedOutsidePoint.y) && num <= 0.35f && num >= -1.5f) { result.y = storedOutsidePoint.y; } else { result.y = Mathf.Clamp(Mathf.Min(currentPosition.y, doorCenter.y + 0.1f), doorCenter.y - 1.25f, doorCenter.y + 0.1f); } return result; } private void GetRoutePointsForInsideSide(float insideSide, out Vector3 outsidePoint, out Vector3 insidePoint) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //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_001e: 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_003f: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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) //IL_0052: Unknown result type (might be due to invalid IL or missing references) Vector3 horizontalPoint = _doorCenter + _doorForward * (1.15f * insideSide); Vector3 horizontalPoint2 = _doorCenter - _doorForward * (1.15f * insideSide); insidePoint = ProjectToGround(horizontalPoint); outsidePoint = ProjectToGround(horizontalPoint2); } private bool IsRoutePointPlausible(Vector3 point) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) Vector3 val = point - _doorCenter; float y = val.y; val.y = 0f; return IsFinite(point.x) && IsFinite(point.y) && IsFinite(point.z) && ((Vector3)(ref val)).sqrMagnitude <= 5.0625f && y <= 0.35f && y >= -1.5f; } private static bool IsFinite(float value) { return !float.IsNaN(value) && !float.IsInfinity(value); } private void RequestClosed(Vector3 userPosition) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_0029: Unknown result type (might be due to invalid IL or missing references) if (IsUsableNetworkObject() && IsOpen()) { bool flag = Vector3.Dot(_doorForward, userPosition - _doorCenter) < 0f; _nview.InvokeRPC("UseDoor", new object[1] { flag }); } } private bool IsOpen() { return IsUsableNetworkObject() && _nview.GetZDO().GetInt("state", 0) != 0; } private bool IsUsableNetworkObject() { return (Object)(object)_nview != (Object)null && _nview.GetZDO() != null && _nview.IsValid(); } private Vector3 ProjectToGround(Vector3 horizontalPoint) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: 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_001c: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_00bd: 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_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) Vector3 val = horizontalPoint; val.y = _doorCenter.y + 1.4f; int num = Physics.RaycastNonAlloc(val, Vector3.down, _groundHits, 3.5f, -5, (QueryTriggerInteraction)1); float num2 = float.MaxValue; Vector3 result = horizontalPoint; result.y = _doorCenter.y; for (int i = 0; i < num; i++) { RaycastHit val2 = _groundHits[i]; if (!((Object)(object)((RaycastHit)(ref val2)).collider == (Object)null) && !IsPartOfThisDoor(((Component)((RaycastHit)(ref val2)).collider).transform) && !(Vector3.Dot(((RaycastHit)(ref val2)).normal, Vector3.up) < 0.55f) && !(((RaycastHit)(ref val2)).distance >= num2)) { float num3 = ((RaycastHit)(ref val2)).point.y - _doorCenter.y; if (!(num3 > 0.35f) && !(num3 < -1.5f)) { num2 = ((RaycastHit)(ref val2)).distance; result = ((RaycastHit)(ref val2)).point + Vector3.up * 0.04f; } } } return result; } private bool IsPartOfThisDoor(Transform candidate) { return (Object)(object)candidate != (Object)null && ((Object)(object)candidate == (Object)(object)((Component)this).transform || candidate.IsChildOf(((Component)this).transform)); } private bool IsVanillaWoodDoor() { string name = ((Object)((Component)this).gameObject).name; return name.StartsWith("wood_door", StringComparison.OrdinalIgnoreCase); } private bool HasKeyRequirement() { if (KeyItemField == null || (Object)(object)_door == (Object)null) { return false; } try { return KeyItemField.GetValue(_door) != null; } catch { return false; } } } [DefaultExecutionOrder(10000)] public sealed class GoblinNightRestJob : MonoBehaviour { private enum RestRouteState { Idle, NightToDoorOutside, NightWaitingForDoor, NightThroughDoor, NightToBed, LyingDown, Sleeping, GettingUp, MorningToDoorInside, MorningWaitingForDoor, MorningThroughDoor } private const string PersistedInsideZdoKey = "AutomationByGoblins.Rest.Inside"; private const string PersistedDoorCenterXKey = "AutomationByGoblins.Rest.DoorCenterX"; private const string PersistedDoorCenterYKey = "AutomationByGoblins.Rest.DoorCenterY"; private const string PersistedDoorCenterZKey = "AutomationByGoblins.Rest.DoorCenterZ"; private const string PersistedDoorInsideXKey = "AutomationByGoblins.Rest.DoorInsideX"; private const string PersistedDoorInsideYKey = "AutomationByGoblins.Rest.DoorInsideY"; private const string PersistedDoorInsideZKey = "AutomationByGoblins.Rest.DoorInsideZ"; private const string PersistedDoorOutsideXKey = "AutomationByGoblins.Rest.DoorOutsideX"; private const string PersistedDoorOutsideYKey = "AutomationByGoblins.Rest.DoorOutsideY"; private const string PersistedDoorOutsideZKey = "AutomationByGoblins.Rest.DoorOutsideZ"; private const float LogicInterval = 0.1f; private const float WardRefreshInterval = 2f; private const float BedRefreshInterval = 2f; private const float ApproachArrivalDistance = 0.9f; private const float BedEntryArrivalDistance = 0.3f; private const float BedEntryMaximumHeightDifference = 0.45f; private const float BedRouteFailureDelay = 8f; private const float DoorRouteFailureDelay = 12f; private const float MorningRouteFailureDelay = 10f; private const float MorningConfirmationDuration = 8f; private const float PersistedDoorResolveDistance = 3f; private const float PersistedDoorResolveGraceDuration = 2f; private const float MaximumDirectBedTransferDistance = 1.8f; private const float MaximumDirectBedTransferDistanceSqr = 3.2399998f; private const float MaximumDirectBedTransferHeight = 1.2f; private const float MaximumApproachHeightDifference = 1.1f; private const float DoorCrossingArrivalDistance = 0.08f; private const float DoorCrossingMaximumHeightDifference = 0.65f; private const float MaximumRecoveryTeleportDistance = 20f; private const float MaximumRecoveryTeleportDistanceSqr = 400f; private const float DoorActionDelay = 0.9f; private const float ProgressSampleInterval = 0.75f; private const float ProgressDistance = 0.18f; private const float ProgressDistanceSqr = 0.0324f; private const float StuckBeforeAvoidance = 2f; private const float AvoidanceDuration = 2.5f; private const float AvoidanceProbeHeight = 0.8f; private const float AvoidanceProbeRadius = 0.28f; private const float AvoidanceProbeDistance = 1.65f; private const float DoorTraversalStartRadius = 2.6f; private const float DoorTraversalStartRadiusSqr = 6.7599993f; private const float DoorTraversalSpeed = 1.8f; private const float MinimumDoorTraversalDuration = 0.65f; private const float MaximumDoorTraversalDuration = 1.5f; private const float DoorTraversalLift = 0.32f; private const float BedLieDownDuration = 2.2f; private const float BedGetUpDuration = 1.6f; private const float SleepRootForwardOffset = 0.62f; private const float SleepRootHeightOffset = 0.06f; private const float SleepBodyPitch = -88f; private const float SleepBodyRoll = 4f; private const float SleepBreathSpeed = 1.25f; private const float SleepBreathAngle = 1.6f; private static readonly float[] AvoidanceAngles = new float[6] { 70f, 90f, 110f, 45f, 135f, 160f }; private static readonly string[] SleepBreathingBoneNames = new string[3] { "spine3", "spine2", "spine1" }; private static readonly Quaternion SleepBodyLocalRotation = Quaternion.Euler(-88f, 0f, 4f); private static readonly HashSet NightRestCharacterIds = new HashSet(); private static readonly HashSet ControlledMonsterAiIds = new HashSet(); private static readonly WaitForSeconds TamePollDelay = new WaitForSeconds(1f); private static readonly MethodInfo BaseAiMoveToMethod = AccessTools.Method(typeof(BaseAI), "MoveTo", new Type[4] { typeof(float), typeof(Vector3), typeof(float), typeof(bool) }, (Type[])null); private GoblinWorkerController _controller; private Character _character; private BaseAI _baseAi; private MonsterAI _monsterAi; private Rigidbody _body; private ZNetView _nview; private Animator _animator; private Transform _cachedTransform; private Transform _sleepBreathingBone; private GoblinWardWorkZone _sleepingZone; private GoblinRestBed _bed; private GoblinRestDoor _restDoor; private object[] _moveToArguments; private readonly RaycastHit[] _avoidanceHits = (RaycastHit[])(object)new RaycastHit[16]; private Vector3 _bedApproachPosition; private Vector3 _doorOutsidePosition; private Vector3 _doorInsidePosition; private Vector3 _progressSamplePosition; private Vector3 _doorTraversalStartPosition; private Vector3 _bedTeleportReturnPosition; private Vector3 _persistedDoorCenter; private Vector3 _persistedDoorInsidePosition; private Vector3 _persistedDoorOutsidePosition; private Vector3 _bedEntryStartPosition; private Vector3 _sleepBodyPosition; private Quaternion _bedTeleportReturnRotation; private Quaternion _bedEntryStartRotation; private Quaternion _sleepBodyRotation; private Quaternion _sleepBreathingBaseRotation; private float _logicAccumulator; private float _wardRefreshTimer; private float _bedRefreshTimer; private float _progressSampleTimer; private float _stationaryTime; private float _navigationFailureTime; private float _avoidanceTimer; private float _doorTraversalTimer; private float _doorTraversalDuration; private float _doorActionTimer; private float _bedEntryTimer; private float _sleepBreathPhase; private float _savedAnimatorSpeed; private float _morningConfirmationTimer; private float _persistedDoorResolveTimer; private float _bestBedDistance = float.MaxValue; private int _characterInstanceId; private int _monsterAiInstanceId; private int _avoidanceSide = 1; private RigidbodyConstraints _savedBodyConstraints; private RigidbodyInterpolation _savedBodyInterpolation; private bool _savedBodyDetectCollisions; private RestRouteState _routeState = RestRouteState.Idle; private bool _ready; private bool _nightRestActive; private bool _hasBedApproachPosition; private bool _standingOnBed; private bool _bodyStateSaved; private bool _doorUserRegistered; private bool _insideDoor; private bool _hasRestControl; private bool _isMoving; private bool _useBaseAiMoveTo; private bool _doorTraversalActive; private bool _animatorPausedForSleep; private bool _sleepBreathingPoseCaptured; private bool _hasBedTeleportReturnPoint; private bool _assignmentDiagnosticLogged; private bool _hasPersistedDoorState; internal static bool IsNightRestActive(Character character) { return (Object)(object)character != (Object)null && NightRestCharacterIds.Contains(((Object)character).GetInstanceID()); } internal static bool IsMonsterAiRestControlled(MonsterAI monsterAi) { return (Object)(object)monsterAi != (Object)null && ControlledMonsterAiIds.Contains(((Object)monsterAi).GetInstanceID()); } private void Start() { _controller = ((Component)this).GetComponent(); _character = ((Component)this).GetComponent(); _baseAi = ((Component)this).GetComponent(); _monsterAi = ((Component)this).GetComponent(); _body = ((Component)this).GetComponent(); _nview = ((Component)this).GetComponent(); _animator = ((Component)this).GetComponentInChildren(true); _cachedTransform = ((Component)this).transform; ((MonoBehaviour)this).StartCoroutine(InitializeWhenReady()); } private IEnumerator InitializeWhenReady() { while ((Object)(object)_controller == (Object)null || _controller.WorkerType == GoblinWorkerType.Unassigned || (Object)(object)_nview == (Object)null || _nview.GetZDO() == null) { if ((Object)(object)_controller == (Object)null) { _controller = ((Component)this).GetComponent(); } if ((Object)(object)_nview == (Object)null) { _nview = ((Component)this).GetComponent(); } yield return null; } if (!_controller.IsIntelligent) { ((Behaviour)this).enabled = false; yield break; } ((Behaviour)this).enabled = false; while ((Object)(object)_character != (Object)null && !_character.IsTamed()) { yield return TamePollDelay; } if (!((Object)(object)_character == (Object)null)) { _sleepBreathingBone = FindSleepBreathingBone(); _sleepBreathPhase = (float)(((Object)this).GetInstanceID() & 0x1F) * 0.19f; _characterInstanceId = ((Object)_character).GetInstanceID(); _monsterAiInstanceId = (((Object)(object)_monsterAi != (Object)null) ? ((Object)_monsterAi).GetInstanceID() : 0); _useBaseAiMoveTo = (Object)(object)_baseAi != (Object)null && BaseAiMoveToMethod != null; LoadPersistedDoorState(); if (_useBaseAiMoveTo) { _moveToArguments = new object[4]; _moveToArguments[2] = 0.18f; _moveToArguments[3] = false; } _logicAccumulator = 0.1f; _wardRefreshTimer = 0f; _bedRefreshTimer = 0f; _ready = true; ((Behaviour)this).enabled = true; } } private void Update() { if (!_ready) { return; } if (IsBedTransitionState(_routeState)) { if (!HasLocalRestAuthority()) { AbandonRestAssignment(); } else { AdvanceBedTransition(Time.deltaTime); } return; } _logicAccumulator += Time.deltaTime; if (!(_logicAccumulator < 0.1f)) { float delta = Mathf.Min(_logicAccumulator, 0.25f); _logicAccumulator = 0f; if (!HasLocalRestAuthority()) { AbandonRestAssignment(); } else { TickNightRest(delta); } } } private bool HasLocalRestAuthority() { return (Object)(object)_character != (Object)null && _character.IsTamed() && (Object)(object)_nview != (Object)null && _nview.GetZDO() != null && _nview.IsOwner(); } private void TickNightRest(float delta) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)EnvMan.instance == (Object)null) { MaintainCurrentRestState(); return; } if (!EnvMan.IsNight()) { if (!_nightRestActive && _hasPersistedDoorState && !BeginPersistedMorningExit()) { _persistedDoorResolveTimer -= delta; if (_persistedDoorResolveTimer > 0f) { SetRestControl(controlled: true); _character.SetMoveDir(Vector3.zero); } else { RecoverPersistedMorningExitWithoutDoor(); } } else if (_nightRestActive) { _morningConfirmationTimer += delta; if (IsLockedInBed() && _morningConfirmationTimer < 8f) { MaintainCurrentRestState(); } else { TickMorningExit(delta); } } return; } _morningConfirmationTimer = 0f; BeginNightRest(); if (_standingOnBed || _routeState == RestRouteState.Sleeping) { MaintainCurrentRestState(); return; } bool hasValidBed = HasValidReservedBed(); RefreshSleepingZone(delta, hasValidBed); RefreshBed(delta, hasValidBed); if ((Object)(object)_bed == (Object)null) { StopMoving(); LogMissingAssignmentOnce(); return; } if (_routeState == RestRouteState.Idle) { InitializeNightRoute(); } TickNightRoute(delta); } private bool IsLockedInBed() { return _standingOnBed || _routeState == RestRouteState.LyingDown || _routeState == RestRouteState.Sleeping; } private void MaintainCurrentRestState() { if (_nightRestActive) { SetRestControl(controlled: true); if (_routeState == RestRouteState.Sleeping || _standingOnBed) { HoldOnBed(); } } } private bool BeginPersistedMorningExit() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) GoblinRestDoor goblinRestDoor = GoblinRestDoor.FindNearestTo(_persistedDoorCenter, 3f); if ((Object)(object)goblinRestDoor == (Object)null) { return false; } _restDoor = goblinRestDoor; if (_restDoor.AreRoutePointsPlausible(_persistedDoorOutsidePosition, _persistedDoorInsidePosition)) { _doorInsidePosition = _persistedDoorInsidePosition; _doorOutsidePosition = _persistedDoorOutsidePosition; } else { _restDoor.GetExitRoutePoints(_cachedTransform.position, out _doorOutsidePosition, out _doorInsidePosition); } _insideDoor = true; _nightRestActive = true; NightRestCharacterIds.Add(_characterInstanceId); _restDoor.RegisterNightUser(_characterInstanceId); _doorUserRegistered = true; SavePersistedDoorState(inside: true); _routeState = RestRouteState.MorningToDoorInside; SetRestControl(controlled: true); ResetNavigationProgress(); return true; } private void RecoverPersistedMorningExitWithoutDoor() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) Vector3 val = GoblinRestDoor.SanitizeUnloadedOutsidePoint(_persistedDoorCenter, _persistedDoorOutsidePosition, _cachedTransform.position); TeleportCharacter(val + Vector3.up * 0.05f, _cachedTransform.rotation); SavePersistedDoorState(inside: false); _insideDoor = false; _routeState = RestRouteState.Idle; StopMoving(); SetRestControl(controlled: false); } private void InitializeNightRoute() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) RefreshBedApproachPosition(); RefreshDoorRoute(); if ((Object)(object)_restDoor != (Object)null) { _restDoor.RegisterNightUser(_characterInstanceId); _doorUserRegistered = true; if (_insideDoor) { _restDoor.MarkNightUserInside(_characterInstanceId, _cachedTransform.position); SavePersistedDoorState(inside: true); _routeState = RestRouteState.NightToBed; } else { _routeState = RestRouteState.NightToDoorOutside; } } else { _routeState = RestRouteState.NightToBed; } ResetNavigationProgress(); } private void TickNightRoute(float delta) { //IL_0044: 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_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_022f: 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_023f: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) if (_standingOnBed) { _routeState = RestRouteState.Sleeping; } if (_routeState == RestRouteState.NightToDoorOutside) { if ((Object)(object)_restDoor == (Object)null) { FallBackToDirectBedRoute(); } else if (MoveToRoutePoint(_doorOutsidePosition, delta)) { StopMoving(); _restDoor.EnsureOpen(_cachedTransform.position); _doorActionTimer = 0.9f; _routeState = RestRouteState.NightWaitingForDoor; ResetNavigationProgress(); } else if (_navigationFailureTime >= 12f && !TryRecoverAtDoorOutside()) { RetryAssignedBedRoute(resetDoorRoute: true); } } else if (_routeState == RestRouteState.NightWaitingForDoor) { _doorActionTimer -= delta; if (_doorActionTimer <= 0f) { _routeState = RestRouteState.NightThroughDoor; ResetNavigationProgress(); } } else if (_routeState == RestRouteState.NightThroughDoor) { if ((Object)(object)_restDoor == (Object)null) { FallBackToDirectBedRoute(); } else if (MoveToRoutePoint(_doorInsidePosition, delta, 0.08f, 0.65f)) { SnapToCompletedDoorPoint(_doorInsidePosition); _insideDoor = true; _restDoor.MarkNightUserInside(_characterInstanceId, _cachedTransform.position); SavePersistedDoorState(inside: true); RefreshBedApproachPosition(); _routeState = RestRouteState.NightToBed; ResetNavigationProgress(); } else if (_navigationFailureTime >= 12f) { RetryAssignedBedRoute(resetDoorRoute: true); } } else if (_routeState == RestRouteState.NightToBed) { if (CanTransferDirectlyToAssignedBed()) { TeleportOntoBedAndLieDown(); return; } if (!_hasBedApproachPosition) { RefreshBedApproachPosition(); } Vector3 target = (_hasBedApproachPosition ? _bedApproachPosition : _bed.RestPosition); if (MoveToRoutePoint(target, delta, 0.3f, 0.45f)) { if (_hasBedApproachPosition && _bed.CanMountFrom(_cachedTransform.position, _cachedTransform)) { TeleportOntoBedAndLieDown(); } else { RetryAssignedBedRoute(resetDoorRoute: false); } } else if (_navigationFailureTime >= 8f && !TryRecoverAtBedApproach()) { RetryAssignedBedRoute(resetDoorRoute: false); } } else if (_routeState != RestRouteState.LyingDown && _routeState == RestRouteState.Sleeping) { HoldOnBed(); } } private void TickMorningExit(float delta) { //IL_00db: 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_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) SetRestControl(controlled: true); if (_standingOnBed || _routeState == RestRouteState.Sleeping) { BeginGettingUpFromBed(); } else { if (_routeState == RestRouteState.GettingUp) { return; } if (_routeState != RestRouteState.MorningToDoorInside && _routeState != RestRouteState.MorningWaitingForDoor && _routeState != RestRouteState.MorningThroughDoor) { if ((Object)(object)_restDoor == (Object)null || !_insideDoor) { EndNightRest(); return; } _routeState = RestRouteState.MorningToDoorInside; ResetNavigationProgress(); } if (_routeState == RestRouteState.MorningToDoorInside) { if ((Object)(object)_restDoor == (Object)null) { EndNightRest(); } else if (MoveToRoutePoint(_doorInsidePosition, delta)) { StopMoving(); _restDoor.EnsureOpen(_cachedTransform.position); _doorActionTimer = 0.9f; _routeState = RestRouteState.MorningWaitingForDoor; ResetNavigationProgress(); } else if (_navigationFailureTime >= 10f) { ForceMorningExit(); } } else if (_routeState == RestRouteState.MorningWaitingForDoor) { _doorActionTimer -= delta; if (_doorActionTimer <= 0f) { _routeState = RestRouteState.MorningThroughDoor; ResetNavigationProgress(); } } else { if (_routeState != RestRouteState.MorningThroughDoor) { return; } if ((Object)(object)_restDoor == (Object)null || MoveToRoutePoint(_doorOutsidePosition, delta, 0.08f, 0.65f)) { if ((Object)(object)_restDoor != (Object)null) { SnapToCompletedDoorPoint(_doorOutsidePosition); } SavePersistedDoorState(inside: false); _insideDoor = false; ReleaseDoorRoute(); EndNightRest(); } else if (_navigationFailureTime >= 10f) { ForceMorningExit(); } } } } private void ForceMorningExit() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_restDoor != (Object)null) { _restDoor.EnsureOpen(_cachedTransform.position); TeleportCharacter(_doorOutsidePosition + Vector3.up * 0.05f, _cachedTransform.rotation); } SavePersistedDoorState(inside: false); _insideDoor = false; ReleaseDoorRoute(); EndNightRest(); } private bool MoveToRoutePoint(Vector3 target, float delta, float arrivalDistance = 0.9f, float maximumHeightDifference = 1.1f) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_0058: 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) Vector3 val = target - _cachedTransform.position; Vector3 val2 = val; val2.y = 0f; if (((Vector3)(ref val2)).sqrMagnitude <= arrivalDistance * arrivalDistance && Mathf.Abs(val.y) <= maximumHeightDifference) { StopMoving(); return true; } if (TryMoveThroughOpenDoor(target, delta, out var completed)) { if (completed) { StopMoving(); ResetNavigationProgress(); return true; } return false; } UpdateNavigationProgress(delta, ((Vector3)(ref val)).magnitude); MoveToBed(target, delta); return false; } private bool TryMoveThroughOpenDoor(Vector3 target, float delta, out bool completed) { //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0174: 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_0185: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: 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_00a3: 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_00af: 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_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: 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) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) completed = false; if ((_routeState != RestRouteState.NightThroughDoor && _routeState != RestRouteState.MorningThroughDoor) || (Object)(object)_restDoor == (Object)null) { ResetDoorTraversal(); return false; } if (!_doorTraversalActive) { Vector3 val = _restDoor.DoorCenter - _cachedTransform.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude > 6.7599993f) { return false; } Vector3 val2 = target - _cachedTransform.position; Vector3 val3 = val2; val3.y = 0f; if (((Vector3)(ref val3)).sqrMagnitude <= 0.001f) { completed = true; return true; } _doorTraversalStartPosition = _cachedTransform.position; _doorTraversalDuration = Mathf.Clamp(((Vector3)(ref val3)).magnitude / 1.8f, 0.65f, 1.5f); _doorTraversalTimer = 0f; _doorTraversalActive = true; } _doorTraversalTimer += delta; float num = Mathf.Clamp01(_doorTraversalTimer / _doorTraversalDuration); Vector3 position = Vector3.Lerp(_doorTraversalStartPosition, target, num); position.y += Mathf.Sin(num * (float)Math.PI) * 0.32f; Vector3 val4 = target - _cachedTransform.position; val4.y = 0f; if (((Vector3)(ref val4)).sqrMagnitude > 0.001f) { ((Vector3)(ref val4)).Normalize(); } ClearBodyVelocity(); SetCharacterTransform(position, _cachedTransform.rotation); _character.SetMoveDir((num < 1f) ? val4 : Vector3.zero); _isMoving = true; if (num >= 1f) { _doorTraversalActive = false; completed = true; } return true; } private void SnapToCompletedDoorPoint(Vector3 destination) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_0060: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) Vector3 val = destination - _cachedTransform.position; val.y = 0f; Quaternion rotation = _cachedTransform.rotation; if (((Vector3)(ref val)).sqrMagnitude > 0.001f) { rotation = Quaternion.LookRotation(((Vector3)(ref val)).normalized, Vector3.up); } TeleportCharacter(destination, rotation); _character.SetMoveDir(Vector3.zero); _isMoving = false; } private void ResetDoorTraversal() { _doorTraversalActive = false; _doorTraversalTimer = 0f; _doorTraversalDuration = 0f; } private void FallBackToDirectBedRoute() { ReleaseDoorRoute(); _insideDoor = false; _routeState = RestRouteState.NightToBed; ResetNavigationProgress(); } private void RefreshDoorRoute() { //IL_003b: 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_00d2: 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) //IL_00e2: 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) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_bed == (Object)null || (Object)(object)_sleepingZone == (Object)null) { ReleaseDoorRoute(); return; } bool flag = _bed.CanMountFrom(_cachedTransform.position, _cachedTransform); bool insideDoor = false; GoblinRestDoor goblinRestDoor = null; if (flag) { goblinRestDoor = ResolveDoorForLoadedInterior(); insideDoor = (Object)(object)goblinRestDoor != (Object)null; } if ((Object)(object)goblinRestDoor == (Object)null) { goblinRestDoor = GoblinRestDoor.FindForRoute(_cachedTransform.position, _bed, _sleepingZone); } if ((Object)(object)goblinRestDoor != (Object)(object)_restDoor) { ReleaseDoorRoute(); _restDoor = goblinRestDoor; } if ((Object)(object)_restDoor != (Object)null) { Vector3 val = _restDoor.DoorCenter - _persistedDoorCenter; if (_hasPersistedDoorState && ((Vector3)(ref val)).sqrMagnitude <= 9f && _restDoor.AreRoutePointsPlausible(_persistedDoorOutsidePosition, _persistedDoorInsidePosition)) { _doorOutsidePosition = _persistedDoorOutsidePosition; _doorInsidePosition = _persistedDoorInsidePosition; } else { _restDoor.GetRoutePoints(_bed.RestPosition, out _doorOutsidePosition, out _doorInsidePosition); if (_hasPersistedDoorState) { SavePersistedDoorState(inside: true); } } _insideDoor = insideDoor; } else { _insideDoor = false; } } private GoblinRestDoor ResolveDoorForLoadedInterior() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (_hasPersistedDoorState) { GoblinRestDoor goblinRestDoor = GoblinRestDoor.FindNearestTo(_persistedDoorCenter, 3f); if ((Object)(object)goblinRestDoor != (Object)null) { return goblinRestDoor; } } return GoblinRestDoor.FindExitForBed(_cachedTransform.position, _bed, _sleepingZone); } private void LoadPersistedDoorState() { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_nview == (Object)null) && _nview.GetZDO() != null) { ZDO zDO = _nview.GetZDO(); _hasPersistedDoorState = zDO.GetInt("AutomationByGoblins.Rest.Inside", 0) != 0; if (_hasPersistedDoorState) { _persistedDoorResolveTimer = 2f; _persistedDoorCenter = new Vector3(zDO.GetFloat("AutomationByGoblins.Rest.DoorCenterX", 0f), zDO.GetFloat("AutomationByGoblins.Rest.DoorCenterY", 0f), zDO.GetFloat("AutomationByGoblins.Rest.DoorCenterZ", 0f)); _persistedDoorInsidePosition = new Vector3(zDO.GetFloat("AutomationByGoblins.Rest.DoorInsideX", 0f), zDO.GetFloat("AutomationByGoblins.Rest.DoorInsideY", 0f), zDO.GetFloat("AutomationByGoblins.Rest.DoorInsideZ", 0f)); _persistedDoorOutsidePosition = new Vector3(zDO.GetFloat("AutomationByGoblins.Rest.DoorOutsideX", 0f), zDO.GetFloat("AutomationByGoblins.Rest.DoorOutsideY", 0f), zDO.GetFloat("AutomationByGoblins.Rest.DoorOutsideZ", 0f)); } } } private void SavePersistedDoorState(bool inside) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_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) _hasPersistedDoorState = inside; if (!((Object)(object)_nview == (Object)null) && _nview.GetZDO() != null && _nview.IsOwner()) { ZDO zDO = _nview.GetZDO(); zDO.Set("AutomationByGoblins.Rest.Inside", inside ? 1 : 0); if (inside && !((Object)(object)_restDoor == (Object)null)) { _persistedDoorCenter = _restDoor.DoorCenter; _persistedDoorInsidePosition = _doorInsidePosition; _persistedDoorOutsidePosition = _doorOutsidePosition; zDO.Set("AutomationByGoblins.Rest.DoorCenterX", _persistedDoorCenter.x); zDO.Set("AutomationByGoblins.Rest.DoorCenterY", _persistedDoorCenter.y); zDO.Set("AutomationByGoblins.Rest.DoorCenterZ", _persistedDoorCenter.z); zDO.Set("AutomationByGoblins.Rest.DoorInsideX", _persistedDoorInsidePosition.x); zDO.Set("AutomationByGoblins.Rest.DoorInsideY", _persistedDoorInsidePosition.y); zDO.Set("AutomationByGoblins.Rest.DoorInsideZ", _persistedDoorInsidePosition.z); zDO.Set("AutomationByGoblins.Rest.DoorOutsideX", _persistedDoorOutsidePosition.x); zDO.Set("AutomationByGoblins.Rest.DoorOutsideY", _persistedDoorOutsidePosition.y); zDO.Set("AutomationByGoblins.Rest.DoorOutsideZ", _persistedDoorOutsidePosition.z); } } } private void ReleaseDoorRoute() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_restDoor != (Object)null && _doorUserRegistered) { _restDoor.ReleaseNightUser(_characterInstanceId, _cachedTransform.position); } _doorUserRegistered = false; _restDoor = null; } private void BeginNightRest() { if (!_nightRestActive) { _nightRestActive = true; NightRestCharacterIds.Add(_characterInstanceId); _wardRefreshTimer = 0f; _bedRefreshTimer = 0f; _routeState = RestRouteState.Idle; _insideDoor = false; _hasBedTeleportReturnPoint = false; _assignmentDiagnosticLogged = false; _morningConfirmationTimer = 0f; ResetNavigationProgress(); RefreshBedApproachPosition(); } SetRestControl(controlled: true); } private void EndNightRest() { if (_nightRestActive) { LeaveBed(); NightRestCharacterIds.Remove(_characterInstanceId); _nightRestActive = false; _morningConfirmationTimer = 0f; ResetNavigationProgress(); } ReleaseDoorRoute(); _insideDoor = false; _routeState = RestRouteState.Idle; StopMoving(); SetRestControl(controlled: false); } private void AbandonRestAssignment() { EndNightRest(); ReleaseBed(); _sleepingZone = null; } private bool HasValidReservedBed() { return (Object)(object)_bed != (Object)null && (Object)(object)_sleepingZone != (Object)null && GoblinRestBed.IsReservedBy(_bed, this) && _bed.IsValidFor(_sleepingZone); } private void RefreshSleepingZone(float delta, bool hasValidBed) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (hasValidBed) { return; } _wardRefreshTimer -= delta; if (!(_wardRefreshTimer > 0f)) { _wardRefreshTimer = 2f; GoblinWardWorkZone goblinWardWorkZone = GoblinWardWorkZone.FindNearest(_cachedTransform.position, GoblinWardZoneType.Sleeping); if (!((Object)(object)goblinWardWorkZone == (Object)(object)_sleepingZone)) { ReleaseBed(); _sleepingZone = goblinWardWorkZone; _bedRefreshTimer = 0f; } } } private void RefreshBed(float delta, bool hasValidBed) { //IL_005a: 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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) if (hasValidBed) { return; } ReleaseBed(); _bedRefreshTimer -= delta; if (!(_bedRefreshTimer > 0f) && !((Object)(object)_sleepingZone == (Object)null)) { _bedRefreshTimer = 2f; _bed = GoblinRestBed.FindAndReserveNearest(this, _cachedTransform.position, _sleepingZone, out var reservedApproachPosition, out var hasReservedApproachPosition); if ((Object)(object)_bed != (Object)null) { _bedApproachPosition = reservedApproachPosition; _hasBedApproachPosition = hasReservedApproachPosition; _assignmentDiagnosticLogged = false; AutomationByGoblinsPlugin.ModLog.LogDebug((object)("Night rest: " + ((Object)((Component)this).gameObject).name + " reserved Bed at " + FormatPosition(_bed.RestPosition) + ".")); ResetNavigationProgress(); } } } private void LogMissingAssignmentOnce() { if (!_assignmentDiagnosticLogged) { _assignmentDiagnosticLogged = true; string text = (((Object)(object)_sleepingZone == (Object)null) ? "no Sleeping Ward was found" : "the Sleeping Ward contains no free registered Bed"); AutomationByGoblinsPlugin.ModLog.LogWarning((object)("Night rest: " + ((Object)((Component)this).gameObject).name + " is waiting because " + text + ". Registered Beds: " + GoblinRestBed.RegisteredCount + ".")); } } private static string FormatPosition(Vector3 position) { return "(" + position.x.ToString("0.0") + ", " + position.y.ToString("0.0") + ", " + position.z.ToString("0.0") + ")"; } private void RefreshBedApproachPosition() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_bed == (Object)null) { _hasBedApproachPosition = false; } else { _hasBedApproachPosition = _bed.TryGetApproachPosition(_cachedTransform.position, out _bedApproachPosition); } } private void RetryAssignedBedRoute(bool resetDoorRoute) { if (!((Object)(object)_bed == (Object)null)) { if (resetDoorRoute) { ReleaseDoorRoute(); _insideDoor = false; _routeState = RestRouteState.Idle; } else { RefreshBedApproachPosition(); _routeState = RestRouteState.NightToBed; } StopMoving(); ResetNavigationProgress(); } } private bool TryRecoverAtDoorOutside() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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) if ((Object)(object)_restDoor == (Object)null || !IsWithinRecoveryDistance(_doorOutsidePosition)) { return false; } StopMoving(); TeleportCharacter(_doorOutsidePosition + Vector3.up * 0.05f, _cachedTransform.rotation); _restDoor.EnsureOpen(_cachedTransform.position); _doorActionTimer = 0.9f; _routeState = RestRouteState.NightWaitingForDoor; ResetNavigationProgress(); return true; } private bool TryRecoverAtBedApproach() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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) if ((Object)(object)_bed == (Object)null || ((Object)(object)_restDoor != (Object)null && !_insideDoor)) { return false; } RefreshBedApproachPosition(); if (!_hasBedApproachPosition || !IsWithinRecoveryDistance(_bedApproachPosition)) { return false; } StopMoving(); TeleportCharacter(_bedApproachPosition + Vector3.up * 0.03f, _bed.RestRotation); ResetNavigationProgress(); if (_bed.CanMountFrom(_cachedTransform.position, _cachedTransform)) { TeleportOntoBedAndLieDown(); } return true; } private bool IsWithinRecoveryDistance(Vector3 destination) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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) Vector3 val = destination - _cachedTransform.position; val.y = 0f; return ((Vector3)(ref val)).sqrMagnitude <= 400f; } private bool CanTransferDirectlyToAssignedBed() { //IL_001c: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_bed == (Object)null) { return false; } Vector3 val = _bed.RestPosition - _cachedTransform.position; Vector3 val2 = val; val2.y = 0f; return ((Vector3)(ref val2)).sqrMagnitude <= 3.2399998f && Mathf.Abs(val.y) <= 1.2f && _bed.CanMountFrom(_cachedTransform.position, _cachedTransform); } private void ReleaseBed() { GoblinRestBed bed = _bed; if (bed == null && !((Object)(object)_restDoor != (Object)null) && !_doorUserRegistered && !_hasBedApproachPosition && !_standingOnBed && !_bodyStateSaved && !_hasBedTeleportReturnPoint && !IsBedTransitionState(_routeState)) { _bed = null; return; } ReleaseDoorRoute(); LeaveBed(); if ((Object)(object)bed != (Object)null) { GoblinRestBed.Release(bed, this); } _bed = null; _hasBedApproachPosition = false; _insideDoor = false; _routeState = RestRouteState.Idle; ResetNavigationProgress(); } private void MoveToBed(Vector3 destination, float delta) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) _isMoving = true; if (_avoidanceTimer > 0f) { _avoidanceTimer -= delta; MoveAroundObstacle(destination); return; } if (_useBaseAiMoveTo) { try { _moveToArguments[0] = delta; _moveToArguments[1] = destination; BaseAiMoveToMethod.Invoke(_baseAi, _moveToArguments); return; } catch { _useBaseAiMoveTo = false; _moveToArguments = null; } } Vector3 val = destination - _cachedTransform.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude > 0.001f) { _character.SetMoveDir(((Vector3)(ref val)).normalized); } else { _character.SetMoveDir(Vector3.zero); } } private void UpdateNavigationProgress(float delta, float distanceToBed) { //IL_0077: 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_0082: 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_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) if (distanceToBed + 0.18f < _bestBedDistance) { _bestBedDistance = distanceToBed; _navigationFailureTime = 0f; } else { _navigationFailureTime += delta; } _progressSampleTimer += delta; if (_progressSampleTimer < 0.75f) { return; } float progressSampleTimer = _progressSampleTimer; _progressSampleTimer = 0f; Vector3 val = _cachedTransform.position - _progressSamplePosition; val.y = 0f; _progressSamplePosition = _cachedTransform.position; if (((Vector3)(ref val)).sqrMagnitude > 0.0324f) { _stationaryTime = 0f; return; } _stationaryTime += progressSampleTimer; if (!(_stationaryTime < 2f)) { _stationaryTime = 0f; _avoidanceTimer = 2.5f; _avoidanceSide = -_avoidanceSide; } } private void MoveAroundObstacle(Vector3 destination) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_005e: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_008d: 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_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: 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_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) Vector3 val = destination - _cachedTransform.position; val.y = 0f; if (((Vector3)(ref val)).sqrMagnitude <= 0.001f) { _character.SetMoveDir(Vector3.zero); return; } float magnitude = ((Vector3)(ref val)).magnitude; ((Vector3)(ref val)).Normalize(); Vector3 chosenDirection; if (IsDirectionClear(val, Mathf.Max(1.65f, magnitude - 0.45f))) { _avoidanceTimer = 0f; _character.SetMoveDir(val); } else if (TryChooseAvoidanceDirection(val, _avoidanceSide, out chosenDirection) || TryChooseAvoidanceDirection(val, -_avoidanceSide, out chosenDirection)) { _character.SetMoveDir(chosenDirection); } else { Vector3 val2 = -val; _character.SetMoveDir(IsDirectionClear(val2) ? val2 : Vector3.zero); } } private bool TryChooseAvoidanceDirection(Vector3 desiredDirection, int side, out Vector3 chosenDirection) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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) for (int i = 0; i < AvoidanceAngles.Length; i++) { float num = AvoidanceAngles[i] * (float)side; Vector3 val = Quaternion.Euler(0f, num, 0f) * desiredDirection; if (IsDirectionClear(val)) { chosenDirection = val; return true; } } chosenDirection = Vector3.zero; return false; } private bool IsDirectionClear(Vector3 direction) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return IsDirectionClear(direction, 1.65f); } private bool IsDirectionClear(Vector3 direction, float probeDistance) { //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_0021: 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) Vector3 val = _cachedTransform.position + Vector3.up * 0.8f; int num = Physics.SphereCastNonAlloc(val, 0.28f, direction, _avoidanceHits, probeDistance, -5, (QueryTriggerInteraction)1); for (int i = 0; i < num; i++) { Collider collider = ((RaycastHit)(ref _avoidanceHits[i])).collider; if (!((Object)(object)collider == (Object)null)) { Transform transform = ((Component)collider).transform; if (!((Object)(object)transform == (Object)(object)_cachedTransform) && !transform.IsChildOf(_cachedTransform) && (!((Object)(object)_bed != (Object)null) || (!((Object)(object)transform == (Object)(object)((Component)_bed).transform) && !transform.IsChildOf(((Component)_bed).transform)))) { return false; } } } return true; } private void ResetNavigationProgress() { //IL_0023: 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_0028: Unknown result type (might be due to invalid IL or missing references) _progressSamplePosition = (((Object)(object)_cachedTransform != (Object)null) ? _cachedTransform.position : ((Component)this).transform.position); _progressSampleTimer = 0f; _stationaryTime = 0f; _navigationFailureTime = 0f; _avoidanceTimer = 0f; ResetDoorTraversal(); _bestBedDistance = float.MaxValue; _avoidanceSide = (((_characterInstanceId & 1) == 0) ? 1 : (-1)); } private static bool IsBedTransitionState(RestRouteState state) { return state == RestRouteState.LyingDown || state == RestRouteState.GettingUp; } private void TeleportOntoBedAndLieDown() { //IL_0058: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_0089: 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_00b5: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_bed == (Object)null) && !_standingOnBed && !IsBedTransitionState(_routeState)) { StopMoving(); _bedTeleportReturnPosition = (((Object)(object)_body != (Object)null) ? _body.position : _cachedTransform.position); _bedTeleportReturnRotation = (((Object)(object)_body != (Object)null) ? _body.rotation : _cachedTransform.rotation); _hasBedTeleportReturnPoint = true; CacheSleepPose(); FreezeBodyForBed(); TeleportCharacter(_bed.RestPosition, _bed.RestRotation); BeginBedTransition(RestRouteState.LyingDown); } } private void BeginGettingUpFromBed() { if ((Object)(object)_bed == (Object)null) { LeaveBed(); _routeState = RestRouteState.Idle; return; } _standingOnBed = false; _sleepBreathingPoseCaptured = false; ResumeAnimatorAfterSleep(); FreezeBodyForBed(); BeginBedTransition(RestRouteState.GettingUp); } private void AdvanceBedTransition(float delta) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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_0081: 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) if ((Object)(object)_bed == (Object)null) { LeaveBed(); _routeState = RestRouteState.Idle; return; } Vector3 targetPosition; Quaternion targetRotation; float duration; if (_routeState == RestRouteState.LyingDown) { targetPosition = _sleepBodyPosition; targetRotation = _sleepBodyRotation; duration = 2.2f; } else { if (_routeState != RestRouteState.GettingUp) { return; } targetPosition = _bed.RestPosition; targetRotation = _bed.RestRotation; duration = 1.6f; } if (AnimateBedTransform(targetPosition, targetRotation, duration, delta)) { if (_routeState == RestRouteState.LyingDown) { CaptureSleepBreathingPose(); PauseAnimatorForSleep(); _standingOnBed = true; _routeState = RestRouteState.Sleeping; } else if (_routeState == RestRouteState.GettingUp) { FinishBedExit(); } } } private bool AnimateBedTransform(Vector3 targetPosition, Quaternion targetRotation, float duration, float delta) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0037: 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_003e: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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) //IL_005a: Unknown result type (might be due to invalid IL or missing references) _bedEntryTimer += delta; float num = Mathf.Clamp01(_bedEntryTimer / duration); float num2 = Mathf.SmoothStep(0f, 1f, num); Vector3 position = Vector3.Lerp(_bedEntryStartPosition, targetPosition, num2); Quaternion rotation = Quaternion.Slerp(_bedEntryStartRotation, targetRotation, num2); SetCharacterTransform(position, rotation); _character.SetMoveDir(Vector3.zero); return num >= 1f; } private void BeginBedTransition(RestRouteState state) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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_001e: Unknown result type (might be due to invalid IL or missing references) _bedEntryStartPosition = _cachedTransform.position; _bedEntryStartRotation = _cachedTransform.rotation; _bedEntryTimer = 0f; _routeState = state; } private void FreezeBodyForBed() { //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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_body == (Object)null)) { if (!_bodyStateSaved) { _savedBodyConstraints = _body.constraints; _savedBodyInterpolation = _body.interpolation; _savedBodyDetectCollisions = _body.detectCollisions; _bodyStateSaved = true; } ClearBodyVelocity(); _body.constraints = (RigidbodyConstraints)126; _body.interpolation = (RigidbodyInterpolation)0; _body.detectCollisions = false; if (!_body.isKinematic) { _body.Sleep(); } } } private void CacheSleepPose() { //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_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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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) //IL_004e: 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_0058: Unknown result type (might be due to invalid IL or missing references) Quaternion restRotation = _bed.RestRotation; _sleepBodyPosition = _bed.RestPosition + restRotation * Vector3.forward * 0.62f + Vector3.up * 0.06f; _sleepBodyRotation = restRotation * SleepBodyLocalRotation; } private void CaptureSleepBreathingPose() { //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) if (!((Object)(object)_sleepBreathingBone == (Object)null)) { _sleepBreathingBaseRotation = _sleepBreathingBone.localRotation; _sleepBreathingPoseCaptured = true; } } private void PauseAnimatorForSleep() { if (!((Object)(object)_animator == (Object)null) && !_animatorPausedForSleep) { _savedAnimatorSpeed = _animator.speed; _animator.speed = 0f; _animatorPausedForSleep = true; } } private void ResumeAnimatorAfterSleep() { if (!((Object)(object)_animator == (Object)null) && _animatorPausedForSleep) { _animator.speed = _savedAnimatorSpeed; _animatorPausedForSleep = false; } } private void FinishBedExit() { RestoreFromBed(); _routeState = RestRouteState.MorningToDoorInside; ResetNavigationProgress(); } private Transform FindSleepBreathingBone() { Transform[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); for (int i = 0; i < SleepBreathingBoneNames.Length; i++) { string text = SleepBreathingBoneNames[i]; foreach (Transform val in componentsInChildren) { if ((Object)(object)val != (Object)null && (string.Equals(((Object)val).name, text, StringComparison.OrdinalIgnoreCase) || ((Object)val).name.EndsWith(text, StringComparison.OrdinalIgnoreCase))) { return val; } } } return null; } private void LateUpdate() { //IL_006c: 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_0081: Unknown result type (might be due to invalid IL or missing references) if (_standingOnBed && !((Object)(object)_bed == (Object)null)) { LockSleepingPose(); if (!((Object)(object)_sleepBreathingBone == (Object)null) && _sleepBreathingPoseCaptured) { float num = Mathf.Sin(Time.time * 1.25f + _sleepBreathPhase) * 1.6f; _sleepBreathingBone.localRotation = _sleepBreathingBaseRotation * Quaternion.Euler(num, 0f, 0f); } } } private void HoldOnBed() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_character != (Object)null) { _character.SetMoveDir(Vector3.zero); } ClearBodyVelocity(); if ((Object)(object)_body != (Object)null && !_body.isKinematic) { _body.Sleep(); } } private void LockSleepingPose() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_character != (Object)null) { _character.SetMoveDir(Vector3.zero); } ClearBodyVelocity(); SetCharacterTransform(_sleepBodyPosition, _sleepBodyRotation); if ((Object)(object)_body != (Object)null && !_body.isKinematic) { _body.Sleep(); } } private void LeaveBed() { if (_standingOnBed || IsBedTransitionState(_routeState) || _bodyStateSaved || _hasBedTeleportReturnPoint) { RestoreFromBed(); } } private void RestoreFromBed() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) ResumeAnimatorAfterSleep(); ReturnToPreBedPosition(); RestoreBodyAfterBed(); if ((Object)(object)_character != (Object)null) { _character.SetMoveDir(Vector3.zero); } _standingOnBed = false; _bedEntryTimer = 0f; _sleepBreathingPoseCaptured = false; _hasBedTeleportReturnPoint = false; } private void ReturnToPreBedPosition() { //IL_0013: 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) if (_hasBedTeleportReturnPoint) { TeleportCharacter(_bedTeleportReturnPosition, _bedTeleportReturnRotation); } } private void SetCharacterTransform(Vector3 position, Quaternion rotation) { //IL_0033: 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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_body != (Object)null) { _body.position = position; _body.rotation = rotation; } _cachedTransform.SetPositionAndRotation(position, rotation); } private void TeleportCharacter(Vector3 position, Quaternion rotation) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) ClearBodyVelocity(); SetCharacterTransform(position, rotation); Physics.SyncTransforms(); } private void ClearBodyVelocity() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_body == (Object)null) && !_body.isKinematic) { _body.linearVelocity = Vector3.zero; _body.angularVelocity = Vector3.zero; } } private void RestoreBodyAfterBed() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) if (!_bodyStateSaved) { return; } if ((Object)(object)_body != (Object)null) { ClearBodyVelocity(); _body.constraints = _savedBodyConstraints; _body.interpolation = _savedBodyInterpolation; _body.detectCollisions = _savedBodyDetectCollisions; if (!_body.isKinematic) { _body.WakeUp(); } } _bodyStateSaved = false; } private void StopMoving() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (_isMoving && !((Object)(object)_character == (Object)null)) { _character.SetMoveDir(Vector3.zero); _isMoving = false; } } private void SetRestControl(bool controlled) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) if (_hasRestControl == controlled) { return; } _hasRestControl = controlled; if (_monsterAiInstanceId == 0) { return; } if (controlled) { ControlledMonsterAiIds.Add(_monsterAiInstanceId); if ((Object)(object)_character != (Object)null) { _character.SetMoveDir(Vector3.zero); } _isMoving = false; } else { ControlledMonsterAiIds.Remove(_monsterAiInstanceId); } } private void OnDisable() { if (_ready) { AbandonRestAssignment(); } } private void OnDestroy() { AbandonRestAssignment(); } } [HarmonyPatch(typeof(Bed), "Awake")] internal static class GoblinRestBedAttachPatch { private static void Postfix(Bed __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).GetComponent() != (Object)null)) { ((Component)__instance).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(Door), "Awake")] internal static class GoblinRestDoorAttachPatch { private static void Postfix(Door __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)((Component)__instance).GetComponent() != (Object)null)) { ((Component)__instance).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(GoblinWorkerController), "Start")] internal static class GoblinNightRestAttachPatch { private static void Postfix(GoblinWorkerController __instance) { if (!((Object)(object)__instance == (Object)null)) { EnsureAttached(((Component)__instance).gameObject); } } internal static void EnsureAttached(GameObject workerObject) { if (!((Object)(object)workerObject == (Object)null) && !((Object)(object)workerObject.GetComponent() != (Object)null)) { workerObject.AddComponent(); } } } [HarmonyPatch(typeof(GoblinGathererJob), "Start")] internal static class GoblinGathererNightRestAttachPatch { private static void Postfix(GoblinGathererJob __instance) { if ((Object)(object)__instance != (Object)null) { GoblinNightRestAttachPatch.EnsureAttached(((Component)__instance).gameObject); } } } [HarmonyPatch(typeof(MonsterAI), "UpdateAI")] internal static class GoblinNightRestMonsterAiPatch { private static bool Prefix(MonsterAI __instance) { return !GoblinNightRestJob.IsMonsterAiRestControlled(__instance); } }