Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ScanTweaks v1.7.0
ScanTweaks.dll
Decompiled 2 years agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using GameNetcodeStuff; using HarmonyLib; using LethalMDK; using ScanTweaks.World; using TMPro; using Unity.Netcode; using UnityEngine; using UnityMDK.Config; using UnityMDK.Injection; using UnityMDK.Logging; using UnityMDK.Reflection; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ScanTweaks")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.2.1")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ScanTweaks")] [assembly: AssemblyTitle("ScanTweaks")] [assembly: AssemblyVersion("1.2.1.0")] namespace ScanTweaks { public static class Player { public static bool IsServerOrHost { get { if (!NetworkManager.Singleton.IsHost) { return NetworkManager.Singleton.IsServer; } return true; } } } public class BatteryTextUpdater : MonoBehaviour { private GrabbableObject _grabbableObject; private ScanNodeProperties _scanNode; private static readonly string NoBatteryMsg = "No Battery"; private static readonly string[] BatteryPercentMsg = new string[2] { "Battery: ", "%" }; private int _currentBattery = int.MaxValue; private void Awake() { _grabbableObject = ((Component)this).GetComponentInParent<GrabbableObject>(true); _scanNode = ((Component)this).GetComponent<ScanNodeProperties>(); } private void Update() { if (!((Behaviour)_scanNode).enabled) { return; } if (_grabbableObject.insertedBattery == null) { _scanNode.subText = NoBatteryMsg; return; } int num = ((!_grabbableObject.insertedBattery.empty) ? ((int)Math.Ceiling(Math.Clamp(_grabbableObject.insertedBattery.charge * 100f, 0f, 100f))) : 0); if (_currentBattery != num) { _currentBattery = num; _scanNode.subText = string.Join(num.ToString(), BatteryPercentMsg); } } } public class CustomScanNodeProperties : ScanNodeProperties { [ConfigSection("PingScan")] [ConfigDescription("Adds a scan node to every item that didn't already have one.")] public static ConfigData<bool> EnableScanNodeForTools = new ConfigData<bool>(true); private void Awake() { GrabbableObject componentInParent = ((Component)this).GetComponentInParent<GrabbableObject>(true); if ((Object)(object)componentInParent != (Object)null && componentInParent.itemProperties.requiresBattery) { ((Component)this).gameObject.AddComponent<BatteryTextUpdater>(); } } } [InjectToComponent(typeof(IngamePlayerSettings), false)] public class PingScan : MonoBehaviour { [ConfigSection("PingScan")] [ConfigDescription("Enable/Disable the ping scan tweaks")] public static readonly ConfigData<bool> PingScanDoPatch = new ConfigData<bool>(true); [ConfigDescription("The delay between each ping scan step. A larger value will make the scan take longer to reach great distances.")] private static readonly ConfigData<float> PingScanStepDuration = new ConfigData<float>(0.01f); [ConfigDescription("Should dynamic objects (e.g. doors) block the ping scan")] private static readonly ConfigData<bool> DynamicObjectsBlockRaycast = new ConfigData<bool>(true); [ConfigDescription("Allows scanning objects in the hands of the players")] private static readonly ConfigData<bool> PlayerHeldItemsScannable = new ConfigData<bool>(false); [SerializeField] private float _range = 80f; [SerializeField] private float _outOfFrustumPaddingHorizontal = 0.2f; private readonly List<Collider> _currentScannedColliders = new List<Collider>(); private readonly List<ScanNodeProperties> _currentScannedNodes = new List<ScanNodeProperties>(); private readonly List<int> _currentScannedValues = new List<int>(); private readonly List<GrabbableObject> _currentScannedGrabbables = new List<GrabbableObject>(); private readonly Collider[] _hitAlloc = (Collider[])(object)new Collider[30]; private static readonly int _physicsMask = LayerMasks.Room; private static readonly int _doorMask = LayerMasks.InteractableObject; private float _outOfFrustumPaddingVertical => _outOfFrustumPaddingHorizontal * ((float)Screen.width / (float)Screen.height); public static int PingedScrapValue { get; private set; } public static int NodeUtility => 0; public static int NodeCreature => 1; public static int NodeScrap => 2; public static event Action<ScanNodeProperties> ScanNodeAdded; public static event Action<ScanNodeProperties> ScanNodeRemoved; public static event Action DoPing; internal static void TriggerPingScan() { PingScan.DoPing?.Invoke(); } private void Update() { PlayerControllerB localPlayer = Player.LocalPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { return; } if (localPlayer.inSpecialInteractAnimation && _currentScannedNodes.Count > 0) { RemoveAll(); } float outOfFrustumPaddingHorizontal = _outOfFrustumPaddingHorizontal; float outOfFrustumPaddingVertical = _outOfFrustumPaddingVertical; for (int num = _currentScannedNodes.Count - 1; num >= 0; num--) { ScanNodeProperties scanNode = _currentScannedNodes[num]; Collider nodeCollider = _currentScannedColliders[num]; GrabbableObject val = _currentScannedGrabbables[num]; if (!ConfigData<bool>.op_Implicit(PlayerHeldItemsScannable) && Object.op_Implicit((Object)(object)val) && val.isHeld && !val.isHeldByEnemy) { RemoveScanNodeAt(num); } else if (!IsNodeVisible(scanNode, nodeCollider, localPlayer.gameplayCamera, outOfFrustumPaddingHorizontal, outOfFrustumPaddingVertical)) { RemoveScanNodeAt(num); } } } private void OnEnable() { DoPing += OnPingScan; } private void OnDisable() { DoPing -= OnPingScan; RemoveAll(); } private void RemoveAll() { for (int num = _currentScannedNodes.Count - 1; num >= 0; num--) { RemoveScanNodeAt(num); } } private void OnPingScan() { Camera gameplayCamera = Player.LocalPlayer.gameplayCamera; ((MonoBehaviour)this).StartCoroutine(Pinging(gameplayCamera)); } private IEnumerator Pinging(Camera camera) { Transform transform = ((Component)camera).transform; Vector3 currentTestPos = transform.position; Vector3 direction = transform.forward; Quaternion boxOrientation = Quaternion.LookRotation(direction); Vector3 screenPos = Vector3.one; Vector3 extents = Vector3.one; float currentLength = 0f; float nextStep = Time.time; while (currentLength < _range) { yield return null; for (; Time.time >= nextStep; nextStep += ConfigData<float>.op_Implicit(PingScanStepDuration)) { UpdateExtents(); DoPing(); currentTestPos += direction * 0.5f; currentLength += 0.5f; } } void DoPing() { //IL_0001: 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_0013: Unknown result type (might be due to invalid IL or missing references) int num = Physics.OverlapBoxNonAlloc(currentTestPos, extents, _hitAlloc, boxOrientation, LayerMasks.ScanNode, (QueryTriggerInteraction)2); ScanNodeProperties val2 = default(ScanNodeProperties); for (int i = 0; i < num; i++) { Collider val = _hitAlloc[i]; if (((Component)val).TryGetComponent<ScanNodeProperties>(ref val2) && IsNodeVisible(val2, val, camera, 0f, 0f)) { AddScanNode(val2); } } } void UpdateExtents() { //IL_0023: 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) //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_0034: 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) screenPos.z = currentLength; Vector3 val3 = ((Component)camera).transform.InverseTransformPoint(camera.ViewportToWorldPoint(screenPos)); extents = val3; extents.z = 0.25f; } } private static bool PointOutOfViewport(float point, float padding) { if (!(point > 1f + padding)) { return point < 0f - padding; } return true; } private static bool IsNodeVisible(ScanNodeProperties scanNode, Collider nodeCollider, Camera camera, float paddingX, float paddingY) { //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_0042: 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_0049: 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) //IL_0057: 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_0084: 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) //IL_008f: 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_00ac: 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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)scanNode == (Object)null) { return false; } if (!((Behaviour)scanNode).enabled) { return false; } if (scanNode is CustomScanNodeProperties && !ConfigData<bool>.op_Implicit(CustomScanNodeProperties.EnableScanNodeForTools)) { return false; } if ((Object)(object)nodeCollider == (Object)null) { return false; } Vector3 position = ((Component)camera).transform.position; Bounds bounds = nodeCollider.bounds; Vector3 val = position - ((Bounds)(ref bounds)).center; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude < (float)scanNode.minRange) { return false; } if (magnitude > (float)scanNode.maxRange) { return false; } bounds = nodeCollider.bounds; Vector3 val2 = camera.WorldToViewportPoint(((Bounds)(ref bounds)).center); if (PointOutOfViewport(val2.x, paddingX) || PointOutOfViewport(val2.y, paddingY) || val2.z < 0f) { return false; } int num = _physicsMask; if (ConfigData<bool>.op_Implicit(DynamicObjectsBlockRaycast)) { num |= _doorMask; } if (scanNode.requiresLineOfSight) { bounds = nodeCollider.bounds; return !Linecast(position, ((Bounds)(ref bounds)).center, num); } return true; } private static bool Linecast(Vector3 start, Vector3 end, int layerMask) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //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_0057: 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_001a: 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_0041: 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_0055: 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_0028: 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) Vector3 val = end - start; if (Math.Abs(val.y) > 0.1f) { end = ((!(val.y > 0f)) ? (end + Vector3.up * 0.1f) : (end - Vector3.up * 0.1f)); } RaycastHit val2 = default(RaycastHit); if (!Physics.Linecast(start, end, ref val2, layerMask, (QueryTriggerInteraction)2)) { return false; } if (((Component)((RaycastHit)(ref val2)).collider).gameObject.CompareTag(Tags.InteractTrigger)) { return Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val2)).collider).GetComponent<AnimatedObjectTrigger>()); } return true; } private void AttemptScanNewCreature(int creatureID) { Terminal val = default(Terminal); if (creatureID >= 0 && Object.op_Implicit((Object)(object)HUDManager.Instance) && ReflectionUtility.TryGetField<Terminal>((object)HUDManager.Instance, "terminalScript", ref val) && !val.scannedEnemyIDs.Contains(creatureID)) { HUDManager.Instance.ScanNewCreatureServerRpc(creatureID); } } private void AddScanNode(ScanNodeProperties scanNodeProperties) { if (Object.op_Implicit((Object)(object)scanNodeProperties) && !_currentScannedNodes.Contains(scanNodeProperties)) { GrabbableObject componentInParent = ((Component)scanNodeProperties).GetComponentInParent<GrabbableObject>(); if (ConfigData<bool>.op_Implicit(PlayerHeldItemsScannable) || !Object.op_Implicit((Object)(object)componentInParent) || !componentInParent.isHeld || componentInParent.isHeldByEnemy) { Collider component = ((Component)scanNodeProperties).GetComponent<Collider>(); component.enabled = false; AttemptScanNewCreature(scanNodeProperties.creatureScanID); _currentScannedValues.Add((scanNodeProperties.nodeType == NodeScrap) ? scanNodeProperties.scrapValue : 0); _currentScannedColliders.Add(component); _currentScannedNodes.Add(scanNodeProperties); _currentScannedGrabbables.Add(componentInParent); CalculateTotalValue(); PingScan.ScanNodeAdded?.Invoke(scanNodeProperties); } } } private void RemoveScanNodeAt(int index) { if (index >= 0 && index < _currentScannedNodes.Count) { Collider val = _currentScannedColliders[index]; if (Object.op_Implicit((Object)(object)val)) { val.enabled = true; } _currentScannedValues.RemoveAt(index); CalculateTotalValue(); PingScan.ScanNodeRemoved?.Invoke(_currentScannedNodes[index]); _currentScannedColliders.RemoveAt(index); _currentScannedNodes.RemoveAt(index); _currentScannedGrabbables.RemoveAt(index); } } private void CalculateTotalValue() { PingedScrapValue = 0; foreach (int currentScannedValue in _currentScannedValues) { PingedScrapValue += currentScannedValue; } } } [Initializer(0)] public class ScanNodeCreator : ComponentInjector<GrabbableObject> { private static readonly string[] excludes = new string[1] { "sticky note" }; [Initializer(0)] private static void Init() { SceneInjection.AddComponentInjector<GrabbableObject>((ComponentInjector<GrabbableObject>)new ScanNodeCreator(), true); } protected override bool CanBeInjected(GrabbableObject component) { if (Object.op_Implicit((Object)(object)((Component)component).GetComponentInChildren<ScanNodeProperties>(true))) { return false; } if (component is RagdollGrabbableObject) { return false; } if (!Object.op_Implicit((Object)(object)component.itemProperties)) { return false; } if (string.IsNullOrEmpty(component.itemProperties.itemName)) { return true; } string[] array = excludes; foreach (string value in array) { if (component.itemProperties.itemName.Equals(value, StringComparison.InvariantCultureIgnoreCase)) { return false; } } return true; } protected override void Inject(GrabbableObject component) { //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_0028: 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_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_0049: 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_0059: Unknown result type (might be due to invalid IL or missing references) Transform transform = ((Component)component).transform; bool isScrap = component.itemProperties.isScrap; GameObject val = new GameObject("Scan Node") { layer = Layers.ScanNode }; val.transform.SetParent(transform); val.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); val.AddComponent<BoxCollider>().size = Vector3.one * 0.2f; CustomScanNodeProperties customScanNodeProperties = val.AddComponent<CustomScanNodeProperties>(); ((ScanNodeProperties)customScanNodeProperties).headerText = component.itemProperties.itemName; ((ScanNodeProperties)customScanNodeProperties).subText = (isScrap ? $"Value: ${component.scrapValue}" : "???"); ((ScanNodeProperties)customScanNodeProperties).minRange = 1; ((ScanNodeProperties)customScanNodeProperties).maxRange = 13; ((ScanNodeProperties)customScanNodeProperties).creatureScanID = -1; ((ScanNodeProperties)customScanNodeProperties).nodeType = (isScrap ? PingScan.NodeScrap : PingScan.NodeUtility); ((ScanNodeProperties)customScanNodeProperties).requiresLineOfSight = true; } } [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("Saradora.ScanTweaks", "Scan Tweaks", "1.7.0")] public class PluginInitializer : BaseUnityPlugin { private readonly Harmony _harmonyInstance = new Harmony("Saradora.ScanTweaks"); private void Awake() { ConfigBinder.BindAll(((BaseUnityPlugin)this).Config); _harmonyInstance.PatchAll(); } } public static class ScanTweaks { public const string ModGuid = "Saradora.ScanTweaks"; public const string ModVersion = "1.7.0"; public const string ModName = "Scan Tweaks"; } } namespace ScanTweaks.World { public class ApparaticeScrapValue : MonoBehaviour { [ConfigDescription("Minimum possible scrap value of the apparatice. This value has a x0.4 multiplier")] private static readonly ConfigData<int> ApparaticeMinValue = new ConfigData<int>(125); [ConfigDescription("Maximum possible scrap value of the apparatice. This value has a x0.4 multiplier")] private static readonly ConfigData<int> ApparaticeMaxValue = new ConfigData<int>(350); private LungProp _lungProp; public static readonly List<LungProp> PatchedApparatices = new List<LungProp>(); [ConfigSection("Apparatice")] [ConfigDescription("Make the apparatice have a random scrap value, also fixes the \"???\" on the scan node, Host-only")] public static ConfigData<bool> ApparaticeMakeRandomValue { get; } = new ConfigData<bool>(true); private void Awake() { _lungProp = ((Component)this).GetComponent<LungProp>(); } private static bool IsLungPropValid(LungProp lungProp) { if (!lungProp.isLungDocked || !lungProp.isLungPowered) { return false; } return ((GrabbableObject)lungProp).isInFactory; } private IEnumerator Start() { yield return (object)new WaitForSeconds(5f); if (IsLungPropValid(_lungProp) && ConfigData<bool>.op_Implicit(ApparaticeMakeRandomValue) && Player.IsServerOrHost) { int num = ConfigData<int>.op_Implicit(ApparaticeMinValue); int num2 = ConfigData<int>.op_Implicit(ApparaticeMaxValue); if (num > num2) { int num3 = num2; num2 = num; num = num3; } int scrapValue = (int)((float)RoundManager.Instance.AnomalyRandom.Next(num, num2) * RoundManager.Instance.scrapValueMultiplier); ((GrabbableObject)_lungProp).SetScrapValue(scrapValue); PatchedApparatices.Add(_lungProp); } } } [InjectToPrefab("LungApparatus")] public class ApparatusScrapValueInjector : IPrefabInjector { public void OnInject(GameObject obj) { if (ConfigData<bool>.op_Implicit(ApparaticeScrapValue.ApparaticeMakeRandomValue)) { LungProp componentInChildren = obj.GetComponentInChildren<LungProp>(); if ((Object)(object)componentInChildren == (Object)null) { Log.Error((object)"Couldn't find apparatus on prefab."); } else { ((Component)componentInChildren).gameObject.AddComponent<ApparaticeScrapValue>(); } } } } [InjectToPrefab("BreakerBox")] public class BreakerBoxPatcher : IPrefabInjector { public void OnInject(GameObject obj) { BreakerBox componentInChildren = obj.GetComponentInChildren<BreakerBox>(); if ((Object)(object)componentInChildren == (Object)null) { Log.Error((object)"Couldn't patch breaker box"); } else { ((Component)componentInChildren).gameObject.AddComponent<BreakerBoxScanNode>(); } } } public class BreakerBoxScanNode : MonoBehaviour { [ConfigSection("BreakerBox")] [ConfigDescription("Adds a scan node to the breaker box")] private static readonly ConfigData<bool> _breakerBoxScanNode = new ConfigData<bool>(true); [ConfigDescription("Minimum range of the scan node")] private static readonly ConfigData<int> _breakerBoxMinRange = new ConfigData<int>(3); [ConfigDescription("Maximum range of the scan node")] private static readonly ConfigData<int> _breakerBoxMaxRange = new ConfigData<int>(13); private static readonly Vector3 Offset = new Vector3(-1f, -0.8f, -1.2f); private ScanNodeProperties _scanNode; private void Start() { //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_0075: Expected O, but got Unknown //IL_007b: 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_0120: 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) _breakerBoxScanNode.ConfigChanged += OnNodeActiveStateChanged; _breakerBoxMinRange.ConfigChanged += OnMinRangeChanged; _breakerBoxMaxRange.ConfigChanged += OnMaxRangeChanged; _scanNode = ((Component)this).GetComponentInChildren<ScanNodeProperties>(true); if (!Object.op_Implicit((Object)(object)_scanNode)) { GameObject val = new GameObject("Scan Node") { layer = Layers.ScanNode }; val.AddComponent<BoxCollider>().size = Vector3.one * 0.2f; _scanNode = val.AddComponent<ScanNodeProperties>(); _scanNode.headerText = "Breaker Box"; _scanNode.subText = "Flip the switches! Maybe it'll do something?"; _scanNode.minRange = ConfigData<int>.op_Implicit(_breakerBoxMinRange); _scanNode.maxRange = ConfigData<int>.op_Implicit(_breakerBoxMaxRange); _scanNode.creatureScanID = -1; _scanNode.nodeType = 0; _scanNode.requiresLineOfSight = true; val.transform.SetParent(((Component)this).transform); val.transform.SetLocalPositionAndRotation(Offset, Quaternion.identity); } ((Behaviour)_scanNode).enabled = ConfigData<bool>.op_Implicit(_breakerBoxScanNode); } private void OnNodeActiveStateChanged(bool value) { if (Object.op_Implicit((Object)(object)_scanNode)) { ((Behaviour)_scanNode).enabled = value; } } private void OnMinRangeChanged(int value) { if (Object.op_Implicit((Object)(object)_scanNode)) { _scanNode.minRange = value; } } private void OnMaxRangeChanged(int value) { if (Object.op_Implicit((Object)(object)_scanNode)) { _scanNode.maxRange = value; } } private void OnDestroy() { _breakerBoxScanNode.ConfigChanged -= OnNodeActiveStateChanged; _breakerBoxMinRange.ConfigChanged -= OnMinRangeChanged; _breakerBoxMaxRange.ConfigChanged -= OnMaxRangeChanged; } } [InjectToComponent(typeof(StartOfRound), false)] public class RadarIcons : MonoBehaviour { [ConfigSection("Radar")] [ConfigDescription("Fixes the item radar so that item icons properly disappear when the item itself is destroyed (e.g. when a player is eaten).")] public static readonly ConfigData<bool> RadarPatchRadarIcons = new ConfigData<bool>(true); private static readonly ConfigData<bool> ShouldScrapsInShipBeVisible = new ConfigData<bool>(false); private static List<(GrabbableObject, MeshRenderer)> _radarIconList = new List<(GrabbableObject, MeshRenderer)>(); private static readonly Vector3 Offset = Vector3.up * 0.5f; private void Update() { //IL_00c3: 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_00cd: Unknown result type (might be due to invalid IL or missing references) for (int num = _radarIconList.Count - 1; num >= 0; num--) { var (val, val2) = _radarIconList[num]; if ((Object)(object)val == (Object)null) { if (Object.op_Implicit((Object)(object)val2)) { Object.Destroy((Object)(object)((Component)val2).gameObject); } _radarIconList.RemoveAt(num); } else if ((Object)(object)val2 == (Object)null) { _radarIconList.RemoveAt(num); } else { bool flag = !ConfigData<bool>.op_Implicit(ShouldScrapsInShipBeVisible) && val.isInShipRoom; if (((Renderer)val2).enabled = ((Component)val).gameObject.activeInHierarchy && !val.deactivated && (val.isHeld || !flag)) { ((Component)val2).transform.position = ((Component)val).transform.position + Offset; } } } } public static void AddRadarIcon(GrabbableObject grabbableObject, MeshRenderer radarIcon) { if (Object.op_Implicit((Object)(object)grabbableObject) && Object.op_Implicit((Object)(object)radarIcon)) { _radarIconList.Add((grabbableObject, radarIcon)); } } } } namespace ScanTweaks.UI { [InjectToComponent(typeof(HUDManager), false)] public class PingScanUI : MonoBehaviour { private struct ScannedObject { public float distance; public UIElement element; public ScannedObject(float distance, UIElement element) { this.distance = distance; this.element = element; } } private class ScannedObjectComparer : IComparer<ScannedObject> { public int Compare(ScannedObject x, ScannedObject y) { if (x.distance > y.distance) { return -1; } return 1; } } private struct UIElement { public RectTransform transform; public TextMeshProUGUI mainText; public TextMeshProUGUI subText; public override int GetHashCode() { return ((object)transform).GetHashCode(); } public override bool Equals(object obj) { Transform val = (Transform)((obj is Transform) ? obj : null); if (val != null) { return (Object)(object)transform == (Object)(object)val; } return ((object)transform).Equals(obj); } } [ConfigSection("PingScan")] [ConfigDescription("The speed at which the scrap counter updates.")] private static ConfigData<int> ScrapCounterUpdateSpeed = new ConfigData<int>(1000); [SerializeField] private float _counterInterval = 0.03f; private float _nextCounterUpdate; private HUDManager _hudManager; private Canvas _canvas; private RectTransform _canvasTransform; private RectTransform _nodeContainer; private Queue<UIElement> _uiElementsPool = new Queue<UIElement>(); private Dictionary<ScanNodeProperties, UIElement> _currentScanNodes = new Dictionary<ScanNodeProperties, UIElement>(); private static readonly int AColorNumber = Animator.StringToHash("colorNumber"); private static readonly int ADisplayBool = Animator.StringToHash("display"); private static readonly string DollarSign = "$"; private int _currentScrapValue; private readonly List<ScannedObject> _scannedObjects = new List<ScannedObject>(); private readonly List<ScanNodeProperties> _toDelete = new List<ScanNodeProperties>(); private readonly ScannedObjectComparer _distanceComparer = new ScannedObjectComparer(); private void Awake() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown _hudManager = ((Component)this).GetComponent<HUDManager>(); _canvas = ((Component)_hudManager.scanElements[0]).GetComponentInParent<Canvas>(true); _canvasTransform = (RectTransform)((Component)_canvas).transform; _nodeContainer = (RectTransform)((Component)((Transform)_hudManager.scanElements[0]).parent).transform; for (int i = 1; i < _hudManager.scanElements.Length; i++) { _uiElementsPool.Enqueue(GetUIElementFromRectTransform(_hudManager.scanElements[i])); } } private void OnEnable() { PingScan.ScanNodeAdded += OnScanNodeAdded; PingScan.ScanNodeRemoved += OnScanNodeRemoved; } private void OnDisable() { PingScan.ScanNodeAdded -= OnScanNodeAdded; PingScan.ScanNodeRemoved -= OnScanNodeRemoved; } private void LateUpdate() { UpdateNodeContainer(); UpdateScanNodes(); UpdateScrapValueCounter(); } private void UpdateNodeContainer() { //IL_0006: 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) _nodeContainer.sizeDelta = Vector2.zero; ((Transform)_nodeContainer).localPosition = Vector3.zero; } private void UpdateScanNodes() { //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_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_0044: 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_00cb: 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_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: 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_00f8: 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_00ff: 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_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_010d: Unknown result type (might be due to invalid IL or missing references) //IL_010e: 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_0118: 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) PlayerControllerB localPlayer = Player.LocalPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { return; } Camera gameplayCamera = localPlayer.gameplayCamera; Vector3 position = ((Component)gameplayCamera).transform.position; _toDelete.Clear(); _scannedObjects.Clear(); Vector2 sizeDelta = _canvasTransform.sizeDelta; Vector2 val = Vector2.one * 0.5f; foreach (var (val3, element) in _currentScanNodes) { if (!Object.op_Implicit((Object)(object)val3)) { _toDelete.Add(val3); continue; } ((TMP_Text)element.mainText).text = val3.headerText; ((TMP_Text)element.subText).text = val3.subText; Vector3 position2 = ((Component)val3).transform.position; float distance = Vector3.SqrMagnitude(position2 - position); _scannedObjects.Add(new ScannedObject(distance, element)); Vector3 val4 = gameplayCamera.WorldToViewportPoint(position2); val4 = Vector2.op_Implicit((Vector2.op_Implicit(val4) - val) * sizeDelta); ((Transform)element.transform).localPosition = val4; } _scannedObjects.Sort(_distanceComparer); foreach (ScanNodeProperties item in _toDelete) { OnScanNodeRemoved(item); } int count = _scannedObjects.Count; for (int i = 0; i < count; i++) { ((Transform)_scannedObjects[i].element.transform).SetSiblingIndex(i); } } private void UpdateScrapValueCounter() { if (PingScan.PingedScrapValue != _currentScrapValue && !(Time.time < _nextCounterUpdate)) { _nextCounterUpdate = Time.time + _counterInterval; if (!_hudManager.scanInfoAnimator.GetBool(ADisplayBool)) { _hudManager.scanInfoAnimator.SetBool(ADisplayBool, true); } if (_currentScrapValue < PingScan.PingedScrapValue) { float num = ConfigData<int>.op_Implicit(ScrapCounterUpdateSpeed); int val = Math.Abs(PingScan.PingedScrapValue - _currentScrapValue); val = Math.Max(100, val); num *= (float)val * 0.01f; _currentScrapValue = Mathf.RoundToInt(Mathf.MoveTowards((float)_currentScrapValue, (float)PingScan.PingedScrapValue, num * Time.deltaTime)); _hudManager.UIAudio.PlayOneShot(_hudManager.addToScrapTotalSFX); } else { _currentScrapValue = PingScan.PingedScrapValue; } ((TMP_Text)_hudManager.totalValueText).text = DollarSign + _currentScrapValue; if (_currentScrapValue == 0) { _hudManager.scanInfoAnimator.SetBool(ADisplayBool, false); } else if (PingScan.PingedScrapValue == _currentScrapValue) { _hudManager.UIAudio.PlayOneShot(_hudManager.finishAddingToTotalSFX); } } } private UIElement GetUIElementFromRectTransform(RectTransform instance) { TextMeshProUGUI[] componentsInChildren = ((Component)((Component)instance).transform).GetComponentsInChildren<TextMeshProUGUI>(true); UIElement result = default(UIElement); result.transform = instance; result.mainText = componentsInChildren[0]; result.subText = componentsInChildren[1]; return result; } private UIElement GetFreeUIElement() { if (_uiElementsPool.Count > 0) { return _uiElementsPool.Dequeue(); } RectTransform instance = Object.Instantiate<RectTransform>(_hudManager.scanElements[0], ((Component)_hudManager.scanElements[0]).transform.parent); return GetUIElementFromRectTransform(instance); } private void OnScanNodeAdded(ScanNodeProperties scanNode) { if (!_currentScanNodes.ContainsKey(scanNode)) { UIElement freeUIElement = GetFreeUIElement(); ((Component)freeUIElement.transform).gameObject.SetActive(true); ((TMP_Text)freeUIElement.mainText).text = scanNode.headerText; ((TMP_Text)freeUIElement.subText).text = scanNode.subText; ((Component)freeUIElement.transform).GetComponent<Animator>().SetInteger(AColorNumber, scanNode.nodeType); _currentScanNodes.Add(scanNode, freeUIElement); } } private void OnScanNodeRemoved(ScanNodeProperties scanNode) { if (_currentScanNodes.ContainsKey(scanNode)) { UIElement item = _currentScanNodes[scanNode]; ((Component)item.transform).gameObject.SetActive(false); _currentScanNodes.Remove(scanNode); _uiElementsPool.Enqueue(item); } } } } namespace ScanTweaks.Patches { [HarmonyPatch(typeof(GrabbableObject))] internal static class GrabbableObject_Patching { [HarmonyPatch("Start")] [HarmonyPostfix] private static void Start_PostFix(GrabbableObject __instance) { if (ConfigData<bool>.op_Implicit(RadarIcons.RadarPatchRadarIcons)) { PatchRadarIcon(__instance); } PatchPropColliders(__instance); } private static void PatchRadarIcon(GrabbableObject grabbableObject) { if (Object.op_Implicit((Object)(object)grabbableObject.radarIcon) && !(grabbableObject is RagdollGrabbableObject)) { RadarIcons.AddRadarIcon(grabbableObject, ((Component)grabbableObject.radarIcon).GetComponent<MeshRenderer>()); ((Component)grabbableObject.radarIcon).transform.SetParent(((Component)StartOfRound.Instance).transform); grabbableObject.radarIcon = null; } } private static void PatchPropColliders(GrabbableObject grabbableObject) { List<Collider> list = new List<Collider>(); Collider[] propColliders = grabbableObject.propColliders; foreach (Collider val in propColliders) { if (((Component)val).gameObject.layer != Layers.ScanNode) { list.Add(val); } } grabbableObject.propColliders = list.ToArray(); } } [HarmonyPatch(typeof(HUDManager))] internal static class HUDManager_Patching { private static bool _insideUpdate; [HarmonyPatch("CanPlayerScan")] [HarmonyPrefix] private static bool CanPlayerScan_Prefix(ref bool __result) { if (!ConfigData<bool>.op_Implicit(PingScan.PingScanDoPatch)) { return true; } if (!_insideUpdate) { return true; } __result = false; return false; } [HarmonyPatch("PingScan_performed")] [HarmonyPostfix] private static void PingScan_performed_Postfix(HUDManager __instance) { if (!((Object)(object)Player.LocalPlayer == (Object)null) && !(ReflectionUtility.GetField<float>((object)__instance, "playerPingingScan") < 0.3f)) { PingScan.TriggerPingScan(); } } [HarmonyPatch("Update")] [HarmonyPrefix] [HarmonyPriority(0)] private static void Update_Prefix() { _insideUpdate = true; } [HarmonyPatch("Update")] [HarmonyPostfix] [HarmonyPriority(800)] private static void Update_Postfix() { _insideUpdate = false; } } [HarmonyPatch(typeof(RoundManager))] public static class RoundManager_Patching { [HarmonyPatch("waitForScrapToSpawnToSync")] [HarmonyPrefix] private static void waitForScrapToSpawnToSync_Prefix() { ApparaticeScrapValue.PatchedApparatices.Clear(); } [HarmonyPatch("SyncScrapValuesClientRpc")] [HarmonyPrefix] private static void SyncScrapValuesClientRpc_Prefix(ref NetworkObjectReference[] spawnedScrap, ref int[] allScrapValue) { //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_0044: 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) if (!Player.IsServerOrHost) { return; } List<NetworkObjectReference> list = spawnedScrap.ToList(); List<int> list2 = allScrapValue.ToList(); foreach (LungProp patchedApparatice in ApparaticeScrapValue.PatchedApparatices) { if (!((Object)(object)patchedApparatice == (Object)null)) { NetworkObjectReference item = NetworkObjectReference.op_Implicit(((NetworkBehaviour)patchedApparatice).NetworkObject); if (!list.Contains(item)) { list.Add(item); list2.Add(((GrabbableObject)patchedApparatice).scrapValue); } } } spawnedScrap = list.ToArray(); allScrapValue = list2.ToArray(); } } [HarmonyPatch(typeof(StartOfRound))] public static class StartOfRound_Patching { [ConfigSection("Patches")] [ConfigDescription("Patches the loot not being properly registered as inside the ship when joining a game as client.")] public static readonly ConfigData<bool> PatchLootInShip = new ConfigData<bool>(true); [HarmonyPatch("SyncAlreadyHeldObjectsServerRpc")] [HarmonyPrefix] private static void SyncAlreadyHeldObjectsServerRpc_Prefix(int joiningClientId) { if ((int)NetworkManager.Singleton.LocalClientId != joiningClientId) { return; } try { GameObject val = GameObject.Find("/Environment/HangarShip"); ((MonoBehaviour)val.GetComponent<ElevatorAnimationEvents>()).StartCoroutine(WaitForSyncItems(val)); } catch (Exception ex) { Debug.LogException(ex); } } private static IEnumerator WaitForSyncItems(GameObject shipObject) { yield return (object)new WaitForSeconds(2f); if (!ConfigData<bool>.op_Implicit(PatchLootInShip)) { yield break; } GrabbableObject[] componentsInChildren = shipObject.GetComponentsInChildren<GrabbableObject>(); foreach (GrabbableObject val in componentsInChildren) { if (!val.isInShipRoom) { val.scrapPersistedThroughRounds = true; GameNetworkManager.Instance.localPlayerController.SetItemInElevator(true, true, val); } } } } }