using System; using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; using HG; using RoR2.CharacterAI; using UnityEngine; using UnityEngine.Networking; namespace RoR2; public class OutsideInteractableLocker : MonoBehaviour { private struct Candidate { public PurchaseInteraction purchaseInteraction; public float distanceSqr; } private class LockInfo { public GameObject lockObj; public float distSqr; public bool IsLocked() { return lockObj != null; } } [StructLayout(LayoutKind.Sequential, Size = 1)] private struct CandidateDistanceCompararer : IComparer { public int Compare(Candidate a, Candidate b) { return a.distanceSqr.CompareTo(b.distanceSqr); } } [Tooltip("The networked object which will be instantiated to lock purchasables.")] public GameObject lockPrefab; [Tooltip("How long to wait between steps.")] public float updateInterval = 0.1f; [Tooltip("Whether or not to invert the requirements.")] public bool lockInside; private Dictionary lockObjectMap; private Dictionary eggLockInfoMap; private float updateTimer; private IEnumerator currentCoroutine; public float radius { get; set; } private void Awake() { if (NetworkServer.active) { lockObjectMap = new Dictionary(); if (DevotionInventoryController.isDevotionEnable) { eggLockInfoMap = new Dictionary(); } } else { base.enabled = false; } } private void OnEnable() { if (NetworkServer.active) { currentCoroutine = ChestLockCoroutine(); updateTimer = updateInterval; } } private void OnDisable() { if (NetworkServer.active) { currentCoroutine = null; UnlockAll(); } } private void FixedUpdate() { updateTimer -= Time.fixedDeltaTime; if (updateTimer <= 0f) { updateTimer = updateInterval; currentCoroutine?.MoveNext(); } } private void LockPurchasable(PurchaseInteraction purchaseInteraction) { if (!purchaseInteraction.lockGameObject) { GameObject gameObject = UnityEngine.Object.Instantiate(lockPrefab, purchaseInteraction.transform.position, Quaternion.identity); NetworkServer.Spawn(gameObject); purchaseInteraction.NetworklockGameObject = gameObject; lockObjectMap.Add(purchaseInteraction, gameObject); } } private void UnlockPurchasable(PurchaseInteraction purchaseInteraction) { if (lockObjectMap.TryGetValue(purchaseInteraction, out var value) && !(value != purchaseInteraction.lockGameObject)) { UnityEngine.Object.Destroy(value); lockObjectMap.Remove(purchaseInteraction); } } private void UnlockAll() { foreach (GameObject value in lockObjectMap.Values) { UnityEngine.Object.Destroy(value); } lockObjectMap.Clear(); if (eggLockInfoMap == null) { return; } foreach (KeyValuePair item in eggLockInfoMap) { UnlockLemurianEgg(item.Key); } eggLockInfoMap.Clear(); } private void LockLemurianEgg(LemurianEggController egg) { GameObject gameObject = UnityEngine.Object.Instantiate(lockPrefab, egg.transform.position, Quaternion.identity); NetworkServer.Spawn(gameObject); eggLockInfoMap[egg].lockObj = gameObject; egg.SetInteractability(interactable: false); } private void UnlockLemurianEgg(LemurianEggController egg) { LockInfo lockInfo = eggLockInfoMap[egg]; if ((bool)lockInfo.lockObj) { NetworkServer.Destroy(lockInfo.lockObj); lockInfo.lockObj = null; } egg.SetInteractability(interactable: true); } private IEnumerator ChestLockCoroutine() { Candidate[] candidates = new Candidate[64]; int candidatesCount = 0; if (DevotionInventoryController.isDevotionEnable) { foreach (LemurianEggController instances in InstanceTracker.GetInstancesList()) { LockInfo lockInfo = new LockInfo(); lockInfo.lockObj = null; lockInfo.distSqr = (instances.transform.position - base.transform.position).sqrMagnitude; eggLockInfoMap[instances] = lockInfo; } } while (true) { Vector3 position = base.transform.position; if (DevotionInventoryController.isDevotionEnable) { foreach (KeyValuePair item in eggLockInfoMap) { float num = radius * radius; LockInfo value = item.Value; bool flag = value.distSqr <= num; value.IsLocked(); if (flag != lockInside) { UnlockLemurianEgg(item.Key); } else { LockLemurianEgg(item.Key); } } } List instancesList = InstanceTracker.GetInstancesList(); int num2 = candidatesCount; candidatesCount = instancesList.Count; ArrayUtils.EnsureCapacity(ref candidates, candidatesCount); for (int j = num2; j < candidatesCount; j++) { candidates[j] = default(Candidate); } for (int k = 0; k < candidatesCount; k++) { PurchaseInteraction purchaseInteraction = instancesList[k]; candidates[k] = new Candidate { purchaseInteraction = purchaseInteraction, distanceSqr = (purchaseInteraction.transform.position - position).sqrMagnitude }; } yield return null; Array.Sort(candidates, 0, candidatesCount, default(CandidateDistanceCompararer)); yield return null; int i = 0; while (i < candidatesCount) { PurchaseInteraction purchaseInteraction2 = candidates[i].purchaseInteraction; if ((bool)purchaseInteraction2) { float num3 = radius * radius; if (candidates[i].distanceSqr <= num3 != lockInside || !purchaseInteraction2.available) { UnlockPurchasable(purchaseInteraction2); } else { LockPurchasable(purchaseInteraction2); } yield return null; } int num4 = i + 1; i = num4; } yield return null; } } }