241 lines
5.8 KiB
C#
241 lines
5.8 KiB
C#
|
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<Candidate>
|
||
|
{
|
||
|
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<PurchaseInteraction, GameObject> lockObjectMap;
|
||
|
|
||
|
private Dictionary<LemurianEggController, LockInfo> eggLockInfoMap;
|
||
|
|
||
|
private float updateTimer;
|
||
|
|
||
|
private IEnumerator currentCoroutine;
|
||
|
|
||
|
public float radius { get; set; }
|
||
|
|
||
|
private void Awake()
|
||
|
{
|
||
|
if (NetworkServer.active)
|
||
|
{
|
||
|
lockObjectMap = new Dictionary<PurchaseInteraction, GameObject>();
|
||
|
if (DevotionInventoryController.isDevotionEnable)
|
||
|
{
|
||
|
eggLockInfoMap = new Dictionary<LemurianEggController, LockInfo>();
|
||
|
}
|
||
|
}
|
||
|
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<LemurianEggController, LockInfo> 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<LemurianEggController>())
|
||
|
{
|
||
|
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<LemurianEggController, LockInfo> 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<PurchaseInteraction> instancesList = InstanceTracker.GetInstancesList<PurchaseInteraction>();
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
}
|