using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BalrondCargoSystems; using BepInEx; using HarmonyLib; using LitJson2; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("BalrondCargoSystems")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("BalrondCargoSystems")] [assembly: AssemblyCopyright("Copyright © 2022")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("cde312a0-cf19-4264-8616-e1c74774beed")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] public enum BalrondLiftGateState { Closed, Opening, Open, Closing } public class BalrondLiftGate : MonoBehaviour, Hoverable, Interactable { private const string RpcToggle = "RPC_BalrondLiftGate_Toggle"; private const string RpcSetOpen = "RPC_BalrondLiftGate_SetOpen"; private const string ZdoState = "BalrondLiftGate_State"; private const string ZdoAnimStart = "BalrondLiftGate_AnimStart"; private const string ZdoInitialized = "BalrondLiftGate_Initialized"; [Header("Gate")] public string m_name = "Lift Gate"; public bool m_enabled = true; public bool m_defaultOpen = false; [Header("Gate Animation")] public Transform m_gatePivot; public Vector3 m_gateAxis = Vector3.right; public float m_openAngle = 85f; public float m_openDirection = 1f; public float m_animationSeconds = 2f; [Header("Gears - One Side")] public Transform m_gearStatic; public Transform m_gearBridge; public Vector3 m_gearAxis = Vector3.right; public float m_gearDegreesPerGateDegree = 4f; [Header("Animation Audio")] public GameObject m_animationActiveObject; [Header("Effects")] public EffectList m_openStartEffects = new EffectList(); public EffectList m_closeStartEffects = new EffectList(); [Header("Debug")] public bool m_debugLogs = false; private ZNetView _nview; private Quaternion _closedLocalRotation; private bool _closedRotationCached; private void Awake() { _nview = ((Component)this).GetComponent(); CacheClosedRotation(); if ((Object)(object)_nview != (Object)null && _nview.IsValid()) { _nview.Register("RPC_BalrondLiftGate_Toggle", (Action)RPC_Toggle); _nview.Register("RPC_BalrondLiftGate_SetOpen", (Action)RPC_SetOpen); ZDO zDO = _nview.GetZDO(); if (zDO != null && !zDO.GetBool("BalrondLiftGate_Initialized", false)) { ClaimOwnershipIfNeeded(); BalrondLiftGateState balrondLiftGateState = (m_defaultOpen ? BalrondLiftGateState.Open : BalrondLiftGateState.Closed); zDO.Set("BalrondLiftGate_State", (int)balrondLiftGateState); zDO.Set("BalrondLiftGate_AnimStart", GetNetworkTime()); zDO.Set("BalrondLiftGate_Initialized", true); } } BalrondLiftGateState state = GetState(); ApplyVisual(GetVisualProgress(state)); UpdateAnimationActiveObject(state); } private void Update() { UpdateAnimationAndState(); } public string GetHoverName() { return m_name; } public string GetHoverText() { string text = m_name + " State: " + GetStateText(GetState()); text = text + "\n[$KEY_Use] " + (IsOpenOrOpening() ? "Close" : "Open"); BCSSignalLiftGateReceiver component = ((Component)this).GetComponent(); if ((Object)(object)component != (Object)null) { text += component.GetExtraHoverText(); } return (Localization.instance != null) ? Localization.instance.Localize(text) : text; } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (hold || !m_enabled) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)val == (Object)null) { return false; } if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return true; } BCSSignalLiftGateReceiver component = ((Component)this).GetComponent(); if ((Object)(object)component != (Object)null) { if (IsShiftHeld()) { component.RequestSetSignalNameFromUser(); return true; } if (IsAltHeld()) { component.ToggleEventStateFromUser(); return true; } } if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { return false; } _nview.InvokeRPC("RPC_BalrondLiftGate_Toggle", Array.Empty()); return true; } private static bool IsShiftHeld() { return Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303); } private static bool IsAltHeld() { return Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307); } public bool UseItem(Humanoid user, ItemData item) { return false; } public void RequestOpen() { RequestSetOpen(open: true); } public void RequestClose() { RequestSetOpen(open: false); } public void RequestSetOpen(bool open) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { _nview.InvokeRPC("RPC_BalrondLiftGate_SetOpen", new object[1] { open }); } } public bool IsOpen() { return GetState() == BalrondLiftGateState.Open; } public bool IsClosed() { return GetState() == BalrondLiftGateState.Closed; } public bool IsAnimating() { BalrondLiftGateState state = GetState(); return state == BalrondLiftGateState.Opening || state == BalrondLiftGateState.Closing; } public bool IsOpenOrOpening() { BalrondLiftGateState state = GetState(); return state == BalrondLiftGateState.Open || state == BalrondLiftGateState.Opening; } public BalrondLiftGateState GetState() { ZDO zdo = GetZdo(); if (zdo == null) { return m_defaultOpen ? BalrondLiftGateState.Open : BalrondLiftGateState.Closed; } return zdo.GetInt("BalrondLiftGate_State", m_defaultOpen ? 2 : 0) switch { 1 => BalrondLiftGateState.Opening, 2 => BalrondLiftGateState.Open, 3 => BalrondLiftGateState.Closing, _ => BalrondLiftGateState.Closed, }; } private void RPC_Toggle(long sender) { if (m_enabled && !IsAnimating()) { SetTargetOpenOwned(!IsOpenOrOpening()); } } private void RPC_SetOpen(long sender, bool open) { if (m_enabled) { SetTargetOpenOwned(open); } } private void SetTargetOpenOwned(bool open) { if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { return; } ClaimOwnershipIfNeeded(); BalrondLiftGateState state = GetState(); if (state == BalrondLiftGateState.Opening || state == BalrondLiftGateState.Closing) { return; } if (open) { if (state != BalrondLiftGateState.Open) { SetStateOwned(BalrondLiftGateState.Opening); CreateEffects(m_openStartEffects); } } else if (state != 0) { SetStateOwned(BalrondLiftGateState.Closing); CreateEffects(m_closeStartEffects); } } private void SetStateOwned(BalrondLiftGateState state) { ZDO zdo = GetZdo(); if (zdo != null) { ClaimOwnershipIfNeeded(); zdo.Set("BalrondLiftGate_State", (int)state); zdo.Set("BalrondLiftGate_AnimStart", GetNetworkTime()); } } private void SetStateNoRestartOwned(BalrondLiftGateState state) { ZDO zdo = GetZdo(); if (zdo != null) { ClaimOwnershipIfNeeded(); zdo.Set("BalrondLiftGate_State", (int)state); } } private void UpdateAnimationAndState() { if (!m_enabled) { return; } CacheClosedRotation(); BalrondLiftGateState state = GetState(); float num = Mathf.Max(0.01f, SanitizeFloat(m_animationSeconds, 2f)); float animStartTime = GetAnimStartTime(); float networkTime = GetNetworkTime(); float num2 = Mathf.Clamp01((networkTime - animStartTime) / num); float progress = 0f; switch (state) { case BalrondLiftGateState.Closed: progress = 0f; break; case BalrondLiftGateState.Open: progress = 1f; break; case BalrondLiftGateState.Opening: progress = num2; if (num2 >= 1f && IsOwner()) { SetStateNoRestartOwned(BalrondLiftGateState.Open); } break; case BalrondLiftGateState.Closing: progress = 1f - num2; if (num2 >= 1f && IsOwner()) { SetStateNoRestartOwned(BalrondLiftGateState.Closed); } break; } ApplyVisual(progress); UpdateAnimationActiveObject(state); } private void ApplyVisual(float progress) { //IL_006f: 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_0079: 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_0087: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp01(progress); float num2 = Mathf.Sign(SanitizeFloat(m_openDirection, 1f)); if (Mathf.Abs(num2) <= 0.001f) { num2 = 1f; } float num3 = num * Mathf.Max(0f, SanitizeFloat(m_openAngle, 85f)) * num2; if ((Object)(object)m_gatePivot != (Object)null) { Vector3 safeAxis = GetSafeAxis(m_gateAxis, Vector3.right); m_gatePivot.localRotation = _closedLocalRotation * Quaternion.AngleAxis(num3, safeAxis); } float num4 = Mathf.Abs(num3) * Mathf.Max(0f, SanitizeFloat(m_gearDegreesPerGateDegree, 4f)); ApplyGear(m_gearStatic, 0f - num4); ApplyGear(m_gearBridge, num4); } private Transform GetGearRotationPivot(Transform gearRoot) { if ((Object)(object)gearRoot == (Object)null) { return null; } if (((Object)gearRoot).name == "gear-pivot") { return gearRoot; } Transform val = gearRoot.Find("gear-pivot"); if ((Object)(object)val != (Object)null) { return val; } Transform[] componentsInChildren = ((Component)gearRoot).GetComponentsInChildren(true); foreach (Transform val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null && ((Object)val2).name == "gear-pivot") { return val2; } } return gearRoot; } private void ApplyGear(Transform gearRoot, float angle) { //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_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_002a: 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) Transform gearRotationPivot = GetGearRotationPivot(gearRoot); if (!((Object)(object)gearRotationPivot == (Object)null)) { Vector3 safeAxis = GetSafeAxis(m_gearAxis, Vector3.right); gearRotationPivot.localRotation = Quaternion.AngleAxis(angle, safeAxis); } } private void CacheClosedRotation() { //IL_0026: 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) if (!_closedRotationCached && !((Object)(object)m_gatePivot == (Object)null)) { _closedLocalRotation = m_gatePivot.localRotation; _closedRotationCached = true; } } private float GetVisualProgress(BalrondLiftGateState state) { if (state == BalrondLiftGateState.Open || state == BalrondLiftGateState.Opening) { return 1f; } return 0f; } private void UpdateAnimationActiveObject(BalrondLiftGateState state) { bool flag = state == BalrondLiftGateState.Opening || state == BalrondLiftGateState.Closing; if ((Object)(object)m_animationActiveObject == (Object)null) { return; } if (m_animationActiveObject.activeSelf != flag) { m_animationActiveObject.SetActive(flag); } AudioSource[] componentsInChildren = m_animationActiveObject.GetComponentsInChildren(true); foreach (AudioSource val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } val.loop = true; if (flag) { if (!val.isPlaying) { val.Play(); } continue; } if (val.isPlaying) { val.Stop(); } val.time = 0f; } } private void CreateEffects(EffectList effects) { //IL_0027: 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) if (effects != null && effects.m_effectPrefabs != null && effects.m_effectPrefabs.Length != 0) { effects.Create(((Component)this).transform.position, ((Component)this).transform.rotation, (Transform)null, 1f, -1); } } private float GetAnimStartTime() { ZDO zdo = GetZdo(); if (zdo == null) { return GetNetworkTime(); } return zdo.GetFloat("BalrondLiftGate_AnimStart", GetNetworkTime()); } private string GetStateText(BalrondLiftGateState state) { return state switch { BalrondLiftGateState.Open => "Open", BalrondLiftGateState.Opening => "Opening", BalrondLiftGateState.Closing => "Closing", _ => "Closed", }; } private ZDO GetZdo() { if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { return null; } return _nview.GetZDO(); } private bool IsOwner() { return (Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.IsOwner(); } private void ClaimOwnershipIfNeeded() { if ((Object)(object)_nview != (Object)null && _nview.IsValid() && !_nview.IsOwner()) { _nview.ClaimOwnership(); } } private static Vector3 GetSafeAxis(Vector3 axis, Vector3 fallback) { //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_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_002b: Unknown result type (might be due to invalid IL or missing references) if (((Vector3)(ref axis)).sqrMagnitude <= 0.0001f) { return ((Vector3)(ref fallback)).normalized; } return ((Vector3)(ref axis)).normalized; } private static float SanitizeFloat(float value, float fallback) { if (float.IsNaN(value) || float.IsInfinity(value)) { return fallback; } return value; } private static float GetNetworkTime() { if ((Object)(object)ZNet.instance != (Object)null) { return (float)ZNet.instance.GetTimeSeconds(); } return Time.time; } private void Log(string msg) { if (m_debugLogs) { Debug.Log((object)("[BalrondLiftGate][" + ((Object)((Component)this).gameObject).name + "] " + msg)); } } } namespace BalrondCargoSystems { public class BalrondTranslator { public static Dictionary> translations = new Dictionary>(); public static Dictionary getLanguage(string language) { if (string.IsNullOrEmpty(language)) { return null; } if (translations.TryGetValue(language, out var value)) { return value; } return null; } } public static class BCSPrefabFind { public static T GetOrAdd(GameObject prefab) where T : Component { T component = prefab.GetComponent(); return ((Object)(object)component != (Object)null) ? component : prefab.AddComponent(); } public static void DestroyIfExists(Object obj) { if (obj != (Object)null) { Object.DestroyImmediate(obj); } } public static Transform FindTransformDeep(GameObject prefab, string childName) { if ((Object)(object)prefab == (Object)null || string.IsNullOrEmpty(childName)) { return null; } Transform[] componentsInChildren = prefab.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)componentsInChildren[i] != (Object)null && ((Object)componentsInChildren[i]).name == childName) { return componentsInChildren[i]; } } return null; } public static GameObject FindGameObjectDeep(GameObject prefab, string childName) { Transform val = FindTransformDeep(prefab, childName); return ((Object)(object)val != (Object)null) ? ((Component)val).gameObject : null; } public static void WarnIfMissing(Object obj, GameObject prefab, string name) { if (obj == (Object)null && (Object)(object)prefab != (Object)null) { Debug.LogWarning((object)("[BCS] Missing " + name + " on " + ((Object)prefab).name)); } } } [DisallowMultipleComponent] public class BuilderWorkstation : MonoBehaviour { public string[] m_supportedBuildStations = new string[6] { "$piece_workbench", "$piece_forge", "$piece_stonecutter", "$piece_artisanstation", "$tag_heavyworkbench_bal", "$tag_ironworks_bal" }; public bool Supports(string stationName) { if (string.IsNullOrEmpty(stationName)) { return false; } for (int i = 0; i < m_supportedBuildStations.Length; i++) { if (m_supportedBuildStations[i] == stationName) { return true; } } return false; } } [HarmonyPatch(typeof(CraftingStation), "HaveBuildStationInRange")] public static class BuilderWorkstation_HaveBuildStationInRange_Patch { private static void Postfix(string name, Vector3 point, ref CraftingStation __result) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__result != (Object)null)) { __result = BuilderWorkstationUtility.HaveBuildStationInRange(name, point); } } } [HarmonyPatch(typeof(CraftingStation), "FindClosestStationInRange")] public static class BuilderWorkstation_FindClosestStationInRange_Patch { private static void Postfix(string name, Vector3 point, float range, ref CraftingStation __result) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)__result != (Object)null)) { __result = BuilderWorkstationUtility.FindClosestStationInRange(name, point, range); } } } [HarmonyPatch(typeof(CraftingStation), "FindStationsInRange")] public static class BuilderWorkstation_FindStationsInRange_Patch { private static void Postfix(string name, Vector3 point, float range, List stations) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) BuilderWorkstationUtility.FindStationsInRange(name, point, range, stations); } } public static class BuilderWorkstationUtility { public static CraftingStation HaveBuildStationInRange(string requiredStationName, Vector3 point) { //IL_003e: 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_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) CraftingStation val = null; float num = 999999f; foreach (CraftingStation allStation in CraftingStation.m_allStations) { if (IsValidSupportedStation(allStation, requiredStationName)) { float stationBuildRange = allStation.GetStationBuildRange(); Vector3 val2 = point; val2.y = ((Component)allStation).transform.position.y; float num2 = Vector3.Distance(((Component)allStation).transform.position, val2); if (!(num2 >= stationBuildRange) && ((Object)(object)val == (Object)null || num2 < num)) { val = allStation; num = num2; } } } return val; } public static CraftingStation FindClosestStationInRange(string requiredStationName, Vector3 point, float range) { //IL_0039: 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) CraftingStation val = null; float num = 999999f; foreach (CraftingStation allStation in CraftingStation.m_allStations) { if (IsValidSupportedStation(allStation, requiredStationName)) { float num2 = Vector3.Distance(((Component)allStation).transform.position, point); if (!(num2 >= range) && ((Object)(object)val == (Object)null || num2 < num)) { val = allStation; num = num2; } } } return val; } public static void FindStationsInRange(string requiredStationName, Vector3 point, float range, List stations) { //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) if (stations == null) { return; } foreach (CraftingStation allStation in CraftingStation.m_allStations) { if (IsValidSupportedStation(allStation, requiredStationName) && !(Vector3.Distance(((Component)allStation).transform.position, point) >= range) && !stations.Contains(allStation)) { stations.Add(allStation); } } } private static bool IsValidSupportedStation(CraftingStation station, string requiredStationName) { if ((Object)(object)station == (Object)null || string.IsNullOrEmpty(requiredStationName)) { return false; } BuilderWorkstation component = ((Component)station).GetComponent(); if ((Object)(object)component == (Object)null) { return false; } return component.Supports(requiredStationName); } } internal class BuildPieceList { public static string[] buildPieces = new string[40] { "pressenceSignalEmitter_bal", "railtrackSignalEmitter_bal", "railSignalLiftGate_bal", "railSignalDoor_bal", "railtrackStop_bal", "railtrackLampReciver_bal", "railtrackControl_bal", "railtrackSignalStopReceiver_bal", "railtrackContainer_bal", "railtrackUnload_bal", "railtrackSpeed_bal", "railtrack_bal", "railtrack1m_bal", "railtrack4m_bal", "railtrack8m_bal", "railtrackRamp_bal", "railtrackRamp26short_bal", "railtrackRamp45_bal", "railtrackRamp45short_bal", "railtrackRamp64_bal", "railtrackCross_bal", "railtrackSwitchLeft_bal", "railtrackSwitchMid_bal", "railtrackSwitchRight_bal", "railtrackTurnRight15_bal", "railtrackTurnRight30_bal", "railtrackTurnRight45_bal", "railtrackTurnLeft15_bal", "railtrackTurnLeft30_bal", "railtrackTurnLeft45_bal", "railtrackJump4m_bal", "railtrackJump6m_bal", "railtrackJump8m_bal", "railtrackDrop8m_bal", "railtrackDrawbridge10m_bal", "RailPowerWagon_bal", "RailCargoWagon_bal", "RailTableWagon_bal", "RailPersonelWagon_bal", "piece_buildstation_bal" }; } public static class BCSContainerInitUtility { public static bool EnsureInitialized(Container container, ZNetView rootOverride) { //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Expected O, but got Unknown if ((Object)(object)container == (Object)null) { return false; } if ((Object)(object)rootOverride != (Object)null) { container.m_rootObjectOverride = rootOverride; } ZNetView val = (((Object)(object)container.m_rootObjectOverride != (Object)null) ? ((Component)container.m_rootObjectOverride).GetComponent() : ((Component)container).GetComponent()); if ((Object)(object)val == (Object)null || !val.IsValid() || val.GetZDO() == null) { return false; } container.m_nview = val; if ((Object)(object)container.m_piece == (Object)null) { container.m_piece = (((Object)(object)container.m_rootObjectOverride != (Object)null) ? ((Component)container.m_rootObjectOverride).GetComponent() : ((Component)container).GetComponent()); } if (container.m_inventory == null) { container.m_inventory = new Inventory(container.m_name, container.m_bkg, container.m_width, container.m_height); Inventory inventory = container.m_inventory; inventory.m_onChanged = (Action)Delegate.Combine(inventory.m_onChanged, new Action(container.OnContainerChanged)); } container.Load(); container.UpdateUseVisual(); return container.m_inventory != null; } public static bool EnsureInitialized(Container container) { return EnsureInitialized(container, null); } } public class BCSCargoCartAppearanceSelector : MonoBehaviour, Hoverable, Interactable { private const string RpcSetVariant = "RPC_SetCargoAppearanceVariant"; private const string ZdoVariant = "BCS_CargoAppearanceVariant"; public string m_name = "Cargo Wagon Appearance"; [Header("States")] public string m_statesRootName = "container_states"; [Header("Debug")] public bool m_debugLogs = false; private ZNetView _nview; private Transform _statesRoot; private readonly List _states = new List(); private int _lastAppliedVariant = -999; private void Awake() { _nview = ((Component)this).GetComponent(); if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { ((Behaviour)this).enabled = false; return; } _nview.Register("RPC_SetCargoAppearanceVariant", (Action)RPC_SetVariant); CacheStates(); ApplyCurrentVariant(); } private void Start() { CacheStates(); ApplyCurrentVariant(); } private void Update() { int variantIndex = GetVariantIndex(); if (variantIndex != _lastAppliedVariant) { ApplyVariant(variantIndex); } } private void CacheStates() { _states.Clear(); _statesRoot = null; Transform val = ((Component)this).transform.Find(m_statesRootName); if ((Object)(object)val == (Object)null) { val = FindTransformDeep(((Component)this).transform, m_statesRootName); } if ((Object)(object)val == (Object)null) { val = ((Component)this).transform.Find("states"); } if ((Object)(object)val == (Object)null) { val = ((Component)this).transform.Find("States"); } _statesRoot = val; if ((Object)(object)_statesRoot == (Object)null) { Log("CacheStates: states root missing"); return; } for (int i = 0; i < _statesRoot.childCount; i++) { Transform child = _statesRoot.GetChild(i); if ((Object)(object)child != (Object)null) { _states.Add(((Component)child).gameObject); } } Log("CacheStates count=" + _states.Count); } public string GetHoverName() { return m_name; } public string GetHoverText() { StringBuilder stringBuilder = new StringBuilder(128); stringBuilder.Append(m_name); stringBuilder.Append("\n[$KEY_Use] Variant: "); stringBuilder.Append(GetVariantName(GetVariantIndex())); return (Localization.instance != null) ? Localization.instance.Localize(stringBuilder.ToString()) : stringBuilder.ToString(); } public bool Interact(Humanoid human, bool hold, bool alt) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) if (hold) { return false; } Player val = (Player)(object)((human is Player) ? human : null); if ((Object)(object)val == (Object)null) { return false; } if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return true; } SetVariant(GetNextVariantIndex()); ((Character)val).Message((MessageType)2, "Cargo variant: " + GetVariantName(GetNextPreviewVariantIndex()), 0, (Sprite)null); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } private void SetVariant(int index) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetCargoAppearanceVariant", new object[1] { ClampVariantIndex(index) }); } } private void RPC_SetVariant(long sender, int value) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { int num = ClampVariantIndex(value); _nview.GetZDO().Set("BCS_CargoAppearanceVariant", num); ApplyVariant(num); } } private void ApplyCurrentVariant() { ApplyVariant(GetVariantIndex()); } private void ApplyVariant(int index) { if (_states.Count == 0) { CacheStates(); } int num = (_lastAppliedVariant = ClampVariantIndex(index)); for (int i = 0; i < _states.Count; i++) { GameObject val = _states[i]; if ((Object)(object)val != (Object)null) { val.SetActive(i == num); } } } public int GetVariantIndex() { if ((Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.GetZDO() != null) { return ClampVariantIndex(_nview.GetZDO().GetInt("BCS_CargoAppearanceVariant", 0)); } return 0; } private int GetNextVariantIndex() { return GetNextVariantIndex(GetVariantIndex()); } private int GetNextPreviewVariantIndex() { return GetNextVariantIndex(GetVariantIndex()); } private int GetNextVariantIndex(int current) { if (_states.Count == 0) { CacheStates(); } if (_states.Count <= 0) { return 0; } return (ClampVariantIndex(current) + 1) % _states.Count; } private int ClampVariantIndex(int value) { if (_states.Count == 0) { CacheStates(); } if (_states.Count <= 0) { return 0; } return Mathf.Clamp(value, 0, _states.Count - 1); } private string GetVariantName(int index) { if (_states.Count == 0) { CacheStates(); } int num = ClampVariantIndex(index); if (num < 0 || num >= _states.Count || (Object)(object)_states[num] == (Object)null) { return ""; } return ((Object)_states[num]).name; } private static Transform FindTransformDeep(Transform root, string childName) { if ((Object)(object)root == (Object)null || string.IsNullOrEmpty(childName)) { return null; } Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)componentsInChildren[i] != (Object)null && ((Object)componentsInChildren[i]).name == childName) { return componentsInChildren[i]; } } return null; } private void Log(string msg) { if (m_debugLogs) { Debug.Log((object)("[BCSCargoCartAppearanceSelector][" + ((Object)((Component)this).gameObject).name + "] " + msg)); } } } public class BCSCartCraftingStation : MonoBehaviour { [Header("Cart Crafting Station")] public bool m_useCartZNetView = true; public bool m_disableRoofRequirement = true; public bool m_disableFireRequirement = true; } public static class BCSCartPrefabConfigurator { public static void Configure(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { Debug.LogWarning((object)"[BCS] ConfigureTrainCart: prefab == null"); return; } BCSCartRoot orAdd = BCSPrefabFind.GetOrAdd(prefab); BCSPrefabFind.GetOrAdd(prefab); Smelter val = prefab.GetComponent(); if ((Object)(object)val == (Object)null) { val = prefab.GetComponentInChildren(true); } StationExtension val2 = prefab.GetComponent(); if ((Object)(object)val2 == (Object)null) { val2 = prefab.GetComponentInChildren(true); } Fermenter val3 = prefab.GetComponent(); if ((Object)(object)val3 == (Object)null) { val3 = prefab.GetComponentInChildren(true); } ZNetView component = prefab.GetComponent(); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("[BCS] ConfigureTrainCart: Smelter missing on " + ((Object)prefab).name)); CleanupVanillaReferenceComponents(prefab); return; } ConfigureCartBase(orAdd, val, val2); ConfigureCartWheels(orAdd, val); ConfigureCartSensorCollider(prefab); if ((Object)(object)val3 != (Object)null) { orAdd.m_haltingStartEffects = val3.m_tapEffects; } switch (((Object)prefab).name) { case "RailPowerWagon_bal": ConfigurePoweredCart(prefab, orAdd, val, val3); break; case "RailCargoWagon_bal": ConfigureCargoCart(prefab, orAdd, val, component); break; case "RailTableWagon_bal": ConfigureUtilityWorkbenchCart(prefab, orAdd, val, component); break; case "RailPersonelWagon_bal": ConfigurePassengerCart(prefab, orAdd); break; default: Debug.LogWarning((object)("[BCS] ConfigureTrainCart: unknown cart prefab: " + ((Object)prefab).name)); break; } CleanupVanillaReferenceComponents(prefab); } private static void ConfigureCartBase(BCSCartRoot cart, Smelter smelter, StationExtension stationExtension) { cart.m_backCouplerPoint = (((Object)(object)smelter.m_addOreSwitch != (Object)null) ? ((Component)smelter.m_addOreSwitch).transform : null); cart.m_backCouplerSwitch = smelter.m_addOreSwitch; cart.m_frontCouplerPoint = (((Object)(object)smelter.m_addWoodSwitch != (Object)null) ? ((Component)smelter.m_addWoodSwitch).transform : null); cart.m_frontCouplerSwitch = smelter.m_addWoodSwitch; cart.m_frontPosePoint = smelter.m_outputPoint; cart.m_backPosePoint = smelter.m_roofCheckPoint; cart.m_isMovingObject = smelter.m_haveFuelObject; cart.m_isHaltingObject = smelter.m_noOreObject; cart.m_moveStartEffects = smelter.m_oreAddedEffects; cart.m_moveStopEffects = smelter.m_fuelAddedEffects; cart.m_jumpLaunchRiderEffects = smelter.m_produceEffects; cart.m_jumpLandRiderEffects = smelter.m_produceEffects; cart.m_connectionPrefab = (((Object)(object)stationExtension != (Object)null) ? stationExtension.m_connectionPrefab : null); cart.m_allowRuntimeAdditions = true; } private static void ConfigureCartWheels(BCSCartRoot cart, Smelter smelter) { if ((Object)(object)cart == (Object)null || (Object)(object)smelter == (Object)null || smelter.m_animators == null || smelter.m_animators.Length < 2) { Debug.LogWarning((object)"[BCS] ConfigureCartWheels: missing wheel animators"); return; } GameObject val = (((Object)(object)smelter.m_animators[0] != (Object)null) ? ((Component)smelter.m_animators[0]).gameObject : null); GameObject val2 = (((Object)(object)smelter.m_animators[1] != (Object)null) ? ((Component)smelter.m_animators[1]).gameObject : null); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { Debug.LogWarning((object)"[BCS] ConfigureCartWheels: wheel object missing"); return; } BCSPrefabFind.DestroyIfExists((Object)(object)val.GetComponent()); BCSPrefabFind.DestroyIfExists((Object)(object)val2.GetComponent()); cart.m_wheelAnimators = (Transform[])(object)new Transform[2] { val.transform, val2.transform }; } private static void ConfigurePoweredCart(GameObject prefab, BCSCartRoot cart, Smelter smelter, Fermenter fermenter) { cart.m_cartType = BCSCartType.Powered; cart.m_engineSwitch = smelter.m_emptyOreSwitch; cart.m_seatObject = smelter.m_haveOreObject; cart.m_chair = (((Object)(object)smelter.m_haveOreObject != (Object)null) ? smelter.m_haveOreObject.GetComponent() : null); cart.m_containerObject = smelter.m_disabledObject; cart.m_container = (((Object)(object)smelter.m_disabledObject != (Object)null) ? smelter.m_disabledObject.GetComponent() : null); cart.m_powerEnabledObject = smelter.m_enabledObject; cart.m_powerDisabledObject = smelter.m_disabledObject; BCSTrainRuntime orAdd = BCSPrefabFind.GetOrAdd(prefab); ConfigurePoweredRuntime(orAdd, cart); BCSCartRunDamage orAdd2 = BCSPrefabFind.GetOrAdd(prefab); ConfigureRunDamage(prefab, cart, orAdd, orAdd2); BCSPowerCartControls orAdd3 = BCSPrefabFind.GetOrAdd(prefab); ConfigurePowerCartControls(orAdd3, cart, orAdd, fermenter); ConfigureMovingChair(cart.m_chair, 2f); } private static void ConfigurePoweredRuntime(BCSTrainRuntime runtime, BCSCartRoot cart) { runtime.m_engineRoot = cart; runtime.m_baseSpeed = 8f; runtime.m_currentSpeed = 8f; runtime.m_minSpeed = 4f; runtime.m_maxSpeed = 16f; runtime.m_speedChangeRate = 2f; runtime.m_useStraightRunAcceleration = true; runtime.m_straightRunRequiredMeters = 4f; runtime.m_straightRunBonusPerMeter = 0.35f; runtime.m_maxStraightRunBonus = 4f; runtime.m_straightRunResetRate = 8f; runtime.m_straightDirectionDotThreshold = 0.985f; runtime.m_useSlopeSpeed = true; runtime.m_slopeSampleDistance = 0.25f; runtime.m_uphillSlowdownFactor = 1.2f; runtime.m_downhillBoostFactor = 1f; runtime.m_maxUphillNormalized = 0.3f; runtime.m_maxDownhillNormalized = 0.3f; runtime.m_minSpeedMultiplierUphill = 0.8f; runtime.m_maxSpeedMultiplierDownhill = 1.5f; runtime.m_useSlopeMomentum = true; runtime.m_slopeMomentumBuildRate = 1.35f; runtime.m_slopeMomentumDecayRate = 0.55f; runtime.m_maxSlopeMomentum = 1.5f; runtime.m_slopeMomentumSpeedInfluence = 1f; runtime.m_slopeMomentumDeadzone = 0.01f; runtime.m_useSoftStopBraking = true; runtime.m_softStopBrakeStartDistance = 1.25f; runtime.m_softStopMinApproachSpeed = 0.2f; runtime.m_softStopBrakeExponent = 1.5f; } private static void ConfigureRunDamage(GameObject prefab, BCSCartRoot cart, BCSTrainRuntime runtime, BCSCartRunDamage runDamage) { runDamage.m_cart = cart; runDamage.m_runtime = runtime; Transform val = prefab.transform.Find("RunHitDamage"); runDamage.m_runDamageObject = (((Object)(object)val != (Object)null) ? ((Component)val).gameObject : null); runDamage.m_runDamageObjectName = "RunHitDamage"; runDamage.m_attachToLeadingCoupler = true; runDamage.m_speedThreshold = 6f; runDamage.m_fullDamageSpeed = 16f; runDamage.m_minDamageMultiplierAtThreshold = 0.75f; runDamage.m_maxDamageMultiplierAtFullSpeed = 2f; runDamage.m_extraDamageMultiplierPerAttachedCart = 0.25f; runDamage.m_maxAttachedCartDamageBonus = 1f; runDamage.m_minForceMultiplierAtThreshold = 1f; runDamage.m_maxForceMultiplierAtFullSpeed = 3f; runDamage.m_extraForceMultiplierPerAttachedCart = 0.35f; runDamage.m_maxAttachedCartForceBonus = 1.5f; if ((Object)(object)runDamage.m_runDamageObject == (Object)null) { Debug.LogWarning((object)("[BCS] ConfigurePoweredCart: RunHitDamage object missing on " + ((Object)prefab).name)); } } private static void ConfigurePowerCartControls(BCSPowerCartControls controls, BCSCartRoot cart, BCSTrainRuntime runtime, Fermenter fermenter) { //IL_0015: 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) controls.m_cart = cart; controls.m_runtime = runtime; controls.m_modifierSwitch = (KeyCode)304; controls.m_modifierCamera = (KeyCode)308; controls.m_switchSearchRadius = 5f; if ((Object)(object)fermenter != (Object)null) { controls.m_switchToggleEffects = fermenter.m_spawnEffects; } } private static void ConfigureCargoCart(GameObject prefab, BCSCartRoot cart, Smelter smelter, ZNetView rootNview) { cart.m_cartType = BCSCartType.Cargo; cart.m_engineSwitch = null; cart.m_powerEnabledObject = null; cart.m_powerDisabledObject = null; cart.m_seatObject = null; cart.m_chair = null; cart.m_containerObject = smelter.m_enabledObject; cart.m_container = (((Object)(object)smelter.m_enabledObject != (Object)null) ? smelter.m_enabledObject.GetComponent() : null); if ((Object)(object)cart.m_container != (Object)null && (Object)(object)rootNview != (Object)null) { cart.m_container.m_rootObjectOverride = rootNview; } BCSCargoCartAppearanceSelector orAdd = BCSPrefabFind.GetOrAdd(prefab); orAdd.m_name = "Cargo Wagon Appearance"; orAdd.m_statesRootName = "container_states"; RemoveNonPoweredRuntime(prefab); } private static void ConfigureUtilityWorkbenchCart(GameObject prefab, BCSCartRoot cart, Smelter smelter, ZNetView rootNview) { cart.m_cartType = BCSCartType.Utility; cart.m_engineSwitch = null; cart.m_powerEnabledObject = null; cart.m_powerDisabledObject = null; cart.m_seatObject = null; cart.m_chair = null; cart.m_containerObject = smelter.m_enabledObject; cart.m_container = (((Object)(object)smelter.m_enabledObject != (Object)null) ? smelter.m_enabledObject.GetComponent() : null); if ((Object)(object)cart.m_container != (Object)null && (Object)(object)rootNview != (Object)null) { cart.m_container.m_rootObjectOverride = rootNview; } CraftingStation componentInChildren = prefab.GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null) { BCSCartCraftingStation bCSCartCraftingStation = ((Component)componentInChildren).GetComponent(); if ((Object)(object)bCSCartCraftingStation == (Object)null) { bCSCartCraftingStation = ((Component)componentInChildren).gameObject.AddComponent(); } bCSCartCraftingStation.m_useCartZNetView = true; bCSCartCraftingStation.m_disableRoofRequirement = true; bCSCartCraftingStation.m_disableFireRequirement = true; componentInChildren.m_craftRequireRoof = false; componentInChildren.m_craftRequireFire = false; } else { Debug.LogWarning((object)("[BCS] ConfigureUtilityWorkbenchCart: CraftingStation missing on " + ((Object)prefab).name)); } RemoveNonPoweredRuntime(prefab); } private static void ConfigurePassengerCart(GameObject prefab, BCSCartRoot cart) { cart.m_cartType = BCSCartType.Passenger; cart.m_engineSwitch = null; cart.m_powerEnabledObject = null; cart.m_powerDisabledObject = null; cart.m_containerObject = null; cart.m_container = null; Chair[] componentsInChildren = prefab.GetComponentsInChildren(true); cart.m_chair = ((componentsInChildren != null && componentsInChildren.Length != 0) ? componentsInChildren[0] : null); cart.m_seatObject = (((Object)(object)cart.m_chair != (Object)null) ? ((Component)cart.m_chair).gameObject : null); if (componentsInChildren != null) { for (int i = 0; i < componentsInChildren.Length; i++) { ConfigureMovingChair(componentsInChildren[i], 2f); } } RemoveNonPoweredRuntime(prefab); if (componentsInChildren == null || componentsInChildren.Length == 0) { Debug.LogWarning((object)("[BCS] ConfigurePassengerCart: no Chair components found on " + ((Object)prefab).name)); } } private static void ConfigureMovingChair(Chair chair, float useDistance) { if (!((Object)(object)chair == (Object)null)) { if ((Object)(object)chair.m_attachPoint == (Object)null) { chair.m_attachPoint = ((Component)chair).transform; } chair.m_inShip = true; chair.m_attachAnimation = "emote_sit"; chair.m_useDistance = useDistance; } } private static void RemoveNonPoweredRuntime(GameObject prefab) { BCSPrefabFind.DestroyIfExists((Object)(object)prefab.GetComponent()); BCSPrefabFind.DestroyIfExists((Object)(object)prefab.GetComponent()); BCSPrefabFind.DestroyIfExists((Object)(object)prefab.GetComponent()); } private static void ConfigureCartSensorCollider(GameObject prefab) { Transform val = prefab.transform.Find("CartSensorCollider"); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("[BCS] ConfigureCartSensorCollider: CartSensorCollider missing on " + ((Object)prefab).name)); return; } GameObject gameObject = ((Component)val).gameObject; int num = LayerMask.NameToLayer("character_noenv"); if (num >= 0) { gameObject.layer = num; } else { Debug.LogWarning((object)("[BCS] ConfigureCartSensorCollider: layer character_noenv missing on " + ((Object)prefab).name)); } Collider component = gameObject.GetComponent(); if ((Object)(object)component == (Object)null) { Debug.LogWarning((object)("[BCS] ConfigureCartSensorCollider: Collider missing on " + ((Object)prefab).name)); return; } component.isTrigger = true; DisableInPlacementGhost component2 = gameObject.GetComponent(); if ((Object)(object)component2 != (Object)null) { Object.DestroyImmediate((Object)(object)component2); } } private static void CleanupVanillaReferenceComponents(GameObject prefab) { if (!((Object)(object)prefab == (Object)null)) { DestroyComponentsInChildren(prefab); DestroyComponentsInChildren(prefab); DestroyComponentsInChildren(prefab); } } private static void DestroyComponentsInChildren(GameObject prefab) where T : Component { if ((Object)(object)prefab == (Object)null) { return; } T[] componentsInChildren = prefab.GetComponentsInChildren(true); if (componentsInChildren == null) { return; } for (int num = componentsInChildren.Length - 1; num >= 0; num--) { T val = componentsInChildren[num]; if (!((Object)(object)val == (Object)null)) { Object.DestroyImmediate((Object)(object)val); } } } } public class BCSDrawbridgeRail : MonoBehaviour { private const string RpcToggleDrawbridge = "RPC_ToggleDrawbridge"; private readonly List _cartScanScratch = new List(64); private ZNetView _nview; private BCSRailPiece _rail; [Header("Drawbridge")] public bool m_enabled = true; public float m_stopMargin = 1f; public float m_animationSeconds = 3f; public float m_raisedAngle = 75f; public float m_extraStopOffset = 1.5f; [Header("Bridge Leaves")] public Transform m_leftPivotC; public Transform m_rightPivotD; [Header("Gears")] public Transform m_gearCStatic; public Transform m_gearCBridge; public Transform m_gearDStatic; public Transform m_gearDBridge; public float m_gearDegreesPerBridgeDegree = 4f; [Header("Rotation Axis")] public Vector3 m_leftLeafAxis = Vector3.right; public Vector3 m_rightLeafAxis = Vector3.right; public Vector3 m_gearAxis = Vector3.right; [Header("Animation Audio")] public GameObject m_animationActiveObject; [Header("Effects")] public EffectList m_openStartEffects = new EffectList(); public EffectList m_closeStartEffects = new EffectList(); [Header("Debug")] public bool m_debugLogs = false; private void Awake() { _nview = ((Component)this).GetComponent(); _rail = ((Component)this).GetComponent(); if ((Object)(object)_nview != (Object)null) { _nview.Register("RPC_ToggleDrawbridge", (Action)RPC_ToggleDrawbridge); } UpdateAnimationActiveObject(GetState()); } private void Update() { UpdateAnimationAndState(); } public bool IsDrawbridgeRail() { return m_enabled && (Object)(object)_rail != (Object)null && _rail.m_pieceType == BCSRailPieceType.Drawbridge; } public bool IsPassableForTrain() { return GetState() == BCSDrawbridgeState.Lowered; } public bool IsBlockedForTrain() { return !IsPassableForTrain(); } public bool IsAnimating() { BCSDrawbridgeState state = GetState(); return state == BCSDrawbridgeState.Raising || state == BCSDrawbridgeState.Lowering; } public BCSDrawbridgeState GetState() { ZDO zdo = GetZdo(); if (zdo == null) { return BCSDrawbridgeState.Lowered; } return zdo.GetInt("hl_rail_drawbridge_state", 0) switch { 1 => BCSDrawbridgeState.Raising, 2 => BCSDrawbridgeState.Raised, 3 => BCSDrawbridgeState.Lowering, _ => BCSDrawbridgeState.Lowered, }; } public string GetHoverText() { string text = "Drawbridge Rail"; BCSDrawbridgeState state = GetState(); text += "\n[$KEY_Use] Toggle bridge"; text = text + "\nState: " + GetStateText(state); if (IsBridgeSpanOccupied()) { text += "\nTrain is on bridge"; } else if (IsAnimating()) { text += "\nBridge is moving"; } return (Localization.instance != null) ? Localization.instance.Localize(text) : text; } public bool TryInteract(Player player) { if ((Object)(object)player == (Object)null || !IsDrawbridgeRail()) { return false; } if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { return false; } if (IsBridgeSpanOccupied()) { ((Character)player).Message((MessageType)2, "Train is on bridge", 0, (Sprite)null); return true; } if (IsAnimating()) { ((Character)player).Message((MessageType)2, "Bridge is moving", 0, (Sprite)null); return true; } _nview.InvokeRPC("RPC_ToggleDrawbridge", Array.Empty()); return true; } public bool TryGetStopDistance(bool travelReversed, out float stopDistance) { stopDistance = 0f; if (!IsDrawbridgeRail()) { return false; } if (IsPassableForTrain()) { return false; } float length = _rail.GetLength(); if (length <= 0.001f) { return false; } float safeStopMargin = GetSafeStopMargin(length); float num = Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_extraStopOffset, 1.5f)); float num2 = Mathf.Clamp(safeStopMargin - num, 0.05f, length - 0.05f); float num3 = Mathf.Clamp(length - safeStopMargin + num, 0.05f, length - 0.05f); stopDistance = (travelReversed ? num3 : num2); return true; } public bool IsDistanceOnBridgeSpan(float distance) { if ((Object)(object)_rail == (Object)null) { return false; } float length = _rail.GetLength(); if (length <= 0.001f) { return false; } float safeStopMargin = GetSafeStopMargin(length); float num = BCSCommonUtility.SanitizeFloat(distance, 0f); return num > safeStopMargin && num < length - safeStopMargin; } public bool IsBridgeSpanOccupied() { if ((Object)(object)_rail == (Object)null) { return false; } string railId = _rail.GetRailId(); if (string.IsNullOrEmpty(railId)) { return false; } BCSCartRegistry.FillAll(_cartScanScratch); for (int i = 0; i < _cartScanScratch.Count; i++) { BCSCartRoot bCSCartRoot = _cartScanScratch[i]; if (!((Object)(object)bCSCartRoot == (Object)null) && !(bCSCartRoot.GetCurrentRailId() != railId) && IsDistanceOnBridgeSpan(bCSCartRoot.GetDistanceOnRail())) { return true; } } return false; } private void RPC_ToggleDrawbridge(long sender) { if (!IsDrawbridgeRail()) { return; } if (IsBridgeSpanOccupied()) { Log("Toggle rejected: train is on bridge"); return; } if (IsAnimating()) { Log("Toggle rejected: bridge is already moving"); return; } ClaimOwnershipIfNeeded(); switch (GetState()) { case BCSDrawbridgeState.Lowered: SetStateOwned(BCSDrawbridgeState.Raising); CreateEffects(m_openStartEffects); Log("Drawbridge raising"); break; case BCSDrawbridgeState.Raised: SetStateOwned(BCSDrawbridgeState.Lowering); CreateEffects(m_closeStartEffects); Log("Drawbridge lowering"); break; } } private void SetStateOwned(BCSDrawbridgeState state) { ZDO zdo = GetZdo(); if (zdo != null) { ClaimOwnershipIfNeeded(); zdo.Set("hl_rail_drawbridge_state", (int)state); zdo.Set("hl_rail_drawbridge_anim_start_time", BCSCommonUtility.GetNetworkTimeSecondsFloat()); } } private void SetStateNoRestartOwned(BCSDrawbridgeState state) { ZDO zdo = GetZdo(); if (zdo != null) { ClaimOwnershipIfNeeded(); zdo.Set("hl_rail_drawbridge_state", (int)state); } } private void UpdateAnimationAndState() { if (!IsDrawbridgeRail()) { return; } BCSDrawbridgeState state = GetState(); float num = Mathf.Max(0.01f, BCSCommonUtility.SanitizeFloat(m_animationSeconds, 3f)); float animStartTime = GetAnimStartTime(); float networkTimeSecondsFloat = BCSCommonUtility.GetNetworkTimeSecondsFloat(); float num2 = Mathf.Clamp01((networkTimeSecondsFloat - animStartTime) / num); float progress = 0f; switch (state) { case BCSDrawbridgeState.Lowered: progress = 0f; break; case BCSDrawbridgeState.Raised: progress = 1f; break; case BCSDrawbridgeState.Raising: progress = num2; if (num2 >= 1f && IsOwner()) { SetStateNoRestartOwned(BCSDrawbridgeState.Raised); } break; case BCSDrawbridgeState.Lowering: progress = 1f - num2; if (num2 >= 1f && IsOwner()) { SetStateNoRestartOwned(BCSDrawbridgeState.Lowered); } break; } UpdateAnimationActiveObject(state); ApplyVisual(progress); } private void ApplyVisual(float progress) { //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_0038: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0048: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: 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_0084: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp01(progress); float num2 = num * BCSCommonUtility.SanitizeFloat(m_raisedAngle, 75f); if ((Object)(object)m_leftPivotC != (Object)null) { Vector3 safeAxis = GetSafeAxis(m_leftLeafAxis, Vector3.right); m_leftPivotC.localRotation = Quaternion.AngleAxis(num2, safeAxis); } if ((Object)(object)m_rightPivotD != (Object)null) { Vector3 safeAxis2 = GetSafeAxis(m_rightLeafAxis, Vector3.right); m_rightPivotD.localRotation = Quaternion.AngleAxis(0f - num2, safeAxis2); } float num3 = num2 * BCSCommonUtility.SanitizeFloat(m_gearDegreesPerBridgeDegree, 4f); ApplyGear(m_gearCStatic, 0f - num3); ApplyGear(m_gearCBridge, num3); ApplyGear(m_gearDStatic, num3); ApplyGear(m_gearDBridge, 0f - num3); } private void UpdateAnimationActiveObject(BCSDrawbridgeState state) { bool flag = state == BCSDrawbridgeState.Raising || state == BCSDrawbridgeState.Lowering; if ((Object)(object)m_animationActiveObject == (Object)null) { return; } if (m_animationActiveObject.activeSelf != flag) { m_animationActiveObject.SetActive(flag); } AudioSource[] componentsInChildren = m_animationActiveObject.GetComponentsInChildren(true); foreach (AudioSource val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } val.loop = true; if (flag) { if (!val.isPlaying) { val.Play(); } continue; } if (val.isPlaying) { val.Stop(); } val.time = 0f; } } private Transform GetGearRotationPivot(Transform gearRoot) { if ((Object)(object)gearRoot == (Object)null) { return null; } if (((Object)gearRoot).name == "gear-pivot") { return gearRoot; } Transform val = gearRoot.Find("gear-pivot"); if ((Object)(object)val != (Object)null) { return val; } Transform[] componentsInChildren = ((Component)gearRoot).GetComponentsInChildren(true); foreach (Transform val2 in componentsInChildren) { if ((Object)(object)val2 != (Object)null && ((Object)val2).name == "gear-pivot") { return val2; } } return gearRoot; } private void CreateEffects(EffectList effects) { //IL_0027: 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) if (effects != null && effects.m_effectPrefabs != null && effects.m_effectPrefabs.Length != 0) { effects.Create(((Component)this).transform.position, ((Component)this).transform.rotation, (Transform)null, 1f, -1); } } private void ApplyGear(Transform gearRoot, float angle) { //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_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_002b: 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) Transform gearRotationPivot = GetGearRotationPivot(gearRoot); if (!((Object)(object)gearRotationPivot == (Object)null)) { Vector3 safeAxis = GetSafeAxis(m_gearAxis, Vector3.right); gearRotationPivot.localRotation = Quaternion.AngleAxis(angle, safeAxis); } } private float GetSafeStopMargin(float length) { float num = Mathf.Max(0.001f, BCSCommonUtility.SanitizeFloat(length, 0f)); return Mathf.Clamp(BCSCommonUtility.SanitizeFloat(m_stopMargin, 1f), 0.05f, Mathf.Max(0.05f, num * 0.45f)); } private Vector3 GetSafeAxis(Vector3 axis, Vector3 fallback) { //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_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_002b: Unknown result type (might be due to invalid IL or missing references) if (((Vector3)(ref axis)).sqrMagnitude <= 0.0001f) { return ((Vector3)(ref fallback)).normalized; } return ((Vector3)(ref axis)).normalized; } private float GetAnimStartTime() { ZDO zdo = GetZdo(); if (zdo == null) { return BCSCommonUtility.GetNetworkTimeSecondsFloat(); } return zdo.GetFloat("hl_rail_drawbridge_anim_start_time", BCSCommonUtility.GetNetworkTimeSecondsFloat()); } private string GetStateText(BCSDrawbridgeState state) { return state switch { BCSDrawbridgeState.Lowered => "Lowered / passable", BCSDrawbridgeState.Raising => "Raising / blocked", BCSDrawbridgeState.Raised => "Raised / blocked", _ => "Lowering / blocked", }; } private ZDO GetZdo() { if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { return null; } return _nview.GetZDO(); } private bool IsOwner() { return (Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.IsOwner(); } private void ClaimOwnershipIfNeeded() { if ((Object)(object)_nview != (Object)null && _nview.IsValid() && !_nview.IsOwner()) { _nview.ClaimOwnership(); } } public bool TryGetStopDistanceFromCurrentDistance(float currentDistance, out float stopDistance) { stopDistance = 0f; if (!IsDrawbridgeRail()) { return false; } if (IsPassableForTrain()) { return false; } float length = _rail.GetLength(); if (length <= 0.001f) { return false; } float safeStopMargin = GetSafeStopMargin(length); float num = Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_extraStopOffset, 1.5f)); float num2 = Mathf.Clamp(safeStopMargin - num, 0.05f, length - 0.05f); float num3 = Mathf.Clamp(length - safeStopMargin + num, 0.05f, length - 0.05f); float num4 = Mathf.Clamp(BCSCommonUtility.SanitizeFloat(currentDistance, 0f), 0f, length); bool flag = num4 > length * 0.5f; stopDistance = (flag ? num3 : num2); return true; } private void Log(string msg) { if (m_debugLogs) { Debug.Log((object)("[BCSDrawbridgeRail][" + ((Object)((Component)this).gameObject).name + "] " + msg)); } } } public static class BCSPrefabConfigurator { public static void ConfigureTrainCart(GameObject prefab) { BCSCartPrefabConfigurator.Configure(prefab); } public static void ConfigureRail(GameObject prefab) { BCSRailPrefabConfigurator.Configure(prefab); } public static void ConfigureSignalPiece(GameObject prefab) { BCSSignalPrefabConfigurator.Configure(prefab); } } public class DatabaseAddMethods { public void AddItems(List items) { foreach (GameObject item in items) { AddItem(item); } } public void AddRecipes(List recipes) { foreach (Recipe recipe in recipes) { AddRecipe(recipe); } } public void AddStatuseffects(List statusEffects) { foreach (StatusEffect statusEffect in statusEffects) { AddStatus(statusEffect); } } private bool IsObjectDBValid() { return (Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.m_items.Count != 0 && ObjectDB.instance.m_recipes.Count != 0 && (Object)(object)ObjectDB.instance.GetItemPrefab("Amber") != (Object)null; } private void AddStatus(StatusEffect status) { if (!IsObjectDBValid()) { return; } if ((Object)(object)status != (Object)null) { if ((Object)(object)ObjectDB.instance.GetStatusEffect(status.m_nameHash) == (Object)null) { ObjectDB.instance.m_StatusEffects.Add(status); } else { Debug.Log((object)(Launch.projectName + ": " + ((Object)status).name + " - Status already in the game")); } } else { Debug.LogError((object)(Launch.projectName + ": " + ((Object)status).name + " - Status not found")); } } private void AddRecipe(Recipe recipe) { if (!IsObjectDBValid()) { return; } if ((Object)(object)recipe != (Object)null) { if ((Object)(object)ObjectDB.instance.m_recipes.Find((Recipe x) => ((Object)x).name == ((Object)recipe).name) == (Object)null) { if ((Object)(object)recipe.m_item != (Object)null) { ObjectDB.instance.m_recipes.Add(recipe); } } else { Debug.Log((object)(Launch.projectName + ": " + ((Object)recipe).name + " - Recipe with this name already in the Game")); } } else { Debug.LogError((object)(Launch.projectName + ": " + ((Object)recipe).name + " - Recipe not found")); } } private void AddItem(GameObject newPrefab) { if (!IsObjectDBValid()) { return; } ItemDrop component = newPrefab.GetComponent(); if ((Object)(object)component != (Object)null) { if ((Object)(object)ObjectDB.instance.GetItemPrefab(((Object)newPrefab).name) == (Object)null) { ObjectDB.instance.m_items.Add(newPrefab); Dictionary dictionary = (Dictionary)typeof(ObjectDB).GetField("m_itemByHash", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(ObjectDB.instance); dictionary[((Object)newPrefab).name.GetHashCode()] = newPrefab; } else { Debug.LogWarning((object)(Launch.projectName + ": " + ((Object)newPrefab).name + " - ItemDrop already exist")); } } else { Debug.LogError((object)(Launch.projectName + ": " + ((Object)newPrefab).name + " - ItemDrop not found on prefab")); } } } public class ModResourceLoader { public AssetBundle assetBundle; public List buildPrefabs = new List(); public List plantPrefabs = new List(); public List itemPrefabs = new List(); public List monsterPrefabs = new List(); public List vegetationPrefabs = new List(); public List clutterPrefabs = new List(); public List locationPrefabs = new List(); public List roomPrefabs = new List(); public List vfxPrefabs = new List(); public List texturePrefabs = new List(); public List recipes = new List(); public List statusEffects = new List(); public StatusEffect newBarleyStatus = null; public ShaderReplacment shaderReplacment = new ShaderReplacment(); public Sprite newLogo = null; public GameObject railwaytable = null; public GameObject unchargedStone = null; public void loadAssets() { assetBundle = GetAssetBundleFromResources("balrondcargosystem"); string basePath = "Assets/Custom/BalrondCargoSystems/"; loadPieces(basePath); loadItems(basePath); loadOther(basePath); } public void AddPrefabsToZnetScene(ZNetScene zNetScene) { zNetScene.m_prefabs.AddRange(vegetationPrefabs); foreach (GameObject gm in itemPrefabs) { GameObject val = zNetScene.m_prefabs.Find((GameObject x) => ((Object)x).name == ((Object)gm).name); if ((Object)(object)val == (Object)null) { zNetScene.m_prefabs.Add(gm); } else { Debug.LogWarning((object)("Object exists: " + ((Object)gm).name)); } } foreach (GameObject gm2 in buildPrefabs) { GameObject val2 = zNetScene.m_prefabs.Find((GameObject x) => ((Object)x).name == ((Object)gm2).name); if ((Object)(object)val2 == (Object)null) { zNetScene.m_prefabs.Add(gm2); } else { Debug.LogWarning((object)("Object exists: " + ((Object)gm2).name)); } } foreach (GameObject gm3 in vfxPrefabs) { GameObject val3 = zNetScene.m_prefabs.Find((GameObject x) => ((Object)x).name == ((Object)gm3).name); if ((Object)(object)val3 == (Object)null) { zNetScene.m_prefabs.Add(gm3); } else { Debug.LogWarning((object)("Object exists: " + ((Object)gm3).name)); } } zNetScene.m_prefabs.RemoveAll((GameObject x) => (Object)(object)x == (Object)null); setupRails(zNetScene); setupTraincarts(zNetScene); setupSignalPieces(zNetScene); addPlantstoCultivator(zNetScene); setupBuildPiecesList(zNetScene); } private void setupTraincarts(ZNetScene zNetScene) { string[] array = new string[4] { "RailCargoWagon_bal", "RailPowerWagon_bal", "RailTableWagon_bal", "RailPersonelWagon_bal" }; string[] array2 = array; foreach (string name in array2) { GameObject val = buildPrefabs.Find((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == name); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("[BCS] setupTraincarts: prefab not found: " + name)); } else { setupTraincart(zNetScene, val); } } } private void setupTraincart(ZNetScene zNetScene, GameObject prefab) { BCSPrefabConfigurator.ConfigureTrainCart(prefab); } private void setupSignalPieces(ZNetScene zNetScene) { string[] array = new string[6] { "pressenceSignalEmitter_bal", "railtrackSignalEmitter_bal", "railtrackLampReciver_bal", "railtrackSpeakerReciver_bal", "railSignalDoor_bal", "railSignalLiftGate_bal" }; string[] array2 = array; foreach (string name in array2) { GameObject val = buildPrefabs.Find((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == name); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("[BCS] setupSignalPieces: prefab not found: " + name)); } else { setupSignalPiece(zNetScene, val); } } } private void setupSignalPiece(ZNetScene zNetScene, GameObject prefab) { BCSPrefabConfigurator.ConfigureSignalPiece(prefab); } private void setupRails(ZNetScene zNetScene) { string[] array = new string[29] { "railtrackControl_bal", "railtrackSignalStopReceiver_bal", "railtrackContainer_bal", "railtrackUnload_bal", "railtrackSpeed_bal", "railtrack_bal", "railtrack1m_bal", "railtrack4m_bal", "railtrack8m_bal", "railtrackRamp_bal", "railtrackRamp26short_bal", "railtrackRamp45_bal", "railtrackRamp45short_bal", "railtrackRamp64_bal", "railtrackCross_bal", "railtrackSwitchLeft_bal", "railtrackSwitchMid_bal", "railtrackSwitchRight_bal", "railtrackTurnRight15_bal", "railtrackTurnRight30_bal", "railtrackTurnRight45_bal", "railtrackTurnLeft15_bal", "railtrackTurnLeft30_bal", "railtrackTurnLeft45_bal", "railtrackJump4m_bal", "railtrackJump6m_bal", "railtrackJump8m_bal", "railtrackDrop8m_bal", "railtrackDrawbridge10m_bal" }; string[] array2 = array; foreach (string name in array2) { GameObject val = buildPrefabs.Find((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == name); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("[BCS] setupRails: prefab not found: " + name)); } else { setupRail(zNetScene, val); } } } private void setupRail(ZNetScene zNetScene, GameObject prefab) { BCSPrefabConfigurator.ConfigureRail(prefab); } private void setupBuildPiecesList(ZNetScene zNetScene) { string[] array = new string[4] { "Hammer", "HammerIron", "HammerDverger", "HammerBlackmetal" }; GameObject val = zNetScene.m_prefabs.Find((GameObject x) => ((Object)x).name == "Hammer"); PieceTable buildPieces = val.GetComponent().m_itemData.m_shared.m_buildPieces; string[] array2 = array; foreach (string name in array2) { addBuildpiecesToOtherHammer(name, buildPieces, zNetScene); } List pieces = buildPieces.m_pieces; foreach (GameObject buildPrefab in buildPrefabs) { setupRavenGuide(buildPrefab, zNetScene.m_prefabs); AddToBuildList(buildPrefab, pieces); } } private void addBuildpiecesToOtherHammer(string name, PieceTable pieceTable, ZNetScene zNetScene) { GameObject val = zNetScene.m_prefabs.Find((GameObject x) => ((Object)x).name == name); if (!((Object)(object)val == (Object)null)) { val.GetComponent().m_itemData.m_shared.m_buildPieces = pieceTable; } } public void setupRavenGuide(GameObject gameObject, List gameObjects) { GameObject val = null; Transform val2 = gameObject.transform.Find("GuidePoint"); if ((Object)(object)val2 == (Object)null) { return; } GameObject val3 = gameObjects.Find((GameObject x) => ((Object)x).name == "piece_workbench"); if ((Object)(object)val3 != (Object)null) { GameObject gameObject2 = ((Component)val3.transform.Find("GuidePoint")).gameObject; if ((Object)(object)gameObject2 != (Object)null) { GuidePoint component = gameObject2.GetComponent(); if ((Object)(object)component != (Object)null) { val = component.m_ravenPrefab; } } } if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)"Ravens not found"); } else { ((Component)val2).GetComponent().m_ravenPrefab = val; } } public void setupBuildPiecesListDB() { GameObject val = ObjectDB.instance.m_items.Find((GameObject x) => ((Object)x).name == "Hammer"); List pieces = val.GetComponent().m_itemData.m_shared.m_buildPieces.m_pieces; foreach (GameObject buildPrefab in buildPrefabs) { AddToBuildList(buildPrefab, pieces); } } private void AddToBuildList(GameObject prefab, List buildPieces) { if ((Object)(object)buildPieces.Find((GameObject x) => ((Object)x).name == ((Object)prefab).name) == (Object)null) { buildPieces.Add(prefab); } } private void addPlantstoCultivator(ZNetScene zNetScene) { GameObject val = zNetScene.m_prefabs.Find((GameObject x) => ((Object)x).name == "Cultivator"); PieceTable buildPieces = val.GetComponent().m_itemData.m_shared.m_buildPieces; List pieces = buildPieces.m_pieces; foreach (GameObject plantPrefab in plantPrefabs) { pieces.Add(plantPrefab); } } private void loadItems(string basePath) { string mainPath = basePath + "Items/"; string[] nameList = new string[9] { "WagonBundlePower_bal", "WagonBundleCargo_bal", "WagonBundleTable_bal", "WagonBundlePersonel_bal", "WagonPartsBundle_bal", "RailPartsBundle_bal", "RailwayHammer_bal", "BuilderWorkstationBundle_bal", "UncharedThunderstone_bal" }; addNewPrefabToCollection(nameList, mainPath, itemPrefabs, "item"); } private void addNewPrefabToCollection(string[] nameList, string mainPath, List prefabList, string typeName) { foreach (string text in nameList) { GameObject val = assetBundle.LoadAsset(mainPath + text + ".prefab"); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("Could not find " + typeName + " with name: " + text)); continue; } if (((Object)val).name == "UncharedThunderstone_bal") { unchargedStone = val; } if (Object.op_Implicit((Object)(object)val.GetComponent()) || typeName == "clutter") { ShaderReplacment.Replace(val); prefabList.Add(val); } else { Debug.LogWarning((object)("Prefab with name has no ZNetView could not been removed: " + text)); } } } private AssetBundle GetAssetBundleFromResources(string filename) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string name = executingAssembly.GetManifestResourceNames().Single((string str) => str.EndsWith(filename)); using Stream stream = executingAssembly.GetManifestResourceStream(name); return AssetBundle.LoadFromStream(stream); } private void loadPlants(string basePath) { string text = basePath + "Plants/"; string[] array = new string[0]; string[] array2 = array; foreach (string text2 in array2) { GameObject val = assetBundle.LoadAsset(text + text2 + ".prefab"); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("Could not find plant with name: " + text2)); continue; } ShaderReplacment.Replace(val); plantPrefabs.Add(val); } } private void loadPieces(string basePath) { string text = basePath + "Pieces/"; string[] buildPieces = BuildPieceList.buildPieces; string[] array = buildPieces; foreach (string text2 in array) { GameObject val = assetBundle.LoadAsset(text + text2 + ".prefab"); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("Could not find piece with name: " + text2)); continue; } ShaderReplacment.Replace(val); if (((Object)val).name == "RailTableWagon_bal") { railwaytable = val; } buildPrefabs.Add(val); } } private void loadVegetation(string basePath) { string text = basePath + "Vegetation/"; string[] array = new string[0]; string[] array2 = array; foreach (string text2 in array2) { GameObject val = assetBundle.LoadAsset(text + text2 + ".prefab"); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("Could not find vegegation with name: " + text2)); continue; } ShaderReplacment.Replace(val); vegetationPrefabs.Add(val); } } private void loadOther(string basePath) { string text = basePath + "Other/"; string[] array = new string[3] { "sfx_stop_cart_bal", "vfx_cartconnector_bal", "_railhammerPieceTable_bal" }; string[] array2 = array; foreach (string text2 in array2) { GameObject val = assetBundle.LoadAsset(text + text2 + ".prefab"); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("Could not find object with name: " + text2)); continue; } ShaderReplacment.Replace(val); vfxPrefabs.Add(val); } } private void prepareOtherEffects(string mainPath) { string[] array = new string[0]; string[] array2 = array; foreach (string text in array2) { StatusEffect val = (StatusEffect)(object)assetBundle.LoadAsset(mainPath + "Status/" + text + ".asset"); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("Status not found: " + text)); } else { statusEffects.Add(val); } } } } public class ShaderReplacment { public static List prefabsToReplaceShader = new List(); public static List materialsInPrefabs = new List(); public string[] shaderlist = new string[49] { "Custom/AlphaParticle", "Custom/Blob", "Custom/Bonemass", "Custom/Clouds", "Custom/Creature", "Custom/Decal", "Custom/Distortion", "Custom/Flow", "Custom/FlowOpaque", "Custom/Grass", "Custom/GuiScroll", "Custom/Heightmap", "Custom/icon", "Custom/InteriorSide", "Custom/LitGui", "Custom/LitParticles", "Custom/mapshader", "Custom/ParticleDecal", "Custom/Piece", "Custom/Player", "Custom/Rug", "Custom/ShadowBlob", "Custom/SkyboxProcedural", "Custom/SkyObject", "Custom/StaticRock", "Custom/Tar", "Custom/Trilinearmap", "Custom/UI/BGBlur", "Custom/Vegetation", "Custom/Water", "Custom/WaterBottom", "Custom/WaterMask", "Custom/Yggdrasil", "Custom/Yggdrasil/root", "Hidden/BlitCopyHDRTonemap", "Hidden/Dof/DepthOfFieldHdr", "Hidden/Dof/DX11Dof", "Hidden/Internal-Loading", "Hidden/Internal-UIRDefaultWorld", "Hidden/SimpleClear", "Hidden/SunShaftsComposite", "Lux Lit Particles/ Bumped", "Lux Lit Particles/ Tess Bumped", "Particles/Standard Surface2", "Particles/Standard Unlit2", "Standard TwoSided", "ToonDeferredShading2017", "Unlit/DepthWrite", "Unlit/Lighting" }; public static List shaders = new List(); private static readonly HashSet CachedShaders = new HashSet(); public static bool debug = true; public static Shader findShader(string name) { Shader[] array = Resources.FindObjectsOfTypeAll(); if (array.Length == 0) { Debug.LogWarning((object)"SHADER LIST IS EMPTY!"); return null; } if (debug) { } return shaders.Find((Shader x) => ((Object)x).name == name); } public static Shader GetShaderByName(string name) { return shaders.Find((Shader x) => ((Object)x).name == name.Trim()); } public static void debugShaderList(List shadersRes) { foreach (Shader shadersRe in shadersRes) { Debug.LogWarning((object)("SHADER NAME IS: " + ((Object)shadersRe).name)); } debug = false; } public static void Replace(GameObject gameObject) { prefabsToReplaceShader.Add(gameObject); GetMaterialsInPrefab(gameObject); } public static void GetMaterialsInPrefab(GameObject gameObject) { Renderer[] componentsInChildren = gameObject.GetComponentsInChildren(true); Renderer[] array = componentsInChildren; foreach (Renderer val in array) { Material[] sharedMaterials = val.sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { continue; } Material[] array2 = sharedMaterials; foreach (Material val2 in array2) { if ((Object)(object)val2 != (Object)null) { materialsInPrefabs.Add(val2); } } } } public static void getMeShaders() { AssetBundle[] array = Resources.FindObjectsOfTypeAll(); AssetBundle[] array2 = array; foreach (AssetBundle val in array2) { IEnumerable enumerable3; try { IEnumerable enumerable2; if (!val.isStreamedSceneAssetBundle || !Object.op_Implicit((Object)(object)val)) { IEnumerable enumerable = val.LoadAllAssets(); enumerable2 = enumerable; } else { enumerable2 = from shader in ((IEnumerable)val.GetAllAssetNames()).Select((Func)val.LoadAsset) where (Object)(object)shader != (Object)null select shader; } enumerable3 = enumerable2; } catch (Exception) { continue; } if (enumerable3 == null) { continue; } foreach (Shader item in enumerable3) { CachedShaders.Add(item); } } } public static void runMaterialFix() { getMeShaders(); shaders.AddRange(CachedShaders); foreach (Material materialsInPrefab in materialsInPrefabs) { Shader shader = materialsInPrefab.shader; if (!((Object)(object)shader == (Object)null)) { string name = ((Object)shader).name; if (!(name == "Standard") && name.Contains("Balrond")) { setProperValue(materialsInPrefab, name); } } } } private static void setProperValue(Material material, string shaderName) { string name = shaderName.Replace("Balrond", "Custom"); name = checkNaming(name); Shader shaderByName = GetShaderByName(name); if ((Object)(object)shaderByName == (Object)null) { Debug.LogWarning((object)("Shader not found " + name)); } else { material.shader = shaderByName; } } private static string checkNaming(string name) { string result = name; if (name.Contains("Bumped")) { result = name.Replace("Custom", "Lux Lit Particles"); } if (name.Contains("Tess Bumped")) { result = name.Replace("Custom", "Lux Lit Particles"); } if (name.Contains("Standard Surface")) { result = name.Replace("Custom", "Particles"); result = result.Replace("Standard Surface2", "Standard Surface"); } if (name.Contains("Standard Unlit")) { result = name.Replace("Custom", "Particles"); result = result.Replace("Standard Unlit", "Standard Unlit2"); result = result.Replace("Standard Unlit22", "Standard Unlit2"); } return result; } } public class JsonLoader { public string defaultPath = string.Empty; public void loadJson() { LoadTranslations(); justDefaultPath(); } public void justDefaultPath() { string configPath = Paths.ConfigPath; string text = Path.Combine(configPath, "BalrondRuneRails-translation/"); defaultPath = text; } public void createDefaultPath() { string configPath = Paths.ConfigPath; string text = Path.Combine(configPath, "BalrondRuneRails-translation/"); if (!Directory.Exists(text)) { CreateFolder(text); } else { Debug.Log((object)("BalrondRuneRails: Folder already exists: " + text)); } defaultPath = text; } private string[] jsonFilePath(string folderName, string extension) { string configPath = Paths.ConfigPath; string text = Path.Combine(configPath, "BalrondRuneRails-translation/"); if (!Directory.Exists(text)) { CreateFolder(text); } else { Debug.Log((object)("BalrondRuneRails: Folder already exists: " + text)); } string[] files = Directory.GetFiles(text, extension); Debug.Log((object)("BalrondRuneRails:" + folderName + " Json Files Found: " + files.Length)); return files; } private static void CreateFolder(string path) { try { Directory.CreateDirectory(path); Debug.Log((object)"BalrondRuneRails: Folder created successfully."); } catch (Exception ex) { Debug.Log((object)("BalrondRuneRails: Error creating folder: " + ex.Message)); } } private void LoadTranslations() { int num = 0; string[] array = jsonFilePath("Translation", "*.json"); foreach (string text in array) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text); string json = File.ReadAllText(text); JsonData jsonData = JsonMapper.ToObject(json); Dictionary dictionary = new Dictionary(); foreach (string key in jsonData.Keys) { dictionary[key] = jsonData[key].ToString(); } if (dictionary != null) { BalrondTranslator.translations.Add(fileNameWithoutExtension, dictionary); Debug.Log((object)("BalrondRuneRails: Json Files Language: " + fileNameWithoutExtension)); num++; } else { Debug.LogError((object)("BalrondRuneRails: Loading FAILED file: " + text)); } } Debug.Log((object)("BalrondRuneRails: Translation JsonFiles Loaded: " + num)); } } [BepInPlugin("balrond.astafaraios.BalrondRuneRails", "BalrondRuneRails", "1.0.5")] public class Launch : BaseUnityPlugin { [HarmonyPatch(typeof(CraftingStation), "Start")] public static class BCSCartCraftingStation_Start_Patch { private static void Postfix(CraftingStation __instance) { if ((Object)(object)__instance == (Object)null) { return; } BCSCartCraftingStation component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null) { return; } if (component.m_disableRoofRequirement) { __instance.m_craftRequireRoof = false; } if (component.m_disableFireRequirement) { __instance.m_craftRequireFire = false; } if (!component.m_useCartZNetView) { return; } BCSCartRoot componentInParent = ((Component)__instance).GetComponentInParent(); if ((Object)(object)componentInParent == (Object)null) { Debug.LogWarning((object)("[BCS] Cart CraftingStation has no BCSCartRoot parent: " + ((Object)__instance).name)); return; } ZNetView netView = componentInParent.GetNetView(); if ((Object)(object)netView == (Object)null) { Debug.LogWarning((object)("[BCS] Cart CraftingStation parent cart has no ZNetView: " + ((Object)__instance).name)); return; } __instance.m_nview = netView; if (!CraftingStation.m_allStations.Contains(__instance)) { CraftingStation.m_allStations.Add(__instance); } } } [HarmonyPatch] public static class BCSPowerCartCameraPatches { private static Vector3 _cameraVelocity; private static Quaternion _lastRotation = Quaternion.identity; private static bool _initialized; [HarmonyPrefix] [HarmonyPatch(typeof(GameCamera), "UpdateCamera")] private static bool GameCamera_UpdateCamera_Prefix(GameCamera __instance, float dt) { //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: 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_0122: 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_012a: 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_013a: 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_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_00c9: 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_00e1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null) { Reset(); return true; } BCSPowerCartControls localDrivingCameraLockControl = BCSPowerCartControls.GetLocalDrivingCameraLockControl(); if ((Object)(object)localDrivingCameraLockControl == (Object)null) { Reset(); return true; } if (!localDrivingCameraLockControl.TryGetDriverViewCameraPose(out var position, out var rotation)) { Reset(); return true; } float num = Mathf.Max(0.01f, BCSCommonUtility.SanitizeFloat(localDrivingCameraLockControl.m_driverViewSmoothTime, 0.12f)); float num2 = ((dt > 0f) ? dt : Time.unscaledDeltaTime); if (num2 <= 0f) { num2 = Time.unscaledDeltaTime; } if (!_initialized) { _initialized = true; _cameraVelocity = Vector3.zero; _lastRotation = rotation; ((Component)__instance).transform.position = position; ((Component)__instance).transform.rotation = rotation; return false; } ((Component)__instance).transform.position = Vector3.SmoothDamp(((Component)__instance).transform.position, position, ref _cameraVelocity, num, 999f, num2); float num3 = Mathf.Clamp01(num2 / num); _lastRotation = Quaternion.Slerp(_lastRotation, rotation, num3); ((Component)__instance).transform.rotation = _lastRotation; return false; } private static void Reset() { //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_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) _initialized = false; _cameraVelocity = Vector3.zero; _lastRotation = Quaternion.identity; } } [HarmonyPatch(typeof(AudioMan), "Awake")] private static class AudioMan_Awake_Patch { private static void Postfix(AudioMan __instance) { List> list = new List> { modResourceLoader.itemPrefabs, modResourceLoader.buildPrefabs, modResourceLoader.monsterPrefabs, modResourceLoader.vfxPrefabs, modResourceLoader.vegetationPrefabs }; foreach (List item in list) { foreach (GameObject item2 in item) { AudioSource[] componentsInChildren = item2.GetComponentsInChildren(true); foreach (AudioSource val in componentsInChildren) { val.outputAudioMixerGroup = __instance.m_masterMixer.outputAudioMixerGroup; } } } } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] public static class Object_CopyOtherDB_Path { public static void Postfix() { if (IsObjectDBValid()) { modResourceLoader.setupBuildPiecesListDB(); modResourceLoader.recipes = recipeFactory.createRecipes(ObjectDB.instance.m_items, modResourceLoader.itemPrefabs, modResourceLoader.railwaytable); databaseAddMethods.AddItems(modResourceLoader.itemPrefabs); databaseAddMethods.AddStatuseffects(modResourceLoader.statusEffects); databaseAddMethods.AddRecipes(modResourceLoader.recipes); } } } [HarmonyPatch(typeof(ObjectDB), "Awake")] public static class ObjectDB_Awake_Path { public static void Postfix() { if (IsObjectDBValid()) { modResourceLoader.setupBuildPiecesListDB(); modResourceLoader.recipes = recipeFactory.createRecipes(ObjectDB.instance.m_items, modResourceLoader.itemPrefabs, modResourceLoader.railwaytable); databaseAddMethods.AddItems(modResourceLoader.itemPrefabs); databaseAddMethods.AddStatuseffects(modResourceLoader.statusEffects); databaseAddMethods.AddRecipes(modResourceLoader.recipes); ObjectDB.instance.m_recipes.Sort(SortByScore); } } private static int SortByScore(Recipe p1, Recipe p2) { if ((Object)(object)p1.m_item == (Object)null) { return 0; } if ((Object)(object)p2.m_item == (Object)null) { return 1; } return ((Object)p1.m_item).name.CompareTo(((Object)p2.m_item).name); } } [HarmonyPatch(typeof(ZNetScene), "Awake")] public static class ZNetScene_Awake_Path { public static void Prefix(ZNetScene __instance) { if ((Object)(object)__instance == (Object)null) { Debug.LogWarning((object)(projectName + ": No ZnetScene found")); return; } modResourceLoader.AddPrefabsToZnetScene(__instance); if (!hasSpawned) { buildPieceBuilder.SetupBuildPieces(__instance.m_prefabs); hasSpawned = true; if (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsDedicated()) { ShaderReplacment.runMaterialFix(); } } } } [HarmonyPatch(typeof(Door), "Interact")] public static class BCSSignalDoorReceiver_Interact_Patch { private static bool Prefix(Door __instance, Humanoid character, bool hold, bool alt, ref bool __result) { if ((Object)(object)__instance == (Object)null || hold) { return true; } BCSSignalDoorReceiver component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null) { return true; } if (IsShiftHeld()) { component.RequestSetSignalNameFromUser(); __result = true; return false; } if (IsAltHeld()) { component.ToggleEventStateFromUser(); __result = true; return false; } return true; } private static bool IsShiftHeld() { return Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303); } private static bool IsAltHeld() { return Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307); } } [HarmonyPatch(typeof(Door), "GetHoverText")] public static class BCSSignalDoorReceiver_Hover_Patch { private static void Postfix(Door __instance, ref string __result) { if (!((Object)(object)__instance == (Object)null)) { BCSSignalDoorReceiver component = ((Component)__instance).GetComponent(); if (!((Object)(object)component == (Object)null)) { __result += ((Localization.instance != null) ? Localization.instance.Localize(component.GetExtraHoverText()) : component.GetExtraHoverText()); } } } } [HarmonyPatch(typeof(Container), "Interact")] public static class BCS_Container_Interact_Patch { private static bool Prefix(Container __instance, Humanoid character, bool hold, bool alt, ref bool __result) { if ((Object)(object)__instance == (Object)null || hold || (Object)(object)character == (Object)null) { return true; } BCSCartRoot componentInParent = ((Component)__instance).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { BCSContainerInitUtility.EnsureInitialized(__instance, componentInParent.GetNetView()); return true; } BCSRailContainerTransfer componentInParent2 = ((Component)__instance).GetComponentInParent(); if ((Object)(object)componentInParent2 == (Object)null) { return true; } BCSContainerInitUtility.EnsureInitialized(__instance); if (!componentInParent2.OwnsContainer(__instance)) { return true; } if (componentInParent2.IsTransferRunning()) { __instance.UpdateUseVisual(); Player val = (Player)(object)((character is Player) ? character : null); if ((Object)(object)val != (Object)null) { ((Character)val).Message((MessageType)2, "Container transfer in progress", 0, (Sprite)null); } __result = true; return false; } return true; } } [HarmonyPatch(typeof(Container), "GetHoverText")] public static class BCS_Container_InitHover_Patch { private static void Prefix(Container __instance) { if ((Object)(object)__instance == (Object)null) { return; } BCSCartRoot componentInParent = ((Component)__instance).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { BCSContainerInitUtility.EnsureInitialized(__instance, componentInParent.GetNetView()); return; } BCSRailContainerTransfer componentInParent2 = ((Component)__instance).GetComponentInParent(); if ((Object)(object)componentInParent2 != (Object)null) { BCSContainerInitUtility.EnsureInitialized(__instance); __instance.UpdateUseVisual(); } } private static void Postfix(Container __instance, ref string __result) { if ((Object)(object)__instance == (Object)null) { return; } BCSRailContainerTransfer componentInParent = ((Component)__instance).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null) && componentInParent.OwnsContainer(__instance)) { string hoverStatusText = componentInParent.GetHoverStatusText(); if (!string.IsNullOrEmpty(hoverStatusText)) { __result = __result + "\n" + hoverStatusText; } } } } private readonly Harmony harmony = new Harmony("balrond.astafaraios.BalrondRuneRails"); public const string PluginGUID = "balrond.astafaraios.BalrondRuneRails"; public const string PluginName = "BalrondRuneRails"; public const string PluginVersion = "1.0.5"; public static ModResourceLoader modResourceLoader = new ModResourceLoader(); public static DatabaseAddMethods databaseAddMethods = new DatabaseAddMethods(); public static BuildPieceBuilder buildPieceBuilder = new BuildPieceBuilder(); public static string projectName = "BalrondRuneRails"; public static GameObject RootObject; public static GameObject PrefabContainer; public static bool hasSpawned = false; public static JsonLoader jsonLoader = new JsonLoader(); public static RecipeFactory recipeFactory = new RecipeFactory(); public static Vector2 sizeDelta; public static bool addedWidth = false; private void Awake() { jsonLoader.loadJson(); createPrefabContainer(); modResourceLoader.loadAssets(); debugvariabelcall(); harmony.PatchAll(); } public void createPrefabContainer() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown RootObject = new GameObject("_ValheimReforgedRoot"); Object.DontDestroyOnLoad((Object)(object)RootObject); PrefabContainer = new GameObject("Prefabs"); PrefabContainer.transform.parent = RootObject.transform; PrefabContainer.SetActive(false); } public static void debugvariabelcall() { Debug.LogWarning((object)"BalrondRuneRails DISPLAY ZDO KEYS KASHED NAMES:"); Debug.LogWarning((object)"BalrondRuneRails Track:"); Debug.Log((object)("Name: " + "hl_rail_id".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_rail_id".ToString()))); Debug.Log((object)("Name: " + "hl_rail_type".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_rail_type".ToString()))); Debug.Log((object)("Name: " + "hl_is_platform".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_is_platform".ToString()))); Debug.Log((object)("Name: " + "hl_neighbor_a".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_neighbor_a".ToString()))); Debug.Log((object)("Name: " + "hl_neighbor_b".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_neighbor_b".ToString()))); Debug.Log((object)("Name: " + "hl_neighbor_c".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_neighbor_c".ToString()))); Debug.Log((object)("Name: " + "hl_neighbor_d".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_neighbor_d".ToString()))); Debug.Log((object)("Name: " + "hl_rail_forced_stop".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_rail_forced_stop".ToString()))); Debug.Log((object)("Name: " + "hl_rail_switch_direction".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_rail_switch_direction".ToString()))); Debug.Log((object)("Name: " + "hl_halting".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_halting".ToString()))); Debug.Log((object)("Name: " + "hl_rail_stop_mode".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_rail_type".ToString()))); Debug.Log((object)("Name: " + "hl_stop_timer_seconds".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_rail_type".ToString()))); Debug.Log((object)("Name: " + "hl_stop_timer_end_time".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_rail_type".ToString()))); Debug.LogWarning((object)"BalrondRuneRails Cart:"); Debug.Log((object)("Name: " + "hl_cart_id".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_cart_id".ToString()))); Debug.Log((object)("Name: " + "hl_cart_type".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_cart_type".ToString()))); Debug.Log((object)("Name: " + "hl_front_cart_id".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_front_cart_id".ToString()))); Debug.Log((object)("Name: " + "hl_back_cart_id".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_back_cart_id".ToString()))); Debug.Log((object)("Name: " + "hl_current_rail_id".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_current_rail_id".ToString()))); Debug.Log((object)("Name: " + "hl_distance_on_rail".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_distance_on_rail".ToString()))); Debug.Log((object)("Name: " + "hl_reversed_on_rail".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_reversed_on_rail".ToString()))); Debug.Log((object)("Name: " + "hl_travel_reversed_on_rail".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_travel_reversed_on_rail".ToString()))); Debug.Log((object)("Name: " + "hl_running".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_running".ToString()))); Debug.Log((object)("Name: " + "hl_active_engine_id".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_active_engine_id".ToString()))); Debug.Log((object)("Name: " + "hl_fuel_amount".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_fuel_amount".ToString()))); Debug.Log((object)("Name: " + "hl_last_driver_id".ToString() + " Encoded: " + StringExtensionMethods.GetStableHashCode("hl_last_driver_id".ToString()))); Debug.LogWarning((object)"BalrondRuneRails DISPLAY ZDO KEYS KASHED END"); } public static GameObject cloneMe(GameObject source, string name) { GameObject val = Object.Instantiate(source, PrefabContainer.transform); ((Object)val).name = name; fixMaterials(val, source); val.SetActive(true); return val; } public static GameObject fixMaterials(GameObject clone, GameObject source) { MeshRenderer[] componentsInChildren = source.GetComponentsInChildren(); foreach (MeshRenderer val in componentsInChildren) { MeshRenderer[] componentsInChildren2 = clone.GetComponentsInChildren(); foreach (MeshRenderer val2 in componentsInChildren2) { if (((Object)val).name == ((Object)val2).name) { ((Renderer)val2).materials = ((Renderer)val).sharedMaterials; ((Renderer)val2).sharedMaterials = ((Renderer)val).sharedMaterials; break; } } } return clone; } private void OnDestroy() { harmony.UnpatchSelf(); } private static bool IsObjectDBValid() { return (Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.m_items.Count != 0 && ObjectDB.instance.m_recipes.Count != 0 && (Object)(object)ObjectDB.instance.GetItemPrefab("Amber") != (Object)null; } } public struct BCSCartPendingLinkData { public string CartId; public BCSCartCouplerSide Side; } public static class BCSCartPendingLinkManager { private static readonly Dictionary PendingLinks = new Dictionary(); public static bool TryGet(long playerId, out BCSCartPendingLinkData data) { return PendingLinks.TryGetValue(playerId, out data); } public static void Set(long playerId, string cartId, BCSCartCouplerSide side) { if (string.IsNullOrEmpty(cartId)) { PendingLinks.Remove(playerId); return; } BCSCartPendingLinkData bCSCartPendingLinkData = default(BCSCartPendingLinkData); bCSCartPendingLinkData.CartId = cartId; bCSCartPendingLinkData.Side = side; BCSCartPendingLinkData value = bCSCartPendingLinkData; PendingLinks[playerId] = value; } public static bool Has(long playerId) { return PendingLinks.ContainsKey(playerId); } public static void Clear(long playerId) { PendingLinks.Remove(playerId); } public static void ClearByCartId(string cartId) { if (string.IsNullOrEmpty(cartId)) { return; } List list = new List(); foreach (KeyValuePair pendingLink in PendingLinks) { if (pendingLink.Value.CartId == cartId) { list.Add(pendingLink.Key); } } for (int i = 0; i < list.Count; i++) { PendingLinks.Remove(list[i]); } } public static void ClearAll() { PendingLinks.Clear(); } } public class BCSCartRailPlacementSnap : MonoBehaviour { [Header("Rail Snap")] public float m_snapDelay = 0.15f; public float m_searchRadius = 1.25f; public float m_verticalRayUp = 1f; public float m_verticalRayDown = 2f; [Header("Cart Spacing")] public bool m_preventOverlap = true; public float m_minCartSpacing = 1.75f; public int m_spacingSearchSteps = 8; private bool _snapDone; private readonly List _cartScanScratch = new List(64); private readonly List _railScanScratch = new List(128); private IEnumerator Start() { yield return (object)new WaitForSeconds(Mathf.Max(0f, m_snapDelay)); if (!_snapDone) { _snapDone = true; TrySnap(); } } private void TrySnap() { BCSCartRoot component = ((Component)this).GetComponent(); if (!((Object)(object)component == (Object)null) && TryFindRailBelowOrNear(out var bestRail, out var bestDistance) && !((Object)(object)bestRail == (Object)null) && !string.IsNullOrEmpty(bestRail.GetRailId())) { bool reversed = ShouldPlaceReversed(bestRail); if (m_preventOverlap) { bestDistance = FindNonOverlappingDistance(bestRail, bestDistance); } component.SetRailPosition(bestRail.GetRailId(), bestDistance, reversed); component.AlignToCurrentRail(); component.TryAutoCoupleAfterManualPositionChange(); } } private bool TryFindRailBelowOrNear(out BCSRailPiece bestRail, out float bestDistance) { //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_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_004e: 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_00b2: 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_00d4: 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_00de: 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_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) bestRail = null; bestDistance = 0f; Vector3 val = ((Component)this).transform.position + Vector3.up * Mathf.Max(0f, m_verticalRayUp); float num = Mathf.Max(0.1f, m_verticalRayUp + m_verticalRayDown); RaycastHit[] array = Physics.RaycastAll(val, Vector3.down, num, -5, (QueryTriggerInteraction)2); float num2 = float.MaxValue; Vector3 val2; for (int i = 0; i < array.Length; i++) { BCSRailPiece bCSRailPiece = (((Object)(object)((RaycastHit)(ref array[i])).collider != (Object)null) ? ((Component)((RaycastHit)(ref array[i])).collider).GetComponentInParent() : null); if (!((Object)(object)bCSRailPiece == (Object)null) && bCSRailPiece.TryGetClosestDistanceOnRail(((Component)this).transform.position, out var distance, out var closestPoint)) { val2 = closestPoint - ((Component)this).transform.position; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude < num2) { num2 = sqrMagnitude; bestRail = bCSRailPiece; bestDistance = distance; } } } if ((Object)(object)bestRail != (Object)null) { return true; } float num3 = m_searchRadius * m_searchRadius; BCSRailRegistry.FillAll(_railScanScratch); for (int j = 0; j < _railScanScratch.Count; j++) { BCSRailPiece bCSRailPiece2 = _railScanScratch[j]; if (!((Object)(object)bCSRailPiece2 == (Object)null) && bCSRailPiece2.TryGetClosestDistanceOnRail(((Component)this).transform.position, out var distance2, out var closestPoint2)) { val2 = closestPoint2 - ((Component)this).transform.position; float sqrMagnitude2 = ((Vector3)(ref val2)).sqrMagnitude; if (!(sqrMagnitude2 > num3) && sqrMagnitude2 < num2) { num2 = sqrMagnitude2; bestRail = bCSRailPiece2; bestDistance = distance2; } } } return (Object)(object)bestRail != (Object)null; } private bool ShouldPlaceReversed(BCSRailPiece rail) { //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_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_0083: 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) if (!rail.TryGetForwardAtDistance(0f, out var forward)) { forward = ((Component)rail).transform.forward; } Vector3 forward2 = ((Component)this).transform.forward; forward.y = 0f; forward2.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude <= 0.0001f || ((Vector3)(ref forward2)).sqrMagnitude <= 0.0001f) { return false; } ((Vector3)(ref forward)).Normalize(); ((Vector3)(ref forward2)).Normalize(); return Vector3.Dot(forward2, forward) < 0f; } private float FindNonOverlappingDistance(BCSRailPiece rail, float desiredDistance) { float length = rail.GetLength(); if (length <= 0.001f) { return desiredDistance; } desiredDistance = Mathf.Clamp(desiredDistance, 0f, length); if (IsDistanceFree(rail, desiredDistance)) { return desiredDistance; } float num = Mathf.Max(0.25f, m_minCartSpacing); int num2 = Mathf.Max(1, m_spacingSearchSteps); for (int i = 1; i <= num2; i++) { float num3 = num * (float)i; float num4 = Mathf.Clamp(desiredDistance + num3, 0f, length); if (IsDistanceFree(rail, num4)) { return num4; } float num5 = Mathf.Clamp(desiredDistance - num3, 0f, length); if (IsDistanceFree(rail, num5)) { return num5; } } return desiredDistance; } private bool IsDistanceFree(BCSRailPiece rail, float distance) { string railId = rail.GetRailId(); if (string.IsNullOrEmpty(railId)) { return true; } BCSCartRegistry.FillAll(_cartScanScratch); for (int i = 0; i < _cartScanScratch.Count; i++) { BCSCartRoot bCSCartRoot = _cartScanScratch[i]; if (!((Object)(object)bCSCartRoot == (Object)null) && !((Object)(object)((Component)bCSCartRoot).gameObject == (Object)(object)((Component)this).gameObject) && !(bCSCartRoot.GetCurrentRailId() != railId)) { float distanceOnRail = bCSCartRoot.GetDistanceOnRail(); if (Mathf.Abs(distanceOnRail - distance) < Mathf.Max(0.1f, m_minCartSpacing)) { return false; } } } return true; } } public static class BCSCartRegistry { private static readonly Dictionary CartsById = new Dictionary(); private static readonly List RemoveKeysScratch = new List(32); public static void Register(BCSCartRoot cart) { if (IsValidCart(cart)) { string cartId = cart.GetCartId(); if (!string.IsNullOrEmpty(cartId)) { CartsById[cartId] = cart; } } } public static void Unregister(BCSCartRoot cart) { if (!((Object)(object)cart == (Object)null)) { string cartId = cart.GetCartId(); if (!string.IsNullOrEmpty(cartId) && CartsById.TryGetValue(cartId, out var value) && (Object)(object)value == (Object)(object)cart) { CartsById.Remove(cartId); } } } public static ICollection GetAll() { CleanupInvalidReferences(); return CartsById.Values; } public static void FillAll(List result) { if (result == null) { return; } result.Clear(); CleanupInvalidReferences(); foreach (BCSCartRoot value in CartsById.Values) { if ((Object)(object)value != (Object)null) { result.Add(value); } } } public static BCSCartRoot FindById(string cartId) { if (string.IsNullOrEmpty(cartId)) { return null; } if (!CartsById.TryGetValue(cartId, out var value)) { return null; } if (!IsValidCart(value)) { CartsById.Remove(cartId); return null; } return value; } public static void CleanupInvalidReferences() { RemoveKeysScratch.Clear(); foreach (KeyValuePair item in CartsById) { if (!IsValidCart(item.Value)) { RemoveKeysScratch.Add(item.Key); } } for (int i = 0; i < RemoveKeysScratch.Count; i++) { CartsById.Remove(RemoveKeysScratch[i]); } RemoveKeysScratch.Clear(); } private static bool IsValidCart(BCSCartRoot cart) { if ((Object)(object)cart == (Object)null) { return false; } try { if (!((Component)cart).gameObject.activeInHierarchy) { return false; } ZNetView netView = cart.GetNetView(); return (Object)(object)netView != (Object)null && netView.IsValid() && netView.GetZDO() != null; } catch { return false; } } } public class BCSCartRoot : MonoBehaviour { private ZNetView _nview; private bool _switchesHooked; private bool _lastMovingState; private bool _lastPowerEnabledState; private bool _lastHaltingState; private bool _movementStateInitialized; private string _cachedCartId = string.Empty; private string _cachedFrontCartId = string.Empty; private string _cachedBackCartId = string.Empty; private string _cachedCurrentRailId = string.Empty; private GameObject _frontConnectionEffect; private GameObject _backConnectionEffect; private bool _lastWheelForward; private bool _lastWheelBackward; private float _lastAppliedWheelAnimSpeed = -1f; private bool _wheelSpeedInitialized; private float _lastDistanceOnRail; private string _lastWheelRailId = string.Empty; private float _currentWheelAnimSpeed = 1f; private bool _wheelDirectionInitialized; private Vector3 _lastWheelWorldPosition; private float _lastSignedLocalWheelMotion; private BCSPowerCartControls _powerControls; private float _connectionVisualIdleTimer; private static readonly List SharedChainBuffer = new List(64); private static readonly HashSet SharedVisited = new HashSet(); private static readonly Queue SharedQueue = new Queue(64); private readonly List _autoCoupleCandidatesScratch = new List(64); [Header("Cart")] public BCSCartType m_cartType = BCSCartType.Powered; public float m_cartLength = 1.8f; public float m_followDistance = 0.1f; public bool m_allowRuntimeAdditions = true; [Header("Switches")] public Switch m_frontCouplerSwitch; public Switch m_backCouplerSwitch; public Switch m_engineSwitch; [Header("Optional Child References")] public GameObject m_containerObject; public Container m_container; public GameObject m_seatObject; public Chair m_chair; [Header("Connection Point")] public Transform m_frontPosePoint; public Transform m_backPosePoint; [Header("References")] public Transform m_frontCouplerPoint; public Transform m_backCouplerPoint; [Header("Visual State Objects")] public GameObject m_powerEnabledObject; public GameObject m_isMovingObject; public GameObject m_isHaltingObject; public GameObject m_powerDisabledObject; [Header("Connection Effect")] public GameObject m_connectionPrefab; public Vector3 m_connectionEffectScale = new Vector3(1f, 1f, 1f); [Header("Movement Effects")] public EffectList m_moveStartEffects = new EffectList(); public EffectList m_moveStopEffects = new EffectList(); public bool m_attachMoveEffectsToCart = true; [Header("Jump Rider Effects")] public bool m_enableJumpRiderEffects = true; public bool m_attachJumpRiderEffectsToCart = true; public float m_jumpEffectCooldown = 0.35f; public EffectList m_jumpLaunchRiderEffects = new EffectList(); public EffectList m_jumpLandRiderEffects = new EffectList(); public float m_jumpSeatDetectionRadius = 0.35f; private bool _jumpTrackerInitialized; private string _lastJumpRailId = string.Empty; private float _lastJumpDistance; private float _lastJumpLaunchEffectTime = -999f; private float _lastJumpLandEffectTime = -999f; [Header("Halting Visual")] public float m_minHaltingVisualDuration = 1.25f; public EffectList m_haltingStartEffects = new EffectList(); private float _haltingVisualUntil; private bool _lastHaltingVisualState; private AudioSource[] _movingAudioSources; private AudioSource[] _haltingAudioSources; [Header("Animation")] public Transform[] m_wheelAnimators; public float m_wheelRotationDegreesPerMeter = 360f; public float m_minWheelAnimationSpeed = 0.75f; public float m_maxWheelAnimationSpeed = 3f; public float m_wheelAnimationSpeedResponse = 8f; public float m_wheelAnimationIdleReturnSpeed = 10f; [Header("Debug")] public bool m_enableDebugLogs = false; private const string RpcToggleTrain = "RPC_ToggleTrain"; private const string RpcFlipCart = "RPC_FlipDisconnected"; private const string RpcAlignCart = "RPC_AlignToCurrentRail"; private const string RpcConnectCouplers = "RPC_ConnectCouplers"; private const string RpcDisconnectCoupler = "RPC_DisconnectCoupler"; public float m_autoCoupleRadius = 0.35f; public bool m_enableAutoCouple = true; private void Awake() { _nview = ((Component)this).GetComponent(); if ((Object)(object)_nview != (Object)null) { _nview.Register("RPC_ToggleTrain", (Action)RPC_ToggleTrain); _nview.Register("RPC_FlipDisconnected", (Action)RPC_FlipDisconnected); _nview.Register("RPC_AlignToCurrentRail", (Action)RPC_AlignToCurrentRail); _nview.Register("RPC_ConnectCouplers", (Action)RPC_ConnectCouplers); _nview.Register("RPC_DisconnectCoupler", (Action)RPC_DisconnectCoupler); } ResolveOptionalReferences(); EnsureCartId(); HookSwitches(); CacheStateAudioSources(); BCSCartRegistry.Register(this); InitializeWheelAnimationTracking(); UpdateVisualStateImmediate(); UpdateWheelAnimationSpeed(); UpdateAnimationStateImmediate(); UpdateConnectionVisualsImmediate(); _powerControls = ((Component)this).GetComponent(); Log("Awake done. cartType=" + m_cartType.ToString() + " cartId=" + BCSCommonUtility.SafeString(GetCartId()) + " railId=" + BCSCommonUtility.SafeString(GetCurrentRailId()) + " engineSwitch=" + BCSCommonUtility.SafeName((Object)(object)m_engineSwitch) + " frontSwitch=" + BCSCommonUtility.SafeName((Object)(object)m_frontCouplerSwitch) + " backSwitch=" + BCSCommonUtility.SafeName((Object)(object)m_backCouplerSwitch)); } private void Start() { ResolveOptionalReferences(); HookSwitches(); Log("Start done. container=" + BCSCommonUtility.SafeName((Object)(object)m_container) + " seat=" + BCSCommonUtility.SafeName((Object)(object)m_chair) + " rootNviewValid=" + ((Object)(object)_nview != (Object)null && _nview.IsValid())); } private void OnDestroy() { string cachedCartId = _cachedCartId; string cachedFrontCartId = _cachedFrontCartId; string cachedBackCartId = _cachedBackCartId; bool flag = ShouldCleanupNetworkLinksOnDestroy(); DestroyConnectionEffect(ref _frontConnectionEffect); DestroyConnectionEffect(ref _backConnectionEffect); UnhookSwitches(); BCSCartRegistry.Unregister(this); BCSCartPendingLinkManager.ClearByCartId(cachedCartId); if ((Object)(object)m_containerObject != (Object)null && (Object)(object)m_container != (Object)null && HasStoredItems()) { m_containerObject.SetActive(true); } Log("OnDestroy cleanupNetworkLinks=" + flag); } public bool TryPrepareContainerForUnload(out Container container, out bool previousActiveState, out bool restoreActiveState) { container = null; previousActiveState = true; restoreActiveState = false; if ((Object)(object)m_containerObject == (Object)null) { ResolveOptionalReferences(); container = m_container; if ((Object)(object)container != (Object)null) { BCSContainerInitUtility.EnsureInitialized(container, _nview); } return (Object)(object)container != (Object)null && container.GetInventory() != null; } previousActiveState = m_containerObject.activeSelf; if (!previousActiveState) { m_containerObject.SetActive(true); restoreActiveState = true; } ResolveOptionalReferences(); container = m_container; if ((Object)(object)container != (Object)null) { BCSContainerInitUtility.EnsureInitialized(container, _nview); } return (Object)(object)container != (Object)null && container.GetInventory() != null; } public void RestoreContainerAfterUnload(bool previousActiveState) { if (!((Object)(object)m_containerObject == (Object)null)) { m_containerObject.SetActive(previousActiveState); ResolveOptionalReferences(); } } private bool ShouldCleanupNetworkLinksOnDestroy() { if ((Object)(object)_nview == (Object)null) { return true; } if (!_nview.IsValid()) { return false; } return _nview.IsOwner(); } private void Update() { bool flag = IsRunning(); bool flag2 = HasFrontConnection() || HasBackConnection(); if (flag) { UpdateWheelAnimationDirection(); UpdateWheelAnimationSpeed(); UpdateAnimationState(); if (flag2) { UpdateConnectionVisuals(); } } else { UpdateIdleVisualTick(); if (flag2) { UpdateConnectionVisualsIdleTick(); } } } private void UpdateIdleVisualTick() { UpdateVisualState(); UpdateAnimationState(); } public ZNetView GetNetView() { return _nview; } public string GetCartId() { ZDO validZdo = GetValidZdo(); if (validZdo != null) { string @string = validZdo.GetString("hl_cart_id", string.Empty); if (!string.IsNullOrEmpty(@string)) { _cachedCartId = @string; } } return _cachedCartId; } public bool IsPowered() { return m_cartType == BCSCartType.Powered; } public string GetFrontCartId() { ZDO validZdo = GetValidZdo(); if (validZdo != null) { _cachedFrontCartId = validZdo.GetString("hl_front_cart_id", string.Empty); } return _cachedFrontCartId; } public string GetBackCartId() { ZDO validZdo = GetValidZdo(); if (validZdo != null) { _cachedBackCartId = validZdo.GetString("hl_back_cart_id", string.Empty); } return _cachedBackCartId; } public void SetFrontCartId(string cartId) { string text = cartId ?? string.Empty; ZDO validZdo = GetValidZdo(); if (validZdo == null) { _cachedFrontCartId = text; return; } ClaimOwnershipIfNeeded(); validZdo.Set("hl_front_cart_id", text); _cachedFrontCartId = text; } public void SetBackCartId(string cartId) { string text = cartId ?? string.Empty; ZDO validZdo = GetValidZdo(); if (validZdo == null) { _cachedBackCartId = text; return; } ClaimOwnershipIfNeeded(); validZdo.Set("hl_back_cart_id", text); _cachedBackCartId = text; } public bool HasFrontConnection() { return !string.IsNullOrEmpty(GetFrontCartId()); } public bool HasBackConnection() { return !string.IsNullOrEmpty(GetBackCartId()); } public bool HasBothConnections() { return HasFrontConnection() && HasBackConnection(); } public bool CanBeDominantEngine() { return IsPowered() && !HasBothConnections(); } public bool ShouldMoveTowardFront() { if (!CanBeDominantEngine()) { return false; } if (!HasFrontConnection() && !HasBackConnection()) { return true; } return !HasFrontConnection(); } public string GetCurrentRailId() { ZDO validZdo = GetValidZdo(); if (validZdo != null) { _cachedCurrentRailId = validZdo.GetString("hl_current_rail_id", string.Empty); } return _cachedCurrentRailId; } public float GetDistanceOnRail() { ZDO validZdo = GetValidZdo(); if (validZdo == null) { return 0f; } return BCSCommonUtility.SanitizeFloat(validZdo.GetFloat("hl_distance_on_rail", 0f), 0f); } public bool IsReversedOnRail() { ZDO validZdo = GetValidZdo(); if (validZdo == null) { return false; } return validZdo.GetBool("hl_reversed_on_rail", false); } public bool GetTravelReversedOnRail() { bool derivedTravelReversedOnRail = GetDerivedTravelReversedOnRail(); ZDO validZdo = GetValidZdo(); if (validZdo == null) { return derivedTravelReversedOnRail; } if (!IsRunning()) { return derivedTravelReversedOnRail; } return validZdo.GetBool("hl_travel_reversed_on_rail", derivedTravelReversedOnRail); } public bool GetDerivedTravelReversedOnRail() { bool flag = IsReversedOnRail(); return ShouldMoveTowardFront() ? flag : (!flag); } public void SetTravelReversedOnRail(bool travelReversed) { ZDO validZdo = GetValidZdo(); if (validZdo != null) { ClaimOwnershipIfNeeded(); validZdo.Set("hl_travel_reversed_on_rail", travelReversed); } } public bool IsRunning() { ZDO validZdo = GetValidZdo(); if (validZdo == null) { return false; } return validZdo.GetBool("hl_running", false); } public bool IsHalting() { ZDO validZdo = GetValidZdo(); if (validZdo == null) { return false; } return validZdo.GetBool("hl_halting", false); } public string GetActiveEngineId() { ZDO validZdo = GetValidZdo(); if (validZdo == null) { return string.Empty; } return validZdo.GetString("hl_active_engine_id", string.Empty); } public void SetRailPosition(string railId, float distanceOnRail, bool reversed) { string currentRailId = GetCurrentRailId(); float distanceOnRail2 = GetDistanceOnRail(); bool travelReversedOnRail = GetTravelReversedOnRail(); string text = railId ?? string.Empty; float num = BCSCommonUtility.SanitizeFloat(distanceOnRail, 0f); ZDO validZdo = GetValidZdo(); if (validZdo == null) { _cachedCurrentRailId = text; HandleJumpRiderEffects(currentRailId, distanceOnRail2, travelReversedOnRail, text, num, travelReversedOnRail); return; } ClaimOwnershipIfNeeded(); validZdo.Set("hl_current_rail_id", text); validZdo.Set("hl_distance_on_rail", num); validZdo.Set("hl_reversed_on_rail", reversed); _cachedCurrentRailId = text; bool travelReversedOnRail2 = GetTravelReversedOnRail(); HandleJumpRiderEffects(currentRailId, distanceOnRail2, travelReversedOnRail, text, num, travelReversedOnRail2); } public void SetHaltingStateLocal(bool halting) { ZDO validZdo = GetValidZdo(); if (validZdo != null) { ClaimOwnershipIfNeeded(); validZdo.Set("hl_halting", halting); if (halting) { TriggerHaltingVisual(); } UpdateVisualStateImmediate(); UpdateAnimationStateImmediate(); Log("SetHaltingStateLocal halting=" + halting + " haltingObject=" + BCSCommonUtility.SafeName((Object)(object)m_isHaltingObject) + " visualUntil=" + _haltingVisualUntil.ToString("0.###")); } } public void AlignToCurrentRail() { //IL_00bf: 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_009b: 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_00b1: 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) string currentRailId = GetCurrentRailId(); if (string.IsNullOrEmpty(currentRailId)) { LogWarn("AlignToCurrentRail: current rail id empty"); return; } BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(currentRailId); if ((Object)(object)bCSRailPiece == (Object)null) { LogWarn("AlignToCurrentRail: rail not found for id=" + currentRailId); return; } float closestCenteredDistance = bCSRailPiece.GetClosestCenteredDistance(GetDistanceOnRail()); closestCenteredDistance = BCSCommonUtility.SanitizeFloat(closestCenteredDistance, 0f); if (!bCSRailPiece.GetPose(closestCenteredDistance, out var pos, out var rot)) { LogWarn("AlignToCurrentRail: rail.GetPose failed"); return; } if (IsReversedOnRail()) { rot *= Quaternion.Euler(0f, 180f, 0f); } ((Component)this).transform.position = pos; ((Component)this).transform.rotation = rot; SetRailPosition(bCSRailPiece.GetRailId(), closestCenteredDistance, IsReversedOnRail()); } public void FlipOnCurrentRail() { SetRailPosition(GetCurrentRailId(), GetDistanceOnRail(), !IsReversedOnRail()); AlignToCurrentRail(); } public void DisconnectAllCouplers() { if (HasFrontConnection()) { TryDisconnectSide(BCSCartCouplerSide.Front); } if (HasBackConnection()) { TryDisconnectSide(BCSCartCouplerSide.Back); } UpdateConnectionVisualsImmediate(); } public void StartTrain() { if (!CanBeDominantEngine()) { LogWarn("StartTrain blocked: CanBeDominantEngine == false"); return; } string cartId = GetCartId(); if (string.IsNullOrEmpty(cartId)) { LogWarn("StartTrain blocked: cart id empty"); return; } SetRunningForConnectedTrain(running: true, cartId); DebugEngineState("StartTrain after SetRunningForConnectedTrain"); } public void StopTrain() { SetRunningForConnectedTrain(running: false, string.Empty); DebugEngineState("StopTrain after SetRunningForConnectedTrain"); } public bool RequestToggleTrain(Player player) { if ((Object)(object)player == (Object)null) { LogWarn("RequestToggleTrain failed: player == null"); return false; } if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { ((Character)player).Message((MessageType)2, "Cart network view invalid", 0, (Sprite)null); LogWarn("RequestToggleTrain failed: nview invalid"); return false; } DebugEngineState("RequestToggleTrain begin"); if (!IsPowered()) { ((Character)player).Message((MessageType)2, "This cart has no engine", 0, (Sprite)null); LogWarn("RequestToggleTrain blocked: IsPowered == false"); return false; } string cartId = GetCartId(); if (string.IsNullOrEmpty(cartId)) { ((Character)player).Message((MessageType)2, "Cart has no id", 0, (Sprite)null); LogWarn("RequestToggleTrain blocked: cart id empty"); return false; } bool flag = IsAnyCartInConnectedTrainRunning(); string connectedTrainActiveEngineId = GetConnectedTrainActiveEngineId(); Log("RequestToggleTrain chainRunning=" + flag + " activeEngineId=" + BCSCommonUtility.SafeString(connectedTrainActiveEngineId) + " hasFront=" + HasFrontConnection() + " hasBack=" + HasBackConnection() + " canBeDominant=" + CanBeDominantEngine() + " currentRail=" + BCSCommonUtility.SafeString(GetCurrentRailId())); if (flag) { if (connectedTrainActiveEngineId == cartId) { _nview.InvokeRPC("RPC_ToggleTrain", Array.Empty()); ((Character)player).Message((MessageType)2, "Train stopped", 0, (Sprite)null); return true; } if (!CanBeDominantEngine()) { ((Character)player).Message((MessageType)2, "Engine must be at train end", 0, (Sprite)null); LogWarn("RequestToggleTrain blocked while running: engine is not at train end"); return false; } _nview.InvokeRPC("RPC_ToggleTrain", Array.Empty()); ((Character)player).Message((MessageType)2, "Engine switched", 0, (Sprite)null); return true; } if (!CanBeDominantEngine()) { ((Character)player).Message((MessageType)2, "Engine must be at train end", 0, (Sprite)null); LogWarn("RequestToggleTrain blocked: CanBeDominantEngine == false"); return false; } if (string.IsNullOrEmpty(GetCurrentRailId())) { ((Character)player).Message((MessageType)2, "Cart is not on rail", 0, (Sprite)null); LogWarn("RequestToggleTrain blocked: current rail id empty"); return false; } _nview.InvokeRPC("RPC_ToggleTrain", Array.Empty()); ((Character)player).Message((MessageType)2, "Train started", 0, (Sprite)null); return true; } private void RPC_ToggleTrain(long sender) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { ToggleTrainOwned(); } } private bool ToggleTrainOwned() { DebugEngineState("ToggleTrainOwned begin"); if (!IsPowered()) { LogWarn("ToggleTrainOwned blocked: IsPowered == false"); return false; } string cartId = GetCartId(); if (string.IsNullOrEmpty(cartId)) { LogWarn("ToggleTrainOwned blocked: cart id empty"); return false; } bool flag = IsAnyCartInConnectedTrainRunning(); string connectedTrainActiveEngineId = GetConnectedTrainActiveEngineId(); Log("ToggleTrainOwned chainRunning=" + flag + " activeEngineId=" + BCSCommonUtility.SafeString(connectedTrainActiveEngineId) + " hasFront=" + HasFrontConnection() + " hasBack=" + HasBackConnection() + " canBeDominant=" + CanBeDominantEngine() + " currentRail=" + BCSCommonUtility.SafeString(GetCurrentRailId())); if (flag) { if (connectedTrainActiveEngineId == cartId) { StopTrain(); return true; } if (!CanBeDominantEngine()) { LogWarn("ToggleTrainOwned blocked while running: engine is not at train end"); return false; } StartTrain(); return true; } if (!CanBeDominantEngine()) { LogWarn("ToggleTrainOwned blocked: CanBeDominantEngine == false"); return false; } if (string.IsNullOrEmpty(GetCurrentRailId())) { LogWarn("ToggleTrainOwned blocked: current rail id empty"); return false; } StartTrain(); return true; } public void ForceRefreshReferences() { _nview = ((Component)this).GetComponent(); ResolveOptionalReferences(); HookSwitches(); _powerControls = ((Component)this).GetComponent(); Log("ForceRefreshReferences done. engineSwitch=" + BCSCommonUtility.SafeName((Object)(object)m_engineSwitch) + " container=" + BCSCommonUtility.SafeName((Object)(object)m_container) + " chair=" + BCSCommonUtility.SafeName((Object)(object)m_chair)); } public void DebugEngineState(string source) { Log(source + " | cartId=" + BCSCommonUtility.SafeString(GetCartId()) + " | railId=" + BCSCommonUtility.SafeString(GetCurrentRailId()) + " | running=" + IsRunning() + " | halting=" + IsHalting() + " | activeEngineId=" + BCSCommonUtility.SafeString(GetActiveEngineId()) + " | front=" + BCSCommonUtility.SafeString(GetFrontCartId()) + " | back=" + BCSCommonUtility.SafeString(GetBackCartId()) + " | isPowered=" + IsPowered() + " | canBeDominant=" + CanBeDominantEngine() + " | towardFront=" + ShouldMoveTowardFront() + " | reversedOnRail=" + IsReversedOnRail() + " | localWheelMotion=" + _lastSignedLocalWheelMotion.ToString("0.#####") + " | wheelForwardVisual=" + IsThisCartMovingForwardVisually() + " | wheelBackwardVisual=" + IsThisCartMovingBackwardVisually() + " | wheelAnimSpeed=" + _currentWheelAnimSpeed.ToString("0.###") + " | approxHalfLength=" + GetApproxHalfLength().ToString("0.###") + " | nviewValid=" + ((Object)(object)_nview != (Object)null && _nview.IsValid()) + " | isOwner=" + ((Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.IsOwner())); } public float GetApproxHalfLength() { //IL_0029: 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) if ((Object)(object)m_frontPosePoint != (Object)null && (Object)(object)m_backPosePoint != (Object)null) { float value = Vector3.Distance(m_frontPosePoint.position, m_backPosePoint.position) * 0.5f; return Mathf.Max(0.05f, BCSCommonUtility.SanitizeFloat(value, 0.5f)); } return Mathf.Max(0.05f, BCSCommonUtility.SanitizeFloat(m_cartLength, 1f) * 0.5f); } public float GetCenterToCouplerDistance(BCSCartCouplerSide side) { //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_0039: 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) Transform val = ((side == BCSCartCouplerSide.Front) ? m_frontCouplerPoint : m_backCouplerPoint); if ((Object)(object)val == (Object)null) { return GetApproxHalfLength(); } Vector3 val2 = ((Component)this).transform.InverseTransformPoint(val.position); return Mathf.Max(0.05f, Mathf.Abs(BCSCommonUtility.SanitizeFloat(val2.z, GetApproxHalfLength()))); } public float GetPreferredFollowDistanceTo(BCSCartRoot other) { return GetPreferredFollowDistanceTo(other, BCSCartCouplerSide.Back, BCSCartCouplerSide.Front); } public float GetPreferredFollowDistanceTo(BCSCartRoot other, BCSCartCouplerSide mySide, BCSCartCouplerSide otherSide) { if ((Object)(object)other == (Object)null) { return Mathf.Max(0.1f, BCSCommonUtility.SanitizeFloat(m_followDistance, 0.1f)); } float centerToCouplerDistance = GetCenterToCouplerDistance(mySide); float centerToCouplerDistance2 = other.GetCenterToCouplerDistance(otherSide); float num = Mathf.Max(0.05f, BCSCommonUtility.SanitizeFloat(m_followDistance, 0.1f)); return centerToCouplerDistance + centerToCouplerDistance2 + num; } private void ResolveOptionalReferences() { if ((Object)(object)m_containerObject != (Object)null) { m_container = m_containerObject.GetComponent(); if ((Object)(object)m_container == (Object)null) { m_container = m_containerObject.GetComponentInChildren(true); } } else if ((Object)(object)m_container == (Object)null) { m_container = ((Component)this).GetComponentInChildren(true); } if ((Object)(object)m_seatObject != (Object)null) { m_chair = m_seatObject.GetComponent(); if ((Object)(object)m_chair == (Object)null) { m_chair = m_seatObject.GetComponentInChildren(true); } } if ((Object)(object)m_container != (Object)null && (Object)(object)_nview != (Object)null) { m_container.m_rootObjectOverride = _nview; } ConfigureChairForMovingCart(); } private void HookSwitches() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Expected O, but got Unknown //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Expected O, but got Unknown //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Expected O, but got Unknown //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Expected O, but got Unknown //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Expected O, but got Unknown if (!_switchesHooked) { if ((Object)(object)m_frontCouplerSwitch != (Object)null) { Switch frontCouplerSwitch = m_frontCouplerSwitch; frontCouplerSwitch.m_onUse = (Callback)Delegate.Combine((Delegate?)(object)frontCouplerSwitch.m_onUse, (Delegate?)new Callback(OnUseFrontCoupler)); Switch frontCouplerSwitch2 = m_frontCouplerSwitch; frontCouplerSwitch2.m_onHover = (TooltipCallback)Delegate.Combine((Delegate?)(object)frontCouplerSwitch2.m_onHover, (Delegate?)new TooltipCallback(OnHoverFrontCoupler)); } if ((Object)(object)m_backCouplerSwitch != (Object)null) { Switch backCouplerSwitch = m_backCouplerSwitch; backCouplerSwitch.m_onUse = (Callback)Delegate.Combine((Delegate?)(object)backCouplerSwitch.m_onUse, (Delegate?)new Callback(OnUseBackCoupler)); Switch backCouplerSwitch2 = m_backCouplerSwitch; backCouplerSwitch2.m_onHover = (TooltipCallback)Delegate.Combine((Delegate?)(object)backCouplerSwitch2.m_onHover, (Delegate?)new TooltipCallback(OnHoverBackCoupler)); } if ((Object)(object)m_engineSwitch != (Object)null) { Switch engineSwitch = m_engineSwitch; engineSwitch.m_onUse = (Callback)Delegate.Combine((Delegate?)(object)engineSwitch.m_onUse, (Delegate?)new Callback(OnUseEngineSwitch)); Switch engineSwitch2 = m_engineSwitch; engineSwitch2.m_onHover = (TooltipCallback)Delegate.Combine((Delegate?)(object)engineSwitch2.m_onHover, (Delegate?)new TooltipCallback(OnHoverEngineSwitch)); } _switchesHooked = true; } } private void UnhookSwitches() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Expected O, but got Unknown //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Expected O, but got Unknown //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Expected O, but got Unknown //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Expected O, but got Unknown //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Expected O, but got Unknown //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Expected O, but got Unknown if (_switchesHooked) { if ((Object)(object)m_frontCouplerSwitch != (Object)null) { Switch frontCouplerSwitch = m_frontCouplerSwitch; frontCouplerSwitch.m_onUse = (Callback)Delegate.Remove((Delegate?)(object)frontCouplerSwitch.m_onUse, (Delegate?)new Callback(OnUseFrontCoupler)); Switch frontCouplerSwitch2 = m_frontCouplerSwitch; frontCouplerSwitch2.m_onHover = (TooltipCallback)Delegate.Remove((Delegate?)(object)frontCouplerSwitch2.m_onHover, (Delegate?)new TooltipCallback(OnHoverFrontCoupler)); } if ((Object)(object)m_backCouplerSwitch != (Object)null) { Switch backCouplerSwitch = m_backCouplerSwitch; backCouplerSwitch.m_onUse = (Callback)Delegate.Remove((Delegate?)(object)backCouplerSwitch.m_onUse, (Delegate?)new Callback(OnUseBackCoupler)); Switch backCouplerSwitch2 = m_backCouplerSwitch; backCouplerSwitch2.m_onHover = (TooltipCallback)Delegate.Remove((Delegate?)(object)backCouplerSwitch2.m_onHover, (Delegate?)new TooltipCallback(OnHoverBackCoupler)); } if ((Object)(object)m_engineSwitch != (Object)null) { Switch engineSwitch = m_engineSwitch; engineSwitch.m_onUse = (Callback)Delegate.Remove((Delegate?)(object)engineSwitch.m_onUse, (Delegate?)new Callback(OnUseEngineSwitch)); Switch engineSwitch2 = m_engineSwitch; engineSwitch2.m_onHover = (TooltipCallback)Delegate.Remove((Delegate?)(object)engineSwitch2.m_onHover, (Delegate?)new TooltipCallback(OnHoverEngineSwitch)); } _switchesHooked = false; } } private bool OnUseFrontCoupler(Switch sw, Humanoid user, ItemData item) { return RequestUseCoupler((Player)(object)((user is Player) ? user : null), BCSCartCouplerSide.Front); } private bool OnUseBackCoupler(Switch sw, Humanoid user, ItemData item) { return RequestUseCoupler((Player)(object)((user is Player) ? user : null), BCSCartCouplerSide.Back); } public bool RequestUseCoupler(Player player, BCSCartCouplerSide side) { if ((Object)(object)player == (Object)null || (Object)(object)_nview == (Object)null || !_nview.IsValid()) { return false; } if (IsAnyCartInConnectedTrainRunning()) { ((Character)player).Message((MessageType)2, "Stop train first", 0, (Sprite)null); return true; } if (!IsSideFree(this, side)) { _nview.InvokeRPC("RPC_DisconnectCoupler", new object[1] { (int)side }); ((Character)player).Message((MessageType)2, "Cart unlink requested", 0, (Sprite)null); return true; } string cartId = GetCartId(); if (string.IsNullOrEmpty(cartId)) { ((Character)player).Message((MessageType)2, "Cart has no id", 0, (Sprite)null); return true; } long playerID = player.GetPlayerID(); if (!BCSCartPendingLinkManager.TryGet(playerID, out var data)) { BCSCartPendingLinkManager.Set(playerID, cartId, side); ((Character)player).Message((MessageType)2, "Link started", 0, (Sprite)null); return true; } BCSCartPendingLinkManager.Clear(playerID); if (data.CartId == cartId) { ((Character)player).Message((MessageType)2, "Link canceled", 0, (Sprite)null); return true; } BCSCartRoot bCSCartRoot = BCSCartRegistry.FindById(data.CartId); if ((Object)(object)bCSCartRoot == (Object)null) { ((Character)player).Message((MessageType)2, "Missing cart", 0, (Sprite)null); return true; } if (bCSCartRoot.IsAnyCartInConnectedTrainRunning()) { ((Character)player).Message((MessageType)2, "Stop train first", 0, (Sprite)null); return true; } _nview.InvokeRPC("RPC_ConnectCouplers", new object[3] { (int)side, bCSCartRoot.GetCartId(), (int)data.Side }); ((Character)player).Message((MessageType)2, "Link requested", 0, (Sprite)null); return true; } private void RPC_DisconnectCoupler(long sender, int sideRaw) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { BCSCartCouplerSide side = BCSCommonUtility.DecodeCouplerSide(sideRaw); if (!IsAnyCartInConnectedTrainRunning()) { TryDisconnectSide(side); UpdateConnectionVisualsImmediate(); } } } private void RPC_ConnectCouplers(long sender, int mySideRaw, string otherCartId, int otherSideRaw) { if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner()) { return; } BCSCartCouplerSide aSide = BCSCommonUtility.DecodeCouplerSide(mySideRaw); BCSCartCouplerSide bSide = BCSCommonUtility.DecodeCouplerSide(otherSideRaw); BCSCartRoot bCSCartRoot = BCSCartRegistry.FindById(otherCartId); if (!((Object)(object)bCSCartRoot == (Object)null) && !IsAnyCartInConnectedTrainRunning() && !bCSCartRoot.IsAnyCartInConnectedTrainRunning()) { if (!TryConnect(this, aSide, bCSCartRoot, bSide)) { LogWarn("RPC_ConnectCouplers TryConnect failed other=" + BCSCommonUtility.SafeString(otherCartId) + " mySide=" + aSide.ToString() + " otherSide=" + bSide); } else { UpdateConnectionVisualsImmediate(); bCSCartRoot.UpdateConnectionVisualsImmediate(); } } } public bool TryGetCouplerSideConnectedTo(string otherCartId, out BCSCartCouplerSide side) { side = BCSCartCouplerSide.Front; if (string.IsNullOrEmpty(otherCartId)) { return false; } if (GetFrontCartId() == otherCartId) { side = BCSCartCouplerSide.Front; return true; } if (GetBackCartId() == otherCartId) { side = BCSCartCouplerSide.Back; return true; } return false; } private bool OnUseEngineSwitch(Switch sw, Humanoid user, ItemData item) { Player val = (Player)(object)((user is Player) ? user : null); Log("OnUseEngineSwitch called. player=" + BCSCommonUtility.SafeName((Object)(object)val) + " switch=" + BCSCommonUtility.SafeName((Object)(object)sw)); if ((Object)(object)val == (Object)null) { LogWarn("OnUseEngineSwitch failed: player == null"); return false; } if ((Object)(object)_powerControls != (Object)null && _powerControls.TryHandleModifiedEngineUse(val, out var handled)) { return handled; } return RequestToggleTrain(val); } private string OnHoverFrontCoupler() { return BuildCouplerHoverText(BCSCartCouplerSide.Front); } public bool RequestAlignToCurrentRail(Player player) { if ((Object)(object)player == (Object)null || (Object)(object)_nview == (Object)null || !_nview.IsValid()) { return false; } _nview.InvokeRPC("RPC_AlignToCurrentRail", Array.Empty()); return true; } private void RPC_AlignToCurrentRail(long sender) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { AlignToCurrentRail(); UpdateConnectionVisualsImmediate(); TryAutoCoupleAfterManualPositionChange(); } } public bool RequestFlipDisconnected(Player player) { if ((Object)(object)player == (Object)null || (Object)(object)_nview == (Object)null || !_nview.IsValid()) { return false; } _nview.InvokeRPC("RPC_FlipDisconnected", Array.Empty()); return true; } private void RPC_FlipDisconnected(long sender) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner() && !IsAnyCartInConnectedTrainRunning()) { DisconnectAllCouplers(); FlipOnCurrentRail(); UpdateConnectionVisualsImmediate(); TryAutoCoupleAfterManualPositionChange(); } } public bool TryAutoCoupleAfterManualPositionChange() { if (!m_enableAutoCouple) { return false; } if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || _nview.GetZDO() == null) { return false; } if (!_nview.IsOwner()) { return false; } if (IsAnyCartInConnectedTrainRunning()) { return false; } return TryAutoCoupleAfterSpawn(); } private string OnHoverBackCoupler() { return BuildCouplerHoverText(BCSCartCouplerSide.Back); } private string OnHoverEngineSwitch() { string text = "Engine"; if (!IsPowered()) { text += "\nNo engine"; } else if (!CanBeDominantEngine()) { text += "\nEngine unavailable"; text += "\nCart must be at train end"; } else if (IsRunning() && GetConnectedTrainActiveEngineId() == GetCartId()) { text += "\n[$KEY_Use] Stop train"; } else { text += (ShouldMoveTowardFront() ? "\nDirection: Front" : "\nDirection: Back"); text += "\n[$KEY_Use] Start train"; } if ((Object)(object)_powerControls != (Object)null) { text += _powerControls.GetDriverHoverText(); } if (HasStoredItems() && (Object)(object)m_containerObject != (Object)null && !m_containerObject.activeSelf) { text += "\nStored cargo inside"; } return (Localization.instance != null) ? Localization.instance.Localize(text) : text; } private string BuildCouplerHoverText(BCSCartCouplerSide side) { bool flag = !IsSideFree(this, side); string text = ((side == BCSCartCouplerSide.Front) ? "Front coupler" : "Back coupler"); text = ((!flag) ? (text + "\n[$KEY_Use] Link cart") : (text + "\n[$KEY_Use] Unlink cart")); return (Localization.instance != null) ? Localization.instance.Localize(text) : text; } private bool TryDisconnectSide(BCSCartCouplerSide side) { string connectedCartId = GetConnectedCartId(side); if (string.IsNullOrEmpty(connectedCartId)) { return false; } BCSCartRoot bCSCartRoot = BCSCartRegistry.FindById(connectedCartId); ClaimOwnershipIfNeeded(); ClearSideLocal(side); if ((Object)(object)bCSCartRoot != (Object)null) { bCSCartRoot.ClaimOwnershipIfNeeded(); if (bCSCartRoot.GetFrontCartId() == GetCartId()) { bCSCartRoot.SetFrontCartId(string.Empty); } if (bCSCartRoot.GetBackCartId() == GetCartId()) { bCSCartRoot.SetBackCartId(string.Empty); } bCSCartRoot.UpdateConnectionVisualsImmediate(); } UpdateConnectionVisualsImmediate(); Log("Disconnected side=" + side.ToString() + " otherId=" + BCSCommonUtility.SafeString(connectedCartId)); return true; } private string GetConnectedCartId(BCSCartCouplerSide side) { return (side == BCSCartCouplerSide.Front) ? GetFrontCartId() : GetBackCartId(); } private void ClearSideLocal(BCSCartCouplerSide side) { if (side == BCSCartCouplerSide.Front) { SetFrontCartId(string.Empty); } else { SetBackCartId(string.Empty); } } public bool TryAutoCoupleAfterSpawn() { if (!m_enableAutoCouple) { return false; } if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || _nview.GetZDO() == null) { return false; } if (!_nview.IsOwner()) { return false; } if (IsAnyCartInConnectedTrainRunning()) { return false; } if (!TryFindNearestAutoCoupleCandidate(out var mySide, out var otherCart, out var otherSide)) { return false; } if ((Object)(object)otherCart == (Object)null) { return false; } string cartId = otherCart.GetCartId(); if (string.IsNullOrEmpty(cartId)) { return false; } if (otherCart.IsAnyCartInConnectedTrainRunning()) { return false; } _nview.InvokeRPC("RPC_ConnectCouplers", new object[3] { (int)mySide, cartId, (int)otherSide }); Log("TryAutoCoupleAfterSpawn requested via RPC mySide=" + mySide.ToString() + " other=" + BCSCommonUtility.SafeString(cartId) + " otherSide=" + otherSide); return true; } private bool TryFindNearestAutoCoupleCandidate(out BCSCartCouplerSide mySide, out BCSCartRoot otherCart, out BCSCartCouplerSide otherSide) { mySide = BCSCartCouplerSide.Front; otherCart = null; otherSide = BCSCartCouplerSide.Front; float num = Mathf.Max(0.01f, BCSCommonUtility.SanitizeFloat(m_autoCoupleRadius, 0.25f)); float bestSqrDistance = num * num; BCSCartRegistry.FillAll(_autoCoupleCandidatesScratch); for (int i = 0; i < _autoCoupleCandidatesScratch.Count; i++) { BCSCartRoot bCSCartRoot = _autoCoupleCandidatesScratch[i]; if (!((Object)(object)bCSCartRoot == (Object)null) && !((Object)(object)bCSCartRoot == (Object)(object)this) && ((Component)bCSCartRoot).gameObject.activeInHierarchy && !bCSCartRoot.IsAnyCartInConnectedTrainRunning() && CanAutoCoupleWithCandidate(bCSCartRoot)) { TryAutoCouplePair(bCSCartRoot, BCSCartCouplerSide.Front, BCSCartCouplerSide.Front, ref bestSqrDistance, ref mySide, ref otherCart, ref otherSide); TryAutoCouplePair(bCSCartRoot, BCSCartCouplerSide.Front, BCSCartCouplerSide.Back, ref bestSqrDistance, ref mySide, ref otherCart, ref otherSide); TryAutoCouplePair(bCSCartRoot, BCSCartCouplerSide.Back, BCSCartCouplerSide.Front, ref bestSqrDistance, ref mySide, ref otherCart, ref otherSide); TryAutoCouplePair(bCSCartRoot, BCSCartCouplerSide.Back, BCSCartCouplerSide.Back, ref bestSqrDistance, ref mySide, ref otherCart, ref otherSide); } } return (Object)(object)otherCart != (Object)null; } private bool CanAutoCoupleWithCandidate(BCSCartRoot candidate) { if ((Object)(object)candidate == (Object)null) { return false; } string currentRailId = GetCurrentRailId(); string currentRailId2 = candidate.GetCurrentRailId(); if (string.IsNullOrEmpty(currentRailId) || string.IsNullOrEmpty(currentRailId2)) { return false; } if (currentRailId == currentRailId2) { return true; } BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(currentRailId); if ((Object)(object)bCSRailPiece == (Object)null) { return false; } return bCSRailPiece.GetNeighborRailId(BCSRailNodeSide.A) == currentRailId2 || bCSRailPiece.GetNeighborRailId(BCSRailNodeSide.B) == currentRailId2 || bCSRailPiece.GetNeighborRailId(BCSRailNodeSide.C) == currentRailId2 || bCSRailPiece.GetNeighborRailId(BCSRailNodeSide.D) == currentRailId2; } private void TryAutoCouplePair(BCSCartRoot candidate, BCSCartCouplerSide thisSide, BCSCartCouplerSide candidateSide, ref float bestSqrDistance, ref BCSCartCouplerSide bestThisSide, ref BCSCartRoot bestOtherCart, ref BCSCartCouplerSide bestOtherSide) { //IL_0068: 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_0078: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)candidate == (Object)null || !IsSideFree(this, thisSide) || !IsSideFree(candidate, candidateSide)) { return; } Transform couplerPoint = GetCouplerPoint(thisSide); Transform couplerPoint2 = candidate.GetCouplerPoint(candidateSide); if (!((Object)(object)couplerPoint == (Object)null) && !((Object)(object)couplerPoint2 == (Object)null)) { Vector3 val = couplerPoint.position - couplerPoint2.position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (!(sqrMagnitude > bestSqrDistance) && !WouldCreateLoop(this, candidate)) { bestSqrDistance = sqrMagnitude; bestThisSide = thisSide; bestOtherCart = candidate; bestOtherSide = candidateSide; } } } public Transform GetCouplerPoint(BCSCartCouplerSide side) { return (side == BCSCartCouplerSide.Front) ? m_frontCouplerPoint : m_backCouplerPoint; } private static bool TryConnect(BCSCartRoot a, BCSCartCouplerSide aSide, BCSCartRoot b, BCSCartCouplerSide bSide) { if ((Object)(object)a == (Object)null || (Object)(object)b == (Object)null || (Object)(object)a == (Object)(object)b) { return false; } string cartId = a.GetCartId(); string cartId2 = b.GetCartId(); if (string.IsNullOrEmpty(cartId) || string.IsNullOrEmpty(cartId2)) { return false; } if (cartId == cartId2) { return false; } if (!IsSideFree(a, aSide) || !IsSideFree(b, bSide)) { return false; } if (WouldCreateLoop(a, b)) { return false; } a.ClaimOwnershipIfNeeded(); b.ClaimOwnershipIfNeeded(); if (aSide == BCSCartCouplerSide.Front) { a.SetFrontCartId(cartId2); } else { a.SetBackCartId(cartId2); } if (bSide == BCSCartCouplerSide.Front) { b.SetFrontCartId(cartId); } else { b.SetBackCartId(cartId); } return true; } private static bool IsSideFree(BCSCartRoot cart, BCSCartCouplerSide side) { if ((Object)(object)cart == (Object)null) { return false; } return (side == BCSCartCouplerSide.Front) ? (!cart.HasFrontConnection()) : (!cart.HasBackConnection()); } private static bool WouldCreateLoop(BCSCartRoot a, BCSCartRoot b) { if ((Object)(object)a == (Object)null || (Object)(object)b == (Object)null) { return true; } string cartId = b.GetCartId(); if (string.IsNullOrEmpty(cartId)) { return true; } HashSet hashSet = new HashSet(); Queue queue = new Queue(); queue.Enqueue(a); while (queue.Count > 0) { BCSCartRoot bCSCartRoot = queue.Dequeue(); if ((Object)(object)bCSCartRoot == (Object)null) { continue; } string cartId2 = bCSCartRoot.GetCartId(); if (!string.IsNullOrEmpty(cartId2) && !hashSet.Contains(cartId2)) { hashSet.Add(cartId2); if (cartId2 == cartId) { return true; } BCSCartRoot bCSCartRoot2 = BCSCartRegistry.FindById(bCSCartRoot.GetFrontCartId()); BCSCartRoot bCSCartRoot3 = BCSCartRegistry.FindById(bCSCartRoot.GetBackCartId()); if ((Object)(object)bCSCartRoot2 != (Object)null) { queue.Enqueue(bCSCartRoot2); } if ((Object)(object)bCSCartRoot3 != (Object)null) { queue.Enqueue(bCSCartRoot3); } } } return false; } private List BuildConnectedTrainChain() { SharedChainBuffer.Clear(); SharedVisited.Clear(); SharedQueue.Clear(); SharedQueue.Enqueue(this); while (SharedQueue.Count > 0) { BCSCartRoot bCSCartRoot = SharedQueue.Dequeue(); if ((Object)(object)bCSCartRoot == (Object)null) { continue; } string cartId = bCSCartRoot.GetCartId(); if (!string.IsNullOrEmpty(cartId) && SharedVisited.Add(cartId)) { SharedChainBuffer.Add(bCSCartRoot); BCSCartRoot bCSCartRoot2 = BCSCartRegistry.FindById(bCSCartRoot.GetFrontCartId()); if ((Object)(object)bCSCartRoot2 != (Object)null) { SharedQueue.Enqueue(bCSCartRoot2); } BCSCartRoot bCSCartRoot3 = BCSCartRegistry.FindById(bCSCartRoot.GetBackCartId()); if ((Object)(object)bCSCartRoot3 != (Object)null) { SharedQueue.Enqueue(bCSCartRoot3); } } } return SharedChainBuffer; } private bool IsAnyCartInConnectedTrainRunning() { List list = BuildConnectedTrainChain(); for (int i = 0; i < list.Count; i++) { BCSCartRoot bCSCartRoot = list[i]; if ((Object)(object)bCSCartRoot != (Object)null && bCSCartRoot.IsRunning()) { return true; } } return false; } private string GetConnectedTrainActiveEngineId() { List list = BuildConnectedTrainChain(); for (int i = 0; i < list.Count; i++) { BCSCartRoot bCSCartRoot = list[i]; if (!((Object)(object)bCSCartRoot == (Object)null)) { string activeEngineId = bCSCartRoot.GetActiveEngineId(); if (!string.IsNullOrEmpty(activeEngineId)) { return activeEngineId; } } } return string.Empty; } private void SetRunningForConnectedTrain(bool running, string activeEngineId) { List list = BuildConnectedTrainChain(); string text = activeEngineId ?? string.Empty; for (int i = 0; i < list.Count; i++) { BCSCartRoot bCSCartRoot = list[i]; if (!((Object)(object)bCSCartRoot == (Object)null)) { bCSCartRoot.SetRunningStateLocal(running, running ? text : string.Empty); } } } private void HandleJumpRiderEffects(string previousRailId, float previousDistance, bool previousTravelReversed, string currentRailId, float currentDistance, bool currentTravelReversed) { if (!m_enableJumpRiderEffects) { return; } if (!_jumpTrackerInitialized) { _jumpTrackerInitialized = true; _lastJumpRailId = currentRailId ?? string.Empty; _lastJumpDistance = BCSCommonUtility.SanitizeFloat(currentDistance, 0f); return; } BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(previousRailId); BCSRailPiece bCSRailPiece2 = BCSRailRegistry.FindById(currentRailId); bool flag = (Object)(object)bCSRailPiece != (Object)null && bCSRailPiece.IsJumpRail(); bool flag2 = (Object)(object)bCSRailPiece2 != (Object)null && bCSRailPiece2.IsJumpRail(); if (flag && (Object)(object)bCSRailPiece == (Object)(object)bCSRailPiece2) { float jumpLaunchDistance = bCSRailPiece2.GetJumpLaunchDistance(currentTravelReversed); if (CrossedDistance(previousDistance, currentDistance, jumpLaunchDistance)) { PlayJumpLaunchRiderEffects(); } float jumpLandingDistance = bCSRailPiece2.GetJumpLandingDistance(currentTravelReversed); if (CrossedDistance(previousDistance, currentDistance, jumpLandingDistance)) { PlayJumpLandRiderEffects(); } } else if (!flag && flag2) { float jumpLaunchDistance2 = bCSRailPiece2.GetJumpLaunchDistance(currentTravelReversed); if (CrossedDistance(previousDistance, currentDistance, jumpLaunchDistance2)) { PlayJumpLaunchRiderEffects(); } } else if (flag && !flag2) { PlayJumpLandRiderEffects(); } _lastJumpRailId = currentRailId ?? string.Empty; _lastJumpDistance = BCSCommonUtility.SanitizeFloat(currentDistance, 0f); } private bool CrossedDistance(float previous, float current, float marker) { previous = BCSCommonUtility.SanitizeFloat(previous, 0f); current = BCSCommonUtility.SanitizeFloat(current, 0f); marker = BCSCommonUtility.SanitizeFloat(marker, 0f); if (previous <= marker && current >= marker) { return true; } if (previous >= marker && current <= marker) { return true; } return false; } private void PlayJumpLaunchRiderEffects() { if (!(Time.time - _lastJumpLaunchEffectTime < Mathf.Max(0f, m_jumpEffectCooldown)) && IsLocalPlayerRidingThisCart()) { _lastJumpLaunchEffectTime = Time.time; CreateJumpRiderEffect(m_jumpLaunchRiderEffects); Log("Jump launch rider effects"); } } private void PlayJumpLandRiderEffects() { if (!(Time.time - _lastJumpLandEffectTime < Mathf.Max(0f, m_jumpEffectCooldown)) && IsLocalPlayerRidingThisCart()) { _lastJumpLandEffectTime = Time.time; CreateJumpRiderEffect(m_jumpLandRiderEffects); Log("Jump land rider effects"); } } private void CreateJumpRiderEffect(EffectList effects) { //IL_0040: 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_0013: 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) if (m_attachJumpRiderEffectsToCart) { effects.Create(((Component)this).transform.position, ((Component)this).transform.rotation, ((Component)this).transform, 1f, -1); } else { effects.Create(((Component)this).transform.position, ((Component)this).transform.rotation, (Transform)null, 1f, -1); } } private bool IsLocalPlayerRidingThisCart() { //IL_0067: 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) if ((Object)(object)Player.m_localPlayer == (Object)null) { return false; } if ((Object)(object)m_chair == (Object)null || (Object)(object)m_chair.m_attachPoint == (Object)null) { return false; } float num = Mathf.Max(0.05f, BCSCommonUtility.SanitizeFloat(m_jumpSeatDetectionRadius, 0.35f)); float num2 = Vector3.Distance(((Component)Player.m_localPlayer).transform.position, m_chair.m_attachPoint.position); return num2 <= num; } private void SetRunningStateLocal(bool running, string activeEngineId) { ZDO validZdo = GetValidZdo(); if (validZdo == null) { LogWarn("SetRunningStateLocal skipped: ZDO null"); return; } ClaimOwnershipIfNeeded(); validZdo.Set("hl_running", running); validZdo.Set("hl_active_engine_id", activeEngineId ?? string.Empty); if (running) { validZdo.Set("hl_travel_reversed_on_rail", GetDerivedTravelReversedOnRail()); } else { validZdo.Set("hl_halting", false); } UpdateVisualStateImmediate(); UpdateAnimationStateImmediate(); Log("SetRunningStateLocal running=" + running + " activeEngineId=" + BCSCommonUtility.SafeString(activeEngineId) + " movingObject=" + BCSCommonUtility.SafeName((Object)(object)m_isMovingObject) + " movingObjectActive=" + ((Object)(object)m_isMovingObject != (Object)null && m_isMovingObject.activeSelf)); } private void UpdateVisualState() { bool flag = CanBeDominantEngine(); bool flag2 = IsCartMoving(); bool flag3 = IsHalting(); bool flag4 = ShouldShowHaltingVisual(); if (flag != _lastPowerEnabledState || flag2 != _lastMovingState || flag3 != _lastHaltingState || flag4 != _lastHaltingVisualState) { UpdateVisualStateImmediate(); UpdateAnimationStateImmediate(); } } public bool HasStoredItems() { if ((Object)(object)m_container == (Object)null) { return false; } Inventory inventory = m_container.GetInventory(); if (inventory == null) { return false; } return inventory.NrOfItems() > 0; } private void UpdateVisualStateImmediate() { bool flag = CanBeDominantEngine(); bool flag2 = IsCartMoving(); bool lastHaltingState = IsHalting(); bool flag3 = ShouldShowHaltingVisual(); bool active = flag2 && !flag3; bool active2 = flag3; bool flag4 = !_movementStateInitialized || flag2 != _lastMovingState; _lastPowerEnabledState = flag; _lastMovingState = flag2; _lastHaltingState = lastHaltingState; _lastHaltingVisualState = flag3; if ((Object)(object)m_powerEnabledObject != (Object)null) { m_powerEnabledObject.SetActive(flag); } if ((Object)(object)m_powerDisabledObject != (Object)null) { m_powerDisabledObject.SetActive(!flag); } SetStateObjectActiveWithAudio(m_isMovingObject, active, forceLoopAudio: true); SetStateObjectActiveWithAudio(m_isHaltingObject, active2, forceLoopAudio: false); Log("VisualState moving=" + flag2 + " showMoving=" + active + " halting=" + lastHaltingState + " haltingVisual=" + flag3 + " movingObject=" + BCSCommonUtility.SafeName((Object)(object)m_isMovingObject) + " movingObjectActive=" + ((Object)(object)m_isMovingObject != (Object)null && m_isMovingObject.activeSelf) + " haltingObject=" + BCSCommonUtility.SafeName((Object)(object)m_isHaltingObject) + " haltingObjectActive=" + ((Object)(object)m_isHaltingObject != (Object)null && m_isHaltingObject.activeSelf) + " powerEnabled=" + flag); if (!_movementStateInitialized) { _movementStateInitialized = true; } else if (flag4) { if (flag2) { PlayMoveStartEffects(); } else { PlayMoveStopEffects(); } } } private void SetStateObjectActiveWithAudio(GameObject stateObject, bool active, bool forceLoopAudio) { if ((Object)(object)stateObject == (Object)null) { return; } if (stateObject.activeSelf != active) { stateObject.SetActive(active); } AudioSource[] array = null; if ((Object)(object)stateObject == (Object)(object)m_isMovingObject) { array = _movingAudioSources; } else if ((Object)(object)stateObject == (Object)(object)m_isHaltingObject) { array = _haltingAudioSources; } if (array == null) { array = stateObject.GetComponentsInChildren(true); } foreach (AudioSource val in array) { if ((Object)(object)val == (Object)null) { continue; } if (forceLoopAudio) { val.loop = true; } if (active) { if (!val.isPlaying) { val.Play(); } continue; } if (val.isPlaying) { val.Stop(); } val.time = 0f; } } private void PlayMoveStartEffects() { //IL_004a: 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_0018: 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) if (m_attachMoveEffectsToCart) { m_moveStartEffects.Create(((Component)this).transform.position, ((Component)this).transform.rotation, ((Component)this).transform, 1f, -1); } else { m_moveStartEffects.Create(((Component)this).transform.position, ((Component)this).transform.rotation, (Transform)null, 1f, -1); } Log("Move start effects played"); } private void PlayMoveStopEffects() { //IL_004a: 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_0018: 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) if (m_attachMoveEffectsToCart) { m_moveStopEffects.Create(((Component)this).transform.position, ((Component)this).transform.rotation, ((Component)this).transform, 1f, -1); } else { m_moveStopEffects.Create(((Component)this).transform.position, ((Component)this).transform.rotation, (Transform)null, 1f, -1); } Log("Move stop effects played"); } private void UpdateAnimationState() { CalculateWheelAnimationState(out var forward, out var backward, out var animSpeed); if (forward != _lastWheelForward || backward != _lastWheelBackward || Mathf.Abs(animSpeed - _lastAppliedWheelAnimSpeed) > 0.01f) { ApplyWheelAnimationState(forward, backward, animSpeed); } } private void UpdateConnectionVisualsIdleTick() { _connectionVisualIdleTimer += Time.deltaTime; if (!(_connectionVisualIdleTimer < 0.25f)) { _connectionVisualIdleTimer = 0f; UpdateConnectionVisuals(); } } private void UpdateAnimationStateImmediate() { CalculateWheelAnimationState(out var forward, out var backward, out var animSpeed); ApplyWheelAnimationState(forward, backward, animSpeed); } private bool IsCartMoving() { return IsRunning(); } private void CalculateWheelAnimationState(out bool forward, out bool backward, out float animSpeed) { bool flag = IsCartMoving(); bool flag2 = ShouldShowHaltingVisual(); forward = false; backward = false; animSpeed = 1f; if (flag && !flag2) { if (IsThisCartMovingForwardVisually()) { forward = true; backward = false; } else if (IsThisCartMovingBackwardVisually()) { forward = false; backward = true; } animSpeed = _currentWheelAnimSpeed; } } private void ApplyWheelAnimationState(bool forward, bool backward, float animSpeed) { //IL_00c9: Unknown result type (might be due to invalid IL or missing references) _lastWheelForward = forward; _lastWheelBackward = backward; _lastAppliedWheelAnimSpeed = animSpeed; if (m_wheelAnimators == null || m_wheelAnimators.Length == 0 || !IsCartMoving() || ShouldShowHaltingVisual()) { return; } float num = BCSCommonUtility.SanitizeFloat(_lastSignedLocalWheelMotion, 0f); if (Mathf.Abs(num) <= 1E-06f) { return; } float num2 = BCSCommonUtility.SanitizeFloat(m_wheelRotationDegreesPerMeter, 360f); float num3 = num * num2; for (int i = 0; i < m_wheelAnimators.Length; i++) { Transform val = m_wheelAnimators[i]; if (!((Object)(object)val == (Object)null) && ((Component)val).gameObject.activeInHierarchy) { val.Rotate(Vector3.right, num3, (Space)1); } } } private void InitializeWheelAnimationTracking() { //IL_000f: 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) _wheelDirectionInitialized = true; _lastWheelWorldPosition = ((Component)this).transform.position; _lastSignedLocalWheelMotion = 0f; _wheelSpeedInitialized = false; _lastWheelRailId = string.Empty; _lastDistanceOnRail = GetDistanceOnRail(); _currentWheelAnimSpeed = 1f; } private void UpdateWheelAnimationDirection() { //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_0036: 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_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_0044: 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_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_0075: Unknown result type (might be due to invalid IL or missing references) //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) //IL_007d: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)this).transform.position; if (!_wheelDirectionInitialized) { _wheelDirectionInitialized = true; _lastWheelWorldPosition = position; _lastSignedLocalWheelMotion = 0f; return; } Vector3 val = position - _lastWheelWorldPosition; _lastWheelWorldPosition = position; if (((Vector3)(ref val)).sqrMagnitude <= 1E-06f) { _lastSignedLocalWheelMotion = 0f; return; } Vector3 val2 = ((Component)this).transform.InverseTransformDirection(val); _lastSignedLocalWheelMotion = val2.z; } private bool IsThisCartMovingForwardVisually() { return _lastSignedLocalWheelMotion > 0.0001f; } private bool IsThisCartMovingBackwardVisually() { return _lastSignedLocalWheelMotion < -0.0001f; } private void UpdateWheelAnimationSpeed() { if (!IsCartMoving() || IsHalting()) { _wheelSpeedInitialized = false; _lastWheelRailId = string.Empty; _currentWheelAnimSpeed = Mathf.Lerp(_currentWheelAnimSpeed, 1f, Time.deltaTime * Mathf.Max(0.01f, m_wheelAnimationIdleReturnSpeed)); return; } string currentRailId = GetCurrentRailId(); float distanceOnRail = GetDistanceOnRail(); if (!_wheelSpeedInitialized || currentRailId != _lastWheelRailId) { _wheelSpeedInitialized = true; _lastWheelRailId = currentRailId; _lastDistanceOnRail = distanceOnRail; _currentWheelAnimSpeed = Mathf.Max(0.01f, m_minWheelAnimationSpeed); return; } float num = Mathf.Abs(distanceOnRail - _lastDistanceOnRail); _lastDistanceOnRail = distanceOnRail; float num2 = 0f; if (Time.deltaTime > 0.0001f) { num2 = num / Time.deltaTime; } float num3 = Mathf.Clamp(num2, Mathf.Max(0.01f, m_minWheelAnimationSpeed), Mathf.Max(m_minWheelAnimationSpeed, m_maxWheelAnimationSpeed)); _currentWheelAnimSpeed = Mathf.Lerp(_currentWheelAnimSpeed, num3, Time.deltaTime * Mathf.Max(0.01f, m_wheelAnimationSpeedResponse)); } private void UpdateConnectionVisuals() { UpdateConnectionVisualForSide(BCSCartCouplerSide.Front); UpdateConnectionVisualForSide(BCSCartCouplerSide.Back); } private void UpdateConnectionVisualsImmediate() { UpdateConnectionVisualForSide(BCSCartCouplerSide.Front); UpdateConnectionVisualForSide(BCSCartCouplerSide.Back); } private void UpdateConnectionVisualForSide(BCSCartCouplerSide side) { //IL_01d9: 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_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) GameObject val = ((side == BCSCartCouplerSide.Front) ? _frontConnectionEffect : _backConnectionEffect); string connectedCartId = GetConnectedCartId(side); if (string.IsNullOrEmpty(connectedCartId) || (Object)(object)m_connectionPrefab == (Object)null) { if (side == BCSCartCouplerSide.Front) { DestroyConnectionEffect(ref _frontConnectionEffect); } else { DestroyConnectionEffect(ref _backConnectionEffect); } return; } BCSCartRoot bCSCartRoot = BCSCartRegistry.FindById(connectedCartId); if ((Object)(object)bCSCartRoot == (Object)null || (Object)(object)bCSCartRoot == (Object)(object)this) { if (side == BCSCartCouplerSide.Front) { DestroyConnectionEffect(ref _frontConnectionEffect); } else { DestroyConnectionEffect(ref _backConnectionEffect); } return; } string cartId = GetCartId(); string cartId2 = bCSCartRoot.GetCartId(); if (string.IsNullOrEmpty(cartId) || string.IsNullOrEmpty(cartId2)) { if (side == BCSCartCouplerSide.Front) { DestroyConnectionEffect(ref _frontConnectionEffect); } else { DestroyConnectionEffect(ref _backConnectionEffect); } return; } if (string.CompareOrdinal(cartId, cartId2) > 0) { if (side == BCSCartCouplerSide.Front) { DestroyConnectionEffect(ref _frontConnectionEffect); } else { DestroyConnectionEffect(ref _backConnectionEffect); } return; } Transform val2 = ((side == BCSCartCouplerSide.Front) ? m_frontCouplerPoint : m_backCouplerPoint); Transform couplerPointConnectedTo = bCSCartRoot.GetCouplerPointConnectedTo(cartId); if ((Object)(object)val2 == (Object)null || (Object)(object)couplerPointConnectedTo == (Object)null) { if (side == BCSCartCouplerSide.Front) { DestroyConnectionEffect(ref _frontConnectionEffect); } else { DestroyConnectionEffect(ref _backConnectionEffect); } return; } GameObject val3 = val; if ((Object)(object)val3 == (Object)null) { val3 = Object.Instantiate(m_connectionPrefab); } Vector3 position = val2.position; Vector3 position2 = couplerPointConnectedTo.position; Vector3 val4 = position2 - position; if (((Vector3)(ref val4)).sqrMagnitude <= 0.0001f) { if (side == BCSCartCouplerSide.Front) { DestroyConnectionEffect(ref _frontConnectionEffect); } else { DestroyConnectionEffect(ref _backConnectionEffect); } return; } val3.transform.position = position; val3.transform.rotation = Quaternion.LookRotation(((Vector3)(ref val4)).normalized); val3.transform.localScale = new Vector3(BCSCommonUtility.SanitizeFloat(m_connectionEffectScale.x, 1f), BCSCommonUtility.SanitizeFloat(m_connectionEffectScale.y, 1f), ((Vector3)(ref val4)).magnitude * BCSCommonUtility.SanitizeFloat(m_connectionEffectScale.z, 1f)); if (side == BCSCartCouplerSide.Front) { _frontConnectionEffect = val3; } else { _backConnectionEffect = val3; } } private void CacheStateAudioSources() { _movingAudioSources = (AudioSource[])(((Object)(object)m_isMovingObject != (Object)null) ? ((Array)m_isMovingObject.GetComponentsInChildren(true)) : ((Array)new AudioSource[0])); _haltingAudioSources = (AudioSource[])(((Object)(object)m_isHaltingObject != (Object)null) ? ((Array)m_isHaltingObject.GetComponentsInChildren(true)) : ((Array)new AudioSource[0])); } private Transform GetCouplerPointConnectedTo(string otherCartId) { if (string.IsNullOrEmpty(otherCartId)) { return null; } if (GetFrontCartId() == otherCartId) { return m_frontCouplerPoint; } if (GetBackCartId() == otherCartId) { return m_backCouplerPoint; } return null; } private bool ShouldShowHaltingVisual() { return IsHalting() || Time.time < _haltingVisualUntil; } private void TriggerHaltingVisual() { //IL_007b: 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_0049: 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) _haltingVisualUntil = Mathf.Max(_haltingVisualUntil, Time.time + Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_minHaltingVisualDuration, 1.25f))); if (m_attachMoveEffectsToCart) { m_haltingStartEffects.Create(((Component)this).transform.position, ((Component)this).transform.rotation, ((Component)this).transform, 1f, -1); } else { m_haltingStartEffects.Create(((Component)this).transform.position, ((Component)this).transform.rotation, (Transform)null, 1f, -1); } } private void DestroyConnectionEffect(ref GameObject effect) { if ((Object)(object)effect != (Object)null) { Object.Destroy((Object)(object)effect); effect = null; } } private void EnsureCartId() { ZDO validZdo = GetValidZdo(); if (validZdo == null) { if (string.IsNullOrEmpty(_cachedCartId)) { _cachedCartId = Guid.NewGuid().ToString("N"); } return; } ClaimOwnershipIfNeeded(); string text = validZdo.GetString("hl_cart_id", string.Empty); if (string.IsNullOrEmpty(text)) { text = Guid.NewGuid().ToString("N"); validZdo.Set("hl_cart_id", text); } validZdo.Set("hl_cart_type", (int)m_cartType); validZdo.Set("hl_halting", validZdo.GetBool("hl_halting", false)); _cachedCartId = text; } private void ClaimOwnershipIfNeeded() { BCSCommonUtility.ClaimOwnershipIfNeeded(_nview); } private ZDO GetValidZdo() { return BCSCommonUtility.GetValidZdo(_nview); } private static void ClearNeighborLink(string otherId, string myId) { if (string.IsNullOrEmpty(otherId) || string.IsNullOrEmpty(myId)) { return; } BCSCartRoot bCSCartRoot = BCSCartRegistry.FindById(otherId); if (!((Object)(object)bCSCartRoot == (Object)null)) { bCSCartRoot.ClaimOwnershipIfNeeded(); if (bCSCartRoot.GetFrontCartId() == myId) { bCSCartRoot.SetFrontCartId(string.Empty); } if (bCSCartRoot.GetBackCartId() == myId) { bCSCartRoot.SetBackCartId(string.Empty); } bCSCartRoot.UpdateConnectionVisualsImmediate(); } } private void ConfigureChairForMovingCart() { if (!((Object)(object)m_chair == (Object)null)) { if ((Object)(object)m_chair.m_attachPoint == (Object)null) { m_chair.m_attachPoint = ((Component)m_chair).transform; } m_chair.m_inShip = true; m_chair.m_attachAnimation = "emote_sit"; if (m_chair.m_useDistance <= 0.1f) { m_chair.m_useDistance = 3f; } } } private void Log(string msg) { if (m_enableDebugLogs) { Debug.Log((object)("[BCSCartRoot][" + ((Object)((Component)this).gameObject).name + "][" + BCSCommonUtility.SafeString(GetCartId()) + "] " + msg)); } } private void LogWarn(string msg) { if (m_enableDebugLogs) { Debug.LogWarning((object)("[BCSCartRoot][" + ((Object)((Component)this).gameObject).name + "][" + BCSCommonUtility.SafeString(GetCartId()) + "] " + msg)); } } } public class BCSCartRunDamage : MonoBehaviour { public BCSCartRoot m_cart; public BCSTrainRuntime m_runtime; [Header("Damage Object")] public GameObject m_runDamageObject; public string m_runDamageObjectName = "RunHitDamage"; public bool m_attachToLeadingCoupler = true; [Header("Activation")] public float m_speedThreshold = 6f; public float m_fullDamageSpeed = 16f; private float _nextActiveCheckTime; private bool _cachedActive; [Header("Damage Scaling")] public float m_minDamageMultiplierAtThreshold = 0.75f; public float m_maxDamageMultiplierAtFullSpeed = 2f; public float m_extraDamageMultiplierPerAttachedCart = 0.25f; public float m_maxAttachedCartDamageBonus = 1f; [Header("Force Scaling")] public float m_minForceMultiplierAtThreshold = 1f; public float m_maxForceMultiplierAtFullSpeed = 3f; public float m_extraForceMultiplierPerAttachedCart = 0.35f; public float m_maxAttachedCartForceBonus = 1.5f; [Header("Performance")] public float m_damageRefreshInterval = 0.15f; public float m_attachedCartRefreshInterval = 0.5f; private float _nextDamageRefreshTime; private float _nextAttachedCartRefreshTime; private int _cachedAttachedCartCount; private readonly List _connectedCartScratch = new List(); private readonly Queue _connectedCartQueue = new Queue(); private readonly HashSet _connectedCartVisited = new HashSet(); private ZNetView _nview; private Aoe _aoe; private BoxCollider _boxCollider; private DamageTypes _baseDamage; private float _baseAttackForce; private bool _hasBaseAoeValues; private Vector3 _lastPosition; private bool _speedInitialized; private float _measuredSpeed; private void Awake() { //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0220: 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_011e: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_cart == (Object)null) { m_cart = ((Component)this).GetComponent(); } if ((Object)(object)m_runtime == (Object)null) { m_runtime = ((Component)this).GetComponent(); } _nview = (((Object)(object)m_cart != (Object)null) ? m_cart.GetNetView() : ((Component)this).GetComponent()); if ((Object)(object)m_runDamageObject == (Object)null) { Transform val = ((Component)this).transform.Find(m_runDamageObjectName); if ((Object)(object)val != (Object)null) { m_runDamageObject = ((Component)val).gameObject; } } if ((Object)(object)m_runDamageObject != (Object)null) { _aoe = m_runDamageObject.GetComponent(); _boxCollider = m_runDamageObject.GetComponent(); if ((Object)(object)_boxCollider != (Object)null) { ((Collider)_boxCollider).isTrigger = true; } if ((Object)(object)_aoe != (Object)null) { _baseDamage = _aoe.m_damage; _baseAttackForce = _aoe.m_attackForce; _hasBaseAoeValues = true; _aoe.m_useTriggers = true; _aoe.m_triggerEnterOnly = true; _aoe.m_hitOnEnable = false; _aoe.m_hitInterval = 0.15f; _aoe.m_activationDelay = 0f; _aoe.m_hitCharacters = true; _aoe.m_hitProps = true; _aoe.m_hitTerrain = false; _aoe.m_hitOwner = false; _aoe.m_hitParent = false; _aoe.m_hitSame = true; _aoe.m_hitFriendly = true; _aoe.m_hitEnemy = true; _aoe.m_attackForceForward = true; _aoe.Setup((Character)null, Vector3.zero, 0f, (HitData)null, (ItemData)null, (ItemData)null); } m_runDamageObject.SetActive(false); } _lastPosition = ((Component)this).transform.position; _speedInitialized = false; } private void Update() { if ((Object)(object)m_runDamageObject == (Object)null) { return; } UpdateMeasuredSpeed(); if (Time.time >= _nextActiveCheckTime) { _nextActiveCheckTime = Time.time + Mathf.Max(0.05f, m_damageRefreshInterval); _cachedActive = ShouldEnableRunDamage(); BCSCommonUtility.SetActiveIfChanged(m_runDamageObject, _cachedActive); if (_cachedActive) { UpdateAoeDamageAndForce(); } } if (_cachedActive) { UpdateDamageObjectTransform(); } } private void UpdateMeasuredSpeed() { //IL_0066: 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_0054: 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_00a8: 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_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: 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_0084: 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)m_runtime != (Object)null) { return; } if ((Object)(object)m_cart != (Object)null && !m_cart.IsRunning()) { _speedInitialized = false; _measuredSpeed = 0f; _lastPosition = ((Component)this).transform.position; return; } Vector3 position = ((Component)this).transform.position; if (!_speedInitialized) { _speedInitialized = true; _lastPosition = position; _measuredSpeed = 0f; } else { float num = Mathf.Max(0.0001f, Time.deltaTime); Vector3 val = position - _lastPosition; _measuredSpeed = ((Vector3)(ref val)).magnitude / num; _lastPosition = position; } } private bool ShouldEnableRunDamage() { if ((Object)(object)m_cart == (Object)null || (Object)(object)m_runDamageObject == (Object)null || (Object)(object)_aoe == (Object)null) { return false; } if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner()) { return false; } if (!m_cart.IsPowered()) { return false; } if (!m_cart.IsRunning()) { return false; } if (!m_cart.CanBeDominantEngine()) { return false; } string cartId = m_cart.GetCartId(); if (string.IsNullOrEmpty(cartId)) { return false; } if (m_cart.GetActiveEngineId() != cartId) { return false; } return GetCurrentSpeed() >= Mathf.Max(0f, m_speedThreshold); } private float GetCurrentSpeed() { if ((Object)(object)m_runtime != (Object)null) { return Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_runtime.m_currentSpeed, 0f)); } return Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(_measuredSpeed, 0f)); } private void UpdateDamageObjectTransform() { //IL_0089: 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_008e: 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_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: 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) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) if (m_attachToLeadingCoupler && !((Object)(object)m_cart == (Object)null) && !((Object)(object)m_runDamageObject == (Object)null)) { bool flag = m_cart.ShouldMoveTowardFront(); Transform val = (flag ? m_cart.m_frontCouplerPoint : m_cart.m_backCouplerPoint); if ((Object)(object)val == (Object)null) { val = ((Component)this).transform; } Vector3 val2 = (flag ? ((Component)this).transform.forward : (-((Component)this).transform.forward)); if (((Vector3)(ref val2)).sqrMagnitude <= 0.0001f) { val2 = ((Component)this).transform.forward; } m_runDamageObject.transform.position = val.position; m_runDamageObject.transform.rotation = Quaternion.LookRotation(((Vector3)(ref val2)).normalized, ((Component)this).transform.up); } } private void UpdateAoeDamageAndForce() { //IL_00c1: 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_00d8: 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) if (!((Object)(object)_aoe == (Object)null) && _hasBaseAoeValues) { float currentSpeed = GetCurrentSpeed(); float num = Mathf.InverseLerp(Mathf.Max(0f, m_speedThreshold), Mathf.Max(m_speedThreshold + 0.01f, m_fullDamageSpeed), currentSpeed); int cachedAttachedCartCount = GetCachedAttachedCartCount(); float num2 = Mathf.Lerp(Mathf.Max(0f, m_minDamageMultiplierAtThreshold), Mathf.Max(0f, m_maxDamageMultiplierAtFullSpeed), num); float num3 = Mathf.Min((float)cachedAttachedCartCount * Mathf.Max(0f, m_extraDamageMultiplierPerAttachedCart), Mathf.Max(0f, m_maxAttachedCartDamageBonus)); float num4 = num2 * (1f + num3); DamageTypes baseDamage = _baseDamage; ((DamageTypes)(ref baseDamage)).Modify(num4); _aoe.m_damage = baseDamage; float num5 = Mathf.Lerp(Mathf.Max(0f, m_minForceMultiplierAtThreshold), Mathf.Max(0f, m_maxForceMultiplierAtFullSpeed), num); float num6 = Mathf.Min((float)cachedAttachedCartCount * Mathf.Max(0f, m_extraForceMultiplierPerAttachedCart), Mathf.Max(0f, m_maxAttachedCartForceBonus)); float num7 = num5 * (1f + num6); _aoe.m_attackForce = Mathf.Max(0f, _baseAttackForce * num7); } } private int GetCachedAttachedCartCount() { if (Time.time < _nextAttachedCartRefreshTime) { return _cachedAttachedCartCount; } _nextAttachedCartRefreshTime = Time.time + Mathf.Max(0.05f, m_attachedCartRefreshInterval); _cachedAttachedCartCount = BCSCommonUtility.CountConnectedCartsExcludingRoot(m_cart, _connectedCartScratch, _connectedCartQueue, _connectedCartVisited); return _cachedAttachedCartCount; } } public static class BCSCommonUtility { public static float SanitizeFloat(float value, float fallback) { return (float.IsNaN(value) || float.IsInfinity(value)) ? fallback : value; } public static string SafeString(string value) { return string.IsNullOrEmpty(value) ? "" : value; } public static string SafeName(Object obj) { return (obj != (Object)null) ? obj.name : ""; } public static string SafeTransformName(Transform t) { return ((Object)(object)t != (Object)null) ? ((Object)t).name : ""; } public static BCSCartCouplerSide DecodeCouplerSide(int raw) { return (raw == 1) ? BCSCartCouplerSide.Back : BCSCartCouplerSide.Front; } public static bool IsPlayerUsingChair(Chair chair, Player player, float radius = 0.35f) { //IL_0043: 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 ((Object)(object)chair == (Object)null || (Object)(object)player == (Object)null || (Object)(object)chair.m_attachPoint == (Object)null) { return false; } if (!((Character)player).IsAttached()) { return false; } return Vector3.Distance(((Component)player).transform.position, chair.m_attachPoint.position) <= Mathf.Max(0.01f, radius); } public static int GetIgnoredLayersMask(string[] layerNames) { int num = 0; if (layerNames == null) { return num; } for (int i = 0; i < layerNames.Length; i++) { int num2 = LayerMask.NameToLayer(layerNames[i]); if (num2 >= 0) { num |= 1 << num2; } } return num; } public static bool IsPlayerAttachedToChair(Player player, Chair chair, float maxDistance) { //IL_0043: 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 ((Object)(object)player == (Object)null || (Object)(object)chair == (Object)null || (Object)(object)chair.m_attachPoint == (Object)null) { return false; } if (!((Character)player).IsAttached()) { return false; } float num = Vector3.Distance(((Component)player).transform.position, chair.m_attachPoint.position); return num <= Mathf.Max(0.01f, maxDistance); } public static bool IsLocalPlayerAttachedToChair(Chair chair, float maxDistance) { return IsPlayerAttachedToChair(Player.m_localPlayer, chair, maxDistance); } public static void BuildConnectedCartGraph(BCSCartRoot root, List result, Queue queue, HashSet visited) { result.Clear(); queue.Clear(); visited.Clear(); if ((Object)(object)root == (Object)null) { return; } queue.Enqueue(root); while (queue.Count > 0) { BCSCartRoot bCSCartRoot = queue.Dequeue(); if ((Object)(object)bCSCartRoot == (Object)null) { continue; } string cartId = bCSCartRoot.GetCartId(); if (!string.IsNullOrEmpty(cartId) && visited.Add(cartId)) { result.Add(bCSCartRoot); BCSCartRoot bCSCartRoot2 = BCSCartRegistry.FindById(bCSCartRoot.GetFrontCartId()); BCSCartRoot bCSCartRoot3 = BCSCartRegistry.FindById(bCSCartRoot.GetBackCartId()); if ((Object)(object)bCSCartRoot2 != (Object)null) { queue.Enqueue(bCSCartRoot2); } if ((Object)(object)bCSCartRoot3 != (Object)null) { queue.Enqueue(bCSCartRoot3); } } } } public static int CountConnectedCartsExcludingRoot(BCSCartRoot root, List result, Queue queue, HashSet visited) { BuildConnectedCartGraph(root, result, queue, visited); if ((Object)(object)root == (Object)null) { return 0; } string cartId = root.GetCartId(); int num = 0; for (int i = 0; i < result.Count; i++) { BCSCartRoot bCSCartRoot = result[i]; if (!((Object)(object)bCSCartRoot == (Object)null) && bCSCartRoot.GetCartId() != cartId) { num++; } } return num; } public static bool HasObstacleStopComponent(Collider hit) { if ((Object)(object)hit == (Object)null) { return false; } return (Object)(object)((Component)hit).GetComponentInParent() != (Object)null || (Object)(object)((Component)hit).GetComponentInParent() != (Object)null || (Object)(object)((Component)hit).GetComponentInParent() != (Object)null || (Object)(object)((Component)hit).GetComponentInParent() != (Object)null || (Object)(object)((Component)hit).GetComponentInParent() != (Object)null; } public static double GetNetworkTimeSeconds() { if ((Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.GetTimeSeconds(); } return Time.time; } public static float GetNetworkTimeSecondsFloat() { return (float)GetNetworkTimeSeconds(); } public static bool MatchesName(string a, string b) { if (string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b)) { return false; } return string.Equals(a, b, StringComparison.Ordinal); } public static ZDO GetValidZdo(ZNetView nview) { if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return null; } return nview.GetZDO(); } public static bool IsOwnerSafe(ZNetView nview) { return (Object)(object)nview != (Object)null && nview.IsValid() && nview.IsOwner(); } public static void ClaimOwnershipIfNeeded(ZNetView nview) { if (!((Object)(object)nview == (Object)null) && nview.IsValid() && !nview.IsOwner()) { nview.ClaimOwnership(); } } public static bool IsPlacementGhostSafe(GameObject gameObject) { try { return Player.IsPlacementGhost(gameObject); } catch { return false; } } public static void SetActiveIfChanged(GameObject target, bool active) { if ((Object)(object)target != (Object)null && target.activeSelf != active) { target.SetActive(active); } } } public class BCSPowerCartControls : MonoBehaviour { private static readonly HashSet ActiveControls = new HashSet(); public BCSCartRoot m_cart; public BCSTrainRuntime m_runtime; [Header("Input")] public KeyCode m_modifierSwitch = (KeyCode)304; public KeyCode m_modifierCamera = (KeyCode)308; [Header("Remote Switch")] public float m_switchSearchRadius = 5f; public EffectList m_switchToggleEffects = new EffectList(); public float m_switchProbeStep = 0.5f; public bool m_allowToggleCurrentSwitch = true; [Header("Driver View")] public BCSDriverCameraMode m_cameraMode = BCSDriverCameraMode.Off; public float m_driverViewSmoothTime = 0.12f; [Header("Driver View Presets")] public float m_firstPersonDistance = 0f; public Vector3 m_firstPersonOffset = new Vector3(0f, -0.01f, 0.1f); public float m_shoulderDistance = 0.25f; public Vector3 m_shoulderRightOffset = new Vector3(0.25f, 0.05f, 0f); public Vector3 m_shoulderLeftOffset = new Vector3(-0.25f, 0.05f, 0f); public float m_closeFollowDistance = 0.5f; public Vector3 m_closeFollowOffset = new Vector3(0f, 0.03f, -1f); [Header("Driver View Rotation Lock")] public bool m_firstPersonLockYawToPlayerForward = true; public bool m_shoulderRightLockYawToPlayerForward = false; public bool m_shoulderLeftLockYawToPlayerForward = false; public bool m_closeFollowLockYawToPlayerForward = true; [Header("Debug")] public bool m_enableDebugLogs = false; private static BCSPowerCartControls _cachedLocalDrivingControl; private static float _nextLocalDrivingScanTime; private const float LocalDrivingScanInterval = 0.2f; private void Awake() { if ((Object)(object)m_cart == (Object)null) { m_cart = ((Component)this).GetComponent(); } if ((Object)(object)m_runtime == (Object)null) { m_runtime = ((Component)this).GetComponent(); } } private void OnEnable() { ActiveControls.Add(this); } private void OnDisable() { ActiveControls.Remove(this); if ((Object)(object)_cachedLocalDrivingControl == (Object)(object)this) { _cachedLocalDrivingControl = null; _nextLocalDrivingScanTime = 0f; } m_cameraMode = BCSDriverCameraMode.Off; } public static bool ShouldLockLocalPlayerCamera() { return (Object)(object)GetLocalDrivingCameraLockControl() != (Object)null; } public static BCSPowerCartControls GetLocalDrivingCameraLockControl() { if ((Object)(object)_cachedLocalDrivingControl != (Object)null) { if (_cachedLocalDrivingControl.m_cameraMode != 0 && _cachedLocalDrivingControl.IsLocalPlayerDrivingThisCart()) { return _cachedLocalDrivingControl; } _cachedLocalDrivingControl.m_cameraMode = BCSDriverCameraMode.Off; _cachedLocalDrivingControl = null; } if (Time.time < _nextLocalDrivingScanTime) { return null; } _nextLocalDrivingScanTime = Time.time + 0.2f; foreach (BCSPowerCartControls activeControl in ActiveControls) { if (!((Object)(object)activeControl == (Object)null) && activeControl.m_cameraMode != 0) { if (activeControl.IsLocalPlayerDrivingThisCart()) { _cachedLocalDrivingControl = activeControl; return activeControl; } activeControl.m_cameraMode = BCSDriverCameraMode.Off; } } return null; } public bool IsLocalPlayerDrivingThisCart() { if ((Object)(object)m_cart == (Object)null || !m_cart.IsPowered()) { return false; } if ((Object)(object)Player.m_localPlayer == (Object)null) { return false; } return BCSCommonUtility.IsPlayerUsingChair(m_cart.m_chair, Player.m_localPlayer); } public string GetDriverHoverText() { //IL_0036: 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) if (!IsLocalPlayerDrivingThisCart()) { return string.Empty; } bool flag = CanUseLeadingCartActions(); string text = ""; text = ((!flag) ? (text + "\nSwitch control unavailable: passenger cart") : (text + "\n[" + GetKeyLabel(m_modifierSwitch) + "+$KEY_Use] Toggle switch/bridge ahead")); return text + "\n[" + GetKeyLabel(m_modifierCamera) + "+$KEY_Use] Camera: " + m_cameraMode; } public bool TryGetDriverViewCameraPose(out Vector3 position, out Quaternion rotation) { //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_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_00c5: 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_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_00cd: 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_00d4: 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_00db: 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_00e7: 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_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: 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_0104: 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_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) //IL_0118: 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_0123: 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_012c: 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_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: 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_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: 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_014d: Unknown result type (might be due to invalid IL or missing references) position = Vector3.zero; rotation = Quaternion.identity; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)((Character)localPlayer).m_eye == (Object)null) { return false; } if (m_cameraMode == BCSDriverCameraMode.Off) { return false; } Transform transform = ((Component)((Character)localPlayer).m_eye).transform; if (!TryGetCameraPreset(m_cameraMode, out var distance, out var offset)) { return false; } distance = Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(distance, 0.35f)); Quaternion val = ((!ShouldLockCameraYawToPlayerForward(m_cameraMode)) ? transform.rotation : GetCameraRotationWithPlayerYawAndEyePitch(localPlayer, transform)); Vector3 val2 = val * Vector3.right; Vector3 val3 = val * Vector3.up; Vector3 val4 = val * Vector3.forward; Vector3 val5 = val2 * offset.x + val3 * offset.y + val4 * offset.z; position = transform.position + val5 - val4 * distance; rotation = val; return true; } private bool TryGetCameraPreset(BCSDriverCameraMode mode, out float distance, out Vector3 offset) { //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_003b: 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_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_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_0083: 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) distance = 0f; offset = Vector3.zero; switch (mode) { case BCSDriverCameraMode.FirstPerson: distance = m_firstPersonDistance; offset = m_firstPersonOffset; return true; case BCSDriverCameraMode.ShoulderRight: distance = m_shoulderDistance; offset = m_shoulderRightOffset; return true; case BCSDriverCameraMode.ShoulderLeft: distance = m_shoulderDistance; offset = m_shoulderLeftOffset; return true; case BCSDriverCameraMode.CloseFollow: distance = m_closeFollowDistance; offset = m_closeFollowOffset; return true; default: return false; } } private static string GetKeyLabel(KeyCode key) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Invalid comparison between Unknown and I4 //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Invalid comparison between Unknown and I4 //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Invalid comparison between Unknown and I4 if ((int)key == 308 || (int)key == 307) { return "Alt"; } if ((int)key == 304 || (int)key == 303) { return "Shift"; } if ((int)key == 306 || (int)key == 305) { return "Ctrl"; } return ((object)(KeyCode)(ref key)).ToString(); } private bool CanUseLeadingCartActions() { if ((Object)(object)m_cart == (Object)null) { return false; } if (!m_cart.IsPowered()) { return false; } if ((Object)(object)m_cart.m_containerObject != (Object)null && m_cart.m_containerObject.activeSelf) { return false; } if (!m_cart.CanBeDominantEngine()) { return false; } string cartId = m_cart.GetCartId(); if (string.IsNullOrEmpty(cartId)) { return false; } string activeEngineId = m_cart.GetActiveEngineId(); if (!string.IsNullOrEmpty(activeEngineId) && activeEngineId != cartId) { return false; } return true; } private bool ShouldLockCameraYawToPlayerForward(BCSDriverCameraMode mode) { return mode switch { BCSDriverCameraMode.FirstPerson => m_firstPersonLockYawToPlayerForward, BCSDriverCameraMode.ShoulderRight => m_shoulderRightLockYawToPlayerForward, BCSDriverCameraMode.ShoulderLeft => m_shoulderLeftLockYawToPlayerForward, BCSDriverCameraMode.CloseFollow => m_closeFollowLockYawToPlayerForward, _ => false, }; } private static Quaternion GetCameraRotationWithPlayerYawAndEyePitch(Player player, Transform eye) { //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_000a: 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_0025: 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_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_0042: Unknown result type (might be due to invalid IL or missing references) Quaternion rotation = eye.rotation; float num = NormalizeEulerAngle(((Quaternion)(ref rotation)).eulerAngles.x); rotation = ((Component)player).transform.rotation; float y = ((Quaternion)(ref rotation)).eulerAngles.y; return Quaternion.Euler(num, y, 0f); } private static float NormalizeEulerAngle(float angle) { if (angle > 180f) { angle -= 360f; } return angle; } private void ToggleSwitchAhead(Player player) { //IL_009d: 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_0191: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) if (!TryFindControllableRailAhead(out var foundRail)) { if ((Object)(object)player != (Object)null) { ((Character)player).Message((MessageType)2, "No switch or bridge ahead", 0, (Sprite)null); } Log("ToggleSwitchAhead: no switch/bridge found"); return; } if (foundRail.IsSwitchRail()) { if (!foundRail.ToggleSwitchFromCart()) { if ((Object)(object)player != (Object)null) { ((Character)player).Message((MessageType)2, "Switch unavailable", 0, (Sprite)null); } return; } if (m_switchToggleEffects != null) { m_switchToggleEffects.Create(((Component)foundRail).transform.position, ((Component)foundRail).transform.rotation, (Transform)null, 1f, -1); } if ((Object)(object)player != (Object)null) { ((Character)player).Message((MessageType)2, "Switch toggled", 0, (Sprite)null); } Log("Switch toggled: " + ((Object)foundRail).name); return; } BCSDrawbridgeRail bCSDrawbridgeRail = ((Component)foundRail).GetComponent(); if ((Object)(object)bCSDrawbridgeRail == (Object)null) { bCSDrawbridgeRail = ((Component)foundRail).GetComponentInChildren(true); } if ((Object)(object)bCSDrawbridgeRail == (Object)null) { if ((Object)(object)player != (Object)null) { ((Character)player).Message((MessageType)2, "Bridge unavailable", 0, (Sprite)null); } return; } if (!bCSDrawbridgeRail.TryInteract(player)) { if ((Object)(object)player != (Object)null) { ((Character)player).Message((MessageType)2, "Bridge unavailable", 0, (Sprite)null); } return; } if (m_switchToggleEffects != null) { m_switchToggleEffects.Create(((Component)foundRail).transform.position, ((Component)foundRail).transform.rotation, (Transform)null, 1f, -1); } if ((Object)(object)player != (Object)null) { ((Character)player).Message((MessageType)2, "Bridge toggled", 0, (Sprite)null); } Log("Bridge toggled: " + ((Object)foundRail).name); } private bool TryFindControllableRailAhead(out BCSRailPiece foundRail) { foundRail = null; if ((Object)(object)m_cart == (Object)null) { return false; } string currentRailId = m_cart.GetCurrentRailId(); if (string.IsNullOrEmpty(currentRailId)) { return false; } float distanceOnRail = m_cart.GetDistanceOnRail(); bool travelReversedOnRail = m_cart.GetTravelReversedOnRail(); BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(currentRailId); if ((Object)(object)bCSRailPiece == (Object)null) { return false; } if (m_allowToggleCurrentSwitch && IsControllableRail(bCSRailPiece)) { foundRail = bCSRailPiece; return true; } float leadingOffsetFromCenter = GetLeadingOffsetFromCenter(); float num = Mathf.Max(0.1f, BCSCommonUtility.SanitizeFloat(m_switchSearchRadius, 5f)); float num2 = Mathf.Max(0.05f, BCSCommonUtility.SanitizeFloat(m_switchProbeStep, 0.5f)); string text = currentRailId; for (float num3 = Mathf.Max(0f, leadingOffsetFromCenter); num3 <= leadingOffsetFromCenter + num; num3 += num2) { if (!BCSRailTraversalUtility.TryGetPoseAtOffset(currentRailId, distanceOnRail, travelReversedOnRail, num3, out var outRailId, out var _, out var _, out var _)) { return false; } if (!string.IsNullOrEmpty(outRailId) && !(outRailId == text)) { text = outRailId; BCSRailPiece bCSRailPiece2 = BCSRailRegistry.FindById(outRailId); if (!((Object)(object)bCSRailPiece2 == (Object)null) && IsControllableRail(bCSRailPiece2)) { foundRail = bCSRailPiece2; return true; } } } return false; } private bool TryFindSwitchAheadOnRailPath(out BCSRailPiece switchRail) { switchRail = null; if ((Object)(object)m_cart == (Object)null) { return false; } string currentRailId = m_cart.GetCurrentRailId(); if (string.IsNullOrEmpty(currentRailId)) { return false; } float distanceOnRail = m_cart.GetDistanceOnRail(); bool travelReversedOnRail = m_cart.GetTravelReversedOnRail(); BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(currentRailId); if ((Object)(object)bCSRailPiece == (Object)null) { return false; } if (m_allowToggleCurrentSwitch && bCSRailPiece.IsSwitchRail()) { switchRail = bCSRailPiece; return true; } float leadingOffsetFromCenter = GetLeadingOffsetFromCenter(); float num = Mathf.Max(0.1f, BCSCommonUtility.SanitizeFloat(m_switchSearchRadius, 5f)); float num2 = Mathf.Max(0.05f, BCSCommonUtility.SanitizeFloat(m_switchProbeStep, 0.5f)); string text = currentRailId; for (float num3 = Mathf.Max(0f, leadingOffsetFromCenter); num3 <= leadingOffsetFromCenter + num; num3 += num2) { if (!BCSRailTraversalUtility.TryGetPoseAtOffset(currentRailId, distanceOnRail, travelReversedOnRail, num3, out var outRailId, out var _, out var _, out var _)) { return false; } if (!string.IsNullOrEmpty(outRailId) && !(outRailId == text)) { text = outRailId; BCSRailPiece bCSRailPiece2 = BCSRailRegistry.FindById(outRailId); if (!((Object)(object)bCSRailPiece2 == (Object)null) && bCSRailPiece2.IsSwitchRail()) { switchRail = bCSRailPiece2; return true; } } } return false; } private bool IsControllableRail(BCSRailPiece rail) { if ((Object)(object)rail == (Object)null) { return false; } if (rail.IsSwitchRail()) { return true; } BCSDrawbridgeRail bCSDrawbridgeRail = ((Component)rail).GetComponent(); if ((Object)(object)bCSDrawbridgeRail == (Object)null) { bCSDrawbridgeRail = ((Component)rail).GetComponentInChildren(true); } return (Object)(object)bCSDrawbridgeRail != (Object)null && bCSDrawbridgeRail.IsDrawbridgeRail(); } private float GetLeadingOffsetFromCenter() { if ((Object)(object)m_cart == (Object)null) { return 0f; } BCSCartCouplerSide side = ((!m_cart.ShouldMoveTowardFront()) ? BCSCartCouplerSide.Back : BCSCartCouplerSide.Front); return Mathf.Max(0f, m_cart.GetCenterToCouplerDistance(side)); } private void ToggleCameraMode(Player player) { m_cameraMode = GetNextCameraMode(m_cameraMode); if ((Object)(object)player != (Object)null) { ((Character)player).Message((MessageType)2, "Camera: " + m_cameraMode, 0, (Sprite)null); } Log("Camera mode=" + m_cameraMode); } private static BCSDriverCameraMode GetNextCameraMode(BCSDriverCameraMode current) { return current switch { BCSDriverCameraMode.Off => BCSDriverCameraMode.FirstPerson, BCSDriverCameraMode.FirstPerson => BCSDriverCameraMode.ShoulderRight, BCSDriverCameraMode.ShoulderRight => BCSDriverCameraMode.ShoulderLeft, BCSDriverCameraMode.ShoulderLeft => BCSDriverCameraMode.CloseFollow, _ => BCSDriverCameraMode.Off, }; } public bool TryHandleModifiedEngineUse(Player player, out bool handled) { //IL_0018: 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_002f: 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) handled = false; if ((Object)(object)player == (Object)null) { return false; } bool flag = (int)m_modifierSwitch != 0 && Input.GetKey(m_modifierSwitch); bool flag2 = (int)m_modifierCamera != 0 && Input.GetKey(m_modifierCamera); if (!flag && !flag2) { return false; } handled = true; if (!IsLocalPlayerDrivingThisCart()) { ((Character)player).Message((MessageType)2, "Sit in cart to use controls", 0, (Sprite)null); return true; } if (flag2) { ToggleCameraMode(player); return true; } if (flag) { if (!CanUseLeadingCartActions()) { ((Character)player).Message((MessageType)2, "Switch control unavailable from passenger cart", 0, (Sprite)null); return true; } ToggleSwitchAhead(player); return true; } return true; } private void Log(string message) { if (m_enableDebugLogs) { Debug.Log((object)("[BCSPowerCartControls][" + ((Object)((Component)this).gameObject).name + "] " + message)); } } } public class BCSPresenceSignalEmitter : MonoBehaviour, Hoverable, Interactable, TextReceiver { private class PresenceRecord { public Character Character; public readonly HashSet ContactKeys = new HashSet(); public Vector3 LastPosition; public bool HasLastPosition; } private const string RpcSetSignalName = "RPC_SetSignalName"; private const string RpcSetTarget = "RPC_SetTarget"; private const string RpcSetShape = "RPC_SetShape"; private const string RpcSetEvent = "RPC_SetEvent"; private const string RpcSetRange = "RPC_SetRange"; public string m_name = "Presence Signal Emitter"; [Header("Signal")] public float m_defaultRange = 3f; public float m_minRange = 1f; public float m_maxRange = 50f; public float m_rangeStep = 1f; [Header("Defaults")] public BCSPresenceSignalTarget m_defaultTarget = BCSPresenceSignalTarget.Players; public BCSPresenceSignalShape m_defaultShape = BCSPresenceSignalShape.Zone; public BCSPresenceSignalEvent m_defaultEvent = BCSPresenceSignalEvent.Present; [Header("Detection")] public float m_stateCheckInterval = 0.2f; public float m_stopConfirmTime = 0.5f; public float m_moveDistanceThreshold = 0.03f; [Header("Trigger Roots")] public GameObject m_zoneTriggerObject; public GameObject m_directionalTriggerObject; [Header("Visuals")] public GameObject m_disabledObject; public GameObject m_enabledObject; public GameObject m_signalObject; public CircleProjector m_areaMarker; [Header("Debug")] public bool m_debugLogs = false; private ZNetView _nview; private readonly Dictionary _records = new Dictionary(); private readonly List _removeBuffer = new List(); private readonly List _receiverCache = new List(); private bool _previousOccupied; private bool _previousCondition; private bool _receiverCacheValid; private bool _areaMarkerVisible; private string _activeSignalName = string.Empty; private float _stateTimer; private float _lastHoverTime = -1000f; private float _occupiedStillTime; private void Awake() { _nview = ((Component)this).GetComponent(); if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { ((Behaviour)this).enabled = false; return; } _nview.Register("RPC_SetSignalName", (Action)RPC_SetSignalName); _nview.Register("RPC_SetTarget", (Action)RPC_SetTarget); _nview.Register("RPC_SetShape", (Action)RPC_SetShape); _nview.Register("RPC_SetEvent", (Action)RPC_SetEvent); _nview.Register("RPC_SetRange", (Action)RPC_SetRange); BCSSignalRegistry.RegisterPresenceEmitter(this); UpdateTriggerObjects(); UpdateAreaMarker(); SetAreaMarkerVisible(visible: false); UpdateVisualState(active: false); } private void OnDestroy() { ResetRuntimeOnly(); SetAreaMarkerVisible(visible: false); BCSSignalRegistry.UnregisterPresenceEmitter(this); } private void Update() { HandleRangeInput(); _stateTimer += Time.deltaTime; if (_stateTimer >= Mathf.Max(0.05f, m_stateCheckInterval)) { _stateTimer = 0f; PruneInvalidRecords(); if ((Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.IsOwner()) { UpdateSignalState(); } UpdateTriggerObjects(); UpdateVisualState(GetEmitterActive()); } UpdateAreaMarkerVisibility(); } private void ResetRuntimeOnly() { _records.Clear(); _removeBuffer.Clear(); _receiverCache.Clear(); _receiverCacheValid = false; _previousOccupied = false; _previousCondition = false; _activeSignalName = string.Empty; _occupiedStillTime = 0f; _stateTimer = 0f; } public void OnPresenceTriggerEnter(BCSPresenceSignalTriggerRelay relay, Collider other) { //IL_00a1: 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) if ((Object)(object)relay == (Object)null || (Object)(object)other == (Object)null || !RelayMatchesCurrentShape(relay)) { return; } Character componentInParent = ((Component)other).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null) && ((Component)componentInParent).gameObject.activeInHierarchy && PassesTargetFilter(componentInParent)) { if (!_records.TryGetValue(componentInParent, out var value)) { value = new PresenceRecord(); value.Character = componentInParent; value.LastPosition = ((Component)componentInParent).transform.position; value.HasLastPosition = true; _records.Add(componentInParent, value); } value.ContactKeys.Add(GetContactKey(relay, other)); Log("Enter " + ((Object)componentInParent).name + " relay=" + relay.m_type.ToString() + " contacts=" + value.ContactKeys.Count); } } public void OnPresenceTriggerExit(BCSPresenceSignalTriggerRelay relay, Collider other) { if ((Object)(object)relay == (Object)null || (Object)(object)other == (Object)null) { return; } Character componentInParent = ((Component)other).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null) && _records.TryGetValue(componentInParent, out var value)) { value.ContactKeys.Remove(GetContactKey(relay, other)); Log("Exit " + ((Object)componentInParent).name + " relay=" + relay.m_type.ToString() + " contacts=" + value.ContactKeys.Count); if (value.ContactKeys.Count <= 0) { _records.Remove(componentInParent); } } } private static string GetContactKey(BCSPresenceSignalTriggerRelay relay, Collider other) { return ((Object)relay).GetInstanceID() + ":" + ((Object)other).GetInstanceID(); } private bool RelayMatchesCurrentShape(BCSPresenceSignalTriggerRelay relay) { if (GetShape() == BCSPresenceSignalShape.Zone) { return relay.m_type == BCSPresenceSignalTriggerType.Zone; } return relay.m_type == BCSPresenceSignalTriggerType.Directional; } private bool PassesTargetFilter(Character character) { if ((Object)(object)character == (Object)null) { return false; } Player val = (Player)(object)((character is Player) ? character : null); BaseAI component = ((Component)character).GetComponent(); bool flag = (Object)(object)val != (Object)null; bool flag2 = character.IsTamed(); bool flag3 = (Object)(object)component != (Object)null && !flag2; return GetTarget() switch { BCSPresenceSignalTarget.Players => flag, BCSPresenceSignalTarget.Monsters => flag3, BCSPresenceSignalTarget.Tamed => flag2, _ => flag || flag3 || flag2, }; } private void PruneInvalidRecords() { _removeBuffer.Clear(); foreach (KeyValuePair record in _records) { Character key = record.Key; PresenceRecord value = record.Value; if ((Object)(object)key == (Object)null || value == null || !((Component)key).gameObject.activeInHierarchy) { _removeBuffer.Add(key); } else if (!PassesTargetFilter(key)) { _removeBuffer.Add(key); } } for (int i = 0; i < _removeBuffer.Count; i++) { _records.Remove(_removeBuffer[i]); } _removeBuffer.Clear(); } private void UpdateSignalState() { string signalName = GetSignalName(); if (string.IsNullOrEmpty(signalName)) { if (_previousCondition || GetEmitterActive()) { StopSignal(_activeSignalName); } _previousCondition = false; _previousOccupied = false; return; } bool flag = _records.Count > 0; bool flag2 = EvaluateCondition(flag); if (!_previousCondition && flag2) { StartSignal(signalName); } else if (_previousCondition && !flag2) { StopSignal(signalName); } _previousOccupied = flag; _previousCondition = flag2; } private bool EvaluateCondition(bool occupied) { return GetEvent() switch { BCSPresenceSignalEvent.Present => occupied, BCSPresenceSignalEvent.Entered => !_previousOccupied && occupied, BCSPresenceSignalEvent.Exited => _previousOccupied && !occupied, BCSPresenceSignalEvent.Stopped => IsStoppedCondition(occupied), BCSPresenceSignalEvent.Moving => occupied && AnyTrackedCharacterMoving(), _ => false, }; } private bool AnyTrackedCharacterMoving() { //IL_004f: 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_0064: 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_00a3: 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) bool result = false; foreach (KeyValuePair record in _records) { Character key = record.Key; PresenceRecord value = record.Value; if ((Object)(object)key == (Object)null || value == null) { continue; } Vector3 position = ((Component)key).transform.position; if (value.HasLastPosition) { float num = Vector3.Distance(position, value.LastPosition); if (num > Mathf.Max(0.001f, m_moveDistanceThreshold)) { result = true; } } else { result = true; value.HasLastPosition = true; } value.LastPosition = position; } return result; } private bool IsStoppedCondition(bool occupied) { if (!occupied) { _occupiedStillTime = 0f; ResetMovementCache(); return false; } if (AnyTrackedCharacterMoving()) { _occupiedStillTime = 0f; return false; } _occupiedStillTime += Mathf.Max(0.05f, m_stateCheckInterval); return _occupiedStillTime >= Mathf.Max(0.05f, m_stopConfirmTime); } private void ResetMovementCache() { foreach (KeyValuePair record in _records) { if (record.Value != null) { record.Value.HasLastPosition = false; } } } private string GetEmitterId() { if ((Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.GetZDO() != null) { return ((object)(ZDOID)(ref _nview.GetZDO().m_uid)).ToString(); } return ((Object)((Component)this).gameObject).GetInstanceID().ToString(); } private void StartSignal(string signalName) { _activeSignalName = signalName ?? string.Empty; SetEmitterActive(active: true); RefreshReceiverCache(); string emitterId = GetEmitterId(); for (int num = _receiverCache.Count - 1; num >= 0; num--) { IBCSSignalReceiver iBCSSignalReceiver = _receiverCache[num]; if (!BCSSignalRegistry.IsValidReceiver(iBCSSignalReceiver)) { _receiverCache.RemoveAt(num); } else { iBCSSignalReceiver.RequestSignalStart(_activeSignalName, emitterId); } } } private void StopSignal(string signalName) { string text = ((!string.IsNullOrEmpty(signalName)) ? signalName : _activeSignalName); SetEmitterActive(active: false); if (!string.IsNullOrEmpty(text)) { RefreshReceiverCache(); string emitterId = GetEmitterId(); for (int num = _receiverCache.Count - 1; num >= 0; num--) { IBCSSignalReceiver iBCSSignalReceiver = _receiverCache[num]; if (!BCSSignalRegistry.IsValidReceiver(iBCSSignalReceiver)) { _receiverCache.RemoveAt(num); } else { iBCSSignalReceiver.RequestSignalStop(text, emitterId); } } } _activeSignalName = string.Empty; } public void RefreshReceiverCache() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) BCSSignalRegistry.CleanupInvalidReferences(); BCSSignalRegistry.FindReceivers(GetSignalName(), ((Component)this).transform.position, GetRange(), _receiverCache); _receiverCacheValid = true; } public void InvalidateReceiverCache() { _receiverCacheValid = false; } public void RemoveCachedReceiver(IBCSSignalReceiver receiver) { if (receiver != null) { _receiverCache.Remove(receiver); } } private void RefreshReceiversAndRuntime() { InvalidateReceiverCache(); RefreshReceiverCache(); ResetSignalRuntime(); } private void ResetSignalRuntime() { if (_previousCondition || GetEmitterActive() || !string.IsNullOrEmpty(_activeSignalName)) { StopSignal(_activeSignalName); } _previousCondition = false; _previousOccupied = false; _occupiedStillTime = 0f; ResetMovementCache(); SetEmitterActive(active: false); } private bool GetEmitterActive() { return (Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.GetZDO().GetBool("hl_presence_signal_active", false); } private void SetEmitterActive(bool active) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { _nview.GetZDO().Set("hl_presence_signal_active", active); UpdateVisualState(active); } } private void UpdateVisualState(bool active) { bool flag = !string.IsNullOrEmpty(GetSignalName()); if ((Object)(object)m_disabledObject != (Object)null) { m_disabledObject.SetActive(!flag); } if ((Object)(object)m_enabledObject != (Object)null) { m_enabledObject.SetActive(flag && !active); } if ((Object)(object)m_signalObject != (Object)null) { m_signalObject.SetActive(flag && active); } } private void UpdateTriggerObjects() { bool flag = GetShape() == BCSPresenceSignalShape.Zone; if ((Object)(object)m_zoneTriggerObject != (Object)null && m_zoneTriggerObject.activeSelf != flag) { m_zoneTriggerObject.SetActive(flag); } bool flag2 = !flag; if ((Object)(object)m_directionalTriggerObject != (Object)null && m_directionalTriggerObject.activeSelf != flag2) { m_directionalTriggerObject.SetActive(flag2); } } public string GetHoverName() { return m_name; } public string GetHoverText() { _lastHoverTime = Time.time; ShowAreaMarker(); string value = (string.IsNullOrEmpty(GetSignalName()) ? "NULL" : GetSignalName()); StringBuilder stringBuilder = new StringBuilder(256); stringBuilder.Append(m_name); stringBuilder.Append("\n[$KEY_Use] Signal: ").Append(value); stringBuilder.Append("\n[Shift+$KEY_Use] Target: ").Append(GetTarget()); stringBuilder.Append("\n[Alt+$KEY_Use] Event: ").Append(GetEvent()); stringBuilder.Append("\n[Ctrl+$KEY_Use] Shape: ").Append(GetShape()); stringBuilder.Append("\n[+ / -] Range: ").Append(Mathf.RoundToInt(GetRange())).Append("m"); stringBuilder.Append("\nDetected: ").Append(_records.Count); return (Localization.instance != null) ? Localization.instance.Localize(stringBuilder.ToString()) : stringBuilder.ToString(); } public bool Interact(Humanoid human, bool hold, bool alt) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (hold) { return false; } Player val = (Player)(object)((human is Player) ? human : null); if ((Object)(object)val == (Object)null) { return false; } if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return true; } if (IsShiftHeld()) { BCSPresenceSignalTarget nextTarget = GetNextTarget(); SetTarget(nextTarget); ((Character)val).Message((MessageType)2, "Target: " + nextTarget, 0, (Sprite)null); return true; } if (IsAltHeld()) { BCSPresenceSignalEvent nextEvent = GetNextEvent(); SetEvent(nextEvent); ((Character)val).Message((MessageType)2, "Event: " + nextEvent, 0, (Sprite)null); return true; } if (IsCtrlHeld()) { BCSPresenceSignalShape shape = ((GetShape() == BCSPresenceSignalShape.Zone) ? BCSPresenceSignalShape.Directional : BCSPresenceSignalShape.Zone); SetShape(shape); ((Character)val).Message((MessageType)2, "Shape: " + shape, 0, (Sprite)null); return true; } if ((Object)(object)TextInput.instance == (Object)null) { ((Character)val).Message((MessageType)2, "Text input unavailable", 0, (Sprite)null); return true; } TextInput.instance.RequestText((TextReceiver)(object)this, "Signal name", 32); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public string GetText() { return GetSignalName(); } public void SetText(string text) { SetSignalName((text == null) ? string.Empty : text.Trim()); } private void SetSignalName(string signalName) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetSignalName", new object[1] { signalName ?? string.Empty }); } } private void SetTarget(BCSPresenceSignalTarget target) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetTarget", new object[1] { (int)target }); } } private void SetShape(BCSPresenceSignalShape shape) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetShape", new object[1] { (int)shape }); } } private void SetEvent(BCSPresenceSignalEvent eventMode) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetEvent", new object[1] { (int)eventMode }); } } private void SetRange(float range) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetRange", new object[1] { Mathf.Clamp(range, m_minRange, m_maxRange) }); } } private void RPC_SetSignalName(long sender, string value) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { string signalName = GetSignalName(); if (_previousCondition && !string.IsNullOrEmpty(signalName)) { StopSignal(signalName); } _nview.GetZDO().Set("hl_presence_signal_name", value ?? string.Empty); RefreshReceiversAndRuntime(); } } private void RPC_SetTarget(long sender, int value) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { _nview.GetZDO().Set("hl_presence_signal_target", Mathf.Clamp(value, 0, 3)); _records.Clear(); RefreshReceiversAndRuntime(); } } private void RPC_SetShape(long sender, int value) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { _nview.GetZDO().Set("hl_presence_signal_shape", Mathf.Clamp(value, 0, 1)); _records.Clear(); UpdateTriggerObjects(); RefreshReceiversAndRuntime(); } } private void RPC_SetEvent(long sender, int value) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { _nview.GetZDO().Set("hl_presence_signal_event", Mathf.Clamp(value, 0, 4)); RefreshReceiversAndRuntime(); } } private void RPC_SetRange(long sender, float value) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { _nview.GetZDO().Set("hl_presence_signal_range", Mathf.Clamp(value, m_minRange, m_maxRange)); InvalidateReceiverCache(); RefreshReceiverCache(); UpdateAreaMarker(); } } public string GetSignalName() { return ((Object)(object)_nview != (Object)null && _nview.IsValid()) ? _nview.GetZDO().GetString("hl_presence_signal_name", string.Empty) : string.Empty; } public BCSPresenceSignalTarget GetTarget() { int num = (((Object)(object)_nview != (Object)null && _nview.IsValid()) ? _nview.GetZDO().GetInt("hl_presence_signal_target", (int)m_defaultTarget) : ((int)m_defaultTarget)); return (BCSPresenceSignalTarget)Mathf.Clamp(num, 0, 3); } public BCSPresenceSignalShape GetShape() { int num = (((Object)(object)_nview != (Object)null && _nview.IsValid()) ? _nview.GetZDO().GetInt("hl_presence_signal_shape", (int)m_defaultShape) : ((int)m_defaultShape)); return (BCSPresenceSignalShape)Mathf.Clamp(num, 0, 1); } public BCSPresenceSignalEvent GetEvent() { int num = (((Object)(object)_nview != (Object)null && _nview.IsValid()) ? _nview.GetZDO().GetInt("hl_presence_signal_event", (int)m_defaultEvent) : ((int)m_defaultEvent)); return (BCSPresenceSignalEvent)Mathf.Clamp(num, 0, 4); } public float GetRange() { return ((Object)(object)_nview != (Object)null && _nview.IsValid()) ? Mathf.Clamp(_nview.GetZDO().GetFloat("hl_presence_signal_range", m_defaultRange), m_minRange, m_maxRange) : Mathf.Clamp(m_defaultRange, m_minRange, m_maxRange); } private BCSPresenceSignalTarget GetNextTarget() { return (BCSPresenceSignalTarget)((int)(GetTarget() + 1) % 4); } private BCSPresenceSignalEvent GetNextEvent() { return (BCSPresenceSignalEvent)((int)(GetEvent() + 1) % 5); } private void HandleRangeInput() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!(Time.time - _lastHoverTime > 0.25f) && PrivateArea.CheckAccess(((Component)this).transform.position, 0f, false, false)) { if (Input.GetKeyDown((KeyCode)61) || Input.GetKeyDown((KeyCode)270)) { SetRange(GetRange() + m_rangeStep); } if (Input.GetKeyDown((KeyCode)45) || Input.GetKeyDown((KeyCode)269)) { SetRange(GetRange() - m_rangeStep); } } } private void ShowAreaMarker() { if (!((Object)(object)m_areaMarker == (Object)null)) { UpdateAreaMarker(); SetAreaMarkerVisible(visible: true); } } private void UpdateAreaMarkerVisibility() { if (Time.time - _lastHoverTime > 0.25f) { SetAreaMarkerVisible(visible: false); } } private void SetAreaMarkerVisible(bool visible) { if ((Object)(object)m_areaMarker == (Object)null) { _areaMarkerVisible = false; } else if (_areaMarkerVisible != visible || ((Component)m_areaMarker).gameObject.activeSelf != visible) { _areaMarkerVisible = visible; ((Component)m_areaMarker).gameObject.SetActive(visible); } } private void UpdateAreaMarker() { if ((Object)(object)m_areaMarker != (Object)null) { m_areaMarker.m_radius = GetRange(); } } private static bool IsShiftHeld() { return Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303); } private static bool IsAltHeld() { return Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307); } private static bool IsCtrlHeld() { return Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305); } private void Log(string msg) { if (m_debugLogs) { Debug.Log((object)("[BCSPresenceSignalEmitter][" + ((Object)((Component)this).gameObject).name + "] " + msg)); } } } public class BCSPresenceSignalTriggerRelay : MonoBehaviour { public BCSPresenceSignalTriggerType m_type = BCSPresenceSignalTriggerType.Zone; private BCSPresenceSignalEmitter _emitter; private void Awake() { ResolveEmitter(); } private void OnEnable() { ResolveEmitter(); } private void ResolveEmitter() { if ((Object)(object)_emitter == (Object)null) { _emitter = ((Component)this).GetComponentInParent(); } } private void OnTriggerEnter(Collider other) { ResolveEmitter(); if ((Object)(object)_emitter != (Object)null) { _emitter.OnPresenceTriggerEnter(this, other); } } private void OnTriggerExit(Collider other) { ResolveEmitter(); if ((Object)(object)_emitter != (Object)null) { _emitter.OnPresenceTriggerExit(this, other); } } } public class BCSRailContainerTransfer : MonoBehaviour { private class TransferLock { public Container Container; public Piece Piece; public bool PreviousCanBeRemoved; public bool HasPiece; public bool Changed; public BCSCartRoot Cart; public bool RestoreActiveState; public bool PreviousActiveState; public void Reset() { Container = null; Piece = null; PreviousCanBeRemoved = false; HasPiece = false; Changed = false; Cart = null; RestoreActiveState = false; PreviousActiveState = false; } } private const string RpcToggleMode = "RPC_ToggleContainerTransferMode"; private const string RpcToggleFilter = "RPC_ToggleContainerTransferFilter"; public const int MinTransferStopTimerSeconds = 3; [Header("Container Transfer")] public BCSRailContainerTransferMode m_defaultMode = BCSRailContainerTransferMode.None; public BCSRailUnloadFilter m_defaultFilter = BCSRailUnloadFilter.All; public Container m_container; [Header("Debug")] public bool m_enableDebugLogs = false; private ZNetView _nview; private bool _transferActive; private Coroutine _releaseLocksRoutine; private readonly List _locks = new List(16); private readonly List _itemScratch = new List(64); private static readonly Dictionary WaitCache = new Dictionary(); private void Awake() { _nview = ((Component)this).GetComponent(); if ((Object)(object)_nview != (Object)null) { _nview.Register("RPC_ToggleContainerTransferMode", (Action)RPC_ToggleMode); _nview.Register("RPC_ToggleContainerTransferFilter", (Action)RPC_ToggleFilter); } ResolveContainer(); } private void Start() { ResolveContainer(); } private void OnDisable() { if (_releaseLocksRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_releaseLocksRoutine); _releaseLocksRoutine = null; } ReleaseLocks(); _transferActive = false; _itemScratch.Clear(); } public bool OwnsContainer(Container container) { ResolveContainer(); return (Object)(object)container != (Object)null && (Object)(object)m_container == (Object)(object)container; } public bool IsTransferEnabled() { return GetMode() != BCSRailContainerTransferMode.None; } public BCSRailContainerTransferMode GetMode() { ZDO zdo = GetZdo(); int raw = ((zdo == null) ? ((int)m_defaultMode) : zdo.GetInt("hl_rail_container_transfer_mode", (int)m_defaultMode)); return NormalizeMode(raw); } public BCSRailContainerTransferMode GetNextMode() { return GetMode() switch { BCSRailContainerTransferMode.None => BCSRailContainerTransferMode.Unload, BCSRailContainerTransferMode.Unload => BCSRailContainerTransferMode.Load, _ => BCSRailContainerTransferMode.None, }; } public string GetModeText() { BCSRailContainerTransferMode mode = GetMode(); if (mode == BCSRailContainerTransferMode.None) { return "Inactive"; } return mode.ToString(); } public string GetNextModeText() { return GetNextMode().ToString(); } public BCSRailUnloadFilter GetFilter() { ZDO zdo = GetZdo(); int raw = ((zdo == null) ? ((int)m_defaultFilter) : zdo.GetInt("hl_rail_container_transfer_filter", (int)m_defaultFilter)); return BCSRailItemFilterUtility.Normalize(raw); } public BCSRailUnloadFilter GetNextFilter() { return BCSRailItemFilterUtility.GetNext(GetFilter()); } public string GetFilterText() { return BCSRailItemFilterUtility.GetText(GetFilter()); } public string GetNextFilterText() { return BCSRailItemFilterUtility.GetText(GetNextFilter()); } public int NormalizeStopTimerSeconds(int seconds) { if (!IsTransferEnabled()) { return Mathf.Max(0, seconds); } return Mathf.Max(3, seconds); } public void RequestToggleMode() { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { _nview.InvokeRPC("RPC_ToggleContainerTransferMode", Array.Empty()); } } public void RequestToggleFilter() { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { _nview.InvokeRPC("RPC_ToggleContainerTransferFilter", Array.Empty()); } } private void RPC_ToggleMode(long sender) { if (!IsOwner()) { return; } ZDO zdo = GetZdo(); if (zdo != null) { BCSRailContainerTransferMode nextMode = GetNextMode(); zdo.Set("hl_rail_container_transfer_mode", (int)nextMode); if (nextMode != 0) { EnsureRailTimerMinimum(); } } } private void RPC_ToggleFilter(long sender) { if (IsOwner()) { ZDO zdo = GetZdo(); if (zdo != null) { BCSRailUnloadFilter nextFilter = GetNextFilter(); zdo.Set("hl_rail_container_transfer_filter", (int)nextFilter); } } } private void EnsureRailTimerMinimum() { ZDO zdo = GetZdo(); if (zdo != null) { int num = Mathf.Max(0, zdo.GetInt("hl_stop_timer_seconds", 0)); if (num < 3) { zdo.Set("hl_stop_timer_seconds", 3); zdo.Set("hl_stop_timer_end_time", 0f); } } } public void BeginTransfer(List trainCarts, int stopTimerSeconds) { if (!IsOwner() || _transferActive || !IsTransferEnabled() || trainCarts == null || trainCarts.Count == 0) { return; } ResolveContainer(); if ((Object)(object)m_container == (Object)null || m_container.GetInventory() == null || m_container.IsInUse()) { return; } _transferActive = true; if (_releaseLocksRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_releaseLocksRoutine); _releaseLocksRoutine = null; } ReleaseLocks(); try { if (!TryLockContainer(m_container, null, previousActive: false, restoreActive: false, out var lockRecord)) { _transferActive = false; return; } switch (GetMode()) { case BCSRailContainerTransferMode.Unload: TransferTrainToChest(trainCarts, lockRecord); break; case BCSRailContainerTransferMode.Load: TransferChestToTrain(trainCarts, lockRecord); break; } int num = NormalizeStopTimerSeconds(stopTimerSeconds); if (num > 0) { _releaseLocksRoutine = ((MonoBehaviour)this).StartCoroutine(ReleaseLocksAfterDelay(num)); return; } ReleaseLocks(); _transferActive = false; } catch { ReleaseLocks(); _transferActive = false; throw; } } private IEnumerator ReleaseLocksAfterDelay(float seconds) { yield return GetWait(Mathf.Max(0.05f, seconds)); ReleaseLocks(); _transferActive = false; _releaseLocksRoutine = null; } private void TransferTrainToChest(List trainCarts, TransferLock railLock) { Inventory inventory = m_container.GetInventory(); BCSRailUnloadFilter filter = GetFilter(); for (int i = 0; i < trainCarts.Count; i++) { BCSCartRoot bCSCartRoot = trainCarts[i]; if ((Object)(object)bCSCartRoot == (Object)null || bCSCartRoot.IsPowered() || !bCSCartRoot.TryPrepareContainerForUnload(out var container, out var previousActiveState, out var restoreActiveState)) { continue; } if ((Object)(object)container == (Object)null || container.GetInventory() == null || container.IsInUse()) { if (restoreActiveState) { bCSCartRoot.RestoreContainerAfterUnload(previousActiveState); } continue; } if (!TryLockContainer(container, bCSCartRoot, previousActiveState, restoreActiveState, out var lockRecord)) { if (restoreActiveState) { bCSCartRoot.RestoreContainerAfterUnload(previousActiveState); } continue; } Inventory inventory2 = container.GetInventory(); FillItems(inventory2, _itemScratch); for (int j = 0; j < _itemScratch.Count; j++) { ItemData val = _itemScratch[j]; if (val != null && val.m_stack > 0 && BCSRailItemFilterUtility.AllowsItem(val, filter) && CanMoveFullStack(inventory, val)) { ItemData val2 = val.Clone(); if (inventory.AddItem(val2)) { inventory2.RemoveItem(val); lockRecord.Changed = true; railLock.Changed = true; } } } _itemScratch.Clear(); } } private void TransferChestToTrain(List trainCarts, TransferLock railLock) { Inventory inventory = m_container.GetInventory(); BCSRailUnloadFilter filter = GetFilter(); FillItems(inventory, _itemScratch); for (int i = 0; i < _itemScratch.Count; i++) { ItemData val = _itemScratch[i]; if (val != null && val.m_stack > 0 && BCSRailItemFilterUtility.AllowsItem(val, filter) && TryFindTargetCartInventory(trainCarts, val, out var targetLock, out var target)) { ItemData val2 = val.Clone(); if (target.AddItem(val2)) { inventory.RemoveItem(val); targetLock.Changed = true; railLock.Changed = true; } } } _itemScratch.Clear(); } private bool TryFindTargetCartInventory(List trainCarts, ItemData item, out TransferLock targetLock, out Inventory target) { targetLock = null; target = null; for (int i = 0; i < trainCarts.Count; i++) { BCSCartRoot bCSCartRoot = trainCarts[i]; if ((Object)(object)bCSCartRoot == (Object)null || bCSCartRoot.IsPowered() || !bCSCartRoot.TryPrepareContainerForUnload(out var container, out var previousActiveState, out var restoreActiveState)) { continue; } if ((Object)(object)container == (Object)null || container.GetInventory() == null) { if (restoreActiveState) { bCSCartRoot.RestoreContainerAfterUnload(previousActiveState); } continue; } if (!TryGetOrLockContainer(container, bCSCartRoot, previousActiveState, restoreActiveState, out var lockRecord)) { if (restoreActiveState) { bCSCartRoot.RestoreContainerAfterUnload(previousActiveState); } continue; } Inventory inventory = container.GetInventory(); if (CanMoveFullStack(inventory, item)) { targetLock = lockRecord; target = inventory; return true; } } return false; } private bool TryGetOrLockContainer(Container container, BCSCartRoot cart, bool previousActive, bool restoreActive, out TransferLock lockRecord) { lockRecord = FindExistingLock(container); if (lockRecord != null) { return true; } return TryLockContainer(container, cart, previousActive, restoreActive, out lockRecord); } private TransferLock FindExistingLock(Container container) { if ((Object)(object)container == (Object)null) { return null; } for (int i = 0; i < _locks.Count; i++) { TransferLock transferLock = _locks[i]; if (transferLock != null && (Object)(object)transferLock.Container == (Object)(object)container) { return transferLock; } } return null; } private bool CanMoveFullStack(Inventory target, ItemData item) { if (target == null || item == null || item.m_stack <= 0) { return false; } return target.CanAddItem(item, item.m_stack); } private bool TryLockContainer(Container container, BCSCartRoot cart, bool previousActive, bool restoreActive, out TransferLock lockRecord) { lockRecord = null; if ((Object)(object)container == (Object)null || container.GetInventory() == null || container.IsInUse()) { return false; } container.SetInUse(true); container.UpdateUseVisual(); lockRecord = new TransferLock(); lockRecord.Container = container; lockRecord.Cart = cart; lockRecord.PreviousActiveState = previousActive; lockRecord.RestoreActiveState = restoreActive; Piece componentInParent = ((Component)container).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { lockRecord.Piece = componentInParent; lockRecord.PreviousCanBeRemoved = componentInParent.m_canBeRemoved; lockRecord.HasPiece = true; componentInParent.m_canBeRemoved = false; } _locks.Add(lockRecord); return true; } private void ReleaseLocks() { for (int num = _locks.Count - 1; num >= 0; num--) { TransferLock transferLock = _locks[num]; if (transferLock != null) { if ((Object)(object)transferLock.Container != (Object)null) { if (transferLock.Changed) { transferLock.Container.Save(); } transferLock.Container.SetInUse(false); transferLock.Container.UpdateUseVisual(); } if (transferLock.HasPiece && (Object)(object)transferLock.Piece != (Object)null) { transferLock.Piece.m_canBeRemoved = transferLock.PreviousCanBeRemoved; } if ((Object)(object)transferLock.Cart != (Object)null && transferLock.RestoreActiveState) { transferLock.Cart.RestoreContainerAfterUnload(transferLock.PreviousActiveState); } transferLock.Reset(); } } _locks.Clear(); } private void ResolveContainer() { if ((Object)(object)m_container == (Object)null) { m_container = ((Component)this).GetComponentInChildren(true); } if ((Object)(object)m_container != (Object)null) { BCSContainerInitUtility.EnsureInitialized(m_container); } } private static void FillItems(Inventory inventory, List result) { result.Clear(); if (inventory != null) { List allItems = inventory.GetAllItems(); for (int i = 0; i < allItems.Count; i++) { result.Add(allItems[i]); } } } private static BCSRailContainerTransferMode NormalizeMode(int raw) { return raw switch { 1 => BCSRailContainerTransferMode.Unload, 2 => BCSRailContainerTransferMode.Load, _ => BCSRailContainerTransferMode.None, }; } private static WaitForSeconds GetWait(float seconds) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown seconds = Mathf.Max(0.01f, seconds); seconds = Mathf.Round(seconds * 1000f) / 1000f; if (!WaitCache.TryGetValue(seconds, out var value)) { value = new WaitForSeconds(seconds); WaitCache[seconds] = value; } return value; } private bool IsOwner() { return (Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.IsOwner() && _nview.GetZDO() != null; } private ZDO GetZdo() { return ((Object)(object)_nview != (Object)null && _nview.IsValid()) ? _nview.GetZDO() : null; } private void Log(string msg) { if (m_enableDebugLogs) { Debug.Log((object)("[BCSRailContainerTransfer][" + ((Object)((Component)this).gameObject).name + "] " + msg)); } } public string GetHoverStatusText() { string text = "Rail Container Transfer"; text = text + "\nMode: " + GetModeText(); text = text + "\nFilter: " + GetFilterText(); if (IsTransferRunning()) { text += "\nTransfer in progress"; text += "\nContainer is in use"; } return text; } public bool IsTransferRunning() { return _transferActive || _locks.Count > 0; } } public static class BCSRailItemFilterUtility { private static readonly ItemType[] Materials = (ItemType[])(object)new ItemType[1] { (ItemType)1 }; private static readonly ItemType[] Consumables = (ItemType[])(object)new ItemType[1] { (ItemType)2 }; private static readonly ItemType[] Weapons; private static readonly ItemType[] Armor; private static readonly ItemType[] Misc; private static readonly ItemType[] Equipables; public static bool AllowsItem(ItemData item, BCSRailUnloadFilter filter) { //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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0076: 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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: 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_00f6: Unknown result type (might be due to invalid IL or missing references) if (item == null || item.m_shared == null) { return false; } switch (filter) { case BCSRailUnloadFilter.None: return false; case BCSRailUnloadFilter.All: return true; default: { ItemType itemType = item.m_shared.m_itemType; return filter switch { BCSRailUnloadFilter.Materials => Contains(Materials, itemType), BCSRailUnloadFilter.Consumables => Contains(Consumables, itemType), BCSRailUnloadFilter.Weapons => Contains(Weapons, itemType), BCSRailUnloadFilter.Armor => Contains(Armor, itemType), BCSRailUnloadFilter.Misc => Contains(Misc, itemType), BCSRailUnloadFilter.Equipables => Contains(Equipables, itemType), BCSRailUnloadFilter.NonEquipable => !Contains(Equipables, itemType), _ => false, }; } } } public static BCSRailUnloadFilter Normalize(int raw) { return raw switch { 1 => BCSRailUnloadFilter.All, 2 => BCSRailUnloadFilter.Materials, 3 => BCSRailUnloadFilter.Consumables, 4 => BCSRailUnloadFilter.Weapons, 5 => BCSRailUnloadFilter.Armor, 6 => BCSRailUnloadFilter.Misc, 7 => BCSRailUnloadFilter.Equipables, 8 => BCSRailUnloadFilter.NonEquipable, _ => BCSRailUnloadFilter.None, }; } public static BCSRailUnloadFilter GetNext(BCSRailUnloadFilter current) { return current switch { BCSRailUnloadFilter.None => BCSRailUnloadFilter.All, BCSRailUnloadFilter.All => BCSRailUnloadFilter.Materials, BCSRailUnloadFilter.Materials => BCSRailUnloadFilter.Consumables, BCSRailUnloadFilter.Consumables => BCSRailUnloadFilter.Weapons, BCSRailUnloadFilter.Weapons => BCSRailUnloadFilter.Armor, BCSRailUnloadFilter.Armor => BCSRailUnloadFilter.Misc, BCSRailUnloadFilter.Misc => BCSRailUnloadFilter.Equipables, BCSRailUnloadFilter.Equipables => BCSRailUnloadFilter.NonEquipable, _ => BCSRailUnloadFilter.None, }; } public static string GetText(BCSRailUnloadFilter filter) { return filter.ToString(); } private static bool Contains(ItemType[] list, ItemType itemType) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Invalid comparison between I4 and Unknown if (list == null) { return false; } for (int i = 0; i < list.Length; i++) { if ((int)list[i] == (int)itemType) { return true; } } return false; } static BCSRailItemFilterUtility() { ItemType[] array = new ItemType[4]; RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); Weapons = (ItemType[])(object)array; ItemType[] array2 = new ItemType[4]; RuntimeHelpers.InitializeArray(array2, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); Armor = (ItemType[])(object)array2; ItemType[] array3 = new ItemType[5]; RuntimeHelpers.InitializeArray(array3, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); Misc = (ItemType[])(object)array3; ItemType[] array4 = new ItemType[12]; RuntimeHelpers.InitializeArray(array4, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/); Equipables = (ItemType[])(object)array4; } } public class BCSRailPiece : MonoBehaviour, Hoverable, Interactable, TextReceiver { private const string RpcSpawnCart = "RPC_SpawnCart"; private const string RpcToggleSwitch = "RPC_ToggleSwitch"; private const string RpcSetStopMode = "RPC_SetStopMode"; private const string RpcSetStopTimerSeconds = "RPC_SetStopTimerSeconds"; private const int CartBlockBufferSize = 16; private readonly List _cartScanScratch = new List(64); private readonly List _railScanScratch = new List(128); private static readonly Collider[] CartBlockBuffer = (Collider[])(object)new Collider[16]; private ZNetView _nview; private string _cachedRailId = string.Empty; private bool _destroying; private BCSDrawbridgeRail _drawbridge; private BCSRailNodeSide _runtimeCrossroadStart = BCSRailNodeSide.A; private BCSRailNodeSide _runtimeCrossroadEnd = BCSRailNodeSide.B; [Header("Rail")] public BCSRailPieceType m_pieceType = BCSRailPieceType.Straight; public bool m_canSpawnCart = true; public bool m_shouldStop = false; public bool m_canAlignAndFlip = true; public bool m_isControlRail = false; [Header("Speed Rail")] public bool m_isSpeedRail = false; public float m_speedMultiplier = 1.75f; [Header("Switch Rail")] public bool m_isSwitchRail = false; public BCSRailSwitchDirection m_defaultSwitchDirection = BCSRailSwitchDirection.Left; [Header("Spawn - Cart Prefabs")] public string m_poweredCartPrefabName = "RailPowerWagon_bal"; public string m_cargoCartPrefabName = "RailCargoWagon_bal"; public string m_tableCartPrefabName = "RailTableWagon_bal"; public string m_personelCartPrefabName = "RailPersonelWagon_bal"; [Header("Spawn - Item Prefabs")] public string m_poweredCartItemPrefabName = "WagonBundlePower_bal"; public string m_cargoCartItemPrefabName = "WagonBundleCargo_bal"; public string m_tableCartItemPrefabName = "WagonBundleTable_bal"; public string m_personelCartItemPrefabName = "WagonBundlePersonel_bal"; private bool _visualStateInitialized; private bool _lastShowGeneralStop; private bool _lastShowSideA; private bool _lastShowSideB; private bool _lastShowCanSpawn; private bool _lastShowSwitchLeft; private bool _lastShowSwitchRight; private readonly Transform[] _nodeScratch4 = (Transform[])(object)new Transform[4]; [Range(0f, 1f)] public float m_spawnDistanceNormalized = 0.5f; public LayerMask m_spawnBlockMask = LayerMask.op_Implicit(-5); public Vector3 m_spawnOverlapHalfExtents = new Vector3(0.75f, 0.75f, 0.75f); [Header("Path")] public Transform m_pointA; public Transform m_pointB; public Transform m_pointC; public Transform m_curvePoint; [Header("Snap / Neighbors")] public Transform m_nodeA; public Transform m_nodeB; public Transform m_nodeC; public float m_nodeSearchRadius = 0.5f; [Header("Centering")] public float m_defaultCartCenterDistance = 0.5f; [Header("Auto Refresh")] public bool m_enableAutoNeighborRefresh = true; public float m_neighborRefreshInterval = 1f; public float m_visualRefreshInterval = 0.5f; public bool m_refreshOnlyWhenOwner = true; [Header("Visual State Objects")] public GameObject m_stopRailObject; public GameObject m_stopSideAObject; public GameObject m_stopSideBObject; public GameObject m_canSpawnCartObject; public GameObject m_switchLeftObject; public GameObject m_switchRightObject; public EffectList m_spawnCartEffect = new EffectList(); public EffectList m_cartActionEffect = new EffectList(); public EffectList m_toggleActionEffect = new EffectList(); [Header("Jump Arc")] public BCSJumpRailArcMode m_jumpArcMode = BCSJumpRailArcMode.Auto; public float m_jumpFlatLiftMultiplier = 1f; public float m_jumpUpLiftMultiplier = 1.35f; public float m_jumpDownLiftMultiplier = 0.75f; public float m_jumpDropLiftMultiplier = 0.25f; public float m_jumpFlatTangentMultiplier = 1f; public float m_jumpUpTangentMultiplier = 1.15f; public float m_jumpDownTangentMultiplier = 0.9f; public float m_jumpDropTangentMultiplier = 0.65f; public float m_jumpUpMinExtraLift = 0.8f; public float m_jumpDownMaxExtraLift = 1.2f; public float m_jumpDropMaxExtraLift = 0.45f; [Header("Debug")] public bool m_enableDebugLogs = false; public bool m_enableVerboseNeighborLogs = false; public bool m_enableVerboseSpawnLogs = false; public bool m_enableVisualLogs = false; private void Awake() { if (IsPlacementGhostSafe()) { ((Behaviour)this).enabled = false; return; } _nview = ((Component)this).GetComponent(); if ((Object)(object)_nview != (Object)null) { _nview.Register("RPC_ToggleSwitch", (Action)RPC_ToggleSwitch); _nview.Register("RPC_SetStopMode", (Action)RPC_SetStopMode); _nview.Register("RPC_SpawnCart", (Action)RPC_SpawnCart); _nview.Register("RPC_SetStopTimerSeconds", (Action)RPC_SetStopTimerSeconds); } _drawbridge = ((Component)this).GetComponent(); EnsureNodeFallbacks(); EnsureRailId(); BCSRailRegistry.Register(this); UpdateVisualStateImmediate(); } private void Start() { if (IsPlacementGhostSafe()) { ((Behaviour)this).enabled = false; return; } EnsureNodeFallbacks(); SafeRefreshNeighborsAndAdjacent("Start"); if (m_enableAutoNeighborRefresh) { float num = Mathf.Max(0.5f, BCSCommonUtility.SanitizeFloat(m_neighborRefreshInterval, 3f)); float staggeredDelay = GetStaggeredDelay(0.15f, 0.35f); ((MonoBehaviour)this).InvokeRepeating("InvokeRefreshNeighborsTick", staggeredDelay, num); } if (ShouldUseVisualRefreshPolling()) { float num2 = Mathf.Max(0.5f, BCSCommonUtility.SanitizeFloat(m_visualRefreshInterval, 1f)); float staggeredDelay2 = GetStaggeredDelay(0.1f, 0.25f); ((MonoBehaviour)this).InvokeRepeating("InvokeVisualRefreshTick", staggeredDelay2, num2); } UpdateVisualStateImmediate(); } private void OnDisable() { ((MonoBehaviour)this).CancelInvoke(); } private void OnDestroy() { _destroying = true; ((MonoBehaviour)this).CancelInvoke(); string neighborRailId = GetNeighborRailId(BCSRailNodeSide.A); string neighborRailId2 = GetNeighborRailId(BCSRailNodeSide.B); string neighborRailId3 = GetNeighborRailId(BCSRailNodeSide.C); string neighborRailId4 = GetNeighborRailId(BCSRailNodeSide.D); BCSRailRegistry.Unregister(this); } private bool ShouldUseVisualRefreshPolling() { if (IsPlacementGhostSafe()) { return false; } if ((Object)(object)GetDrawbridge() != (Object)null && GetDrawbridge().IsDrawbridgeRail()) { return true; } if ((Object)(object)GetSignalStopReceiverOverride() != (Object)null) { return true; } if ((Object)(object)((Component)this).GetComponent() != (Object)null) { return true; } if ((Object)(object)GetUnloader() != (Object)null) { return true; } if ((Object)(object)GetContainerTransfer() != (Object)null) { return true; } return false; } public string GetHoverName() { BCSRailSignalStopReceiver signalStopReceiverOverride = GetSignalStopReceiverOverride(); if ((Object)(object)signalStopReceiverOverride != (Object)null) { return signalStopReceiverOverride.GetHoverName(); } BCSRailSignalSwitchReceiver signalSwitchReceiverOverride = GetSignalSwitchReceiverOverride(); if ((Object)(object)signalSwitchReceiverOverride != (Object)null) { return signalSwitchReceiverOverride.GetHoverName(); } return "Rail"; } public string GetHoverText() { BCSRailSignalStopReceiver signalStopReceiverOverride = GetSignalStopReceiverOverride(); if ((Object)(object)signalStopReceiverOverride != (Object)null) { return signalStopReceiverOverride.GetHoverText(); } BCSRailSignalSwitchReceiver signalSwitchReceiverOverride = GetSignalSwitchReceiverOverride(); if ((Object)(object)signalSwitchReceiverOverride != (Object)null) { return signalSwitchReceiverOverride.GetHoverText(); } string text = "Rail"; BCSDrawbridgeRail drawbridge = GetDrawbridge(); if ((Object)(object)drawbridge != (Object)null && drawbridge.IsDrawbridgeRail()) { return drawbridge.GetHoverText(); } if (IsSwitchRail()) { text += "\n[$KEY_Use] Toggle switch path"; text += ((GetActiveBranchSide() == BCSRailNodeSide.B) ? "\nPath: Straight" : "\nPath: Branch"); return (Localization.instance != null) ? Localization.instance.Localize(text) : text; } BCSRailUnloader unloader = GetUnloader(); BCSRailContainerTransfer containerTransfer = GetContainerTransfer(); if (IsControlRail()) { if ((Object)(object)unloader != (Object)null) { text = text + "\n[$KEY_Use] Unload filter: " + unloader.GetUnloadFilterText(); text += "\n[Alt+$KEY_Use] Stop mode"; text = text + "\n[Ctrl+$KEY_Use] Set Timer (" + GetStopTimerHoverText() + ")"; text = text + "\nStop: " + GetStopModeText(); return (Localization.instance != null) ? Localization.instance.Localize(text) : text; } if ((Object)(object)containerTransfer != (Object)null) { text = text + "\n[$KEY_Use] Transfer mode: " + containerTransfer.GetModeText(); text = text + "\n[Shift+$KEY_Use] Filter: " + containerTransfer.GetFilterText(); if (containerTransfer.IsTransferRunning()) { text += "\nTransfer in progress"; text += "\nContainer is open / in use"; } text += "\n[Alt+$KEY_Use] Stop mode"; text = text + "\n[Ctrl+$KEY_Use] Set Timer (" + GetStopTimerHoverText() + ")"; text = text + "\nStop: " + GetStopModeText(); return (Localization.instance != null) ? Localization.instance.Localize(text) : text; } if (CanAlignAndFlip()) { text += "\n[$KEY_Use] Align cart"; text += "\n[Shift+$KEY_Use] Flip direction"; } text += "\n[Alt+$KEY_Use] Stop mode"; text = text + "\n[Ctrl+$KEY_Use] Set Timer (" + GetStopTimerHoverText() + ")"; text = text + "\nStop: " + GetStopModeText(); if (CanSpawnCart()) { text += "\n[1-8] Spawn Cart"; } return (Localization.instance != null) ? Localization.instance.Localize(text) : text; } return (Localization.instance != null) ? Localization.instance.Localize(text) : text; } public bool Interact(Humanoid user, bool hold, bool alt) { if (hold || IsPlacementGhostSafe()) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)val == (Object)null) { return false; } if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || _nview.GetZDO() == null) { return false; } BCSRailSignalStopReceiver signalStopReceiverOverride = GetSignalStopReceiverOverride(); if ((Object)(object)signalStopReceiverOverride != (Object)null) { return signalStopReceiverOverride.Interact(user, hold, alt); } BCSRailSignalSwitchReceiver signalSwitchReceiverOverride = GetSignalSwitchReceiverOverride(); if ((Object)(object)signalSwitchReceiverOverride != (Object)null) { return signalSwitchReceiverOverride.Interact(user, hold, alt); } BCSDrawbridgeRail drawbridge = GetDrawbridge(); if ((Object)(object)drawbridge != (Object)null && drawbridge.IsDrawbridgeRail()) { return drawbridge.TryInteract(val); } if (IsSwitchRail()) { BCSRailSwitchDirection bCSRailSwitchDirection = ((GetSwitchDirection() == BCSRailSwitchDirection.Left) ? BCSRailSwitchDirection.Right : BCSRailSwitchDirection.Left); _nview.InvokeRPC("RPC_ToggleSwitch", Array.Empty()); ((Character)val).Message((MessageType)2, (bCSRailSwitchDirection == BCSRailSwitchDirection.Left) ? "Switch: Straight" : "Switch: Branch", 0, (Sprite)null); return true; } if (!IsControlRail()) { return false; } if (IsCtrlHeld()) { if ((Object)(object)TextInput.instance == (Object)null) { ((Character)val).Message((MessageType)2, "Text input unavailable", 0, (Sprite)null); return true; } TextInput.instance.RequestText((TextReceiver)(object)this, "Stop timer seconds", 8); return true; } if (IsAltHeld()) { BCSRailStopMode nextStopMode = GetNextStopMode(); _nview.InvokeRPC("RPC_SetStopMode", new object[1] { (int)nextStopMode }); ((Character)val).Message((MessageType)2, "Stop: " + GetStopModeText(nextStopMode), 0, (Sprite)null); return true; } BCSRailUnloader unloader = GetUnloader(); if ((Object)(object)unloader != (Object)null) { string nextUnloadFilterText = unloader.GetNextUnloadFilterText(); unloader.RequestToggleUnloadFilter(); ((Character)val).Message((MessageType)2, "Unload filter: " + nextUnloadFilterText, 0, (Sprite)null); return true; } BCSRailContainerTransfer containerTransfer = GetContainerTransfer(); if ((Object)(object)containerTransfer != (Object)null) { if (IsShiftHeld()) { string nextFilterText = containerTransfer.GetNextFilterText(); containerTransfer.RequestToggleFilter(); ((Character)val).Message((MessageType)2, "Transfer filter: " + nextFilterText, 0, (Sprite)null); return true; } string nextModeText = containerTransfer.GetNextModeText(); containerTransfer.RequestToggleMode(); ((Character)val).Message((MessageType)2, "Transfer mode: " + nextModeText, 0, (Sprite)null); return true; } if (!CanAlignAndFlip()) { return false; } if (HasMultipleCartsOnThisRail()) { ((Character)val).Message((MessageType)2, "More than one cart is on this rail", 0, (Sprite)null); return true; } BCSCartRoot bCSCartRoot = FindNearestCartOnThisRail(); if ((Object)(object)bCSCartRoot == (Object)null) { ((Character)val).Message((MessageType)2, "No cart on this rail", 0, (Sprite)null); return true; } if (IsShiftHeld()) { bool flag = bCSCartRoot.RequestFlipDisconnected(val); if (flag) { PlayCartActionEffects(); } return flag; } if (bCSCartRoot.RequestAlignToCurrentRail(val)) { PlayCartActionEffects(); ((Character)val).Message((MessageType)2, "Cart aligned", 0, (Sprite)null); return true; } return false; } private BCSRailContainerTransfer GetContainerTransfer() { return ((Component)this).GetComponent(); } private void RPC_ToggleSwitch(long sender) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { ToggleSwitchOwned(); } } private void ToggleSwitchOwned() { if (IsSwitchRail()) { BCSRailSwitchDirection switchDirectionOwned = ((GetSwitchDirection() == BCSRailSwitchDirection.Left) ? BCSRailSwitchDirection.Right : BCSRailSwitchDirection.Left); SetSwitchDirectionOwned(switchDirectionOwned); UpdateVisualStateImmediate(); RefreshAdjacentNeighbors(); PlayToggleActionEffects(); if (m_enableDebugLogs) { Debug.Log((object)(Prefix() + "ToggleSwitchOwned direction=" + switchDirectionOwned)); } } } public bool UseItem(Humanoid user, ItemData item) { if (IsPlacementGhostSafe()) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)val == (Object)null || item == null) { return false; } if (!CanSpawnCart()) { return false; } return TrySpawnCart(val, item); } private BCSRailUnloader GetUnloader() { return ((Component)this).GetComponent(); } public string GetRailId() { ZDO validZdo = GetValidZdo(); if (validZdo != null) { string @string = validZdo.GetString("hl_rail_id", string.Empty); if (!string.IsNullOrEmpty(@string)) { _cachedRailId = @string; } } return _cachedRailId ?? string.Empty; } public bool CanSpawnCart() { return IsControlRail() && m_canSpawnCart; } public bool CanAlignAndFlip() { return IsControlRail() && m_canAlignAndFlip; } public bool IsControlRail() { return m_isControlRail; } public bool IsDrawbridgeRail() { return m_pieceType == BCSRailPieceType.Drawbridge && (Object)(object)GetDrawbridge() != (Object)null; } public BCSDrawbridgeRail GetDrawbridge() { if ((Object)(object)_drawbridge == (Object)null) { _drawbridge = ((Component)this).GetComponent(); } return _drawbridge; } public bool IsSwitchRail() { return m_isSwitchRail; } public bool IsSpeedRail() { return m_pieceType == BCSRailPieceType.Speed || m_isSpeedRail; } public float GetSpeedMultiplier() { if (!IsSpeedRail()) { return 1f; } return Mathf.Max(0.01f, BCSCommonUtility.SanitizeFloat(m_speedMultiplier, 1.75f)); } public bool IsCrossroadRail() { return m_pieceType == BCSRailPieceType.Crossroad; } public bool IsJumpRail() { return m_pieceType == BCSRailPieceType.Jump; } public bool HasNeighborA() { return !string.IsNullOrEmpty(GetNeighborRailId(BCSRailNodeSide.A)); } public bool HasNeighborB() { return !string.IsNullOrEmpty(GetNeighborRailId(BCSRailNodeSide.B)); } public bool HasNeighborC() { return !string.IsNullOrEmpty(GetNeighborRailId(BCSRailNodeSide.C)); } public bool HasNeighborD() { return !string.IsNullOrEmpty(GetNeighborRailId(BCSRailNodeSide.D)); } public bool HasActiveBranchNeighbor() { if (!IsSwitchRail()) { return HasNeighborB(); } return (GetActiveBranchSide() == BCSRailNodeSide.B) ? HasNeighborB() : HasNeighborC(); } public BCSRailStopMode GetStopMode() { if (!IsControlRail()) { return BCSRailStopMode.None; } ZDO validZdo = GetValidZdo(); if (validZdo == null) { return m_shouldStop ? BCSRailStopMode.Both : BCSRailStopMode.None; } return validZdo.GetInt("hl_rail_stop_mode", validZdo.GetBool("hl_rail_forced_stop", m_shouldStop) ? 1 : 0) switch { 1 => BCSRailStopMode.Both, 2 => BCSRailStopMode.SideA, 3 => BCSRailStopMode.SideB, _ => BCSRailStopMode.None, }; } private void SetStopModeOwned(BCSRailStopMode mode) { if (IsControlRail()) { ZDO validZdo = GetValidZdo(); if (validZdo == null) { m_shouldStop = mode != BCSRailStopMode.None; return; } validZdo.Set("hl_rail_stop_mode", (int)mode); validZdo.Set("hl_rail_forced_stop", mode != BCSRailStopMode.None); m_shouldStop = mode != BCSRailStopMode.None; } } public BCSRailStopMode GetNextStopMode() { return GetStopMode() switch { BCSRailStopMode.None => BCSRailStopMode.Both, BCSRailStopMode.Both => BCSRailStopMode.SideA, BCSRailStopMode.SideA => BCSRailStopMode.SideB, _ => BCSRailStopMode.None, }; } public bool ShouldStopForEntry(string previousRailId) { if (!IsControlRail()) { return false; } BCSRailStopMode stopMode = GetStopMode(); switch (stopMode) { case BCSRailStopMode.None: return false; case BCSRailStopMode.Both: return true; default: { string text = previousRailId ?? string.Empty; if (string.IsNullOrEmpty(text)) { return false; } bool flag = GetNeighborRailId(BCSRailNodeSide.A) == text; bool flag2 = GetNeighborRailId(BCSRailNodeSide.B) == text; return stopMode switch { BCSRailStopMode.SideA => flag, BCSRailStopMode.SideB => flag2, _ => false, }; } } } private void RPC_SetStopMode(long sender, int rawMode) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner() && IsControlRail()) { BCSRailStopMode stopModeOwned = BCSRailStopMode.None; switch (rawMode) { case 1: stopModeOwned = BCSRailStopMode.Both; break; case 2: stopModeOwned = BCSRailStopMode.SideA; break; case 3: stopModeOwned = BCSRailStopMode.SideB; break; } SetStopModeOwned(stopModeOwned); UpdateVisualStateImmediate(); PlayToggleActionEffects(); } } private string GetStopModeText() { return GetStopModeText(GetStopMode()); } private string GetStopModeText(BCSRailStopMode mode) { return mode switch { BCSRailStopMode.Both => "Both", BCSRailStopMode.SideA => "Side A", BCSRailStopMode.SideB => "Side B", _ => "None", }; } public BCSRailSwitchDirection GetSwitchDirection() { ZDO validZdo = GetValidZdo(); if (validZdo == null) { return m_defaultSwitchDirection; } int @int = validZdo.GetInt("hl_rail_switch_direction", (int)m_defaultSwitchDirection); return (@int == 1) ? BCSRailSwitchDirection.Right : BCSRailSwitchDirection.Left; } private void SetSwitchDirectionOwned(BCSRailSwitchDirection direction) { ZDO validZdo = GetValidZdo(); if (validZdo == null) { m_defaultSwitchDirection = direction; return; } validZdo.Set("hl_rail_switch_direction", (int)direction); m_defaultSwitchDirection = direction; } public void SetSwitchDirection(BCSRailSwitchDirection direction) { ZDO validZdo = GetValidZdo(); if (validZdo == null) { m_defaultSwitchDirection = direction; return; } ClaimOwnershipIfNeeded(); validZdo.Set("hl_rail_switch_direction", (int)direction); m_defaultSwitchDirection = direction; } public bool ShouldStop() { if (IsPlacementGhostSafe()) { return false; } if (IsControlRail() && GetStopMode() != 0) { return true; } if (!HasNeighborA()) { return true; } if (IsSwitchRail()) { return !HasActiveBranchNeighbor(); } if (IsCrossroadRail()) { return !HasNeighborB() || !HasNeighborC() || !HasNeighborD(); } return !HasNeighborB(); } public float GetLength() { //IL_00cb: 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_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_00a4: 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_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_0097: 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_00ac: 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_00b3: 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) //IL_00bc: 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) if (!TryGetTraversalPoints(out var startPoint, out var endPoint)) { return 0f; } if (IsJumpRail()) { return GetJumpLength(startPoint, endPoint); } if (IsCurveRailType() || (IsSwitchRail() && GetActiveBranchSide() == BCSRailNodeSide.C && (Object)(object)m_curvePoint != (Object)null)) { Vector3 position = startPoint.position; Vector3 val = (((Object)(object)m_curvePoint != (Object)null) ? m_curvePoint.position : ((position + endPoint.position) * 0.5f)); Vector3 position2 = endPoint.position; return Vector3.Distance(position, val) + Vector3.Distance(val, position2); } return Vector3.Distance(startPoint.position, endPoint.position); } public bool GetPose(float distance, out Vector3 pos, out Quaternion rot) { //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) pos = ((Component)this).transform.position; rot = ((Component)this).transform.rotation; float length = GetLength(); if (length <= 0.001f) { return false; } float t = Mathf.Clamp01(BCSCommonUtility.SanitizeFloat(distance, 0f) / length); return GetNormalizedPose(t, out pos, out rot); } public bool GetNormalizedPose(float t, out Vector3 pos, out Quaternion rot) { //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) //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_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019d: 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_01ba: 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_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: 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_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: 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_00e1: 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_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: 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) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: 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_0104: 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_0123: 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_0127: 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_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_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) pos = ((Component)this).transform.position; rot = ((Component)this).transform.rotation; if (!TryGetTraversalPoints(out var startPoint, out var endPoint)) { return false; } t = Mathf.Clamp01(BCSCommonUtility.SanitizeFloat(t, 0f)); if (IsJumpRail()) { return GetJumpPose(startPoint, endPoint, t, out pos, out rot); } if (IsCurveRailType() || (IsSwitchRail() && GetActiveBranchSide() == BCSRailNodeSide.C && (Object)(object)m_curvePoint != (Object)null)) { Vector3 position = startPoint.position; Vector3 c = (((Object)(object)m_curvePoint != (Object)null) ? m_curvePoint.position : ((position + endPoint.position) * 0.5f)); Vector3 position2 = endPoint.position; pos = EvaluateQuadraticBezier(position, c, position2, t); Vector3 val = EvaluateQuadraticBezierTangent(position, c, position2, t); if (((Vector3)(ref val)).sqrMagnitude <= 0.0001f) { Vector3 val2 = position2 - position; val = ((Vector3)(ref val2)).normalized; } if (((Vector3)(ref val)).sqrMagnitude <= 0.0001f) { return false; } rot = Quaternion.LookRotation(((Vector3)(ref val)).normalized, ((Component)this).transform.up); return true; } Vector3 position3 = startPoint.position; Vector3 position4 = endPoint.position; Vector3 val3 = position4 - position3; pos = Vector3.Lerp(position3, position4, t); if (((Vector3)(ref val3)).sqrMagnitude > 0.0001f) { rot = Quaternion.LookRotation(((Vector3)(ref val3)).normalized, ((Component)this).transform.up); } return true; } public float GetClosestCenteredDistance(float rawDistance) { float length = GetLength(); if (length <= 0.001f) { return 0f; } float num = BCSCommonUtility.SanitizeFloat(rawDistance, 0f); if (CanSpawnCart()) { return Mathf.Clamp(length * Mathf.Clamp01(m_spawnDistanceNormalized), 0f, length); } if (m_defaultCartCenterDistance > 0f) { return Mathf.Clamp(m_defaultCartCenterDistance, 0f, length); } return Mathf.Clamp(num, 0f, length); } public string GetNeighborRailId(BCSRailNodeSide side) { ZDO validZdo = GetValidZdo(); if (validZdo == null) { return string.Empty; } return side switch { BCSRailNodeSide.A => validZdo.GetString("hl_neighbor_a", string.Empty), BCSRailNodeSide.B => validZdo.GetString("hl_neighbor_b", string.Empty), BCSRailNodeSide.C => validZdo.GetString("hl_neighbor_c", string.Empty), _ => validZdo.GetString("hl_neighbor_d", string.Empty), }; } public string GetResolvedNeighborRailId(BCSRailNodeSide side) { if (IsCrossroadRail()) { return side switch { BCSRailNodeSide.A => GetNeighborRailId(BCSRailNodeSide.A), BCSRailNodeSide.B => GetNeighborRailId(BCSRailNodeSide.B), BCSRailNodeSide.C => GetNeighborRailId(BCSRailNodeSide.C), _ => GetNeighborRailId(BCSRailNodeSide.D), }; } if (!IsSwitchRail()) { return GetNeighborRailId(side); } BCSRailNodeSide activeBranchSide = GetActiveBranchSide(); return side switch { BCSRailNodeSide.A => GetNeighborRailId(BCSRailNodeSide.A), BCSRailNodeSide.B => (activeBranchSide == BCSRailNodeSide.B) ? GetNeighborRailId(BCSRailNodeSide.B) : string.Empty, _ => (activeBranchSide == BCSRailNodeSide.C) ? GetNeighborRailId(BCSRailNodeSide.C) : string.Empty, }; } public void EnsureSwitchTraversalBranch(BCSRailNodeSide branchSide) { if (IsSwitchRail()) { switch (branchSide) { case BCSRailNodeSide.B: SetSwitchDirection(BCSRailSwitchDirection.Left); UpdateVisualStateImmediate(); break; case BCSRailNodeSide.C: SetSwitchDirection(BCSRailSwitchDirection.Right); UpdateVisualStateImmediate(); break; } } } public void EnsureCrossroadTraversalPath(BCSRailNodeSide entrySide) { if (IsCrossroadRail()) { switch (entrySide) { case BCSRailNodeSide.A: _runtimeCrossroadStart = BCSRailNodeSide.A; _runtimeCrossroadEnd = BCSRailNodeSide.B; break; case BCSRailNodeSide.B: _runtimeCrossroadStart = BCSRailNodeSide.B; _runtimeCrossroadEnd = BCSRailNodeSide.A; break; case BCSRailNodeSide.C: _runtimeCrossroadStart = BCSRailNodeSide.C; _runtimeCrossroadEnd = BCSRailNodeSide.D; break; default: _runtimeCrossroadStart = BCSRailNodeSide.D; _runtimeCrossroadEnd = BCSRailNodeSide.C; break; } } } public Transform GetTraversalNode(BCSRailNodeSide side) { return (Transform)(side switch { BCSRailNodeSide.A => m_nodeA, BCSRailNodeSide.B => m_nodeB, BCSRailNodeSide.C => m_nodeC, _ => m_curvePoint, }); } public void RefreshNeighbors() { if (!IsPlacementGhostSafe()) { EnsureNodeFallbacks(); RefreshNeighborForSide(BCSRailNodeSide.A); RefreshNeighborForSide(BCSRailNodeSide.B); if (IsSwitchRail() || IsCrossroadRail()) { RefreshNeighborForSide(BCSRailNodeSide.C); } if (IsCrossroadRail()) { RefreshNeighborForSide(BCSRailNodeSide.D); } UpdateVisualStateImmediate(); } } public bool TrySpawnCart(Player player, ItemData item) { if ((Object)(object)player == (Object)null || item == null || IsPlacementGhostSafe()) { return false; } if (!CanSpawnCart()) { return false; } if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || _nview.GetZDO() == null) { return false; } if (!HasSpaceForCart()) { ((Character)player).Message((MessageType)2, "Rail occupied", 0, (Sprite)null); return true; } if (!TryResolveCartPrefabName(item, out var prefabName)) { ((Character)player).Message((MessageType)2, "You can't use that item on Rail", 0, (Sprite)null); return true; } float num = Mathf.Clamp01(BCSCommonUtility.SanitizeFloat(m_spawnDistanceNormalized, 0.5f)); _nview.InvokeRPC("RPC_SpawnCart", new object[3] { prefabName, num, false }); Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory != null) { inventory.RemoveOneItem(item); } return true; } public bool HasSpaceForCart() { //IL_0023: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: 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) if (!GetNormalizedPose(m_spawnDistanceNormalized, out var pos, out var rot)) { return false; } int num = Physics.OverlapBoxNonAlloc(pos, new Vector3(Mathf.Abs(m_spawnOverlapHalfExtents.x), Mathf.Abs(m_spawnOverlapHalfExtents.y), Mathf.Abs(m_spawnOverlapHalfExtents.z)), CartBlockBuffer, rot, LayerMask.op_Implicit(m_spawnBlockMask)); float num2 = 1.25f; for (int i = 0; i < num; i++) { Collider val = CartBlockBuffer[i]; if ((Object)(object)val == (Object)null || val.isTrigger) { continue; } BCSCartRoot componentInParent = ((Component)val).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null)) { float num3 = Vector3.Distance(((Component)componentInParent).transform.position, pos); if (num3 < num2) { return false; } } } return true; } private void RPC_SpawnCart(long sender, string prefabName, float normalizedDistance, bool reversed) { //IL_0104: 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) if (IsPlacementGhostSafe() || (Object)(object)_nview == (Object)null || !_nview.IsValid() || _nview.GetZDO() == null || !_nview.IsOwner() || !CanSpawnCart() || !HasSpaceForCart()) { return; } string text = prefabName ?? string.Empty; if (string.IsNullOrEmpty(text)) { return; } GameObject val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.GetPrefab(text) : null); if ((Object)(object)val == (Object)null) { return; } float num = Mathf.Clamp01(BCSCommonUtility.SanitizeFloat(normalizedDistance, 0.5f)); if (!GetNormalizedPose(num, out var pos, out var rot)) { return; } GameObject val2 = Object.Instantiate(val, pos, rot); if (!((Object)(object)val2 == (Object)null)) { BCSCartRoot component = val2.GetComponent(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val2); return; } float value = GetLength() * num; value = BCSCommonUtility.SanitizeFloat(value, 0f); component.SetRailPosition(GetRailId(), value, reversed); component.AlignToCurrentRail(); component.TryAutoCoupleAfterSpawn(); PlaySpawnEffects(); } } private BCSCartRoot FindNearestCartOnThisRail() { //IL_0072: 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) string railId = GetRailId(); if (string.IsNullOrEmpty(railId)) { return null; } BCSCartRegistry.FillAll(_cartScanScratch); float num = float.MaxValue; BCSCartRoot result = null; for (int i = 0; i < _cartScanScratch.Count; i++) { BCSCartRoot bCSCartRoot = _cartScanScratch[i]; if (!((Object)(object)bCSCartRoot == (Object)null) && !(bCSCartRoot.GetCurrentRailId() != railId)) { Vector3 val = ((Component)bCSCartRoot).transform.position - ((Component)this).transform.position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = bCSCartRoot; } } } return result; } public int CountCartsOnThisRail() { string railId = GetRailId(); if (string.IsNullOrEmpty(railId)) { return 0; } BCSCartRegistry.FillAll(_cartScanScratch); int num = 0; for (int i = 0; i < _cartScanScratch.Count; i++) { BCSCartRoot bCSCartRoot = _cartScanScratch[i]; if ((Object)(object)bCSCartRoot != (Object)null && bCSCartRoot.GetCurrentRailId() == railId) { num++; } } return num; } public bool HasMultipleCartsOnThisRail() { return CountCartsOnThisRail() > 1; } public bool ToggleSwitchFromCart() { if (!IsSwitchRail()) { return false; } if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || _nview.GetZDO() == null) { return false; } BCSRailSignalSwitchReceiver signalSwitchReceiverOverride = GetSignalSwitchReceiverOverride(); if ((Object)(object)signalSwitchReceiverOverride != (Object)null) { return signalSwitchReceiverOverride.RequestManualToggleFromCart(); } _nview.InvokeRPC("RPC_ToggleSwitch", Array.Empty()); return true; } public void RefreshVisualState() { UpdateVisualStateImmediate(); } private bool TryResolveCartPrefabName(ItemData item, out string prefabName) { prefabName = string.Empty; if (item == null) { return false; } string a = SafeItemDropPrefabName(item); if (MatchesName(a, m_poweredCartItemPrefabName) || MatchesName(a, m_poweredCartPrefabName)) { prefabName = m_poweredCartPrefabName; return !string.IsNullOrEmpty(prefabName); } if (MatchesName(a, m_cargoCartItemPrefabName) || MatchesName(a, m_cargoCartPrefabName)) { prefabName = m_cargoCartPrefabName; return !string.IsNullOrEmpty(prefabName); } if (MatchesName(a, m_tableCartItemPrefabName) || MatchesName(a, m_tableCartPrefabName)) { prefabName = m_tableCartPrefabName; return !string.IsNullOrEmpty(prefabName); } if (MatchesName(a, m_personelCartItemPrefabName) || MatchesName(a, m_personelCartPrefabName)) { prefabName = m_personelCartPrefabName; return !string.IsNullOrEmpty(prefabName); } return false; } private BCSRailSignalStopReceiver GetSignalStopReceiverOverride() { BCSRailSignalStopReceiver component = ((Component)this).GetComponent(); if ((Object)(object)component == (Object)null || !((Behaviour)component).enabled) { return null; } return component; } private void RefreshNeighborForSide(BCSRailNodeSide side) { //IL_00c5: 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_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) Transform nodeForSide = GetNodeForSide(side); if ((Object)(object)nodeForSide == (Object)null) { SetNeighborRailId(side, string.Empty); return; } BCSRailPiece bCSRailPiece = null; float num = float.MaxValue; float num2 = Mathf.Max(0.01f, BCSCommonUtility.SanitizeFloat(m_nodeSearchRadius, 0.5f)); float num3 = num2 * num2; BCSRailRegistry.FillAll(_railScanScratch); for (int i = 0; i < _railScanScratch.Count; i++) { BCSRailPiece bCSRailPiece2 = _railScanScratch[i]; if ((Object)(object)bCSRailPiece2 == (Object)null || (Object)(object)bCSRailPiece2 == (Object)(object)this) { continue; } int num4 = bCSRailPiece2.FillAvailableNodes(_nodeScratch4); for (int j = 0; j < num4; j++) { Transform val = _nodeScratch4[j]; if (!((Object)(object)val == (Object)null)) { Vector3 val2 = nodeForSide.position - val.position; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude <= num3 && sqrMagnitude < num) { num = sqrMagnitude; bCSRailPiece = bCSRailPiece2; } } } } string text = (((Object)(object)bCSRailPiece != (Object)null) ? bCSRailPiece.GetRailId() : string.Empty); SetNeighborRailId(side, text); if (m_enableVerboseNeighborLogs) { Debug.Log((object)(Prefix() + "RefreshNeighborForSide " + side.ToString() + " => " + BCSCommonUtility.SafeString(text))); } } private void RefreshAdjacentNeighbors() { RefreshNeighborById(GetNeighborRailId(BCSRailNodeSide.A)); RefreshNeighborById(GetNeighborRailId(BCSRailNodeSide.B)); RefreshNeighborById(GetNeighborRailId(BCSRailNodeSide.C)); RefreshNeighborById(GetNeighborRailId(BCSRailNodeSide.D)); } private static void RefreshNeighborById(string railId) { if (!string.IsNullOrEmpty(railId)) { BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(railId); if ((Object)(object)bCSRailPiece != (Object)null) { bCSRailPiece.RefreshNeighbors(); } } } private void SetNeighborRailId(BCSRailNodeSide side, string railId) { ZDO validZdo = GetValidZdo(); if (validZdo != null) { string text = railId ?? string.Empty; string text2 = side switch { BCSRailNodeSide.A => "hl_neighbor_a", BCSRailNodeSide.B => "hl_neighbor_b", BCSRailNodeSide.C => "hl_neighbor_c", _ => "hl_neighbor_d", }; if (!(validZdo.GetString(text2, string.Empty) == text)) { ClaimOwnershipIfNeeded(); validZdo.Set(text2, text); } } } private void EnsureRailId() { ZDO validZdo = GetValidZdo(); if (validZdo == null) { if (string.IsNullOrEmpty(_cachedRailId)) { _cachedRailId = Guid.NewGuid().ToString("N"); } return; } ClaimOwnershipIfNeeded(); string text = validZdo.GetString("hl_rail_id", string.Empty); if (string.IsNullOrEmpty(text)) { text = Guid.NewGuid().ToString("N"); validZdo.Set("hl_rail_id", text); } validZdo.Set("hl_rail_type", (int)m_pieceType); validZdo.Set("hl_is_platform", CanSpawnCart()); validZdo.Set("hl_rail_forced_stop", validZdo.GetBool("hl_rail_forced_stop", m_shouldStop)); validZdo.Set("hl_rail_switch_direction", validZdo.GetInt("hl_rail_switch_direction", (int)m_defaultSwitchDirection)); validZdo.Set("hl_rail_stop_mode", validZdo.GetInt("hl_rail_stop_mode", validZdo.GetBool("hl_rail_forced_stop", m_shouldStop) ? 1 : 0)); _cachedRailId = text; } private void UpdateVisualStateImmediate() { bool flag = ShouldStop(); bool flag2 = CanSpawnCart(); BCSRailSwitchDirection switchDirection = GetSwitchDirection(); BCSRailStopMode bCSRailStopMode = GetStopMode(); bool flag3 = IsControlRail(); bool flag4 = false; BCSRailSignalStopReceiver signalStopReceiverOverride = GetSignalStopReceiverOverride(); if ((Object)(object)signalStopReceiverOverride != (Object)null) { flag4 = true; bCSRailStopMode = signalStopReceiverOverride.GetCurrentStopMode(); flag = bCSRailStopMode != BCSRailStopMode.None; } BCSDrawbridgeRail drawbridge = GetDrawbridge(); bool flag5 = (Object)(object)drawbridge != (Object)null && drawbridge.IsDrawbridgeRail() && drawbridge.IsBlockedForTrain(); bool flag6 = flag5 || bCSRailStopMode == BCSRailStopMode.Both || (!flag4 && !flag3 && flag); bool flag7 = bCSRailStopMode == BCSRailStopMode.SideA; bool flag8 = bCSRailStopMode == BCSRailStopMode.SideB; bool flag9 = IsSwitchRail(); bool flag10 = flag9 && GetActiveBranchSide() == BCSRailNodeSide.B; bool flag11 = flag9 && GetActiveBranchSide() == BCSRailNodeSide.C; if (!_visualStateInitialized || _lastShowGeneralStop != flag6 || _lastShowSideA != flag7 || _lastShowSideB != flag8 || _lastShowCanSpawn != flag2 || _lastShowSwitchLeft != flag10 || _lastShowSwitchRight != flag11) { _visualStateInitialized = true; _lastShowGeneralStop = flag6; _lastShowSideA = flag7; _lastShowSideB = flag8; _lastShowCanSpawn = flag2; _lastShowSwitchLeft = flag10; _lastShowSwitchRight = flag11; if ((Object)(object)m_stopRailObject != (Object)null && m_stopRailObject.activeSelf != flag6) { m_stopRailObject.SetActive(flag6); } if ((Object)(object)m_stopSideAObject != (Object)null && m_stopSideAObject.activeSelf != flag7) { m_stopSideAObject.SetActive(flag7); } if ((Object)(object)m_stopSideBObject != (Object)null && m_stopSideBObject.activeSelf != flag8) { m_stopSideBObject.SetActive(flag8); } if ((Object)(object)m_canSpawnCartObject != (Object)null && m_canSpawnCartObject.activeSelf != flag2) { m_canSpawnCartObject.SetActive(flag2); } if ((Object)(object)m_switchLeftObject != (Object)null && m_switchLeftObject.activeSelf != flag10) { m_switchLeftObject.SetActive(flag10); } if ((Object)(object)m_switchRightObject != (Object)null && m_switchRightObject.activeSelf != flag11) { m_switchRightObject.SetActive(flag11); } if (m_enableVisualLogs) { Debug.Log((object)(Prefix() + "Visual stop=" + flag + " stopMode=" + bCSRailStopMode.ToString() + " signalReceiver=" + flag4 + " drawbridgeBlocked=" + flag5 + " generalStop=" + flag6 + " sideA=" + flag7 + " sideB=" + flag8 + " canSpawn=" + flag2 + " switch=" + switchDirection.ToString() + " switchStraight=" + flag10 + " switchBranch=" + flag11)); } } } private int FillAvailableNodes(Transform[] result) { if (result == null || result.Length < 4) { return 0; } result[0] = null; result[1] = null; result[2] = null; result[3] = null; result[0] = m_nodeA; result[1] = m_nodeB; int num = 2; if (IsSwitchRail()) { result[num] = m_nodeC; return num + 1; } if (IsCrossroadRail()) { result[num] = m_nodeC; num++; result[num] = m_curvePoint; return num + 1; } return num; } private void InvokeRefreshNeighborsTick() { if (!_destroying && ((Behaviour)this).isActiveAndEnabled && !IsPlacementGhostSafe() && (!m_refreshOnlyWhenOwner || IsOwnerSafe())) { SafeRefreshNeighborsAndAdjacent("InvokeRepeating"); } } private void InvokeVisualRefreshTick() { if (!_destroying && ((Behaviour)this).isActiveAndEnabled && !IsPlacementGhostSafe()) { UpdateVisualStateImmediate(); } } private void SafeRefreshNeighborsAndAdjacent(string source) { try { EnsureNodeFallbacks(); if (!((Object)(object)m_nodeA == (Object)null) && !((Object)(object)m_nodeB == (Object)null)) { if ((Object)(object)_nview == (Object)null) { _nview = ((Component)this).GetComponent(); } if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.GetZDO() != null) { RefreshNeighbors(); RefreshAdjacentNeighbors(); } } } catch (Exception ex) { Debug.LogError((object)(Prefix() + source + " exception\n" + ex)); } } private void EnsureNodeFallbacks() { if ((Object)(object)m_pointA != (Object)null && (Object)(object)m_nodeA == (Object)null) { m_nodeA = m_pointA; } if ((Object)(object)m_pointB != (Object)null && (Object)(object)m_nodeB == (Object)null) { m_nodeB = m_pointB; } if ((Object)(object)m_pointC != (Object)null && (Object)(object)m_nodeC == (Object)null) { m_nodeC = m_pointC; } } private bool TryGetTraversalPoints(out Transform startPoint, out Transform endPoint) { startPoint = m_pointA; endPoint = m_pointB; if (IsCrossroadRail()) { startPoint = GetTraversalNode(_runtimeCrossroadStart); endPoint = GetTraversalNode(_runtimeCrossroadEnd); return (Object)(object)startPoint != (Object)null && (Object)(object)endPoint != (Object)null; } if (!IsSwitchRail()) { return (Object)(object)startPoint != (Object)null && (Object)(object)endPoint != (Object)null; } BCSRailNodeSide activeBranchSide = GetActiveBranchSide(); Transform val = ((activeBranchSide != BCSRailNodeSide.B) ? (((Object)(object)m_pointC != (Object)null) ? m_pointC : m_pointB) : (((Object)(object)m_pointB != (Object)null) ? m_pointB : m_pointC)); if ((Object)(object)startPoint == (Object)null || (Object)(object)val == (Object)null) { endPoint = m_pointB; return (Object)(object)startPoint != (Object)null && (Object)(object)endPoint != (Object)null; } endPoint = val; return true; } public BCSRailNodeSide GetActiveCrossroadStartSide() { return _runtimeCrossroadStart; } public BCSRailNodeSide GetActiveCrossroadEndSide() { return _runtimeCrossroadEnd; } private Transform GetNodeForSide(BCSRailNodeSide side) { return (Transform)(side switch { BCSRailNodeSide.A => m_nodeA, BCSRailNodeSide.B => m_nodeB, BCSRailNodeSide.C => m_nodeC, _ => m_curvePoint, }); } private Transform[] GetAllAvailableNodes() { if (IsCrossroadRail()) { return (Transform[])(object)new Transform[4] { m_nodeA, m_nodeB, m_nodeC, m_curvePoint }; } if (IsSwitchRail()) { return (Transform[])(object)new Transform[3] { m_nodeA, m_nodeB, m_nodeC }; } return (Transform[])(object)new Transform[2] { m_nodeA, m_nodeB }; } private BCSRailNodeSide GetActiveBranchSide() { if (!IsSwitchRail()) { return BCSRailNodeSide.B; } return (GetSwitchDirection() == BCSRailSwitchDirection.Left) ? BCSRailNodeSide.B : BCSRailNodeSide.C; } private void PlaySpawnEffects() { //IL_000d: 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) m_spawnCartEffect.Create(((Component)this).transform.position, ((Component)this).transform.rotation, (Transform)null, 1f, -1); } private void PlayCartActionEffects() { //IL_000d: 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) m_cartActionEffect.Create(((Component)this).transform.position, ((Component)this).transform.rotation, (Transform)null, 1f, -1); } private void PlayToggleActionEffects() { //IL_000d: 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) m_toggleActionEffect.Create(((Component)this).transform.position, ((Component)this).transform.rotation, (Transform)null, 1f, -1); } private static bool IsShiftHeld() { return Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303); } private static bool IsAltHeld() { return Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307); } private static bool IsCtrlHeld() { return Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305); } public BCSRailNodeSide GetNearTraversalSide() { return BCSRailNodeSide.A; } public BCSRailNodeSide GetFarTraversalSide() { if (!IsSwitchRail()) { return BCSRailNodeSide.B; } return GetActiveBranchSide(); } public bool ShouldStopForEntrySide(BCSRailNodeSide entrySide) { if (!IsControlRail()) { return false; } return GetStopMode() switch { BCSRailStopMode.None => false, BCSRailStopMode.Both => true, BCSRailStopMode.SideA => entrySide == BCSRailNodeSide.A, BCSRailStopMode.SideB => entrySide == GetFarTraversalSide(), _ => false, }; } private void ClaimOwnershipIfNeeded() { BCSCommonUtility.ClaimOwnershipIfNeeded(_nview); } private ZDO GetValidZdo() { return BCSCommonUtility.GetValidZdo(_nview); } private bool IsOwnerSafe() { return BCSCommonUtility.IsOwnerSafe(_nview); } private bool IsPlacementGhostSafe() { return BCSCommonUtility.IsPlacementGhostSafe(((Component)this).gameObject); } private static bool MatchesName(string a, string b) { return BCSCommonUtility.MatchesName(a, b); } private static float GetNetworkTimeSeconds() { return BCSCommonUtility.GetNetworkTimeSecondsFloat(); } private float GetStaggeredDelay(float min, float max) { int num = Mathf.Abs(((Object)this).GetInstanceID()); float num2 = (float)(num % 100) / 100f; return Mathf.Lerp(min, max, num2); } private static Vector3 EvaluateQuadraticBezier(Vector3 a, Vector3 c, Vector3 b, float t) { //IL_000c: 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_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_0021: 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_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_0034: 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) float num = 1f - t; return num * num * a + 2f * num * t * c + t * t * b; } private static Vector3 EvaluateQuadraticBezierTangent(Vector3 a, Vector3 c, Vector3 b, float t) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: 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_0015: 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_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_0035: Unknown result type (might be due to invalid IL or missing references) return 2f * (1f - t) * (c - a) + 2f * t * (b - c); } private bool IsCurveRailType() { return m_pieceType == BCSRailPieceType.Turn15 || m_pieceType == BCSRailPieceType.Turn30 || m_pieceType == BCSRailPieceType.Turn45 || m_pieceType == BCSRailPieceType.Turn90; } private float GetJumpLength(Transform startPoint, Transform endPoint) { //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_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_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_004a: 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_007f: 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_006c: 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_0084: 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_0086: 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_008c: 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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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_009a: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: 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_00b0: 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_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: 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_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) if ((Object)(object)startPoint == (Object)null || (Object)(object)endPoint == (Object)null) { return 0f; } Vector3 position = startPoint.position; Vector3 position2 = endPoint.position; Vector3 val = (((Object)(object)m_pointC != (Object)null) ? m_pointC.position : Vector3.Lerp(position, position2, 0.15f)); Vector3 val2 = (((Object)(object)m_curvePoint != (Object)null) ? m_curvePoint.position : Vector3.Lerp(position, position2, 0.85f)); Vector3 safeDirection = GetSafeDirection(val - position, val2 - val); Vector3 safeDirection2 = GetSafeDirection(position2 - val2, val2 - val); BCSJumpRailArcMode mode = ResolveJumpArcMode(val, val2); float num = Vector3.Distance(position, val); float num2 = EstimateBallisticJumpLength(val, val2, safeDirection, safeDirection2, mode, 48); float num3 = Vector3.Distance(val2, position2); return num + num2 + num3; } private bool GetJumpPose(Transform startPoint, Transform endPoint, float t, out Vector3 pos, out Quaternion rot) { //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_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_0048: 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_004f: 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_0077: 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_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_009f: 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_008c: 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_00a4: 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_00a7: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: 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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_00bc: 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_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) //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_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_00e3: 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_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) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: 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) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0164: 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_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0175: 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_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: 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_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: 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_01d6: 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_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_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02d4: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: 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_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0240: 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_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) pos = ((Component)this).transform.position; rot = ((Component)this).transform.rotation; if ((Object)(object)startPoint == (Object)null || (Object)(object)endPoint == (Object)null) { return false; } Vector3 position = startPoint.position; Vector3 position2 = endPoint.position; Vector3 val = (((Object)(object)m_pointC != (Object)null) ? m_pointC.position : Vector3.Lerp(position, position2, 0.15f)); Vector3 val2 = (((Object)(object)m_curvePoint != (Object)null) ? m_curvePoint.position : Vector3.Lerp(position, position2, 0.85f)); Vector3 safeDirection = GetSafeDirection(val - position, val2 - val); Vector3 safeDirection2 = GetSafeDirection(position2 - val2, val2 - val); BCSJumpRailArcMode mode = ResolveJumpArcMode(val, val2); float num = Vector3.Distance(position, val); float num2 = EstimateBallisticJumpLength(val, val2, safeDirection, safeDirection2, mode, 48); float num3 = Vector3.Distance(val2, position2); float num4 = num + num2 + num3; if (num4 <= 0.001f) { return false; } float num5 = Mathf.Clamp01(t) * num4; if (num5 <= num && num > 0.001f) { float num6 = Mathf.Clamp01(num5 / num); pos = Vector3.Lerp(position, val, num6); Vector3 safeDirection3 = GetSafeDirection(val - position, val2 - val); rot = Quaternion.LookRotation(safeDirection3, ((Component)this).transform.up); return true; } num5 -= num; if (num5 <= num2 && num2 > 0.001f) { float ballisticJumpTAtArcLength = GetBallisticJumpTAtArcLength(val, val2, safeDirection, safeDirection2, mode, num5, num2, 48); pos = EvaluateBallisticJump(val, val2, safeDirection, safeDirection2, mode, ballisticJumpTAtArcLength); Vector3 val3 = EvaluateBallisticJumpTangent(val, val2, safeDirection, safeDirection2, mode, ballisticJumpTAtArcLength); if (((Vector3)(ref val3)).sqrMagnitude <= 0.0001f) { val3 = val2 - val; } if (((Vector3)(ref val3)).sqrMagnitude <= 0.0001f) { return false; } rot = Quaternion.LookRotation(((Vector3)(ref val3)).normalized, ((Component)this).transform.up); return true; } num5 -= num2; if (num3 > 0.001f) { float num7 = Mathf.Clamp01(num5 / num3); pos = Vector3.Lerp(val2, position2, num7); Vector3 safeDirection4 = GetSafeDirection(position2 - val2, val2 - val); rot = Quaternion.LookRotation(safeDirection4, ((Component)this).transform.up); return true; } pos = position2; rot = Quaternion.LookRotation(GetSafeDirection(position2 - val2, val2 - val), ((Component)this).transform.up); return true; } private Vector3 EvaluateBallisticJump(Vector3 launch, Vector3 landing, Vector3 launchDir, Vector3 landingDir, BCSJumpRailArcMode mode, float s) { //IL_000a: 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_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_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_001d: 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_001f: 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_002b: 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_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_008d: 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_0095: 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_00a2: 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_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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) //IL_00ba: 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_00be: Unknown result type (might be due to invalid IL or missing references) //IL_010f: 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_0115: Unknown result type (might be due to invalid IL or missing references) s = Mathf.Clamp01(s); Vector3 fallback = landing - launch; float jumpTangentLength = GetJumpTangentLength(launch, landing, mode); Vector3 val = GetSafeDirection(launchDir, fallback) * jumpTangentLength; Vector3 val2 = GetSafeDirection(landingDir, fallback) * jumpTangentLength; float num = s * s; float num2 = num * s; float num3 = 2f * num2 - 3f * num + 1f; float num4 = num2 - 2f * num + s; float num5 = -2f * num2 + 3f * num; float num6 = num2 - num; Vector3 result = num3 * launch + num4 * val + num5 * landing + num6 * val2; float jumpExtraLift = GetJumpExtraLift(launch, landing, mode); float num7 = Mathf.Sin((float)Math.PI * s); num7 *= num7; float num8 = Mathf.SmoothStep(0f, 1f, Mathf.Clamp01(s / 0.28f)); result.y += jumpExtraLift * num7 * num8; return result; } private Vector3 EvaluateBallisticJumpTangent(Vector3 launch, Vector3 landing, Vector3 launchDir, Vector3 landingDir, BCSJumpRailArcMode mode, float s) { //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_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_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_0028: 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_002a: 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_0038: 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_003e: 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_0048: Unknown result type (might be due to invalid IL or missing references) s = Mathf.Clamp01(s); float num = 0.01f; Vector3 val = EvaluateBallisticJump(launch, landing, launchDir, landingDir, mode, Mathf.Clamp01(s - num)); Vector3 val2 = EvaluateBallisticJump(launch, landing, launchDir, landingDir, mode, Mathf.Clamp01(s + num)); return val2 - val; } private float EstimateBallisticJumpLength(Vector3 launch, Vector3 landing, Vector3 launchDir, Vector3 landingDir, BCSJumpRailArcMode mode, int steps) { //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_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_0022: 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_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_0030: 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_003a: 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) steps = Mathf.Max(2, steps); float num = 0f; Vector3 val = launch; for (int i = 1; i <= steps; i++) { float s = (float)i / (float)steps; Vector3 val2 = EvaluateBallisticJump(launch, landing, launchDir, landingDir, mode, s); num += Vector3.Distance(val, val2); val = val2; } return num; } private float GetBallisticJumpTAtArcLength(Vector3 launch, Vector3 landing, Vector3 launchDir, Vector3 landingDir, BCSJumpRailArcMode mode, float targetDistance, float totalLength, int steps) { //IL_002b: 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_003a: 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_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_0049: 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_009c: 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) steps = Mathf.Max(2, steps); targetDistance = Mathf.Clamp(targetDistance, 0f, Mathf.Max(0f, totalLength)); float num = 0f; Vector3 val = launch; for (int i = 1; i <= steps; i++) { float num2 = (float)i / (float)steps; Vector3 val2 = EvaluateBallisticJump(launch, landing, launchDir, landingDir, mode, num2); float num3 = Vector3.Distance(val, val2); if (num + num3 >= targetDistance) { float num4 = ((num3 > 0.0001f) ? Mathf.Clamp01((targetDistance - num) / num3) : 0f); return Mathf.Lerp((float)(i - 1) / (float)steps, num2, num4); } num += num3; val = val2; } return 1f; } private BCSJumpRailArcMode ResolveJumpArcMode(Vector3 launch, Vector3 landing) { //IL_0018: 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) if (m_jumpArcMode != 0) { return m_jumpArcMode; } float num = landing.y - launch.y; if (num > 0.35f) { return BCSJumpRailArcMode.JumpUp; } if (num < -1.25f) { return BCSJumpRailArcMode.Drop; } if (num < -0.35f) { return BCSJumpRailArcMode.JumpDown; } return BCSJumpRailArcMode.Flat; } private float GetJumpTangentLength(Vector3 launch, Vector3 landing, BCSJumpRailArcMode mode) { //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_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_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) Vector3 val = landing - launch; Vector3 val2 = new Vector3(val.x, 0f, val.z); float magnitude = ((Vector3)(ref val2)).magnitude; float num = Mathf.Abs(val.y); float num2 = Mathf.Clamp(magnitude * 0.55f + num * 0.45f, 0.35f, 10f); float num3 = 1f; return Mathf.Clamp(num2 * mode switch { BCSJumpRailArcMode.JumpUp => Mathf.Max(0.05f, BCSCommonUtility.SanitizeFloat(m_jumpUpTangentMultiplier, 1.15f)), BCSJumpRailArcMode.JumpDown => Mathf.Max(0.05f, BCSCommonUtility.SanitizeFloat(m_jumpDownTangentMultiplier, 0.9f)), BCSJumpRailArcMode.Drop => Mathf.Max(0.05f, BCSCommonUtility.SanitizeFloat(m_jumpDropTangentMultiplier, 0.65f)), _ => Mathf.Max(0.05f, BCSCommonUtility.SanitizeFloat(m_jumpFlatTangentMultiplier, 1f)), }, 0.1f, 20f); } private float GetJumpExtraLift(Vector3 launch, Vector3 landing, BCSJumpRailArcMode mode) { //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_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_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) Vector3 val = landing - launch; Vector3 val2 = new Vector3(val.x, 0f, val.z); float magnitude = ((Vector3)(ref val2)).magnitude; float num = Mathf.Abs(val.y); float num2 = Mathf.Clamp(magnitude * 0.16f + num * 0.5f, 0.05f, 5.5f); switch (mode) { case BCSJumpRailArcMode.JumpUp: { float num5 = num2 * Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_jumpUpLiftMultiplier, 1.35f)); return Mathf.Max(num5, Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_jumpUpMinExtraLift, 0.8f))); } case BCSJumpRailArcMode.JumpDown: { float num4 = num2 * Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_jumpDownLiftMultiplier, 0.75f)); return Mathf.Min(num4, Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_jumpDownMaxExtraLift, 1.2f))); } case BCSJumpRailArcMode.Drop: { float num3 = num2 * Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_jumpDropLiftMultiplier, 0.25f)); return Mathf.Min(num3, Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_jumpDropMaxExtraLift, 0.45f))); } default: return num2 * Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_jumpFlatLiftMultiplier, 1f)); } } public float GetJumpLaunchDistance() { return GetJumpLaunchDistance(travelReversed: false); } public float GetJumpLaunchDistance(bool travelReversed) { //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_004e: 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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0076: 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_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_007b: 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_008a: 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_0091: 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_00a4: 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_00ab: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: 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_00ba: 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_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_00cc: 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_00d0: 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_00d9: 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_00e3: 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_00e6: Unknown result type (might be due to invalid IL or missing references) if (!IsJumpRail() || (Object)(object)m_pointA == (Object)null) { return 0f; } Vector3 position = m_pointA.position; Vector3 val = (((Object)(object)m_pointB != (Object)null) ? m_pointB.position : position); Vector3 val2 = (((Object)(object)m_pointC != (Object)null) ? m_pointC.position : Vector3.Lerp(position, val, 0.15f)); Vector3 val3 = (((Object)(object)m_curvePoint != (Object)null) ? m_curvePoint.position : Vector3.Lerp(position, val, 0.85f)); Vector3 safeDirection = GetSafeDirection(val2 - position, val3 - val2); Vector3 safeDirection2 = GetSafeDirection(val - val3, val3 - val2); BCSJumpRailArcMode mode = ResolveJumpArcMode(val2, val3); float num = Vector3.Distance(position, val2); float num2 = EstimateBallisticJumpLength(val2, val3, safeDirection, safeDirection2, mode, 48); if (!travelReversed) { return num; } return num + num2; } public float GetJumpLandingDistance() { return GetJumpLandingDistance(travelReversed: false); } public float GetJumpLandingDistance(bool travelReversed) { //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_004e: 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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0076: 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_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_007b: 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_008a: 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_0091: 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_00a4: 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_00ab: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: 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_00ba: 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_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_00cc: 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_00d0: 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_00d9: 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_00e3: 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_00e6: Unknown result type (might be due to invalid IL or missing references) if (!IsJumpRail() || (Object)(object)m_pointA == (Object)null) { return 0f; } Vector3 position = m_pointA.position; Vector3 val = (((Object)(object)m_pointB != (Object)null) ? m_pointB.position : position); Vector3 val2 = (((Object)(object)m_pointC != (Object)null) ? m_pointC.position : Vector3.Lerp(position, val, 0.15f)); Vector3 val3 = (((Object)(object)m_curvePoint != (Object)null) ? m_curvePoint.position : Vector3.Lerp(position, val, 0.85f)); Vector3 safeDirection = GetSafeDirection(val2 - position, val3 - val2); Vector3 safeDirection2 = GetSafeDirection(val - val3, val3 - val2); BCSJumpRailArcMode mode = ResolveJumpArcMode(val2, val3); float num = Vector3.Distance(position, val2); float num2 = EstimateBallisticJumpLength(val2, val3, safeDirection, safeDirection2, mode, 48); if (!travelReversed) { return num + num2; } return num; } private string SafeItemDropPrefabName(ItemData item) { if (item == null || (Object)(object)item.m_dropPrefab == (Object)null) { return string.Empty; } return ((Object)item.m_dropPrefab).name ?? string.Empty; } private static Vector3 GetSafeDirection(Vector3 preferred, Vector3 fallback) { //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_003b: 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_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_0043: Unknown result type (might be due to invalid IL or missing references) if (((Vector3)(ref preferred)).sqrMagnitude > 0.0001f) { return ((Vector3)(ref preferred)).normalized; } if (((Vector3)(ref fallback)).sqrMagnitude > 0.0001f) { return ((Vector3)(ref fallback)).normalized; } return Vector3.forward; } private string Prefix() { return "[BCSRailPiece][" + ((Object)((Component)this).gameObject).name + "][" + BCSCommonUtility.SafeString(GetRailId()) + "] "; } public string GetText() { return GetStopTimerSeconds().ToString(); } public void SetText(string text) { if (!IsControlRail()) { return; } BCSRailUnloader unloader = GetUnloader(); if (!TryParseTimerSecondsStrict(text, out var value)) { if (!((Object)(object)unloader != (Object)null) || !unloader.IsUnloadEnabled()) { return; } value = 3; } if ((Object)(object)unloader != (Object)null) { value = unloader.NormalizeStopTimerSeconds(value); } if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.GetZDO() != null) { _nview.InvokeRPC("RPC_SetStopTimerSeconds", new object[1] { value }); } } private static bool TryParseTimerSecondsStrict(string text, out int value) { value = 0; if (string.IsNullOrEmpty(text)) { return false; } foreach (char c in text) { if (c < '0' || c > '9') { value = 0; return false; } int num = c - 48; if (value > (int.MaxValue - num) / 10) { value = 0; return false; } value = value * 10 + num; } return true; } private void RPC_SetStopTimerSeconds(long sender, int seconds) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner() && IsControlRail()) { seconds = Mathf.Max(0, seconds); BCSRailUnloader unloader = GetUnloader(); if ((Object)(object)unloader != (Object)null) { seconds = unloader.NormalizeStopTimerSeconds(seconds); } BCSRailContainerTransfer containerTransfer = GetContainerTransfer(); if ((Object)(object)containerTransfer != (Object)null) { seconds = containerTransfer.NormalizeStopTimerSeconds(seconds); } ZDO validZdo = GetValidZdo(); if (validZdo != null) { validZdo.Set("hl_stop_timer_seconds", seconds); validZdo.Set("hl_stop_timer_end_time", 0f); UpdateVisualStateImmediate(); } } } public int GetStopTimerSeconds() { ZDO validZdo = GetValidZdo(); if (validZdo == null) { return 0; } return Mathf.Max(0, validZdo.GetInt("hl_stop_timer_seconds", 0)); } public void StartStopTimerCountdown(int seconds) { if (!IsControlRail()) { return; } if (seconds <= 0) { ClearStopTimerCountdown(); return; } ZDO validZdo = GetValidZdo(); if (validZdo != null) { ClaimOwnershipIfNeeded(); validZdo.Set("hl_stop_timer_end_time", GetNetworkTimeSeconds() + (float)seconds); } } public void ClearStopTimerCountdown() { ZDO validZdo = GetValidZdo(); if (validZdo != null) { ClaimOwnershipIfNeeded(); validZdo.Set("hl_stop_timer_end_time", 0f); } } public float GetStopTimerRemainingSeconds() { ZDO validZdo = GetValidZdo(); if (validZdo == null) { return 0f; } float @float = validZdo.GetFloat("hl_stop_timer_end_time", 0f); if (@float <= 0f) { return 0f; } return Mathf.Max(0f, @float - GetNetworkTimeSeconds()); } private BCSRailSignalSwitchReceiver GetSignalSwitchReceiverOverride() { BCSRailSignalSwitchReceiver component = ((Component)this).GetComponent(); if ((Object)(object)component == (Object)null || !((Behaviour)component).enabled) { return null; } return component; } public void RefreshVisualStateFromReceiver() { UpdateVisualStateImmediate(); } public void SetStopModeFromReceiver(BCSRailStopMode mode) { if (IsControlRail()) { ClaimOwnershipIfNeeded(); if (mode != BCSRailStopMode.Both && mode != BCSRailStopMode.SideA && mode != BCSRailStopMode.SideB) { mode = BCSRailStopMode.None; } SetStopModeOwned(mode); UpdateVisualStateImmediate(); } } public void SetSwitchDirectionFromReceiver(BCSRailSwitchDirection direction) { if (IsSwitchRail()) { SetSwitchDirection(direction); UpdateVisualStateImmediate(); RefreshAdjacentNeighbors(); } } public bool TryGetClosestDistanceOnRail(Vector3 worldPosition, out float distance, out Vector3 closestPoint) { //IL_000f: 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_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) //IL_00cf: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_00a6: 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) distance = 0f; closestPoint = ((Component)this).transform.position; float length = GetLength(); if (length <= 0.001f) { return false; } float num = 0f; Vector3 val = ((Component)this).transform.position; float num2 = float.MaxValue; for (int i = 0; i <= 32; i++) { float num3 = (float)i / 32f; float num4 = length * num3; if (GetPose(num4, out var pos, out var _)) { Vector3 val2 = pos - worldPosition; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude < num2) { num2 = sqrMagnitude; num = num4; val = pos; } } } distance = Mathf.Clamp(num, 0f, length); closestPoint = val; return true; } public bool TryGetForwardAtDistance(float distance, out Vector3 forward) { //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_002a: 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) forward = ((Component)this).transform.forward; if (!GetPose(distance, out var _, out var rot)) { return false; } forward = rot * Vector3.forward; return ((Vector3)(ref forward)).sqrMagnitude > 0.0001f; } private string GetStopTimerHoverText() { int stopTimerSeconds = GetStopTimerSeconds(); if (stopTimerSeconds <= 0) { return "0"; } float stopTimerRemainingSeconds = GetStopTimerRemainingSeconds(); if (stopTimerRemainingSeconds > 0f) { return Mathf.CeilToInt(stopTimerRemainingSeconds) + "/" + stopTimerSeconds + "s"; } return stopTimerSeconds + "s"; } } public static class BCSRailPrefabConfigurator { public static void Configure(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { Debug.LogWarning((object)"[BCS] ConfigureRail: prefab == null"); return; } BCSRailPiece orAdd = BCSPrefabFind.GetOrAdd(prefab); Smelter component = prefab.GetComponent(); if ((Object)(object)component == (Object)null) { Debug.LogWarning((object)("[BCS] ConfigureRail: Smelter missing on " + ((Object)prefab).name)); return; } ApplyRailDefaults(prefab, orAdd, component); ApplyRailType(prefab, orAdd); ConfigureDisableInPlacementGhost(prefab, orAdd); BCSPrefabFind.DestroyIfExists((Object)(object)component); } private static void ApplyRailDefaults(GameObject prefab, BCSRailPiece rail, Smelter smelter) { Transform val = prefab.transform.Find("mainsnap2"); Transform val2 = prefab.transform.Find("mainsnap1"); rail.m_pieceType = BCSRailPieceType.Straight; rail.m_canSpawnCart = false; rail.m_canAlignAndFlip = false; rail.m_shouldStop = false; rail.m_isControlRail = false; rail.m_isSwitchRail = false; rail.m_isSpeedRail = false; rail.m_pointA = val; rail.m_pointB = val2; rail.m_pointC = null; rail.m_curvePoint = null; rail.m_nodeA = val; rail.m_nodeB = val2; rail.m_nodeC = null; rail.m_switchLeftObject = null; rail.m_switchRightObject = null; rail.m_stopRailObject = smelter.m_enabledObject; rail.m_stopSideAObject = null; rail.m_stopSideBObject = null; rail.m_canSpawnCartObject = smelter.m_disabledObject; rail.m_spawnCartEffect = smelter.m_oreAddedEffects; rail.m_cartActionEffect = smelter.m_oreAddedEffects; rail.m_toggleActionEffect = smelter.m_fuelAddedEffects; rail.m_nodeSearchRadius = 0.5f; rail.m_enableAutoNeighborRefresh = false; rail.m_neighborRefreshInterval = 3f; rail.m_visualRefreshInterval = 1f; rail.m_refreshOnlyWhenOwner = true; rail.m_enableDebugLogs = false; rail.m_enableVerboseNeighborLogs = false; rail.m_enableVerboseSpawnLogs = false; rail.m_enableVisualLogs = false; } private static void ApplyRailType(GameObject prefab, BCSRailPiece rail) { switch (((Object)prefab).name) { case "railtrackSignalStopReceiver_bal": ConfigureSignalStopReceiverRail(prefab, rail); break; case "railtrackDrawbridge6m_bal": case "railtrackDrawbridge8m_bal": case "railtrackDrawbridge10m_bal": ConfigureDrawbridgeRail(prefab, rail); break; case "railtrackControl_bal": ConfigureControlRail(prefab, rail); break; case "railtrackContainer_bal": ConfigureContainerTransferRail(prefab, rail); break; case "railtrackUnload_bal": ConfigureUnloadRail(prefab, rail); break; case "railtrack1m_bal": case "railtrack_bal": case "railtrack4m_bal": case "railtrack8m_bal": rail.m_pieceType = BCSRailPieceType.Straight; break; case "railtrackSpeed_bal": rail.m_pieceType = BCSRailPieceType.Speed; rail.m_isSpeedRail = true; rail.m_speedMultiplier = 1.75f; break; case "railtrackRamp_bal": case "railtrackRamp26short_bal": rail.m_pieceType = BCSRailPieceType.Slope26; break; case "railtrackRamp45short_bal": case "railtrackRamp45_bal": rail.m_pieceType = BCSRailPieceType.Slope45; break; case "railtrackRamp64_bal": rail.m_pieceType = BCSRailPieceType.Slope64; break; case "railtrackCross_bal": ConfigureCrossRail(prefab, rail); break; case "railtrackSwitchMid_bal": case "railtrackSwitchLeft_bal": case "railtrackSwitchRight_bal": ConfigureSwitchRail(prefab, rail); ConfigureSignalSwitchReceiver(prefab); break; case "railtrackTurnLeft15_bal": case "railtrackTurnRight15_bal": case "railtrackTurn15_bal": ConfigureTurnRail(prefab, rail, BCSRailPieceType.Turn15); break; case "railtrackTurnLeft30_bal": case "railtrackTurnRight30_bal": case "railtrackTurn30_bal": ConfigureTurnRail(prefab, rail, BCSRailPieceType.Turn30); break; case "railtrackTurnLeft45_bal": case "railtrackTurnRight45_bal": case "railtrackTurn45_bal": ConfigureTurnRail(prefab, rail, BCSRailPieceType.Turn45); break; case "railtrackJump4m_bal": case "railtrackJump6m_bal": case "railtrackJump8m_bal": ConfigureJumpRail(prefab, rail, BCSJumpRailArcMode.Flat); break; case "railtrackJumpUp4m_bal": case "railtrackJumpUp6m_bal": case "railtrackJumpUp8m_bal": ConfigureJumpRail(prefab, rail, BCSJumpRailArcMode.JumpUp); break; case "railtrackJumpDown4m_bal": case "railtrackJumpDown6m_bal": case "railtrackJumpDown8m_bal": ConfigureJumpRail(prefab, rail, BCSJumpRailArcMode.JumpDown); break; case "railtrackDrop4m_bal": case "railtrackDrop6m_bal": case "railtrackDrop8m_bal": ConfigureJumpRail(prefab, rail, BCSJumpRailArcMode.Drop); break; default: Debug.LogWarning((object)("[BCS] ConfigureRail: unhandled rail prefab: " + ((Object)prefab).name)); break; } } private static void ConfigureControlRail(GameObject prefab, BCSRailPiece rail) { rail.m_pieceType = BCSRailPieceType.Control; rail.m_canSpawnCart = true; rail.m_canAlignAndFlip = true; rail.m_isControlRail = true; rail.m_stopSideAObject = BCSPrefabFind.FindGameObjectDeep(prefab, "stopRailObjectA"); rail.m_stopSideBObject = BCSPrefabFind.FindGameObjectDeep(prefab, "stopRailObjectB"); } private static void ConfigureSignalStopReceiverRail(GameObject prefab, BCSRailPiece rail) { rail.m_pieceType = BCSRailPieceType.Control; rail.m_canSpawnCart = false; rail.m_canAlignAndFlip = false; rail.m_shouldStop = false; rail.m_isControlRail = true; rail.m_isSwitchRail = false; rail.m_isSpeedRail = false; GameObject val = BCSPrefabFind.FindGameObjectDeep(prefab, "stopRailObject") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "StopRailObject") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "stop_active") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "StopActive"); GameObject val2 = BCSPrefabFind.FindGameObjectDeep(prefab, "stopRailObjectA") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "StopRailObjectA") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "stop_side_a") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "StopSideA"); GameObject val3 = BCSPrefabFind.FindGameObjectDeep(prefab, "stopRailObjectB") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "StopRailObjectB") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "stop_side_b") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "StopSideB"); rail.m_stopRailObject = val; rail.m_stopSideAObject = val2; rail.m_stopSideBObject = val3; BCSRailSignalStopReceiver orAdd = BCSPrefabFind.GetOrAdd(prefab); orAdd.m_name = "Signal Stop Rail Receiver"; orAdd.m_defaultEventDuration = 0f; orAdd.m_durationStep = 1f; orAdd.m_minDuration = 0f; orAdd.m_maxDuration = 120f; orAdd.m_signalConfiguredObject = BCSPrefabFind.FindGameObjectDeep(prefab, "signal_configured") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "SignalConfigured"); orAdd.m_signalActiveObject = BCSPrefabFind.FindGameObjectDeep(prefab, "signal_recived") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "signal_recived"); orAdd.m_stopActiveObject = val; orAdd.m_stopSideAObject = val2; orAdd.m_stopSideBObject = val3; orAdd.m_stopInactiveObject = BCSPrefabFind.FindGameObjectDeep(prefab, "signal_inactive") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "SignalInactive") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "stop_inactive") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "StopInactive"); ConfigureDisableInPlacementGhost(prefab, (Behaviour)(object)orAdd); if ((Object)(object)val2 == (Object)null) { Debug.LogWarning((object)("[BCS] ConfigureSignalStopReceiverRail: missing stopRailObjectA/StopSideA on " + ((Object)prefab).name)); } if ((Object)(object)val3 == (Object)null) { Debug.LogWarning((object)("[BCS] ConfigureSignalStopReceiverRail: missing stopRailObjectB/StopSideB on " + ((Object)prefab).name)); } } private static void ConfigureSignalSwitchReceiver(GameObject prefab) { BCSRailSignalSwitchReceiver orAdd = BCSPrefabFind.GetOrAdd(prefab); orAdd.m_name = "Signal Switch Receiver"; orAdd.m_defaultEventDuration = 0f; orAdd.m_durationStep = 1f; orAdd.m_minDuration = 0f; orAdd.m_maxDuration = 120f; orAdd.m_signalConfiguredObject = BCSPrefabFind.FindGameObjectDeep(prefab, "signal_configured") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "SignalConfigured"); orAdd.m_signalActiveObject = BCSPrefabFind.FindGameObjectDeep(prefab, "signal_recived") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "signal_recived"); ConfigureDisableInPlacementGhost(prefab, (Behaviour)(object)orAdd); } private static void ConfigureSwitchRail(GameObject prefab, BCSRailPiece rail) { rail.m_pieceType = BCSRailPieceType.Straight; rail.m_isSwitchRail = true; rail.m_isControlRail = false; rail.m_canSpawnCart = false; rail.m_canAlignAndFlip = false; rail.m_pointA = prefab.transform.Find("mainsnap1"); rail.m_pointB = prefab.transform.Find("mainsnap2"); rail.m_pointC = prefab.transform.Find("mainsnap3"); rail.m_curvePoint = prefab.transform.Find("mainsnap4"); rail.m_nodeA = rail.m_pointA; rail.m_nodeB = rail.m_pointB; rail.m_nodeC = rail.m_pointC; rail.m_switchLeftObject = BCSPrefabFind.FindGameObjectDeep(prefab, "SwitchLeft") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "switch_left") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "Switch_Left") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "switchLeft") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "Straight") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "switch_straight"); rail.m_switchRightObject = BCSPrefabFind.FindGameObjectDeep(prefab, "SwitchRight") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "switch_right") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "Switch_Right") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "switchRight") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "Branch") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "switch_branch"); if ((Object)(object)rail.m_switchLeftObject == (Object)null) { Debug.LogWarning((object)("[BCS] ConfigureSwitchRail: missing SwitchLeft visual on " + ((Object)prefab).name)); } if ((Object)(object)rail.m_switchRightObject == (Object)null) { Debug.LogWarning((object)("[BCS] ConfigureSwitchRail: missing SwitchRight visual on " + ((Object)prefab).name)); } } private static void ConfigureCrossRail(GameObject prefab, BCSRailPiece rail) { rail.m_pieceType = BCSRailPieceType.Crossroad; rail.m_pointA = prefab.transform.Find("mainsnap1"); rail.m_pointB = prefab.transform.Find("mainsnap2"); rail.m_pointC = prefab.transform.Find("mainsnap3"); rail.m_curvePoint = prefab.transform.Find("mainsnap4"); rail.m_nodeA = rail.m_pointA; rail.m_nodeB = rail.m_pointB; rail.m_nodeC = rail.m_pointC; } private static void ConfigureTurnRail(GameObject prefab, BCSRailPiece rail, BCSRailPieceType type) { rail.m_pieceType = type; rail.m_pointA = prefab.transform.Find("mainsnap1"); rail.m_pointB = prefab.transform.Find("mainsnap2"); rail.m_pointC = null; rail.m_curvePoint = prefab.transform.Find("mainsnap4"); rail.m_nodeA = rail.m_pointA; rail.m_nodeB = rail.m_pointB; rail.m_nodeC = null; } private static void ConfigureJumpRail(GameObject prefab, BCSRailPiece rail, BCSJumpRailArcMode arcMode) { rail.m_pieceType = BCSRailPieceType.Jump; rail.m_jumpArcMode = arcMode; rail.m_pointA = prefab.transform.Find("mainsnap1"); rail.m_pointB = prefab.transform.Find("mainsnap2"); rail.m_pointC = prefab.transform.Find("mainsnap3"); rail.m_curvePoint = prefab.transform.Find("mainsnap4"); rail.m_nodeA = rail.m_pointA; rail.m_nodeB = rail.m_pointB; rail.m_nodeC = null; } private static void ConfigureDrawbridgeRail(GameObject prefab, BCSRailPiece rail) { //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) rail.m_pieceType = BCSRailPieceType.Drawbridge; rail.m_canSpawnCart = false; rail.m_canAlignAndFlip = false; rail.m_shouldStop = false; rail.m_isControlRail = false; rail.m_isSwitchRail = false; rail.m_isSpeedRail = false; rail.m_pointA = prefab.transform.Find("mainsnap1"); rail.m_pointB = prefab.transform.Find("mainsnap2"); rail.m_pointC = prefab.transform.Find("mainsnap3"); rail.m_curvePoint = prefab.transform.Find("mainsnap4"); rail.m_nodeA = rail.m_pointA; rail.m_nodeB = rail.m_pointB; rail.m_nodeC = null; rail.m_switchLeftObject = null; rail.m_switchRightObject = null; rail.m_stopSideAObject = null; rail.m_stopSideBObject = null; BCSDrawbridgeRail orAdd = BCSPrefabFind.GetOrAdd(prefab); orAdd.m_animationActiveObject = BCSPrefabFind.FindGameObjectDeep(prefab, "drawbridge_animation_audio"); Door component = prefab.GetComponent(); if ((Object)(object)component != (Object)null) { orAdd.m_openStartEffects = component.m_openEffects; orAdd.m_closeStartEffects = component.m_closeEffects; BCSPrefabFind.DestroyIfExists((Object)(object)component); } orAdd.m_enabled = true; orAdd.m_stopMargin = 1f; orAdd.m_animationSeconds = 3f; orAdd.m_raisedAngle = 70f; orAdd.m_leftPivotC = BCSPrefabFind.FindTransformDeep(prefab, "bridge_left_pivot_C"); orAdd.m_rightPivotD = BCSPrefabFind.FindTransformDeep(prefab, "bridge_right_pivot_D"); orAdd.m_gearCStatic = BCSPrefabFind.FindTransformDeep(prefab, "gear_C_static"); orAdd.m_gearCBridge = BCSPrefabFind.FindTransformDeep(prefab, "gear_C_bridge"); orAdd.m_gearDStatic = BCSPrefabFind.FindTransformDeep(prefab, "gear_D_static"); orAdd.m_gearDBridge = BCSPrefabFind.FindTransformDeep(prefab, "gear_D_bridge"); orAdd.m_gearDegreesPerBridgeDegree = 4f; orAdd.m_leftLeafAxis = Vector3.right; orAdd.m_rightLeafAxis = Vector3.right; orAdd.m_gearAxis = Vector3.right; orAdd.m_debugLogs = false; ConfigureDisableInPlacementGhost(prefab, (Behaviour)(object)orAdd); } private static void ConfigureUnloadRail(GameObject prefab, BCSRailPiece rail) { rail.m_pieceType = BCSRailPieceType.Control; rail.m_canSpawnCart = false; rail.m_canAlignAndFlip = false; rail.m_shouldStop = false; rail.m_isControlRail = true; rail.m_isSwitchRail = false; rail.m_stopSideAObject = BCSPrefabFind.FindGameObjectDeep(prefab, "stopRailObjectA"); rail.m_stopSideBObject = BCSPrefabFind.FindGameObjectDeep(prefab, "stopRailObjectB"); BCSRailUnloader orAdd = BCSPrefabFind.GetOrAdd(prefab); orAdd.m_defaultUnloadFilter = BCSRailUnloadFilter.None; orAdd.m_unloadFinishBeforeStopEnd = 1f; orAdd.m_minUnloadInterval = 0.02f; orAdd.m_maxUnloadInterval = 1f; orAdd.m_activeObject = BCSPrefabFind.FindGameObjectDeep(prefab, "UnloadActive"); orAdd.m_inactiveObject = BCSPrefabFind.FindGameObjectDeep(prefab, "UnloadInactive"); GameObject val = BCSPrefabFind.FindGameObjectDeep(prefab, "UnloadSpawn"); orAdd.m_spawnPoint = (((Object)(object)val != (Object)null) ? val.transform : null); orAdd.m_spawnRadius = 0.12f; orAdd.m_spawnUpOffset = 0.05f; orAdd.UpdateVisualState(); } private static void ConfigureContainerTransferRail(GameObject prefab, BCSRailPiece rail) { rail.m_pieceType = BCSRailPieceType.Control; rail.m_canSpawnCart = false; rail.m_canAlignAndFlip = false; rail.m_shouldStop = false; rail.m_isControlRail = true; rail.m_isSwitchRail = false; rail.m_stopSideAObject = BCSPrefabFind.FindGameObjectDeep(prefab, "stopRailObjectA"); rail.m_stopSideBObject = BCSPrefabFind.FindGameObjectDeep(prefab, "stopRailObjectB"); BCSRailContainerTransfer orAdd = BCSPrefabFind.GetOrAdd(prefab); orAdd.m_defaultMode = BCSRailContainerTransferMode.None; orAdd.m_defaultFilter = BCSRailUnloadFilter.All; orAdd.m_container = prefab.GetComponentInChildren(true); } private static void ConfigureDisableInPlacementGhost(GameObject prefab, BCSRailPiece rail) { if (!((Object)(object)prefab == (Object)null) && !((Object)(object)rail == (Object)null)) { ConfigureDisableInPlacementGhost(prefab, (Behaviour)(object)rail); AddGhostDisabledComponent(prefab, (Behaviour)(object)prefab.GetComponent()); AddGhostDisabledComponent(prefab, (Behaviour)(object)prefab.GetComponent()); AddGhostDisabledComponent(prefab, (Behaviour)(object)prefab.GetComponent()); AddGhostDisabledComponent(prefab, (Behaviour)(object)prefab.GetComponent()); AddGhostDisabledComponent(prefab, (Behaviour)(object)prefab.GetComponent()); } } private static void ConfigureDisableInPlacementGhost(GameObject prefab, Behaviour behaviour) { if (!((Object)(object)prefab == (Object)null) && !((Object)(object)behaviour == (Object)null)) { DisableInPlacementGhost val = prefab.GetComponent(); if ((Object)(object)val == (Object)null) { val = prefab.AddComponent(); } if (val.m_components == null) { val.m_components = new List(); } if (!val.m_components.Contains(behaviour)) { val.m_components.Add(behaviour); } } } private static void AddGhostDisabledComponent(GameObject prefab, Behaviour behaviour) { if ((Object)(object)behaviour != (Object)null) { ConfigureDisableInPlacementGhost(prefab, behaviour); } } } public static class BCSRailRegistry { private static readonly Dictionary RailsById = new Dictionary(); private static readonly List RemoveKeysScratch = new List(64); public static void Register(BCSRailPiece rail) { if (IsValidRail(rail)) { string railId = rail.GetRailId(); if (!string.IsNullOrEmpty(railId)) { RailsById[railId] = rail; } } } public static void Unregister(BCSRailPiece rail) { if (!((Object)(object)rail == (Object)null)) { string railId = rail.GetRailId(); if (!string.IsNullOrEmpty(railId) && RailsById.TryGetValue(railId, out var value) && (Object)(object)value == (Object)(object)rail) { RailsById.Remove(railId); } } } public static BCSRailPiece FindById(string railId) { if (string.IsNullOrEmpty(railId)) { return null; } if (!RailsById.TryGetValue(railId, out var value)) { return null; } if (!IsValidRail(value)) { RailsById.Remove(railId); return null; } return value; } public static ICollection GetAll() { CleanupInvalidReferences(); return RailsById.Values; } public static void FillAll(List result) { if (result == null) { return; } result.Clear(); CleanupInvalidReferences(); foreach (BCSRailPiece value in RailsById.Values) { if ((Object)(object)value != (Object)null) { result.Add(value); } } } public static void CleanupInvalidReferences() { RemoveKeysScratch.Clear(); foreach (KeyValuePair item in RailsById) { if (!IsValidRail(item.Value)) { RemoveKeysScratch.Add(item.Key); } } for (int i = 0; i < RemoveKeysScratch.Count; i++) { RailsById.Remove(RemoveKeysScratch[i]); } RemoveKeysScratch.Clear(); } public static void ClearAll() { RailsById.Clear(); RemoveKeysScratch.Clear(); } private static bool IsValidRail(BCSRailPiece rail) { if ((Object)(object)rail == (Object)null) { return false; } try { if (!((Component)rail).gameObject.activeInHierarchy) { return false; } ZNetView component = ((Component)rail).GetComponent(); return (Object)(object)component != (Object)null && component.IsValid() && component.GetZDO() != null; } catch { return false; } } } public class BCSRailSignalStopReceiver : MonoBehaviour, Hoverable, Interactable, TextReceiver, IBCSSignalReceiver { private const string RpcSetSignalName = "RPC_SetSignalName"; private const string RpcSetDefaultStopMode = "RPC_SetDefaultStopMode"; private const string RpcSetEventStopMode = "RPC_SetEventStopMode"; private const string RpcSetDuration = "RPC_SetDuration"; private const string RpcSignalStart = "RPC_SignalStart"; private const string RpcSignalStop = "RPC_SignalStop"; private const string ZdoDefaultStopMode = "hl_signal_rail_stop_default_mode"; private const string ZdoEventStopMode = "hl_signal_rail_stop_event_mode"; public string m_name = "Signal Stop Rail Receiver"; [Header("Duration")] public float m_defaultEventDuration = 0f; public float m_durationStep = 1f; public float m_minDuration = 0f; public float m_maxDuration = 120f; [Header("Visuals")] public GameObject m_signalConfiguredObject; public GameObject m_signalActiveObject; public GameObject m_stopActiveObject; public GameObject m_stopInactiveObject; public GameObject m_stopSideAObject; public GameObject m_stopSideBObject; private ZNetView _nview; private BCSRailPiece _rail; private readonly HashSet _activeEmitterIds = new HashSet(); private readonly Dictionary _emitterDurationRoutines = new Dictionary(); private float _lastHoverTime = -1000f; private BCSRailStopMode _lastAppliedMode = (BCSRailStopMode)(-1); private float _nextVisualSyncTime; private const float VisualSyncInterval = 0.2f; private bool _visualInitialized; private bool _lastHasSignal; private bool _lastSignalActive; private bool _lastStopActive; private BCSRailStopMode _lastVisualMode = (BCSRailStopMode)(-1); private void Awake() { _nview = ((Component)this).GetComponent(); _rail = ((Component)this).GetComponent(); if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || (Object)(object)_rail == (Object)null) { ((Behaviour)this).enabled = false; return; } _nview.Register("RPC_SetSignalName", (Action)RPC_SetSignalName); _nview.Register("RPC_SetDefaultStopMode", (Action)RPC_SetDefaultStopMode); _nview.Register("RPC_SetEventStopMode", (Action)RPC_SetEventStopMode); _nview.Register("RPC_SetDuration", (Action)RPC_SetDuration); _nview.Register("RPC_SignalStart", (Action)RPC_SignalStart); _nview.Register("RPC_SignalStop", (Action)RPC_SignalStop); ApplyCurrentState(); } private void OnEnable() { if ((Object)(object)_nview == (Object)null) { _nview = ((Component)this).GetComponent(); } if ((Object)(object)_rail == (Object)null) { _rail = ((Component)this).GetComponent(); } if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && !((Object)(object)_rail == (Object)null)) { BCSSignalRegistry.RegisterReceiver(this); BCSSignalRegistry.InvalidateAllEmitterCaches(); ApplyVisualState(GetCurrentStopMode()); } } private void OnDisable() { BCSSignalRegistry.UnregisterReceiver(this); ClearActiveEmitters(); } private void OnDestroy() { BCSSignalRegistry.UnregisterReceiver(this); ClearActiveEmitters(); } private void Update() { HandleDurationInput(); if (!(Time.time < _nextVisualSyncTime)) { _nextVisualSyncTime = Time.time + 0.2f; BCSRailStopMode currentStopMode = GetCurrentStopMode(); if (currentStopMode != _lastAppliedMode) { ApplyVisualState(currentStopMode); } } } public void RequestSignalStart(string signalName, string emitterId) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { _nview.InvokeRPC("RPC_SignalStart", new object[2] { signalName ?? string.Empty, emitterId ?? string.Empty }); } } public void RequestSignalStop(string signalName, string emitterId) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { _nview.InvokeRPC("RPC_SignalStop", new object[2] { signalName ?? string.Empty, emitterId ?? string.Empty }); } } private void RPC_SignalStart(long sender, string signalName, string emitterId) { if (SignalMatches(signalName) && !string.IsNullOrEmpty(emitterId)) { bool flag = !IsEventActive(); _activeEmitterIds.Add(emitterId); float eventDuration = GetEventDuration(); if (eventDuration > 0f) { StopEmitterDurationRoutine(emitterId); _emitterDurationRoutines[emitterId] = ((MonoBehaviour)this).StartCoroutine(EventDurationRoutine(eventDuration, emitterId)); } if (flag) { ApplyEventState(); } } } private void RPC_SignalStop(long sender, string signalName, string emitterId) { if (SignalMatches(signalName) && !string.IsNullOrEmpty(emitterId) && IsEventActive() && !(GetEventDuration() > 0f)) { RemoveActiveEmitter(emitterId, stopRoutine: true); } } private IEnumerator EventDurationRoutine(float duration, string emitterId) { yield return (object)new WaitForSeconds(duration); RemoveActiveEmitter(emitterId, stopRoutine: false); } private void RemoveActiveEmitter(string emitterId, bool stopRoutine) { if (!string.IsNullOrEmpty(emitterId)) { if (stopRoutine) { StopEmitterDurationRoutine(emitterId); } else { _emitterDurationRoutines.Remove(emitterId); } _activeEmitterIds.Remove(emitterId); if (_activeEmitterIds.Count <= 0) { ApplyDefaultState(); } } } private void StopEmitterDurationRoutine(string emitterId) { if (_emitterDurationRoutines.TryGetValue(emitterId, out var value) && value != null) { ((MonoBehaviour)this).StopCoroutine(value); } _emitterDurationRoutines.Remove(emitterId); } private bool IsEventActive() { return _activeEmitterIds.Count > 0; } private void ClearActiveEmitters() { foreach (KeyValuePair emitterDurationRoutine in _emitterDurationRoutines) { if (emitterDurationRoutine.Value != null) { ((MonoBehaviour)this).StopCoroutine(emitterDurationRoutine.Value); } } _emitterDurationRoutines.Clear(); _activeEmitterIds.Clear(); } private void ApplyDefaultState() { SetCurrentStopModeOwned(GetDefaultStopMode()); } private void ApplyEventState() { SetCurrentStopModeOwned(GetEventStopMode()); } private void ApplyCurrentState() { if (IsEventActive()) { ApplyEventState(); } else { ApplyDefaultState(); } ApplyVisualState(GetCurrentStopMode()); } private void SetCurrentStopModeOwned(BCSRailStopMode mode) { mode = ClampStopMode(mode); if ((Object)(object)_rail == (Object)null) { _rail = ((Component)this).GetComponent(); } if ((Object)(object)_rail != (Object)null) { _rail.SetStopModeFromReceiver(mode); } ApplyVisualState(mode); } public bool ShouldStopForEntrySide(BCSRailNodeSide entrySide) { if ((Object)(object)_rail == (Object)null) { _rail = ((Component)this).GetComponent(); } return (Object)(object)_rail != (Object)null && _rail.ShouldStopForEntrySide(entrySide); } public bool IsStopActive() { return GetCurrentStopMode() != BCSRailStopMode.None; } public BCSRailStopMode GetCurrentStopMode() { if ((Object)(object)_rail != (Object)null) { return _rail.GetStopMode(); } return GetDefaultStopMode(); } private void ApplyVisualState(BCSRailStopMode mode) { mode = ClampStopMode(mode); _lastAppliedMode = mode; bool flag = !string.IsNullOrEmpty(GetSignalName()); bool flag2 = flag && IsEventActive(); bool flag3 = mode != BCSRailStopMode.None; if (!_visualInitialized || _lastVisualMode != mode || _lastHasSignal != flag || _lastSignalActive != flag2 || _lastStopActive != flag3) { _visualInitialized = true; _lastVisualMode = mode; _lastHasSignal = flag; _lastSignalActive = flag2; _lastStopActive = flag3; bool flag4 = flag && !flag2; bool flag5 = flag2; bool flag6 = flag3 && mode == BCSRailStopMode.Both; bool flag7 = !flag3; bool flag8 = flag3 && mode == BCSRailStopMode.SideA; bool flag9 = flag3 && mode == BCSRailStopMode.SideB; if ((Object)(object)m_signalConfiguredObject != (Object)null && m_signalConfiguredObject.activeSelf != flag4) { m_signalConfiguredObject.SetActive(flag4); } if ((Object)(object)m_signalActiveObject != (Object)null && m_signalActiveObject.activeSelf != flag5) { m_signalActiveObject.SetActive(flag5); } if ((Object)(object)m_stopActiveObject != (Object)null && m_stopActiveObject.activeSelf != flag6) { m_stopActiveObject.SetActive(flag6); } if ((Object)(object)m_stopInactiveObject != (Object)null && m_stopInactiveObject.activeSelf != flag7) { m_stopInactiveObject.SetActive(flag7); } if ((Object)(object)m_stopSideAObject != (Object)null && m_stopSideAObject.activeSelf != flag8) { m_stopSideAObject.SetActive(flag8); } if ((Object)(object)m_stopSideBObject != (Object)null && m_stopSideBObject.activeSelf != flag9) { m_stopSideBObject.SetActive(flag9); } if ((Object)(object)_rail != (Object)null) { _rail.RefreshVisualStateFromReceiver(); } } } public string GetHoverName() { return m_name; } public string GetHoverText() { _lastHoverTime = Time.time; string value = (string.IsNullOrEmpty(GetSignalName()) ? "NULL" : GetSignalName()); StringBuilder stringBuilder = new StringBuilder(256); stringBuilder.Append(m_name); stringBuilder.Append("\n[$KEY_Use] Signal: ").Append(value); stringBuilder.Append("\n[Shift+$KEY_Use] Default: ").Append(GetStopModeText(GetDefaultStopMode())); stringBuilder.Append("\n[Alt+$KEY_Use] Event: ").Append(GetStopModeText(GetEventStopMode())); stringBuilder.Append("\n[+ / -] Duration: ").Append(GetEventDuration().ToString("0")).Append("s"); stringBuilder.Append("\nCurrent: ").Append(GetStopModeText(GetCurrentStopMode())); return (Localization.instance != null) ? Localization.instance.Localize(stringBuilder.ToString()) : stringBuilder.ToString(); } public bool Interact(Humanoid human, bool hold, bool alt) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (hold) { return false; } Player val = (Player)(object)((human is Player) ? human : null); if ((Object)(object)val == (Object)null) { return false; } if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return true; } if (IsShiftHeld()) { BCSRailStopMode nextStopMode = GetNextStopMode(GetDefaultStopMode()); SetDefaultStopMode(nextStopMode); ((Character)val).Message((MessageType)2, "Default: " + GetStopModeText(nextStopMode), 0, (Sprite)null); return true; } if (IsAltHeld()) { BCSRailStopMode nextStopMode2 = GetNextStopMode(GetEventStopMode()); SetEventStopMode(nextStopMode2); ((Character)val).Message((MessageType)2, "Event: " + GetStopModeText(nextStopMode2), 0, (Sprite)null); return true; } if ((Object)(object)TextInput.instance == (Object)null) { ((Character)val).Message((MessageType)2, "Text input unavailable", 0, (Sprite)null); return true; } TextInput.instance.RequestText((TextReceiver)(object)this, "Signal name", 32); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public string GetText() { return GetSignalName(); } public void SetText(string text) { SetSignalName((text == null) ? string.Empty : text.Trim()); } private void SetSignalName(string signalName) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetSignalName", new object[1] { signalName ?? string.Empty }); } } private void SetDefaultStopMode(BCSRailStopMode mode) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetDefaultStopMode", new object[1] { (int)ClampStopMode(mode) }); } } private void SetEventStopMode(BCSRailStopMode mode) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetEventStopMode", new object[1] { (int)ClampStopMode(mode) }); } } private void SetDuration(float duration) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetDuration", new object[1] { Mathf.Clamp(duration, m_minDuration, m_maxDuration) }); } } private void RPC_SetSignalName(long sender, string value) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { _nview.GetZDO().Set("hl_signal_name", value ?? string.Empty); ClearActiveEmitters(); ApplyDefaultState(); BCSSignalRegistry.InvalidateAllEmitterCaches(); } } private void RPC_SetDefaultStopMode(long sender, int rawMode) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { BCSRailStopMode bCSRailStopMode = ClampStopMode((BCSRailStopMode)rawMode); _nview.GetZDO().Set("hl_signal_rail_stop_default_mode", (int)bCSRailStopMode); if (!IsEventActive()) { ApplyDefaultState(); } } } private void RPC_SetEventStopMode(long sender, int rawMode) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { BCSRailStopMode bCSRailStopMode = ClampStopMode((BCSRailStopMode)rawMode); _nview.GetZDO().Set("hl_signal_rail_stop_event_mode", (int)bCSRailStopMode); if (IsEventActive()) { ApplyEventState(); } } } private void RPC_SetDuration(long sender, float value) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { _nview.GetZDO().Set("hl_signal_event_duration", Mathf.Clamp(value, m_minDuration, m_maxDuration)); } } private void HandleDurationInput() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!(Time.time - _lastHoverTime > 0.25f) && PrivateArea.CheckAccess(((Component)this).transform.position, 0f, false, false)) { if (Input.GetKeyDown((KeyCode)61) || Input.GetKeyDown((KeyCode)270)) { SetDuration(GetEventDuration() + m_durationStep); } if (Input.GetKeyDown((KeyCode)45) || Input.GetKeyDown((KeyCode)269)) { SetDuration(GetEventDuration() - m_durationStep); } } } private bool SignalMatches(string signalName) { string signalName2 = GetSignalName(); return !string.IsNullOrEmpty(signalName2) && string.Equals(signalName2, signalName, StringComparison.Ordinal); } public string GetSignalName() { return ((Object)(object)_nview != (Object)null && _nview.IsValid()) ? _nview.GetZDO().GetString("hl_signal_name", string.Empty) : string.Empty; } public Transform GetSignalTransform() { return ((Component)this).transform; } public ZNetView GetSignalNetView() { return _nview; } public BCSRailStopMode GetDefaultStopMode() { if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { return BCSRailStopMode.None; } return ClampStopMode((BCSRailStopMode)_nview.GetZDO().GetInt("hl_signal_rail_stop_default_mode", 0)); } public BCSRailStopMode GetEventStopMode() { if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { return BCSRailStopMode.Both; } return ClampStopMode((BCSRailStopMode)_nview.GetZDO().GetInt("hl_signal_rail_stop_event_mode", 1)); } public float GetEventDuration() { return ((Object)(object)_nview != (Object)null && _nview.IsValid()) ? Mathf.Clamp(_nview.GetZDO().GetFloat("hl_signal_event_duration", m_defaultEventDuration), m_minDuration, m_maxDuration) : m_defaultEventDuration; } private static BCSRailStopMode GetNextStopMode(BCSRailStopMode current) { return current switch { BCSRailStopMode.None => BCSRailStopMode.Both, BCSRailStopMode.Both => BCSRailStopMode.SideA, BCSRailStopMode.SideA => BCSRailStopMode.SideB, _ => BCSRailStopMode.None, }; } private static BCSRailStopMode ClampStopMode(BCSRailStopMode mode) { return mode switch { BCSRailStopMode.Both => BCSRailStopMode.Both, BCSRailStopMode.SideA => BCSRailStopMode.SideA, BCSRailStopMode.SideB => BCSRailStopMode.SideB, _ => BCSRailStopMode.None, }; } private static string GetStopModeText(BCSRailStopMode mode) { return mode switch { BCSRailStopMode.Both => "Both", BCSRailStopMode.SideA => "Side A", BCSRailStopMode.SideB => "Side B", _ => "None", }; } private static bool IsShiftHeld() { return Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303); } private static bool IsAltHeld() { return Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307); } } public class BCSRailSignalSwitchReceiver : MonoBehaviour, Hoverable, Interactable, TextReceiver, IBCSSignalReceiver { private const string RpcSetSignalName = "RPC_SetSignalName"; private const string RpcSetDefaultDirection = "RPC_SetDefaultDirection"; private const string RpcSetEventDirection = "RPC_SetEventDirection"; private const string RpcSetDuration = "RPC_SetDuration"; private const string RpcSignalStart = "RPC_SignalStart"; private const string RpcSignalStop = "RPC_SignalStop"; private const string RpcManualToggleFromCart = "RPC_ManualToggleFromCart"; public string m_name = "Signal Switch Rail Receiver"; public float m_defaultEventDuration = 0f; public float m_durationStep = 1f; public float m_minDuration = 0f; public float m_maxDuration = 120f; public GameObject m_signalConfiguredObject; public GameObject m_signalActiveObject; private ZNetView _nview; private BCSRailPiece _rail; private readonly HashSet _activeEmitterIds = new HashSet(); private readonly Dictionary _emitterDurationRoutines = new Dictionary(); private float _nextVisualSyncTime; private const float VisualSyncInterval = 0.2f; private bool _visualInitialized; private bool _lastHasSignal; private bool _lastSignalActive; private float _lastHoverTime = -1000f; private void Awake() { _nview = ((Component)this).GetComponent(); _rail = ((Component)this).GetComponent(); if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || (Object)(object)_rail == (Object)null || !_rail.IsSwitchRail()) { ((Behaviour)this).enabled = false; return; } _nview.Register("RPC_SetSignalName", (Action)RPC_SetSignalName); _nview.Register("RPC_SetDefaultDirection", (Action)RPC_SetDefaultDirection); _nview.Register("RPC_SetEventDirection", (Action)RPC_SetEventDirection); _nview.Register("RPC_SetDuration", (Action)RPC_SetDuration); _nview.Register("RPC_SignalStart", (Action)RPC_SignalStart); _nview.Register("RPC_SignalStop", (Action)RPC_SignalStop); _nview.Register("RPC_ManualToggleFromCart", (Action)RPC_ManualToggleFromCart); ApplyDefaultState(); UpdateVisuals(); } private void OnEnable() { if ((Object)(object)_nview == (Object)null) { _nview = ((Component)this).GetComponent(); } if ((Object)(object)_rail == (Object)null) { _rail = ((Component)this).GetComponent(); } if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && !((Object)(object)_rail == (Object)null) && _rail.IsSwitchRail()) { BCSSignalRegistry.RegisterReceiver(this); BCSSignalRegistry.InvalidateAllEmitterCaches(); UpdateVisuals(); } } private void OnDisable() { BCSSignalRegistry.UnregisterReceiver(this); ClearActiveEmitters(); } private void OnDestroy() { BCSSignalRegistry.UnregisterReceiver(this); ClearActiveEmitters(); } private void Update() { HandleDurationInput(); if (!(Time.time < _nextVisualSyncTime)) { _nextVisualSyncTime = Time.time + 0.2f; UpdateVisuals(); } } public void RequestSignalStart(string signalName, string emitterId) { if ((Object)(object)_nview != (Object)null && _nview.IsValid()) { _nview.InvokeRPC("RPC_SignalStart", new object[2] { signalName ?? string.Empty, emitterId ?? string.Empty }); } } public void RequestSignalStop(string signalName, string emitterId) { if ((Object)(object)_nview != (Object)null && _nview.IsValid()) { _nview.InvokeRPC("RPC_SignalStop", new object[2] { signalName ?? string.Empty, emitterId ?? string.Empty }); } } public bool RequestManualToggleFromCart() { if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { return false; } _nview.InvokeRPC("RPC_ManualToggleFromCart", Array.Empty()); return true; } private void RPC_ManualToggleFromCart(long sender) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner() && !((Object)(object)_rail == (Object)null) && _rail.IsSwitchRail()) { BCSRailSwitchDirection opposite = GetOpposite(_rail.GetSwitchDirection()); ApplyDirection(opposite); } } private void RPC_SignalStart(long sender, string signalName, string emitterId) { if (SignalMatches(signalName) && !string.IsNullOrEmpty(emitterId)) { bool flag = !IsEventActive(); _activeEmitterIds.Add(emitterId); float eventDuration = GetEventDuration(); if (eventDuration > 0f) { StopEmitterDurationRoutine(emitterId); _emitterDurationRoutines[emitterId] = ((MonoBehaviour)this).StartCoroutine(EventDurationRoutine(eventDuration, emitterId)); } if (flag) { ApplyEventState(); } else { ApplyDirection(GetEventDirection()); } } } private void RPC_SignalStop(long sender, string signalName, string emitterId) { if (SignalMatches(signalName) && !string.IsNullOrEmpty(emitterId) && IsEventActive() && !(GetEventDuration() > 0f)) { RemoveActiveEmitter(emitterId, stopRoutine: true); } } private IEnumerator EventDurationRoutine(float duration, string emitterId) { yield return (object)new WaitForSeconds(duration); RemoveActiveEmitter(emitterId, stopRoutine: false); } private void RemoveActiveEmitter(string emitterId, bool stopRoutine) { if (!string.IsNullOrEmpty(emitterId)) { if (stopRoutine) { StopEmitterDurationRoutine(emitterId); } else { _emitterDurationRoutines.Remove(emitterId); } _activeEmitterIds.Remove(emitterId); if (_activeEmitterIds.Count == 0) { ApplyDefaultState(); } } } private void StopEmitterDurationRoutine(string emitterId) { if (_emitterDurationRoutines.TryGetValue(emitterId, out var value) && value != null) { ((MonoBehaviour)this).StopCoroutine(value); } _emitterDurationRoutines.Remove(emitterId); } private bool IsEventActive() { return _activeEmitterIds.Count > 0; } private void ClearActiveEmitters() { foreach (KeyValuePair emitterDurationRoutine in _emitterDurationRoutines) { if (emitterDurationRoutine.Value != null) { ((MonoBehaviour)this).StopCoroutine(emitterDurationRoutine.Value); } } _emitterDurationRoutines.Clear(); _activeEmitterIds.Clear(); } private void ApplyDefaultState() { ApplyDirection(GetDefaultDirection()); } private void ApplyEventState() { ApplyDirection(GetEventDirection()); } private void ApplyDirection(BCSRailSwitchDirection direction) { if ((Object)(object)_rail == (Object)null) { _rail = ((Component)this).GetComponent(); } if (!((Object)(object)_rail == (Object)null) && _rail.IsSwitchRail()) { _rail.SetSwitchDirectionFromReceiver(direction); UpdateVisuals(); } } public string GetHoverName() { return m_name; } public string GetHoverText() { _lastHoverTime = Time.time; string value = (string.IsNullOrEmpty(GetSignalName()) ? "NULL" : GetSignalName()); StringBuilder stringBuilder = new StringBuilder(256); stringBuilder.Append(m_name); stringBuilder.Append("\n[$KEY_Use] Signal: ").Append(value); stringBuilder.Append("\n[Shift+$KEY_Use] Default: ").Append(GetDirectionText(GetDefaultDirection())); stringBuilder.Append("\n[Alt+$KEY_Use] Event: ").Append(GetDirectionText(GetEventDirection())); stringBuilder.Append("\n[+ / -] Duration: ").Append(GetEventDuration().ToString("0")).Append("s"); if ((Object)(object)_rail != (Object)null) { stringBuilder.Append("\nCurrent: ").Append(GetDirectionText(_rail.GetSwitchDirection())); } return (Localization.instance != null) ? Localization.instance.Localize(stringBuilder.ToString()) : stringBuilder.ToString(); } public bool Interact(Humanoid human, bool hold, bool alt) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (hold) { return false; } Player val = (Player)(object)((human is Player) ? human : null); if ((Object)(object)val == (Object)null) { return false; } if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return true; } if (IsShiftHeld()) { BCSRailSwitchDirection opposite = GetOpposite(GetDefaultDirection()); SetDefaultDirection(opposite); ((Character)val).Message((MessageType)2, "Default switch: " + GetDirectionText(opposite), 0, (Sprite)null); return true; } if (IsAltHeld()) { BCSRailSwitchDirection opposite2 = GetOpposite(GetEventDirection()); SetEventDirection(opposite2); ((Character)val).Message((MessageType)2, "Event switch: " + GetDirectionText(opposite2), 0, (Sprite)null); return true; } if ((Object)(object)TextInput.instance == (Object)null) { ((Character)val).Message((MessageType)2, "Text input unavailable", 0, (Sprite)null); return true; } TextInput.instance.RequestText((TextReceiver)(object)this, "Signal name", 32); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public string GetText() { return GetSignalName(); } public void SetText(string text) { SetSignalName((text == null) ? string.Empty : text.Trim()); } private void SetSignalName(string signalName) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetSignalName", new object[1] { signalName ?? string.Empty }); } } private void SetDefaultDirection(BCSRailSwitchDirection direction) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetDefaultDirection", new object[1] { (int)direction }); } } private void SetEventDirection(BCSRailSwitchDirection direction) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetEventDirection", new object[1] { (int)direction }); } } private void SetDuration(float duration) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetDuration", new object[1] { Mathf.Clamp(duration, m_minDuration, m_maxDuration) }); } } private void RPC_SetSignalName(long sender, string value) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { _nview.GetZDO().Set("hl_signal_name", value ?? string.Empty); ClearActiveEmitters(); ApplyDefaultState(); UpdateVisuals(); BCSSignalRegistry.InvalidateAllEmitterCaches(); } } private void RPC_SetDefaultDirection(long sender, int raw) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { BCSRailSwitchDirection bCSRailSwitchDirection = DecodeDirection(raw); _nview.GetZDO().Set("hl_signal_switch_default_direction", (int)bCSRailSwitchDirection); if (!IsEventActive()) { ApplyDefaultState(); } } } private void RPC_SetEventDirection(long sender, int raw) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { BCSRailSwitchDirection bCSRailSwitchDirection = DecodeDirection(raw); _nview.GetZDO().Set("hl_signal_switch_event_direction", (int)bCSRailSwitchDirection); if (IsEventActive()) { ApplyEventState(); } } } private void RPC_SetDuration(long sender, float value) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { _nview.GetZDO().Set("hl_signal_event_duration", Mathf.Clamp(value, m_minDuration, m_maxDuration)); } } private void HandleDurationInput() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!(Time.time - _lastHoverTime > 0.25f) && PrivateArea.CheckAccess(((Component)this).transform.position, 0f, false, false)) { if (Input.GetKeyDown((KeyCode)61) || Input.GetKeyDown((KeyCode)270)) { SetDuration(GetEventDuration() + m_durationStep); } if (Input.GetKeyDown((KeyCode)45) || Input.GetKeyDown((KeyCode)269)) { SetDuration(GetEventDuration() - m_durationStep); } } } private void UpdateVisuals() { bool flag = !string.IsNullOrEmpty(GetSignalName()); bool flag2 = flag && IsEventActive(); if (!_visualInitialized || _lastHasSignal != flag || _lastSignalActive != flag2) { _visualInitialized = true; _lastHasSignal = flag; _lastSignalActive = flag2; bool flag3 = flag && !flag2; bool flag4 = flag2; if ((Object)(object)m_signalConfiguredObject != (Object)null && m_signalConfiguredObject.activeSelf != flag3) { m_signalConfiguredObject.SetActive(flag3); } if ((Object)(object)m_signalActiveObject != (Object)null && m_signalActiveObject.activeSelf != flag4) { m_signalActiveObject.SetActive(flag4); } } } private bool SignalMatches(string signalName) { string signalName2 = GetSignalName(); return !string.IsNullOrEmpty(signalName2) && string.Equals(signalName2, signalName, StringComparison.Ordinal); } public string GetSignalName() { return ((Object)(object)_nview != (Object)null && _nview.IsValid()) ? _nview.GetZDO().GetString("hl_signal_name", string.Empty) : string.Empty; } public Transform GetSignalTransform() { return ((Component)this).transform; } public ZNetView GetSignalNetView() { return _nview; } public BCSRailSwitchDirection GetDefaultDirection() { return ((Object)(object)_nview != (Object)null && _nview.IsValid()) ? DecodeDirection(_nview.GetZDO().GetInt("hl_signal_switch_default_direction", 0)) : BCSRailSwitchDirection.Left; } public BCSRailSwitchDirection GetEventDirection() { return (!((Object)(object)_nview != (Object)null) || !_nview.IsValid()) ? BCSRailSwitchDirection.Right : DecodeDirection(_nview.GetZDO().GetInt("hl_signal_switch_event_direction", 1)); } public float GetEventDuration() { return ((Object)(object)_nview != (Object)null && _nview.IsValid()) ? Mathf.Clamp(_nview.GetZDO().GetFloat("hl_signal_event_duration", m_defaultEventDuration), m_minDuration, m_maxDuration) : m_defaultEventDuration; } private static BCSRailSwitchDirection DecodeDirection(int raw) { return (raw == 1) ? BCSRailSwitchDirection.Right : BCSRailSwitchDirection.Left; } private static BCSRailSwitchDirection GetOpposite(BCSRailSwitchDirection direction) { return (direction == BCSRailSwitchDirection.Left) ? BCSRailSwitchDirection.Right : BCSRailSwitchDirection.Left; } private static string GetDirectionText(BCSRailSwitchDirection direction) { return (direction == BCSRailSwitchDirection.Left) ? "Straight" : "Branch"; } private static bool IsShiftHeld() { return Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303); } private static bool IsAltHeld() { return Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307); } } public static class BCSRailTraversalUtility { public static bool TryMoveAlongRail(ref string railId, ref float distance, float deltaDistance, bool reversed) { bool reversed2 = reversed; return TryMoveAlongRail(ref railId, ref distance, deltaDistance, ref reversed2); } public static bool TryMoveAlongRail(ref string railId, ref float distance, float deltaDistance, ref bool reversed) { railId = railId ?? string.Empty; distance = BCSCommonUtility.SanitizeFloat(distance, 0f); deltaDistance = Mathf.Abs(BCSCommonUtility.SanitizeFloat(deltaDistance, 0f)); if (string.IsNullOrEmpty(railId)) { return false; } if (deltaDistance <= 0f) { BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(railId); if ((Object)(object)bCSRailPiece == (Object)null) { return false; } distance = Mathf.Clamp(distance, 0f, bCSRailPiece.GetLength()); return true; } BCSRailPiece bCSRailPiece2 = BCSRailRegistry.FindById(railId); if ((Object)(object)bCSRailPiece2 == (Object)null) { return false; } float length = bCSRailPiece2.GetLength(); if (length <= 0.001f) { return false; } float num = (reversed ? (0f - deltaDistance) : deltaDistance); float num2 = distance + num; int num3 = 0; while ((num2 < 0f || num2 > length) && num3 < 256) { num3++; bool flag = num2 < 0f; BCSRailNodeSide bCSRailNodeSide = (flag ? GetNearExitSide(bCSRailPiece2) : GetFarExitSide(bCSRailPiece2)); string resolvedNeighborRailId = bCSRailPiece2.GetResolvedNeighborRailId(bCSRailNodeSide); if (string.IsNullOrEmpty(resolvedNeighborRailId)) { return false; } BCSRailPiece bCSRailPiece3 = BCSRailRegistry.FindById(resolvedNeighborRailId); if ((Object)(object)bCSRailPiece3 == (Object)null) { return false; } float num4 = (flag ? (0f - num2) : (num2 - length)); if (!TryResolveConnectedEntrySide(bCSRailPiece2, bCSRailNodeSide, bCSRailPiece3, out var entrySide)) { return false; } bCSRailPiece2 = bCSRailPiece3; if (bCSRailPiece2.IsSwitchRail() && (entrySide == BCSRailNodeSide.B || entrySide == BCSRailNodeSide.C)) { bCSRailPiece2.EnsureSwitchTraversalBranch(entrySide); } if (bCSRailPiece2.IsCrossroadRail()) { bCSRailPiece2.EnsureCrossroadTraversalPath(entrySide); } railId = bCSRailPiece2.GetRailId(); if (string.IsNullOrEmpty(railId)) { return false; } length = bCSRailPiece2.GetLength(); if (length <= 0.001f) { return false; } if (bCSRailPiece2.IsCrossroadRail()) { num2 = num4; reversed = false; } else if (entrySide == BCSRailNodeSide.A) { num2 = num4; reversed = false; } else { num2 = length - num4; reversed = true; } } if (num3 >= 256) { return false; } distance = Mathf.Clamp(num2, 0f, length); return true; } public static bool TryGetPoseAtOffset(string railId, float distance, bool reversed, float offset, out string outRailId, out float outDistance, out Vector3 pos, out Quaternion rot) { //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_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) outRailId = railId ?? string.Empty; outDistance = BCSCommonUtility.SanitizeFloat(distance, 0f); pos = Vector3.zero; rot = Quaternion.identity; float num = BCSCommonUtility.SanitizeFloat(offset, 0f); bool reversed2 = ((num < 0f) ? (!reversed) : reversed); if (!TryMoveAlongRail(ref outRailId, ref outDistance, Mathf.Abs(num), ref reversed2)) { return false; } BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(outRailId); if ((Object)(object)bCSRailPiece == (Object)null) { return false; } if (!bCSRailPiece.GetPose(outDistance, out pos, out rot)) { return false; } return true; } private static BCSRailNodeSide GetNearExitSide(BCSRailPiece rail) { if ((Object)(object)rail == (Object)null) { return BCSRailNodeSide.A; } if (rail.IsCrossroadRail()) { return rail.GetActiveCrossroadStartSide(); } return BCSRailNodeSide.A; } private static BCSRailNodeSide GetFarExitSide(BCSRailPiece rail) { if ((Object)(object)rail == (Object)null) { return BCSRailNodeSide.B; } if (rail.IsCrossroadRail()) { return rail.GetActiveCrossroadEndSide(); } if (!rail.IsSwitchRail()) { return BCSRailNodeSide.B; } return (rail.GetSwitchDirection() == BCSRailSwitchDirection.Left) ? BCSRailNodeSide.B : BCSRailNodeSide.C; } private static bool TryResolveConnectedEntrySide(BCSRailPiece fromRail, BCSRailNodeSide fromSide, BCSRailPiece toRail, out BCSRailNodeSide entrySide) { entrySide = BCSRailNodeSide.A; if ((Object)(object)fromRail == (Object)null || (Object)(object)toRail == (Object)null) { return false; } Transform traversalNode = fromRail.GetTraversalNode(fromSide); if ((Object)(object)traversalNode == (Object)null) { return false; } float num = Mathf.Max(0.01f, fromRail.m_nodeSearchRadius); float maxDistanceSqr = num * num; float bestDist = float.MaxValue; bool found = false; TrySelectEntrySide(traversalNode, toRail, BCSRailNodeSide.A, maxDistanceSqr, ref bestDist, ref found, ref entrySide); TrySelectEntrySide(traversalNode, toRail, BCSRailNodeSide.B, maxDistanceSqr, ref bestDist, ref found, ref entrySide); if (toRail.IsSwitchRail() || toRail.IsCrossroadRail()) { TrySelectEntrySide(traversalNode, toRail, BCSRailNodeSide.C, maxDistanceSqr, ref bestDist, ref found, ref entrySide); } if (toRail.IsCrossroadRail()) { TrySelectEntrySide(traversalNode, toRail, BCSRailNodeSide.D, maxDistanceSqr, ref bestDist, ref found, ref entrySide); } return found; } private static void TrySelectEntrySide(Transform fromNode, BCSRailPiece toRail, BCSRailNodeSide candidateSide, float maxDistanceSqr, ref float bestDist, ref bool found, ref BCSRailNodeSide entrySide) { //IL_0032: 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_003d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)fromNode == (Object)null || (Object)(object)toRail == (Object)null) { return; } Transform traversalNode = toRail.GetTraversalNode(candidateSide); if (!((Object)(object)traversalNode == (Object)null)) { float num = Vector3.SqrMagnitude(fromNode.position - traversalNode.position); if (!(num > maxDistanceSqr) && !(num >= bestDist)) { bestDist = num; entrySide = candidateSide; found = true; } } } } public class BCSRailUnloader : MonoBehaviour { private class UnloadContainerJob { public BCSCartRoot Cart; public Container Container; public bool RestoreActiveState; public bool PreviousActiveState; public void Reset() { Cart = null; Container = null; RestoreActiveState = false; PreviousActiveState = false; } } private const string RpcToggleUnloadFilter = "RPC_ToggleUnloadFilter"; public const int MinUnloadStopTimerSeconds = 3; [Header("Unload")] public BCSRailUnloadFilter m_defaultUnloadFilter = BCSRailUnloadFilter.None; [Header("Timing")] public float m_unloadFinishBeforeStopEnd = 1f; public float m_minUnloadInterval = 0.02f; public float m_maxUnloadInterval = 1f; [Header("Visuals")] public GameObject m_activeObject; public GameObject m_inactiveObject; [Header("Spawn Point")] public Transform m_spawnPoint; [Header("Spawn Randomization")] public float m_spawnRadius = 0.12f; public float m_spawnUpOffset = 0.05f; [Header("Debug")] public bool m_enableDebugLogs = false; private ZNetView _nview; private Coroutine _unloadRoutine; private readonly List _jobs = new List(16); private readonly List _itemScratch = new List(64); private bool _visualInitialized; private bool _lastVisualEnabled; private static readonly Dictionary WaitCache = new Dictionary(); private void Awake() { _nview = ((Component)this).GetComponent(); if ((Object)(object)_nview != (Object)null) { _nview.Register("RPC_ToggleUnloadFilter", (Action)RPC_ToggleUnloadFilter); } UpdateVisualState(); } private void Start() { UpdateVisualState(); } private void OnDisable() { if (_unloadRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_unloadRoutine); _unloadRoutine = null; } ReleaseJobs(); } public bool IsUnloadEnabled() { return GetUnloadFilter() != BCSRailUnloadFilter.None; } public BCSRailUnloadFilter GetUnloadFilter() { ZDO zdo = GetZdo(); if (zdo == null) { return m_defaultUnloadFilter; } int @int = zdo.GetInt("hl_rail_unload_filter", (int)m_defaultUnloadFilter); return BCSRailItemFilterUtility.Normalize(@int); } public string GetUnloadFilterText() { return BCSRailItemFilterUtility.GetText(GetUnloadFilter()); } public BCSRailUnloadFilter GetNextUnloadFilter() { return BCSRailItemFilterUtility.GetNext(GetUnloadFilter()); } public string GetNextUnloadFilterText() { return BCSRailItemFilterUtility.GetText(GetNextUnloadFilter()); } public int NormalizeStopTimerSeconds(int seconds) { if (!IsUnloadEnabled()) { return Mathf.Max(0, seconds); } return Mathf.Max(3, seconds); } public void RequestToggleUnloadFilter() { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { _nview.InvokeRPC("RPC_ToggleUnloadFilter", Array.Empty()); } } private void RPC_ToggleUnloadFilter(long sender) { if (!IsOwner()) { return; } ZDO zdo = GetZdo(); if (zdo != null) { BCSRailUnloadFilter next = BCSRailItemFilterUtility.GetNext(GetUnloadFilter()); zdo.Set("hl_rail_unload_filter", (int)next); if (next != 0) { EnsureRailTimerMinimum(); } UpdateVisualState(); } } private void EnsureRailTimerMinimum() { ZDO zdo = GetZdo(); if (zdo != null) { int num = Mathf.Max(0, zdo.GetInt("hl_stop_timer_seconds", 0)); if (num < 3) { zdo.Set("hl_stop_timer_seconds", 3); zdo.Set("hl_stop_timer_end_time", 0f); } } } public void BeginUnload(List trainCarts, int stopTimerSeconds) { if (IsOwner() && IsUnloadEnabled() && trainCarts != null && trainCarts.Count != 0) { if (_unloadRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_unloadRoutine); _unloadRoutine = null; ReleaseJobs(); } _unloadRoutine = ((MonoBehaviour)this).StartCoroutine(UnloadRoutine(trainCarts, stopTimerSeconds)); } } private IEnumerator UnloadRoutine(List trainCarts, int stopTimerSeconds) { _jobs.Clear(); try { CollectJobs(trainCarts); BCSRailUnloadFilter filter = GetUnloadFilter(); int slotCount = CountUnloadSlots(_jobs, filter); if (slotCount <= 0) { yield break; } int effectiveStopTimer = ((stopTimerSeconds > 0) ? Mathf.Max(3, stopTimerSeconds) : 0); float interval = GetUnloadInterval(effectiveStopTimer, slotCount); Transform spawnPoint = GetSpawnPoint(); int j = 0; while (j < _jobs.Count) { UnloadContainerJob job = _jobs[j]; int num; if (job != null && !((Object)(object)job.Container == (Object)null) && job.Container.GetInventory() != null) { Inventory inventory = job.Container.GetInventory(); FillItems(inventory, _itemScratch); for (int i = 0; i < _itemScratch.Count; i = num) { ItemData item = _itemScratch[i]; if (item != null && item.m_stack > 0 && BCSRailItemFilterUtility.AllowsItem(item, filter)) { ItemData dropItem = item.Clone(); Vector3 pos = GetSpawnPosition(spawnPoint); Quaternion rot = Quaternion.Euler(0f, Random.Range(0f, 360f), 0f); ItemDrop.DropItem(dropItem, 0, pos, rot); inventory.RemoveItem(item); job.Container.Save(); if (interval > 0f) { yield return GetWait(interval); } else { yield return null; } } num = i + 1; } _itemScratch.Clear(); } num = j + 1; j = num; } } finally { _itemScratch.Clear(); ReleaseJobs(); _unloadRoutine = null; } } private void CollectJobs(List trainCarts) { for (int i = 0; i < trainCarts.Count; i++) { BCSCartRoot bCSCartRoot = trainCarts[i]; if ((Object)(object)bCSCartRoot == (Object)null || !bCSCartRoot.TryPrepareContainerForUnload(out var container, out var previousActiveState, out var restoreActiveState)) { continue; } if ((Object)(object)container == (Object)null || container.GetInventory() == null || container.IsInUse()) { if (restoreActiveState) { bCSCartRoot.RestoreContainerAfterUnload(previousActiveState); } continue; } container.SetInUse(true); container.UpdateUseVisual(); UnloadContainerJob unloadContainerJob = new UnloadContainerJob(); unloadContainerJob.Cart = bCSCartRoot; unloadContainerJob.Container = container; unloadContainerJob.PreviousActiveState = previousActiveState; unloadContainerJob.RestoreActiveState = restoreActiveState; _jobs.Add(unloadContainerJob); } } private int CountUnloadSlots(List jobs, BCSRailUnloadFilter filter) { int num = 0; for (int i = 0; i < jobs.Count; i++) { UnloadContainerJob unloadContainerJob = jobs[i]; if (unloadContainerJob == null || (Object)(object)unloadContainerJob.Container == (Object)null || unloadContainerJob.Container.GetInventory() == null) { continue; } Inventory inventory = unloadContainerJob.Container.GetInventory(); FillItems(inventory, _itemScratch); for (int j = 0; j < _itemScratch.Count; j++) { ItemData val = _itemScratch[j]; if (val != null && val.m_stack > 0 && BCSRailItemFilterUtility.AllowsItem(val, filter)) { num++; } } _itemScratch.Clear(); } return num; } private static void FillItems(Inventory inventory, List result) { result.Clear(); if (inventory != null) { List allItems = inventory.GetAllItems(); for (int i = 0; i < allItems.Count; i++) { result.Add(allItems[i]); } } } private float GetUnloadInterval(int stopTimerSeconds, int slotCount) { if (slotCount <= 0) { return 0f; } float num = Mathf.Max(0.01f, m_maxUnloadInterval); float num2 = Mathf.Max(0f, m_minUnloadInterval); if (stopTimerSeconds <= 0) { return num; } float num3 = Mathf.Max(0f, (float)stopTimerSeconds - Mathf.Max(0f, m_unloadFinishBeforeStopEnd)); if (num3 <= 0f) { return 0f; } if (num2 > 0f && num2 * (float)slotCount > num3) { return 0f; } return Mathf.Clamp(num3 / (float)slotCount, num2, num); } private Transform GetSpawnPoint() { return ((Object)(object)m_spawnPoint != (Object)null) ? m_spawnPoint : ((Component)this).transform; } private Vector3 GetSpawnPosition(Transform spawnPoint) { //IL_0018: 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_001d: 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_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_0039: 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_0050: 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_0060: 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) Vector3 val = (((Object)(object)spawnPoint != (Object)null) ? spawnPoint.position : ((Component)this).transform.position); Vector2 val2 = Random.insideUnitCircle * Mathf.Max(0f, m_spawnRadius); return val + new Vector3(val2.x, Mathf.Max(0f, m_spawnUpOffset), val2.y); } private void ReleaseJobs() { for (int i = 0; i < _jobs.Count; i++) { UnloadContainerJob unloadContainerJob = _jobs[i]; if (unloadContainerJob != null) { if ((Object)(object)unloadContainerJob.Container != (Object)null) { unloadContainerJob.Container.SetInUse(false); unloadContainerJob.Container.UpdateUseVisual(); unloadContainerJob.Container.Save(); } if ((Object)(object)unloadContainerJob.Cart != (Object)null && unloadContainerJob.RestoreActiveState) { unloadContainerJob.Cart.RestoreContainerAfterUnload(unloadContainerJob.PreviousActiveState); } unloadContainerJob.Reset(); } } _jobs.Clear(); } public void UpdateVisualState() { BCSRailUnloadFilter unloadFilter = GetUnloadFilter(); bool flag = unloadFilter != BCSRailUnloadFilter.None; if (!_visualInitialized || _lastVisualEnabled != flag) { _visualInitialized = true; _lastVisualEnabled = flag; if ((Object)(object)m_activeObject != (Object)null && m_activeObject.activeSelf != flag) { m_activeObject.SetActive(flag); } if ((Object)(object)m_inactiveObject != (Object)null && m_inactiveObject.activeSelf != !flag) { m_inactiveObject.SetActive(!flag); } } } private static WaitForSeconds GetWait(float seconds) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown seconds = Mathf.Max(0.01f, seconds); seconds = Mathf.Round(seconds * 1000f) / 1000f; if (!WaitCache.TryGetValue(seconds, out var value)) { value = new WaitForSeconds(seconds); WaitCache[seconds] = value; } return value; } private bool IsOwner() { return (Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.IsOwner() && _nview.GetZDO() != null; } private ZDO GetZdo() { if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { return null; } return _nview.GetZDO(); } public bool IsUnloadRunning() { return _unloadRoutine != null || _jobs.Count > 0; } private void Log(string msg) { if (m_enableDebugLogs) { Debug.Log((object)("[BCSRailUnloader][" + ((Object)((Component)this).gameObject).name + "] " + msg)); } } } public class BCSSignalDoorReceiver : MonoBehaviour, TextReceiver, IBCSSignalReceiver { private const string RpcSetSignalName = "RPC_SetSignalName"; private const string RpcSetEventState = "RPC_SetEventState"; private const string RpcSetDuration = "RPC_SetDuration"; private const string RpcSignalStart = "RPC_SignalStart"; private const string RpcSignalStop = "RPC_SignalStop"; public string m_name = "Signal Door Receiver"; public float m_defaultEventDuration = 0f; public float m_durationStep = 1f; public float m_minDuration = 0f; public float m_maxDuration = 120f; private ZNetView _nview; private Door _door; [Header("Signal Visual")] public GameObject m_signalConfiguredObject; public GameObject m_signalActiveObject; private bool _eventActive; private Coroutine _eventRoutine; private readonly HashSet _activeEmitterIds = new HashSet(); private readonly Dictionary _emitterDurationRoutines = new Dictionary(); public float m_lastHoverTime = -1000f; private void Awake() { _nview = ((Component)this).GetComponent(); _door = ((Component)this).GetComponent(); if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || (Object)(object)_door == (Object)null) { ((Behaviour)this).enabled = false; return; } _nview.Register("RPC_SetSignalName", (Action)RPC_SetSignalName); _nview.Register("RPC_SetEventState", (Action)RPC_SetEventState); _nview.Register("RPC_SetDuration", (Action)RPC_SetDuration); _nview.Register("RPC_SignalStart", (Action)RPC_SignalStart); _nview.Register("RPC_SignalStop", (Action)RPC_SignalStop); UpdateSignalConfiguredVisual(); } private void OnEnable() { if ((Object)(object)_nview == (Object)null) { _nview = ((Component)this).GetComponent(); } if ((Object)(object)_door == (Object)null) { _door = ((Component)this).GetComponent(); } if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && !((Object)(object)_door == (Object)null)) { BCSSignalRegistry.RegisterReceiver(this); BCSSignalRegistry.InvalidateAllEmitterCaches(); UpdateSignalConfiguredVisual(); } } private void OnDisable() { BCSSignalRegistry.UnregisterReceiver(this); ClearActiveEmitters(); } private void OnDestroy() { BCSSignalRegistry.UnregisterReceiver(this); ClearActiveEmitters(); } private void Update() { HandleDurationInput(); UpdateSignalConfiguredVisual(); } public void RequestSignalStart(string signalName, string emitterId) { if ((Object)(object)_nview != (Object)null && _nview.IsValid()) { _nview.InvokeRPC("RPC_SignalStart", new object[2] { signalName ?? string.Empty, emitterId ?? string.Empty }); } } public void RequestSignalStop(string signalName, string emitterId) { if ((Object)(object)_nview != (Object)null && _nview.IsValid()) { _nview.InvokeRPC("RPC_SignalStop", new object[2] { signalName ?? string.Empty, emitterId ?? string.Empty }); } } private void RPC_SignalStart(long sender, string signalName, string emitterId) { if (SignalMatches(signalName) && !string.IsNullOrEmpty(emitterId)) { bool flag = !IsEventActive(); _activeEmitterIds.Add(emitterId); _eventActive = true; float eventDuration = GetEventDuration(); if (eventDuration > 0f) { StopEmitterDurationRoutine(emitterId); _emitterDurationRoutines[emitterId] = ((MonoBehaviour)this).StartCoroutine(EventDurationRoutine(eventDuration, emitterId)); } if (flag) { ApplyDoorState(GetEventState()); } } } private void RPC_SignalStop(long sender, string signalName, string emitterId) { if (SignalMatches(signalName) && !string.IsNullOrEmpty(emitterId) && IsEventActive() && !(GetEventDuration() > 0f)) { RemoveActiveEmitter(emitterId, stopRoutine: true); } } private IEnumerator EventDurationRoutine(float duration, string emitterId) { yield return (object)new WaitForSeconds(duration); RemoveActiveEmitter(emitterId, stopRoutine: false); } private void RemoveActiveEmitter(string emitterId, bool stopRoutine) { if (!string.IsNullOrEmpty(emitterId)) { if (stopRoutine) { StopEmitterDurationRoutine(emitterId); } else { _emitterDurationRoutines.Remove(emitterId); } _activeEmitterIds.Remove(emitterId); if (_activeEmitterIds.Count > 0) { _eventActive = true; } else { EndEvent(); } } } private void StopEmitterDurationRoutine(string emitterId) { if (_emitterDurationRoutines.TryGetValue(emitterId, out var value) && value != null) { ((MonoBehaviour)this).StopCoroutine(value); } _emitterDurationRoutines.Remove(emitterId); } private bool IsEventActive() { return _activeEmitterIds.Count > 0; } private void ClearActiveEmitters() { foreach (KeyValuePair emitterDurationRoutine in _emitterDurationRoutines) { if (emitterDurationRoutine.Value != null) { ((MonoBehaviour)this).StopCoroutine(emitterDurationRoutine.Value); } } _emitterDurationRoutines.Clear(); _activeEmitterIds.Clear(); _eventActive = false; } private void EndEvent() { _eventActive = false; ApplyDoorState(GetOppositeState(GetEventState())); } private void ApplyDoorState(BCSSignalDoorState state) { if ((Object)(object)_door == (Object)null || (Object)(object)_nview == (Object)null || !_nview.IsValid()) { return; } if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } if (_nview.IsOwner()) { int @int = _nview.GetZDO().GetInt(ZDOVars.s_state, 0); int num = ((state == BCSSignalDoorState.Open) ? 1 : 0); if ((@int == 0 || num == 0) && @int != num) { _nview.GetZDO().Set(ZDOVars.s_state, num, false); _door.UpdateState(); } } } public void RequestSetSignalNameFromUser() { if ((Object)(object)TextInput.instance != (Object)null) { TextInput.instance.RequestText((TextReceiver)(object)this, "Signal name", 32); } } public void ToggleEventStateFromUser() { BCSSignalDoorState eventState = ((GetEventState() == BCSSignalDoorState.Closed) ? BCSSignalDoorState.Open : BCSSignalDoorState.Closed); SetEventState(eventState); } public string GetExtraHoverText() { m_lastHoverTime = Time.time; string text = (string.IsNullOrEmpty(GetSignalName()) ? "NULL" : GetSignalName()); BCSSignalDoorState eventState = GetEventState(); BCSSignalDoorState oppositeState = GetOppositeState(eventState); return "\n[Shift+$KEY_Use] Signal: " + text + "\n[Alt+$KEY_Use] Event: " + eventState.ToString() + " (Default: " + oppositeState.ToString() + ")\n[+ / -] Duration: " + GetEventDuration().ToString("0") + "s"; } public string GetText() { return GetSignalName(); } public void SetText(string text) { SetSignalName((text == null) ? string.Empty : text.Trim()); } private void SetSignalName(string signalName) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetSignalName", new object[1] { signalName ?? string.Empty }); } } private void SetEventState(BCSSignalDoorState state) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetEventState", new object[1] { (int)state }); } } private void SetDuration(float duration) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetDuration", new object[1] { Mathf.Clamp(duration, m_minDuration, m_maxDuration) }); } } private void RPC_SetSignalName(long sender, string value) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { _nview.GetZDO().Set("hl_signal_name", value ?? string.Empty); ClearActiveEmitters(); BCSSignalRegistry.InvalidateAllEmitterCaches(); UpdateSignalConfiguredVisual(); } } private void UpdateSignalConfiguredVisual() { bool flag = !string.IsNullOrEmpty(GetSignalName()); bool flag2 = flag && IsEventActive(); if ((Object)(object)m_signalConfiguredObject != (Object)null) { m_signalConfiguredObject.SetActive(flag && !flag2); } if ((Object)(object)m_signalActiveObject != (Object)null) { m_signalActiveObject.SetActive(flag2); } } private void RPC_SetEventState(long sender, int value) { if (_nview.IsOwner()) { value = Mathf.Clamp(value, 0, 1); _nview.GetZDO().Set("hl_signal_door_event_state", value); } } private void RPC_SetDuration(long sender, float value) { if (_nview.IsOwner()) { _nview.GetZDO().Set("hl_signal_event_duration", Mathf.Clamp(value, m_minDuration, m_maxDuration)); } } private void HandleDurationInput() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!(Time.time - m_lastHoverTime > 0.25f) && PrivateArea.CheckAccess(((Component)this).transform.position, 0f, false, false)) { if (Input.GetKeyDown((KeyCode)61) || Input.GetKeyDown((KeyCode)270)) { SetDuration(GetEventDuration() + m_durationStep); } if (Input.GetKeyDown((KeyCode)45) || Input.GetKeyDown((KeyCode)269)) { SetDuration(GetEventDuration() - m_durationStep); } } } private bool SignalMatches(string signalName) { string signalName2 = GetSignalName(); return !string.IsNullOrEmpty(signalName2) && string.Equals(signalName2, signalName, StringComparison.Ordinal); } public string GetSignalName() { return ((Object)(object)_nview != (Object)null && _nview.IsValid()) ? _nview.GetZDO().GetString("hl_signal_name", string.Empty) : string.Empty; } public Transform GetSignalTransform() { return ((Component)this).transform; } public ZNetView GetSignalNetView() { return _nview; } public BCSSignalDoorState GetEventState() { int num = (((Object)(object)_nview != (Object)null && _nview.IsValid()) ? _nview.GetZDO().GetInt("hl_signal_door_event_state", 0) : 0); return (num == 1) ? BCSSignalDoorState.Open : BCSSignalDoorState.Closed; } public float GetEventDuration() { return ((Object)(object)_nview != (Object)null && _nview.IsValid()) ? Mathf.Clamp(_nview.GetZDO().GetFloat("hl_signal_event_duration", m_defaultEventDuration), m_minDuration, m_maxDuration) : m_defaultEventDuration; } private static BCSSignalDoorState GetOppositeState(BCSSignalDoorState state) { return (state != BCSSignalDoorState.Open) ? BCSSignalDoorState.Open : BCSSignalDoorState.Closed; } } public class BCSSignalEmitter : MonoBehaviour, Hoverable, Interactable, TextReceiver { private const string RpcSetSignalName = "RPC_SetSignalName"; private const string RpcSetMode = "RPC_SetMode"; private const string RpcSetRange = "RPC_SetRange"; private const string CartSensorColliderName = "CartSensorCollider"; private const int RailAttachBufferSize = 16; private static readonly Collider[] RailAttachBuffer = (Collider[])(object)new Collider[16]; private const int CartDetectorBufferSize = 32; private static readonly Collider[] CartDetectorBuffer = (Collider[])(object)new Collider[32]; public string m_name = "Signal Emitter"; [Header("Signal")] public float m_defaultRange = 5f; public float m_minRange = 1f; public float m_maxRange = 50f; public float m_rangeStep = 1f; [Header("State Visuals")] public GameObject m_disabledObject; public GameObject m_enabledObject; public GameObject m_signalObject; [Header("Detection")] public float m_stateCheckInterval = 0.1f; public float m_stoppedDistanceDelta = 0.02f; public float m_attachScanDelay = 0.25f; public LayerMask m_cartDetectionMask; public float m_stopConfirmTime = 0.5f; public float m_cartMoveDistanceThreshold = 0.02f; [Header("Trigger Roots")] public GameObject m_railAttachTriggerObject; public GameObject m_cartDetectorTriggerObject; [Header("Range Visual")] public CircleProjector m_areaMarker; private ZNetView _nview; private BCSRailPiece _attachedRail; private WearNTear _attachedRailWear; private BCSSignalTriggerRelay _railAttachRelay; private BCSSignalTriggerRelay _cartDetectorRelay; private BoxCollider _railAttachBox; private BoxCollider _cartDetectorBox; private readonly List _cartsInside = new List(); private readonly Dictionary _cartContactCounts = new Dictionary(); private readonly Dictionary _lastCartPositions = new Dictionary(); private readonly List _receiverCache = new List(); private bool _receiverCacheValid; private bool _previousOccupied; private bool _previousCondition; private string _activeSignalName = string.Empty; private float _stateTimer; private float _lastHoverTime = -1000f; private float _occupiedStillTime; private bool _areaMarkerVisible; private bool _visualInitialized; private bool _lastShowDisabled; private bool _lastShowEnabled; private bool _lastShowSignal; private string _lastObservedSignalName = null; private bool _lastObservedEmitterActive; private float _lastObservedRange = -1f; private bool _enteredThisTick; private bool _exitedThisTick; private readonly List _previousCartsInside = new List(); private void Awake() { //IL_00c4: 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) _nview = ((Component)this).GetComponent(); if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { ((Behaviour)this).enabled = false; return; } _nview.Register("RPC_SetSignalName", (Action)RPC_SetSignalName); _nview.Register("RPC_SetMode", (Action)RPC_SetMode); _nview.Register("RPC_SetRange", (Action)RPC_SetRange); if (((LayerMask)(ref m_cartDetectionMask)).value == 0) { m_cartDetectionMask = LayerMask.op_Implicit(LayerMask.GetMask(new string[2] { "character_noenv", "vehicle" })); } ResolveTriggerReferences(); BCSSignalRegistry.RegisterEmitter(this); UpdateAreaMarker(); SetAreaMarkerVisible(visible: false); UpdateEmitterVisualState(signalActive: false); UpdateNetworkVisualState(); } private void Start() { ((MonoBehaviour)this).Invoke("TryAttachRailByOverlapOnce", Mathf.Max(0.05f, m_attachScanDelay)); ((MonoBehaviour)this).Invoke("InitializeSensorRuntimeOnce", Mathf.Max(0.05f, m_attachScanDelay + 0.05f)); } private void InitializeSensorRuntimeOnce() { //IL_0067: Unknown result type (might be due to invalid IL or missing references) ReconcileCartsInsideByOverlap(); _previousOccupied = _cartsInside.Count > 0; _previousCondition = false; _enteredThisTick = false; _exitedThisTick = false; _occupiedStillTime = 0f; for (int i = 0; i < _cartsInside.Count; i++) { BCSCartRoot bCSCartRoot = _cartsInside[i]; if ((Object)(object)bCSCartRoot != (Object)null) { _lastCartPositions[bCSCartRoot] = ((Component)bCSCartRoot).transform.position; } } } private void OnDestroy() { ResetRuntimeOnly(); SetAreaMarkerVisible(visible: false); UnhookAttachedRail(); BCSSignalRegistry.UnregisterEmitter(this); } private void ResetRuntimeOnly() { _cartsInside.Clear(); _cartContactCounts.Clear(); _lastCartPositions.Clear(); _receiverCache.Clear(); _receiverCacheValid = false; _previousOccupied = false; _previousCondition = false; _activeSignalName = string.Empty; _occupiedStillTime = 0f; _stateTimer = 0f; } private void Update() { ValidateAttachedRailAlive(); HandleRangeInput(); UpdateNetworkVisualState(); _stateTimer += Time.deltaTime; float num = Mathf.Clamp(BCSCommonUtility.SanitizeFloat(m_stateCheckInterval, 0.1f), 0.05f, 0.25f); if (_stateTimer >= num) { float stateTimer = _stateTimer; _stateTimer = 0f; ReconcileCartsInsideByOverlap(); PruneInvalidCarts(); if ((Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.IsOwner()) { UpdateSignalState(stateTimer); } } UpdateAreaMarkerVisibility(); } private void UpdateNetworkVisualState() { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.GetZDO() != null) { string signalName = GetSignalName(); bool emitterActive = GetEmitterActive(); float range = GetRange(); if (!(_lastObservedSignalName == signalName) || _lastObservedEmitterActive != emitterActive || !(Mathf.Abs(_lastObservedRange - range) <= 0.001f)) { _lastObservedSignalName = signalName; _lastObservedEmitterActive = emitterActive; _lastObservedRange = range; UpdateEmitterVisualState(emitterActive); UpdateAreaMarker(); } } } private void ResolveTriggerReferences() { if ((Object)(object)m_railAttachTriggerObject == (Object)null) { Transform val = ((Component)this).transform.Find("RailAttachTrigger"); if ((Object)(object)val != (Object)null) { m_railAttachTriggerObject = ((Component)val).gameObject; } } if ((Object)(object)m_cartDetectorTriggerObject == (Object)null) { Transform val2 = ((Component)this).transform.Find("CartDetectorTrigger"); if ((Object)(object)val2 != (Object)null) { m_cartDetectorTriggerObject = ((Component)val2).gameObject; } } if ((Object)(object)m_railAttachTriggerObject != (Object)null) { _railAttachRelay = m_railAttachTriggerObject.GetComponent(); _railAttachBox = m_railAttachTriggerObject.GetComponent(); } if ((Object)(object)m_cartDetectorTriggerObject != (Object)null) { _cartDetectorRelay = m_cartDetectorTriggerObject.GetComponent(); _cartDetectorBox = m_cartDetectorTriggerObject.GetComponent(); } } private void ValidateAttachedRailAlive() { if ((Object)(object)_attachedRail == (Object)null) { return; } if ((Object)(object)_attachedRailWear == (Object)null) { UnhookAttachedRail(); return; } ZNetView component = ((Component)_attachedRail).GetComponent(); if (!((Object)(object)component == (Object)null) && component.IsValid()) { } } private bool GetEmitterActive() { return (Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.GetZDO().GetBool("hl_signal_emitter_active", false); } private void SetEmitterActive(bool active) { if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner()) { return; } ZDO zDO = _nview.GetZDO(); if (zDO != null) { if (zDO.GetBool("hl_signal_emitter_active", false) != active) { zDO.Set("hl_signal_emitter_active", active); } UpdateEmitterVisualState(active); _lastObservedEmitterActive = active; _lastObservedSignalName = GetSignalName(); } } private void TryAttachRailByOverlapOnce() { //IL_005b: 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_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_00b4: 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_00e5: 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) //IL_0101: 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) if ((Object)(object)_attachedRail != (Object)null) { return; } if ((Object)(object)_railAttachBox == (Object)null) { ResolveTriggerReferences(); } if ((Object)(object)_railAttachBox == (Object)null) { return; } Vector3 val = ((Component)_railAttachBox).transform.TransformPoint(_railAttachBox.center); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(Mathf.Abs(_railAttachBox.size.x * ((Component)_railAttachBox).transform.lossyScale.x) * 0.5f, Mathf.Abs(_railAttachBox.size.y * ((Component)_railAttachBox).transform.lossyScale.y) * 0.5f, Mathf.Abs(_railAttachBox.size.z * ((Component)_railAttachBox).transform.lossyScale.z) * 0.5f); int num = Physics.OverlapBoxNonAlloc(val, val2, RailAttachBuffer, ((Component)_railAttachBox).transform.rotation, -5, (QueryTriggerInteraction)2); for (int i = 0; i < num; i++) { Collider val3 = RailAttachBuffer[i]; RailAttachBuffer[i] = null; if (!((Object)(object)val3 == (Object)null) && !((Object)(object)((Component)val3).GetComponentInParent() == (Object)(object)this)) { BCSRailPiece componentInParent = ((Component)val3).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { AttachRail(componentInParent); break; } } } } public void OnRelayTriggerEnter(BCSSignalTriggerRelay relay, Collider other) { //IL_00fd: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)relay == (Object)null || (Object)(object)other == (Object)null) { return; } if (relay.m_type == BCSSignalTriggerRelayType.RailAttach) { if ((Object)(object)_attachedRail == (Object)null) { BCSRailPiece componentInParent = ((Component)other).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { AttachRail(componentInParent); } } } else { if (relay.m_type != BCSSignalTriggerRelayType.CartDetector || !IsCartSensorCollider(other)) { return; } BCSCartRoot componentInParent2 = ((Component)other).GetComponentInParent(); if (!((Object)(object)componentInParent2 == (Object)null) && ((Component)componentInParent2).gameObject.activeInHierarchy) { if (!_cartContactCounts.TryGetValue(componentInParent2, out var value)) { _cartContactCounts[componentInParent2] = 1; _cartsInside.Add(componentInParent2); _lastCartPositions[componentInParent2] = ((Component)componentInParent2).transform.position; } else { _cartContactCounts[componentInParent2] = value + 1; } } } } public void OnRelayTriggerExit(BCSSignalTriggerRelay relay, Collider other) { if ((Object)(object)relay == (Object)null || (Object)(object)other == (Object)null || relay.m_type != BCSSignalTriggerRelayType.CartDetector || !IsCartSensorCollider(other)) { return; } BCSCartRoot componentInParent = ((Component)other).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null) && _cartContactCounts.TryGetValue(componentInParent, out var value)) { value--; if (value > 0) { _cartContactCounts[componentInParent] = value; return; } _cartContactCounts.Remove(componentInParent); _cartsInside.Remove(componentInParent); _lastCartPositions.Remove(componentInParent); } } private void PruneInvalidCarts() { for (int num = _cartsInside.Count - 1; num >= 0; num--) { BCSCartRoot bCSCartRoot = _cartsInside[num]; if (!((Object)(object)bCSCartRoot != (Object)null) || !((Component)bCSCartRoot).gameObject.activeInHierarchy) { _cartsInside.RemoveAt(num); if ((Object)(object)bCSCartRoot != (Object)null) { _cartContactCounts.Remove(bCSCartRoot); _lastCartPositions.Remove(bCSCartRoot); } } } } private bool AnyCartMovingByPosition() { //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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009a: 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_00a1: 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_00c3: Unknown result type (might be due to invalid IL or missing references) bool result = false; float num = Mathf.Max(0.001f, BCSCommonUtility.SanitizeFloat(m_cartMoveDistanceThreshold, 0.02f)); float num2 = num * num; for (int i = 0; i < _cartsInside.Count; i++) { BCSCartRoot bCSCartRoot = _cartsInside[i]; if ((Object)(object)bCSCartRoot == (Object)null || !((Component)bCSCartRoot).gameObject.activeInHierarchy) { continue; } Vector3 position = ((Component)bCSCartRoot).transform.position; if (!_lastCartPositions.TryGetValue(bCSCartRoot, out var value)) { _lastCartPositions[bCSCartRoot] = position; result = true; continue; } Vector3 val = position - value; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude > num2) { result = true; } _lastCartPositions[bCSCartRoot] = position; } return result; } private bool IsTrainStoppedOnSensor(bool occupied, float sensorDt) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) if (!occupied) { _occupiedStillTime = 0f; _lastCartPositions.Clear(); return false; } if (_enteredThisTick) { _occupiedStillTime = 0f; for (int i = 0; i < _cartsInside.Count; i++) { BCSCartRoot bCSCartRoot = _cartsInside[i]; if ((Object)(object)bCSCartRoot != (Object)null) { _lastCartPositions[bCSCartRoot] = ((Component)bCSCartRoot).transform.position; } } return false; } if (AnyCartMovingByPosition()) { _occupiedStillTime = 0f; return false; } _occupiedStillTime += Mathf.Max(0.01f, sensorDt); return _occupiedStillTime >= Mathf.Max(0.05f, m_stopConfirmTime); } private void AttachRail(BCSRailPiece rail) { if (!((Object)(object)rail == (Object)null) && !((Object)(object)_attachedRail != (Object)null)) { _attachedRail = rail; _attachedRailWear = ((Component)rail).GetComponent(); if ((Object)(object)_attachedRailWear == (Object)null) { _attachedRailWear = ((Component)rail).GetComponentInParent(); } if ((Object)(object)_attachedRailWear == (Object)null) { _attachedRailWear = ((Component)rail).GetComponentInChildren(true); } if ((Object)(object)_attachedRailWear != (Object)null) { WearNTear attachedRailWear = _attachedRailWear; attachedRailWear.m_onDestroyed = (Action)Delegate.Combine(attachedRailWear.m_onDestroyed, new Action(OnAttachedRailDestroyed)); } else { Debug.LogWarning((object)("[BCSSignalEmitter][" + ((Object)((Component)this).gameObject).name + "] Attached rail has no WearNTear: " + ((Object)rail).name)); } } } private void UnhookAttachedRail() { if ((Object)(object)_attachedRailWear != (Object)null) { WearNTear attachedRailWear = _attachedRailWear; attachedRailWear.m_onDestroyed = (Action)Delegate.Remove(attachedRailWear.m_onDestroyed, new Action(OnAttachedRailDestroyed)); } _attachedRailWear = null; _attachedRail = null; } private void OnAttachedRailDestroyed() { UnhookAttachedRail(); } private void UpdateSignalState(float sensorDt) { if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || !_nview.IsOwner()) { return; } string signalName = GetSignalName(); if (string.IsNullOrEmpty(signalName) || !((Object)(object)_attachedRail != (Object)null)) { if (_previousCondition || GetEmitterActive()) { StopSignal(_activeSignalName); } _previousCondition = false; _previousOccupied = false; _occupiedStillTime = 0f; return; } bool flag = HasValidCartInside(); bool flag2 = EvaluateCondition(flag, sensorDt); if (!_previousCondition && flag2) { StartSignal(signalName); } else if (_previousCondition && !flag2) { StopSignal(signalName); } _previousOccupied = flag; _previousCondition = flag2; } private bool HasValidCartInside() { return _cartsInside.Count > 0; } private bool EvaluateCondition(bool occupied, float sensorDt) { return GetMode() switch { BCSSignalEmitterMode.TrainOnSensor => occupied, BCSSignalEmitterMode.TrainEntered => _enteredThisTick, BCSSignalEmitterMode.TrainExited => _exitedThisTick, BCSSignalEmitterMode.TrainStopped => IsTrainStoppedOnSensor(occupied, sensorDt), BCSSignalEmitterMode.TrainMoving => occupied && !_enteredThisTick && AnyCartMovingByPosition(), _ => false, }; } private string GetEmitterId() { if ((Object)(object)_nview != (Object)null && _nview.IsValid() && _nview.GetZDO() != null) { return ((object)(ZDOID)(ref _nview.GetZDO().m_uid)).ToString(); } return ((Object)((Component)this).gameObject).GetInstanceID().ToString(); } private void StartSignal(string signalName) { _activeSignalName = signalName ?? string.Empty; SetEmitterActive(active: true); RefreshReceiverCache(); string emitterId = GetEmitterId(); for (int num = _receiverCache.Count - 1; num >= 0; num--) { IBCSSignalReceiver iBCSSignalReceiver = _receiverCache[num]; if (!BCSSignalRegistry.IsValidReceiver(iBCSSignalReceiver)) { _receiverCache.RemoveAt(num); } else { iBCSSignalReceiver.RequestSignalStart(_activeSignalName, emitterId); } } } private void StopSignal(string signalName) { string text = ((!string.IsNullOrEmpty(signalName)) ? signalName : _activeSignalName); SetEmitterActive(active: false); if (!string.IsNullOrEmpty(text)) { RefreshReceiverCache(); string emitterId = GetEmitterId(); for (int num = _receiverCache.Count - 1; num >= 0; num--) { IBCSSignalReceiver iBCSSignalReceiver = _receiverCache[num]; if (!BCSSignalRegistry.IsValidReceiver(iBCSSignalReceiver)) { _receiverCache.RemoveAt(num); } else { iBCSSignalReceiver.RequestSignalStop(text, emitterId); } } } _activeSignalName = string.Empty; } public void RefreshReceiverCache() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) BCSSignalRegistry.CleanupInvalidReferences(); BCSSignalRegistry.FindReceivers(GetSignalName(), ((Component)this).transform.position, GetRange(), _receiverCache); _receiverCacheValid = true; } public void InvalidateReceiverCache() { _receiverCacheValid = false; } public void RemoveCachedReceiver(IBCSSignalReceiver receiver) { if (receiver != null) { _receiverCache.Remove(receiver); } } private List GetReceiverCache() { if (!_receiverCacheValid) { RefreshReceiverCache(); } return _receiverCache; } public string GetHoverName() { return m_name; } public string GetHoverText() { _lastHoverTime = Time.time; ShowAreaMarker(); string value = (string.IsNullOrEmpty(GetSignalName()) ? "" : GetSignalName()); string value2 = (((Object)(object)_attachedRail != (Object)null) ? "Connected" : "Disconnected"); int value3 = Mathf.RoundToInt(GetRange()); int value4 = Mathf.RoundToInt(m_maxRange); StringBuilder stringBuilder = new StringBuilder(256); stringBuilder.Append(m_name).Append(" (").Append(value2) .Append(")"); stringBuilder.Append("\n[$KEY_Use] Signal: ").Append(value); stringBuilder.Append("\n[Shift+$KEY_Use] Mode: ").Append(GetMode()); stringBuilder.Append("\n[Alt+$KEY_Use] Refresh receivers"); stringBuilder.Append("\n[+ / -] Range: ").Append(value3).Append("/") .Append(value4) .Append("m"); stringBuilder.Append("\nReceivers: ").Append(GetReceiverCache().Count); stringBuilder.Append("\nCarts: ").Append(_cartsInside.Count); return (Localization.instance != null) ? Localization.instance.Localize(stringBuilder.ToString()) : stringBuilder.ToString(); } private void ReconcileCartsInsideByOverlap() { //IL_00c6: 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_00d9: 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) //IL_010a: 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_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: 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_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) _enteredThisTick = false; _exitedThisTick = false; _previousCartsInside.Clear(); for (int i = 0; i < _cartsInside.Count; i++) { BCSCartRoot bCSCartRoot = _cartsInside[i]; if ((Object)(object)bCSCartRoot != (Object)null) { _previousCartsInside.Add(bCSCartRoot); } } _cartsInside.Clear(); _cartContactCounts.Clear(); if ((Object)(object)_cartDetectorBox == (Object)null) { ResolveTriggerReferences(); } if ((Object)(object)_cartDetectorBox == (Object)null) { return; } Vector3 val = ((Component)_cartDetectorBox).transform.TransformPoint(_cartDetectorBox.center); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(Mathf.Abs(_cartDetectorBox.size.x * ((Component)_cartDetectorBox).transform.lossyScale.x) * 0.5f, Mathf.Abs(_cartDetectorBox.size.y * ((Component)_cartDetectorBox).transform.lossyScale.y) * 0.5f, Mathf.Abs(_cartDetectorBox.size.z * ((Component)_cartDetectorBox).transform.lossyScale.z) * 0.5f); int num = ((((LayerMask)(ref m_cartDetectionMask)).value != 0) ? ((LayerMask)(ref m_cartDetectionMask)).value : LayerMask.GetMask(new string[2] { "character_noenv", "vehicle" })); int num2 = Physics.OverlapBoxNonAlloc(val, val2, CartDetectorBuffer, ((Component)_cartDetectorBox).transform.rotation, num, (QueryTriggerInteraction)2); for (int j = 0; j < num2; j++) { Collider hit = CartDetectorBuffer[j]; CartDetectorBuffer[j] = null; AddDetectedCartFromCollider(hit); } for (int k = 0; k < _cartsInside.Count; k++) { BCSCartRoot bCSCartRoot2 = _cartsInside[k]; if ((Object)(object)bCSCartRoot2 != (Object)null && !_previousCartsInside.Contains(bCSCartRoot2)) { _enteredThisTick = true; } } for (int l = 0; l < _previousCartsInside.Count; l++) { BCSCartRoot bCSCartRoot3 = _previousCartsInside[l]; if ((Object)(object)bCSCartRoot3 != (Object)null && !_cartsInside.Contains(bCSCartRoot3)) { _exitedThisTick = true; _lastCartPositions.Remove(bCSCartRoot3); } } } private void AddDetectedCartFromCollider(Collider hit) { if (!IsCartSensorCollider(hit)) { return; } BCSCartRoot componentInParent = ((Component)hit).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null) && ((Component)componentInParent).gameObject.activeInHierarchy) { if (_cartContactCounts.TryGetValue(componentInParent, out var value)) { _cartContactCounts[componentInParent] = value + 1; return; } _cartContactCounts[componentInParent] = 1; _cartsInside.Add(componentInParent); } } public bool Interact(Humanoid human, bool hold, bool alt) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (hold) { return false; } Player val = (Player)(object)((human is Player) ? human : null); if ((Object)(object)val == (Object)null) { return false; } if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return true; } if (IsShiftHeld()) { BCSSignalEmitterMode nextMode = GetNextMode(); SetMode(nextMode); ((Character)val).Message((MessageType)2, "Signal mode: " + nextMode, 0, (Sprite)null); return true; } if (IsAltHeld()) { RefreshReceiverCache(); ((Character)val).Message((MessageType)2, "Receivers: " + _receiverCache.Count, 0, (Sprite)null); return true; } if ((Object)(object)TextInput.instance == (Object)null) { ((Character)val).Message((MessageType)2, "Text input unavailable", 0, (Sprite)null); return true; } TextInput.instance.RequestText((TextReceiver)(object)this, "Signal name", 32); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public string GetText() { return GetSignalName(); } public void SetText(string text) { SetSignalName((text == null) ? string.Empty : text.Trim()); } private void SetSignalName(string signalName) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetSignalName", new object[1] { signalName ?? string.Empty }); } } private void SetMode(BCSSignalEmitterMode mode) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetMode", new object[1] { (int)mode }); } } private void SetRange(float range) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetRange", new object[1] { Mathf.Clamp(range, m_minRange, m_maxRange) }); } } private void RPC_SetSignalName(long sender, string value) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { string signalName = GetSignalName(); if ((_previousCondition || GetEmitterActive()) && !string.IsNullOrEmpty(signalName)) { StopSignal(signalName); } ZDO zDO = _nview.GetZDO(); if (zDO != null) { zDO.Set("hl_signal_name", value ?? string.Empty); _previousCondition = false; _previousOccupied = HasValidCartInside(); _activeSignalName = string.Empty; _occupiedStillTime = 0f; InvalidateReceiverCache(); SetEmitterActive(active: false); _lastObservedSignalName = null; UpdateNetworkVisualState(); } } } private void RPC_SetMode(long sender, int value) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { value = Mathf.Clamp(value, 0, 4); if (_previousCondition || GetEmitterActive()) { StopSignal(_activeSignalName); } ZDO zDO = _nview.GetZDO(); if (zDO != null) { zDO.Set("hl_signal_emitter_mode", value); _previousCondition = false; _previousOccupied = HasValidCartInside(); _occupiedStillTime = 0f; _activeSignalName = string.Empty; SetEmitterActive(active: false); } } } private void RPC_SetRange(long sender, float value) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { ZDO zDO = _nview.GetZDO(); if (zDO != null) { float num = Mathf.Clamp(value, m_minRange, m_maxRange); zDO.Set("hl_signal_emitter_range", num); UpdateAreaMarker(); InvalidateReceiverCache(); _lastObservedRange = -1f; UpdateNetworkVisualState(); } } } public string GetSignalName() { if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { return string.Empty; } return _nview.GetZDO().GetString("hl_signal_name", string.Empty); } public BCSSignalEmitterMode GetMode() { if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { return BCSSignalEmitterMode.TrainOnSensor; } int @int = _nview.GetZDO().GetInt("hl_signal_emitter_mode", 0); return (BCSSignalEmitterMode)Mathf.Clamp(@int, 0, 4); } public float GetRange() { if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { return m_defaultRange; } return Mathf.Clamp(_nview.GetZDO().GetFloat("hl_signal_emitter_range", m_defaultRange), m_minRange, m_maxRange); } private void UpdateEmitterVisualState(bool signalActive) { bool flag = !string.IsNullOrEmpty(GetSignalName()); bool flag2 = !flag; bool flag3 = flag && signalActive; bool flag4 = flag && !signalActive; if (!_visualInitialized || _lastShowDisabled != flag2 || _lastShowEnabled != flag4 || _lastShowSignal != flag3) { _visualInitialized = true; _lastShowDisabled = flag2; _lastShowEnabled = flag4; _lastShowSignal = flag3; if ((Object)(object)m_disabledObject != (Object)null && m_disabledObject.activeSelf != flag2) { m_disabledObject.SetActive(flag2); } if ((Object)(object)m_enabledObject != (Object)null && m_enabledObject.activeSelf != flag4) { m_enabledObject.SetActive(flag4); } if ((Object)(object)m_signalObject != (Object)null && m_signalObject.activeSelf != flag3) { m_signalObject.SetActive(flag3); } } } private BCSSignalEmitterMode GetNextMode() { return (BCSSignalEmitterMode)((int)(GetMode() + 1) % 5); } private void HandleRangeInput() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!(Time.time - _lastHoverTime > 0.25f) && PrivateArea.CheckAccess(((Component)this).transform.position, 0f, false, false)) { if (Input.GetKeyDown((KeyCode)61) || Input.GetKeyDown((KeyCode)270)) { SetRange(GetRange() + m_rangeStep); } if (Input.GetKeyDown((KeyCode)45) || Input.GetKeyDown((KeyCode)269)) { SetRange(GetRange() - m_rangeStep); } } } private void ShowAreaMarker() { if (!((Object)(object)m_areaMarker == (Object)null)) { UpdateAreaMarker(); SetAreaMarkerVisible(visible: true); } } private void UpdateAreaMarkerVisibility() { if (Time.time - _lastHoverTime > 0.25f) { SetAreaMarkerVisible(visible: false); } } private void SetAreaMarkerVisible(bool visible) { if ((Object)(object)m_areaMarker == (Object)null) { _areaMarkerVisible = false; } else if (_areaMarkerVisible != visible || ((Component)m_areaMarker).gameObject.activeSelf != visible) { _areaMarkerVisible = visible; ((Component)m_areaMarker).gameObject.SetActive(visible); } } private void UpdateAreaMarker() { if ((Object)(object)m_areaMarker != (Object)null) { m_areaMarker.m_radius = GetRange(); } } private static bool IsCartSensorCollider(Collider other) { if ((Object)(object)other == (Object)null) { return false; } if (((Object)other).name == "CartSensorCollider") { return true; } if ((Object)(object)((Component)other).transform != (Object)null && ((Object)((Component)other).transform).name == "CartSensorCollider") { return true; } return false; } private static bool IsShiftHeld() { return Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303); } private static bool IsAltHeld() { return Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307); } } public enum BCSLiftGateSignalState { Closed, Open } public class BCSSignalLiftGateReceiver : MonoBehaviour, TextReceiver, IBCSSignalReceiver { private const string RpcSetSignalName = "RPC_SetSignalName"; private const string RpcSetEventState = "RPC_SetEventState"; private const string RpcSetDuration = "RPC_SetDuration"; private const string RpcSignalStart = "RPC_SignalStart"; private const string RpcSignalStop = "RPC_SignalStop"; private const string ZdoSignalName = "BCS_SignalName"; private const string ZdoLiftGateEventState = "BCS_LiftGateEventState"; private const string ZdoSignalEventDuration = "BCS_SignalEventDuration"; public string m_name = "Signal Lift Gate Receiver"; [Header("Duration")] public float m_defaultEventDuration = 0f; public float m_durationStep = 1f; public float m_minDuration = 0f; public float m_maxDuration = 120f; [Header("Signal Visual")] public GameObject m_signalConfiguredObject; public GameObject m_signalActiveObject; private ZNetView _nview; private BalrondLiftGate _gate; private readonly HashSet _activeEmitterIds = new HashSet(); private readonly Dictionary _emitterDurationRoutines = new Dictionary(); public float m_lastHoverTime = -1000f; private void Awake() { _nview = ((Component)this).GetComponent(); _gate = ((Component)this).GetComponent(); if ((Object)(object)_gate == (Object)null) { _gate = ((Component)this).GetComponentInChildren(true); } if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || (Object)(object)_gate == (Object)null) { ((Behaviour)this).enabled = false; return; } _nview.Register("RPC_SetSignalName", (Action)RPC_SetSignalName); _nview.Register("RPC_SetEventState", (Action)RPC_SetEventState); _nview.Register("RPC_SetDuration", (Action)RPC_SetDuration); _nview.Register("RPC_SignalStart", (Action)RPC_SignalStart); _nview.Register("RPC_SignalStop", (Action)RPC_SignalStop); UpdateSignalConfiguredVisual(); } private void OnEnable() { if ((Object)(object)_nview == (Object)null) { _nview = ((Component)this).GetComponent(); } if ((Object)(object)_gate == (Object)null) { _gate = ((Component)this).GetComponent(); if ((Object)(object)_gate == (Object)null) { _gate = ((Component)this).GetComponentInChildren(true); } } if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && !((Object)(object)_gate == (Object)null)) { BCSSignalRegistry.RegisterReceiver(this); BCSSignalRegistry.InvalidateAllEmitterCaches(); UpdateSignalConfiguredVisual(); } } private void OnDisable() { BCSSignalRegistry.UnregisterReceiver(this); ClearActiveEmitters(); } private void OnDestroy() { BCSSignalRegistry.UnregisterReceiver(this); ClearActiveEmitters(); } private void Update() { HandleDurationInput(); UpdateSignalConfiguredVisual(); } public void RequestSignalStart(string signalName, string emitterId) { if ((Object)(object)_nview != (Object)null && _nview.IsValid()) { _nview.InvokeRPC("RPC_SignalStart", new object[2] { signalName ?? string.Empty, emitterId ?? string.Empty }); } } public void RequestSignalStop(string signalName, string emitterId) { if ((Object)(object)_nview != (Object)null && _nview.IsValid()) { _nview.InvokeRPC("RPC_SignalStop", new object[2] { signalName ?? string.Empty, emitterId ?? string.Empty }); } } private void RPC_SignalStart(long sender, string signalName, string emitterId) { if (SignalMatches(signalName) && !string.IsNullOrEmpty(emitterId)) { bool flag = !IsEventActive(); _activeEmitterIds.Add(emitterId); float eventDuration = GetEventDuration(); if (eventDuration > 0f) { StopEmitterDurationRoutine(emitterId); _emitterDurationRoutines[emitterId] = ((MonoBehaviour)this).StartCoroutine(EventDurationRoutine(eventDuration, emitterId)); } if (flag) { ApplyGateState(GetEventState()); } } } private void RPC_SignalStop(long sender, string signalName, string emitterId) { if (SignalMatches(signalName) && !string.IsNullOrEmpty(emitterId) && IsEventActive() && !(GetEventDuration() > 0f)) { RemoveActiveEmitter(emitterId, stopRoutine: true); } } private IEnumerator EventDurationRoutine(float duration, string emitterId) { yield return (object)new WaitForSeconds(duration); RemoveActiveEmitter(emitterId, stopRoutine: false); } private void RemoveActiveEmitter(string emitterId, bool stopRoutine) { if (!string.IsNullOrEmpty(emitterId)) { if (stopRoutine) { StopEmitterDurationRoutine(emitterId); } else { _emitterDurationRoutines.Remove(emitterId); } _activeEmitterIds.Remove(emitterId); if (_activeEmitterIds.Count <= 0) { EndEvent(); } } } private void StopEmitterDurationRoutine(string emitterId) { if (_emitterDurationRoutines.TryGetValue(emitterId, out var value) && value != null) { ((MonoBehaviour)this).StopCoroutine(value); } _emitterDurationRoutines.Remove(emitterId); } private bool IsEventActive() { return _activeEmitterIds.Count > 0; } private void ClearActiveEmitters() { foreach (KeyValuePair emitterDurationRoutine in _emitterDurationRoutines) { if (emitterDurationRoutine.Value != null) { ((MonoBehaviour)this).StopCoroutine(emitterDurationRoutine.Value); } } _emitterDurationRoutines.Clear(); _activeEmitterIds.Clear(); } private void EndEvent() { ApplyGateState(GetOppositeState(GetEventState())); } private void ApplyGateState(BCSLiftGateSignalState state) { if (!((Object)(object)_gate == (Object)null)) { if (state == BCSLiftGateSignalState.Open) { _gate.RequestOpen(); } else { _gate.RequestClose(); } } } public void RequestSetSignalNameFromUser() { if ((Object)(object)TextInput.instance != (Object)null) { TextInput.instance.RequestText((TextReceiver)(object)this, "Signal name", 32); } } public void ToggleEventStateFromUser() { BCSLiftGateSignalState eventState = ((GetEventState() == BCSLiftGateSignalState.Closed) ? BCSLiftGateSignalState.Open : BCSLiftGateSignalState.Closed); SetEventState(eventState); } public string GetExtraHoverText() { m_lastHoverTime = Time.time; string text = (string.IsNullOrEmpty(GetSignalName()) ? "NULL" : GetSignalName()); BCSLiftGateSignalState eventState = GetEventState(); BCSLiftGateSignalState oppositeState = GetOppositeState(eventState); return "\n[Shift+$KEY_Use] Signal: " + text + "\n[Alt+$KEY_Use] Event: " + eventState.ToString() + " (Default: " + oppositeState.ToString() + ")\n[+ / -] Duration: " + GetEventDuration().ToString("0") + "s"; } public string GetText() { return GetSignalName(); } public void SetText(string text) { SetSignalName((text == null) ? string.Empty : text.Trim()); } private void SetSignalName(string signalName) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetSignalName", new object[1] { signalName ?? string.Empty }); } } private void SetEventState(BCSLiftGateSignalState state) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetEventState", new object[1] { (int)state }); } } private void SetDuration(float duration) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetDuration", new object[1] { Mathf.Clamp(duration, m_minDuration, m_maxDuration) }); } } private void RPC_SetSignalName(long sender, string value) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { _nview.GetZDO().Set("BCS_SignalName", value ?? string.Empty); ClearActiveEmitters(); BCSSignalRegistry.InvalidateAllEmitterCaches(); UpdateSignalConfiguredVisual(); } } private void RPC_SetEventState(long sender, int value) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { value = Mathf.Clamp(value, 0, 1); _nview.GetZDO().Set("BCS_LiftGateEventState", value); } } private void RPC_SetDuration(long sender, float value) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.IsOwner()) { _nview.GetZDO().Set("BCS_SignalEventDuration", Mathf.Clamp(value, m_minDuration, m_maxDuration)); } } private void UpdateSignalConfiguredVisual() { bool flag = !string.IsNullOrEmpty(GetSignalName()); bool flag2 = flag && IsEventActive(); if ((Object)(object)m_signalConfiguredObject != (Object)null) { m_signalConfiguredObject.SetActive(flag && !flag2); } if ((Object)(object)m_signalActiveObject != (Object)null) { m_signalActiveObject.SetActive(flag2); } } private void HandleDurationInput() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!(Time.time - m_lastHoverTime > 0.25f) && PrivateArea.CheckAccess(((Component)this).transform.position, 0f, false, false)) { if (Input.GetKeyDown((KeyCode)61) || Input.GetKeyDown((KeyCode)270)) { SetDuration(GetEventDuration() + m_durationStep); } if (Input.GetKeyDown((KeyCode)45) || Input.GetKeyDown((KeyCode)269)) { SetDuration(GetEventDuration() - m_durationStep); } } } private bool SignalMatches(string signalName) { string signalName2 = GetSignalName(); return !string.IsNullOrEmpty(signalName2) && string.Equals(signalName2, signalName, StringComparison.Ordinal); } public string GetSignalName() { return ((Object)(object)_nview != (Object)null && _nview.IsValid()) ? _nview.GetZDO().GetString("BCS_SignalName", string.Empty) : string.Empty; } public Transform GetSignalTransform() { return ((Component)this).transform; } public ZNetView GetSignalNetView() { return _nview; } public BCSLiftGateSignalState GetEventState() { int num = ((!((Object)(object)_nview != (Object)null) || !_nview.IsValid()) ? 1 : _nview.GetZDO().GetInt("BCS_LiftGateEventState", 1)); return (num == 1) ? BCSLiftGateSignalState.Open : BCSLiftGateSignalState.Closed; } public float GetEventDuration() { return ((Object)(object)_nview != (Object)null && _nview.IsValid()) ? Mathf.Clamp(_nview.GetZDO().GetFloat("BCS_SignalEventDuration", m_defaultEventDuration), m_minDuration, m_maxDuration) : m_defaultEventDuration; } private static BCSLiftGateSignalState GetOppositeState(BCSLiftGateSignalState state) { return (state != BCSLiftGateSignalState.Open) ? BCSLiftGateSignalState.Open : BCSLiftGateSignalState.Closed; } } public static class BCSSignalPrefabConfigurator { public static void Configure(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { Debug.LogWarning((object)"[BCS] ConfigureSignalPiece: prefab == null"); return; } switch (((Object)prefab).name) { case "pressenceSignalEmitter_bal": ConfigurePresenceSignalEmitter(prefab); break; case "railtrackSignalEmitter_bal": ConfigureSignalEmitter(prefab); break; case "railtrackLampReciver_bal": case "railtrackSpeakerReciver_bal": ConfigureSignalStateReceiver(prefab); break; case "railSignalDoor_bal": ConfigureSignalDoorReceiver(prefab); break; case "railSignalLiftGate_bal": case "railtrackLiftGateReciver_bal": case "railtrackLiftGateReceiver_bal": ConfigureSignalLiftGateReceiver(prefab); break; default: Debug.LogWarning((object)("[BCS] ConfigureSignalPiece: unknown prefab: " + ((Object)prefab).name)); break; } } private static void ConfigureSignalEmitter(GameObject prefab) { //IL_00c5: 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) BCSSignalEmitter orAdd = BCSPrefabFind.GetOrAdd(prefab); orAdd.m_name = "Signal Emitter"; orAdd.m_defaultRange = 5f; orAdd.m_minRange = 1f; orAdd.m_maxRange = 50f; orAdd.m_rangeStep = 1f; orAdd.m_disabledObject = BCSPrefabFind.FindGameObjectDeep(prefab, "disabled"); orAdd.m_enabledObject = BCSPrefabFind.FindGameObjectDeep(prefab, "enabled"); orAdd.m_signalObject = BCSPrefabFind.FindGameObjectDeep(prefab, "signal"); orAdd.m_stateCheckInterval = 0.1f; orAdd.m_stoppedDistanceDelta = 0.02f; orAdd.m_stopConfirmTime = 0.5f; orAdd.m_cartMoveDistanceThreshold = 0.02f; orAdd.m_attachScanDelay = 0.25f; orAdd.m_cartDetectionMask = LayerMask.op_Implicit(LayerMask.GetMask(new string[2] { "character_noenv", "vehicle" })); orAdd.m_railAttachTriggerObject = BCSPrefabFind.FindGameObjectDeep(prefab, "RailAttachTrigger"); orAdd.m_cartDetectorTriggerObject = BCSPrefabFind.FindGameObjectDeep(prefab, "CartDetectorTrigger"); GameObject val = BCSPrefabFind.FindGameObjectDeep(prefab, "AreaMarker"); orAdd.m_areaMarker = (((Object)(object)val != (Object)null) ? val.GetComponent() : null); ConfigureSignalRelay(orAdd.m_railAttachTriggerObject, prefab, "RailAttachTrigger", BCSSignalTriggerRelayType.RailAttach); ConfigureSignalRelay(orAdd.m_cartDetectorTriggerObject, prefab, "CartDetectorTrigger", BCSSignalTriggerRelayType.CartDetector); ConfigureDisableInPlacementGhost(prefab, (Behaviour)(object)orAdd); } private static void ConfigureSignalRelay(GameObject triggerObject, GameObject prefab, string childName, BCSSignalTriggerRelayType relayType) { if ((Object)(object)triggerObject == (Object)null) { Debug.LogWarning((object)("[BCS] ConfigureSignalRelay: missing " + childName + " on " + ((Object)prefab).name)); return; } Collider component = triggerObject.GetComponent(); if ((Object)(object)component == (Object)null) { Debug.LogWarning((object)("[BCS] ConfigureSignalRelay: collider missing on " + childName + " in " + ((Object)prefab).name)); } else { component.isTrigger = true; } BCSSignalTriggerRelay orAdd = BCSPrefabFind.GetOrAdd(triggerObject); orAdd.m_type = relayType; } private static void ConfigurePresenceSignalEmitter(GameObject prefab) { BCSPresenceSignalEmitter orAdd = BCSPrefabFind.GetOrAdd(prefab); orAdd.m_name = "Presence Signal Emitter"; orAdd.m_defaultRange = 5f; orAdd.m_minRange = 1f; orAdd.m_maxRange = 50f; orAdd.m_rangeStep = 1f; orAdd.m_defaultTarget = BCSPresenceSignalTarget.Players; orAdd.m_defaultShape = BCSPresenceSignalShape.Zone; orAdd.m_defaultEvent = BCSPresenceSignalEvent.Present; orAdd.m_stateCheckInterval = 0.75f; orAdd.m_stopConfirmTime = 0.5f; orAdd.m_moveDistanceThreshold = 0.03f; orAdd.m_zoneTriggerObject = BCSPrefabFind.FindGameObjectDeep(prefab, "ZoneDetectorTrigger"); orAdd.m_directionalTriggerObject = BCSPrefabFind.FindGameObjectDeep(prefab, "DirectionDetectorTrigger"); orAdd.m_disabledObject = BCSPrefabFind.FindGameObjectDeep(prefab, "disabled"); orAdd.m_enabledObject = BCSPrefabFind.FindGameObjectDeep(prefab, "enabled"); orAdd.m_signalObject = BCSPrefabFind.FindGameObjectDeep(prefab, "signal"); GameObject val = BCSPrefabFind.FindGameObjectDeep(prefab, "AreaMarker"); orAdd.m_areaMarker = (((Object)(object)val != (Object)null) ? val.GetComponent() : null); ConfigurePresenceSignalRelay(prefab, "ZoneDetectorTrigger", BCSPresenceSignalTriggerType.Zone); ConfigurePresenceSignalRelay(prefab, "DirectionDetectorTrigger", BCSPresenceSignalTriggerType.Directional); ConfigureDisableInPlacementGhost(prefab, (Behaviour)(object)orAdd); } private static void ConfigurePresenceSignalRelay(GameObject prefab, string childName, BCSPresenceSignalTriggerType relayType) { GameObject val = BCSPrefabFind.FindGameObjectDeep(prefab, childName); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("[BCS] ConfigurePresenceSignalRelay: missing " + childName + " on " + ((Object)prefab).name)); return; } Collider component = val.GetComponent(); if ((Object)(object)component == (Object)null) { Debug.LogWarning((object)("[BCS] ConfigurePresenceSignalRelay: collider missing on " + childName + " in " + ((Object)prefab).name)); } else { component.isTrigger = true; } BCSPresenceSignalTriggerRelay orAdd = BCSPrefabFind.GetOrAdd(val); orAdd.m_type = relayType; } private static void ConfigureSignalStateReceiver(GameObject prefab) { BCSSignalStateReceiver orAdd = BCSPrefabFind.GetOrAdd(prefab); orAdd.m_name = ((((Object)prefab).name == "railtrackSpeakerReciver_bal") ? "Signal Audio Receiver" : "Signal Light Receiver"); orAdd.m_defaultEventDuration = 0f; orAdd.m_durationStep = 1f; orAdd.m_minDuration = 0f; orAdd.m_maxDuration = 120f; orAdd.m_enableCtrlPreview = true; orAdd.m_previewSeconds = 2f; Transform val = BCSPrefabFind.FindTransformDeep(prefab, "states") ?? BCSPrefabFind.FindTransformDeep(prefab, "States"); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("[BCS] ConfigureSignalStateReceiver: missing states/States object on " + ((Object)prefab).name)); } ConfigureDisableInPlacementGhost(prefab, (Behaviour)(object)orAdd); } private static void ConfigureSignalDoorReceiver(GameObject prefab) { Door val = prefab.GetComponent(); if ((Object)(object)val == (Object)null) { val = prefab.GetComponentInChildren(true); } if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("[BCS] ConfigureSignalDoorReceiver: Door missing on " + ((Object)prefab).name)); return; } BCSSignalDoorReceiver bCSSignalDoorReceiver = ((Component)val).GetComponent(); if ((Object)(object)bCSSignalDoorReceiver == (Object)null) { bCSSignalDoorReceiver = ((Component)val).gameObject.AddComponent(); } bCSSignalDoorReceiver.m_name = "Signal Door Receiver"; bCSSignalDoorReceiver.m_defaultEventDuration = 0f; bCSSignalDoorReceiver.m_durationStep = 1f; bCSSignalDoorReceiver.m_minDuration = 0f; bCSSignalDoorReceiver.m_maxDuration = 120f; bCSSignalDoorReceiver.m_signalConfiguredObject = BCSPrefabFind.FindGameObjectDeep(prefab, "signal_configured") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "SignalConfigured"); bCSSignalDoorReceiver.m_signalActiveObject = BCSPrefabFind.FindGameObjectDeep(prefab, "signal_recived") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "signal_recived"); ConfigureDisableInPlacementGhost(prefab, (Behaviour)(object)bCSSignalDoorReceiver); } private static void ConfigureSignalLiftGateReceiver(GameObject prefab) { //IL_0051: 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_00db: 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) BalrondLiftGate orAdd = BCSPrefabFind.GetOrAdd(prefab); orAdd.m_name = "Lift Gate"; orAdd.m_enabled = true; orAdd.m_defaultOpen = false; orAdd.m_gatePivot = BCSPrefabFind.FindTransformDeep(prefab, "gate_pivot") ?? BCSPrefabFind.FindTransformDeep(prefab, "GatePivot") ?? BCSPrefabFind.FindTransformDeep(prefab, "pivot"); orAdd.m_gateAxis = Vector3.right; orAdd.m_openAngle = 85f; orAdd.m_animationSeconds = 2f; orAdd.m_openDirection = 1f; orAdd.m_gearStatic = BCSPrefabFind.FindTransformDeep(prefab, "m_gearStatic") ?? BCSPrefabFind.FindTransformDeep(prefab, "gear_static") ?? BCSPrefabFind.FindTransformDeep(prefab, "gear_A_static"); orAdd.m_gearBridge = BCSPrefabFind.FindTransformDeep(prefab, "m_gearBridge") ?? BCSPrefabFind.FindTransformDeep(prefab, "gear_bridge") ?? BCSPrefabFind.FindTransformDeep(prefab, "gear_A_bridge"); orAdd.m_gearAxis = Vector3.right; orAdd.m_gearDegreesPerGateDegree = 4f; orAdd.m_animationActiveObject = BCSPrefabFind.FindGameObjectDeep(prefab, "drawbridge_animation_audio") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "gate_animation_audio") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "liftgate_animation_audio") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "animation_audio"); if ((Object)(object)orAdd.m_animationActiveObject != (Object)null) { orAdd.m_animationActiveObject.SetActive(false); } Door val = prefab.GetComponent(); if ((Object)(object)val == (Object)null) { val = prefab.GetComponentInChildren(true); } if ((Object)(object)val != (Object)null) { orAdd.m_openStartEffects = val.m_openEffects; orAdd.m_closeStartEffects = val.m_closeEffects; BCSPrefabFind.DestroyIfExists((Object)(object)val); } BCSSignalLiftGateReceiver orAdd2 = BCSPrefabFind.GetOrAdd(prefab); orAdd2.m_signalConfiguredObject = BCSPrefabFind.FindGameObjectDeep(prefab, "signal_configured") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "SignalConfigured"); orAdd2.m_signalActiveObject = BCSPrefabFind.FindGameObjectDeep(prefab, "signal_recived") ?? BCSPrefabFind.FindGameObjectDeep(prefab, "signal_recived"); orAdd2.m_name = "Signal Lift Gate Receiver"; orAdd2.m_defaultEventDuration = 0f; orAdd2.m_durationStep = 1f; orAdd2.m_minDuration = 0f; orAdd2.m_maxDuration = 120f; ConfigureDisableInPlacementGhost(prefab, (Behaviour)(object)orAdd); ConfigureDisableInPlacementGhost(prefab, (Behaviour)(object)orAdd2); } private static void ConfigureDisableInPlacementGhost(GameObject prefab, Behaviour behaviour) { if (!((Object)(object)prefab == (Object)null) && !((Object)(object)behaviour == (Object)null)) { DisableInPlacementGhost val = prefab.GetComponent(); if ((Object)(object)val == (Object)null) { val = prefab.AddComponent(); } if (val.m_components == null) { val.m_components = new List(); } if (!val.m_components.Contains(behaviour)) { val.m_components.Add(behaviour); } } } } [DisallowMultipleComponent] public class BCSSignalReceiverBase : MonoBehaviour, IBCSSignalReceiver { private const string RpcSetSignalName = "RPC_SetSignalName"; private const string RpcSetDuration = "RPC_SetDuration"; private const string RpcSignalStart = "RPC_SignalStart"; private const string RpcSignalStop = "RPC_SignalStop"; public float m_defaultEventDuration = 0f; public float m_minDuration = 0f; public float m_maxDuration = 120f; protected ZNetView m_nview; private Coroutine _eventRoutine; private bool _eventActive; private readonly HashSet _activeEmitterIds = new HashSet(); private readonly Dictionary _emitterDurationRoutines = new Dictionary(); protected virtual void Awake() { m_nview = ((Component)this).GetComponent(); if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { ((Behaviour)this).enabled = false; return; } m_nview.Register("RPC_SetSignalName", (Action)RPC_SetSignalName); m_nview.Register("RPC_SetDuration", (Action)RPC_SetDuration); m_nview.Register("RPC_SignalStart", (Action)RPC_SignalStart); m_nview.Register("RPC_SignalStop", (Action)RPC_SignalStop); } protected virtual void OnEnable() { BCSSignalRegistry.RegisterReceiver(this); } protected virtual void OnDisable() { BCSSignalRegistry.UnregisterReceiver(this); } protected virtual void OnDestroy() { BCSSignalRegistry.UnregisterReceiver(this); } public void RequestSignalStart(string signalName, string emitterId) { if ((Object)(object)m_nview != (Object)null && m_nview.IsValid()) { m_nview.InvokeRPC("RPC_SignalStart", new object[2] { signalName ?? string.Empty, emitterId ?? string.Empty }); } } public void RequestSignalStop(string signalName, string emitterId) { if ((Object)(object)m_nview != (Object)null && m_nview.IsValid()) { m_nview.InvokeRPC("RPC_SignalStop", new object[2] { signalName ?? string.Empty, emitterId ?? string.Empty }); } } private void RPC_SignalStart(long sender, string signalName, string emitterId) { if (SignalMatches(signalName) && !string.IsNullOrEmpty(emitterId)) { bool flag = _activeEmitterIds.Count == 0; _activeEmitterIds.Add(emitterId); _eventActive = true; SetSignalActive(active: true); float eventDuration = GetEventDuration(); if (eventDuration > 0f) { StopEmitterDurationRoutine(emitterId); _emitterDurationRoutines[emitterId] = ((MonoBehaviour)this).StartCoroutine(EventDurationRoutine(eventDuration, signalName, emitterId)); } if (flag) { OnSignalStarted(signalName); } } } private void RPC_SignalStop(long sender, string signalName, string emitterId) { if (SignalMatches(signalName) && !string.IsNullOrEmpty(emitterId) && _activeEmitterIds.Count > 0 && !(GetEventDuration() > 0f)) { RemoveActiveEmitter(signalName, emitterId, stopRoutine: true); } } private IEnumerator EventDurationRoutine(float duration, string signalName, string emitterId) { yield return (object)new WaitForSeconds(duration); RemoveActiveEmitter(signalName, emitterId, stopRoutine: false); } private void RemoveActiveEmitter(string signalName, string emitterId, bool stopRoutine) { if (!string.IsNullOrEmpty(emitterId)) { if (stopRoutine) { StopEmitterDurationRoutine(emitterId); } else { _emitterDurationRoutines.Remove(emitterId); } _activeEmitterIds.Remove(emitterId); if (_activeEmitterIds.Count > 0) { _eventActive = true; } else { EndEvent(signalName); } } } private void StopEmitterDurationRoutine(string emitterId) { if (_emitterDurationRoutines.TryGetValue(emitterId, out var value) && value != null) { ((MonoBehaviour)this).StopCoroutine(value); } _emitterDurationRoutines.Remove(emitterId); } protected bool HasActiveSignalSources() { return _activeEmitterIds.Count > 0; } protected void ClearActiveSignalSources() { foreach (KeyValuePair emitterDurationRoutine in _emitterDurationRoutines) { if (emitterDurationRoutine.Value != null) { ((MonoBehaviour)this).StopCoroutine(emitterDurationRoutine.Value); } } _emitterDurationRoutines.Clear(); _activeEmitterIds.Clear(); _eventActive = false; if (_eventRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_eventRoutine); _eventRoutine = null; } } private void EndEvent(string signalName) { _eventActive = false; if (_eventRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_eventRoutine); _eventRoutine = null; } SetSignalActive(active: false); OnSignalStopped(signalName); } protected virtual void OnSignalStarted(string signalName) { } protected virtual void OnSignalStopped(string signalName) { } public bool IsSignalActive() { return (Object)(object)m_nview != (Object)null && m_nview.IsValid() && m_nview.GetZDO().GetBool("hl_signal_receiver_active", false); } protected void SetSignalActive(bool active) { if (!((Object)(object)m_nview == (Object)null) && m_nview.IsValid()) { if (!m_nview.HasOwner()) { m_nview.ClaimOwnership(); } if (m_nview.IsOwner()) { m_nview.GetZDO().Set("hl_signal_receiver_active", active); } } } public string GetSignalName() { return ((Object)(object)m_nview != (Object)null && m_nview.IsValid()) ? m_nview.GetZDO().GetString("hl_signal_name", string.Empty) : string.Empty; } public void SetSignalName(string signalName) { if (!((Object)(object)m_nview == (Object)null) && m_nview.IsValid()) { if (!m_nview.HasOwner()) { m_nview.ClaimOwnership(); } m_nview.InvokeRPC("RPC_SetSignalName", new object[1] { signalName ?? string.Empty }); } } public float GetEventDuration() { return ((Object)(object)m_nview != (Object)null && m_nview.IsValid()) ? Mathf.Clamp(m_nview.GetZDO().GetFloat("hl_signal_event_duration", m_defaultEventDuration), m_minDuration, m_maxDuration) : m_defaultEventDuration; } public void SetEventDuration(float duration) { if (!((Object)(object)m_nview == (Object)null) && m_nview.IsValid()) { if (!m_nview.HasOwner()) { m_nview.ClaimOwnership(); } m_nview.InvokeRPC("RPC_SetDuration", new object[1] { Mathf.Clamp(duration, m_minDuration, m_maxDuration) }); } } private void RPC_SetSignalName(long sender, string value) { if (m_nview.IsOwner()) { m_nview.GetZDO().Set("hl_signal_name", value ?? string.Empty); SetSignalActive(active: false); ClearActiveSignalSources(); BCSSignalRegistry.InvalidateAllEmitterCaches(); } } private void RPC_SetDuration(long sender, float value) { if (m_nview.IsOwner()) { m_nview.GetZDO().Set("hl_signal_event_duration", Mathf.Clamp(value, m_minDuration, m_maxDuration)); } } protected bool SignalMatches(string signalName) { string signalName2 = GetSignalName(); return !string.IsNullOrEmpty(signalName2) && string.Equals(signalName2, signalName, StringComparison.Ordinal); } public Transform GetSignalTransform() { return ((Component)this).transform; } public ZNetView GetSignalNetView() { return m_nview; } } [DisallowMultipleComponent] [RequireComponent(typeof(BCSSignalReceiverBase))] public class BCSSignalReceiverConfigurator : MonoBehaviour, Hoverable, Interactable, TextReceiver { public string m_name = "Signal Receiver"; public float m_durationStep = 1f; private BCSSignalReceiverBase _receiver; private float _lastHoverTime = -1000f; private void Awake() { _receiver = ((Component)this).GetComponent(); } private void Update() { HandleDurationInput(); } public string GetHoverName() { return m_name; } public string GetHoverText() { _lastHoverTime = Time.time; if ((Object)(object)_receiver == (Object)null) { return m_name; } string text = (string.IsNullOrEmpty(_receiver.GetSignalName()) ? "" : _receiver.GetSignalName()); string text2 = (_receiver.IsSignalActive() ? "True" : "False"); string text3 = m_name + "\nSignal: " + text + "\nActive: " + text2 + "\nDuration: " + _receiver.GetEventDuration().ToString("0") + "s\n[$KEY_Use] Set signal name\n[+ / -] Duration"; return Localization.instance.Localize(text3); } public bool Interact(Humanoid human, bool hold, bool alt) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (hold) { return false; } if ((Object)(object)_receiver == (Object)null) { return false; } if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return true; } TextInput.instance.RequestText((TextReceiver)(object)this, "Signal name", 32); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public string GetText() { return ((Object)(object)_receiver != (Object)null) ? _receiver.GetSignalName() : string.Empty; } public void SetText(string text) { if (!((Object)(object)_receiver == (Object)null)) { _receiver.SetSignalName((text == null) ? string.Empty : text.Trim()); } } private void HandleDurationInput() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_receiver == (Object)null) && !(Time.time - _lastHoverTime > 0.25f) && PrivateArea.CheckAccess(((Component)this).transform.position, 0f, false, false)) { if (Input.GetKeyDown((KeyCode)61) || Input.GetKeyDown((KeyCode)270)) { _receiver.SetEventDuration(_receiver.GetEventDuration() + m_durationStep); } if (Input.GetKeyDown((KeyCode)45) || Input.GetKeyDown((KeyCode)269)) { _receiver.SetEventDuration(_receiver.GetEventDuration() - m_durationStep); } } } } public interface IBCSSignalReceiver { string GetSignalName(); Transform GetSignalTransform(); ZNetView GetSignalNetView(); void RequestSignalStart(string signalName, string emitterId); void RequestSignalStop(string signalName, string emitterId); } public static class BCSSignalRegistry { private static readonly List Emitters = new List(); private static readonly List PresenceEmitters = new List(); private static readonly List Receivers = new List(); public static void RegisterEmitter(BCSSignalEmitter emitter) { if ((Object)(object)emitter != (Object)null && !Emitters.Contains(emitter)) { Emitters.Add(emitter); } } public static void UnregisterEmitter(BCSSignalEmitter emitter) { if (!((Object)(object)emitter == (Object)null)) { Emitters.Remove(emitter); } } public static void RegisterPresenceEmitter(BCSPresenceSignalEmitter emitter) { if ((Object)(object)emitter != (Object)null && !PresenceEmitters.Contains(emitter)) { PresenceEmitters.Add(emitter); } } public static void UnregisterPresenceEmitter(BCSPresenceSignalEmitter emitter) { if (!((Object)(object)emitter == (Object)null)) { PresenceEmitters.Remove(emitter); } } public static void RegisterReceiver(IBCSSignalReceiver receiver) { if (receiver != null && IsValidReceiver(receiver) && !Receivers.Contains(receiver)) { Receivers.Add(receiver); InvalidateAllEmitterCaches(); } } public static void UnregisterReceiver(IBCSSignalReceiver receiver) { if (receiver != null) { Receivers.Remove(receiver); RemoveReceiverFromAllEmitters(receiver); } } public static void FindReceivers(string signalName, Vector3 origin, float range, List result) { //IL_0090: 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_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) result.Clear(); if (string.IsNullOrEmpty(signalName)) { return; } CleanupInvalidReferences(); float num = Mathf.Max(0f, range) * Mathf.Max(0f, range); for (int i = 0; i < Receivers.Count; i++) { IBCSSignalReceiver iBCSSignalReceiver = Receivers[i]; if (!IsValidReceiver(iBCSSignalReceiver) || !string.Equals(iBCSSignalReceiver.GetSignalName(), signalName, StringComparison.Ordinal)) { continue; } Transform signalTransform = iBCSSignalReceiver.GetSignalTransform(); if (!((Object)(object)signalTransform == (Object)null)) { Vector3 val = signalTransform.position - origin; if (!(((Vector3)(ref val)).sqrMagnitude > num)) { result.Add(iBCSSignalReceiver); } } } } public static void InvalidateAllEmitterCaches() { CleanupInvalidReferences(); for (int i = 0; i < Emitters.Count; i++) { if ((Object)(object)Emitters[i] != (Object)null) { Emitters[i].InvalidateReceiverCache(); } } for (int j = 0; j < PresenceEmitters.Count; j++) { if ((Object)(object)PresenceEmitters[j] != (Object)null) { PresenceEmitters[j].InvalidateReceiverCache(); } } } public static void RemoveReceiverFromAllEmitters(IBCSSignalReceiver receiver) { for (int i = 0; i < Emitters.Count; i++) { if ((Object)(object)Emitters[i] != (Object)null) { Emitters[i].RemoveCachedReceiver(receiver); } } for (int j = 0; j < PresenceEmitters.Count; j++) { if ((Object)(object)PresenceEmitters[j] != (Object)null) { PresenceEmitters[j].RemoveCachedReceiver(receiver); } } } public static bool IsValidReceiver(IBCSSignalReceiver receiver) { if (receiver == null) { return false; } try { Transform signalTransform = receiver.GetSignalTransform(); ZNetView signalNetView = receiver.GetSignalNetView(); return (Object)(object)signalTransform != (Object)null && (Object)(object)signalNetView != (Object)null && signalNetView.IsValid() && signalNetView.GetZDO() != null; } catch { return false; } } public static void CleanupInvalidReferences() { Receivers.RemoveAll((IBCSSignalReceiver r) => !IsValidReceiver(r)); Emitters.RemoveAll(delegate(BCSSignalEmitter e) { if (!((Object)(object)e == (Object)null)) { try { ZNetView component2 = ((Component)e).GetComponent(); return (Object)(object)component2 == (Object)null || !component2.IsValid() || component2.GetZDO() == null; } catch { return true; } } return true; }); PresenceEmitters.RemoveAll(delegate(BCSPresenceSignalEmitter e) { if (!((Object)(object)e == (Object)null)) { try { ZNetView component = ((Component)e).GetComponent(); return (Object)(object)component == (Object)null || !component.IsValid() || component.GetZDO() == null; } catch { return true; } } return true; }); } } public class BCSSignalStateReceiver : MonoBehaviour, Hoverable, Interactable, TextReceiver, IBCSSignalReceiver { private const string RpcSetSignalName = "RPC_SetSignalName"; private const string RpcSetDefaultState = "RPC_SetDefaultState"; private const string RpcSetEventState = "RPC_SetEventState"; private const string RpcSetDuration = "RPC_SetDuration"; private const string RpcSignalStart = "RPC_SignalStart"; private const string RpcSignalStop = "RPC_SignalStop"; public string m_name = "Signal Receiver"; [Header("Duration")] public float m_defaultEventDuration = 0f; public float m_durationStep = 1f; public float m_minDuration = 0f; public float m_maxDuration = 120f; [Header("Preview")] public bool m_enableCtrlPreview = true; public float m_previewSeconds = 2f; public GameObject m_signalActiveObject; public GameObject m_signalConfiguredObject; private ZNetView _nview; private Transform _statesRoot; private readonly List _states = new List(); private bool _eventActive; private Coroutine _eventRoutine; private Coroutine _previewRoutine; private readonly HashSet _activeEmitterIds = new HashSet(); private readonly Dictionary _emitterDurationRoutines = new Dictionary(); private float _lastHoverTime = -1000f; private void Awake() { _nview = ((Component)this).GetComponent(); if ((Object)(object)_nview == (Object)null || !_nview.IsValid()) { ((Behaviour)this).enabled = false; return; } _nview.Register("RPC_SetSignalName", (Action)RPC_SetSignalName); _nview.Register("RPC_SetDefaultState", (Action)RPC_SetDefaultState); _nview.Register("RPC_SetEventState", (Action)RPC_SetEventState); _nview.Register("RPC_SetDuration", (Action)RPC_SetDuration); _nview.Register("RPC_SignalStart", (Action)RPC_SignalStart); _nview.Register("RPC_SignalStop", (Action)RPC_SignalStop); CacheStates(); ApplyDefaultState(); } private void OnEnable() { if ((Object)(object)_nview == (Object)null) { _nview = ((Component)this).GetComponent(); } if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { if (_states.Count == 0) { CacheStates(); } BCSSignalRegistry.RegisterReceiver(this); BCSSignalRegistry.InvalidateAllEmitterCaches(); if (IsEventActive()) { ApplyEventState(); } else { ApplyDefaultState(); } } } private void OnDisable() { BCSSignalRegistry.UnregisterReceiver(this); ClearActiveEmitters(); if (_previewRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_previewRoutine); _previewRoutine = null; } } private void OnDestroy() { BCSSignalRegistry.UnregisterReceiver(this); ClearActiveEmitters(); if (_previewRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_previewRoutine); _previewRoutine = null; } } private void Update() { HandleDurationInput(); } private void CacheStates() { _states.Clear(); _statesRoot = null; Transform val = ((Component)this).transform.Find("states"); if ((Object)(object)val == (Object)null) { val = ((Component)this).transform.Find("States"); } _statesRoot = val; if (!((Object)(object)_statesRoot == (Object)null)) { for (int i = 0; i < _statesRoot.childCount; i++) { GameObject gameObject = ((Component)_statesRoot.GetChild(i)).gameObject; _states.Add(gameObject); } } } private void UpdateSignalConfiguredVisual() { bool flag = !string.IsNullOrEmpty(GetSignalName()); bool flag2 = flag && IsEventActive(); if ((Object)(object)m_signalConfiguredObject != (Object)null) { m_signalConfiguredObject.SetActive(flag && !flag2); } if ((Object)(object)m_signalActiveObject != (Object)null) { m_signalActiveObject.SetActive(flag2); } } public void RequestSignalStart(string signalName, string emitterId) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { _nview.InvokeRPC("RPC_SignalStart", new object[2] { signalName ?? string.Empty, emitterId ?? string.Empty }); } } public void RequestSignalStop(string signalName, string emitterId) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid()) { _nview.InvokeRPC("RPC_SignalStop", new object[2] { signalName ?? string.Empty, emitterId ?? string.Empty }); } } private void RPC_SignalStart(long sender, string signalName, string emitterId) { if (SignalMatches(signalName) && !string.IsNullOrEmpty(emitterId)) { bool flag = !IsEventActive(); _activeEmitterIds.Add(emitterId); _eventActive = true; float eventDuration = GetEventDuration(); if (eventDuration > 0f) { StopEmitterDurationRoutine(emitterId); _emitterDurationRoutines[emitterId] = ((MonoBehaviour)this).StartCoroutine(EventDurationRoutine(eventDuration, emitterId)); } if (flag) { ApplyEventState(); } } } private void RPC_SignalStop(long sender, string signalName, string emitterId) { if (SignalMatches(signalName) && !string.IsNullOrEmpty(emitterId) && IsEventActive() && !(GetEventDuration() > 0f)) { RemoveActiveEmitter(emitterId, stopRoutine: true); } } private IEnumerator EventDurationRoutine(float duration, string emitterId) { yield return (object)new WaitForSeconds(duration); RemoveActiveEmitter(emitterId, stopRoutine: false); } private void RemoveActiveEmitter(string emitterId, bool stopRoutine) { if (!string.IsNullOrEmpty(emitterId)) { if (stopRoutine) { StopEmitterDurationRoutine(emitterId); } else { _emitterDurationRoutines.Remove(emitterId); } _activeEmitterIds.Remove(emitterId); if (_activeEmitterIds.Count > 0) { _eventActive = true; } else { EndEvent(); } } } private void StopEmitterDurationRoutine(string emitterId) { if (_emitterDurationRoutines.TryGetValue(emitterId, out var value) && value != null) { ((MonoBehaviour)this).StopCoroutine(value); } _emitterDurationRoutines.Remove(emitterId); } private bool IsEventActive() { return _activeEmitterIds.Count > 0; } private void ClearActiveEmitters() { foreach (KeyValuePair emitterDurationRoutine in _emitterDurationRoutines) { if (emitterDurationRoutine.Value != null) { ((MonoBehaviour)this).StopCoroutine(emitterDurationRoutine.Value); } } _emitterDurationRoutines.Clear(); _activeEmitterIds.Clear(); _eventActive = false; if (_eventRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_eventRoutine); _eventRoutine = null; } } private void EndEvent() { _eventActive = false; if (_eventRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_eventRoutine); _eventRoutine = null; } ApplyDefaultState(); } private void ApplyDefaultState() { ApplyState(GetDefaultStateIndex()); } private void ApplyEventState() { ApplyState(GetEventStateIndex()); } private void ApplyState(int index) { if (_states.Count == 0) { CacheStates(); } for (int i = 0; i < _states.Count; i++) { if ((Object)(object)_states[i] != (Object)null) { _states[i].SetActive(i == index); } } } public string GetHoverName() { return m_name; } public string GetHoverText() { _lastHoverTime = Time.time; string value = (string.IsNullOrEmpty(GetSignalName()) ? "NULL" : GetSignalName()); string stateName = GetStateName(GetDefaultStateIndex()); string stateName2 = GetStateName(GetEventStateIndex()); StringBuilder stringBuilder = new StringBuilder(256); stringBuilder.Append(m_name); stringBuilder.Append("\n[$KEY_Use] Signal: ").Append(value); stringBuilder.Append("\n[Shift+$KEY_Use] Default: ").Append(stateName); stringBuilder.Append("\n[Alt+$KEY_Use] Event: ").Append(stateName2); stringBuilder.Append("\n[+ / -] Duration: ").Append(GetEventDuration().ToString("0")).Append("s"); if (m_enableCtrlPreview) { stringBuilder.Append("\n[Ctrl+$KEY_Use] Preview"); } return (Localization.instance != null) ? Localization.instance.Localize(stringBuilder.ToString()) : stringBuilder.ToString(); } public bool Interact(Humanoid human, bool hold, bool alt) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) if (hold) { return false; } Player val = (Player)(object)((human is Player) ? human : null); if ((Object)(object)val == (Object)null) { return false; } if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return true; } if (IsCtrlHeld() && m_enableCtrlPreview) { PreviewEventState(); return true; } if (IsShiftHeld()) { SetDefaultState(GetNextStateIndex(GetDefaultStateIndex())); return true; } if (IsAltHeld()) { SetEventState(GetNextStateIndex(GetEventStateIndex())); return true; } if ((Object)(object)TextInput.instance == (Object)null) { ((Character)val).Message((MessageType)2, "Text input unavailable", 0, (Sprite)null); return true; } TextInput.instance.RequestText((TextReceiver)(object)this, "Signal name", 32); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public string GetText() { return GetSignalName(); } public void SetText(string text) { SetSignalName((text == null) ? string.Empty : text.Trim()); } private void SetSignalName(string signalName) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetSignalName", new object[1] { signalName ?? string.Empty }); } private void SetDefaultState(int state) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetDefaultState", new object[1] { state }); } private void SetEventState(int state) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetEventState", new object[1] { state }); } private void SetDuration(float duration) { if (!_nview.HasOwner()) { _nview.ClaimOwnership(); } _nview.InvokeRPC("RPC_SetDuration", new object[1] { Mathf.Clamp(duration, m_minDuration, m_maxDuration) }); } private void RPC_SetSignalName(long sender, string value) { if (_nview.IsOwner()) { _nview.GetZDO().Set("hl_signal_name", value ?? string.Empty); ClearActiveEmitters(); ApplyDefaultState(); BCSSignalRegistry.InvalidateAllEmitterCaches(); } } private void RPC_SetDefaultState(long sender, int value) { if (_nview.IsOwner()) { _nview.GetZDO().Set("hl_signal_default_state", ClampStateIndex(value)); if (!IsEventActive() && _previewRoutine == null) { ApplyDefaultState(); } } } private void RPC_SetEventState(long sender, int value) { if (_nview.IsOwner()) { _nview.GetZDO().Set("hl_signal_event_state", ClampStateIndex(value)); if (IsEventActive()) { ApplyEventState(); } } } private void RPC_SetDuration(long sender, float value) { if (_nview.IsOwner()) { _nview.GetZDO().Set("hl_signal_event_duration", Mathf.Clamp(value, m_minDuration, m_maxDuration)); } } private void HandleDurationInput() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!(Time.time - _lastHoverTime > 0.25f) && PrivateArea.CheckAccess(((Component)this).transform.position, 0f, false, false)) { if (Input.GetKeyDown((KeyCode)61) || Input.GetKeyDown((KeyCode)270)) { SetDuration(GetEventDuration() + m_durationStep); } if (Input.GetKeyDown((KeyCode)45) || Input.GetKeyDown((KeyCode)269)) { SetDuration(GetEventDuration() - m_durationStep); } } } private void PreviewEventState() { if (_previewRoutine != null) { ((MonoBehaviour)this).StopCoroutine(_previewRoutine); } _previewRoutine = ((MonoBehaviour)this).StartCoroutine(PreviewRoutine()); } private IEnumerator PreviewRoutine() { ApplyEventState(); yield return (object)new WaitForSeconds(Mathf.Max(0.1f, m_previewSeconds)); if (IsEventActive()) { ApplyEventState(); } else { ApplyDefaultState(); } _previewRoutine = null; } private bool SignalMatches(string signalName) { string signalName2 = GetSignalName(); return !string.IsNullOrEmpty(signalName2) && string.Equals(signalName2, signalName, StringComparison.Ordinal); } private int GetNextStateIndex(int current) { if (_states.Count == 0) { CacheStates(); } if (_states.Count <= 0) { return 0; } return (current + 1) % _states.Count; } private int ClampStateIndex(int value) { if (_states.Count == 0) { CacheStates(); } if (_states.Count <= 0) { return 0; } return Mathf.Clamp(value, 0, _states.Count - 1); } private string GetStateName(int index) { if (_states.Count == 0) { CacheStates(); } if (index < 0 || index >= _states.Count || (Object)(object)_states[index] == (Object)null) { return ""; } return ((Object)_states[index]).name; } public string GetSignalName() { return ((Object)(object)_nview != (Object)null && _nview.IsValid()) ? _nview.GetZDO().GetString("hl_signal_name", string.Empty) : string.Empty; } public Transform GetSignalTransform() { return ((Component)this).transform; } public ZNetView GetSignalNetView() { return _nview; } public int GetDefaultStateIndex() { return ((Object)(object)_nview != (Object)null && _nview.IsValid()) ? ClampStateIndex(_nview.GetZDO().GetInt("hl_signal_default_state", 0)) : 0; } public int GetEventStateIndex() { return ((Object)(object)_nview != (Object)null && _nview.IsValid()) ? ClampStateIndex(_nview.GetZDO().GetInt("hl_signal_event_state", 0)) : 0; } public float GetEventDuration() { return ((Object)(object)_nview != (Object)null && _nview.IsValid()) ? Mathf.Clamp(_nview.GetZDO().GetFloat("hl_signal_event_duration", m_defaultEventDuration), m_minDuration, m_maxDuration) : m_defaultEventDuration; } private static bool IsShiftHeld() { return Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303); } private static bool IsAltHeld() { return Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307); } private static bool IsCtrlHeld() { return Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305); } } public enum BCSSignalTriggerRelayType { RailAttach, CartDetector } public class BCSSignalTriggerRelay : MonoBehaviour { public BCSSignalTriggerRelayType m_type; private BCSSignalEmitter _emitter; private void Awake() { ResolveEmitter(); } private void OnEnable() { ResolveEmitter(); } private void ResolveEmitter() { if ((Object)(object)_emitter == (Object)null) { _emitter = ((Component)this).GetComponentInParent(); } } private void OnTriggerEnter(Collider other) { ResolveEmitter(); if ((Object)(object)_emitter != (Object)null) { _emitter.OnRelayTriggerEnter(this, other); } } private void OnTriggerExit(Collider other) { ResolveEmitter(); if ((Object)(object)_emitter != (Object)null) { _emitter.OnRelayTriggerExit(this, other); } } } public class BCSTrainRuntime : MonoBehaviour { public BCSCartRoot m_engineRoot; [Header("Speed")] public float m_baseSpeed = 8f; public float m_currentSpeed = 8f; public float m_minSpeed = 4f; public float m_maxSpeed = 16f; public float m_speedChangeRate = 2f; [Header("Speed Rail")] public bool m_useSpeedRailMultiplier = true; public float m_speedRailMultiplierResponse = 6f; private float _speedRailMultiplier = 1f; [Header("Straight Run Acceleration")] public bool m_useStraightRunAcceleration = true; public float m_straightRunRequiredMeters = 4f; public float m_straightRunBonusPerMeter = 0.35f; public float m_maxStraightRunBonus = 4f; public float m_straightRunResetRate = 8f; public float m_straightDirectionDotThreshold = 0.985f; private float _straightRunDistance; private float _straightRunBonusSpeed; private bool _straightRunInitialized; private Vector3 _lastStraightRunForward; [Header("Slope Speed")] public bool m_useSlopeSpeed = true; public float m_slopeSampleDistance = 0.25f; public float m_uphillSlowdownFactor = 1.2f; public float m_downhillBoostFactor = 1f; public float m_maxUphillNormalized = 0.3f; public float m_maxDownhillNormalized = 0.3f; public float m_minSpeedMultiplierUphill = 0.8f; public float m_maxSpeedMultiplierDownhill = 1.5f; [Header("Slope Momentum")] public bool m_useSlopeMomentum = true; public float m_slopeMomentumBuildRate = 1.35f; public float m_slopeMomentumDecayRate = 0.55f; public float m_maxSlopeMomentum = 1.5f; public float m_slopeMomentumSpeedInfluence = 1f; public float m_slopeMomentumDeadzone = 0.01f; [Header("Obstacle Detection")] private static readonly Collider[] ObstacleHits = (Collider[])(object)new Collider[32]; private readonly List _graphResultScratch = new List(32); private readonly List _endpointScratch = new List(8); private readonly HashSet _linearVisitedScratch = new HashSet(); private readonly Queue _graphQueueScratch = new Queue(32); private readonly HashSet _graphVisitedScratch = new HashSet(); private readonly HashSet _pathVisitedScratch = new HashSet(); public float m_obstacleCheckForwardOffset = 0.18f; public Vector3 m_obstacleCheckHalfExtents = new Vector3(0.12f, 0.18f, 0.22f); public LayerMask m_obstacleMask = LayerMask.op_Implicit(-5); private bool _drawbridgeStopActive; private string _drawbridgeStopRailId = string.Empty; private bool _signalStopActive; private string _signalStopRailId = string.Empty; private BCSRailNodeSide _signalStopEntrySide = BCSRailNodeSide.A; [SerializeField] private string[] m_ignoredLayerNames = new string[20] { "TransparentFX", "Ignore Raycast", "Water", "UI", "effect", "item", "ghost", "character_trigger", "piece_nonsolid", "character_ghost", "hitbox", "skybox", "WaterVolume", "weapon", "blocker", "pathblocker", "viewblock", "character_net", "character_noenv", "smoke" }; [Header("Stop Rail")] public float m_stopRailCenterTolerance = 0.08f; [Header("Soft Stop Braking")] public bool m_useSoftStopBraking = true; public float m_softStopBrakeStartDistance = 1.25f; public float m_softStopMinApproachSpeed = 0.2f; public float m_softStopBrakeExponent = 1.5f; [Header("Jump Rider Effects")] public bool m_enableJumpRiderEffects = true; public bool m_attachJumpRiderEffectsToCart = true; public float m_jumpEffectCooldown = 0.35f; [Header("Debug")] public bool m_enableDebugLogs = false; public bool m_enableVerboseObstacleLogs = false; public bool m_enableMovementLogs = false; public bool m_enableFollowerLogs = false; public bool m_enableStopLogs = false; public bool m_enableSpeedLogs = false; private readonly List _trainCache = new List(); private string _lastLeaderRailId = string.Empty; private bool _hadRunningStateLastFrame; private bool _pendingSoftStop; private string _pendingStopRailId = string.Empty; private float _pendingStopDistance; private string _pendingStopReason = string.Empty; private float _slopeMomentum; private bool _timedStopActive; private double _timedStopEndTime; private string _timedStopRailId = string.Empty; private void Awake() { if ((Object)(object)m_engineRoot == (Object)null) { m_engineRoot = ((Component)this).GetComponent(); } if ((Object)(object)m_engineRoot != (Object)null) { _lastLeaderRailId = m_engineRoot.GetCurrentRailId(); } m_currentSpeed = Mathf.Clamp(BCSCommonUtility.SanitizeFloat(m_currentSpeed, m_baseSpeed), m_minSpeed, m_maxSpeed); _slopeMomentum = 0f; Log("Awake engineRoot=" + SafeCartId(m_engineRoot) + " rail=" + BCSCommonUtility.SafeString(_lastLeaderRailId)); } private void FixedUpdate() { if (!((Object)(object)m_engineRoot == (Object)null)) { UpdateTimedStopResume(); UpdateDrawbridgeStopResume(); UpdateSignalStopResume(); if (m_engineRoot.IsRunning() && !_hadRunningStateLastFrame) { _speedRailMultiplier = 1f; _lastLeaderRailId = m_engineRoot.GetCurrentRailId(); ClearPendingSoftStop(); ClearTimedStop(clearRailCountdown: true); ClearDrawbridgeStop(); ClearSignalStop(); _slopeMomentum = 0f; ResetStraightRunAcceleration(); SetHaltingForConnectedTrain(halting: false); Log("Detected train start. lastLeaderRailId=" + BCSCommonUtility.SafeString(_lastLeaderRailId)); } if (!m_engineRoot.IsRunning() && _hadRunningStateLastFrame) { _speedRailMultiplier = 1f; ClearPendingSoftStop(); m_currentSpeed = Mathf.Clamp(BCSCommonUtility.SanitizeFloat(m_baseSpeed, 2.5f), m_minSpeed, m_maxSpeed); _slopeMomentum = 0f; ResetStraightRunAcceleration(); SetHaltingForConnectedTrain(halting: false); } _hadRunningStateLastFrame = m_engineRoot.IsRunning(); if (CanRunUpdate()) { UpdateTrainMovement(Time.fixedDeltaTime); } } } private void TryRequestSoftStopForEnteredSignalStopRail(string previousRailId, string currentRailId) { if (_pendingSoftStop || _signalStopActive || (Object)(object)m_engineRoot == (Object)null || string.IsNullOrEmpty(currentRailId) || currentRailId == previousRailId) { return; } BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(currentRailId); if ((Object)(object)bCSRailPiece == (Object)null) { return; } BCSRailSignalStopReceiver component = ((Component)bCSRailPiece).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsStopActive()) { return; } float length = bCSRailPiece.GetLength(); if (length <= 0.001f) { return; } bool travelReversedOnRail = m_engineRoot.GetTravelReversedOnRail(); BCSRailNodeSide entrySide = (travelReversedOnRail ? bCSRailPiece.GetFarTraversalSide() : bCSRailPiece.GetNearTraversalSide()); if (component.ShouldStopForEntrySide(entrySide)) { float distanceOnRail = m_engineRoot.GetDistanceOnRail(); float num = length * 0.5f; if (travelReversedOnRail ? (num <= distanceOnRail) : (num >= distanceOnRail)) { StartSignalStop(currentRailId); RequestSoftStop(currentRailId, num, "signal stop rail active"); } } } private void UpdateSignalStopResume() { if (!_signalStopActive || (Object)(object)m_engineRoot == (Object)null) { return; } if (m_engineRoot.IsRunning()) { ClearSignalStop(); } else { if (!CanRestartAfterTimedStop()) { return; } string text = ((!string.IsNullOrEmpty(_signalStopRailId)) ? _signalStopRailId : m_engineRoot.GetCurrentRailId()); if (string.IsNullOrEmpty(text)) { ClearSignalStop(); return; } BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(text); if ((Object)(object)bCSRailPiece == (Object)null) { ClearSignalStop(); return; } BCSRailSignalStopReceiver component = ((Component)bCSRailPiece).GetComponent(); if ((Object)(object)component == (Object)null) { ClearSignalStop(); } else if (!component.IsStopActive()) { ClearSignalStop(); ClearTimedStop(clearRailCountdown: true); ClearPendingSoftStop(); m_engineRoot.StartTrain(); if (m_enableStopLogs) { Log("Signal stop rail resumed train rail=" + BCSCommonUtility.SafeString(bCSRailPiece.GetRailId())); } } } } private void StartSignalStop(string railId) { _signalStopActive = true; _signalStopRailId = railId ?? string.Empty; if (m_enableStopLogs) { Log("Signal stop started rail=" + BCSCommonUtility.SafeString(_signalStopRailId)); } } private void ClearSignalStop() { _signalStopActive = false; _signalStopRailId = string.Empty; } private void TryRequestSoftStopForEnteredDrawbridgeRail(string previousRailId, string currentRailId) { if ((Object)(object)m_engineRoot == (Object)null || string.IsNullOrEmpty(currentRailId) || currentRailId == previousRailId) { return; } BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(currentRailId); if ((Object)(object)bCSRailPiece == (Object)null) { return; } BCSDrawbridgeRail drawbridge = bCSRailPiece.GetDrawbridge(); if (!((Object)(object)drawbridge == (Object)null) && drawbridge.IsDrawbridgeRail() && !drawbridge.IsPassableForTrain()) { float distanceOnRail = m_engineRoot.GetDistanceOnRail(); if (drawbridge.TryGetStopDistanceFromCurrentDistance(distanceOnRail, out var stopDistance)) { _drawbridgeStopActive = true; _drawbridgeStopRailId = currentRailId; RequestSoftStop(currentRailId, stopDistance, "drawbridge blocked"); } } } private void UpdateDrawbridgeStopResume() { if (!_drawbridgeStopActive || (Object)(object)m_engineRoot == (Object)null) { return; } if (m_engineRoot.IsRunning()) { ClearDrawbridgeStop(); } else { if (!CanRestartAfterTimedStop()) { return; } string text = ((!string.IsNullOrEmpty(_drawbridgeStopRailId)) ? _drawbridgeStopRailId : m_engineRoot.GetCurrentRailId()); if (string.IsNullOrEmpty(text)) { ClearDrawbridgeStop(); return; } BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(text); if ((Object)(object)bCSRailPiece == (Object)null) { ClearDrawbridgeStop(); return; } BCSDrawbridgeRail drawbridge = bCSRailPiece.GetDrawbridge(); if ((Object)(object)drawbridge == (Object)null) { ClearDrawbridgeStop(); } else if (drawbridge.IsPassableForTrain()) { ClearDrawbridgeStop(); m_engineRoot.StartTrain(); if (m_enableStopLogs) { Log("Drawbridge stop resumed train rail=" + BCSCommonUtility.SafeString(bCSRailPiece.GetRailId())); } } } } private void StartDrawbridgeStop(string railId) { _drawbridgeStopActive = true; _drawbridgeStopRailId = railId ?? string.Empty; if (m_enableStopLogs) { Log("Drawbridge stop started rail=" + BCSCommonUtility.SafeString(_drawbridgeStopRailId)); } } private void ClearDrawbridgeStop() { _drawbridgeStopActive = false; _drawbridgeStopRailId = string.Empty; } private void UpdateTimedStopResume() { if ((Object)(object)m_engineRoot == (Object)null) { return; } if (!_timedStopActive) { TryRestoreTimedStopFromCurrentRail(); } if (!_timedStopActive) { return; } if (m_engineRoot.IsRunning()) { ClearTimedStop(clearRailCountdown: true); } else if (!(GetNetworkTimeSeconds() < _timedStopEndTime)) { ClearTimedStop(clearRailCountdown: true); if (CanRestartAfterTimedStop()) { m_engineRoot.StartTrain(); } } } private void TryRestoreTimedStopFromCurrentRail() { if ((Object)(object)m_engineRoot == (Object)null || m_engineRoot.IsRunning()) { return; } string currentRailId = m_engineRoot.GetCurrentRailId(); if (string.IsNullOrEmpty(currentRailId)) { return; } BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(currentRailId); if ((Object)(object)bCSRailPiece == (Object)null) { return; } float stopTimerRemainingSeconds = bCSRailPiece.GetStopTimerRemainingSeconds(); if (!(stopTimerRemainingSeconds <= 0f)) { _timedStopActive = true; _timedStopRailId = currentRailId; _timedStopEndTime = GetNetworkTimeSeconds() + (double)stopTimerRemainingSeconds; if (m_enableStopLogs) { Log("Timed stop restored rail=" + BCSCommonUtility.SafeString(_timedStopRailId) + " remaining=" + stopTimerRemainingSeconds.ToString("0.###")); } } } private bool CanRestartAfterTimedStop() { if ((Object)(object)m_engineRoot == (Object)null) { return false; } ZNetView netView = m_engineRoot.GetNetView(); if ((Object)(object)netView == (Object)null || !netView.IsValid() || !netView.IsOwner()) { return false; } if (!m_engineRoot.IsPowered()) { return false; } if (!m_engineRoot.CanBeDominantEngine()) { return false; } if (string.IsNullOrEmpty(m_engineRoot.GetCurrentRailId())) { return false; } return true; } private void StartTimedStop(BCSRailPiece rail, int seconds) { if ((Object)(object)rail == (Object)null || seconds <= 0) { ClearTimedStop(clearRailCountdown: true); return; } _timedStopActive = true; _timedStopRailId = rail.GetRailId(); _timedStopEndTime = GetNetworkTimeSeconds() + (double)seconds; rail.StartStopTimerCountdown(seconds); if (m_enableStopLogs) { Log("Timed stop started rail=" + BCSCommonUtility.SafeString(_timedStopRailId) + " seconds=" + seconds); } } private void ClearTimedStop(bool clearRailCountdown) { if (clearRailCountdown && !string.IsNullOrEmpty(_timedStopRailId)) { BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(_timedStopRailId); if ((Object)(object)bCSRailPiece != (Object)null) { bCSRailPiece.ClearStopTimerCountdown(); } } _timedStopActive = false; _timedStopEndTime = 0.0; _timedStopRailId = string.Empty; } private static double GetNetworkTimeSeconds() { return BCSCommonUtility.GetNetworkTimeSeconds(); } private bool CanRunUpdate() { if ((Object)(object)m_engineRoot == (Object)null) { Log("CanRunUpdate=false reason=no engine root"); return false; } ZNetView netView = m_engineRoot.GetNetView(); if ((Object)(object)netView == (Object)null) { Log("CanRunUpdate=false reason=nview null"); return false; } if (!netView.IsValid()) { Log("CanRunUpdate=false reason=nview invalid"); return false; } if (netView.GetZDO() == null) { Log("CanRunUpdate=false reason=zdo null"); return false; } if (!netView.IsOwner()) { Log("CanRunUpdate=false reason=not owner"); return false; } if (!m_engineRoot.IsRunning()) { return false; } if (!m_engineRoot.IsPowered()) { Log("CanRunUpdate=false reason=engine not powered"); return false; } string cartId = m_engineRoot.GetCartId(); if (string.IsNullOrEmpty(cartId)) { Log("CanRunUpdate=false reason=cart id empty"); return false; } string activeEngineId = m_engineRoot.GetActiveEngineId(); if (activeEngineId != cartId) { Log("CanRunUpdate=false reason=active engine mismatch active=" + BCSCommonUtility.SafeString(activeEngineId) + " mine=" + BCSCommonUtility.SafeString(cartId)); return false; } if (!m_engineRoot.CanBeDominantEngine()) { Log("CanRunUpdate=false reason=engine not at train end"); return false; } string currentRailId = m_engineRoot.GetCurrentRailId(); if (string.IsNullOrEmpty(currentRailId)) { Log("CanRunUpdate=false reason=current rail id empty"); return false; } return true; } private LayerMask GetFinalObstacleMask() { //IL_0002: 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_0021: Unknown result type (might be due to invalid IL or missing references) return LayerMask.op_Implicit(LayerMask.op_Implicit(m_obstacleMask) & ~BCSCommonUtility.GetIgnoredLayersMask(m_ignoredLayerNames)); } public void UpdateTrainMovement(float dt) { if ((Object)(object)m_engineRoot == (Object)null) { return; } dt = BCSCommonUtility.SanitizeFloat(dt, 0f); if (dt <= 0f) { return; } UpdateDynamicSpeed(dt); BuildOrderedTrainFromActiveEngine(_trainCache); if (_trainCache.Count == 0) { Log("UpdateTrainMovement: train cache empty -> stop"); ResetStraightRunAcceleration(); StopWholeTrain(alignToRail: false); return; } string currentRailId = m_engineRoot.GetCurrentRailId(); float distanceOnRail = m_engineRoot.GetDistanceOnRail(); bool travelReversedOnRail = m_engineRoot.GetTravelReversedOnRail(); if (!_pendingSoftStop) { if (HasObstacleAhead()) { TryRequestSoftStopOnCurrentRail("obstacle ahead"); } else if (HasForeignCartAhead()) { TryRequestSoftStopOnCurrentRail("foreign cart ahead"); } } if (!TryAdvanceLeader(dt)) { Log("UpdateTrainMovement: TryAdvanceLeader failed -> stop"); ResetStraightRunAcceleration(); StopWholeTrain(alignToRail: false); return; } ApplyFollowerPositions(); string currentRailId2 = m_engineRoot.GetCurrentRailId(); float distanceOnRail2 = m_engineRoot.GetDistanceOnRail(); bool travelReversedOnRail2 = m_engineRoot.GetTravelReversedOnRail(); UpdateStraightRunAcceleration(currentRailId, distanceOnRail, travelReversedOnRail, currentRailId2, distanceOnRail2, travelReversedOnRail2, dt); TryRequestSoftStopForEnteredStopRail(currentRailId, currentRailId2); TryRequestSoftStopForEnteredDrawbridgeRail(currentRailId, currentRailId2); TryRequestSoftStopForEnteredSignalStopRail(currentRailId, currentRailId2); if (_pendingSoftStop && HasReachedPendingStop(currentRailId, distanceOnRail, currentRailId2, distanceOnRail2)) { FinalizeSoftStop(); } else { _lastLeaderRailId = currentRailId2; } } private void UpdateStraightRunAcceleration(string previousRailId, float previousDistance, bool previousTravelReversed, string currentRailId, float currentDistance, bool currentTravelReversed, float dt) { //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_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_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) if (!m_useStraightRunAcceleration || _pendingSoftStop || (Object)(object)m_engineRoot == (Object)null) { DecayStraightRunAcceleration(dt); return; } BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(previousRailId); BCSRailPiece bCSRailPiece2 = BCSRailRegistry.FindById(currentRailId); if (!IsStraightAccelerationRail(bCSRailPiece) || !IsStraightAccelerationRail(bCSRailPiece2)) { DecayStraightRunAcceleration(dt); return; } if (!TryGetTravelPose(bCSRailPiece, previousDistance, previousTravelReversed, out var _, out var forward)) { DecayStraightRunAcceleration(dt); return; } if (!TryGetTravelPose(bCSRailPiece2, currentDistance, currentTravelReversed, out var _, out var forward2)) { DecayStraightRunAcceleration(dt); return; } float num = Mathf.Clamp(BCSCommonUtility.SanitizeFloat(m_straightDirectionDotThreshold, 0.985f), -1f, 1f); float num2 = Vector3.Dot(((Vector3)(ref forward)).normalized, ((Vector3)(ref forward2)).normalized); if (num2 < num) { DecayStraightRunAcceleration(dt); _straightRunInitialized = false; return; } if (_straightRunInitialized) { float num3 = Vector3.Dot(((Vector3)(ref _lastStraightRunForward)).normalized, ((Vector3)(ref forward2)).normalized); if (num3 < num) { DecayStraightRunAcceleration(dt); _straightRunInitialized = false; return; } } if (!TryGetStraightRunMovedDistance(bCSRailPiece, previousDistance, previousTravelReversed, bCSRailPiece2, currentDistance, currentTravelReversed, out var movedDistance)) { DecayStraightRunAcceleration(dt); return; } _straightRunInitialized = true; _lastStraightRunForward = ((Vector3)(ref forward2)).normalized; _straightRunDistance += movedDistance; float num4 = Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_straightRunRequiredMeters, 4f)); float num5 = Mathf.Max(0f, _straightRunDistance - num4); float num6 = num5 * Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_straightRunBonusPerMeter, 0.35f)); num6 = Mathf.Clamp(num6, 0f, Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_maxStraightRunBonus, 4f))); _straightRunBonusSpeed = Mathf.MoveTowards(_straightRunBonusSpeed, num6, Mathf.Max(0.01f, BCSCommonUtility.SanitizeFloat(m_speedChangeRate, 2f)) * dt); } private void DecayStraightRunAcceleration(float dt) { //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) _straightRunDistance = 0f; _straightRunInitialized = false; _lastStraightRunForward = Vector3.zero; _straightRunBonusSpeed = Mathf.MoveTowards(_straightRunBonusSpeed, 0f, Mathf.Max(0.01f, BCSCommonUtility.SanitizeFloat(m_straightRunResetRate, 8f)) * Mathf.Max(0f, dt)); } private void ResetStraightRunAcceleration() { //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) _straightRunDistance = 0f; _straightRunBonusSpeed = 0f; _straightRunInitialized = false; _lastStraightRunForward = Vector3.zero; } private bool IsStraightAccelerationRail(BCSRailPiece rail) { if ((Object)(object)rail == (Object)null) { return false; } if (rail.IsSwitchRail() || rail.IsCrossroadRail() || rail.IsJumpRail()) { return false; } return rail.m_pieceType == BCSRailPieceType.Straight || rail.m_pieceType == BCSRailPieceType.Speed; } private bool TryGetTravelPose(BCSRailPiece rail, float distance, bool travelReversed, out Vector3 pos, out Vector3 forward) { //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_000f: 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_0042: 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_0048: 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_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_0068: Unknown result type (might be due to invalid IL or missing references) pos = Vector3.zero; forward = Vector3.zero; if ((Object)(object)rail == (Object)null) { return false; } if (!rail.GetPose(distance, out pos, out var rot)) { return false; } forward = rot * Vector3.forward; if (travelReversed) { forward = -forward; } if (((Vector3)(ref forward)).sqrMagnitude <= 0.0001f) { return false; } ((Vector3)(ref forward)).Normalize(); return true; } private void UpdateDynamicSpeed(float dt) { float num = Mathf.Clamp(BCSCommonUtility.SanitizeFloat(m_baseSpeed, 2.5f), m_minSpeed, m_maxSpeed); float num2 = 0f; float num3 = 1f; float currentSpeedRailMultiplier = GetCurrentSpeedRailMultiplier(); if (m_useSpeedRailMultiplier) { _speedRailMultiplier = Mathf.MoveTowards(_speedRailMultiplier, currentSpeedRailMultiplier, Mathf.Max(0.01f, BCSCommonUtility.SanitizeFloat(m_speedRailMultiplierResponse, 6f)) * dt); } else { _speedRailMultiplier = 1f; } if (m_useSlopeSpeed) { num2 = GetCurrentSignedSlope(); num3 = GetSlopeSpeedMultiplier(num2); num *= num3; } if (m_useSlopeMomentum) { UpdateSlopeMomentum(num2, dt); num += _slopeMomentum * Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_slopeMomentumSpeedInfluence, 1f)); } else { _slopeMomentum = 0f; } if (m_useStraightRunAcceleration) { num += _straightRunBonusSpeed; } else { _straightRunDistance = 0f; _straightRunBonusSpeed = 0f; _straightRunInitialized = false; } num *= _speedRailMultiplier; if (m_useSoftStopBraking) { num = ApplySoftStopSpeedLimit(num); } num = Mathf.Clamp(num, m_minSpeed, m_maxSpeed); float num4 = Mathf.Max(0.01f, BCSCommonUtility.SanitizeFloat(m_speedChangeRate, 2f)); m_currentSpeed = Mathf.MoveTowards(BCSCommonUtility.SanitizeFloat(m_currentSpeed, num), num, num4 * dt); m_currentSpeed = Mathf.Clamp(m_currentSpeed, m_minSpeed, m_maxSpeed); if (m_enableSpeedLogs) { Log("Speed slope=" + num2.ToString("0.###") + " slopeMultiplier=" + num3.ToString("0.###") + " speedRailMultiplier=" + _speedRailMultiplier.ToString("0.###") + " momentum=" + _slopeMomentum.ToString("0.###") + " straightRun=" + _straightRunDistance.ToString("0.###") + " straightBonus=" + _straightRunBonusSpeed.ToString("0.###") + " target=" + num.ToString("0.###") + " current=" + m_currentSpeed.ToString("0.###")); } } private float GetCurrentSpeedRailMultiplier() { if (!m_useSpeedRailMultiplier || (Object)(object)m_engineRoot == (Object)null) { return 1f; } string currentRailId = m_engineRoot.GetCurrentRailId(); if (string.IsNullOrEmpty(currentRailId)) { return 1f; } BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(currentRailId); if ((Object)(object)bCSRailPiece == (Object)null) { return 1f; } return Mathf.Max(0.01f, bCSRailPiece.GetSpeedMultiplier()); } private void UpdateSlopeMomentum(float slope, float dt) { dt = Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(dt, 0f)); slope = BCSCommonUtility.SanitizeFloat(slope, 0f); float num = Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_slopeMomentumDeadzone, 0.01f)); float num2 = Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_slopeMomentumBuildRate, 1.35f)); float num3 = Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_slopeMomentumDecayRate, 0.55f)); float num4 = Mathf.Max(0f, BCSCommonUtility.SanitizeFloat(m_maxSlopeMomentum, 1.5f)); if (Mathf.Abs(slope) <= num) { _slopeMomentum = Mathf.MoveTowards(_slopeMomentum, 0f, num3 * dt); } else if (slope < 0f) { float num5 = Mathf.Clamp01((0f - slope) / Mathf.Max(0.01f, m_maxDownhillNormalized)); float num6 = num5 * num2; _slopeMomentum = Mathf.MoveTowards(_slopeMomentum, num4, num6 * dt); } else { float num7 = Mathf.Clamp01(slope / Mathf.Max(0.01f, m_maxUphillNormalized)); float num8 = num7 * num2; _slopeMomentum = Mathf.MoveTowards(_slopeMomentum, 0f - num4, num8 * dt); } } private float GetCurrentSignedSlope() { //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_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_0111: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_engineRoot == (Object)null) { return 0f; } string currentRailId = m_engineRoot.GetCurrentRailId(); if (string.IsNullOrEmpty(currentRailId)) { return 0f; } BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(currentRailId); if ((Object)(object)bCSRailPiece == (Object)null) { return 0f; } float distanceOnRail = m_engineRoot.GetDistanceOnRail(); float offset = Mathf.Max(0.01f, BCSCommonUtility.SanitizeFloat(m_slopeSampleDistance, 0.2f)); if (!bCSRailPiece.GetPose(distanceOnRail, out var pos, out var _)) { return 0f; } bool travelReversedOnRail = m_engineRoot.GetTravelReversedOnRail(); if (!BCSRailTraversalUtility.TryGetPoseAtOffset(currentRailId, distanceOnRail, travelReversedOnRail, offset, out var _, out var _, out var pos2, out var _)) { return 0f; } Vector3 val = pos2 - pos; if (((Vector3)(ref val)).sqrMagnitude <= 0.0001f) { return 0f; } ((Vector3)(ref val)).Normalize(); return BCSCommonUtility.SanitizeFloat(val.y, 0f); } private float GetSlopeSpeedMultiplier(float signedSlope) { signedSlope = BCSCommonUtility.SanitizeFloat(signedSlope, 0f); if (signedSlope > 0f) { float num = Mathf.Clamp01(signedSlope / Mathf.Max(0.01f, m_maxUphillNormalized)); num *= Mathf.Max(0f, m_uphillSlowdownFactor); num = Mathf.Clamp01(num); return Mathf.Lerp(1f, Mathf.Clamp(m_minSpeedMultiplierUphill, 0.05f, 1f), num); } if (signedSlope < 0f) { float num2 = Mathf.Clamp01((0f - signedSlope) / Mathf.Max(0.01f, m_maxDownhillNormalized)); num2 *= Mathf.Max(0f, m_downhillBoostFactor); num2 = Mathf.Clamp01(num2); return Mathf.Lerp(1f, Mathf.Max(1f, m_maxSpeedMultiplierDownhill), num2); } return 1f; } private float ApplySoftStopSpeedLimit(float targetSpeed) { if (!m_useSoftStopBraking || !_pendingSoftStop || (Object)(object)m_engineRoot == (Object)null) { return targetSpeed; } if (m_engineRoot.GetCurrentRailId() != _pendingStopRailId) { return targetSpeed; } float distanceOnRail = m_engineRoot.GetDistanceOnRail(); float num = (m_engineRoot.GetTravelReversedOnRail() ? Mathf.Max(0f, distanceOnRail - _pendingStopDistance) : Mathf.Max(0f, _pendingStopDistance - distanceOnRail)); float num2 = Mathf.Max(0.05f, BCSCommonUtility.SanitizeFloat(m_softStopBrakeStartDistance, 1.25f)); if (num >= num2) { return targetSpeed; } float num3 = Mathf.Clamp01(num / num2); num3 = Mathf.Pow(num3, Mathf.Max(0.01f, BCSCommonUtility.SanitizeFloat(m_softStopBrakeExponent, 1.5f))); float num4 = Mathf.Lerp(Mathf.Max(0.01f, BCSCommonUtility.SanitizeFloat(m_softStopMinApproachSpeed, 0.2f)), targetSpeed, num3); return Mathf.Min(targetSpeed, num4); } public bool TryAdvanceLeader(float dt) { //IL_018a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_engineRoot == (Object)null) { return false; } string currentRailId = m_engineRoot.GetCurrentRailId(); if (string.IsNullOrEmpty(currentRailId)) { Log("TryAdvanceLeader failed: previousRailId empty"); return false; } float distanceOnRail = m_engineRoot.GetDistanceOnRail(); bool travelReversedOnRail = m_engineRoot.GetTravelReversedOnRail(); float num = BCSCommonUtility.SanitizeFloat(m_currentSpeed, 0f) * dt; if (num <= 0f) { Log("TryAdvanceLeader failed: delta <= 0"); return false; } if (_pendingSoftStop && _pendingStopRailId == currentRailId) { float num2 = Mathf.Abs(_pendingStopDistance - distanceOnRail); if (num2 < num) { num = num2; } } string railId = currentRailId; float distance = distanceOnRail; bool reversed = travelReversedOnRail; if (!BCSRailTraversalUtility.TryMoveAlongRail(ref railId, ref distance, num, ref reversed)) { Log("TryAdvanceLeader failed: traversal blocked from " + BCSCommonUtility.SafeString(currentRailId) + " distance=" + distanceOnRail + " delta=" + num + " reversed=" + travelReversedOnRail); return false; } bool reversed2 = m_engineRoot.IsReversedOnRail(); if (railId != currentRailId) { reversed2 = DetermineBestReversedForPose(m_engineRoot, railId, distance, ((Component)m_engineRoot).transform.forward, m_engineRoot.IsReversedOnRail()); } m_engineRoot.SetRailPosition(railId, distance, reversed2); m_engineRoot.SetTravelReversedOnRail(reversed); if (!ApplyCartPoseFromCenter(m_engineRoot, railId, distance)) { Log("TryAdvanceLeader failed: ApplyCartPoseFromCenter failed"); return false; } if (m_enableMovementLogs) { Log("Leader moved rail=" + BCSCommonUtility.SafeString(railId) + " distance=" + distance.ToString("0.###") + " reversed=" + reversed2 + " speed=" + m_currentSpeed.ToString("0.###")); } if (railId != currentRailId) { BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(railId); if ((Object)(object)bCSRailPiece != (Object)null) { bCSRailPiece.RefreshNeighbors(); } Log("TryAdvanceLeader entered new rail old=" + BCSCommonUtility.SafeString(currentRailId) + " new=" + BCSCommonUtility.SafeString(railId)); } return true; } public void ApplyFollowerPositions() { //IL_0132: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_engineRoot == (Object)null) { return; } BuildOrderedTrainFromActiveEngine(_trainCache); if (_trainCache.Count <= 1) { return; } int num = _trainCache.IndexOf(m_engineRoot); if (num < 0) { Log("ApplyFollowerPositions skipped: engine not in cache"); return; } bool travelReversedOnRail = m_engineRoot.GetTravelReversedOnRail(); string currentRailId = m_engineRoot.GetCurrentRailId(); float distanceOnRail = m_engineRoot.GetDistanceOnRail(); float num2 = 0f; BCSCartRoot a = m_engineRoot; for (int i = num + 1; i < _trainCache.Count; i++) { BCSCartRoot bCSCartRoot = _trainCache[i]; if ((Object)(object)bCSCartRoot == (Object)null) { continue; } float actualPairFollowDistance = GetActualPairFollowDistance(a, bCSCartRoot); num2 += actualPairFollowDistance; if (!BCSRailTraversalUtility.TryGetPoseAtOffset(currentRailId, distanceOnRail, travelReversedOnRail, 0f - num2, out var outRailId, out var outDistance, out var _, out var _)) { Log("ApplyFollowerPositions back follower skipped: pose lookup failed for " + SafeCartId(bCSCartRoot)); a = bCSCartRoot; continue; } bool reversed = DetermineBestReversedForPose(bCSCartRoot, outRailId, outDistance, ((Component)bCSCartRoot).transform.forward, bCSCartRoot.IsReversedOnRail()); bCSCartRoot.SetRailPosition(outRailId, outDistance, reversed); ApplyCartPoseFromCenter(bCSCartRoot, outRailId, outDistance); if (m_enableFollowerLogs) { Log("Follower back placed cart=" + SafeCartId(bCSCartRoot) + " pairDistance=" + actualPairFollowDistance.ToString("0.###") + " totalOffset=" + num2.ToString("0.###") + " rail=" + BCSCommonUtility.SafeString(outRailId) + " centerDistance=" + outDistance.ToString("0.###") + " reversed=" + reversed); } a = bCSCartRoot; } float num3 = 0f; BCSCartRoot b = m_engineRoot; for (int num4 = num - 1; num4 >= 0; num4--) { BCSCartRoot bCSCartRoot2 = _trainCache[num4]; if (!((Object)(object)bCSCartRoot2 == (Object)null)) { float actualPairFollowDistance2 = GetActualPairFollowDistance(bCSCartRoot2, b); num3 += actualPairFollowDistance2; if (!BCSRailTraversalUtility.TryGetPoseAtOffset(currentRailId, distanceOnRail, travelReversedOnRail, num3, out var outRailId2, out var outDistance2, out var _, out var _)) { Log("ApplyFollowerPositions front follower skipped: pose lookup failed for " + SafeCartId(bCSCartRoot2)); b = bCSCartRoot2; } else { bool reversed2 = bCSCartRoot2.IsReversedOnRail(); bCSCartRoot2.SetRailPosition(outRailId2, outDistance2, reversed2); ApplyCartPoseFromCenter(bCSCartRoot2, outRailId2, outDistance2); if (m_enableFollowerLogs) { Log("Follower front placed cart=" + SafeCartId(bCSCartRoot2) + " pairDistance=" + actualPairFollowDistance2.ToString("0.###") + " totalOffset=" + num3.ToString("0.###") + " rail=" + BCSCommonUtility.SafeString(outRailId2) + " centerDistance=" + outDistance2.ToString("0.###") + " reversed=" + reversed2); } b = bCSCartRoot2; } } } } private void TryRequestSoftStopOnCurrentRail(string reason) { if ((Object)(object)m_engineRoot == (Object)null) { return; } string currentRailId = m_engineRoot.GetCurrentRailId(); if (string.IsNullOrEmpty(currentRailId)) { return; } BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(currentRailId); if ((Object)(object)bCSRailPiece == (Object)null) { return; } float length = bCSRailPiece.GetLength(); if (length <= 0.001f) { return; } float distanceOnRail = m_engineRoot.GetDistanceOnRail(); float num = length * 0.5f; if (!(m_engineRoot.GetTravelReversedOnRail() ? (num <= distanceOnRail) : (num >= distanceOnRail))) { if (m_enableStopLogs) { Log("Soft stop skipped on current rail because center is behind. reason=" + reason); } } else { RequestSoftStop(currentRailId, num, reason); } } private void TryRequestSoftStopForEnteredStopRail(string previousRailId, string currentRailId) { if ((Object)(object)m_engineRoot == (Object)null || string.IsNullOrEmpty(currentRailId) || currentRailId == previousRailId) { return; } BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(currentRailId); if ((Object)(object)bCSRailPiece == (Object)null) { return; } float length = bCSRailPiece.GetLength(); if (length <= 0.001f) { return; } bool travelReversedOnRail = m_engineRoot.GetTravelReversedOnRail(); BCSRailNodeSide entrySide = (travelReversedOnRail ? bCSRailPiece.GetFarTraversalSide() : bCSRailPiece.GetNearTraversalSide()); if (!bCSRailPiece.ShouldStopForEntrySide(entrySide)) { return; } float distanceOnRail = m_engineRoot.GetDistanceOnRail(); float num = length * 0.5f; if (travelReversedOnRail ? (num <= distanceOnRail) : (num >= distanceOnRail)) { if ((Object)(object)((Component)bCSRailPiece).GetComponent() != (Object)null) { StartSignalStop(currentRailId); RequestSoftStop(currentRailId, num, "entered signal stop rail"); } else { RequestSoftStop(currentRailId, num, "entered stop rail"); } } } private void RequestSoftStop(string railId, float stopDistance, string reason) { string text = railId ?? string.Empty; float num = BCSCommonUtility.SanitizeFloat(stopDistance, 0f); if (!_pendingSoftStop || !(_pendingStopRailId == text) || !(Mathf.Abs(_pendingStopDistance - num) <= 0.001f)) { _pendingSoftStop = true; _pendingStopRailId = text; _pendingStopDistance = num; _pendingStopReason = reason ?? string.Empty; SetHaltingForConnectedTrain(halting: true); if (m_enableStopLogs) { Log("Soft stop requested rail=" + BCSCommonUtility.SafeString(_pendingStopRailId) + " distance=" + _pendingStopDistance.ToString("0.###") + " reason=" + BCSCommonUtility.SafeString(_pendingStopReason)); } } } private bool HasReachedPendingStop(string previousRailId, float previousCenterDistance, string currentRailId, float currentCenterDistance) { if (!_pendingSoftStop) { return false; } if (string.IsNullOrEmpty(_pendingStopRailId)) { return false; } if (currentRailId != _pendingStopRailId) { return false; } float num = Mathf.Max(0.01f, BCSCommonUtility.SanitizeFloat(m_stopRailCenterTolerance, 0.08f)); bool flag = (Object)(object)m_engineRoot != (Object)null && m_engineRoot.GetTravelReversedOnRail(); if (Mathf.Abs(currentCenterDistance - _pendingStopDistance) <= num) { return true; } if (previousRailId != currentRailId) { return flag ? (currentCenterDistance <= _pendingStopDistance + num) : (currentCenterDistance >= _pendingStopDistance - num); } if (!flag) { return previousCenterDistance <= _pendingStopDistance && currentCenterDistance >= _pendingStopDistance - num; } return previousCenterDistance >= _pendingStopDistance && currentCenterDistance <= _pendingStopDistance + num; } private void FinalizeSoftStop() { BCSRailPiece bCSRailPiece = null; int num = 0; bool drawbridgeStopActive = _drawbridgeStopActive; bool signalStopActive = _signalStopActive; if ((Object)(object)m_engineRoot != (Object)null && _pendingSoftStop && !string.IsNullOrEmpty(_pendingStopRailId)) { bool reversed = m_engineRoot.IsReversedOnRail(); m_engineRoot.SetRailPosition(_pendingStopRailId, _pendingStopDistance, reversed); ApplyCartPoseFromCenter(m_engineRoot, _pendingStopRailId, _pendingStopDistance); ApplyFollowerPositions(); bCSRailPiece = BCSRailRegistry.FindById(_pendingStopRailId); if ((Object)(object)bCSRailPiece != (Object)null && !drawbridgeStopActive && !signalStopActive) { num = bCSRailPiece.GetStopTimerSeconds(); } } if (m_enableStopLogs) { Log("Soft stop finalized. reason=" + BCSCommonUtility.SafeString(_pendingStopReason) + " timerSeconds=" + num + " drawbridgeStop=" + drawbridgeStopActive + " signalStop=" + signalStopActive); } StopWholeTrain(alignToRail: false); ClearPendingSoftStop(); if (drawbridgeStopActive || signalStopActive) { ClearTimedStop(clearRailCountdown: true); return; } if ((Object)(object)bCSRailPiece != (Object)null) { BCSRailUnloader component = ((Component)bCSRailPiece).GetComponent(); if ((Object)(object)component != (Object)null && component.IsUnloadEnabled()) { num = component.NormalizeStopTimerSeconds(num); BuildOrderedTrainFromActiveEngine(_trainCache); component.BeginUnload(_trainCache, num); } BCSRailContainerTransfer component2 = ((Component)bCSRailPiece).GetComponent(); if ((Object)(object)component2 != (Object)null && component2.IsTransferEnabled()) { num = component2.NormalizeStopTimerSeconds(num); BuildOrderedTrainFromActiveEngine(_trainCache); component2.BeginTransfer(_trainCache, num); } } if ((Object)(object)bCSRailPiece != (Object)null && num > 0) { StartTimedStop(bCSRailPiece, num); } else { ClearTimedStop(clearRailCountdown: true); } } private void ClearPendingSoftStop() { _pendingSoftStop = false; _pendingStopRailId = string.Empty; _pendingStopDistance = 0f; _pendingStopReason = string.Empty; SetHaltingForConnectedTrain(halting: false); } private void SetHaltingForConnectedTrain(bool halting) { List list = BuildConnectedTrainGraph(m_engineRoot); if (list.Count == 0) { if ((Object)(object)m_engineRoot != (Object)null) { m_engineRoot.SetHaltingStateLocal(halting); Log("SetHaltingForConnectedTrain fallback engineOnly halting=" + halting); } return; } for (int i = 0; i < list.Count; i++) { BCSCartRoot bCSCartRoot = list[i]; if ((Object)(object)bCSCartRoot != (Object)null) { bCSCartRoot.SetHaltingStateLocal(halting); if (m_enableStopLogs) { Log("SetHaltingForConnectedTrain cart=" + SafeCartId(bCSCartRoot) + " halting=" + halting); } } } } private bool IsLeaderOnJumpRail() { if ((Object)(object)m_engineRoot == (Object)null) { return false; } string currentRailId = m_engineRoot.GetCurrentRailId(); if (string.IsNullOrEmpty(currentRailId)) { return false; } BCSRailPiece bCSRailPiece = BCSRailRegistry.FindById(currentRailId); return (Object)(object)bCSRailPiece != (Object)null && bCSRailPiece.IsJumpRail(); } public bool HasObstacleAhead() { //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) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_009e: 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_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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_00b7: 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_00c0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_engineRoot == (Object)null) { return false; } BuildOrderedTrainFromActiveEngine(_trainCache); if (!TryGetActiveObstacleCheckTransform(out var checkTransform, out var forward)) { return false; } Vector3 val = checkTransform.position + forward * Mathf.Max(0f, m_obstacleCheckForwardOffset); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(Mathf.Abs(m_obstacleCheckHalfExtents.x), Mathf.Abs(m_obstacleCheckHalfExtents.y), Mathf.Abs(m_obstacleCheckHalfExtents.z)); Quaternion val3 = Quaternion.LookRotation(forward, ((Component)m_engineRoot).transform.up); int num = Physics.OverlapBoxNonAlloc(val, val2, ObstacleHits, val3, LayerMask.op_Implicit(GetFinalObstacleMask()), (QueryTriggerInteraction)1); for (int i = 0; i < num; i++) { Collider val4 = ObstacleHits[i]; ObstacleHits[i] = null; if (!((Object)(object)val4 == (Object)null) && ShouldStopForObstacleHit(val4)) { return true; } } return false; } private bool ShouldStopForObstacleHit(Collider hit) { if ((Object)(object)hit == (Object)null || hit.isTrigger) { return false; } BCSCartRoot componentInParent = ((Component)hit).GetComponentInParent(); if ((Object)(object)componentInParent != (Object)null) { return false; } if ((Object)(object)((Component)hit).GetComponentInParent() != (Object)null) { return false; } if ((Object)(object)((Component)hit).GetComponentInParent() != (Object)null) { return false; } if ((Object)(object)((Component)hit).GetComponentInParent() != (Object)null) { return false; } return BCSCommonUtility.HasObstacleStopComponent(hit); } public bool HasForeignCartAhead() { //IL_005b: 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_0071: Unknown result type (might be due to invalid IL or missing references) //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) //IL_00b3: 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_00c4: 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_00cb: 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_00d2: 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) if ((Object)(object)m_engineRoot == (Object)null) { return false; } if (IsLeaderOnJumpRail()) { return false; } BuildOrderedTrainFromActiveEngine(_trainCache); if (!TryGetActiveObstacleCheckTransform(out var checkTransform, out var forward)) { return false; } Vector3 val = checkTransform.position + forward * Mathf.Max(0f, m_obstacleCheckForwardOffset); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(Mathf.Abs(m_obstacleCheckHalfExtents.x), Mathf.Abs(m_obstacleCheckHalfExtents.y), Mathf.Abs(m_obstacleCheckHalfExtents.z)); Quaternion val3 = Quaternion.LookRotation(forward, ((Component)m_engineRoot).transform.up); int num = Physics.OverlapBoxNonAlloc(val, val2, ObstacleHits, val3, LayerMask.op_Implicit(GetFinalObstacleMask()), (QueryTriggerInteraction)1); for (int i = 0; i < num; i++) { Collider val4 = ObstacleHits[i]; ObstacleHits[i] = null; if (!((Object)(object)val4 == (Object)null) && !val4.isTrigger) { BCSCartRoot componentInParent = ((Component)val4).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null) && !_trainCache.Contains(componentInParent)) { Log("HasForeignCartAhead detected foreign cart=" + SafeCartId(componentInParent) + " collider=" + ((Object)val4).name); return true; } } } return false; } private bool TryGetActiveObstacleCheckTransform(out Transform checkTransform, out Vector3 forward) { //IL_0005: 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) //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) //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_010d: 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) checkTransform = null; forward = Vector3.zero; if ((Object)(object)m_engineRoot == (Object)null) { return false; } bool flag = m_engineRoot.ShouldMoveTowardFront(); if (flag) { checkTransform = GetFrontCheckTransform(m_engineRoot); forward = ((Component)m_engineRoot).transform.forward; } else { checkTransform = GetBackCheckTransform(m_engineRoot); forward = -((Component)m_engineRoot).transform.forward; } if ((Object)(object)checkTransform == (Object)null) { checkTransform = ((Component)m_engineRoot).transform; } if (((Vector3)(ref forward)).sqrMagnitude <= 0.0001f) { return false; } ((Vector3)(ref forward)).Normalize(); if (m_enableVerboseObstacleLogs) { string[] obj = new string[6] { "TryGetActiveObstacleCheckTransform towardFront=", flag.ToString(), " checkTransform=", BCSCommonUtility.SafeTransformName(checkTransform), " forward=", null }; Vector3 val = forward; obj[5] = ((object)(Vector3)(ref val)).ToString(); Log(string.Concat(obj)); } return true; } private Transform GetFrontCheckTransform(BCSCartRoot cart) { if ((Object)(object)cart == (Object)null) { return null; } if ((Object)(object)cart.m_frontCouplerPoint != (Object)null) { return cart.m_frontCouplerPoint; } if ((Object)(object)cart.m_frontCouplerSwitch != (Object)null) { return ((Component)cart.m_frontCouplerSwitch).transform; } return null; } private Transform GetBackCheckTransform(BCSCartRoot cart) { if ((Object)(object)cart == (Object)null) { return null; } if ((Object)(object)cart.m_backCouplerPoint != (Object)null) { return cart.m_backCouplerPoint; } if ((Object)(object)cart.m_backCouplerSwitch != (Object)null) { return ((Component)cart.m_backCouplerSwitch).transform; } return null; } private void StopWholeTrain(bool alignToRail) { ResetStraightRunAcceleration(); BuildOrderedTrainFromActiveEngine(_trainCache); if (_trainCache.Count == 0 && (Object)(object)m_engineRoot != (Object)null) { m_engineRoot.StopTrain(); m_engineRoot.SetHaltingStateLocal(halting: false); if (alignToRail) { m_engineRoot.AlignToCurrentRail(); } _lastLeaderRailId = m_engineRoot.GetCurrentRailId(); return; } for (int i = 0; i < _trainCache.Count; i++) { BCSCartRoot bCSCartRoot = _trainCache[i]; if (!((Object)(object)bCSCartRoot == (Object)null)) { bCSCartRoot.StopTrain(); bCSCartRoot.SetHaltingStateLocal(halting: false); if (alignToRail) { bCSCartRoot.AlignToCurrentRail(); } } } if ((Object)(object)m_engineRoot != (Object)null) { _lastLeaderRailId = m_engineRoot.GetCurrentRailId(); } } private void BuildOrderedTrainFromActiveEngine(List result) { result.Clear(); if ((Object)(object)m_engineRoot == (Object)null) { return; } List list = BuildConnectedTrainGraph(m_engineRoot); if (list.Count == 0) { return; } BCSCartRoot bCSCartRoot = FindBestTrainStart(list, m_engineRoot); if ((Object)(object)bCSCartRoot == (Object)null) { bCSCartRoot = m_engineRoot; } HashSet hashSet = new HashSet(); BCSCartRoot previous = null; BCSCartRoot bCSCartRoot2 = bCSCartRoot; while ((Object)(object)bCSCartRoot2 != (Object)null) { string cartId = bCSCartRoot2.GetCartId(); if (string.IsNullOrEmpty(cartId) || hashSet.Contains(cartId)) { break; } hashSet.Add(cartId); result.Add(bCSCartRoot2); BCSCartRoot nextLinearNeighbor = GetNextLinearNeighbor(bCSCartRoot2, previous); previous = bCSCartRoot2; bCSCartRoot2 = nextLinearNeighbor; } if (result.Count != list.Count) { Log("BuildOrderedTrainFromActiveEngine warning ordered=" + result.Count + " all=" + list.Count + " start=" + SafeCartId(bCSCartRoot)); } if (!result.Contains(m_engineRoot)) { Log("BuildOrderedTrainFromActiveEngine fallback: engine root missing, rebuilding from root"); result.Clear(); RebuildOrderedTrainFromRoot(result, m_engineRoot); } } private void RebuildOrderedTrainFromRoot(List result, BCSCartRoot root) { if (result == null) { return; } result.Clear(); _linearVisitedScratch.Clear(); if ((Object)(object)root == (Object)null) { return; } BCSCartRoot previous = null; BCSCartRoot bCSCartRoot = root; while ((Object)(object)bCSCartRoot != (Object)null) { string cartId = bCSCartRoot.GetCartId(); if (string.IsNullOrEmpty(cartId) || !_linearVisitedScratch.Add(cartId)) { break; } result.Add(bCSCartRoot); BCSCartRoot nextLinearNeighbor = GetNextLinearNeighbor(bCSCartRoot, previous); previous = bCSCartRoot; bCSCartRoot = nextLinearNeighbor; } } private List BuildConnectedTrainGraph(BCSCartRoot root) { _graphResultScratch.Clear(); _graphQueueScratch.Clear(); _graphVisitedScratch.Clear(); if ((Object)(object)root == (Object)null) { return _graphResultScratch; } _graphQueueScratch.Enqueue(root); while (_graphQueueScratch.Count > 0) { BCSCartRoot bCSCartRoot = _graphQueueScratch.Dequeue(); if ((Object)(object)bCSCartRoot == (Object)null) { continue; } string cartId = bCSCartRoot.GetCartId(); if (string.IsNullOrEmpty(cartId) || !_graphVisitedScratch.Add(cartId)) { continue; } _graphResultScratch.Add(bCSCartRoot); string frontCartId = bCSCartRoot.GetFrontCartId(); if (!string.IsNullOrEmpty(frontCartId)) { BCSCartRoot bCSCartRoot2 = BCSCartRegistry.FindById(frontCartId); if ((Object)(object)bCSCartRoot2 != (Object)null) { _graphQueueScratch.Enqueue(bCSCartRoot2); } } string backCartId = bCSCartRoot.GetBackCartId(); if (!string.IsNullOrEmpty(backCartId)) { BCSCartRoot bCSCartRoot3 = BCSCartRegistry.FindById(backCartId); if ((Object)(object)bCSCartRoot3 != (Object)null) { _graphQueueScratch.Enqueue(bCSCartRoot3); } } } return _graphResultScratch; } private BCSCartRoot FindBestTrainStart(List carts, BCSCartRoot preferredEngine) { if (carts == null || carts.Count == 0) { return null; } _endpointScratch.Clear(); for (int i = 0; i < carts.Count; i++) { BCSCartRoot bCSCartRoot = carts[i]; if (!((Object)(object)bCSCartRoot == (Object)null)) { int connectionDegree = GetConnectionDegree(bCSCartRoot); if (connectionDegree <= 1) { _endpointScratch.Add(bCSCartRoot); } } } if (_endpointScratch.Count == 0) { return preferredEngine; } if ((Object)(object)preferredEngine != (Object)null && _endpointScratch.Contains(preferredEngine)) { return preferredEngine; } if ((Object)(object)preferredEngine != (Object)null) { for (int j = 0; j < _endpointScratch.Count; j++) { BCSCartRoot bCSCartRoot2 = _endpointScratch[j]; if (!((Object)(object)bCSCartRoot2 == (Object)null) && PathContainsAllFromStart(bCSCartRoot2, carts.Count, preferredEngine)) { return bCSCartRoot2; } } } return _endpointScratch[0]; } private bool PathContainsAllFromStart(BCSCartRoot start, int expectedCount, BCSCartRoot mustContain) { if ((Object)(object)start == (Object)null) { return false; } _pathVisitedScratch.Clear(); BCSCartRoot previous = null; BCSCartRoot bCSCartRoot = start; bool flag = false; int num = 0; while ((Object)(object)bCSCartRoot != (Object)null) { string cartId = bCSCartRoot.GetCartId(); if (string.IsNullOrEmpty(cartId) || !_pathVisitedScratch.Add(cartId)) { break; } num++; if ((Object)(object)bCSCartRoot == (Object)(object)mustContain) { flag = true; } BCSCartRoot nextLinearNeighbor = GetNextLinearNeighbor(bCSCartRoot, previous); previous = bCSCartRoot; bCSCartRoot = nextLinearNeighbor; } return num == expectedCount && flag; } private BCSCartRoot GetNextLinearNeighbor(BCSCartRoot current, BCSCartRoot previous) { if ((Object)(object)current == (Object)null) { return null; } BCSCartRoot bCSCartRoot = BCSCartRegistry.FindById(current.GetFrontCartId()); if ((Object)(object)bCSCartRoot != (Object)null && (Object)(object)bCSCartRoot != (Object)(object)previous) { return bCSCartRoot; } BCSCartRoot bCSCartRoot2 = BCSCartRegistry.FindById(current.GetBackCartId()); if ((Object)(object)bCSCartRoot2 != (Object)null && (Object)(object)bCSCartRoot2 != (Object)(object)previous) { return bCSCartRoot2; } return null; } private int GetConnectionDegree(BCSCartRoot cart) { if ((Object)(object)cart == (Object)null) { return 0; } int num = 0; string frontCartId = cart.GetFrontCartId(); string backCartId = cart.GetBackCartId(); if (!string.IsNullOrEmpty(frontCartId)) { num++; } if (!string.IsNullOrEmpty(backCartId)) { num++; } return num; } private bool ApplyCartPoseFromCenter(BCSCartRoot cart, string centerRailId, float centerDistance) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_008a: 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_00ae: 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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_00c4: 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_00d3: 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_00f2: 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_0109: 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_0115: 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_012d: 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) if ((Object)(object)cart == (Object)null || string.IsNullOrEmpty(centerRailId)) { return false; } float localZOffset = GetLocalZOffset(cart, front: true); float localZOffset2 = GetLocalZOffset(cart, front: false); bool reversed = cart.IsReversedOnRail(); if (!BCSRailTraversalUtility.TryGetPoseAtOffset(centerRailId, centerDistance, reversed, localZOffset, out var _, out var _, out var pos, out var rot)) { return false; } if (!BCSRailTraversalUtility.TryGetPoseAtOffset(centerRailId, centerDistance, reversed, localZOffset2, out var _, out var _, out var pos2, out var rot2)) { return false; } Vector3 val = pos - pos2; if (((Vector3)(ref val)).sqrMagnitude <= 0.0001f) { return false; } Vector3 val2 = (rot * Vector3.up + rot2 * Vector3.up) * 0.5f; if (((Vector3)(ref val2)).sqrMagnitude <= 0.0001f) { val2 = Vector3.up; } else { ((Vector3)(ref val2)).Normalize(); } ((Component)cart).transform.position = (pos + pos2) * 0.5f; ((Component)cart).transform.rotation = Quaternion.LookRotation(((Vector3)(ref val)).normalized, val2); return true; } private bool DetermineBestReversedForPose(BCSCartRoot cart, string railId, float centerDistance, Vector3 desiredForward, bool fallbackReversed) { //IL_007f: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)cart == (Object)null || string.IsNullOrEmpty(railId)) { return fallbackReversed; } if (((Vector3)(ref desiredForward)).sqrMagnitude <= 0.0001f) { return fallbackReversed; } ((Vector3)(ref desiredForward)).Normalize(); Vector3 forward; bool flag = TryGetCartForwardForPose(cart, railId, centerDistance, visualReversedOnRail: false, out forward); Vector3 forward2; bool flag2 = TryGetCartForwardForPose(cart, railId, centerDistance, visualReversedOnRail: true, out forward2); if (!flag || !flag2) { return fallbackReversed; } float num = Vector3.Dot(((Vector3)(ref forward)).normalized, desiredForward); float num2 = Vector3.Dot(((Vector3)(ref forward2)).normalized, desiredForward); if (num2 > num + 0.001f) { return true; } if (num > num2 + 0.001f) { return false; } return fallbackReversed; } private bool TryGetCartForwardForPose(BCSCartRoot cart, string centerRailId, float centerDistance, bool visualReversedOnRail, out Vector3 forward) { //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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_008a: Unknown result type (might be due to invalid IL or missing references) forward = Vector3.zero; if ((Object)(object)cart == (Object)null || string.IsNullOrEmpty(centerRailId)) { return false; } float localZOffset = GetLocalZOffset(cart, front: true); float localZOffset2 = GetLocalZOffset(cart, front: false); if (!BCSRailTraversalUtility.TryGetPoseAtOffset(centerRailId, centerDistance, visualReversedOnRail, localZOffset, out var _, out var _, out var pos, out var _)) { return false; } if (!BCSRailTraversalUtility.TryGetPoseAtOffset(centerRailId, centerDistance, visualReversedOnRail, localZOffset2, out var _, out var _, out var pos2, out var _)) { return false; } forward = pos - pos2; return ((Vector3)(ref forward)).sqrMagnitude > 0.0001f; } private float GetLocalZOffset(BCSCartRoot cart, bool front) { //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_007f: 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)cart == (Object)null) { return front ? 0.5f : (-0.5f); } Transform val = (front ? cart.m_frontPosePoint : cart.m_backPosePoint); if ((Object)(object)val == (Object)null) { float num = Mathf.Max(0.05f, BCSCommonUtility.SanitizeFloat(cart.m_cartLength, 1f) * 0.5f); return front ? num : (0f - num); } Vector3 val2 = ((Component)cart).transform.InverseTransformPoint(val.position); return BCSCommonUtility.SanitizeFloat(val2.z, front ? 0.5f : (-0.5f)); } private void Log(string msg) { if (m_enableDebugLogs) { Debug.Log((object)("[BCSTrainRuntime][" + ((Object)((Component)this).gameObject).name + "] " + msg)); } } private string SafeCartId(BCSCartRoot cart) { if ((Object)(object)cart == (Object)null) { return ""; } string cartId = cart.GetCartId(); return string.IsNullOrEmpty(cartId) ? "" : cartId; } private bool TryGetStraightRunMovedDistance(BCSRailPiece previousRail, float previousDistance, bool previousTravelReversed, BCSRailPiece currentRail, float currentDistance, bool currentTravelReversed, out float movedDistance) { movedDistance = 0f; if ((Object)(object)previousRail == (Object)null || (Object)(object)currentRail == (Object)null) { return false; } string railId = previousRail.GetRailId(); string railId2 = currentRail.GetRailId(); if (string.IsNullOrEmpty(railId) || string.IsNullOrEmpty(railId2)) { return false; } previousDistance = BCSCommonUtility.SanitizeFloat(previousDistance, 0f); currentDistance = BCSCommonUtility.SanitizeFloat(currentDistance, 0f); if (railId == railId2) { movedDistance = Mathf.Abs(currentDistance - previousDistance); return movedDistance > 0.0001f; } float length = previousRail.GetLength(); float length2 = currentRail.GetLength(); if (length <= 0.001f || length2 <= 0.001f) { return false; } float num = (previousTravelReversed ? Mathf.Clamp(previousDistance, 0f, length) : Mathf.Clamp(length - previousDistance, 0f, length)); float num2 = (currentTravelReversed ? Mathf.Clamp(length2 - currentDistance, 0f, length2) : Mathf.Clamp(currentDistance, 0f, length2)); movedDistance = num + num2; movedDistance = BCSCommonUtility.SanitizeFloat(movedDistance, 0f); return movedDistance > 0.0001f; } private float GetActualPairFollowDistance(BCSCartRoot a, BCSCartRoot b) { if ((Object)(object)a == (Object)null || (Object)(object)b == (Object)null) { return 0.1f; } if (!a.TryGetCouplerSideConnectedTo(b.GetCartId(), out var side)) { return a.GetPreferredFollowDistanceTo(b); } if (!b.TryGetCouplerSideConnectedTo(a.GetCartId(), out var side2)) { return a.GetPreferredFollowDistanceTo(b); } return a.GetPreferredFollowDistanceTo(b, side, side2); } } public static class BCSZdoKeys { public const string RailId = "hl_rail_id"; public const string RailType = "hl_rail_type"; public const string RailIsPlatform = "hl_is_platform"; public const string NeighborA = "hl_neighbor_a"; public const string NeighborB = "hl_neighbor_b"; public const string NeighborC = "hl_neighbor_c"; public const string NeighborD = "hl_neighbor_d"; public const string RailForcedStop = "hl_rail_forced_stop"; public const string RailSwitchDirection = "hl_rail_switch_direction"; public const string RailStopMode = "hl_rail_stop_mode"; public const string StopTimerSeconds = "hl_stop_timer_seconds"; public const string StopTimerEndTime = "hl_stop_timer_end_time"; public const string Halting = "hl_halting"; public const string CartId = "hl_cart_id"; public const string CartType = "hl_cart_type"; public const string FrontCartId = "hl_front_cart_id"; public const string BackCartId = "hl_back_cart_id"; public const string CurrentRailId = "hl_current_rail_id"; public const string DistanceOnRail = "hl_distance_on_rail"; public const string ReversedOnRail = "hl_reversed_on_rail"; public const string TravelReversedOnRail = "hl_travel_reversed_on_rail"; public const string Running = "hl_running"; public const string ActiveEngineId = "hl_active_engine_id"; public const string FuelAmount = "hl_fuel_amount"; public const string LastDriverId = "hl_last_driver_id"; public const string RailUnloadEnabled = "hl_rail_unload_enabled"; public const string RailUnloadFilter = "hl_rail_unload_filter"; public const string RailUnloadShowFilterIcon = "hl_rail_unload_show_filter_icon"; public const string SignalSwitchDefaultDirection = "hl_signal_switch_default_direction"; public const string SignalSwitchEventDirection = "hl_signal_switch_event_direction"; public const string SignalEmitterActive = "hl_signal_emitter_active"; public const string SignalName = "hl_signal_name"; public const string SignalEmitterMode = "hl_signal_emitter_mode"; public const string SignalEmitterRange = "hl_signal_emitter_range"; public const string SignalDefaultState = "hl_signal_default_state"; public const string SignalEventState = "hl_signal_event_state"; public const string SignalEventDuration = "hl_signal_event_duration"; public const string SignalDoorEventState = "hl_signal_door_event_state"; public const string SignalReceiverActive = "hl_signal_receiver_active"; public const string RailContainerTransferMode = "hl_rail_container_transfer_mode"; public const string RailContainerTransferEnabled = "hl_rail_container_transfer_enabled"; public const string RailContainerTransferFilter = "hl_rail_container_transfer_filter"; public const string RailDrawbridgeState = "hl_rail_drawbridge_state"; public const string RailDrawbridgeAnimStartTime = "hl_rail_drawbridge_anim_start_time"; public const string PresenceSignalActive = "hl_presence_signal_active"; public const string PresenceSignalName = "hl_presence_signal_name"; public const string PresenceSignalTarget = "hl_presence_signal_target"; public const string PresenceSignalShape = "hl_presence_signal_shape"; public const string PresenceSignalEvent = "hl_presence_signal_event"; public const string PresenceSignalRange = "hl_presence_signal_range"; } public enum BCSRailStopMode { None, Both, SideA, SideB } public enum BCSDriverCameraMode { Off, FirstPerson, ShoulderRight, ShoulderLeft, CloseFollow } public enum BCSRailPieceType { Platform, Straight, Slope26, Slope45, Turn45, Turn90, Crossroad, Control, Turn15, Turn30, Jump, Slope64, Speed, Drawbridge } public enum BCSJumpRailArcMode { Auto, Flat, JumpUp, JumpDown, Drop } public enum BCSRailNodeSide { A, B, C, D } public enum BCSRailSwitchDirection { Left, Right } public enum BCSCartCouplerSide { Front, Back } public enum BCSCartType { Powered, Cargo, Utility, Passenger } public enum BCSRailUnloadSide { Left, Right } public enum BCSSignalEmitterMode { TrainOnSensor, TrainEntered, TrainExited, TrainStopped, TrainMoving } public enum BCSSignalDoorState { Closed, Open } public enum BCSRailContainerTransferMode { None, Unload, Load } public enum BCSRailUnloadFilter { None, All, Materials, Consumables, Weapons, Armor, Misc, Equipables, NonEquipable } public enum BCSDrawbridgeState { Lowered, Raising, Raised, Lowering } public enum BCSPresenceSignalTarget { Players, Monsters, Tamed, Everything } public enum BCSPresenceSignalShape { Zone, Directional } public enum BCSPresenceSignalEvent { Present, Entered, Exited, Stopped, Moving } public enum BCSPresenceSignalTriggerType { Zone, Directional } public class RecipeFactory { private List pieces; private List items; private List newItems; public List recipes = new List(); private readonly Dictionary _itemCache = new Dictionary(); private readonly string[] toRecipe = new string[8] { "WagonBundlePower_bal", "WagonBundleCargo_bal", "WagonBundleTable_bal", "RailPartsBundle_bal", "RailwayHammer_bal", "WagonPartsBundle_bal", "BuilderWorkstationBundle_bal", "UncharedThunderstone_bal" }; public List createRecipes(List items, List newItems, GameObject railwayTable) { this.items = items; this.newItems = newItems; pieces = ObjectDB.instance.GetItemPrefab("Hammer").GetComponent().m_itemData.m_shared.m_buildPieces.m_pieces; TableMapper.setupTables(null, pieces); CraftingStation forge = TableMapper.forge; foreach (GameObject newItem in newItems) { if (toRecipe.Contains(((Object)newItem).name)) { Recipe recipe = CreateBaseRecipe(newItem, forge, 3); recipe = createResources(newItem, recipe); recipes.Add(recipe); CreateRailwayTableRecipeIfNeeded(railwayTable, newItem); } } return recipes; } private Recipe CreateBaseRecipe(GameObject item, CraftingStation station, int stationLevel) { Recipe val = ScriptableObject.CreateInstance(); val.m_craftingStation = station; val.m_repairStation = station; val.m_minStationLevel = stationLevel; val.m_item = item.GetComponent(); val.m_amount = 1; val.m_enabled = true; ((Object)val).name = "Recipe_" + ((Object)item).name; return val; } private void CreateRailwayTableRecipeIfNeeded(GameObject railwayTable, GameObject itemToMake) { switch (((Object)itemToMake).name) { case "RailwayHammer_bal": createRailwayHammerRecipe(railwayTable, itemToMake); break; case "RailPartsBundle_bal": createRailwayPartsRecipe(railwayTable, itemToMake); break; case "WagonPartsBundle_bal": createRailwayWagonPartsRecipe(railwayTable, itemToMake); break; case "WagonBundleCargo_bal": createRailwyyWagonPCargoRecipe(railwayTable, itemToMake); break; case "WagonBundleTable_bal": createRailwyyWagonTableRecipe(railwayTable, itemToMake); break; case "WagonBundlePower_bal": createRailwyyWagonPowerRecipe(railwayTable, itemToMake); break; } } private CraftingStation GetRailwayTableStation(GameObject railwayTable) { return ((Component)railwayTable.transform.Find("table")).GetComponent(); } private Recipe CreateRailwayTableRecipe(GameObject railwayTable, GameObject itemToMake, string recipeName, params Tuple[] ingredients) { Recipe val = ScriptableObject.CreateInstance(); CraftingStation railwayTableStation = GetRailwayTableStation(railwayTable); ((Object)val).name = recipeName; val.m_craftingStation = railwayTableStation; val.m_repairStation = railwayTableStation; val.m_enabled = true; val.m_amount = 1; val.m_minStationLevel = 1; val.m_item = itemToMake.GetComponent(); val.m_resources = CreateRequirements(ingredients).ToArray(); recipes.Add(val); return val; } private Recipe createRailwayHammerRecipe(GameObject railwayTable, GameObject itemToMake) { return CreateRailwayTableRecipe(railwayTable, itemToMake, "Recipe_WagonRailwayHammer_bal", Tuple.Create("Iron", 3, 1), Tuple.Create("FineWood", 4, 2), Tuple.Create("BronzeNails", 10, 5)); } private Recipe createRailwayPartsRecipe(GameObject railwayTable, GameObject itemToMake) { return CreateRailwayTableRecipe(railwayTable, itemToMake, "Recipe_WagonRailwayParts_bal", Tuple.Create("IronNails", 4, 0), Tuple.Create("FineWood", 2, 0), Tuple.Create("BronzeNails", 4, 0), Tuple.Create("GreydwarfEye", 2, 0)); } private Recipe createRailwayWagonPartsRecipe(GameObject railwayTable, GameObject itemToMake) { return CreateRailwayTableRecipe(railwayTable, itemToMake, "Recipe_WagonCartParts_bal", Tuple.Create("Iron", 2, 0), Tuple.Create("FineWood", 12, 0), Tuple.Create("BronzeNails", 22, 0), Tuple.Create("Tin", 2, 0)); } private Recipe createRailwyyWagonPCargoRecipe(GameObject railwayTable, GameObject itemToMake) { return CreateRailwayTableRecipe(railwayTable, itemToMake, "Recipe_WagonWagonBundleCargo_bal", Tuple.Create("WagonPartsBundle_bal", 1, 0), Tuple.Create("Wood", 10, 0)); } private Recipe createRailwyyWagonTableRecipe(GameObject railwayTable, GameObject itemToMake) { return CreateRailwayTableRecipe(railwayTable, itemToMake, "Recipe_WagonWagonBundleTable_bal", Tuple.Create("WagonPartsBundle_bal", 1, 0), Tuple.Create("BuilderWorkstationBundle_bal", 1, 0), Tuple.Create("Crystal", 4, 0)); } private Recipe createRailwyyWagonPowerRecipe(GameObject railwayTable, GameObject itemToMake) { return CreateRailwayTableRecipe(railwayTable, itemToMake, "Recipe_WagonWagonBundlePower_bal", Tuple.Create("WagonPartsBundle_bal", 1, 0), Tuple.Create("SurtlingCore", 2, 0), Tuple.Create("Thunderstone", 1, 0)); } private Recipe createResources(GameObject item, Recipe recipe) { ((Object)recipe).name = "Recipe_" + ((Object)item).name; recipe.m_item = item.GetComponent(); if (((Object)item).name == "UncharedThunderstone_bal") { recipe.m_amount = 6; } recipe.m_enabled = true; List recipeRequirements = GetRecipeRequirements(((Object)item).name); recipe.m_craftingStation = TableMapper.artisian; recipe.m_repairStation = recipe.m_craftingStation; recipe.m_minStationLevel = 1; recipe.m_resources = recipeRequirements.ToArray(); return recipe; } private List GetRecipeRequirements(string itemName) { return itemName switch { "UncharedThunderstone_bal" => CreateRequirements(Tuple.Create("Flint", 6, 0), Tuple.Create("HardAntler", 1, 0), Tuple.Create("Crystal", 3, 0)), "RailPartsBundle_bal" => CreateRequirements(Tuple.Create("IronNails", 4, 0), Tuple.Create("FineWood", 2, 0), Tuple.Create("BronzeNails", 4, 0), Tuple.Create("GreydwarfEye", 2, 0)), "RailwayHammer_bal" => CreateRequirements(Tuple.Create("Iron", 3, 1), Tuple.Create("FineWood", 4, 2), Tuple.Create("BronzeNails", 10, 5)), "WagonPartsBundle_bal" => CreateRequirements(Tuple.Create("Iron", 2, 0), Tuple.Create("FineWood", 10, 0), Tuple.Create("BronzeNails", 16, 0), Tuple.Create("Tin", 2, 0)), "BuilderWorkstationBundle_bal" => CreateRequirements(Tuple.Create("Bronze", 6, 0), Tuple.Create("FineWood", 20, 0), Tuple.Create("Flint", 10, 0), Tuple.Create("Iron", 6, 0)), "WagonBundleTable_bal" => CreateRequirements(Tuple.Create("WagonPartsBundle_bal", 1, 0), Tuple.Create("BuilderWorkstationBundle_bal", 1, 0), Tuple.Create("Crystal", 4, 0)), "WagonBundlePower_bal" => CreateRequirements(Tuple.Create("WagonPartsBundle_bal", 1, 0), Tuple.Create("SurtlingCore", 2, 0), Tuple.Create("Thunderstone", 1, 0)), "WagonBundleCargo_bal" => CreateRequirements(Tuple.Create("WagonPartsBundle_bal", 1, 0), Tuple.Create("FineWood", 10, 0)), "WagonBundlePersonel_bal" => CreateRequirements(Tuple.Create("WagonPartsBundle_bal", 1, 0), Tuple.Create("Wood", 5, 0)), _ => new List(), }; } private List CreateRequirements(params Tuple[] ingredients) { List list = new List(); foreach (Tuple tuple in ingredients) { Requirement val = createReq(tuple.Item1, tuple.Item2, tuple.Item3); if (val != null) { list.Add(val); } } return list; } private Requirement createReq(string name, int amount, int amountPerLevel, GameObject commonReference = null) { //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_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_0070: Expected O, but got Unknown object obj2; if (!((Object)(object)commonReference != (Object)null)) { GameObject obj = FindItem(name); obj2 = ((obj != null) ? obj.GetComponent() : null); } else { obj2 = commonReference.GetComponent(); } ItemDrop val = (ItemDrop)obj2; if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("createReq failed: ItemDrop missing for \"" + name + "\"")); return null; } return new Requirement { m_resItem = val, m_amount = amount, m_amountPerLevel = amountPerLevel, m_recover = true }; } private GameObject FindItem(string name) { if (_itemCache.TryGetValue(name, out var value)) { return value; } GameObject val = ObjectDB.instance.GetItemPrefab(name); if ((Object)(object)val == (Object)null && newItems != null) { val = newItems.Find((GameObject x) => ((Object)x).name == name); } if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("FindItem: \"" + name + "\" not found, using fallback \"Wood\"")); val = ObjectDB.instance.GetItemPrefab("Wood"); } if ((Object)(object)val != (Object)null) { _itemCache[name] = val; } return val; } private Recipe AddRecipe(Recipe newRecipe, int amount, CraftingStation station, int stationLevel, List> ingredients) { newRecipe.m_craftingStation = station; newRecipe.m_minStationLevel = stationLevel; newRecipe.m_amount = amount; List list = new List(); HashSet hashSet = new HashSet(); foreach (Tuple ingredient in ingredients) { Requirement val = createReq(ingredient.Item1, ingredient.Item2, ingredient.Item3); if (val == null) { Debug.LogWarning((object)("Requirement skipped: " + ingredient.Item1 + " is null or invalid.")); continue; } if (hashSet.Contains(val.m_resItem)) { Debug.LogWarning((object)("Duplicate ingredient skipped: " + ((Object)val.m_resItem).name)); continue; } list.Add(val); hashSet.Add(val.m_resItem); } newRecipe.m_resources = list.ToArray(); if (list.Count == 0) { Debug.LogWarning((object)("No valid requirements found for recipe: " + ((Object)newRecipe).name)); return null; } return newRecipe; } } public class BuildPieceBuilder { private struct ResourceCost { public readonly string ItemName; public readonly int Amount; public readonly int AmountPerLevel; public readonly string AltItemName; public readonly int AltAmount; public readonly int AltAmountPerLevel; public ResourceCost(string itemName, int amount, int amountPerLevel, string altItemName, int altAmount, int altAmountPerLevel) { ItemName = itemName; Amount = amount; AmountPerLevel = amountPerLevel; AltItemName = altItemName; AltAmount = altAmount; AltAmountPerLevel = altAmountPerLevel; } } private const string WoodFallbackItemName = "Wood"; private readonly string[] piecesNames = BuildPieceList.buildPieces; private List list; private CraftingStation workbench; private CraftingStation tannery; private CraftingStation runeForge; private CraftingStation alchemyLab; private CraftingStation grill; private CraftingStation fletcher; private CraftingStation blackforge; private CraftingStation forge; private CraftingStation cauldron; private CraftingStation stonecutter; private CraftingStation artisan; public void SetupBuildPieces(List list) { this.list = list; SetupTables(list); string[] array = piecesNames; foreach (string name in array) { GameObject val = list.Find((GameObject x) => ((Object)x).name == name); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("Cant find buildpiece with name: " + name)); } else { EditBuildPiece(val); } } GameObject incinerator = list.Find((GameObject x) => ((Object)x).name == "incinerator" || ((Object)x).name == "iincinerator"); EditIncinerator(incinerator); } private void EditIncinerator(GameObject incinerator) { //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) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Expected O, but got Unknown //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0158: 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) //IL_016b: Expected O, but got Unknown if ((Object)(object)incinerator == (Object)null) { Debug.LogWarning((object)"[BCS] EditIncinerator: prefab incinerator not found."); return; } Incinerator component = incinerator.GetComponent(); if ((Object)(object)component == (Object)null) { Debug.LogWarning((object)("[BCS] EditIncinerator: Incinerator component missing on " + ((Object)incinerator).name)); return; } if (component.m_conversions == null) { component.m_conversions = new List(); } if (Launch.modResourceLoader == null || (Object)(object)Launch.modResourceLoader.unchargedStone == (Object)null) { Debug.LogWarning((object)"[BCS] EditIncinerator: unchargedStone is missing."); return; } ItemDrop component2 = Launch.modResourceLoader.unchargedStone.GetComponent(); if ((Object)(object)component2 == (Object)null) { Debug.LogWarning((object)"[BCS] EditIncinerator: unchargedStone has no ItemDrop."); return; } GameObject val = FindItem(list, "Thunderstone"); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)"[BCS] EditIncinerator: Thunderstone prefab missing."); return; } ItemDrop component3 = val.GetComponent(); if ((Object)(object)component3 == (Object)null) { Debug.LogWarning((object)"[BCS] EditIncinerator: Thunderstone has no ItemDrop."); return; } component.m_conversions.Add(new IncineratorConversion { m_priority = 1, m_requirements = new List { new Requirement { m_amount = 1, m_resItem = component2 } }, m_result = component3, m_resultAmount = 1, m_requireOnlyOneIngredient = false }); } private void EditBuildPiece(GameObject gameObject) { Piece component = gameObject.GetComponent(); if ((Object)(object)component == (Object)null) { Debug.LogWarning((object)("[BCS] EditBuildPiece: Piece component missing on " + ((Object)gameObject).name)); return; } ClearResources(component); SetStation(component, workbench); switch (((Object)gameObject).name) { case "railSignalDoor_bal": ConfigureRailPiece(component, 5, Resource("Crystal", 2)); break; case "railSignalLiftGate_bal": ConfigureRailPiece(component, 7, Resource("Crystal", 2), Resource("RoundLog", 10)); break; case "railtrackLampReciver_bal": ConfigureRailPiece(component, 2, Resource("Tin", 3), Resource("Crystal", 2)); break; case "railtrackSpeakerReciver_bal": ConfigureRailPiece(component, 2, Resource("Tin", 3), Resource("Crystal", 2)); break; case "railtrackStop_bal": ConfigureRailPiece(component, 1, Resource("Wood", 2)); break; case "pressenceSignalEmitter_bal": case "railtrackSignalEmitter_bal": ConfigureRailPiece(component, 1, Resource("Thunderstone", 1), Resource("Crystal", 1)); break; case "piece_buildstation_bal": ConfigurePiece(component, null, (PieceCategory)1, Resource("BuilderWorkstationBundle_bal", 1)); ConfigureBuilderWorkstation(((Component)component).gameObject); break; case "railtrackRamp26short_bal": case "railtrackRamp45short_bal": case "railtrack1m_bal": ConfigureRailPiece(component, 1); break; case "railtrackSwitchMid_bal": case "railtrackSwitchRight_bal": case "railtrackSwitchLeft_bal": ConfigureRailPiece(component, 3, Resource("Crystal", 1)); break; case "railtrack8m_bal": ConfigureRailPiece(component, 4); break; case "railtrackUnload_bal": ConfigureRailPiece(component, 2, Resource("Iron", 2), Resource("SurtlingCore", 1), Resource("FineWood", 5)); break; case "railtrackSpeed_bal": ConfigureRailPiece(component, 3, Resource("Thunderstone", 1)); break; case "railtrack4m_bal": ConfigureRailPiece(component, 3); break; case "railtrackCross_bal": ConfigureRailPiece(component, 2); break; case "railtrackTurnRight45_bal": case "railtrackTurnRight30_bal": case "railtrackTurnRight15_bal": case "railtrackTurnLeft45_bal": case "railtrackTurnLeft30_bal": case "railtrackTurnLeft15_bal": case "railtrackRamp_bal": case "railtrackRamp45_bal": case "railtrackRamp64_bal": case "railtrack_bal": ConfigureRailPiece(component, 2); break; case "railtrackControl_bal": ConfigureRailPiece(component, 2, Resource("Thunderstone", 1), Resource("Crystal", 1)); break; case "railtrackSignalStopReceiver_bal": ConfigureRailPiece(component, 2, Resource("Crystal", 1)); break; case "railtrackContainer_bal": ConfigureRailPiece(component, 2, Resource("Thunderstone", 1), Resource("Iron", 4), Resource("FineWood", 20)); break; case "railtrackJump4m_bal": ConfigureRailPiece(component, 2, Resource("SurtlingCore", 1)); break; case "railtrackJump6m_bal": ConfigureRailPiece(component, 3, Resource("SurtlingCore", 1)); break; case "railtrackDrop8m_bal": case "railtrackJump8m_bal": ConfigureRailPiece(component, 4, Resource("SurtlingCore", 1)); break; case "railtrackDrawbridge10m_bal": ConfigureRailPiece(component, 8, Resource("Thunderstone", 1), Resource("Iron", 4), Resource("FineWood", 20)); break; case "RailPersonelWagon_bal": ConfigurePiece(component, null, (PieceCategory)0, Resource("WagonBundlePersonel_bal", 1)); break; case "RailPowerWagon_bal": ConfigurePiece(component, null, (PieceCategory)0, Resource("WagonBundlePower_bal", 1)); break; case "RailCargoWagon_bal": ConfigurePiece(component, null, (PieceCategory)0, Resource("WagonBundleCargo_bal", 1)); break; case "RailTableWagon_bal": { ConfigurePiece(component, null, (PieceCategory)0, Resource("WagonBundleTable_bal", 1)); CraftingStation componentInChildren = ((Component)component).GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { ConfigureBuilderWorkstation(((Component)componentInChildren).gameObject); } break; } } } private void ConfigureRailPiece(Piece piece, int railPartsAmount, params ResourceCost[] extraResources) { List list = new List { Resource("RailPartsBundle_bal", railPartsAmount) }; if (extraResources != null) { list.AddRange(extraResources); } ConfigurePiece(piece, null, (PieceCategory)0, list.ToArray()); } private void ConfigurePiece(Piece piece, CraftingStation station, PieceCategory category, params ResourceCost[] resources) { //IL_005a: 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) SetStation(piece, station); ClearResources(piece); for (int i = 0; i < resources.Length; i++) { ResourceCost resourceCost = resources[i]; AddResources(piece, resourceCost.ItemName, resourceCost.Amount, resourceCost.AmountPerLevel, resourceCost.AltItemName, resourceCost.AltAmount, resourceCost.AltAmountPerLevel); } piece.m_category = category; } private static ResourceCost Resource(string itemName, int amount, int amountPerLevel = 0, string altItemName = "", int altAmount = 0, int altAmountPerLevel = 0) { return new ResourceCost(itemName, amount, amountPerLevel, altItemName, altAmount, altAmountPerLevel); } private static void ClearResources(Piece piece) { piece.m_resources = (Requirement[])(object)new Requirement[0]; } private static void ConfigureBuilderWorkstation(GameObject prefab) { if (!((Object)(object)prefab == (Object)null)) { BuilderWorkstation component = prefab.GetComponent(); if ((Object)(object)component == (Object)null) { prefab.AddComponent(); } CraftingStation val = prefab.GetComponent(); if ((Object)(object)val == (Object)null) { val = prefab.GetComponentInChildren(true); } if ((Object)(object)val != (Object)null) { val.m_craftRequireFire = false; val.m_rangeBuild = 40f; } else { Debug.LogWarning((object)("[BCS] ConfigureBuilderWorkstation: CraftingStation missing on " + ((Object)prefab).name)); } } } private void setFireplaceFuelItem(Piece piece, string name, int startFuel = -1, int maxFuel = -1, float secPerFuel = -1f) { Fireplace component = ((Component)piece).GetComponent(); if (!((Object)(object)component == (Object)null)) { component.m_fuelItem = FindItem(list, name).GetComponent(); component.m_startFuel = ((startFuel != -1) ? ((float)startFuel) : component.m_startFuel); component.m_maxFuel = ((maxFuel != -1) ? ((float)maxFuel) : component.m_maxFuel); component.m_secPerFuel = ((secPerFuel != -1f) ? secPerFuel : component.m_secPerFuel); } } private void SetStation(Piece piece, CraftingStation station) { piece.m_craftingStation = station; } private void EditResource(Piece piece, string itemName, int amount, bool remove = false) { if (remove) { List list = new List(); Requirement[] resources = piece.m_resources; foreach (Requirement val in resources) { if (((Object)((Component)val.m_resItem).gameObject).name != itemName) { list.Add(val); } } piece.m_resources = list.ToArray(); return; } Requirement[] resources2 = piece.m_resources; foreach (Requirement val2 in resources2) { if (((Object)((Component)val2.m_resItem).gameObject).name == itemName) { val2.m_amount = amount; } } } private void AddResources(Piece piece, string itemName, int amount, int amountPerLevel = 0, string altItem = "", int altAmount = 0, int altAmountPerLevel = 0) { List list = new List(); list.AddRange(piece.m_resources); Requirement val = CreateRequirement(itemName, amount, amountPerLevel, altItem, altAmount, altAmountPerLevel); if (val != null) { list.Add(val); } piece.m_resources = list.ToArray(); } private Requirement CreateRequirement(string name, int amount, int amountPerLevel, string altItem = "", int altAmount = 0, int altAmountPerLevel = 0) { //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_003e: 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_0059: Expected O, but got Unknown //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_0089: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown GameObject val = list.Find((GameObject x) => ((Object)x).name == name); if ((Object)(object)val != (Object)null) { return new Requirement { m_recover = true, m_amount = amount, m_amountPerLevel = amountPerLevel, m_resItem = val.GetComponent() }; } val = FindItem(list, altItem); if ((Object)(object)val == (Object)null) { return null; } return new Requirement { m_recover = true, m_amount = altAmount, m_amountPerLevel = altAmountPerLevel, m_resItem = val.GetComponent() }; } private GameObject FindItem(List list, string name, bool isStation = false) { GameObject val = list.Find((GameObject x) => ((Object)x).name == name); if ((Object)(object)val != (Object)null) { return val; } if (isStation) { return null; } Debug.LogWarning((object)(Launch.projectName + ": Item Not Found - " + name + ", Replaced With Wood")); return list.Find((GameObject x) => ((Object)x).name == "Wood"); } private CraftingStation FindStation(List list, string name) { GameObject val = FindItem(list, name, isStation: true); return ((Object)(object)val != (Object)null) ? val.GetComponent() : null; } private void SetupTables(List list) { workbench = FindRequiredStation(list, "piece_workbench", "piece_workbench"); artisan = FindRequiredStation(list, "piece_artisanstation", "piece_workbench"); blackforge = FindRequiredStation(list, "blackforge", "blackforge"); forge = FindRequiredStation(list, "forge", "forge"); cauldron = FindRequiredStation(list, "piece_cauldron", "piece_cauldron"); tannery = FindOptionalStation(list, "piece_tannery", workbench); runeForge = FindOptionalStation(list, "piece_runeforge", forge); alchemyLab = FindOptionalStation(list, "piece_alchemylab", cauldron); grill = FindOptionalStation(list, "piece_grill", cauldron); fletcher = FindOptionalStation(list, "piece_fletcher", workbench); stonecutter = FindOptionalStation(list, "piece_stonecutter", workbench, logMissing: true); } private CraftingStation FindRequiredStation(List list, string stationName, string warningName) { CraftingStation val = FindStation(list, stationName); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("Did not found" + warningName)); } return val; } private CraftingStation FindOptionalStation(List list, string stationName, CraftingStation fallback, bool logMissing = false) { CraftingStation val = FindStation(list, stationName); if ((Object)(object)val == (Object)null) { if (logMissing) { Debug.LogWarning((object)("Did not found" + stationName)); } return fallback; } return val; } } public class Resource { public int amount = 1; public int amountPerLevel = 0; public bool recovery = true; public ItemDrop itemDrop; public Requirement pieceConfig; public string item = "Wood"; public Resource() { } public Resource(string item, int amount, int amountPerLevel = 0, bool recovery = true) { this.item = item; this.amount = amount; this.amountPerLevel = amountPerLevel; this.recovery = recovery; } public void setItemDrop(GameObject prefab) { if ((Object)(object)prefab.GetComponent() != (Object)null) { itemDrop = prefab.GetComponent(); } else { Debug.LogWarning((object)("DVERGER FURNITURE: NO ITEM DROP FOUND on prefab name: " + ((Object)prefab).name)); } } public Requirement getPieceConfig() { //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_0013: 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_002b: 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_0039: Expected O, but got Unknown //IL_003e: Expected O, but got Unknown Requirement val = new Requirement { m_resItem = itemDrop, m_amount = amount, m_amountPerLevel = amountPerLevel, m_recover = recovery }; Requirement result = val; pieceConfig = val; return result; } } public class TableMapper { public static CraftingStation cauldron; public static CraftingStation workbench; public static CraftingStation heavyWorkbench; public static CraftingStation forge; public static CraftingStation ironworks; public static CraftingStation blackforge; public static CraftingStation stoneCutter; public static CraftingStation artisian; public static CraftingStation magetable; public static CraftingStation runeforge; public static CraftingStation tannery; public static CraftingStation fletcher; public static CraftingStation grill; public static CraftingStation alchemylab; public static CraftingStation shamantable; public static CraftingStation foodtable; public static CraftingStation smeltworks; public static ZNetScene zNetScene; public static List list = new List(); public static void setupTables(ZNetScene zNetScene = null, List list = null) { TableMapper.zNetScene = zNetScene; TableMapper.list = list; prepareTables(); } private static GameObject FindPrefabInZnet(string name, ZNetScene zNetScene) { GameObject value = null; zNetScene.m_namedPrefabs.TryGetValue(StringExtensionMethods.GetStableHashCode(name), out value); if ((Object)(object)value == (Object)null) { value = zNetScene.m_prefabs.Find((GameObject x) => ((Object)x).name == name); } return value; } private static CraftingStation FindStation(string name) { GameObject val = null; val = (GameObject)((!((Object)(object)zNetScene != (Object)null)) ? ((object)list.Find((GameObject x) => ((Object)x).name == name)) : ((object)FindPrefabInZnet(name, zNetScene))); if ((Object)(object)val != (Object)null) { return val.GetComponent(); } return null; } private static void prepareTables() { cauldron = FindStation("piece_cauldron"); workbench = FindStation("piece_workbench"); heavyWorkbench = FindStation("piece_heavy_workbench_bal"); forge = FindStation("forge"); ironworks = FindStation("piece_metalworks_bal"); blackforge = FindStation("blackforge"); stoneCutter = FindStation("piece_stonecutter"); artisian = FindStation("piece_artisanstation"); runeforge = FindStation("piece_runeforge_bal"); magetable = FindStation("piece_magetable"); fletcher = FindStation("piece_fletcher_bal"); shamantable = FindStation("piece_shamantable_bal"); foodtable = FindStation("piece_preptable"); grill = FindStation("piece_grill_bal"); alchemylab = FindStation("piece_MeadCauldron"); smeltworks = FindStation("piece_scrapsmelter_bal"); } } [HarmonyPatch] internal static class TranslationPatches { [HarmonyPatch(typeof(FejdStartup), "SetupGui")] private class FejdStartup_SetupGUI { private static void Postfix() { string selectedLanguage = Localization.instance.GetSelectedLanguage(); Dictionary translations = GetTranslations(selectedLanguage); AddTranslations(translations); } } [HarmonyPriority(800)] [HarmonyPatch(typeof(Localization), "SetupLanguage")] private class Translation_SetupLanguage { private static void Prefix(Localization __instance, string language) { Dictionary translations = GetTranslations(language); AddTranslations(translations, __instance); } } [HarmonyPriority(800)] [HarmonyPatch(typeof(Localization), "LoadCSV")] private class Translation_LoadCSV { private static void Prefix(Localization __instance, string language) { Dictionary translations = GetTranslations(language); AddTranslations(translations, __instance); } } private static Dictionary GetTranslations(string language) { Dictionary result = BalrondTranslator.getLanguage("English"); if (!string.Equals(language, "English", StringComparison.OrdinalIgnoreCase)) { Dictionary language2 = BalrondTranslator.getLanguage(language); if (language2 != null) { result = language2; } else { Debug.Log((object)("BalrondRuneRails: Did not find translation file for '" + language + "', loading English")); } } return result; } private static void AddTranslations(Dictionary translations, Localization localizationInstance = null) { if (translations == null) { Debug.LogWarning((object)"BalrondRuneRails: No translation file found!"); return; } if (localizationInstance != null) { foreach (KeyValuePair translation in translations) { localizationInstance.AddWord(translation.Key, translation.Value); } return; } foreach (KeyValuePair translation2 in translations) { Localization.instance.AddWord(translation2.Key, translation2.Value); } } } } namespace LitJson2 { internal enum JsonType { None, Object, Array, String, Int, Long, Double, Boolean } internal interface IJsonWrapper : IList, IOrderedDictionary, IDictionary, ICollection, IEnumerable { bool IsArray { get; } bool IsBoolean { get; } bool IsDouble { get; } bool IsInt { get; } bool IsLong { get; } bool IsObject { get; } bool IsString { get; } bool GetBoolean(); double GetDouble(); int GetInt(); JsonType GetJsonType(); long GetLong(); string GetString(); void SetBoolean(bool val); void SetDouble(double val); void SetInt(int val); void SetJsonType(JsonType type); void SetLong(long val); void SetString(string val); string ToJson(); void ToJson(JsonWriter writer); } internal class JsonData : IJsonWrapper, IList, IOrderedDictionary, IDictionary, ICollection, IEnumerable, IEquatable { private IList inst_array; private bool inst_boolean; private double inst_double; private int inst_int; private long inst_long; private IDictionary inst_object; private string inst_string; private string json; private JsonType type; private IList> object_list; public int Count => EnsureCollection().Count; public bool IsArray => type == JsonType.Array; public bool IsBoolean => type == JsonType.Boolean; public bool IsDouble => type == JsonType.Double; public bool IsInt => type == JsonType.Int; public bool IsLong => type == JsonType.Long; public bool IsObject => type == JsonType.Object; public bool IsString => type == JsonType.String; public ICollection Keys { get { EnsureDictionary(); return inst_object.Keys; } } int ICollection.Count => Count; bool ICollection.IsSynchronized => EnsureCollection().IsSynchronized; object ICollection.SyncRoot => EnsureCollection().SyncRoot; bool IDictionary.IsFixedSize => EnsureDictionary().IsFixedSize; bool IDictionary.IsReadOnly => EnsureDictionary().IsReadOnly; ICollection IDictionary.Keys { get { EnsureDictionary(); IList list = new List(); foreach (KeyValuePair item in object_list) { list.Add(item.Key); } return (ICollection)list; } } ICollection IDictionary.Values { get { EnsureDictionary(); IList list = new List(); foreach (KeyValuePair item in object_list) { list.Add(item.Value); } return (ICollection)list; } } bool IJsonWrapper.IsArray => IsArray; bool IJsonWrapper.IsBoolean => IsBoolean; bool IJsonWrapper.IsDouble => IsDouble; bool IJsonWrapper.IsInt => IsInt; bool IJsonWrapper.IsLong => IsLong; bool IJsonWrapper.IsObject => IsObject; bool IJsonWrapper.IsString => IsString; bool IList.IsFixedSize => EnsureList().IsFixedSize; bool IList.IsReadOnly => EnsureList().IsReadOnly; object IDictionary.this[object key] { get { return EnsureDictionary()[key]; } set { if (!(key is string)) { throw new ArgumentException("The key has to be a string"); } JsonData value2 = ToJsonData(value); this[(string)key] = value2; } } object IOrderedDictionary.this[int idx] { get { EnsureDictionary(); return object_list[idx].Value; } set { EnsureDictionary(); JsonData value2 = ToJsonData(value); KeyValuePair keyValuePair = object_list[idx]; inst_object[keyValuePair.Key] = value2; KeyValuePair value3 = new KeyValuePair(keyValuePair.Key, value2); object_list[idx] = value3; } } object IList.this[int index] { get { return EnsureList()[index]; } set { EnsureList(); JsonData value2 = ToJsonData(value); this[index] = value2; } } public JsonData this[string prop_name] { get { EnsureDictionary(); return inst_object[prop_name]; } set { EnsureDictionary(); KeyValuePair keyValuePair = new KeyValuePair(prop_name, value); if (inst_object.ContainsKey(prop_name)) { for (int i = 0; i < object_list.Count; i++) { if (object_list[i].Key == prop_name) { object_list[i] = keyValuePair; break; } } } else { object_list.Add(keyValuePair); } inst_object[prop_name] = value; json = null; } } public JsonData this[int index] { get { EnsureCollection(); if (type == JsonType.Array) { return inst_array[index]; } return object_list[index].Value; } set { EnsureCollection(); if (type == JsonType.Array) { inst_array[index] = value; } else { KeyValuePair keyValuePair = object_list[index]; KeyValuePair value2 = new KeyValuePair(keyValuePair.Key, value); object_list[index] = value2; inst_object[keyValuePair.Key] = value; } json = null; } } public JsonData() { } public JsonData(bool boolean) { type = JsonType.Boolean; inst_boolean = boolean; } public JsonData(double number) { type = JsonType.Double; inst_double = number; } public JsonData(int number) { type = JsonType.Int; inst_int = number; } public JsonData(long number) { type = JsonType.Long; inst_long = number; } public JsonData(object obj) { if (obj is bool) { type = JsonType.Boolean; inst_boolean = (bool)obj; return; } if (obj is double) { type = JsonType.Double; inst_double = (double)obj; return; } if (obj is int) { type = JsonType.Int; inst_int = (int)obj; return; } if (obj is long) { type = JsonType.Long; inst_long = (long)obj; return; } if (obj is string) { type = JsonType.String; inst_string = (string)obj; return; } throw new ArgumentException("Unable to wrap the given object with JsonData"); } public JsonData(string str) { type = JsonType.String; inst_string = str; } public static implicit operator JsonData(bool data) { return new JsonData(data); } public static implicit operator JsonData(double data) { return new JsonData(data); } public static implicit operator JsonData(int data) { return new JsonData(data); } public static implicit operator JsonData(long data) { return new JsonData(data); } public static implicit operator JsonData(string data) { return new JsonData(data); } public static explicit operator bool(JsonData data) { if (data.type != JsonType.Boolean) { throw new InvalidCastException("Instance of JsonData doesn't hold a double"); } return data.inst_boolean; } public static explicit operator double(JsonData data) { if (data.type != JsonType.Double) { throw new InvalidCastException("Instance of JsonData doesn't hold a double"); } return data.inst_double; } public static explicit operator int(JsonData data) { if (data.type != JsonType.Int) { throw new InvalidCastException("Instance of JsonData doesn't hold an int"); } return data.inst_int; } public static explicit operator long(JsonData data) { if (data.type != JsonType.Long) { throw new InvalidCastException("Instance of JsonData doesn't hold an int"); } return data.inst_long; } public static explicit operator string(JsonData data) { if (data.type != JsonType.String) { throw new InvalidCastException("Instance of JsonData doesn't hold a string"); } return data.inst_string; } void ICollection.CopyTo(Array array, int index) { EnsureCollection().CopyTo(array, index); } void IDictionary.Add(object key, object value) { JsonData value2 = ToJsonData(value); EnsureDictionary().Add(key, value2); KeyValuePair item = new KeyValuePair((string)key, value2); object_list.Add(item); json = null; } void IDictionary.Clear() { EnsureDictionary().Clear(); object_list.Clear(); json = null; } bool IDictionary.Contains(object key) { return EnsureDictionary().Contains(key); } IDictionaryEnumerator IDictionary.GetEnumerator() { return ((IOrderedDictionary)this).GetEnumerator(); } void IDictionary.Remove(object key) { EnsureDictionary().Remove(key); for (int i = 0; i < object_list.Count; i++) { if (object_list[i].Key == (string)key) { object_list.RemoveAt(i); break; } } json = null; } IEnumerator IEnumerable.GetEnumerator() { return EnsureCollection().GetEnumerator(); } bool IJsonWrapper.GetBoolean() { if (type != JsonType.Boolean) { throw new InvalidOperationException("JsonData instance doesn't hold a boolean"); } return inst_boolean; } double IJsonWrapper.GetDouble() { if (type != JsonType.Double) { throw new InvalidOperationException("JsonData instance doesn't hold a double"); } return inst_double; } int IJsonWrapper.GetInt() { if (type != JsonType.Int) { throw new InvalidOperationException("JsonData instance doesn't hold an int"); } return inst_int; } long IJsonWrapper.GetLong() { if (type != JsonType.Long) { throw new InvalidOperationException("JsonData instance doesn't hold a long"); } return inst_long; } string IJsonWrapper.GetString() { if (type != JsonType.String) { throw new InvalidOperationException("JsonData instance doesn't hold a string"); } return inst_string; } void IJsonWrapper.SetBoolean(bool val) { type = JsonType.Boolean; inst_boolean = val; json = null; } void IJsonWrapper.SetDouble(double val) { type = JsonType.Double; inst_double = val; json = null; } void IJsonWrapper.SetInt(int val) { type = JsonType.Int; inst_int = val; json = null; } void IJsonWrapper.SetLong(long val) { type = JsonType.Long; inst_long = val; json = null; } void IJsonWrapper.SetString(string val) { type = JsonType.String; inst_string = val; json = null; } string IJsonWrapper.ToJson() { return ToJson(); } void IJsonWrapper.ToJson(JsonWriter writer) { ToJson(writer); } int IList.Add(object value) { return Add(value); } void IList.Clear() { EnsureList().Clear(); json = null; } bool IList.Contains(object value) { return EnsureList().Contains(value); } int IList.IndexOf(object value) { return EnsureList().IndexOf(value); } void IList.Insert(int index, object value) { EnsureList().Insert(index, value); json = null; } void IList.Remove(object value) { EnsureList().Remove(value); json = null; } void IList.RemoveAt(int index) { EnsureList().RemoveAt(index); json = null; } IDictionaryEnumerator IOrderedDictionary.GetEnumerator() { EnsureDictionary(); return new OrderedDictionaryEnumerator(object_list.GetEnumerator()); } void IOrderedDictionary.Insert(int idx, object key, object value) { string text = (string)key; JsonData value2 = (this[text] = ToJsonData(value)); KeyValuePair item = new KeyValuePair(text, value2); object_list.Insert(idx, item); } void IOrderedDictionary.RemoveAt(int idx) { EnsureDictionary(); inst_object.Remove(object_list[idx].Key); object_list.RemoveAt(idx); } private ICollection EnsureCollection() { if (type == JsonType.Array) { return (ICollection)inst_array; } if (type == JsonType.Object) { return (ICollection)inst_object; } throw new InvalidOperationException("The JsonData instance has to be initialized first"); } private IDictionary EnsureDictionary() { if (type == JsonType.Object) { return (IDictionary)inst_object; } if (type != 0) { throw new InvalidOperationException("Instance of JsonData is not a dictionary"); } type = JsonType.Object; inst_object = new Dictionary(); object_list = new List>(); return (IDictionary)inst_object; } private IList EnsureList() { if (type == JsonType.Array) { return (IList)inst_array; } if (type != 0) { throw new InvalidOperationException("Instance of JsonData is not a list"); } type = JsonType.Array; inst_array = new List(); return (IList)inst_array; } private JsonData ToJsonData(object obj) { if (obj == null) { return null; } if (obj is JsonData) { return (JsonData)obj; } return new JsonData(obj); } private static void WriteJson(IJsonWrapper obj, JsonWriter writer) { if (obj == null) { writer.Write(null); } else if (obj.IsString) { writer.Write(obj.GetString()); } else if (obj.IsBoolean) { writer.Write(obj.GetBoolean()); } else if (obj.IsDouble) { writer.Write(obj.GetDouble()); } else if (obj.IsInt) { writer.Write(obj.GetInt()); } else if (obj.IsLong) { writer.Write(obj.GetLong()); } else if (obj.IsArray) { writer.WriteArrayStart(); foreach (object item in (IEnumerable)obj) { WriteJson((JsonData)item, writer); } writer.WriteArrayEnd(); } else { if (!obj.IsObject) { return; } writer.WriteObjectStart(); foreach (DictionaryEntry item2 in (IDictionary)obj) { writer.WritePropertyName((string)item2.Key); WriteJson((JsonData)item2.Value, writer); } writer.WriteObjectEnd(); } } public int Add(object value) { JsonData value2 = ToJsonData(value); json = null; return EnsureList().Add(value2); } public void Clear() { if (IsObject) { ((IDictionary)this).Clear(); } else if (IsArray) { ((IList)this).Clear(); } } public bool Equals(JsonData x) { if (x == null) { return false; } if (x.type != type) { return false; } return type switch { JsonType.None => true, JsonType.Object => inst_object.Equals(x.inst_object), JsonType.Array => inst_array.Equals(x.inst_array), JsonType.String => inst_string.Equals(x.inst_string), JsonType.Int => inst_int.Equals(x.inst_int), JsonType.Long => inst_long.Equals(x.inst_long), JsonType.Double => inst_double.Equals(x.inst_double), JsonType.Boolean => inst_boolean.Equals(x.inst_boolean), _ => false, }; } public JsonType GetJsonType() { return type; } public void SetJsonType(JsonType type) { if (this.type != type) { switch (type) { case JsonType.Object: inst_object = new Dictionary(); object_list = new List>(); break; case JsonType.Array: inst_array = new List(); break; case JsonType.String: inst_string = null; break; case JsonType.Int: inst_int = 0; break; case JsonType.Long: inst_long = 0L; break; case JsonType.Double: inst_double = 0.0; break; case JsonType.Boolean: inst_boolean = false; break; } this.type = type; } } public string ToJson() { if (json != null) { return json; } StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.Validate = false; WriteJson(this, jsonWriter); json = stringWriter.ToString(); return json; } public void ToJson(JsonWriter writer) { bool validate = writer.Validate; writer.Validate = false; WriteJson(this, writer); writer.Validate = validate; } public override string ToString() { return type switch { JsonType.Array => "JsonData array", JsonType.Boolean => inst_boolean.ToString(), JsonType.Double => inst_double.ToString(), JsonType.Int => inst_int.ToString(), JsonType.Long => inst_long.ToString(), JsonType.Object => "JsonData object", JsonType.String => inst_string, _ => "Uninitialized JsonData", }; } } internal class OrderedDictionaryEnumerator : IDictionaryEnumerator, IEnumerator { private IEnumerator> list_enumerator; public object Current => Entry; public DictionaryEntry Entry { get { KeyValuePair current = list_enumerator.Current; return new DictionaryEntry(current.Key, current.Value); } } public object Key => list_enumerator.Current.Key; public object Value => list_enumerator.Current.Value; public OrderedDictionaryEnumerator(IEnumerator> enumerator) { list_enumerator = enumerator; } public bool MoveNext() { return list_enumerator.MoveNext(); } public void Reset() { list_enumerator.Reset(); } } internal class JsonException : ApplicationException { public JsonException() { } internal JsonException(ParserToken token) : base($"Invalid token '{token}' in input string") { } internal JsonException(ParserToken token, Exception inner_exception) : base($"Invalid token '{token}' in input string", inner_exception) { } internal JsonException(int c) : base($"Invalid character '{(char)c}' in input string") { } internal JsonException(int c, Exception inner_exception) : base($"Invalid character '{(char)c}' in input string", inner_exception) { } public JsonException(string message) : base(message) { } public JsonException(string message, Exception inner_exception) : base(message, inner_exception) { } } internal struct PropertyMetadata { public MemberInfo Info; public bool IsField; public Type Type; } internal struct ArrayMetadata { private Type element_type; private bool is_array; private bool is_list; public Type ElementType { get { if (element_type == null) { return typeof(JsonData); } return element_type; } set { element_type = value; } } public bool IsArray { get { return is_array; } set { is_array = value; } } public bool IsList { get { return is_list; } set { is_list = value; } } } internal struct ObjectMetadata { private Type element_type; private bool is_dictionary; private IDictionary properties; public Type ElementType { get { if (element_type == null) { return typeof(JsonData); } return element_type; } set { element_type = value; } } public bool IsDictionary { get { return is_dictionary; } set { is_dictionary = value; } } public IDictionary Properties { get { return properties; } set { properties = value; } } } internal delegate void ExporterFunc(object obj, JsonWriter writer); internal delegate void ExporterFunc(T obj, JsonWriter writer); internal delegate object ImporterFunc(object input); internal delegate TValue ImporterFunc(TJson input); internal delegate IJsonWrapper WrapperFactory(); internal class JsonMapper { private static int max_nesting_depth; private static IFormatProvider datetime_format; private static IDictionary base_exporters_table; private static IDictionary custom_exporters_table; private static IDictionary> base_importers_table; private static IDictionary> custom_importers_table; private static IDictionary array_metadata; private static readonly object array_metadata_lock; private static IDictionary> conv_ops; private static readonly object conv_ops_lock; private static IDictionary object_metadata; private static readonly object object_metadata_lock; private static IDictionary> type_properties; private static readonly object type_properties_lock; private static JsonWriter static_writer; private static readonly object static_writer_lock; static JsonMapper() { array_metadata_lock = new object(); conv_ops_lock = new object(); object_metadata_lock = new object(); type_properties_lock = new object(); static_writer_lock = new object(); max_nesting_depth = 100; array_metadata = new Dictionary(); conv_ops = new Dictionary>(); object_metadata = new Dictionary(); type_properties = new Dictionary>(); static_writer = new JsonWriter(); datetime_format = DateTimeFormatInfo.InvariantInfo; base_exporters_table = new Dictionary(); custom_exporters_table = new Dictionary(); base_importers_table = new Dictionary>(); custom_importers_table = new Dictionary>(); RegisterBaseExporters(); RegisterBaseImporters(); } private static void AddArrayMetadata(Type type) { if (array_metadata.ContainsKey(type)) { return; } ArrayMetadata value = default(ArrayMetadata); value.IsArray = type.IsArray; if (type.GetInterface("System.Collections.IList") != null) { value.IsList = true; } PropertyInfo[] properties = type.GetProperties(); foreach (PropertyInfo propertyInfo in properties) { if (!(propertyInfo.Name != "Item")) { ParameterInfo[] indexParameters = propertyInfo.GetIndexParameters(); if (indexParameters.Length == 1 && indexParameters[0].ParameterType == typeof(int)) { value.ElementType = propertyInfo.PropertyType; } } } lock (array_metadata_lock) { try { array_metadata.Add(type, value); } catch (ArgumentException) { } } } private static void AddObjectMetadata(Type type) { if (object_metadata.ContainsKey(type)) { return; } ObjectMetadata value = default(ObjectMetadata); if (type.GetInterface("System.Collections.IDictionary") != null) { value.IsDictionary = true; } value.Properties = new Dictionary(); PropertyInfo[] properties = type.GetProperties(); foreach (PropertyInfo propertyInfo in properties) { if (propertyInfo.Name == "Item") { ParameterInfo[] indexParameters = propertyInfo.GetIndexParameters(); if (indexParameters.Length == 1 && indexParameters[0].ParameterType == typeof(string)) { value.ElementType = propertyInfo.PropertyType; } } else { PropertyMetadata value2 = default(PropertyMetadata); value2.Info = propertyInfo; value2.Type = propertyInfo.PropertyType; value.Properties.Add(propertyInfo.Name, value2); } } FieldInfo[] fields = type.GetFields(); foreach (FieldInfo fieldInfo in fields) { PropertyMetadata value3 = default(PropertyMetadata); value3.Info = fieldInfo; value3.IsField = true; value3.Type = fieldInfo.FieldType; value.Properties.Add(fieldInfo.Name, value3); } lock (object_metadata_lock) { try { object_metadata.Add(type, value); } catch (ArgumentException) { } } } private static void AddTypeProperties(Type type) { if (type_properties.ContainsKey(type)) { return; } IList list = new List(); PropertyInfo[] properties = type.GetProperties(); foreach (PropertyInfo propertyInfo in properties) { if (!(propertyInfo.Name == "Item")) { PropertyMetadata item = default(PropertyMetadata); item.Info = propertyInfo; item.IsField = false; list.Add(item); } } FieldInfo[] fields = type.GetFields(); foreach (FieldInfo info in fields) { PropertyMetadata item2 = default(PropertyMetadata); item2.Info = info; item2.IsField = true; list.Add(item2); } lock (type_properties_lock) { try { type_properties.Add(type, list); } catch (ArgumentException) { } } } private static MethodInfo GetConvOp(Type t1, Type t2) { lock (conv_ops_lock) { if (!conv_ops.ContainsKey(t1)) { conv_ops.Add(t1, new Dictionary()); } } if (conv_ops[t1].ContainsKey(t2)) { return conv_ops[t1][t2]; } MethodInfo method = t1.GetMethod("op_Implicit", new Type[1] { t2 }); lock (conv_ops_lock) { try { conv_ops[t1].Add(t2, method); return method; } catch (ArgumentException) { return conv_ops[t1][t2]; } } } private static object ReadValue(Type inst_type, JsonReader reader) { reader.Read(); if (reader.Token == JsonToken.ArrayEnd) { return null; } Type underlyingType = Nullable.GetUnderlyingType(inst_type); Type type = underlyingType ?? inst_type; if (reader.Token == JsonToken.Null) { if (inst_type.IsClass || underlyingType != null) { return null; } throw new JsonException($"Can't assign null to an instance of type {inst_type}"); } if (reader.Token == JsonToken.Double || reader.Token == JsonToken.Int || reader.Token == JsonToken.Long || reader.Token == JsonToken.String || reader.Token == JsonToken.Boolean) { Type type2 = reader.Value.GetType(); if (type.IsAssignableFrom(type2)) { return reader.Value; } if (custom_importers_table.ContainsKey(type2) && custom_importers_table[type2].ContainsKey(type)) { ImporterFunc importerFunc = custom_importers_table[type2][type]; return importerFunc(reader.Value); } if (base_importers_table.ContainsKey(type2) && base_importers_table[type2].ContainsKey(type)) { ImporterFunc importerFunc2 = base_importers_table[type2][type]; return importerFunc2(reader.Value); } if (type.IsEnum) { return Enum.ToObject(type, reader.Value); } MethodInfo convOp = GetConvOp(type, type2); if (convOp != null) { return convOp.Invoke(null, new object[1] { reader.Value }); } throw new JsonException($"Can't assign value '{reader.Value}' (type {type2}) to type {inst_type}"); } object obj = null; if (reader.Token == JsonToken.ArrayStart) { AddArrayMetadata(inst_type); ArrayMetadata arrayMetadata = array_metadata[inst_type]; if (!arrayMetadata.IsArray && !arrayMetadata.IsList) { throw new JsonException($"Type {inst_type} can't act as an array"); } IList list; Type elementType; if (!arrayMetadata.IsArray) { list = (IList)Activator.CreateInstance(inst_type); elementType = arrayMetadata.ElementType; } else { list = new ArrayList(); elementType = inst_type.GetElementType(); } while (true) { object obj2 = ReadValue(elementType, reader); if (obj2 == null && reader.Token == JsonToken.ArrayEnd) { break; } list.Add(obj2); } if (arrayMetadata.IsArray) { int count = list.Count; obj = Array.CreateInstance(elementType, count); for (int i = 0; i < count; i++) { ((Array)obj).SetValue(list[i], i); } } else { obj = list; } } else if (reader.Token == JsonToken.ObjectStart) { AddObjectMetadata(type); ObjectMetadata objectMetadata = object_metadata[type]; obj = Activator.CreateInstance(type); while (true) { reader.Read(); if (reader.Token == JsonToken.ObjectEnd) { break; } string text = (string)reader.Value; if (objectMetadata.Properties.ContainsKey(text)) { PropertyMetadata propertyMetadata = objectMetadata.Properties[text]; if (propertyMetadata.IsField) { ((FieldInfo)propertyMetadata.Info).SetValue(obj, ReadValue(propertyMetadata.Type, reader)); continue; } PropertyInfo propertyInfo = (PropertyInfo)propertyMetadata.Info; if (propertyInfo.CanWrite) { propertyInfo.SetValue(obj, ReadValue(propertyMetadata.Type, reader), null); } else { ReadValue(propertyMetadata.Type, reader); } } else if (!objectMetadata.IsDictionary) { if (!reader.SkipNonMembers) { throw new JsonException($"The type {inst_type} doesn't have the property '{text}'"); } ReadSkip(reader); } else { ((IDictionary)obj).Add(text, ReadValue(objectMetadata.ElementType, reader)); } } } return obj; } private static IJsonWrapper ReadValue(WrapperFactory factory, JsonReader reader) { reader.Read(); if (reader.Token == JsonToken.ArrayEnd || reader.Token == JsonToken.Null) { return null; } IJsonWrapper jsonWrapper = factory(); if (reader.Token == JsonToken.String) { jsonWrapper.SetString((string)reader.Value); return jsonWrapper; } if (reader.Token == JsonToken.Double) { jsonWrapper.SetDouble((double)reader.Value); return jsonWrapper; } if (reader.Token == JsonToken.Int) { jsonWrapper.SetInt((int)reader.Value); return jsonWrapper; } if (reader.Token == JsonToken.Long) { jsonWrapper.SetLong((long)reader.Value); return jsonWrapper; } if (reader.Token == JsonToken.Boolean) { jsonWrapper.SetBoolean((bool)reader.Value); return jsonWrapper; } if (reader.Token == JsonToken.ArrayStart) { jsonWrapper.SetJsonType(JsonType.Array); while (true) { IJsonWrapper jsonWrapper2 = ReadValue(factory, reader); if (jsonWrapper2 == null && reader.Token == JsonToken.ArrayEnd) { break; } jsonWrapper.Add(jsonWrapper2); } } else if (reader.Token == JsonToken.ObjectStart) { jsonWrapper.SetJsonType(JsonType.Object); while (true) { reader.Read(); if (reader.Token == JsonToken.ObjectEnd) { break; } string key = (string)reader.Value; jsonWrapper[key] = ReadValue(factory, reader); } } return jsonWrapper; } private static void ReadSkip(JsonReader reader) { ToWrapper(() => new JsonMockWrapper(), reader); } private static void RegisterBaseExporters() { base_exporters_table[typeof(byte)] = delegate(object obj, JsonWriter writer) { writer.Write(Convert.ToInt32((byte)obj)); }; base_exporters_table[typeof(char)] = delegate(object obj, JsonWriter writer) { writer.Write(Convert.ToString((char)obj)); }; base_exporters_table[typeof(DateTime)] = delegate(object obj, JsonWriter writer) { writer.Write(Convert.ToString((DateTime)obj, datetime_format)); }; base_exporters_table[typeof(decimal)] = delegate(object obj, JsonWriter writer) { writer.Write((decimal)obj); }; base_exporters_table[typeof(sbyte)] = delegate(object obj, JsonWriter writer) { writer.Write(Convert.ToInt32((sbyte)obj)); }; base_exporters_table[typeof(short)] = delegate(object obj, JsonWriter writer) { writer.Write(Convert.ToInt32((short)obj)); }; base_exporters_table[typeof(ushort)] = delegate(object obj, JsonWriter writer) { writer.Write(Convert.ToInt32((ushort)obj)); }; base_exporters_table[typeof(uint)] = delegate(object obj, JsonWriter writer) { writer.Write(Convert.ToUInt64((uint)obj)); }; base_exporters_table[typeof(ulong)] = delegate(object obj, JsonWriter writer) { writer.Write((ulong)obj); }; } private static void RegisterBaseImporters() { ImporterFunc importer = (object input) => Convert.ToByte((int)input); RegisterImporter(base_importers_table, typeof(int), typeof(byte), importer); importer = (object input) => Convert.ToUInt64((int)input); RegisterImporter(base_importers_table, typeof(int), typeof(ulong), importer); importer = (object input) => Convert.ToSByte((int)input); RegisterImporter(base_importers_table, typeof(int), typeof(sbyte), importer); importer = (object input) => Convert.ToInt16((int)input); RegisterImporter(base_importers_table, typeof(int), typeof(short), importer); importer = (object input) => Convert.ToUInt16((int)input); RegisterImporter(base_importers_table, typeof(int), typeof(ushort), importer); importer = (object input) => Convert.ToUInt32((int)input); RegisterImporter(base_importers_table, typeof(int), typeof(uint), importer); importer = (object input) => Convert.ToSingle((int)input); RegisterImporter(base_importers_table, typeof(int), typeof(float), importer); importer = (object input) => Convert.ToDouble((int)input); RegisterImporter(base_importers_table, typeof(int), typeof(double), importer); importer = (object input) => Convert.ToDecimal((double)input); RegisterImporter(base_importers_table, typeof(double), typeof(decimal), importer); importer = (object input) => Convert.ToUInt32((long)input); RegisterImporter(base_importers_table, typeof(long), typeof(uint), importer); importer = (object input) => Convert.ToChar((string)input); RegisterImporter(base_importers_table, typeof(string), typeof(char), importer); importer = (object input) => Convert.ToDateTime((string)input, datetime_format); RegisterImporter(base_importers_table, typeof(string), typeof(DateTime), importer); } private static void RegisterImporter(IDictionary> table, Type json_type, Type value_type, ImporterFunc importer) { if (!table.ContainsKey(json_type)) { table.Add(json_type, new Dictionary()); } table[json_type][value_type] = importer; } private static void WriteValue(object obj, JsonWriter writer, bool writer_is_private, int depth) { if (depth > max_nesting_depth) { throw new JsonException($"Max allowed object depth reached while trying to export from type {obj.GetType()}"); } if (obj == null) { writer.Write(null); return; } if (obj is IJsonWrapper) { if (writer_is_private) { writer.TextWriter.Write(((IJsonWrapper)obj).ToJson()); } else { ((IJsonWrapper)obj).ToJson(writer); } return; } if (obj is string) { writer.Write((string)obj); return; } if (obj is double) { writer.Write((double)obj); return; } if (obj is int) { writer.Write((int)obj); return; } if (obj is bool) { writer.Write((bool)obj); return; } if (obj is long) { writer.Write((long)obj); return; } if (obj is Array) { writer.WriteArrayStart(); foreach (object item in (Array)obj) { WriteValue(item, writer, writer_is_private, depth + 1); } writer.WriteArrayEnd(); return; } if (obj is IList) { writer.WriteArrayStart(); foreach (object item2 in (IList)obj) { WriteValue(item2, writer, writer_is_private, depth + 1); } writer.WriteArrayEnd(); return; } if (obj is IDictionary) { writer.WriteObjectStart(); foreach (DictionaryEntry item3 in (IDictionary)obj) { writer.WritePropertyName((string)item3.Key); WriteValue(item3.Value, writer, writer_is_private, depth + 1); } writer.WriteObjectEnd(); return; } Type type = obj.GetType(); if (custom_exporters_table.ContainsKey(type)) { ExporterFunc exporterFunc = custom_exporters_table[type]; exporterFunc(obj, writer); return; } if (base_exporters_table.ContainsKey(type)) { ExporterFunc exporterFunc2 = base_exporters_table[type]; exporterFunc2(obj, writer); return; } if (obj is Enum) { Type underlyingType = Enum.GetUnderlyingType(type); if (underlyingType == typeof(long) || underlyingType == typeof(uint) || underlyingType == typeof(ulong)) { writer.Write((ulong)obj); } else { writer.Write((int)obj); } return; } AddTypeProperties(type); IList list = type_properties[type]; writer.WriteObjectStart(); foreach (PropertyMetadata item4 in list) { if (item4.IsField) { writer.WritePropertyName(item4.Info.Name); WriteValue(((FieldInfo)item4.Info).GetValue(obj), writer, writer_is_private, depth + 1); continue; } PropertyInfo propertyInfo = (PropertyInfo)item4.Info; if (propertyInfo.CanRead) { writer.WritePropertyName(item4.Info.Name); WriteValue(propertyInfo.GetValue(obj, null), writer, writer_is_private, depth + 1); } } writer.WriteObjectEnd(); } public static string ToJson(object obj) { lock (static_writer_lock) { static_writer.Reset(); WriteValue(obj, static_writer, writer_is_private: true, 0); return static_writer.ToString(); } } public static void ToJson(object obj, JsonWriter writer) { WriteValue(obj, writer, writer_is_private: false, 0); } public static JsonData ToObject(JsonReader reader) { return (JsonData)ToWrapper(() => new JsonData(), reader); } public static JsonData ToObject(TextReader reader) { JsonReader reader2 = new JsonReader(reader); return (JsonData)ToWrapper(() => new JsonData(), reader2); } public static JsonData ToObject(string json) { return (JsonData)ToWrapper(() => new JsonData(), json); } public static T ToObject(JsonReader reader) { return (T)ReadValue(typeof(T), reader); } public static T ToObject(TextReader reader) { JsonReader reader2 = new JsonReader(reader); return (T)ReadValue(typeof(T), reader2); } public static T ToObject(string json) { JsonReader reader = new JsonReader(json); return (T)ReadValue(typeof(T), reader); } public static IJsonWrapper ToWrapper(WrapperFactory factory, JsonReader reader) { return ReadValue(factory, reader); } public static IJsonWrapper ToWrapper(WrapperFactory factory, string json) { JsonReader reader = new JsonReader(json); return ReadValue(factory, reader); } public static void RegisterExporter(ExporterFunc exporter) { ExporterFunc value = delegate(object obj, JsonWriter writer) { exporter((T)obj, writer); }; custom_exporters_table[typeof(T)] = value; } public static void RegisterImporter(ImporterFunc importer) { ImporterFunc importer2 = (object input) => importer((TJson)input); RegisterImporter(custom_importers_table, typeof(TJson), typeof(TValue), importer2); } public static void UnregisterExporters() { custom_exporters_table.Clear(); } public static void UnregisterImporters() { custom_importers_table.Clear(); } } internal class JsonMockWrapper : IJsonWrapper, IList, IOrderedDictionary, IDictionary, ICollection, IEnumerable { public bool IsArray => false; public bool IsBoolean => false; public bool IsDouble => false; public bool IsInt => false; public bool IsLong => false; public bool IsObject => false; public bool IsString => false; bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; object IList.this[int index] { get { return null; } set { } } int ICollection.Count => 0; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => null; bool IDictionary.IsFixedSize => true; bool IDictionary.IsReadOnly => true; ICollection IDictionary.Keys => null; ICollection IDictionary.Values => null; object IDictionary.this[object key] { get { return null; } set { } } object IOrderedDictionary.this[int idx] { get { return null; } set { } } public bool GetBoolean() { return false; } public double GetDouble() { return 0.0; } public int GetInt() { return 0; } public JsonType GetJsonType() { return JsonType.None; } public long GetLong() { return 0L; } public string GetString() { return ""; } public void SetBoolean(bool val) { } public void SetDouble(double val) { } public void SetInt(int val) { } public void SetJsonType(JsonType type) { } public void SetLong(long val) { } public void SetString(string val) { } public string ToJson() { return ""; } public void ToJson(JsonWriter writer) { } int IList.Add(object value) { return 0; } void IList.Clear() { } bool IList.Contains(object value) { return false; } int IList.IndexOf(object value) { return -1; } void IList.Insert(int i, object v) { } void IList.Remove(object value) { } void IList.RemoveAt(int index) { } void ICollection.CopyTo(Array array, int index) { } IEnumerator IEnumerable.GetEnumerator() { return null; } void IDictionary.Add(object k, object v) { } void IDictionary.Clear() { } bool IDictionary.Contains(object key) { return false; } void IDictionary.Remove(object key) { } IDictionaryEnumerator IDictionary.GetEnumerator() { return null; } IDictionaryEnumerator IOrderedDictionary.GetEnumerator() { return null; } void IOrderedDictionary.Insert(int i, object k, object v) { } void IOrderedDictionary.RemoveAt(int i) { } } internal enum JsonToken { None, ObjectStart, PropertyName, ObjectEnd, ArrayStart, ArrayEnd, Int, Long, Double, String, Boolean, Null } internal class JsonReader { private static IDictionary> parse_table; private Stack automaton_stack; private int current_input; private int current_symbol; private bool end_of_json; private bool end_of_input; private Lexer lexer; private bool parser_in_string; private bool parser_return; private bool read_started; private TextReader reader; private bool reader_is_owned; private bool skip_non_members; private object token_value; private JsonToken token; public bool AllowComments { get { return lexer.AllowComments; } set { lexer.AllowComments = value; } } public bool AllowSingleQuotedStrings { get { return lexer.AllowSingleQuotedStrings; } set { lexer.AllowSingleQuotedStrings = value; } } public bool SkipNonMembers { get { return skip_non_members; } set { skip_non_members = value; } } public bool EndOfInput => end_of_input; public bool EndOfJson => end_of_json; public JsonToken Token => token; public object Value => token_value; static JsonReader() { PopulateParseTable(); } public JsonReader(string json_text) : this(new StringReader(json_text), owned: true) { } public JsonReader(TextReader reader) : this(reader, owned: false) { } private JsonReader(TextReader reader, bool owned) { if (reader == null) { throw new ArgumentNullException("reader"); } parser_in_string = false; parser_return = false; read_started = false; automaton_stack = new Stack(); automaton_stack.Push(65553); automaton_stack.Push(65543); lexer = new Lexer(reader); end_of_input = false; end_of_json = false; skip_non_members = true; this.reader = reader; reader_is_owned = owned; } private static void PopulateParseTable() { parse_table = new Dictionary>(); TableAddRow(ParserToken.Array); TableAddCol(ParserToken.Array, 91, 91, 65549); TableAddRow(ParserToken.ArrayPrime); TableAddCol(ParserToken.ArrayPrime, 34, 65550, 65551, 93); TableAddCol(ParserToken.ArrayPrime, 91, 65550, 65551, 93); TableAddCol(ParserToken.ArrayPrime, 93, 93); TableAddCol(ParserToken.ArrayPrime, 123, 65550, 65551, 93); TableAddCol(ParserToken.ArrayPrime, 65537, 65550, 65551, 93); TableAddCol(ParserToken.ArrayPrime, 65538, 65550, 65551, 93); TableAddCol(ParserToken.ArrayPrime, 65539, 65550, 65551, 93); TableAddCol(ParserToken.ArrayPrime, 65540, 65550, 65551, 93); TableAddRow(ParserToken.Object); TableAddCol(ParserToken.Object, 123, 123, 65545); TableAddRow(ParserToken.ObjectPrime); TableAddCol(ParserToken.ObjectPrime, 34, 65546, 65547, 125); TableAddCol(ParserToken.ObjectPrime, 125, 125); TableAddRow(ParserToken.Pair); TableAddCol(ParserToken.Pair, 34, 65552, 58, 65550); TableAddRow(ParserToken.PairRest); TableAddCol(ParserToken.PairRest, 44, 44, 65546, 65547); TableAddCol(ParserToken.PairRest, 125, 65554); TableAddRow(ParserToken.String); TableAddCol(ParserToken.String, 34, 34, 65541, 34); TableAddRow(ParserToken.Text); TableAddCol(ParserToken.Text, 91, 65548); TableAddCol(ParserToken.Text, 123, 65544); TableAddRow(ParserToken.Value); TableAddCol(ParserToken.Value, 34, 65552); TableAddCol(ParserToken.Value, 91, 65548); TableAddCol(ParserToken.Value, 123, 65544); TableAddCol(ParserToken.Value, 65537, 65537); TableAddCol(ParserToken.Value, 65538, 65538); TableAddCol(ParserToken.Value, 65539, 65539); TableAddCol(ParserToken.Value, 65540, 65540); TableAddRow(ParserToken.ValueRest); TableAddCol(ParserToken.ValueRest, 44, 44, 65550, 65551); TableAddCol(ParserToken.ValueRest, 93, 65554); } private static void TableAddCol(ParserToken row, int col, params int[] symbols) { parse_table[(int)row].Add(col, symbols); } private static void TableAddRow(ParserToken rule) { parse_table.Add((int)rule, new Dictionary()); } private void ProcessNumber(string number) { int result2; long result3; ulong result4; if ((number.IndexOf('.') != -1 || number.IndexOf('e') != -1 || number.IndexOf('E') != -1) && double.TryParse(number, out var result)) { token = JsonToken.Double; token_value = result; } else if (int.TryParse(number, out result2)) { token = JsonToken.Int; token_value = result2; } else if (long.TryParse(number, out result3)) { token = JsonToken.Long; token_value = result3; } else if (ulong.TryParse(number, out result4)) { token = JsonToken.Long; token_value = result4; } else { token = JsonToken.Int; token_value = 0; } } private void ProcessSymbol() { if (current_symbol == 91) { token = JsonToken.ArrayStart; parser_return = true; } else if (current_symbol == 93) { token = JsonToken.ArrayEnd; parser_return = true; } else if (current_symbol == 123) { token = JsonToken.ObjectStart; parser_return = true; } else if (current_symbol == 125) { token = JsonToken.ObjectEnd; parser_return = true; } else if (current_symbol == 34) { if (parser_in_string) { parser_in_string = false; parser_return = true; return; } if (token == JsonToken.None) { token = JsonToken.String; } parser_in_string = true; } else if (current_symbol == 65541) { token_value = lexer.StringValue; } else if (current_symbol == 65539) { token = JsonToken.Boolean; token_value = false; parser_return = true; } else if (current_symbol == 65540) { token = JsonToken.Null; parser_return = true; } else if (current_symbol == 65537) { ProcessNumber(lexer.StringValue); parser_return = true; } else if (current_symbol == 65546) { token = JsonToken.PropertyName; } else if (current_symbol == 65538) { token = JsonToken.Boolean; token_value = true; parser_return = true; } } private bool ReadToken() { if (end_of_input) { return false; } lexer.NextToken(); if (lexer.EndOfInput) { Close(); return false; } current_input = lexer.Token; return true; } public void Close() { if (!end_of_input) { end_of_input = true; end_of_json = true; if (reader_is_owned) { reader.Close(); } reader = null; } } public bool Read() { if (end_of_input) { return false; } if (end_of_json) { end_of_json = false; automaton_stack.Clear(); automaton_stack.Push(65553); automaton_stack.Push(65543); } parser_in_string = false; parser_return = false; token = JsonToken.None; token_value = null; if (!read_started) { read_started = true; if (!ReadToken()) { return false; } } while (true) { if (parser_return) { if (automaton_stack.Peek() == 65553) { end_of_json = true; } return true; } current_symbol = automaton_stack.Pop(); ProcessSymbol(); if (current_symbol == current_input) { if (!ReadToken()) { break; } continue; } int[] array; try { array = parse_table[current_symbol][current_input]; } catch (KeyNotFoundException inner_exception) { throw new JsonException((ParserToken)current_input, inner_exception); } if (array[0] != 65554) { for (int num = array.Length - 1; num >= 0; num--) { automaton_stack.Push(array[num]); } } } if (automaton_stack.Peek() != 65553) { throw new JsonException("Input doesn't evaluate to proper JSON text"); } if (parser_return) { return true; } return false; } } internal enum Condition { InArray, InObject, NotAProperty, Property, Value } internal class WriterContext { public int Count; public bool InArray; public bool InObject; public bool ExpectingValue; public int Padding; } internal class JsonWriter { private static NumberFormatInfo number_format; private WriterContext context; private Stack ctx_stack; private bool has_reached_end; private char[] hex_seq; private int indentation; private int indent_value; private StringBuilder inst_string_builder; private bool pretty_print; private bool validate; private TextWriter writer; public int IndentValue { get { return indent_value; } set { indentation = indentation / indent_value * value; indent_value = value; } } public bool PrettyPrint { get { return pretty_print; } set { pretty_print = value; } } public TextWriter TextWriter => writer; public bool Validate { get { return validate; } set { validate = value; } } static JsonWriter() { number_format = NumberFormatInfo.InvariantInfo; } public JsonWriter() { inst_string_builder = new StringBuilder(); writer = new StringWriter(inst_string_builder); Init(); } public JsonWriter(StringBuilder sb) : this(new StringWriter(sb)) { } public JsonWriter(TextWriter writer) { if (writer == null) { throw new ArgumentNullException("writer"); } this.writer = writer; Init(); } private void DoValidation(Condition cond) { if (!context.ExpectingValue) { context.Count++; } if (!validate) { return; } if (has_reached_end) { throw new JsonException("A complete JSON symbol has already been written"); } switch (cond) { case Condition.InArray: if (!context.InArray) { throw new JsonException("Can't close an array here"); } break; case Condition.InObject: if (!context.InObject || context.ExpectingValue) { throw new JsonException("Can't close an object here"); } break; case Condition.NotAProperty: if (context.InObject && !context.ExpectingValue) { throw new JsonException("Expected a property"); } break; case Condition.Property: if (!context.InObject || context.ExpectingValue) { throw new JsonException("Can't add a property here"); } break; case Condition.Value: if (!context.InArray && (!context.InObject || !context.ExpectingValue)) { throw new JsonException("Can't add a value here"); } break; } } private void Init() { has_reached_end = false; hex_seq = new char[4]; indentation = 0; indent_value = 4; pretty_print = false; validate = true; ctx_stack = new Stack(); context = new WriterContext(); ctx_stack.Push(context); } private static void IntToHex(int n, char[] hex) { for (int i = 0; i < 4; i++) { int num = n % 16; if (num < 10) { hex[3 - i] = (char)(48 + num); } else { hex[3 - i] = (char)(65 + (num - 10)); } n >>= 4; } } private void Indent() { if (pretty_print) { indentation += indent_value; } } private void Put(string str) { if (pretty_print && !context.ExpectingValue) { for (int i = 0; i < indentation; i++) { writer.Write(' '); } } writer.Write(str); } private void PutNewline() { PutNewline(add_comma: true); } private void PutNewline(bool add_comma) { if (add_comma && !context.ExpectingValue && context.Count > 1) { writer.Write(','); } if (pretty_print && !context.ExpectingValue) { writer.Write('\n'); } } private void PutString(string str) { Put(string.Empty); writer.Write('"'); int length = str.Length; for (int i = 0; i < length; i++) { switch (str[i]) { case '\n': writer.Write("\\n"); continue; case '\r': writer.Write("\\r"); continue; case '\t': writer.Write("\\t"); continue; case '"': case '\\': writer.Write('\\'); writer.Write(str[i]); continue; case '\f': writer.Write("\\f"); continue; case '\b': writer.Write("\\b"); continue; } if (str[i] >= ' ' && str[i] <= '~') { writer.Write(str[i]); continue; } IntToHex(str[i], hex_seq); writer.Write("\\u"); writer.Write(hex_seq); } writer.Write('"'); } private void Unindent() { if (pretty_print) { indentation -= indent_value; } } public override string ToString() { if (inst_string_builder == null) { return string.Empty; } return inst_string_builder.ToString(); } public void Reset() { has_reached_end = false; ctx_stack.Clear(); context = new WriterContext(); ctx_stack.Push(context); if (inst_string_builder != null) { inst_string_builder.Remove(0, inst_string_builder.Length); } } public void Write(bool boolean) { DoValidation(Condition.Value); PutNewline(); Put(boolean ? "true" : "false"); context.ExpectingValue = false; } public void Write(decimal number) { DoValidation(Condition.Value); PutNewline(); Put(Convert.ToString(number, number_format)); context.ExpectingValue = false; } public void Write(double number) { DoValidation(Condition.Value); PutNewline(); string text = Convert.ToString(number, number_format); Put(text); if (text.IndexOf('.') == -1 && text.IndexOf('E') == -1) { writer.Write(".0"); } context.ExpectingValue = false; } public void Write(int number) { DoValidation(Condition.Value); PutNewline(); Put(Convert.ToString(number, number_format)); context.ExpectingValue = false; } public void Write(long number) { DoValidation(Condition.Value); PutNewline(); Put(Convert.ToString(number, number_format)); context.ExpectingValue = false; } public void Write(string str) { DoValidation(Condition.Value); PutNewline(); if (str == null) { Put("null"); } else { PutString(str); } context.ExpectingValue = false; } [CLSCompliant(false)] public void Write(ulong number) { DoValidation(Condition.Value); PutNewline(); Put(Convert.ToString(number, number_format)); context.ExpectingValue = false; } public void WriteArrayEnd() { DoValidation(Condition.InArray); PutNewline(add_comma: false); ctx_stack.Pop(); if (ctx_stack.Count == 1) { has_reached_end = true; } else { context = ctx_stack.Peek(); context.ExpectingValue = false; } Unindent(); Put("]"); } public void WriteArrayStart() { DoValidation(Condition.NotAProperty); PutNewline(); Put("["); context = new WriterContext(); context.InArray = true; ctx_stack.Push(context); Indent(); } public void WriteObjectEnd() { DoValidation(Condition.InObject); PutNewline(add_comma: false); ctx_stack.Pop(); if (ctx_stack.Count == 1) { has_reached_end = true; } else { context = ctx_stack.Peek(); context.ExpectingValue = false; } Unindent(); Put("}"); } public void WriteObjectStart() { DoValidation(Condition.NotAProperty); PutNewline(); Put("{"); context = new WriterContext(); context.InObject = true; ctx_stack.Push(context); Indent(); } public void WritePropertyName(string property_name) { DoValidation(Condition.Property); PutNewline(); PutString(property_name); if (pretty_print) { if (property_name.Length > context.Padding) { context.Padding = property_name.Length; } for (int num = context.Padding - property_name.Length; num >= 0; num--) { writer.Write(' '); } writer.Write(": "); } else { writer.Write(':'); } context.ExpectingValue = true; } } internal class FsmContext { public bool Return; public int NextState; public Lexer L; public int StateStack; } internal class Lexer { private delegate bool StateHandler(FsmContext ctx); private static int[] fsm_return_table; private static StateHandler[] fsm_handler_table; private bool allow_comments; private bool allow_single_quoted_strings; private bool end_of_input; private FsmContext fsm_context; private int input_buffer; private int input_char; private TextReader reader; private int state; private StringBuilder string_buffer; private string string_value; private int token; private int unichar; public bool AllowComments { get { return allow_comments; } set { allow_comments = value; } } public bool AllowSingleQuotedStrings { get { return allow_single_quoted_strings; } set { allow_single_quoted_strings = value; } } public bool EndOfInput => end_of_input; public int Token => token; public string StringValue => string_value; static Lexer() { PopulateFsmTables(); } public Lexer(TextReader reader) { allow_comments = true; allow_single_quoted_strings = true; input_buffer = 0; string_buffer = new StringBuilder(128); state = 1; end_of_input = false; this.reader = reader; fsm_context = new FsmContext(); fsm_context.L = this; } private static int HexValue(int digit) { switch (digit) { case 65: case 97: return 10; case 66: case 98: return 11; case 67: case 99: return 12; case 68: case 100: return 13; case 69: case 101: return 14; case 70: case 102: return 15; default: return digit - 48; } } private static void PopulateFsmTables() { fsm_handler_table = new StateHandler[28] { State1, State2, State3, State4, State5, State6, State7, State8, State9, State10, State11, State12, State13, State14, State15, State16, State17, State18, State19, State20, State21, State22, State23, State24, State25, State26, State27, State28 }; fsm_return_table = new int[28] { 65542, 0, 65537, 65537, 0, 65537, 0, 65537, 0, 0, 65538, 0, 0, 0, 65539, 0, 0, 65540, 65541, 65542, 0, 0, 65541, 65542, 0, 0, 0, 0 }; } private static char ProcessEscChar(int esc_char) { switch (esc_char) { case 34: case 39: case 47: case 92: return Convert.ToChar(esc_char); case 110: return '\n'; case 116: return '\t'; case 114: return '\r'; case 98: return '\b'; case 102: return '\f'; default: return '?'; } } private static bool State1(FsmContext ctx) { while (ctx.L.GetChar()) { if (ctx.L.input_char == 32 || (ctx.L.input_char >= 9 && ctx.L.input_char <= 13)) { continue; } if (ctx.L.input_char >= 49 && ctx.L.input_char <= 57) { ctx.L.string_buffer.Append((char)ctx.L.input_char); ctx.NextState = 3; return true; } switch (ctx.L.input_char) { case 34: ctx.NextState = 19; ctx.Return = true; return true; case 44: case 58: case 91: case 93: case 123: case 125: ctx.NextState = 1; ctx.Return = true; return true; case 45: ctx.L.string_buffer.Append((char)ctx.L.input_char); ctx.NextState = 2; return true; case 48: ctx.L.string_buffer.Append((char)ctx.L.input_char); ctx.NextState = 4; return true; case 102: ctx.NextState = 12; return true; case 110: ctx.NextState = 16; return true; case 116: ctx.NextState = 9; return true; case 39: if (!ctx.L.allow_single_quoted_strings) { return false; } ctx.L.input_char = 34; ctx.NextState = 23; ctx.Return = true; return true; case 47: if (!ctx.L.allow_comments) { return false; } ctx.NextState = 25; return true; default: return false; } } return true; } private static bool State2(FsmContext ctx) { ctx.L.GetChar(); if (ctx.L.input_char >= 49 && ctx.L.input_char <= 57) { ctx.L.string_buffer.Append((char)ctx.L.input_char); ctx.NextState = 3; return true; } int num = ctx.L.input_char; if (num == 48) { ctx.L.string_buffer.Append((char)ctx.L.input_char); ctx.NextState = 4; return true; } return false; } private static bool State3(FsmContext ctx) { while (ctx.L.GetChar()) { if (ctx.L.input_char >= 48 && ctx.L.input_char <= 57) { ctx.L.string_buffer.Append((char)ctx.L.input_char); continue; } if (ctx.L.input_char == 32 || (ctx.L.input_char >= 9 && ctx.L.input_char <= 13)) { ctx.Return = true; ctx.NextState = 1; return true; } switch (ctx.L.input_char) { case 44: case 93: case 125: ctx.L.UngetChar(); ctx.Return = true; ctx.NextState = 1; return true; case 46: ctx.L.string_buffer.Append((char)ctx.L.input_char); ctx.NextState = 5; return true; case 69: case 101: ctx.L.string_buffer.Append((char)ctx.L.input_char); ctx.NextState = 7; return true; default: return false; } } return true; } private static bool State4(FsmContext ctx) { ctx.L.GetChar(); if (ctx.L.input_char == 32 || (ctx.L.input_char >= 9 && ctx.L.input_char <= 13)) { ctx.Return = true; ctx.NextState = 1; return true; } switch (ctx.L.input_char) { case 44: case 93: case 125: ctx.L.UngetChar(); ctx.Return = true; ctx.NextState = 1; return true; case 46: ctx.L.string_buffer.Append((char)ctx.L.input_char); ctx.NextState = 5; return true; case 69: case 101: ctx.L.string_buffer.Append((char)ctx.L.input_char); ctx.NextState = 7; return true; default: return false; } } private static bool State5(FsmContext ctx) { ctx.L.GetChar(); if (ctx.L.input_char >= 48 && ctx.L.input_char <= 57) { ctx.L.string_buffer.Append((char)ctx.L.input_char); ctx.NextState = 6; return true; } return false; } private static bool State6(FsmContext ctx) { while (ctx.L.GetChar()) { if (ctx.L.input_char >= 48 && ctx.L.input_char <= 57) { ctx.L.string_buffer.Append((char)ctx.L.input_char); continue; } if (ctx.L.input_char == 32 || (ctx.L.input_char >= 9 && ctx.L.input_char <= 13)) { ctx.Return = true; ctx.NextState = 1; return true; } switch (ctx.L.input_char) { case 44: case 93: case 125: ctx.L.UngetChar(); ctx.Return = true; ctx.NextState = 1; return true; case 69: case 101: ctx.L.string_buffer.Append((char)ctx.L.input_char); ctx.NextState = 7; return true; default: return false; } } return true; } private static bool State7(FsmContext ctx) { ctx.L.GetChar(); if (ctx.L.input_char >= 48 && ctx.L.input_char <= 57) { ctx.L.string_buffer.Append((char)ctx.L.input_char); ctx.NextState = 8; return true; } switch (ctx.L.input_char) { case 43: case 45: ctx.L.string_buffer.Append((char)ctx.L.input_char); ctx.NextState = 8; return true; default: return false; } } private static bool State8(FsmContext ctx) { while (ctx.L.GetChar()) { if (ctx.L.input_char >= 48 && ctx.L.input_char <= 57) { ctx.L.string_buffer.Append((char)ctx.L.input_char); continue; } if (ctx.L.input_char == 32 || (ctx.L.input_char >= 9 && ctx.L.input_char <= 13)) { ctx.Return = true; ctx.NextState = 1; return true; } int num = ctx.L.input_char; if (num == 44 || num == 93 || num == 125) { ctx.L.UngetChar(); ctx.Return = true; ctx.NextState = 1; return true; } return false; } return true; } private static bool State9(FsmContext ctx) { ctx.L.GetChar(); int num = ctx.L.input_char; if (num == 114) { ctx.NextState = 10; return true; } return false; } private static bool State10(FsmContext ctx) { ctx.L.GetChar(); int num = ctx.L.input_char; if (num == 117) { ctx.NextState = 11; return true; } return false; } private static bool State11(FsmContext ctx) { ctx.L.GetChar(); int num = ctx.L.input_char; if (num == 101) { ctx.Return = true; ctx.NextState = 1; return true; } return false; } private static bool State12(FsmContext ctx) { ctx.L.GetChar(); int num = ctx.L.input_char; if (num == 97) { ctx.NextState = 13; return true; } return false; } private static bool State13(FsmContext ctx) { ctx.L.GetChar(); int num = ctx.L.input_char; if (num == 108) { ctx.NextState = 14; return true; } return false; } private static bool State14(FsmContext ctx) { ctx.L.GetChar(); int num = ctx.L.input_char; if (num == 115) { ctx.NextState = 15; return true; } return false; } private static bool State15(FsmContext ctx) { ctx.L.GetChar(); int num = ctx.L.input_char; if (num == 101) { ctx.Return = true; ctx.NextState = 1; return true; } return false; } private static bool State16(FsmContext ctx) { ctx.L.GetChar(); int num = ctx.L.input_char; if (num == 117) { ctx.NextState = 17; return true; } return false; } private static bool State17(FsmContext ctx) { ctx.L.GetChar(); int num = ctx.L.input_char; if (num == 108) { ctx.NextState = 18; return true; } return false; } private static bool State18(FsmContext ctx) { ctx.L.GetChar(); int num = ctx.L.input_char; if (num == 108) { ctx.Return = true; ctx.NextState = 1; return true; } return false; } private static bool State19(FsmContext ctx) { while (ctx.L.GetChar()) { switch (ctx.L.input_char) { case 34: ctx.L.UngetChar(); ctx.Return = true; ctx.NextState = 20; return true; case 92: ctx.StateStack = 19; ctx.NextState = 21; return true; } ctx.L.string_buffer.Append((char)ctx.L.input_char); } return true; } private static bool State20(FsmContext ctx) { ctx.L.GetChar(); int num = ctx.L.input_char; if (num == 34) { ctx.Return = true; ctx.NextState = 1; return true; } return false; } private static bool State21(FsmContext ctx) { ctx.L.GetChar(); switch (ctx.L.input_char) { case 117: ctx.NextState = 22; return true; case 34: case 39: case 47: case 92: case 98: case 102: case 110: case 114: case 116: ctx.L.string_buffer.Append(ProcessEscChar(ctx.L.input_char)); ctx.NextState = ctx.StateStack; return true; default: return false; } } private static bool State22(FsmContext ctx) { int num = 0; int num2 = 4096; ctx.L.unichar = 0; while (ctx.L.GetChar()) { if ((ctx.L.input_char >= 48 && ctx.L.input_char <= 57) || (ctx.L.input_char >= 65 && ctx.L.input_char <= 70) || (ctx.L.input_char >= 97 && ctx.L.input_char <= 102)) { ctx.L.unichar += HexValue(ctx.L.input_char) * num2; num++; num2 /= 16; if (num == 4) { ctx.L.string_buffer.Append(Convert.ToChar(ctx.L.unichar)); ctx.NextState = ctx.StateStack; return true; } continue; } return false; } return true; } private static bool State23(FsmContext ctx) { while (ctx.L.GetChar()) { switch (ctx.L.input_char) { case 39: ctx.L.UngetChar(); ctx.Return = true; ctx.NextState = 24; return true; case 92: ctx.StateStack = 23; ctx.NextState = 21; return true; } ctx.L.string_buffer.Append((char)ctx.L.input_char); } return true; } private static bool State24(FsmContext ctx) { ctx.L.GetChar(); int num = ctx.L.input_char; if (num == 39) { ctx.L.input_char = 34; ctx.Return = true; ctx.NextState = 1; return true; } return false; } private static bool State25(FsmContext ctx) { ctx.L.GetChar(); switch (ctx.L.input_char) { case 42: ctx.NextState = 27; return true; case 47: ctx.NextState = 26; return true; default: return false; } } private static bool State26(FsmContext ctx) { while (ctx.L.GetChar()) { if (ctx.L.input_char == 10) { ctx.NextState = 1; return true; } } return true; } private static bool State27(FsmContext ctx) { while (ctx.L.GetChar()) { if (ctx.L.input_char == 42) { ctx.NextState = 28; return true; } } return true; } private static bool State28(FsmContext ctx) { while (ctx.L.GetChar()) { if (ctx.L.input_char != 42) { if (ctx.L.input_char == 47) { ctx.NextState = 1; return true; } ctx.NextState = 27; return true; } } return true; } private bool GetChar() { if ((input_char = NextChar()) != -1) { return true; } end_of_input = true; return false; } private int NextChar() { if (input_buffer != 0) { int result = input_buffer; input_buffer = 0; return result; } return reader.Read(); } public bool NextToken() { fsm_context.Return = false; while (true) { StateHandler stateHandler = fsm_handler_table[state - 1]; if (!stateHandler(fsm_context)) { throw new JsonException(input_char); } if (end_of_input) { return false; } if (fsm_context.Return) { break; } state = fsm_context.NextState; } string_value = string_buffer.ToString(); string_buffer.Remove(0, string_buffer.Length); token = fsm_return_table[state - 1]; if (token == 65542) { token = input_char; } state = fsm_context.NextState; return true; } private void UngetChar() { input_buffer = input_char; } } internal enum ParserToken { None = 65536, Number, True, False, Null, CharSeq, Char, Text, Object, ObjectPrime, Pair, PairRest, Array, ArrayPrime, Value, ValueRest, String, End, Epsilon } }