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 ExtractionConfirm v1.0.0
plugins/ExtractionConfirm.dll
Decompiled 8 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using UnityEngine; using UnityEngine.SceneManagement; [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("ExtractionConfirm")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+6db82c7aedec6d3546a3bf6d75c7a0bba7122f54")] [assembly: AssemblyProduct("ExtractionConfirm")] [assembly: AssemblyTitle("ExtractionConfirm")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ExtractionConfirm { internal sealed class ConfirmButton : MonoBehaviour { private const string VisualName = "Shop Button Visual"; private static readonly Color LitColor = new Color(1f, 0.5f, 0f); private static readonly Color DenyColor = new Color(1f, 0f, 0f, 1f); private ExtractionPoint _extractionPoint; private StaticGrabObject _grabObject; private Transform _visual; private Vector3 _baseScale; private Material _material; private Action _onPress; private bool _wasPressed; private float _animEval; private bool _animating; private float _flashTimer; public void Setup(ExtractionPoint extractionPoint, Transform head, StaticGrabObject grabObject, Action onPress) { //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_0098: Unknown result type (might be due to invalid IL or missing references) _extractionPoint = extractionPoint; _grabObject = grabObject; _onPress = onPress; _visual = FindDeep(head, "Shop Button Visual") ?? head; if ((Object)(object)_visual == (Object)null) { return; } _baseScale = _visual.localScale; MeshRenderer component = ((Component)_visual).GetComponent<MeshRenderer>(); if ((Object)(object)component != (Object)null) { _material = ((Renderer)component).material; if ((Object)(object)_material != (Object)null && _material.HasProperty("_EmissionColor")) { _material.SetColor("_EmissionColor", LitColor); } } } private static Transform FindDeep(Transform root, string name) { if ((Object)(object)root == (Object)null) { return null; } Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true); foreach (Transform val in componentsInChildren) { if ((Object)(object)val != (Object)null && ((Object)val).name == name) { return val; } } return null; } private void Update() { if (!((Object)(object)_extractionPoint == (Object)null)) { bool flag = ConfirmGate.IsLocallyGrabbed(_grabObject); if (flag && !_wasPressed) { Press(); } _wasPressed = flag; Animate(); TickFlash(); } } private void TickFlash() { //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (!(_flashTimer <= 0f)) { _flashTimer -= Time.deltaTime; if (!(_flashTimer > 0f) && (Object)(object)_material != (Object)null && _material.HasProperty("_EmissionColor")) { _material.SetColor("_EmissionColor", LitColor); } } } public void Flash() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) _flashTimer = 0.7f; if ((Object)(object)_material != (Object)null && _material.HasProperty("_EmissionColor")) { _material.SetColor("_EmissionColor", DenyColor); } } private void Press() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) _animEval = 0f; _animating = true; try { if (_extractionPoint.soundButton != null) { _extractionPoint.soundButton.Play(_visual.position, 1f, 1f, 1f, 1f); } } catch { } } private void Animate() { //IL_00a0: 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_00e0: 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) if (!_animating || (Object)(object)_extractionPoint == (Object)null) { return; } _animEval = Mathf.Clamp01(_animEval + Time.deltaTime * 2f); AnimationCurve buttonPressAnimationCurve = _extractionPoint.buttonPressAnimationCurve; float num = ((buttonPressAnimationCurve != null) ? buttonPressAnimationCurve.Evaluate(_animEval) : _animEval); float num2 = Mathf.Lerp(0.1f, num, 0.5f); if ((Object)(object)_visual != (Object)null) { _visual.localScale = new Vector3(_baseScale.x, _baseScale.y * num2, _baseScale.z); } if ((Object)(object)_material != (Object)null && _material.HasProperty("_EmissionColor")) { _material.SetColor("_EmissionColor", Color.Lerp(LitColor, Color.white, num)); } if (_animEval >= 1f) { _animating = false; if ((Object)(object)_visual != (Object)null) { _visual.localScale = _baseScale; } } } } internal static class ConfirmGate { private sealed class HoldState { public bool Confirmed; public bool Released; public bool TextApplied; public float LastConfirmTime = -99f; public string TubeTextOriginal; public Color TubeColorOriginal; public string ButtonHintOriginal; public ConfirmButton Button; public Transform Anchor; } public const byte ConfirmEventCode = 177; public const byte ValidationEventCode = 178; private const float ConfirmDebounce = 0.35f; private const string HoldText = "CONFIRM"; private const string ButtonHint = "Confirm extraction"; private static readonly Color HoldColor = new Color(1f, 0.5f, 0f); private static readonly Vector3 StandPosition = new Vector3(2.08f, 1.03f, 2.03f); private static readonly HashSet<string> ReportedErrors = new HashSet<string>(); private static readonly HashSet<string> ReportedReasons = new HashSet<string>(); private static readonly Dictionary<ExtractionPoint, HoldState> Holds = new Dictionary<ExtractionPoint, HoldState>(); private static FieldInfo _currentState; private static FieldInfo _isShop; private static FieldInfo _shopStation; private static FieldInfo _tubeTextString; private static FieldInfo _tubeTextColor; private static FieldInfo _buttonOriginalMaterial; private static FieldInfo _buttonDenyActive; private static FieldInfo _buttonDenyLerp; private static FieldInfo _haulCurrent; private static FieldInfo _roundDirectorInstance; private static FieldInfo _roundCurrentHaul; private static FieldInfo _grabbedStaticGrabObject; private static MethodInfo _tubeScreenTextChange; private static MethodInfo _stateSet; private static GameObject _standTemplate; private static bool _hostSettingKnown; private static bool _hostUsesAuto = true; private static int _hostAmount; private static float _nextValidationPush; private static ManualLogSource Log => ExtractionConfirmPlugin.Log; private static ConfirmSettings Settings => ExtractionConfirmPlugin.Settings; public static bool Resolve(Type extractionPointType) { try { _currentState = AccessTools.Field(extractionPointType, "currentState"); _isShop = AccessTools.Field(extractionPointType, "isShop"); _shopStation = AccessTools.Field(extractionPointType, "shopStation"); _tubeTextString = AccessTools.Field(extractionPointType, "tubeScreenTextString"); _tubeTextColor = AccessTools.Field(extractionPointType, "tubeScreenTextColor"); _buttonOriginalMaterial = AccessTools.Field(extractionPointType, "buttonOriginalMaterial"); _buttonDenyActive = AccessTools.Field(extractionPointType, "buttonDenyActive"); _buttonDenyLerp = AccessTools.Field(extractionPointType, "buttonDenyLerp"); _haulCurrent = AccessTools.Field(extractionPointType, "haulCurrent"); _tubeScreenTextChange = AccessTools.Method(extractionPointType, "TubeScreenTextChange", (Type[])null, (Type[])null); _stateSet = AccessTools.Method(extractionPointType, "StateSet", new Type[1] { typeof(State) }, (Type[])null); Type type = AccessTools.TypeByName("PhysGrabber"); _grabbedStaticGrabObject = ((type != null) ? AccessTools.Field(type, "grabbedStaticGrabObject") : null); Type type2 = AccessTools.TypeByName("RoundDirector"); if (type2 != null) { _roundDirectorInstance = AccessTools.Field(type2, "instance"); _roundCurrentHaul = AccessTools.Field(type2, "currentHaul"); } bool flag = _currentState != null && _isShop != null && _tubeTextString != null && _tubeTextColor != null && _buttonOriginalMaterial != null && _tubeScreenTextChange != null && _grabbedStaticGrabObject != null; if (!flag) { ManualLogSource log = Log; if (log != null) { log.LogError((object)("Missing members: " + $"currentState={_currentState != null}, isShop={_isShop != null}, " + $"tubeScreenTextString={_tubeTextString != null}, " + $"tubeScreenTextColor={_tubeTextColor != null}, " + $"buttonOriginalMaterial={_buttonOriginalMaterial != null}, " + $"TubeScreenTextChange={_tubeScreenTextChange != null}, " + $"PhysGrabber.grabbedStaticGrabObject={_grabbedStaticGrabObject != null}")); } } return flag; } catch (Exception arg) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogError((object)$"Failed to resolve game members: {arg}"); } return false; } } public static bool ShouldSkipTransition(ExtractionPoint ep, State newState) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Invalid comparison between Unknown and I4 //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Invalid comparison between Unknown and I4 //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Invalid comparison between Unknown and I4 //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Invalid comparison between Unknown and I4 //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Invalid comparison between Unknown and I4 //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Invalid comparison between Unknown and I4 if ((Object)(object)ep == (Object)null || _currentState == null) { return false; } HoldState holdState = Get(ep); if ((int)newState == 4) { if (!IsHolding(ep)) { RestoreTubeText(ep, holdState); return false; } if (holdState.Confirmed) { holdState.Confirmed = false; RestoreTubeText(ep, holdState); return false; } ApplyHoldVisuals(ep, holdState); return true; } if ((int)newState == 6 || (int)newState == 7 || (int)newState == 5 || (int)newState == 1 || (int)newState == 9) { holdState.Confirmed = false; RestoreTubeText(ep, holdState); } return false; } public static bool HandleButtonPress(ExtractionPoint ep) { if ((Object)(object)ep == (Object)null || _currentState == null) { return false; } if (IsHolding(ep)) { ConfirmExtraction(ep); return true; } if (!IsRequirementMet(ep)) { DenyPress(ep); } return false; } public static void ConfirmExtraction(ExtractionPoint ep) { if ((Object)(object)ep == (Object)null || _currentState == null) { return; } HoldState holdState = Get(ep); if (Time.time - holdState.LastConfirmTime < 0.35f) { return; } holdState.LastConfirmTime = Time.time; if (!IsHolding(ep)) { return; } if (SemiFunc.IsMultiplayer() && SemiFunc.IsNotMasterClient()) { if (RaiseConfirmRequest(ep)) { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"Confirmation press - requested the countdown from the host"); } } else { holdState.Confirmed = true; } } else { holdState.Confirmed = true; ManualLogSource log2 = Log; if (log2 != null) { log2.LogInfo((object)"Extraction confirmed - countdown starting"); } } } public static bool IsHolding(ExtractionPoint ep) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: 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_0026: Invalid comparison between Unknown and I4 //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Invalid comparison between Unknown and I4 if ((Object)(object)ep == (Object)null || IsShop(ep)) { return false; } State val = (State)_currentState.GetValue(ep); if ((int)val != 3) { return (int)val == 8; } return true; } public static bool IsLocallyGrabbed(StaticGrabObject grabObject) { try { PhysGrabber instance = PhysGrabber.instance; if ((Object)(object)instance == (Object)null || (Object)(object)grabObject == (Object)null) { return false; } return _grabbedStaticGrabObject.GetValue(instance) == grabObject; } catch { return false; } } private static bool IsShop(ExtractionPoint ep) { return (bool)_isShop.GetValue(ep); } public static void Tick(ExtractionPoint ep) { if ((Object)(object)ep == (Object)null) { return; } HoldState holdState = Get(ep); EnsureButton(ep); if (!IsHolding(ep)) { if (holdState.Confirmed) { holdState.Confirmed = false; } holdState.Released = false; RestoreTubeText(ep, holdState); } else { ApplyHoldVisuals(ep, holdState); ReleaseHold(ep, holdState); ArmButton(ep); WatchPress(ep, holdState); } } private static void ReleaseHold(ExtractionPoint ep, HoldState hold) { if (!hold.Confirmed || hold.Released || _stateSet == null) { return; } try { hold.Released = true; _stateSet.Invoke(ep, new object[1] { (object)(State)4 }); if (hold.Confirmed) { hold.Released = false; } } catch (Exception ex) { ReportPatchError("ReleaseHold", ex); hold.Released = false; } } private static void ArmButton(ExtractionPoint ep) { try { StaticGrabObject buttonGrabObject = ep.buttonGrabObject; if ((Object)(object)buttonGrabObject != (Object)null && !((Behaviour)buttonGrabObject).enabled) { ((Behaviour)buttonGrabObject).enabled = true; } if ((Object)(object)ep.buttonLight != (Object)null && !((Behaviour)ep.buttonLight).enabled) { ((Behaviour)ep.buttonLight).enabled = true; } MeshRenderer button = ep.button; object? obj = _buttonOriginalMaterial?.GetValue(ep); Material val = (Material)((obj is Material) ? obj : null); if ((Object)(object)button != (Object)null && (Object)(object)val != (Object)null && (Object)(object)((Renderer)button).material != (Object)(object)val) { ((Renderer)button).material = val; } } catch (Exception ex) { ReportPatchError("ArmButton", ex); } } private static void WatchPress(ExtractionPoint ep, HoldState hold) { if (hold.Confirmed) { return; } try { if (IsLocallyGrabbed(ep.buttonGrabObject)) { ConfirmExtraction(ep); } } catch (Exception ex) { ReportPatchError("WatchPress", ex); } } public static void Pump() { if (_currentState == null) { return; } ExtractionPoint[] array; try { array = Object.FindObjectsOfType<ExtractionPoint>(true); } catch (Exception ex) { ReportPatchError("FindObjectsOfType", ex); return; } ExtractionPoint[] array2 = array; foreach (ExtractionPoint val in array2) { if (!((Object)(object)val == (Object)null)) { EnsureButton(val); Tick(val); } } if (SemiFunc.IsMultiplayer() && PhotonNetwork.IsMasterClient) { PushValidationSetting(); } } public static void PreparePoint(ExtractionPoint ep) { try { if (!((Object)(object)ep == (Object)null)) { EnsureButton(ep); } } catch (Exception ex) { ReportPatchError("PreparePoint", ex); } } public static void EnsureButton(ExtractionPoint ep) { //IL_0114: 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_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: 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_0138: Expected O, but got Unknown //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015b: 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_0171: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0252: 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_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ep == (Object)null) { return; } HoldState holdState = Get(ep); if ((Object)(object)holdState.Button != (Object)null || SemiFunc.RunIsShop()) { return; } GameObject val = EnsureStandTemplate(ep); if ((Object)(object)val == (Object)null) { return; } try { GameObject val2 = Object.Instantiate<GameObject>(val, ((Component)ep).transform, false); ((Object)val2).name = "ExtractionConfirmStand"; val2.SetActive(true); Transform val3 = FindDeep(val2.transform, "Shop Button"); if ((Object)(object)val3 == (Object)null) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)"The shop stand has no 'Shop Button'; keeping the regular button."); } Object.Destroy((Object)(object)val2); return; } Neutralise(val2.transform); Transform val4 = (((Object)(object)ep.button != (Object)null) ? ((Component)ep.button).transform : null); if ((Object)(object)val4 == (Object)null) { ManualLogSource log2 = Log; if (log2 != null) { log2.LogWarning((object)"The extraction point has no button to move; keeping the stand where it spawned."); } Object.Destroy((Object)(object)val2); return; } Vector3 standPosition = StandPosition; if ((Object)(object)holdState.Anchor == (Object)null) { GameObject val5 = new GameObject("ExtractionConfirmAnchor"); val5.transform.SetParent(((Component)ep).transform, false); val5.transform.localPosition = standPosition - val4.localPosition; val5.transform.localRotation = Quaternion.identity; holdState.Anchor = val5.transform; Transform val6 = (((Object)(object)ep.buttonDenyTransform != (Object)null) ? ep.buttonDenyTransform : val4.parent); if ((Object)(object)val6 != (Object)null) { val6.SetParent(val5.transform, false); } } Vector3 val7 = ((Component)ep).transform.TransformPoint(standPosition); if (Vector3.Distance(val4.position, val7) > 0.05f) { ManualLogSource log3 = Log; if (log3 != null) { log3.LogWarning((object)($"The button did not move to the corner: at {val4.position}, expected {val7}. " + "buttonDenyTransform is probably no longer the button's parent.")); } } Vector3 localPosition = val3.localPosition; val2.transform.SetParent(((Component)ep).transform, false); val2.transform.localPosition = standPosition - localPosition; val2.transform.localRotation = Quaternion.identity; ((Renderer)ep.button).enabled = false; ConfirmButton confirmButton = ((Component)val3).gameObject.AddComponent<ConfirmButton>(); confirmButton.Setup(ep, val3, ep.buttonGrabObject, delegate { ConfirmExtraction(ep); }); holdState.Button = confirmButton; } catch (Exception ex) { ReportPatchError("EnsureButton", ex); } } private static GameObject EnsureStandTemplate(ExtractionPoint ep) { //IL_0095: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_standTemplate != (Object)null) { return _standTemplate; } object? obj = _shopStation?.GetValue(ep); Transform val = (Transform)((obj is Transform) ? obj : null); if ((Object)(object)val == (Object)null && (Object)(object)ep != (Object)null) { val = ((Component)ep).transform.Find("Scale/Shop Station"); } if ((Object)(object)val == (Object)null) { ReportReason("this extraction point has no Shop Station and none was cached yet"); return null; } GameObject obj2 = Object.Instantiate<GameObject>(((Component)val).gameObject); ((Object)obj2).name = "ExtractionConfirmTemplate"; obj2.SetActive(false); obj2.transform.position = new Vector3(0f, -5000f, 0f); Object.DontDestroyOnLoad((Object)(object)obj2); _standTemplate = obj2; return _standTemplate; } private static void Neutralise(Transform root) { Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true); foreach (Transform val in componentsInChildren) { MonoBehaviour[] components = ((Component)val).GetComponents<MonoBehaviour>(); for (int j = 0; j < components.Length; j++) { ((Behaviour)components[j]).enabled = false; } AudioSource[] components2 = ((Component)val).GetComponents<AudioSource>(); for (int j = 0; j < components2.Length; j++) { ((Behaviour)components2[j]).enabled = false; } } } private static Transform FindDeep(Transform root, string name) { if ((Object)(object)root == (Object)null) { return null; } Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true); foreach (Transform val in componentsInChildren) { if ((Object)(object)val != (Object)null && ((Object)val).name == name) { return val; } } return null; } private static void ReportReason(string reason) { if (ReportedReasons.Add(reason)) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("No confirm button: " + reason)); } } } private static void ApplyHoldVisuals(ExtractionPoint ep, HoldState hold) { //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_0043: Unknown result type (might be due to invalid IL or missing references) if (hold.TextApplied) { return; } try { hold.TubeTextOriginal = _tubeTextString.GetValue(ep) as string; hold.TubeColorOriginal = (Color)_tubeTextColor.GetValue(ep); hold.TextApplied = true; SetTubeText(ep, "CONFIRM", HoldColor); StaticGrabObject buttonGrabObject = ep.buttonGrabObject; if ((Object)(object)buttonGrabObject != (Object)null) { hold.ButtonHintOriginal = buttonGrabObject.hoverText; buttonGrabObject.hoverText = "Confirm extraction"; } if (SemiFunc.IsMultiplayer()) { ExtractionConfirmPlugin.Instance?.EnsureNetworkHook(); } } catch (Exception ex) { hold.TextApplied = false; ReportPatchError("ApplyHoldVisuals", ex); } } private static void RestoreTubeText(ExtractionPoint ep, HoldState hold) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (hold == null || !hold.TextApplied) { return; } hold.TextApplied = false; try { if (hold.TubeTextOriginal != null) { SetTubeText(ep, hold.TubeTextOriginal, hold.TubeColorOriginal); } if (hold.ButtonHintOriginal != null && (Object)(object)ep.buttonGrabObject != (Object)null) { ep.buttonGrabObject.hoverText = hold.ButtonHintOriginal; } hold.ButtonHintOriginal = null; } catch (Exception ex) { ReportPatchError("RestoreTubeText", ex); } } private static void SetTubeText(ExtractionPoint ep, string text, Color color) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) _tubeScreenTextChange.Invoke(ep, new object[2] { text ?? string.Empty, color }); } private static HoldState Get(ExtractionPoint ep) { if (Holds.Count > 16) { PruneDestroyed(); } if (!Holds.TryGetValue(ep, out var value)) { value = new HoldState(); Holds.Add(ep, value); } return value; } private static void PruneDestroyed() { List<ExtractionPoint> list = null; foreach (KeyValuePair<ExtractionPoint, HoldState> hold in Holds) { if ((Object)(object)hold.Key == (Object)null) { if (list == null) { list = new List<ExtractionPoint>(); } list.Add(hold.Key); } } if (list == null) { return; } foreach (ExtractionPoint item in list) { Holds.Remove(item); } } public static int RequiredHaul(ExtractionPoint ep) { if (_hostSettingKnown && SemiFunc.IsMultiplayer() && !SemiFunc.IsMasterClient()) { if (!_hostUsesAuto) { return _hostAmount; } return ep.haulGoal; } if (Settings.ValidationAuto.Value && Settings.ValidationAmount.Value == 0f) { return ep.haulGoal; } return Mathf.Clamp(Mathf.RoundToInt(Settings.ValidationAmount.Value), 0, 100000); } public static bool IsRequirementMet(ExtractionPoint ep) { try { return CurrentHaul(ep) >= RequiredHaul(ep); } catch (Exception ex) { ReportPatchError("IsRequirementMet", ex); return true; } } private static int CurrentHaul(ExtractionPoint ep) { if (_haulCurrent != null) { object value = _haulCurrent.GetValue(ep); if (value != null) { return Convert.ToInt32(value); } } object obj = _roundDirectorInstance?.GetValue(null); if (obj != null) { object obj2 = _roundCurrentHaul?.GetValue(obj); if (obj2 != null) { return Convert.ToInt32(obj2); } } return 0; } private static void DenyPress(ExtractionPoint ep) { //IL_008d: Unknown result type (might be due to invalid IL or missing references) try { _buttonDenyLerp?.SetValue(ep, 0f); _buttonDenyActive?.SetValue(ep, true); if ((Object)(object)ep.button != (Object)null && (Object)(object)ep.buttonDenyMaterial != (Object)null) { ((Renderer)ep.button).material = ep.buttonDenyMaterial; } if ((Object)(object)ep.buttonLight != (Object)null) { ((Behaviour)ep.buttonLight).enabled = true; } if (ep.soundCancel != null) { ep.soundCancel.Play(((Component)ep).transform.position, 1f, 1f, 1f, 1f); } HoldState holdState = Get(ep); if ((Object)(object)holdState.Button != (Object)null) { holdState.Button.Flash(); } ManualLogSource log = Log; if (log != null) { log.LogInfo((object)$"Denied: haul {CurrentHaul(ep)} of {RequiredHaul(ep)} required."); } } catch (Exception ex) { ReportPatchError("DenyPress", ex); } } private static void PushValidationSetting() { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected O, but got Unknown if (Time.unscaledTime < _nextValidationPush) { return; } _nextValidationPush = Time.unscaledTime + 5f; try { bool flag = Settings.ValidationAuto.Value && Settings.ValidationAmount.Value == 0f; int num = Mathf.Clamp(Mathf.RoundToInt(Settings.ValidationAmount.Value), 0, 100000); _hostUsesAuto = flag; _hostAmount = num; _hostSettingKnown = true; PhotonNetwork.RaiseEvent((byte)178, (object)new object[2] { flag ? "Auto" : "Fixed", num }, new RaiseEventOptions(), SendOptions.SendReliable); } catch (Exception ex) { ReportPatchError("PushValidationSetting", ex); } } private static void ApplyHostSetting(object[] payload) { if (payload != null && payload.Length >= 2) { _hostUsesAuto = Convert.ToString(payload[0]).Trim().Equals("Auto", StringComparison.OrdinalIgnoreCase); _hostAmount = Convert.ToInt32(payload[1]); _hostSettingKnown = true; ManualLogSource log = Log; if (log != null) { log.LogInfo((object)("Using the host's validation setting: " + (_hostUsesAuto ? "Auto" : ("Fixed " + _hostAmount)))); } } } private static bool RaiseConfirmRequest(ExtractionPoint ep) { //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_004f: Expected O, but got Unknown PhotonView component = ((Component)ep).GetComponent<PhotonView>(); if ((Object)(object)component == (Object)null) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)"Extraction point has no PhotonView; cannot reach the host"); } return false; } PhotonNetwork.RaiseEvent((byte)177, (object)new object[1] { component.ViewID }, new RaiseEventOptions(), SendOptions.SendReliable); return true; } public static void OnPhotonEvent(EventData eventData) { try { if (eventData == null) { return; } if (eventData.Code == 178) { ApplyHostSetting(eventData.CustomData as object[]); } else { if (eventData.Code != 177 || !PhotonNetwork.IsMasterClient || !(eventData.CustomData is object[] array) || array.Length < 1) { return; } PhotonView val = PhotonView.Find(Convert.ToInt32(array[0])); if ((Object)(object)val == (Object)null) { return; } ExtractionPoint component = ((Component)val).GetComponent<ExtractionPoint>(); if (!((Object)(object)component == (Object)null) && IsHolding(component)) { Get(component).Confirmed = true; ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"Confirmation received from a player - countdown starting"); } } } } catch (Exception ex) { ReportPatchError("OnPhotonEvent", ex); } } public static void ReportPatchError(string where, Exception ex) { if (ReportedErrors.Add(where)) { ManualLogSource log = Log; if (log != null) { log.LogError((object)$"Patch error in {where}: {ex}"); } } } } [BepInPlugin("com.repo.extractionconfirm", "ExtractionConfirm", "1.0.0")] [BepInProcess("REPO.exe")] public class ExtractionConfirmPlugin : BaseUnityPlugin, IOnEventCallback { public const string PluginGuid = "com.repo.extractionconfirm"; public const string PluginName = "ExtractionConfirm"; public const string PluginVersion = "1.0.0"; public static ExtractionConfirmPlugin Instance; public static ManualLogSource Log; public static ConfirmSettings Settings; private Harmony _harmony; private bool _networkHookInstalled; private void Awake() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; Settings = new ConfirmSettings(((BaseUnityPlugin)this).Config); Log.LogInfo((object)"ExtractionConfirm 1.0.0 loaded"); try { _harmony = new Harmony("com.repo.extractionconfirm"); ApplyPatches(_harmony); } catch (Exception arg) { Log.LogError((object)$"Failed to initialise: {arg}"); } try { ModRunner.Start(); } catch (Exception arg2) { Log.LogError((object)$"Failed to start the runner: {arg2}"); } } private void Update() { ModRunner.Tick(); } private static void ApplyPatches(Harmony harmony) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Expected O, but got Unknown //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Expected O, but got Unknown //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Expected O, but got Unknown //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Expected O, but got Unknown Type type = AccessTools.TypeByName("ExtractionPoint"); if (type == null) { Log.LogError((object)"ExtractionPoint type not found - ExtractionConfirm is inactive."); return; } if (!ConfirmGate.Resolve(type)) { Log.LogError((object)"ExtractionPoint members missing - ExtractionConfirm is inactive."); return; } MethodInfo methodInfo = AccessTools.Method(type, "StateSet", (Type[])null, (Type[])null); if (methodInfo == null) { Log.LogError((object)"ExtractionPoint.StateSet not found - ExtractionConfirm is inactive."); return; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ExtractionPatches), "StateSetPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); MethodInfo methodInfo2 = AccessTools.Method(type, "OnClick", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(type, "Start", Type.EmptyTypes, (Type[])null); MethodInfo methodInfo4 = AccessTools.Method(type, "Update", Type.EmptyTypes, (Type[])null); List<string> list = new List<string> { "ExtractionPoint.StateSet" }; if (methodInfo2 != null) { harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(ExtractionPatches), "OnClickPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); list.Add("ExtractionPoint.OnClick"); } else { Log.LogWarning((object)"ExtractionPoint.OnClick not found - a press of the extraction point's own button may not register."); } if (methodInfo3 != null) { harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(ExtractionPatches), "StartPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); list.Add("ExtractionPoint.Start"); } else { Log.LogWarning((object)"ExtractionPoint.Start not found - no per-point startup report."); } if (methodInfo4 != null) { harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(typeof(ExtractionPatches), "UpdatePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); list.Add("ExtractionPoint.Update"); } Type type2 = AccessTools.TypeByName("ChatManager"); MethodInfo methodInfo5 = ((type2 != null) ? AccessTools.Method(type2, "Update", Type.EmptyTypes, (Type[])null) : null); if (methodInfo5 != null) { harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, new HarmonyMethod(typeof(ExtractionPatches), "ChatUpdatePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); list.Add("ChatManager.Update"); } else { Log.LogWarning((object)"ChatManager.Update not found - the mod keeps no per-frame heartbeat."); } Log.LogInfo((object)("Patched " + string.Join(", ", list.ToArray()))); } internal void EnsureNetworkHook() { if (!_networkHookInstalled) { _networkHookInstalled = true; PhotonNetwork.AddCallbackTarget((object)this); } } public void OnEvent(EventData eventData) { try { ConfirmGate.OnPhotonEvent(eventData); } catch (Exception ex) { ConfirmGate.ReportPatchError("OnEvent", ex); } } } public class ConfirmSettings { public readonly ConfigEntry<bool> ValidationAuto; public readonly ConfigEntry<float> ValidationAmount; public ConfirmSettings(ConfigFile config) { ValidationAuto = config.Bind<bool>("Validation", "Auto", true, "True validates against the game's own haul goal. False uses Amount instead. Changing Amount turns this off automatically. In multiplayer the host's setting always wins."); ValidationAmount = config.Bind<float>("Validation", "Amount", 0f, "Fixed validation target, 0 to 100000. Changing this turns Auto off. Leave it at 0 to keep using the game's target. In multiplayer the host's value is what everyone uses."); ValidationAmount.SettingChanged += delegate { if (ValidationAmount.Value != 0f) { ValidationAuto.Value = false; } }; } } public static class ExtractionPatches { public static bool StateSetPrefix(ExtractionPoint __instance, State newState) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) try { return !ConfirmGate.ShouldSkipTransition(__instance, newState); } catch (Exception ex) { ConfirmGate.ReportPatchError("StateSet", ex); return true; } } public static bool OnClickPrefix(ExtractionPoint __instance) { try { return !ConfirmGate.HandleButtonPress(__instance); } catch (Exception ex) { ConfirmGate.ReportPatchError("OnClick", ex); return true; } } public static void StartPrefix(ExtractionPoint __instance) { try { ConfirmGate.PreparePoint(__instance); } catch (Exception ex) { ConfirmGate.ReportPatchError("Start", ex); } } public static void UpdatePostfix(ExtractionPoint __instance) { try { ConfirmGate.Tick(__instance); } catch (Exception ex) { ConfirmGate.ReportPatchError("Update", ex); } } public static void ChatUpdatePostfix() { try { ModRunner.Tick(); } catch (Exception ex) { ConfirmGate.ReportPatchError("ChatUpdate", ex); } } } internal static class ModRunner { private const float PumpInterval = 0.5f; private static bool _subscribed; private static float _nextPump; public static void Start() { if (!_subscribed) { _subscribed = true; SceneManager.sceneLoaded += OnSceneLoaded; } } public static void Stop() { if (_subscribed) { _subscribed = false; SceneManager.sceneLoaded -= OnSceneLoaded; } } private static void OnSceneLoaded(Scene scene, LoadSceneMode mode) { try { Pump(); } catch (Exception ex) { ConfirmGate.ReportPatchError("SceneLoaded", ex); } } public static void Tick() { if (!(Time.unscaledTime < _nextPump)) { Pump(); } } private static void Pump() { _nextPump = Time.unscaledTime + 0.5f; try { ConfirmGate.Pump(); } catch (Exception ex) { ConfirmGate.ReportPatchError("ModRunner", ex); } } } }