using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.Audio; using UnityEngine.Rendering; using UnityEngine.UI; using VikingRail.Core; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("VikingRail")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Valheim railways with side-rail structural support, dirt trackbeds, portable vehicles, passenger seating, movement sounds and track snapping.")] [assembly: AssemblyFileVersion("0.46.1.0")] [assembly: AssemblyInformationalVersion("0.46.1")] [assembly: AssemblyProduct("VikingRail")] [assembly: AssemblyTitle("VikingRail")] [assembly: AssemblyVersion("0.46.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace VikingRail { internal static class RailAudioClips { private static AudioClip? _handcart; private static AudioClip? _locomotive; private static AudioClip? _chuff; private static AudioClip? _hiss; private static AudioClip? _eitr; private static readonly MethodInfo? SetSamples = AccessTools.Method(typeof(AudioClip), "SetData", new Type[2] { typeof(float[]), typeof(int) }, (Type[])null); internal static AudioClip Chuff { get { if (!Object.op_Implicit((Object)(object)_chuff)) { return _chuff = Create("VikingRail steam chuff", RailAudioSynthesis.GenerateSteamChuff()); } return _chuff; } } internal static AudioClip Hiss { get { if (!Object.op_Implicit((Object)(object)_hiss)) { return _hiss = Create("VikingRail steam hiss", RailAudioSynthesis.GenerateSteamHiss()); } return _hiss; } } internal static AudioClip EitrHum { get { if (!Object.op_Implicit((Object)(object)_eitr)) { return _eitr = Create("VikingRail Eitr resonance", RailAudioSynthesis.GenerateEitrHum()); } return _eitr; } } internal static AudioClip Rolling(bool coal) { if (coal) { if (!Object.op_Implicit((Object)(object)_locomotive)) { return _locomotive = Create("VikingRail locomotive wheels", RailAudioSynthesis.GenerateLocomotiveRoll()); } return _locomotive; } if (!Object.op_Implicit((Object)(object)_handcart)) { return _handcart = Create("VikingRail handcart wood and wheels", RailAudioSynthesis.GenerateHandcartRoll()); } return _handcart; } private static AudioClip Create(string name, float[] samples) { AudioClip val = AudioClip.Create(name, samples.Length, 1, 22050, false); try { if (SetSamples != null && true.Equals(SetSamples.Invoke(val, new object[2] { samples, 0 }))) { return val; } throw new InvalidOperationException("Could not load generated sound samples: " + name); } catch { Object.Destroy((Object)(object)val); throw; } } internal static AudioMixerGroup? FindEffectsMixer() { GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab("Cart") : null); if (!Object.op_Implicit((Object)(object)val)) { return null; } Vagon component = val.GetComponent(); if (Object.op_Implicit((Object)(object)component) && component.m_wheelLoops != null) { ZSFX[] wheelLoops = component.m_wheelLoops; foreach (ZSFX val2 in wheelLoops) { AudioSource val3 = (Object.op_Implicit((Object)(object)val2) ? ((Component)val2).GetComponent() : null); if (Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)val3.outputAudioMixerGroup)) { return val3.outputAudioMixerGroup; } } } AudioSource[] componentsInChildren = val.GetComponentsInChildren(true); foreach (AudioSource val4 in componentsInChildren) { if (Object.op_Implicit((Object)(object)val4.outputAudioMixerGroup)) { return val4.outputAudioMixerGroup; } } return null; } internal static void Cleanup() { if (Object.op_Implicit((Object)(object)_handcart)) { Object.Destroy((Object)(object)_handcart); } if (Object.op_Implicit((Object)(object)_locomotive)) { Object.Destroy((Object)(object)_locomotive); } if (Object.op_Implicit((Object)(object)_chuff)) { Object.Destroy((Object)(object)_chuff); } if (Object.op_Implicit((Object)(object)_hiss)) { Object.Destroy((Object)(object)_hiss); } if (Object.op_Implicit((Object)(object)_eitr)) { Object.Destroy((Object)(object)_eitr); } _handcart = (_locomotive = (_chuff = (_hiss = (_eitr = null)))); } } public sealed class RailAutoDrive : MonoBehaviour, Hoverable, Interactable { internal const string PrefabName = "vr_autocontroller"; internal const string ControllerKey = "vikingrail_autodrive_controller"; private const string ControllerZdoKey = "vikingrail_autodrive_controller_zdo"; private const string EngineKey = "vikingrail_autodrive_engine"; private const string EngineZdoKey = "vikingrail_autodrive_engine_zdo"; internal static readonly Vector3 SocketOffset = new Vector3(-0.67f, 0.9f, -0.46f); internal static readonly Vector3 LocalBoundsCenter = new Vector3(0f, 0.31f, 0f); internal static readonly Vector3 LocalBoundsHalfSize = new Vector3(0.13f, 0.31f, 0.15f); private const float SocketRange = 2.5f; private static readonly HashSet Controllers = new HashSet(); private static readonly HashSet DestroyedIdentities = new HashSet(); private static ZDOMan? _trackedManager; private ZNetView _view; private Rigidbody? _body; private WearNTear? _wear; private Transform? _lever; private string _identity = ""; private bool _started; private bool _pending; private float _requestTime; private long _requestOwner; private long _requestPlayer; internal bool IsReady { get { if (_started && Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { return _identity.Length != 0; } return false; } } internal ZNetView View => _view; internal string PersistentId => _identity; internal string EngineIdentity { get { if (!IsReady) { return ""; } return _view.GetZDO().GetString("vikingrail_autodrive_engine", ""); } } internal bool IsAttached => EngineIdentity.Length != 0; internal static IEnumerable LoadedControllers => Controllers; internal RailVehicle? Engine { get { RailVehicle railVehicle = FindEngine(EngineIdentity); if (!Object.op_Implicit((Object)(object)railVehicle) || !(railVehicle.AttachedAutoDriveId == PersistentId)) { return null; } return railVehicle; } } internal static bool WasDestroyed(string identity) { if (identity.Length != 0) { return DestroyedIdentities.Contains(identity); } return false; } internal static RailAutoDrive? Find(string identity) { if (string.IsNullOrEmpty(identity)) { return null; } foreach (RailAutoDrive controller in Controllers) { if (Object.op_Implicit((Object)(object)controller) && controller.IsReady && controller.PersistentId == identity) { return controller; } } return null; } private static RailVehicle? FindEngine(string identity) { if (identity.Length == 0) { return null; } foreach (RailVehicle loadedVehicle in RailVehicle.LoadedVehicles) { if (Object.op_Implicit((Object)(object)loadedVehicle) && loadedVehicle.IsReady && loadedVehicle.SupportsAutoDrive && loadedVehicle.PersistentId == identity) { return loadedVehicle; } } return null; } private void Awake() { _view = ((Component)this).GetComponent(); _body = ((Component)this).GetComponent(); _wear = ((Component)this).GetComponent(); _lever = ((Component)this).transform.Find("visual/vr_auto_lever"); } private void Start() { if (!_started && Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { _started = true; EnsureIdentity(); EnsureDestructionTracking(); Controllers.Add(this); _view.Register("VR_AutoAttach", (Action)RequestAttachment); _view.Register("VR_AutoAttachReply", (Action)ReceiveReply); if (Object.op_Implicit((Object)(object)_wear)) { WearNTear? wear = _wear; wear.m_onDestroyed = (Action)Delegate.Combine(wear.m_onDestroyed, new Action(OnDestroyedPermanently)); } } } private void EnsureIdentity() { _identity = _view.GetZDO().GetString("vikingrail_identity", ""); if (_identity.Length == 0 && _view.IsOwner()) { _identity = Guid.NewGuid().ToString("N"); _view.GetZDO().Set("vikingrail_identity", _identity); } } private void Update() { //IL_00c7: 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_015c: Unknown result type (might be due to invalid IL or missing references) if (!_started || !Object.op_Implicit((Object)(object)_view) || !_view.IsValid()) { return; } if (_identity.Length == 0) { EnsureIdentity(); } if (_pending && Time.unscaledTime - _requestTime > 6f) { _pending = false; Tell("The controller request timed out. Check the attachment and try again."); } if (!IsReady) { return; } RailVehicle engine = Engine; if (Object.op_Implicit((Object)(object)engine) && engine.View.IsOwner()) { if (!_view.IsOwner()) { _view.ClaimOwnership(); } if (_view.IsOwner()) { _view.GetZDO().Set("vikingrail_autodrive_engine_zdo", engine.View.GetZDO().m_uid); engine.View.GetZDO().Set("vikingrail_autodrive_controller_zdo", _view.GetZDO().m_uid); } } if (_view.IsOwner() && IsAttached && DestroyedIdentities.Contains(EngineIdentity)) { ClearEngine(); } if (Object.op_Implicit((Object)(object)_lever)) { _lever.localRotation = Quaternion.Euler((Object.op_Implicit((Object)(object)engine) && engine.AutoDriveActive) ? (-28f) : 28f, 0f, 0f); } } private void LateUpdate() { if (IsReady) { RailVehicle engine = Engine; if (Object.op_Implicit((Object)(object)engine)) { Follow(engine); } } } internal void Follow(RailVehicle engine) { //IL_0045: 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_004f: 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_0087: 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_006f: 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) if (IsReady && Object.op_Implicit((Object)(object)engine) && engine.IsReady && !(engine.AttachedAutoDriveId != PersistentId) && !(EngineIdentity != engine.PersistentId)) { Vector3 val = ((Component)engine).transform.TransformPoint(SocketOffset); Quaternion rotation = ((Component)engine).transform.rotation; if (Object.op_Implicit((Object)(object)_body)) { _body.position = val; _body.rotation = rotation; } ((Component)this).transform.SetPositionAndRotation(val, rotation); } } public float GetHoverOffset() { return 0f; } public string GetHoverName() { return "Rail automatic controller"; } public string GetHoverText() { RailVehicle engine = Engine; string text = ((!IsAttached) ? "Build beside a parked steam or Eitr engine" : (Object.op_Implicit((Object)(object)engine) ? engine.AutoDriveStatus : "Waiting for the attached engine to load")); string text2 = ((!IsAttached) ? "Attach controller" : ((Object.op_Implicit((Object)(object)engine) && engine.AutoDriveActive) ? "Stop automatic travel" : "Start automatic travel")); return Localization.instance.Localize(GetHoverName() + "\n" + text + "\n[$KEY_Use] " + text2 + (IsAttached ? "\n[$KEY_AltPlace + $KEY_Use] Detach when parked" : "\nRemove with the Hammer to recover its materials")); } public bool UseItem(Humanoid user, ItemData item) { return false; } public bool Interact(Humanoid user, bool hold, bool alt) { //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) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_014a: 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_0168: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) if (hold || !IsReady || _pending) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val != (Object)(object)Player.m_localPlayer || ((Character)val).IsDead() || ((Character)val).IsTeleporting()) { return false; } if (Vector3.Distance(((Component)val).transform.position, ((Component)this).transform.position) > 4f || !PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return false; } RailVehicle railVehicle = (IsAttached ? FindEngine(EngineIdentity) : ClosestParkedEngine()); if (!Object.op_Implicit((Object)(object)railVehicle)) { Tell(IsAttached ? "Approach the linked engine so it is loaded before using the controller." : "Build the controller within 2.5 m of a parked steam or Eitr engine's left controls."); return false; } if (IsAttached && !alt) { if (railVehicle.AttachedAutoDriveId != PersistentId) { Tell("This controller's engine link is unavailable. Detach it before attaching again."); return false; } return railVehicle.RequestAutoDriveToggle(val); } if (!IsAttached && alt) { Tell("Remove the detached controller with the Hammer to recover its materials."); return false; } if (((Character)val).IsAttached() || val.GetDoodadController() != null) { Tell("Dismount before attaching or detaching the controller."); return false; } if (!railVehicle.AutoDriveAttachmentChangesAllowed) { Tell("Stop automatic travel, park the engine and dismount before changing its controller."); return false; } if (!NearSocket(railVehicle, val) || !PrivateArea.CheckAccess(((Component)railVehicle).transform.position, 0f, true, false) || !PrivateArea.CheckAccess(((Component)railVehicle).transform.TransformPoint(SocketOffset), 0f, true, false)) { return false; } if (!_view.HasOwner()) { Tell("Waiting for the controller's network owner. Try again shortly."); return false; } _pending = true; _requestTime = Time.unscaledTime; _requestOwner = _view.GetZDO().GetOwner(); _requestPlayer = val.GetPlayerID(); _view.InvokeRPC("VR_AutoAttach", new object[3] { _requestPlayer, railVehicle.View.GetZDO().m_uid, IsAttached }); return true; } private RailVehicle? ClosestParkedEngine() { //IL_004f: 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_005f: Unknown result type (might be due to invalid IL or missing references) RailVehicle result = null; float num = 2.5f; foreach (RailVehicle loadedVehicle in RailVehicle.LoadedVehicles) { if (Object.op_Implicit((Object)(object)loadedVehicle) && loadedVehicle.IsReady && loadedVehicle.SupportsAutoDrive && loadedVehicle.AutoDriveAttachmentChangesAllowed && loadedVehicle.AttachedAutoDriveId.Length == 0) { float num2 = Vector3.Distance(((Component)this).transform.position, ((Component)loadedVehicle).transform.TransformPoint(SocketOffset)); if (!(num2 > num)) { num = num2; result = loadedVehicle; } } } return result; } private bool NearSocket(RailVehicle engine, Player player) { //IL_0006: 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_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_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) Vector3 val = ((Component)engine).transform.TransformPoint(SocketOffset); if (Vector3.Distance(((Component)this).transform.position, val) <= 2.5f) { return Vector3.Distance(((Component)player).transform.position, val) <= 2.5f; } return false; } private void RequestAttachment(long sender, long playerId, ZDOID target, bool detach) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (IsReady && _view.IsOwner()) { string message; bool flag = TryAttachment(sender, playerId, target, detach, out message); _view.InvokeRPC(sender, "VR_AutoAttachReply", new object[2] { flag, message }); } } private bool TryAttachment(long sender, long playerId, ZDOID target, bool detach, out string message) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0156: 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_02bd: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) message = "The controller is unavailable. Try again shortly."; if (!IsReady || !_view.IsOwner() || !RailSettings.Ready) { return false; } Player player = Player.GetPlayer(playerId); if (!Object.op_Implicit((Object)(object)player) || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || ((Character)player).IsAttached() || player.GetDoodadController() != null || ((Character)player).GetOwner() != sender || Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position) > 4f) { message = "Stand on foot beside the controller before changing its attachment."; return false; } if (!RailWardAccess.Allows(((Component)this).transform.position, playerId)) { message = "A ward prevents changing this controller."; return false; } RailVehicle railVehicle = null; foreach (RailVehicle loadedVehicle in RailVehicle.LoadedVehicles) { if (Object.op_Implicit((Object)(object)loadedVehicle) && loadedVehicle.IsReady && loadedVehicle.SupportsAutoDrive && loadedVehicle.View.GetZDO().m_uid == target) { railVehicle = loadedVehicle; break; } } if (!Object.op_Implicit((Object)(object)railVehicle) || !NearSocket(railVehicle, player)) { message = "The controller and player must be beside a loaded steam or Eitr engine's left controls."; return false; } if (!railVehicle.AutoDriveAttachmentChangesAllowed) { message = "Stop automatic travel, park the engine and dismount before changing its controller."; return false; } if (!RailWardAccess.Allows(((Component)railVehicle).transform.position, playerId) || !RailWardAccess.Allows(((Component)railVehicle).transform.TransformPoint(SocketOffset), playerId)) { message = "A ward protects the engine's controller socket."; return false; } bool num; if (!detach) { if (IsAttached) { goto IL_01a9; } num = railVehicle.AttachedAutoDriveId.Length != 0; } else { num = EngineIdentity != railVehicle.PersistentId; } if (!num) { if (!detach && !HasClearance(railVehicle)) { message = "Clear the left control socket of people and other objects before attaching."; return false; } if (!detach || railVehicle.AttachedAutoDriveId == PersistentId) { railVehicle.View.ClaimOwnership(); if (!railVehicle.View.IsOwner() || !railVehicle.AutoDriveAttachmentChangesAllowed || (!detach && railVehicle.AttachedAutoDriveId.Length != 0)) { message = "The engine became unavailable. Try again once it is parked."; return false; } railVehicle.StopAutomaticDrive(""); railVehicle.SetAutoDriveId(detach ? "" : PersistentId); railVehicle.View.GetZDO().Set("vikingrail_autodrive_controller_zdo", detach ? ZDOID.None : _view.GetZDO().m_uid); } _view.GetZDO().Set("vikingrail_autodrive_engine", detach ? "" : railVehicle.PersistentId); _view.GetZDO().Set("vikingrail_autodrive_engine_zdo", detach ? ZDOID.None : railVehicle.View.GetZDO().m_uid); if (!detach) { Follow(railVehicle); } ZDOMan.instance.ForceSendZDO(sender, railVehicle.View.GetZDO().m_uid); ZDOMan.instance.ForceSendZDO(sender, _view.GetZDO().m_uid); message = (detach ? "Controller detached. Remove it with the Hammer to recover its materials." : "Automatic controller attached. Fuel the engine, then use the lever to send it forward."); return true; } goto IL_01a9; IL_01a9: message = "The controller attachment changed. Check both pieces and try again."; return false; } private bool HasClearance(RailVehicle engine) { //IL_0006: 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_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_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) //IL_002e: 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) Collider[] array = Physics.OverlapBox(((Component)engine).transform.TransformPoint(SocketOffset + LocalBoundsCenter), LocalBoundsHalfSize - Vector3.one * 0.002f, ((Component)engine).transform.rotation, -1, (QueryTriggerInteraction)1); foreach (Collider val in array) { if (!((Object)(object)((Component)val).GetComponentInParent() == (Object)(object)this) && !((Object)(object)((Component)val).GetComponentInParent() == (Object)(object)engine)) { return false; } } return true; } private void ReceiveReply(long sender, bool success, string message) { if (_pending && sender == _requestOwner) { _pending = false; if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerID() == _requestPlayer) { Tell(message); } } } internal void DetachFromDestroyedEngine(RailVehicle engine) { //IL_0098: Unknown result type (might be due to invalid IL or missing references) if (!IsReady || !Object.op_Implicit((Object)(object)engine) || !engine.IsReady || !engine.View.IsOwner() || EngineIdentity != engine.PersistentId) { return; } _view.ClaimOwnership(); if (_view.IsOwner()) { Follow(engine); ClearEngine(); if (engine.AttachedAutoDriveId == PersistentId) { engine.StopAutomaticDrive(""); engine.SetAutoDriveId(""); engine.View.GetZDO().Set("vikingrail_autodrive_controller_zdo", ZDOID.None); } } } private void ClearEngine() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) _view.GetZDO().Set("vikingrail_autodrive_engine", ""); _view.GetZDO().Set("vikingrail_autodrive_engine_zdo", ZDOID.None); } private void OnDestroyedPermanently() { if (IsReady && _view.IsOwner()) { TrackDestroyed(_view.GetZDO()); } } private void OnDestroy() { if (Object.op_Implicit((Object)(object)_wear)) { WearNTear? wear = _wear; wear.m_onDestroyed = (Action)Delegate.Remove(wear.m_onDestroyed, new Action(OnDestroyedPermanently)); } Controllers.Remove(this); _started = false; } internal static void EnsureDestructionTracking() { if (_trackedManager != ZDOMan.instance && ZDOMan.instance != null) { if (_trackedManager != null) { ZDOMan? trackedManager = _trackedManager; trackedManager.m_onZDODestroyed = (Action)Delegate.Remove(trackedManager.m_onZDODestroyed, new Action(TrackDestroyed)); } _trackedManager = ZDOMan.instance; DestroyedIdentities.Clear(); ZDOMan? trackedManager2 = _trackedManager; trackedManager2.m_onZDODestroyed = (Action)Delegate.Combine(trackedManager2.m_onZDODestroyed, new Action(TrackDestroyed)); } } internal static void Cleanup() { if (_trackedManager != null) { ZDOMan? trackedManager = _trackedManager; trackedManager.m_onZDODestroyed = (Action)Delegate.Remove(trackedManager.m_onZDODestroyed, new Action(TrackDestroyed)); } _trackedManager = null; DestroyedIdentities.Clear(); Controllers.Clear(); } private static void TrackDestroyed(ZDO destroyed) { try { RepairDestroyedLinks(destroyed); } catch (Exception error) { RailPlugin.Error(error); } } private static void RepairDestroyedLinks(ZDO destroyed) { //IL_00e7: 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_01f8: Unknown result type (might be due to invalid IL or missing references) if (destroyed == null) { return; } string text = destroyed.GetString("vikingrail_identity", ""); if (text.Length == 0) { return; } DestroyedIdentities.Add(text); RailAutoDrive[] array = Controllers.ToArray(); foreach (RailAutoDrive railAutoDrive in array) { if (Object.op_Implicit((Object)(object)railAutoDrive) && railAutoDrive.IsReady && railAutoDrive._view.IsOwner() && !(railAutoDrive.EngineIdentity != text)) { railAutoDrive.ClearEngine(); } } string text2 = destroyed.GetString("vikingrail_autodrive_engine", ""); RailVehicle railVehicle = FindEngine(text2); if (Object.op_Implicit((Object)(object)railVehicle) && railVehicle.View.IsOwner() && railVehicle.AttachedAutoDriveId == text) { railVehicle.SetAutoDriveId(""); railVehicle.StopAutomaticDrive("The automatic controller was destroyed."); railVehicle.View.GetZDO().Set("vikingrail_autodrive_controller_zdo", ZDOID.None); } if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer() || ZDOMan.instance == null) { return; } string text3 = destroyed.GetString("vikingrail_autodrive_controller", ""); if (text3.Length != 0) { ZDO val = FindSavedLink(destroyed, "vikingrail_autodrive_controller_zdo", text3, "vikingrail_autodrive_engine", text); if (val != null) { val.SetOwner(ZDOMan.GetSessionID()); val.Set("vikingrail_autodrive_engine", ""); val.Set("vikingrail_autodrive_engine_zdo", ZDOID.None); } } if (text2.Length != 0 && !Object.op_Implicit((Object)(object)railVehicle)) { ZDO val2 = FindSavedLink(destroyed, "vikingrail_autodrive_engine_zdo", text2, "vikingrail_autodrive_controller", text); if (val2 != null) { val2.SetOwner(ZDOMan.GetSessionID()); val2.Set("vikingrail_autodrive_active", false); val2.Set("vikingrail_autodrive_owner", 0L); val2.Set("vikingrail_autodrive_owner_revision", -1); val2.Set("vikingrail_autodrive_status", "The automatic controller was destroyed."); val2.Set("vikingrail_autodrive_controller", ""); val2.Set("vikingrail_autodrive_controller_zdo", ZDOID.None); } } } private static ZDO? FindSavedLink(ZDO origin, string cachedIdKey, string identity, string reverseKey, string reverseIdentity) { //IL_0020: 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_004b: Unknown result type (might be due to invalid IL or missing references) ZDO zDO = ZDOMan.instance.GetZDO(origin.GetZDOID(cachedIdKey)); if (Matches(zDO)) { return zDO; } List list = new List(); ZDOMan.instance.FindSectorObjects(origin.GetSector(), new SimulationDistance(1, 0, false), list, (List)null); foreach (ZDO item in list) { if (Matches(item)) { return item; } } return null; bool Matches(ZDO? candidate) { if (candidate != null && candidate.GetString("vikingrail_identity", "") == identity) { return candidate.GetString(reverseKey, "") == reverseIdentity; } return false; } } private static void Tell(string message) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false); } } } [HarmonyPatch(typeof(Piece), "CanBeRemoved")] internal static class AttachedAutoDriveRemovalPatch { [HarmonyPostfix] private static void Postfix(Piece __instance, ref bool __result) { RailAutoDrive component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component) && component.IsAttached) { __result = false; } } } [HarmonyPatch(typeof(WearNTear), "RPC_Remove")] internal static class AttachedAutoDriveRemovalRequestPatch { [HarmonyPrefix] private static bool Prefix(WearNTear __instance) { RailAutoDrive component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { return !component.IsAttached; } return true; } } internal static class RailBuildMenu { private static readonly FieldInfo? Usage = AccessTools.Field(typeof(Piece), "m_usage"); internal static void ConfigureTransportPiece(Piece piece) { if (Usage == null || Usage.IsStatic || !Usage.FieldType.IsEnum || !Enum.IsDefined(Usage.FieldType, "Transport")) { return; } try { Usage.SetValue(piece, Enum.Parse(Usage.FieldType, "Transport")); } catch (Exception ex) { RailPlugin.Warn("Eitr engine usage tag was unavailable; retaining its Misc category: " + ex.GetBaseException().Message); } } internal static void ConfigureRepairPiece(Piece piece) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) piece.m_category = (PieceCategory)1; if (Usage == null || Usage.IsStatic || !Usage.FieldType.IsEnum || !Enum.IsDefined(Usage.FieldType, "Crafting") || !Enum.IsDefined(Usage.FieldType, "Transport")) { return; } try { Usage.SetValue(piece, Enum.Parse(Usage.FieldType, "Crafting, Transport")); } catch (Exception ex) { RailPlugin.Warn("Repair cart usage tags were unavailable; retaining its Crafting category: " + ex.GetBaseException().Message); } } } [HarmonyPatch] internal static class RailBuildMenuRefreshPatch { private static readonly MethodInfo? Toggle = VoidMethod(typeof(Hud), "TogglePieceSelection"); private static readonly MethodInfo? Known = VoidMethod(typeof(Player), "UpdateKnownRecipesList"); private static readonly MethodInfo? Available = VoidMethod(typeof(Player), "UpdateAvailablePiecesList"); private static readonly FieldInfo? Window = AccessTools.Field(typeof(Hud), "m_pieceSelectionWindow"); private static readonly FieldInfo? BuildPieces = AccessTools.Field(typeof(Player), "m_buildPieces"); private static bool _refreshing; private static bool _warned; private static MethodInfo? VoidMethod(Type type, string name) { MethodInfo methodInfo = AccessTools.Method(type, name, Type.EmptyTypes, (Type[])null); if (!(methodInfo != null) || methodInfo.IsStatic || !(methodInfo.ReturnType == typeof(void))) { return null; } return methodInfo; } [HarmonyPrepare] private static bool Prepare() { int num; if (Toggle != null && Known != null && Available != null && Window != null && !Window.IsStatic && Window.FieldType == typeof(GameObject) && BuildPieces != null && !BuildPieces.IsStatic) { num = ((BuildPieces.FieldType == typeof(PieceTable)) ? 1 : 0); if (num != 0) { goto IL_00a0; } } else { num = 0; } Warn("the native build-menu refresh API is unavailable on this game build."); goto IL_00a0; IL_00a0: return (byte)num != 0; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return Toggle; } [HarmonyPrefix] private static void Prefix(Hud __instance) { if (_refreshing || !Object.op_Implicit((Object)(object)__instance)) { return; } try { object? value = Window.GetValue(__instance); GameObject val = (GameObject)((value is GameObject) ? value : null); Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)val) || val.activeSelf || !Object.op_Implicit((Object)(object)localPlayer) || ((Character)localPlayer).IsDead() || !((Character)localPlayer).InPlaceMode() || !Object.op_Implicit((Object)(object)Game.instance) || !Object.op_Implicit((Object)(object)ObjectDB.instance) || !Object.op_Implicit((Object)(object)ZoneSystem.instance)) { return; } object? value2 = BuildPieces.GetValue(localPlayer); PieceTable val2 = (PieceTable)((value2 is PieceTable) ? value2 : null); ItemData rightItem = ((Humanoid)localPlayer).GetRightItem(); if (Object.op_Implicit((Object)(object)val2) && rightItem != null && rightItem.m_shared != null && !((Object)(object)rightItem.m_shared.m_buildPieces != (Object)(object)val2) && ((Humanoid)localPlayer).GetInventory().GetAllItems().Contains(rightItem)) { _refreshing = true; if (RailPrefabs.HasDeferredWorkshopRecipes) { RailPrefabs.AddToHammer(ObjectDB.instance); } if (HasRegisteredRailRecipe(val2)) { Known.Invoke(localPlayer, null); Available.Invoke(localPlayer, null); } } } catch (Exception ex) { Warn(ex.GetBaseException().Message); } finally { _refreshing = false; } } private static bool HasRegisteredRailRecipe(PieceTable table) { if (table.m_pieces == null) { return false; } foreach (GameObject piece in table.m_pieces) { if (!RailPrefabs.IsRegisteredBuildPiece(piece)) { continue; } Piece component = piece.GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !component.m_enabled || component.m_resources == null || component.m_resources.Length == 0) { continue; } bool flag = true; Requirement[] resources = component.m_resources; foreach (Requirement val in resources) { if (val == null || !Object.op_Implicit((Object)(object)val.m_resItem) || val.m_amount <= 0) { flag = false; break; } } if (flag) { return true; } } return false; } private static void Warn(string reason) { if (!_warned) { _warned = true; RailPlugin.Warn("Railway build-menu refresh skipped; normal build-menu behavior remains: " + reason); } } } internal static class RailCamera { internal static readonly MethodInfo? EyeMethod = AccessTools.Method(typeof(GameCamera), "GetOffsetedEyePos", Type.EmptyTypes, (Type[])null); internal static readonly MethodInfo? CollisionMethod = AccessTools.Method(typeof(GameCamera), "CollideRay2", new Type[3] { typeof(Vector3), typeof(Vector3), typeof(Vector3).MakeByRefType() }, (Type[])null); private static readonly FieldInfo? PlayerPosition = AccessTools.Field(typeof(GameCamera), "m_playerPos"); private static readonly FieldInfo? PlayerVelocity = AccessTools.Field(typeof(GameCamera), "m_playerVel"); private static bool _warned; private static Player? _player; private static Component? _rider; private static int _lastFrame = -1; private static Vector3 _lastPosition; internal static bool Prepare() { int num; if (EyeMethod != null && !EyeMethod.IsStatic && EyeMethod.ReturnType == typeof(Vector3) && CollisionMethod != null && !CollisionMethod.IsStatic && CollisionMethod.ReturnType == typeof(void) && PlayerPosition != null && !PlayerPosition.IsStatic && PlayerPosition.FieldType == typeof(Vector3) && PlayerVelocity != null && !PlayerVelocity.IsStatic) { num = ((PlayerVelocity.FieldType == typeof(Vector3)) ? 1 : 0); if (num != 0) { goto IL_00fa; } } else { num = 0; } if (!_warned) { _warned = true; RailPlugin.Warn("Rail camera smoothing is unavailable on this Valheim build; using the native camera."); } goto IL_00fa; IL_00fa: return (byte)num != 0; } internal static bool TryOffset(ref Vector3 smoothedPosition, ref Vector3 smoothedVelocity, out Vector3 offset) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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_015d: 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_0165: 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_0185: 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_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) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: 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_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) offset = Vector3.zero; Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting() || !((Character)localPlayer).IsAttached() || (Object)(object)localPlayer.GetAttachCameraPoint() != (Object)null) { return Reset(); } IDoodadController doodadController = localPlayer.GetDoodadController(); Component val = null; Transform anchor; if (doodadController is RailVehicle railVehicle && Object.op_Implicit((Object)(object)railVehicle) && (Object)(object)railVehicle == (Object)(object)RailVehicle.LocalDriven && railVehicle.IsReady) { Transform attachPoint = localPlayer.GetAttachPoint(); if (Object.op_Implicit((Object)(object)attachPoint) && (Object)(object)((Component)attachPoint).GetComponentInParent() == (Object)(object)railVehicle) { val = (Component)(object)railVehicle; } } else if (doodadController is RailPassengerSeat railPassengerSeat && Object.op_Implicit((Object)(object)railPassengerSeat) && (Object)(object)railPassengerSeat == (Object)(object)RailPassengerSeat.LocalSeat) { if (railPassengerSeat.HasLocalRider(localPlayer)) { val = (Component)(object)railPassengerSeat; } } else if (doodadController is RailPumpPartner railPumpPartner && Object.op_Implicit((Object)(object)railPumpPartner) && (Object)(object)railPumpPartner == (Object)(object)RailPumpPartner.LocalPartner && railPumpPartner.TryRider(localPlayer, out anchor)) { val = (Component)(object)railPumpPartner; } if (!Object.op_Implicit((Object)(object)val)) { return Reset(); } Vector3 position = ((Component)localPlayer).transform.position; if (!((Object)(object)_player != (Object)(object)localPlayer) && !((Object)(object)_rider != (Object)(object)val) && Time.frameCount <= _lastFrame + 1) { Vector3 val2 = position - _lastPosition; if (!(((Vector3)(ref val2)).sqrMagnitude > 4f)) { goto IL_016f; } } smoothedPosition = position; smoothedVelocity = Vector3.zero; goto IL_016f; IL_016f: _player = localPlayer; _rider = val; _lastFrame = Time.frameCount; _lastPosition = position; offset = smoothedPosition - position; return true; } private static bool Reset() { _player = null; _rider = null; _lastFrame = -1; return false; } } [HarmonyPatch] internal static class RailCameraTargetPatch { [HarmonyPrepare] private static bool Prepare() { return RailCamera.Prepare(); } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailCamera.EyeMethod; } [HarmonyPostfix] private static void Postfix(ref Vector3 ___m_playerPos, ref Vector3 ___m_playerVel, ref Vector3 __result) { //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_0013: 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) if (RailCamera.TryOffset(ref ___m_playerPos, ref ___m_playerVel, out var offset)) { __result += offset; } } } [HarmonyPatch] internal static class RailCameraCollisionPatch { [HarmonyPrepare] private static bool Prepare() { return RailCamera.Prepare(); } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailCamera.CollisionMethod; } [HarmonyPrefix] private static void Prefix(ref Vector3 ___m_playerPos, ref Vector3 ___m_playerVel, ref Vector3 __0) { //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_0013: 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) if (RailCamera.TryOffset(ref ___m_playerPos, ref ___m_playerVel, out var offset)) { __0 += offset; } } } internal sealed class RailCargoInventory : MonoBehaviour { private sealed class NativeRequestScope { internal RailCargoInventory State; internal long Peer; internal long Player; internal string Token = ""; internal int Request; internal ContainerRpcResponse Response; } internal sealed class ReadScope { internal Inventory? Previous; internal bool Nested; } private static readonly MethodInfo? NativeLoad = AccessTools.Method(typeof(Container), "Load", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo? CheckAccess = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null); private static readonly FieldInfo? InventoryField = AccessTools.Field(typeof(Container), "m_inventory"); private static readonly FieldInfo? LoadingField = AccessTools.Field(typeof(Container), "m_loading"); private static readonly FieldInfo? RevisionField = AccessTools.Field(typeof(Container), "m_lastRevision"); private static readonly FieldInfo? DataField = AccessTools.Field(typeof(Container), "m_lastDataString"); private static readonly FieldInfo? WeightField = AccessTools.Field(typeof(Inventory), "m_totalWeight"); private static readonly FieldInfo? WidthField = AccessTools.Field(typeof(Inventory), "m_width"); private static readonly FieldInfo? HeightField = AccessTools.Field(typeof(Inventory), "m_height"); private static readonly FieldInfo? CurrentContainer = AccessTools.Field(typeof(InventoryGui), "m_currentContainer"); private static readonly FieldInfo? DragInventory = AccessTools.Field(typeof(InventoryGui), "m_dragInventory"); private static readonly FieldInfo? SplitInventory = AccessTools.Field(typeof(InventoryGui), "m_splitInventory"); private static readonly MethodInfo? ResetDrag = AccessTools.Method(typeof(InventoryGui), "SetupDragItem", new Type[3] { typeof(ItemData), typeof(Inventory), typeof(int) }, (Type[])null); private static readonly ConditionalWeakTable Inventories = new ConditionalWeakTable(); private const float GrantTimeout = 5f; private static long _latestIntent; private static Inventory? _stagedLoad; private static Inventory? _readingInventory; [ThreadStatic] private static NativeRequestScope? _requestScope; private static int _requestSequence; private static readonly MethodInfo?[] NativeRequests = new MethodInfo[3] { AccessTools.Method(typeof(Container), "RPC_RequestOpen", new Type[2] { typeof(long), typeof(long) }, (Type[])null), AccessTools.Method(typeof(Container), "RPC_RequestStack", new Type[2] { typeof(long), typeof(long) }, (Type[])null), AccessTools.Method(typeof(Container), "RPC_RequestTakeAll", new Type[2] { typeof(long), typeof(long) }, (Type[])null) }; private Container _container; private RailVehicle _cart; private ZNetView _view; private bool _nativeLoad; private string _error = ""; private ContainerRpcResponse? _requested; private long _expectedPeer; private long _intent; private float _expires; private bool _granted; private bool _replaying; private long _loadedOwner; private ushort _loadedOwnerRevision; private uint _loadedDataRevision; private bool _hasLoadedOwner; private string _leaseToken = ""; private RailVehicle? _leaseRoot; private bool _leaseAccepted; private bool _returning; private bool _requestSent; private int _requestNumber; private string _sealedToken = ""; private float _nextRenew; private long _ownerRequestPeer; private long _ownerRequestPlayer; private string _ownerRequestToken = ""; private int _ownerRequestOperation; private float _ownerRequestUntil; private bool _rpcRegistered; private bool LeaseUsable { get { if (_leaseAccepted && !_returning && _sealedToken != _leaseToken && Object.op_Implicit((Object)(object)Player.m_localPlayer) && Object.op_Implicit((Object)(object)_cart)) { return _cart.CargoGrantMatches(((Character)Player.m_localPlayer).GetOwner(), Player.m_localPlayer.GetPlayerID(), _leaseToken); } return false; } } private bool GuiOpen { get { if (Object.op_Implicit((Object)(object)InventoryGui.instance)) { object? obj = CurrentContainer?.GetValue(InventoryGui.instance); Container val = (Container)((obj is Container) ? obj : null); if (val != null) { return (Object)(object)val == (Object)(object)_container; } } return false; } } private void Awake() { _container = ((Component)this).GetComponent(); _cart = ((Component)this).GetComponent(); _view = ((Component)this).GetComponent(); RegisterRpc(); } private void OnDestroy() { CloseUnsafeInventory(); if (_leaseToken.Length != 0 && Object.op_Implicit((Object)(object)_cart) && _cart.IsReady) { _cart.EndCargoAccess(_leaseToken, _leaseRoot); } } private void RegisterRpc() { if (!_rpcRegistered && Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { _view.Register("VR_CargoNative", (Action)OwnerRequest); _view.Register("VR_CargoNativeReply", (Action)NativeReply); _rpcRegistered = true; } } private static RailCargoInventory Get(Container container) { return ((Component)container).GetComponent() ?? ((Component)container).gameObject.AddComponent(); } internal static void Ensure(Container container) { Get(container).RegisterRpc(); } internal static bool HasPending(RailVehicle cart) { RailCargoInventory component = ((Component)cart).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { if (component._leaseToken.Length == 0) { return component._ownerRequestToken.Length != 0; } return true; } return false; } internal static bool HasLocalLease(RailVehicle cart, string token) { RailCargoInventory component = ((Component)cart).GetComponent(); if (Object.op_Implicit((Object)(object)component) && component._leaseAccepted && component._leaseToken == token && !component._returning) { return (Object)(object)component._leaseRoot == (Object)(object)cart; } return false; } internal static bool HasConflictingPending(RailVehicle cart, string token) { RailCargoInventory component = ((Component)cart).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { if (component._leaseToken.Length == 0 || !(component._leaseToken != token)) { if (component._ownerRequestToken.Length != 0) { return component._ownerRequestToken != token; } return false; } return true; } return false; } internal static string InventoryDigest(ZDO data) { string text = data.GetString(ZDOVars.s_items, ""); byte[] byteArray = data.GetByteArray(ZDOVars.s_items, (byte[])null); return RailCargoSnapshot.Digest("S" + text.Length + ":" + text + "B" + ((byteArray == null) ? "-" : Convert.ToBase64String(byteArray))); } internal static bool ValidRequester(Container container, long peer, long playerId, out Player player) { //IL_0042: 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_006c: Unknown result type (might be due to invalid IL or missing references) player = Player.GetPlayer(playerId); if (!Object.op_Implicit((Object)(object)container) || peer == 0L || playerId == 0L || !Object.op_Implicit((Object)(object)player) || ((Character)player).GetOwner() != peer || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || Vector3.Distance(((Component)player).transform.position, ((Component)container).transform.position) >= 5f || (container.m_checkGuardStone && !RailWardAccess.Allows(((Component)container).transform.position, playerId))) { return false; } try { return CheckAccess != null && (bool)CheckAccess.Invoke(container, new object[1] { playerId }); } catch (Exception ex) { RailPlugin.Warn("Cargo access validation failed: " + ex.GetBaseException().Message); return false; } } internal static bool TryRefresh(Container container, out string error, bool requireOwner = true) { error = ""; if (!Object.op_Implicit((Object)(object)container)) { error = "The cargo container is unavailable."; return false; } RailCargoInventory railCargoInventory = Get(container); if (!Object.op_Implicit((Object)(object)railCargoInventory._view) || !railCargoInventory._view.IsValid() || (requireOwner && !railCargoInventory._view.IsOwner())) { error = "Wait for the cargo owner and try again."; return false; } bool changed; bool result = railCargoInventory.LoadSafely(out changed); error = railCargoInventory._error; return result; } internal static bool TryRefreshForOwnership(Container container, out string error) { error = ""; if (!Object.op_Implicit((Object)(object)container)) { error = "The cargo container is unavailable."; return false; } RailCargoInventory railCargoInventory = Get(container); if (!Object.op_Implicit((Object)(object)railCargoInventory._view) || !railCargoInventory._view.IsValid() || !railCargoInventory._view.IsOwner()) { error = "Wait for the cargo owner and try again."; return false; } ZDO zDO = railCargoInventory._view.GetZDO(); if (railCargoInventory._hasLoadedOwner && railCargoInventory._loadedOwner == zDO.GetOwner() && railCargoInventory._loadedOwnerRevision == zDO.OwnerRevision) { error = railCargoInventory._error; return error.Length == 0; } return TryRefresh(container, out error); } internal static bool LoadPrefix(Container container, ref bool result) { if (!Object.op_Implicit((Object)(object)((Component)container).GetComponent())) { return true; } RailCargoInventory railCargoInventory = Get(container); if (railCargoInventory._nativeLoad) { return true; } railCargoInventory.LoadSafely(out result); return false; } private bool LoadSafely(out bool changed) { //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Expected O, but got Unknown changed = false; if (!Object.op_Implicit((Object)(object)_view) || !_view.IsValid() || _container.GetInventory() == null) { return Fail("The cargo inventory is not ready."); } if (NativeLoad == null || InventoryField?.FieldType != typeof(Inventory) || LoadingField?.FieldType != typeof(bool) || RevisionField?.FieldType != typeof(uint) || WeightField?.FieldType != typeof(float) || WidthField?.FieldType != typeof(int) || HeightField?.FieldType != typeof(int) || CurrentContainer?.FieldType != typeof(Container)) { return Fail("This Valheim build's native cargo loader is unavailable."); } Inventory inventory = _container.GetInventory(); if ((bool)LoadingField.GetValue(_container)) { return Fail("The cargo inventory is already loading."); } if (_error.Length == 0 && _hasLoadedOwner && _loadedDataRevision == _view.GetZDO().DataRevision && _loadedOwner == _view.GetZDO().GetOwner() && _loadedOwnerRevision == _view.GetZDO().OwnerRevision) { MarkLoadedOwner(); return true; } List collection = new List(inventory.GetAllItems()); float totalWeight = inventory.GetTotalWeight(); int width = inventory.GetWidth(); int height = inventory.GetHeight(); object value = RevisionField.GetValue(_container); object value2 = DataField?.GetValue(_container); Inventory stagedLoad = _stagedLoad; bool forceDisableInit = ZNetView.m_forceDisableInit; try { Inventory val = new Inventory(_container.m_name, _container.m_bkg, width, height); val.GetAllItems().AddRange(collection); WeightField.SetValue(val, totalWeight); InventoryField.SetValue(_container, val); _stagedLoad = val; _nativeLoad = true; changed = (bool)NativeLoad.Invoke(_container, null); _nativeLoad = false; _stagedLoad = stagedLoad; InventoryField.SetValue(_container, inventory); if (changed) { LoadingField.SetValue(_container, true); inventory.GetAllItems().Clear(); inventory.GetAllItems().AddRange(val.GetAllItems()); WeightField.SetValue(inventory, val.GetTotalWeight()); WidthField.SetValue(inventory, val.GetWidth()); HeightField.SetValue(inventory, val.GetHeight()); inventory.m_onChanged?.Invoke(); } LoadingField.SetValue(_container, false); _error = ""; MarkLoadedOwner(); return true; } catch (Exception ex) { InventoryField.SetValue(_container, inventory); inventory.GetAllItems().Clear(); inventory.GetAllItems().AddRange(collection); WeightField.SetValue(inventory, totalWeight); WidthField.SetValue(inventory, width); HeightField.SetValue(inventory, height); RevisionField.SetValue(_container, value); DataField?.SetValue(_container, value2); LoadingField.SetValue(_container, false); changed = false; return Fail("Cargo could not be loaded safely; its saved items have been kept. " + ex.GetBaseException().Message); } finally { _nativeLoad = false; _stagedLoad = stagedLoad; ZNetView.m_forceDisableInit = forceDisableInit; } } private bool Fail(string error) { if (_error != error) { RailPlugin.Error(new InvalidOperationException(error)); } _error = error; CloseUnsafeInventory(); return false; } private void MarkLoadedOwner() { Inventory inventory = _container.GetInventory(); if (inventory != null && !Inventories.TryGetValue(inventory, out RailCargoInventory _)) { Inventories.Add(inventory, this); } _loadedOwner = _view.GetZDO().GetOwner(); _loadedOwnerRevision = _view.GetZDO().OwnerRevision; _loadedDataRevision = _view.GetZDO().DataRevision; _hasLoadedOwner = true; } private void CloseUnsafeInventory() { InventoryGui instance = InventoryGui.instance; if (Object.op_Implicit((Object)(object)instance)) { object? obj = CurrentContainer?.GetValue(instance); Container val = (Container)((obj is Container) ? obj : null); if (val != null && (Object)(object)val == (Object)(object)_container) { instance.Hide(); } } } internal static bool AllowShow(Container? container) { if (Object.op_Implicit((Object)(object)container)) { RailMountAccess.Remember(container); if (RailMountAccess.Locked((Component)(object)container)) { return false; } } if (!Object.op_Implicit((Object)(object)container) || !Object.op_Implicit((Object)(object)((Component)container).GetComponent())) { return true; } RailCargoInventory railCargoInventory = Get(container); if (railCargoInventory.CanUse() && railCargoInventory.LeaseUsable && TryRefresh(container, out string _)) { return true; } railCargoInventory.CloseUnsafeInventory(); return false; } internal static void GuardOpenInventory(InventoryGui gui) { object? obj = CurrentContainer?.GetValue(gui); Container val = (Container)((obj is Container) ? obj : null); if (val == null || !Object.op_Implicit((Object)(object)val)) { return; } RailMountAccess.Remember(val); if (RailMountAccess.Locked((Component)(object)val)) { gui.Hide(); } else if (Object.op_Implicit((Object)(object)((Component)val).GetComponent())) { RailCargoInventory railCargoInventory = Get(val); if (!railCargoInventory.CanUse() || !railCargoInventory.LeaseUsable || !Object.op_Implicit((Object)(object)railCargoInventory._view) || !railCargoInventory._view.IsValid() || !railCargoInventory._view.IsOwner() || railCargoInventory._error.Length != 0) { gui.Hide(); } } } internal static bool AllowGuiMutation(InventoryGui gui, InventoryGrid? grid = null, bool checkSplit = false) { Inventory inventory = (Object.op_Implicit((Object)(object)grid) ? grid.GetInventory() : null); object? obj = CurrentContainer?.GetValue(gui); Container val = (Container)((obj is Container) ? obj : null); object? obj2 = DragInventory?.GetValue(gui); Inventory inventory2 = (Inventory)((obj2 is Inventory) ? obj2 : null); Inventory inventory3 = (Inventory)(checkSplit ? /*isinst with value type is only supported in some contexts*/: null); if (CanMutateGuiInventory(gui, inventory) && CanMutateGuiInventory(gui, Object.op_Implicit((Object)(object)val) ? val.GetInventory() : null) && CanMutateGuiInventory(gui, inventory2)) { return CanMutateGuiInventory(gui, inventory3); } return false; } private static bool CanMutateGuiInventory(InventoryGui gui, Inventory? inventory) { if (!RailMountAccess.CanMutate(inventory)) { if (DragInventory?.GetValue(gui) == inventory) { try { ResetDrag?.Invoke(gui, new object[3] { null, null, 1 }); } catch (Exception ex) { RailPlugin.Warn("Could not clear a stale mounted-object drag: " + ex.GetBaseException().Message); } } gui.Hide(); return false; } if (inventory == null || !Inventories.TryGetValue(inventory, out RailCargoInventory value)) { return true; } if (!Object.op_Implicit((Object)(object)value) || !Object.op_Implicit((Object)(object)value._container) || !value.GuiOpen || !value.CanUse() || !value.LeaseUsable || !value._view.IsOwner() || value._error.Length != 0) { if (DragInventory?.GetValue(gui) == inventory) { try { ResetDrag?.Invoke(gui, new object[3] { null, null, 1 }); } catch (Exception ex2) { RailPlugin.Warn("Could not clear a stale cargo drag: " + ex2.GetBaseException().Message); } } if (Object.op_Implicit((Object)(object)value)) { value.CloseUnsafeInventory(); } return false; } return true; } internal static bool AllowSave(Container container) { if (Object.op_Implicit((Object)(object)((Component)container).GetComponent())) { return ((Component)container).GetComponent()._error.Length == 0; } return true; } internal static ReadScope? BeginRead(Inventory inventory) { if (inventory != _stagedLoad) { return null; } ReadScope result = new ReadScope { Previous = _readingInventory, Nested = (_readingInventory == inventory) }; _readingInventory = inventory; return result; } internal static void EndRead(ReadScope? scope) { if (scope != null) { _readingInventory = scope.Previous; } } internal static void CheckLoaded(Inventory inventory, ZPackage package, ReadScope? scope) { if (scope == null || scope.Nested) { return; } if (package.GetPos() != package.Size()) { throw new FormatException("The native cargo payload was not completely read."); } foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem == null || !Object.op_Implicit((Object)(object)allItem.m_dropPrefab) || allItem.m_stack <= 0) { throw new FormatException("A cargo item could not be loaded."); } } } internal static void CheckItemAdded(Inventory inventory, bool success) { if (!success && inventory == _stagedLoad && inventory == _readingInventory) { throw new FormatException("A cargo item could not be loaded. Restore its item mod before using this cart."); } } internal static bool BeginRequest(Container container, ContainerRpcResponse response) { if (!Object.op_Implicit((Object)(object)((Component)container).GetComponent())) { return true; } RailCargoInventory railCargoInventory = Get(container); if (!railCargoInventory.CanUse()) { string reason = "Stop the train before opening storage."; if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { railCargoInventory._cart.CanRequestCargo(Player.m_localPlayer, out reason); } railCargoInventory.Notify(reason); return false; } if (railCargoInventory._returning || railCargoInventory._requested != null) { return false; } railCargoInventory._requested = response; railCargoInventory._intent = ++_latestIntent; railCargoInventory._expires = Time.unscaledTime + 5f; railCargoInventory._granted = false; railCargoInventory._requestSent = false; if (++_requestSequence >= 700000000) { _requestSequence = 1; } railCargoInventory._requestNumber = _requestSequence * 3 + Operation(response); if (railCargoInventory._leaseToken.Length == 0) { if (!railCargoInventory._cart.TryCargoRoot(out RailVehicle root)) { railCargoInventory._requested = null; return false; } railCargoInventory._leaseToken = Guid.NewGuid().ToString("N"); railCargoInventory._leaseRoot = root; railCargoInventory._leaseAccepted = false; railCargoInventory._cart.RequestCargoAccess(Player.m_localPlayer.GetPlayerID(), railCargoInventory._leaseToken); } railCargoInventory.DispatchRequest(); return false; } private static int Operation(ContainerRpcResponse response) { if (response != CargoProtocol.Open) { if (response != CargoProtocol.Stack) { return 2; } return 1; } return 0; } private static ContainerRpcResponse ResponseFor(int request) { if (request % 3 != 0) { if (request % 3 != 1) { return CargoProtocol.TakeAll; } return CargoProtocol.Stack; } return CargoProtocol.Open; } internal static void LeaseReply(Container container, RailVehicle root, long sender, string token, bool granted, string reason) { RailCargoInventory railCargoInventory = Get(container); if (!((Object)(object)railCargoInventory._leaseRoot != (Object)(object)root) && !(railCargoInventory._leaseToken != token) && !railCargoInventory._returning && railCargoInventory._requested != null) { if (!granted) { railCargoInventory.Notify(reason); railCargoInventory.ClearLocalLease(); } else { railCargoInventory._leaseAccepted = true; railCargoInventory.DispatchRequest(); } } } private void DispatchRequest() { if (_requested != null && !_requestSent && CanUse() && LeaseUsable) { _requestSent = true; _expectedPeer = _view.GetZDO().GetOwner(); _view.InvokeRPC("VR_CargoNative", new object[3] { Player.m_localPlayer.GetPlayerID(), _leaseToken, _requestNumber }); } } private void OwnerRequest(long sender, long playerId, string token, int request) { if (Object.op_Implicit((Object)(object)_view) && _view.IsValid() && _view.IsOwner() && token != null && token.Length == 32 && Guid.TryParseExact(token, "N", out var _) && request >= 3 && request <= 2100000002 && !(token == _sealedToken) && _ownerRequestToken.Length == 0) { if (!ValidRequester(_container, sender, playerId, out Player player) || !_cart.CanRequestCargo(player, out string _)) { _view.InvokeRPC(sender, "VR_CargoNativeReply", new object[3] { token, request, false }); } else { _ownerRequestPeer = sender; _ownerRequestPlayer = playerId; _ownerRequestToken = token; _ownerRequestOperation = request; _ownerRequestUntil = Time.unscaledTime + 5f; ProcessOwnerRequest(); } } } private void ProcessOwnerRequest() { if (_ownerRequestToken.Length == 0) { return; } Player player; string reason; if (!Object.op_Implicit((Object)(object)_view) || !_view.IsValid() || !_view.IsOwner()) { _ownerRequestToken = ""; } else if (Time.unscaledTime >= _ownerRequestUntil || _sealedToken == _ownerRequestToken || !ValidRequester(_container, _ownerRequestPeer, _ownerRequestPlayer, out player) || !_cart.CanRequestCargo(player, out reason)) { _view.InvokeRPC(_ownerRequestPeer, "VR_CargoNativeReply", new object[3] { _ownerRequestToken, _ownerRequestOperation, false }); _ownerRequestToken = ""; } else { if (!_cart.CargoGrantMatches(_ownerRequestPeer, _ownerRequestPlayer, _ownerRequestToken)) { return; } NativeRequestScope nativeRequestScope = new NativeRequestScope { State = this, Peer = _ownerRequestPeer, Player = _ownerRequestPlayer, Token = _ownerRequestToken, Request = _ownerRequestOperation, Response = ResponseFor(_ownerRequestOperation) }; _ownerRequestToken = ""; NativeRequestScope requestScope = _requestScope; try { _requestScope = nativeRequestScope; _cart.MarkCargoOrigin(nativeRequestScope.Token); MethodInfo? obj = NativeRequests[nativeRequestScope.Request % 3]; if (obj == null) { throw new MissingMethodException("The native storage request is unavailable."); } obj.Invoke(_container, new object[2] { nativeRequestScope.Peer, nativeRequestScope.Player }); } catch (Exception ex) { RailPlugin.Warn("Storage request failed safely: " + ex.GetBaseException().Message); _view.InvokeRPC(nativeRequestScope.Peer, "VR_CargoNativeReply", new object[3] { nativeRequestScope.Token, nativeRequestScope.Request, false }); } finally { _requestScope = requestScope; } } } internal static bool TagNativeReply(ZNetView view, long peer, string name, object[] parameters) { NativeRequestScope requestScope = _requestScope; if (requestScope == null || (Object)(object)requestScope.State._view != (Object)(object)view || requestScope.Peer != peer || requestScope.Response.RpcName != name || parameters == null || parameters.Length != 1 || !(parameters[0] is bool flag)) { return true; } view.InvokeRPC(peer, "VR_CargoNativeReply", new object[3] { requestScope.Token, requestScope.Request, flag }); return false; } internal static bool AllowOwnerRequest(Container container, long peer, long playerId, ContainerRpcResponse response) { if (!Object.op_Implicit((Object)(object)((Component)container).GetComponent())) { return true; } NativeRequestScope requestScope = _requestScope; RailCargoInventory railCargoInventory = Get(container); if (requestScope == null || (Object)(object)requestScope.State != (Object)(object)railCargoInventory || requestScope.Peer != peer || requestScope.Player != playerId || requestScope.Response != response) { return false; } Player player; string error; bool flag = Object.op_Implicit((Object)(object)railCargoInventory._view) && railCargoInventory._view.IsValid() && railCargoInventory._view.IsOwner() && railCargoInventory._sealedToken != requestScope.Token && ValidRequester(container, peer, playerId, out player) && railCargoInventory._cart.CanRequestCargo(player, out error) && railCargoInventory._cart.CargoGrantMatches(peer, playerId, requestScope.Token) && (response != CargoProtocol.TakeAll || railCargoInventory._view.GetZDO().GetOwner() == peer) && TryRefresh(container, out error); if (!flag && Object.op_Implicit((Object)(object)railCargoInventory._view) && railCargoInventory._view.IsValid()) { railCargoInventory._view.InvokeRPC(peer, response.RpcName, new object[1] { false }); } return flag; } internal static bool Response(Container container, long peer, bool granted, ContainerRpcResponse response) { if (Object.op_Implicit((Object)(object)((Component)container).GetComponent())) { return Get(container)._replaying; } return true; } private void NativeReply(long peer, string token, int request, bool granted) { if (_requested != null && _requestSent && !(token != _leaseToken) && request == _requestNumber && ResponseFor(request) == _requested && _expectedPeer == peer && _intent == _latestIntent && !_returning && !(Time.unscaledTime >= _expires)) { if (!granted) { Notify("Storage is busy or access was denied. Stop the train and try again."); ReturnLease(); } else { _granted = true; TryComplete(); } } } internal static void Seal(Container container, string token) { RailCargoInventory railCargoInventory = Get(container); railCargoInventory._sealedToken = token; railCargoInventory._ownerRequestToken = ""; if (railCargoInventory._leaseToken == token) { railCargoInventory._requested = null; railCargoInventory._returning = true; } railCargoInventory.CloseUnsafeInventory(); container.SetInUse(false); } private bool CanUse() { Player localPlayer = Player.m_localPlayer; string reason; if (Object.op_Implicit((Object)(object)_cart) && _cart.IsReady && Object.op_Implicit((Object)(object)_view) && _view.IsValid() && Object.op_Implicit((Object)(object)localPlayer) && ValidRequester(_container, ((Character)localPlayer).GetOwner(), localPlayer.GetPlayerID(), out Player _)) { return _cart.CanRequestCargo(localPlayer, out reason); } return false; } private void Notify(string message) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && message.Length != 0) { ((Character)Player.m_localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false); } } private void ReturnLease() { _requested = null; _granted = false; _returning = true; CloseUnsafeInventory(); if (Object.op_Implicit((Object)(object)_cart) && _cart.IsReady && _leaseToken.Length != 0) { _cart.EndCargoAccess(_leaseToken, _leaseRoot); } } private void ClearLocalLease() { _requested = null; _leaseToken = ""; _leaseRoot = null; _leaseAccepted = false; _returning = false; _requestSent = false; _granted = false; } private void Update() { RegisterRpc(); ProcessOwnerRequest(); if (_leaseToken.Length == 0) { return; } bool flag = Object.op_Implicit((Object)(object)_cart) && _cart.CargoTokenMatches(_leaseToken); if (_returning) { CloseUnsafeInventory(); if (!flag && (_leaseAccepted || Time.unscaledTime >= _expires)) { ClearLocalLease(); } return; } if (!CanUse() || (_requested != null && (_intent != _latestIntent || Time.unscaledTime >= _expires))) { Notify("Storage access ended. Stop the train and try again."); ReturnLease(); return; } if (!LeaseUsable) { if (_requested == null || Time.unscaledTime >= _expires) { ReturnLease(); } return; } if (Time.unscaledTime >= _nextRenew) { _nextRenew = Time.unscaledTime + 1f; _cart.RenewCargoAccess(_leaseToken); } DispatchRequest(); if (_granted) { TryComplete(); } if (_requested == null && !GuiOpen) { ReturnLease(); } } private void TryComplete() { if (_requested == null || !_granted || !CanUse() || !LeaseUsable || !_view.IsOwner()) { return; } ContainerRpcResponse requested = _requested; _requested = null; _granted = false; if (!TryRefresh(_container, out string error)) { Notify(error); ReturnLease(); return; } try { _replaying = true; requested.Method.Invoke(_container, new object[2] { _expectedPeer, true }); } catch (Exception ex) { RailPlugin.Error(ex.GetBaseException()); ReturnLease(); } finally { _replaying = false; } if (!GuiOpen) { ReturnLease(); } } } [HarmonyPatch(typeof(Container), "Load")] internal static class RailCargoLoadPatch { [HarmonyPrefix] private static bool Prefix(Container __instance, ref bool __result) { return RailCargoInventory.LoadPrefix(__instance, ref __result); } } [HarmonyPatch(typeof(ZNetView), "InvokeRPC", new Type[] { typeof(long), typeof(string), typeof(object[]) })] internal static class RailCargoTaggedReplyPatch { [HarmonyPrefix] private static bool Prefix(ZNetView __instance, long __0, string __1, object[] __2) { return RailCargoInventory.TagNativeReply(__instance, __0, __1, __2); } } [HarmonyPatch(typeof(Container), "Save")] internal static class RailCargoSavePatch { [HarmonyPrefix] private static bool Prefix(Container __instance) { return RailCargoInventory.AllowSave(__instance); } } [HarmonyPatch] internal static class RailCargoDeserializePatch { [HarmonyTargetMethods] private static IEnumerable TargetMethods() { yield return AccessTools.Method(typeof(Inventory), "Load", new Type[1] { typeof(ZPackage) }, (Type[])null); MethodInfo methodInfo = AccessTools.Method(typeof(Inventory), "Load", new Type[2] { typeof(ZPackage), typeof(bool) }, (Type[])null); if (methodInfo != null) { yield return methodInfo; } } [HarmonyPrefix] private static void Prefix(Inventory __instance, ZPackage __0, out RailCargoInventory.ReadScope? __state) { __state = RailCargoInventory.BeginRead(__instance); } [HarmonyPostfix] private static void Postfix(Inventory __instance, ZPackage __0, RailCargoInventory.ReadScope? __state) { RailCargoInventory.CheckLoaded(__instance, __0, __state); } [HarmonyFinalizer] private static void Finalizer(RailCargoInventory.ReadScope? __state) { RailCargoInventory.EndRead(__state); } } [HarmonyPatch] internal static class RailCargoLoadItemPatch { [HarmonyTargetMethods] private static IEnumerable TargetMethods() { MethodInfo[] methods = typeof(Inventory).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name == "AddItem" && methodInfo.ReturnType == typeof(bool) && !methodInfo.ContainsGenericParameters) { yield return methodInfo; } } } [HarmonyPostfix] private static void Postfix(Inventory __instance, bool __result) { RailCargoInventory.CheckItemAdded(__instance, __result); } } [HarmonyPatch(typeof(InventoryGui), "Show", new Type[] { typeof(Container), typeof(int) })] internal static class RailCargoShowPatch { [HarmonyPrefix] private static bool Prefix(Container __0) { return RailCargoInventory.AllowShow(__0); } } [HarmonyPatch(typeof(InventoryGui), "Update")] internal static class RailCargoOpenInventoryPatch { [HarmonyPrefix] private static void Prefix(InventoryGui __instance) { RailCargoInventory.GuardOpenInventory(__instance); } } [HarmonyPatch] internal static class RailCargoGridInteractionPatch { [HarmonyTargetMethods] private static IEnumerable TargetMethods() { string[] array = new string[3] { "OnSelectedItem", "OnRightClickItem", "OnReleasedItem" }; foreach (string text in array) { MethodInfo methodInfo = AccessTools.Method(typeof(InventoryGui), text, (Type[])null, (Type[])null); if (methodInfo != null && methodInfo.GetParameters().Length != 0 && methodInfo.GetParameters()[0].ParameterType == typeof(InventoryGrid)) { yield return methodInfo; } } } [HarmonyPrefix] private static bool Prefix(InventoryGui __instance, InventoryGrid __0) { return RailCargoInventory.AllowGuiMutation(__instance, __0); } } [HarmonyPatch] internal static class RailCargoGuiActionPatch { [HarmonyTargetMethods] private static IEnumerable TargetMethods() { string[] array = new string[4] { "OnTakeAll", "OnStackAll", "OnDropOutside", "OnSplitOk" }; foreach (string text in array) { MethodInfo methodInfo = AccessTools.Method(typeof(InventoryGui), text, Type.EmptyTypes, (Type[])null); if (methodInfo != null) { yield return methodInfo; } } } [HarmonyPrefix] private static bool Prefix(InventoryGui __instance, MethodBase __originalMethod) { return RailCargoInventory.AllowGuiMutation(__instance, null, __originalMethod.Name == "OnSplitOk"); } } internal sealed class RailCargoVisual : MonoBehaviour { private const int SlotCount = 16; private const int MaxRenderers = 24; private const int MaxTransformDepth = 32; private const int MaxVertices = 150000; private static readonly Vector3 ItemSpace = new Vector3(0.26f, 0.4f, 0.3f); private readonly GameObject?[] _models = (GameObject?[])(object)new GameObject[16]; private readonly GameObject?[] _prefabs = (GameObject?[])(object)new GameObject[16]; private readonly int[] _variants = new int[16]; private readonly bool[] _occupied = new bool[16]; private readonly ItemData?[] _items = (ItemData?[])(object)new ItemData[16]; private Container _container; private RailVehicle _cart; private ZNetView _view; private Inventory? _inventory; private GameObject? _display; private Mesh? _boxMesh; private Material? _woodMaterial; private bool _dirty = true; private bool _warned; private float _nextPoll; private void Awake() { _container = ((Component)this).GetComponent(); _cart = ((Component)this).GetComponent(); _view = ((Component)this).GetComponent(); } private void Update() { if (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsDedicated()) { ((Behaviour)this).enabled = false; return; } if (!Object.op_Implicit((Object)(object)_container) || !Object.op_Implicit((Object)(object)_cart) || !_cart.IsReady || !Object.op_Implicit((Object)(object)_view) || !_view.IsValid()) { if (Object.op_Implicit((Object)(object)_display)) { _display.SetActive(false); } return; } if (Object.op_Implicit((Object)(object)_display) && !_display.activeSelf) { _display.SetActive(true); } if (!_dirty && Time.unscaledTime < _nextPoll) { return; } _nextPoll = Time.unscaledTime + 0.5f; _dirty = false; Inventory inventory = _container.GetInventory(); if (inventory != _inventory) { if (_inventory != null) { Inventory? inventory2 = _inventory; inventory2.m_onChanged = (Action)Delegate.Remove(inventory2.m_onChanged, new Action(MarkCargoDirty)); } _inventory = inventory; if (_inventory != null) { Inventory? inventory3 = _inventory; inventory3.m_onChanged = (Action)Delegate.Combine(inventory3.m_onChanged, new Action(MarkCargoDirty)); } } if (_inventory == null) { return; } try { Refresh(); } catch (Exception ex) { if (!_warned) { _warned = true; RailPlugin.Warn("A cargo item could not be displayed: " + ex.Message); } } } private void MarkCargoDirty() { _dirty = true; } private void OnDestroy() { if (_inventory != null) { Inventory? inventory = _inventory; inventory.m_onChanged = (Action)Delegate.Remove(inventory.m_onChanged, new Action(MarkCargoDirty)); } } private void Refresh() { //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Expected O, but got Unknown //IL_025e: Unknown result type (might be due to invalid IL or missing references) Array.Clear(_items, 0, _items.Length); List allItems = _inventory.GetAllItems(); foreach (ItemData item in allItems) { if (item != null && item.m_stack > 0) { int x = item.m_gridPos.x; int y = item.m_gridPos.y; if (x >= 0 && x < 4 && y >= 0 && y < 4 && _items[y * 4 + x] == null) { _items[y * 4 + x] = item; } } } foreach (ItemData item2 in allItems) { if (item2 != null && item2.m_stack > 0 && Array.IndexOf(_items, item2) < 0) { int num = Array.IndexOf(_items, null); if (num < 0) { break; } _items[num] = item2; } } for (int i = 0; i < 16; i++) { ItemData? obj = _items[i]; GameObject val = obj?.m_dropPrefab; int num2 = obj?.m_variant ?? 0; bool flag = obj != null; if (_occupied[i] == flag && (Object)(object)_prefabs[i] == (Object)(object)val && _variants[i] == num2 && (!flag || Object.op_Implicit((Object)(object)_models[i]))) { continue; } if (Object.op_Implicit((Object)(object)_models[i])) { _models[i].SetActive(false); Object.Destroy((Object)(object)_models[i]); } _models[i] = null; _occupied[i] = flag; _prefabs[i] = val; _variants[i] = num2; if (flag) { EnsureDisplay(); GameObject val2 = new GameObject("cargo_slot_" + i); val2.SetActive(false); val2.layer = ((Component)this).gameObject.layer; val2.transform.SetParent(_display.transform, false); val2.transform.localPosition = new Vector3(((float)(i % 4) - 1.5f) * 0.3f, 1.08f, ((float)(i / 4) - 1.5f) * 0.35f); _models[i] = val2; bool flag2 = false; try { flag2 = Object.op_Implicit((Object)(object)val) && TryBuildItem(val, val2.transform); } catch (Exception) { } if (!flag2) { AddFallbackCrate(val2.transform); } val2.SetActive(true); } } } private void EnsureDisplay() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)_display)) { _display = new GameObject("vr_cargo_display"); _display.SetActive(false); _display.layer = ((Component)this).gameObject.layer; _display.transform.SetParent(((Component)this).transform, false); Transform val = ((Component)this).transform.Find("visual/cargo_bed_floor"); if (Object.op_Implicit((Object)(object)val)) { MeshFilter component = ((Component)val).GetComponent(); _boxMesh = ((component != null) ? component.sharedMesh : null); MeshRenderer component2 = ((Component)val).GetComponent(); _woodMaterial = ((component2 != null) ? ((Renderer)component2).sharedMaterial : null); } _display.SetActive(true); } } private bool TryBuildItem(GameObject prefab, Transform slot) { //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Expected O, but got Unknown //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02af: 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_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_0366: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_037e: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_038d: Unknown result type (might be due to invalid IL or missing references) //IL_0394: 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_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_020d: 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_0217: 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_0243: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) Transform val = FindVisualRoot(prefab.transform); MeshRenderer[] componentsInChildren = ((Component)val).GetComponentsInChildren(true); if (componentsInChildren.Length == 0 || componentsInChildren.Length > 96) { return false; } HashSet hashSet = LowerLodRenderers(val); List list = new List(); long num = 0L; MeshRenderer[] array = componentsInChildren; foreach (MeshRenderer val2 in array) { if (!Object.op_Implicit((Object)(object)val2) || !((Renderer)val2).enabled || hashSet.Contains((Renderer)(object)val2) || !VisiblePart(((Component)val2).transform, val)) { continue; } MeshFilter component = ((Component)val2).GetComponent(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.sharedMesh) && ((Renderer)val2).sharedMaterials.Length != 0) { num += component.sharedMesh.vertexCount; if (num > 150000 || list.Count == 24) { return false; } list.Add(val2); } } if (list.Count == 0) { return false; } GameObject val3 = new GameObject("item_model"); val3.SetActive(false); val3.layer = ((Component)this).gameObject.layer; val3.transform.SetParent(slot, false); bool flag = false; try { Dictionary copies = new Dictionary { [val] = val3.transform }; Bounds val4 = default(Bounds); bool flag2 = false; foreach (MeshRenderer item in list) { Transform val5 = CopyTransform(((Component)item).transform, val, copies, 0); if (!Object.op_Implicit((Object)(object)val5)) { return false; } Mesh sharedMesh = ((Component)item).GetComponent().sharedMesh; ((Component)val5).gameObject.AddComponent().sharedMesh = sharedMesh; MeshRenderer obj = ((Component)val5).gameObject.AddComponent(); ((Renderer)obj).sharedMaterials = ((Renderer)item).sharedMaterials; ((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)obj).receiveShadows = true; Bounds bounds = sharedMesh.bounds; for (int j = -1; j <= 1; j += 2) { for (int k = -1; k <= 1; k += 2) { for (int l = -1; l <= 1; l += 2) { Vector3 val6 = val3.transform.InverseTransformPoint(val5.TransformPoint(((Bounds)(ref bounds)).center + Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3((float)j, (float)k, (float)l)))); if (!Finite(val6)) { return false; } if (!flag2) { val4 = new Bounds(val6, Vector3.zero); flag2 = true; } else { ((Bounds)(ref val4)).Encapsulate(val6); } } } } } if (flag2 && Finite(((Bounds)(ref val4)).center) && Finite(((Bounds)(ref val4)).size)) { Vector3 size = ((Bounds)(ref val4)).size; if (!(((Vector3)(ref size)).sqrMagnitude < 1E-07f)) { float num2 = Mathf.Min(new float[3] { ItemSpace.x / Mathf.Max(((Bounds)(ref val4)).size.x, 1E-05f), ItemSpace.y / Mathf.Max(((Bounds)(ref val4)).size.y, 1E-05f), ItemSpace.z / Mathf.Max(((Bounds)(ref val4)).size.z, 1E-05f) }); val3.transform.localScale = Vector3.one * num2; val3.transform.localPosition = -new Vector3(((Bounds)(ref val4)).center.x, ((Bounds)(ref val4)).min.y, ((Bounds)(ref val4)).center.z) * num2; val3.SetActive(true); flag = true; return true; } } return false; } finally { if (!flag) { Object.Destroy((Object)(object)val3); } } } private static Transform FindVisualRoot(Transform prefab) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown string[] array = new string[2] { "attach", "visual" }; foreach (string b in array) { foreach (Transform item in prefab) { Transform val = item; if (string.Equals(((Object)val).name, b, StringComparison.OrdinalIgnoreCase) && Object.op_Implicit((Object)(object)((Component)val).GetComponentInChildren(true))) { return val; } } } return prefab; } private static HashSet LowerLodRenderers(Transform source) { HashSet hashSet = new HashSet(); HashSet hashSet2 = new HashSet(); LODGroup[] componentsInChildren = ((Component)source).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { LOD[] lODs = componentsInChildren[i].GetLODs(); for (int j = 0; j < lODs.Length; j++) { Renderer[] renderers = lODs[j].renderers; foreach (Renderer val in renderers) { if (Object.op_Implicit((Object)(object)val)) { ((j == 0) ? hashSet2 : hashSet).Add(val); } } } } hashSet.ExceptWith(hashSet2); return hashSet; } private Transform? CopyTransform(Transform original, Transform source, Dictionary copies, int depth) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_0079: 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_009b: Unknown result type (might be due to invalid IL or missing references) if (copies.TryGetValue(original, out Transform value)) { return value; } if (depth >= 32 || !Object.op_Implicit((Object)(object)original.parent) || (Object)(object)original == (Object)(object)source) { return null; } Transform val = CopyTransform(original.parent, source, copies, depth + 1); if (!Object.op_Implicit((Object)(object)val)) { return null; } GameObject val2 = new GameObject(((Object)original).name); val2.layer = ((Component)this).gameObject.layer; val2.transform.SetParent(val, false); val2.transform.localPosition = original.localPosition; val2.transform.localRotation = original.localRotation; val2.transform.localScale = original.localScale; copies.Add(original, val2.transform); return val2.transform; } private static bool VisiblePart(Transform part, Transform root) { Transform val = part; while (Object.op_Implicit((Object)(object)val) && (Object)(object)val != (Object)(object)root) { if (!((Component)val).gameObject.activeSelf) { return false; } val = val.parent; } return true; } private void AddFallbackCrate(Transform slot) { //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_0036: 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_0058: 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_0077: 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) if (Object.op_Implicit((Object)(object)_boxMesh) && Object.op_Implicit((Object)(object)_woodMaterial)) { GameObject val = new GameObject("cargo_crate") { layer = ((Component)this).gameObject.layer }; val.transform.SetParent(slot, false); val.transform.localPosition = new Vector3(0f, 0.13f, 0f); val.transform.localScale = new Vector3(0.24f, 0.26f, 0.28f); val.AddComponent().sharedMesh = _boxMesh; MeshRenderer obj = val.AddComponent(); ((Renderer)obj).sharedMaterial = _woodMaterial; ((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0; } } private static bool Finite(Vector3 value) { //IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references) if (Finite(value.x) && Finite(value.y)) { return Finite(value.z); } return false; } private static bool Finite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } public sealed class RailCouplingLever : MonoBehaviour, Hoverable, Interactable { public bool Front = true; internal static readonly Vector3 SocketOffset = new Vector3(-0.975f, 0.88f, 0.85f); internal static readonly Vector3 RearSocketOffset = new Vector3(-0.975f, 0.88f, -1.15f); internal static readonly Vector3 TargetCenter = new Vector3(-0.035f, 0.115f, 0f); internal static readonly Vector3 HalfExtents = new Vector3(0.115f, 0.23f, 0.25f); internal static readonly Vector3 Offset = SocketOffset + TargetCenter; internal static readonly Vector3 RearOffset = RearSocketOffset + TargetCenter; private RailVehicle? _cart; private Transform? _arm; private bool? _shownCoupled; private void Awake() { _cart = ((Component)this).GetComponentInParent(); _arm = ((Component)this).transform.Find("vr_release_arm"); RefreshPose(); } private void Update() { RefreshPose(); } private void RefreshPose() { //IL_0079: Unknown result type (might be due to invalid IL or missing references) bool flag = Object.op_Implicit((Object)(object)_cart) && _cart.IsReady && _cart.HasCouplingAt(Front); if (Object.op_Implicit((Object)(object)_arm) && _shownCoupled != flag) { _arm.localRotation = Quaternion.Euler(flag ? 35f : (-35f), 0f, 0f); _shownCoupled = flag; } } public float GetHoverOffset() { return 0f; } public string GetHoverName() { if (!Front) { return "Rear coupling lever"; } return "Front coupling lever"; } public string GetHoverText() { string text = ((!Object.op_Implicit((Object)(object)_cart) || !_cart.IsReady) ? "\nCoupling unavailable" : (_cart.HasCouplingAt(Front) ? "\n[$KEY_Use] Uncouple this end\nStop the train before releasing." : "\n[$KEY_Use] Couple this end\nStop and align an open coupler nearby.")); return Localization.instance.Localize(GetHoverName() + text); } public bool Interact(Humanoid user, bool hold, bool alt) { if (!hold && Object.op_Implicit((Object)(object)_cart)) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer)) { return _cart.UseCouplingEnd(val, Front); } } return false; } public bool UseItem(Humanoid user, ItemData item) { return false; } } public sealed class RailGate : MonoBehaviour, Hoverable { public Transform LeftLeaf; public Transform RightLeaf; public float OpenDegrees = 100f; private const string AmountKey = "vr_gate_amount"; private const string OpenKey = "vr_gate_open"; private const string OwnerKey = "vr_gate_owner"; private const string RevisionKey = "vr_gate_revision"; private const string UntilKey = "vr_gate_until"; private const string ApproachRpc = "VR_GateApproach_v1"; private static readonly HashSet Gates = new HashSet(); private readonly Dictionary _requests = new Dictionary(); private ZNetView _view; private BoxCollider[] _leaves = Array.Empty(); private float _amount; private bool _open; private bool _blocked; private float _clearAfter; private float _nextScan; private float _nextPublish; private float _nextInitialize; private bool _started; private bool _wasOwner; private ushort _revision; private static long Now { get { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return 0L; } return (long)(ZNet.instance.GetTimeSeconds() * 1000.0); } } private bool Ready { get { if (_started && Object.op_Implicit((Object)(object)_view) && _view.IsValid() && Object.op_Implicit((Object)(object)LeftLeaf)) { return Object.op_Implicit((Object)(object)RightLeaf); } return false; } } private bool Passable { get { if (!Ready || _leaves.Length != 2 || _amount < 0.9999f) { return false; } ZDO zDO = _view.GetZDO(); long num = zDO.GetLong("vr_gate_until", 0L); if (zDO.GetBool("vr_gate_open", false) && ReadAmount() >= 0.9999f && zDO.GetLong("vr_gate_owner", 0L) == zDO.GetOwner() && zDO.GetInt("vr_gate_revision", -1) == zDO.OwnerRevision && num > Now) { return num <= Now + 1500; } return false; } } private void Awake() { _view = ((Component)this).GetComponent(); if (Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { _amount = ReadAmount(); } ApplyPose(); } private void Start() { TryInitialize(); } private void TryInitialize() { if (_started || Time.time < _nextInitialize) { return; } _nextInitialize = Time.time + 0.5f; if (!Object.op_Implicit((Object)(object)_view)) { _view = ((Component)this).GetComponent(); } if (Object.op_Implicit((Object)(object)_view) && _view.IsValid() && Object.op_Implicit((Object)(object)LeftLeaf) && Object.op_Implicit((Object)(object)RightLeaf)) { List list = new List(); RailGateLeaf[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (RailGateLeaf railGateLeaf in componentsInChildren) { list.AddRange(((Component)railGateLeaf).GetComponentsInChildren(true)); } _leaves = list.ToArray(); _amount = ReadAmount(); ApplyPose(); if (_amount > 0f) { HoldForOpening(); } _view.Register("VR_GateApproach_v1", (Action)RequestApproach); Gates.Add(this); _started = true; } } private float ReadAmount() { float num = _view.GetZDO().GetFloat("vr_gate_amount", 0f); if (!float.IsNaN(num) && !float.IsInfinity(num)) { return Mathf.Clamp01(num); } return 0f; } private void ApplyPose() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)LeftLeaf)) { LeftLeaf.localRotation = Quaternion.Euler(0f, OpenDegrees * _amount, 0f); } if (Object.op_Implicit((Object)(object)RightLeaf)) { RightLeaf.localRotation = Quaternion.Euler(0f, (0f - OpenDegrees) * _amount, 0f); } } private void FixedUpdate() { if (!_started) { TryInitialize(); } if (!Ready) { return; } if (!_view.IsOwner()) { _wasOwner = false; _open = _view.GetZDO().GetBool("vr_gate_open", false); _amount = Mathf.MoveTowards(_amount, ReadAmount(), Time.fixedDeltaTime); ApplyPose(); return; } if (!_wasOwner || _revision != _view.GetZDO().OwnerRevision) { _wasOwner = true; _revision = _view.GetZDO().OwnerRevision; _amount = ReadAmount(); ApplyPose(); if (_amount > 0f) { HoldForOpening(); } _nextScan = (_nextPublish = 0f); } if (Time.time >= _nextScan) { _nextScan = Time.time + 0.1f; if (TrainNeedsGate()) { HoldForOpening(); } bool flag = Time.time < _clearAfter; if (_open != flag) { _nextPublish = 0f; } _open = flag; } float num = Mathf.MoveTowards(_amount, _open ? 1f : 0f, Mathf.Min(Time.fixedDeltaTime, 0.05f) / 2f); _blocked = num != _amount && !ClearStep(num); if (!_blocked) { _amount = num; } else if (!_open) { _open = true; HoldForOpening(); _nextPublish = 0f; } ApplyPose(); if (Time.time >= _nextPublish) { ZDO zDO = _view.GetZDO(); zDO.Set("vr_gate_amount", _amount); zDO.Set("vr_gate_open", _open); zDO.Set("vr_gate_owner", zDO.GetOwner()); zDO.Set("vr_gate_revision", (int)zDO.OwnerRevision); zDO.Set("vr_gate_until", Now + 1000); _nextPublish = Time.time + ((_amount == 0f && !_open) ? 1f : 0.1f); } } private bool TrainNeedsGate() { foreach (RailVehicle.GateTrain item in RailVehicle.GateTrains()) { IReadOnlyList readOnlyList = item.Bodies(((Component)this).transform); foreach (RailGateBody item2 in readOnlyList) { if (RailGatePolicy.OverlapsDoor(item2, 2.5, item.Complete ? 3.2 : 8.0, 0.0, 4.0) || RailGatePolicy.CanWait(item2, 2.5, 0.0, 4.0) || RailGatePolicy.CanApproach(item2, 2.5, 0.75, 0.0, 4.0)) { return true; } } if (RailGatePolicy.TrainStraddles(readOnlyList, item.Complete, 2.5, 0.75, 0.0, 4.0)) { return true; } } return false; } internal bool Near(Vector3 point, float distance) { //IL_0000: 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_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) Vector3 val = point - ((Component)this).transform.position; return ((Vector3)(ref val)).sqrMagnitude <= distance * distance; } private void HoldForOpening() { float num = (float)((double)(1f - _amount) * 2.0 + 2.0); _clearAfter = Mathf.Max(_clearAfter, Time.time + num); } private void RequestApproach(long sender, string rootId) { if (Ready && _view.IsOwner() && RailVehicle.GateRequestValid(sender, rootId, this)) { HoldForOpening(); _open = true; _nextPublish = 0f; } } private void Request(RailVehicle root) { string persistentId = root.PersistentId; if (!_requests.TryGetValue(persistentId, out var value) || !(Time.time < value)) { if (_requests.Count > 128) { _requests.Clear(); } _requests[persistentId] = Time.time + 0.25f; if (_view.IsOwner()) { RequestApproach(root.View.GetZDO().GetOwner(), persistentId); } else if (_view.HasOwner()) { _view.InvokeRPC("VR_GateApproach_v1", new object[1] { persistentId }); } } } internal static bool AllowTrainStep(RailVehicle root, List train, List next, bool forward) { //IL_004f: 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_0090: 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_00ca: 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) //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) //IL_00eb: 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_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_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015e: 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_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0176: 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_018a: 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_018e: 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) bool flag = true; foreach (RailGate gate in Gates) { if (!Object.op_Implicit((Object)(object)gate) || !gate.Ready) { continue; } bool flag2 = false; bool flag3 = false; for (int i = 0; i < train.Count; i++) { RailVehicle railVehicle = train[i]; if (!gate.Near(((Component)railVehicle).transform.position, 16f + Mathf.Abs(root.Speed) * 0.05f)) { continue; } RailGateBody railGateBody = railVehicle.GateBody(((Component)gate).transform, ((Component)railVehicle).transform.position, ((Component)railVehicle).transform.rotation, root.PersistentId, Vector3.zero); RailPose railPose = RailVehiclePose.Sample(RailSegment.Network, next[i]); RailGateBody railGateBody2 = railVehicle.GateBody(((Component)gate).transform, RailSegment.ToUnity(railPose.Position), Quaternion.LookRotation(RailSegment.ToUnity(railPose.Tangent), Vector3.up), root.PersistentId, Vector3.zero); Vector3 val = Vector3.Min(RailSegment.ToUnity(railGateBody.Center - railGateBody.HalfExtents), RailSegment.ToUnity(railGateBody2.Center - railGateBody2.HalfExtents)); Vector3 val2 = Vector3.Max(RailSegment.ToUnity(railGateBody.Center + railGateBody.HalfExtents), RailSegment.ToUnity(railGateBody2.Center + railGateBody2.HalfExtents)); if (RailGatePolicy.OverlapsDoor(new RailGateBody(railVehicle.PersistentId, root.PersistentId, RailSegment.ToRail((val + val2) * 0.5f), RailSegment.ToRail((val2 - val) * 0.5f), new RailVector(0.0, 0.0, 0.0), railGateBody.Forward), 2.5, 3.2, 0.0, 4.0)) { flag2 = true; double num = railGateBody.Center.Z - railGateBody.HalfExtents.Z; double num2 = railGateBody.Center.Z + railGateBody.HalfExtents.Z; if ((!(num >= 0.75) || !(railGateBody2.Center.Z - railGateBody2.HalfExtents.Z > num + 1E-06)) && (!(num2 <= -0.75) || !(railGateBody2.Center.Z + railGateBody2.HalfExtents.Z < num2 - 1E-06))) { flag3 = true; } } } if (flag2 || root.GateApproach(gate, train, forward, Mathf.Abs(root.Speed))) { gate.Request(root); } if (flag3 && !gate.Passable) { flag = false; } } if (!flag) { root.WaitAtGate(); } return flag; } private bool ClearStep(float next) { //IL_006f: 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_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) //IL_0097: 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_009f: 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_00a9: 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_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_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_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) if (_leaves.Length != 2) { return false; } BoxCollider[] leaves = _leaves; foreach (BoxCollider val in leaves) { if (!Object.op_Implicit((Object)(object)val)) { return false; } Transform transform = ((Component)((Component)val).GetComponentInParent()).transform; float num = (((Object)(object)transform == (Object)(object)LeftLeaf) ? 1 : (-1)); for (int j = 1; j <= 2; j++) { float num2 = Mathf.Lerp(_amount, next, (float)j * 0.5f); Quaternion val2 = ((Component)this).transform.rotation * Quaternion.Euler(0f, num * OpenDegrees * num2, 0f); Vector3 val3 = transform.position + val2 * val.center; Vector3 val4 = val.size * 0.5f + Vector3.one * 0.06f; Collider[] array = Physics.OverlapBox(val3, val4, val2, -1, (QueryTriggerInteraction)1); foreach (Collider val5 in array) { if (Object.op_Implicit((Object)(object)val5) && !((Component)val5).transform.IsChildOf(((Component)this).transform) && !Object.op_Implicit((Object)(object)((Component)val5).GetComponentInParent()) && !Object.op_Implicit((Object)(object)((Component)val5).GetComponentInParent()) && !RailNaturalResource.IgnoreRailObstacle(val5) && (Object.op_Implicit((Object)(object)((Component)val5).GetComponentInParent()) || !Physics.GetIgnoreLayerCollision(((Component)this).gameObject.layer, ((Component)val5).gameObject.layer))) { return false; } } } } return true; } public string GetHoverName() { return "Automatic rail gate"; } public float GetHoverOffset() { return 0f; } public string GetHoverText() { return GetHoverName() + "\n" + (_blocked ? "Clear the space where the doors swing." : ((!_open) ? ((_amount > 0f) ? "Closing" : "Opens automatically for approaching trains") : ((_amount >= 0.9999f) ? "Open — waiting for the whole train to clear" : "Opening for a train"))); } private void OnDestroy() { Gates.Remove(this); } } public sealed class RailGateLeaf : MonoBehaviour { } public sealed class RailGateHover : MonoBehaviour, Hoverable { public float GetHoverOffset() { return 0f; } public string GetHoverName() { return ((Component)this).GetComponentInParent()?.GetHoverName() ?? "Automatic rail gate"; } public string GetHoverText() { return ((Component)this).GetComponentInParent()?.GetHoverText() ?? ""; } } internal static class RailIcons { private const string ResourcePrefix = "VikingRail.Icons."; private static readonly Dictionary Sprites = new Dictionary(); private static readonly List Textures = new List(); private static readonly HashSet FailedIcons = new HashSet(); private static Func loadImage; public static Sprite Get(string prefabName) { //IL_00a4: 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_00ba: 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_00c9: Expected O, but got Unknown //IL_0117: 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) if (Sprites.TryGetValue(prefabName, out var value)) { return value; } if (FailedIcons.Contains(prefabName)) { return null; } Texture2D val = null; Sprite val2 = null; try { string text = "VikingRail.Icons." + prefabName + ".png"; byte[] image; using (Stream stream = typeof(RailIcons).Assembly.GetManifestResourceStream(text)) { if (stream == null) { throw new FileNotFoundException("Embedded icon was not found: " + text); } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); image = memoryStream.ToArray(); } val = new Texture2D(256, 256, (TextureFormat)4, false) { name = prefabName + "_icon_texture", filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; if (!LoadImage(val, image)) { throw new InvalidDataException("The embedded PNG could not be decoded."); } if (((Texture)val).width != 256 || ((Texture)val).height != 256) { throw new InvalidDataException("Hammer icons must be 256 by 256 pixels."); } val2 = Sprite.Create(val, new Rect(0f, 0f, 256f, 256f), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0); if ((Object)(object)val2 == (Object)null) { throw new InvalidOperationException("Unity could not create the Hammer icon sprite."); } ((Object)val2).name = prefabName + "_icon"; Sprites.Add(prefabName, val2); Textures.Add(val); return val2; } catch (Exception ex) { if ((Object)(object)val2 != (Object)null) { Object.Destroy((Object)(object)val2); } if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } FailedIcons.Add(prefabName); RailPlugin.Warn("Could not load icon for " + prefabName + "; keeping the vanilla icon. " + ex.Message); return null; } } private static bool LoadImage(Texture2D texture, byte[] image) { if (loadImage == null) { Type type = Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule", throwOnError: true); MethodInfo method = type.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[3] { typeof(Texture2D), typeof(byte[]), typeof(bool) }, null); if (method == null) { throw new MissingMethodException(type.FullName, "LoadImage(Texture2D, byte[], bool)"); } loadImage = (Func)Delegate.CreateDelegate(typeof(Func), method); } return loadImage(texture, image, arg3: true); } public static void Cleanup() { foreach (Sprite value in Sprites.Values) { if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } } foreach (Texture2D texture in Textures) { if ((Object)(object)texture != (Object)null) { Object.Destroy((Object)(object)texture); } } Sprites.Clear(); Textures.Clear(); FailedIcons.Clear(); loadImage = null; } } internal static class RailLightingView { internal static bool TryGetPosition(out Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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) position = Vector3.zero; if (!Object.op_Implicit((Object)(object)Player.m_localPlayer)) { return false; } Camera mainCamera = Utils.GetMainCamera(); if (!Object.op_Implicit((Object)(object)mainCamera)) { return false; } position = ((Component)mainCamera).transform.position; return true; } } public sealed class RailMountCart : MonoBehaviour { internal const int Prepared = 1; internal const int Committed = 2; internal const int Detaching = 3; internal const long LeaseMilliseconds = 12000L; private const string Prefix = "vikingrail_mount_"; private static readonly HashSet Hosts = new HashSet(); private ZNetView _view; private RailVehicle _vehicle; private bool _registered; private float _nextPoll; private float _nextScan; internal ZNetView View => _view; internal RailVehicle Vehicle => _vehicle; internal bool Ready { get { if (_registered && Object.op_Implicit((Object)(object)_view) && _view.IsValid() && Object.op_Implicit((Object)(object)_vehicle)) { return _vehicle.IsReady; } return false; } } internal string Identity { get { if (!Ready) { return ""; } return _vehicle.PersistentId; } } internal static long Now { get { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return 0L; } return (long)(ZNet.instance.GetTimeSeconds() * 1000.0); } } internal bool HasOccupants { get { if (Ready) { return Enumerable.Range(0, 2).Any((int s) => Phase(s) != 0 || ChildIdentity(s).Length != 0); } return false; } } internal bool Busy { get { if (Ready) { return Enumerable.Range(0, 2).Any((int s) => Phase(s) == 1 || Phase(s) == 3); } return false; } } internal IEnumerable Attachments => RailMountedObject.Loaded.Where((RailMountedObject o) => Object.op_Implicit((Object)(object)o) && (Object)(object)o.Vehicle == (Object)(object)_vehicle); internal bool CanChange { get { if (Ready && _vehicle.MountChangesAllowed) { if (!_view.IsOwner()) { if (Object.op_Implicit((Object)(object)ZNet.instance)) { return _view.GetZDO().GetLong("vikingrail_moving_until", 0L) <= Now; } return false; } return _vehicle.Speed == 0f; } return false; } } internal static string Key(int slot, string field) { return "vikingrail_mount_" + slot + "_" + field; } internal int Phase(int slot) { if (!Ready) { return 0; } return _view.GetZDO().GetInt(Key(slot, "phase"), 0); } internal string Token(int slot) { if (!Ready) { return ""; } return _view.GetZDO().GetString(Key(slot, "token"), ""); } internal string ChildIdentity(int slot) { if (!Ready) { return ""; } return _view.GetZDO().GetString(Key(slot, "guid"), ""); } internal ZDOID ChildId(int slot) { //IL_0024: 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) if (!Ready) { return ZDOID.None; } return _view.GetZDO().GetZDOID(Key(slot, "id")); } internal long Expires(int slot) { if (!Ready) { return 0L; } return _view.GetZDO().GetLong(Key(slot, "until"), 0L); } internal int Attempt(int slot) { if (!Ready) { return 0; } return _view.GetZDO().GetInt(Key(slot, "attempt"), 0); } internal Vector3 Socket(int slot) { //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) Vector3 vector = RailMountPolicy.Socket(slot); return ((Component)this).transform.TransformPoint(new Vector3(vector.X, vector.Y, vector.Z)); } internal static RailMountCart? Find(string identity) { return Hosts.FirstOrDefault((RailMountCart h) => Object.op_Implicit((Object)(object)h) && h.Ready && h.Identity == identity); } internal static RailMountCart? Find(ZDOID id) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) return Hosts.FirstOrDefault((RailMountCart h) => Object.op_Implicit((Object)(object)h) && h.Ready && h.View.GetZDO().m_uid == id); } internal RailMountedObject? Attachment(int slot) { return RailMountedObject.Find(ChildIdentity(slot)); } private void Awake() { _view = ((Component)this).GetComponent(); _vehicle = ((Component)this).GetComponent(); } private void Start() { Register(); } private void Register() { if (!_registered && Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { _registered = true; Hosts.Add(this); _view.Register("VR_MountChange", (Action)RequestChange); _view.Register("VR_MountChildReply", (Method)ChildReply); _view.Register("VR_MountFeedback", (Action)Feedback); RailMountedObject.EnsureDestructionTracking(); } } private void Update() { Register(); if (!Ready) { return; } if (Time.unscaledTime >= _nextScan) { _nextScan = Time.unscaledTime + 2f; RailMountedObject.Discover(); } if (_view.IsOwner() && !(Time.unscaledTime < _nextPoll)) { _nextPoll = Time.unscaledTime + 0.5f; for (int i = 0; i < 2; i++) { Reconcile(i); } } } private void OnDestroy() { Hosts.Remove(this); } internal bool Request(Player player, int slot) { //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_0155: 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_012a: 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_00b7: 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_00da: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !ValidSlot(slot) || !Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return false; } if (!CanChange || (Busy && Phase(slot) != 3)) { Tell(player, "Uncouple both ends, park and clear the cart before changing its mounted objects."); return false; } RailMountedObject.Discover(force: true); ZDOID val = ZDOID.None; if (Phase(slot) == 0) { RailMountedObject railMountedObject = null; float num = 2.5f; foreach (RailMountedObject item in RailMountedObject.Loaded) { if (Object.op_Implicit((Object)(object)item) && item.Ready && !item.IsLocked && item.CanPrepare(out string _)) { float num2 = Vector3.Distance(((Component)item).transform.position, Socket(slot)); if (!(num2 > num) && !(Vector3.Distance(((Component)player).transform.position, ((Component)item).transform.position) > 4f)) { railMountedObject = item; num = num2; } } } if (!Object.op_Implicit((Object)(object)railMountedObject)) { Tell(player, "Place a supported dummy, sign, item stand or standing torch within 2.5 m of this pad, then use the pad."); return false; } val = railMountedObject.View.GetZDO().m_uid; } _view.InvokeRPC("VR_MountChange", new object[3] { player.GetPlayerID(), slot, val }); return true; } private static bool ValidSlot(int slot) { if (slot >= 0) { return slot < 2; } return false; } internal bool ValidRequester(int slot, out Player player) { player = null; if (!Ready || !ValidSlot(slot)) { return false; } ZDO zDO = _view.GetZDO(); return ValidatePlayer(zDO.GetLong(Key(slot, "peer"), 0L), zDO.GetLong(Key(slot, "player"), 0L), slot, out player); } private bool ValidatePlayer(long peer, long playerId, int slot, out Player player) { //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_0078: 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) player = Player.GetPlayer(playerId); if (peer != 0L && playerId != 0L && Object.op_Implicit((Object)(object)player) && ((Character)player).GetOwner() == peer && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && !((Character)player).IsAttached() && player.GetDoodadController() == null && Vector3.Distance(((Component)player).transform.position, Socket(slot)) <= 4f && RailWardAccess.Allows(((Component)this).transform.position, playerId)) { return RailWardAccess.Allows(Socket(slot), playerId); } return false; } private void RequestChange(long sender, long playerId, int slot, ZDOID candidate) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0114: 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_01d9: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !_view.IsOwner() || !ValidSlot(slot)) { return; } if (!CanChange || (Busy && (!((ZDOID)(ref candidate)).IsNone() || Phase(slot) != 3)) || !ValidatePlayer(sender, playerId, slot, out Player player)) { Reply(sender, success: false, "Uncouple both ends and park the cart; finish other interactions before changing its mounts."); return; } bool flag = ((ZDOID)(ref candidate)).IsNone(); RailMountedObject railMountedObject = (flag ? Attachment(slot) : RailMountedObject.Find(candidate)); if (!Object.op_Implicit((Object)(object)railMountedObject) || !railMountedObject.Ready || !railMountedObject.View.HasOwner()) { Reply(sender, success: false, "Wait for the existing object and its owner to load."); return; } bool num; if (!flag) { if (Phase(slot) == 0) { num = railMountedObject.IsLocked; goto IL_00dd; } } else if (Phase(slot) == 2 || Phase(slot) == 3) { num = !Matches(railMountedObject, slot, requireActive: true); goto IL_00dd; } goto IL_00df; IL_00dd: if (!num) { if (!flag && (Vector3.Distance(((Component)railMountedObject).transform.position, Socket(slot)) > 2.5f || Vector3.Distance(((Component)player).transform.position, ((Component)railMountedObject).transform.position) > 4f || !railMountedObject.CanPrepare(out string _))) { Reply(sender, success: false, "Close the object's controls and place it close to the mounting pad."); return; } if (!RailWardAccess.Allows(((Component)railMountedObject).transform.position, playerId)) { Reply(sender, success: false, "A ward protects that object."); return; } string text = (flag ? Token(slot) : Guid.NewGuid().ToString("N")); ZDO zDO = _view.GetZDO(); zDO.Set(Key(slot, "token"), text); zDO.Set(Key(slot, "guid"), railMountedObject.Identity); zDO.Set(Key(slot, "id"), railMountedObject.View.GetZDO().m_uid); zDO.Set(Key(slot, "peer"), sender); zDO.Set(Key(slot, "player"), playerId); zDO.Set(Key(slot, "until"), Now + 12000); int num2 = zDO.GetInt(Key(slot, "attempt"), 0); zDO.Set(Key(slot, "attempt"), (num2 < 1 || num2 == int.MaxValue) ? 1 : (num2 + 1)); zDO.Set(Key(slot, "phase"), (!flag) ? 1 : 3); SendChild(slot, railMountedObject); Reply(sender, success: true, flag ? "Preparing a clear place beside the cart…" : "Waiting for the object's owner to secure it…"); return; } goto IL_00df; IL_00df: Reply(sender, success: false, "The mounting pad or object is already reserved."); } internal bool Matches(RailMountedObject child, int slot, bool requireActive) { int num = Phase(slot); if (Ready && child.Ready && ValidSlot(slot) && child.HostIdentity == Identity && child.Slot == slot && ChildIdentity(slot) == child.Identity && Token(slot) == child.Token) { if (!requireActive) { return num != 0; } if (num != 2) { return num == 3; } return true; } return false; } private void SendChild(int slot, RailMountedObject child) { //IL_003c: 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) if (child.Ready && child.View.HasOwner()) { ZDOMan instance = ZDOMan.instance; if (instance != null) { instance.ForceSendZDO(child.View.GetZDO().GetOwner(), _view.GetZDO().m_uid); } child.View.InvokeRPC("VR_MountedChange", new object[4] { _view.GetZDO().m_uid, slot, Token(slot), Attempt(slot) }); } } private void ChildReply(long sender, int slot, string token, int attempt, bool success, string reason) { if (!Ready || !_view.IsOwner() || !ValidSlot(slot) || Token(slot) != token || Attempt(slot) != attempt || reason.Length > 512) { return; } RailMountedObject railMountedObject = Attachment(slot); if (Object.op_Implicit((Object)(object)railMountedObject) && railMountedObject.Ready && railMountedObject.View.GetZDO().GetOwner() == sender) { Reconcile(slot); long num = _view.GetZDO().GetLong(Key(slot, "peer"), 0L); if (num != 0L && reason.Length != 0) { Reply(num, success, reason); } } } private void Reconcile(int slot) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) int num = Phase(slot); if (num == 0) { return; } if (RailMountedObject.WasDestroyed(ChildIdentity(slot))) { ClearSlot(slot); return; } if (num == 1 && (Now > Expires(slot) || !CanChange || !ValidRequester(slot, out Player _))) { ClearSlot(slot); return; } RailMountedObject railMountedObject = Attachment(slot); if (!Object.op_Implicit((Object)(object)railMountedObject) || !railMountedObject.Ready) { return; } _view.GetZDO().Set(Key(slot, "id"), railMountedObject.View.GetZDO().m_uid); if (railMountedObject.DetachedFrom(Identity, slot, Token(slot))) { ClearSlot(slot); return; } if (railMountedObject.Rejected(Identity, slot, Token(slot), Attempt(slot))) { switch (num) { case 1: ClearSlot(slot); break; case 3: if (Matches(railMountedObject, slot, requireActive: true)) { _view.GetZDO().Set(Key(slot, "phase"), 2); _view.GetZDO().Set(Key(slot, "until"), 0L); } break; } return; } switch (num) { case 1: if (Matches(railMountedObject, slot, requireActive: false)) { if (!railMountedObject.MountSpaceClear(this)) { ClearSlot(slot); break; } _view.GetZDO().Set(Key(slot, "phase"), 2); _view.GetZDO().Set(Key(slot, "until"), 0L); ZDOMan instance = ZDOMan.instance; if (instance != null) { instance.ForceSendZDO(railMountedObject.View.GetZDO().GetOwner(), _view.GetZDO().m_uid); } } else { SendChild(slot, railMountedObject); } break; case 3: SendChild(slot, railMountedObject); break; } } private void ClearSlot(int slot) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) ZDO zDO = _view.GetZDO(); zDO.Set(Key(slot, "phase"), 0); zDO.Set(Key(slot, "id"), ZDOID.None); zDO.Set(Key(slot, "guid"), ""); zDO.Set(Key(slot, "token"), ""); zDO.Set(Key(slot, "until"), 0L); } internal static void ChildDestroyed(string identity) { RailMountCart[] array = Hosts.ToArray(); foreach (RailMountCart railMountCart in array) { if (!Object.op_Implicit((Object)(object)railMountCart) || !railMountCart.Ready || !railMountCart.View.IsOwner()) { continue; } for (int j = 0; j < 2; j++) { if (railMountCart.ChildIdentity(j) == identity) { railMountCart.ClearSlot(j); } } } } internal static void Cleanup() { Hosts.Clear(); } internal void FollowMounts() { foreach (RailMountedObject attachment in Attachments) { attachment.FollowMount(persist: true); } } internal static bool TrainBusy(IEnumerable train) { return train.Any(delegate(RailVehicle v) { if (Object.op_Implicit((Object)(object)v)) { RailMountCart component = ((Component)v).GetComponent(); if (component != null) { return component.Busy; } } return false; }); } internal static bool PrepareTrain(IEnumerable train, out string reason) { foreach (RailVehicle item in train) { RailMountCart railMountCart = (Object.op_Implicit((Object)(object)item) ? ((Component)item).GetComponent() : null); if (!Object.op_Implicit((Object)(object)railMountCart)) { continue; } if (!railMountCart.Ready || railMountCart.Busy) { reason = "Finish the mounting operation before moving."; return false; } for (int i = 0; i < 2; i++) { if (railMountCart.Phase(i) != 0) { RailMountedObject railMountedObject = railMountCart.Attachment(i); if (!Object.op_Implicit((Object)(object)railMountedObject) || !railMountedObject.Alive || !railMountCart.Matches(railMountedObject, i, requireActive: true) || !railMountedObject.View.HasOwner() || !railMountedObject.MotionCompatible) { reason = "A mounted object is missing or still synchronizing. Wait nearby for it to load."; return false; } railMountedObject.UpdateMotionMount(); if (!railMountedObject.MotionCompatible) { reason = "A mounted object's movement adapter is unavailable."; return false; } } } } reason = ""; return true; } private void Reply(long peer, bool success, string reason) { _view.InvokeRPC(peer, "VR_MountFeedback", new object[2] { success, reason }); } private void Feedback(long sender, bool success, string reason) { if (Ready && sender == _view.GetZDO().GetOwner()) { Tell(Player.m_localPlayer, reason); } } private static void Tell(Player? player, string reason) { if (Object.op_Implicit((Object)(object)player)) { ((Character)player).Message((MessageType)2, reason, 0, (Sprite)null, false); } } } public sealed class RailMountPad : MonoBehaviour, Hoverable, Interactable { public int Slot; private RailMountCart? Host => ((Component)this).GetComponentInParent(); public float GetHoverOffset() { return 0f; } public string GetHoverName() { return "Mounting pad " + (Slot + 1); } public string GetHoverText() { return GetHoverName() + "\n[$KEY_Use] " + ((Object.op_Implicit((Object)(object)Host) && Host.Phase(Slot) != 0) ? "Detach existing object" : "Mount nearby dummy or utility piece"); } public bool Interact(Humanoid user, bool hold, bool alt) { if (!hold && !alt) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null && Object.op_Implicit((Object)(object)Host)) { return Host.Request(val, Slot); } } return false; } public bool UseItem(Humanoid user, ItemData item) { return false; } } internal static class RailMountAccess { private static readonly ConditionalWeakTable Inventories = new ConditionalWeakTable(); internal static void Remember(Container container) { RailMountedObject componentInParent = ((Component)container).GetComponentInParent(); Inventory inventory = container.GetInventory(); if (Object.op_Implicit((Object)(object)componentInParent) && inventory != null && !Inventories.TryGetValue(inventory, out RailMountedObject _)) { Inventories.Add(inventory, componentInParent); } } internal static bool CanMutate(Inventory? inventory) { if (inventory == null) { return true; } if (!Inventories.TryGetValue(inventory, out RailMountedObject value)) { foreach (RailMountedObject item in RailMountedObject.Loaded) { if (Object.op_Implicit((Object)(object)item)) { Container component = ((Component)item).GetComponent(); if (Object.op_Implicit((Object)(object)component) && component.GetInventory() == inventory) { Remember(component); value = item; break; } } } if (value == null) { return true; } } if (Object.op_Implicit((Object)(object)value) && value.Ready) { return !value.IsLocked; } return false; } internal static bool Locked(Component component) { RailMountedObject componentInParent = component.GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent)) { return componentInParent.IsLocked; } return false; } internal static bool RemovalBlocked(Component component) { if (Locked(component)) { return true; } RailVehicle component2 = component.GetComponent(); if (Object.op_Implicit((Object)(object)component2)) { if (!component2.HasMountedObjects) { return component2.MountServiceBusy; } return true; } return false; } internal static IEnumerable Methods(Type type, Type returns, params string[] names) { foreach (string name in names) { MethodInfo[] methods = type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name == name && methodInfo.ReturnType == returns) { yield return methodInfo; } } } } internal static void Explain() { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, "Use the cart's mounting pad to detach this piece before editing it. Park and uncouple both ends first.", 0, (Sprite)null, false); } } } [HarmonyPatch] internal static class RailMountedInteractionPatch { [HarmonyTargetMethods] private static IEnumerable Targets() { Type[] array = new Type[4] { typeof(Container), typeof(Sign), typeof(ItemStand), typeof(Fireplace) }; foreach (Type type in array) { foreach (MethodBase item in RailMountAccess.Methods(type, typeof(bool), "Interact", "UseItem")) { yield return item; } } } [HarmonyPrefix] [HarmonyPriority(800)] private static bool Prefix(Component __instance, ref bool __result) { if (!RailMountAccess.Locked(__instance)) { return true; } RailMountAccess.Explain(); __result = false; return false; } } [HarmonyPatch(typeof(Container), "CheckAccess")] internal static class RailMountedContainerAccessPatch { [HarmonyPrefix] [HarmonyPriority(800)] private static bool Prefix(Container __instance, ref bool __result) { if (!RailMountAccess.Locked((Component)(object)__instance)) { return true; } __result = false; return false; } } [HarmonyPatch] internal static class RailMountedEditRequestPatch { [HarmonyTargetMethods] private static IEnumerable Targets() { foreach (MethodBase item in RailMountAccess.Methods(typeof(Container), typeof(void), "RPC_RequestOpen", "RPC_RequestStack", "RPC_RequestTakeAll")) { yield return item; } foreach (MethodBase item2 in RailMountAccess.Methods(typeof(ItemStand), typeof(void), "RPC_RequestOwn", "RPC_DropItem", "RPC_DestroyAttachment", "UpdateAttach")) { yield return item2; } foreach (MethodBase item3 in RailMountAccess.Methods(typeof(Fireplace), typeof(void), "RPC_AddFuel", "RPC_ToggleOn", "RPC_AddFuelAmount", "RPC_SetFuelAmount")) { yield return item3; } foreach (MethodBase item4 in RailMountAccess.Methods(typeof(Sign), typeof(void), "SetText")) { yield return item4; } } [HarmonyPrefix] [HarmonyPriority(800)] private static bool Prefix(Component __instance) { return !RailMountAccess.Locked(__instance); } } [HarmonyPatch] internal static class RailMountedContainerReplyPatch { [HarmonyTargetMethods] private static IEnumerable Targets() { foreach (MethodBase item in RailMountAccess.Methods(typeof(Container), typeof(void), "RPC_OpenResponse", "RPC_OpenRespons", "OpenRespons", "RPC_StackResponse", "RPC_StackRespons", "StackRespons", "RPC_TakeAllResponse", "RPC_TakeAllRespons", "TakeAllRespons")) { ParameterInfo[] parameters = item.GetParameters(); if (parameters.Length == 2 && parameters[0].ParameterType == typeof(long) && parameters[1].ParameterType == typeof(bool)) { yield return item; } } } [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix(Container __instance, ref bool __1) { if (RailMountAccess.Locked((Component)(object)__instance)) { __1 = false; } } } [HarmonyPatch(typeof(Piece), "CanBeRemoved")] internal static class RailMountedRemovalPatch { [HarmonyPostfix] private static void Postfix(Piece __instance, ref bool __result) { if (RailMountAccess.RemovalBlocked((Component)(object)__instance)) { __result = false; } } } [HarmonyPatch(typeof(WearNTear), "RPC_Remove")] internal static class RailMountedRemoveRequestPatch { [HarmonyPrefix] [HarmonyPriority(800)] private static bool Prefix(WearNTear __instance) { return !RailMountAccess.RemovalBlocked((Component)(object)__instance); } } public sealed class RailMountedObject : MonoBehaviour { internal const string HostKey = "vikingrail_object_host"; internal const string HostGuidKey = "vikingrail_object_host_guid"; internal const string SlotKey = "vikingrail_object_slot"; internal const string TokenKey = "vikingrail_object_token"; private const string PhaseKey = "vikingrail_object_phase"; private const string RotationKey = "vikingrail_object_rotation"; private const string LastHostKey = "vikingrail_object_detached_host"; private const string LastSlotKey = "vikingrail_object_detached_slot"; private const string LastTokenKey = "vikingrail_object_detached_token"; private const string ReturnPendingKey = "vikingrail_object_detach_pending"; private const string RejectHostKey = "vikingrail_object_reject_host"; private const string RejectSlotKey = "vikingrail_object_reject_slot"; private const string RejectTokenKey = "vikingrail_object_reject_token"; private const string RejectAttemptKey = "vikingrail_object_reject_attempt"; private static float _nextDiscovery; private static readonly HashSet Objects = new HashSet(); private static readonly HashSet Destroyed = new HashSet(); private static ZDOMan? _manager; private static readonly FieldInfo? QueuedStandItem = AccessTools.Field(typeof(ItemStand), "m_queuedItem"); private static readonly FieldInfo? CurrentContainer = AccessTools.Field(typeof(InventoryGui), "m_currentContainer"); private ZNetView _view; private bool _registered; private Rigidbody? _mountBody; private Character? _mountCharacter; private ZSyncTransform? _mountSync; private WearNTear? _mountWear; private bool _motionInitialized; private bool _motionHeld; private bool _motionFailed; private bool _bodyGravity; private RigidbodyConstraints _bodyConstraints; private bool _syncEnabled; private bool _syncPosition; private bool _syncRotation; private bool _syncGravity; private bool _wearSupport; private bool _wearSupports; private bool _wearStatic; internal static IEnumerable Loaded => Objects; internal bool Ready { get { if (_registered && Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { return Identity.Length != 0; } return false; } } internal ZNetView View => _view; internal string Identity { get { if (!Object.op_Implicit((Object)(object)_view) || !_view.IsValid()) { return ""; } return _view.GetZDO().GetString("vikingrail_identity", ""); } } internal string HostIdentity { get { if (!Object.op_Implicit((Object)(object)_view) || !_view.IsValid()) { return ""; } return _view.GetZDO().GetString("vikingrail_object_host_guid", ""); } } internal string Token { get { if (!Object.op_Implicit((Object)(object)_view) || !_view.IsValid()) { return ""; } return _view.GetZDO().GetString("vikingrail_object_token", ""); } } internal int Slot { get { if (!Object.op_Implicit((Object)(object)_view) || !_view.IsValid()) { return -1; } return _view.GetZDO().GetInt("vikingrail_object_slot", -1); } } private bool ReturnPending { get { if (Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { return _view.GetZDO().GetBool("vikingrail_object_detach_pending", false); } return false; } } internal bool IsLocked { get { if (HostIdentity.Length == 0 && Token.Length == 0) { return ReturnPending; } return true; } } internal bool IsAttached { get { if (Object.op_Implicit((Object)(object)Host)) { return Host.Matches(this, Slot, requireActive: true); } return false; } } internal bool HasCommittedMount { get { if (!Ready || HostIdentity.Length != 32 || Slot < 0 || Slot >= 2 || !Guid.TryParseExact(Token, "N", out var _) || WasDestroyed(HostIdentity)) { return false; } RailMountCart host = Host; if (!Object.op_Implicit((Object)(object)host)) { return _view.GetZDO().GetInt("vikingrail_object_phase", 0) == 2; } return host.Matches(this, Slot, requireActive: true); } } internal bool IsDummy => RailMountPolicy.IsDummy(Utils.GetPrefabName(((Component)this).gameObject)); internal bool IsDefender => RailMountPolicy.IsDefender(Utils.GetPrefabName(((Component)this).gameObject)); internal bool Alive { get { if (Ready && (!Object.op_Implicit((Object)(object)((Component)this).GetComponent()) || !((Component)this).GetComponent().IsDead())) { if (Object.op_Implicit((Object)(object)((Component)this).GetComponent())) { return _view.GetZDO().GetFloat(ZDOVars.s_health, 1f) > 0f; } return true; } return false; } } internal RailMountCart? Host => RailMountCart.Find(HostIdentity); internal RailVehicle? Vehicle { get { if (!IsAttached) { return null; } return Host.Vehicle; } } internal bool MotionCompatible { get { InitializeMotion(); if (!_motionFailed && (!Object.op_Implicit((Object)(object)_mountSync) || RailMountedMotionNative.SyncCompatible) && (!IsDummy || (Object.op_Implicit((Object)(object)_mountCharacter) && Object.op_Implicit((Object)(object)_mountBody) && RailMountedMotionNative.CharacterCompatible))) { if (Object.op_Implicit((Object)(object)_mountWear)) { return RailMountedMotionNative.WearCompatible; } return true; } return false; } } internal bool HoldMountedCharacter { get { if (_motionHeld && Ready && IsLocked) { return IsDummy; } return false; } } internal static RailMountedObject? Find(string identity) { if (identity.Length != 0) { return Objects.FirstOrDefault((RailMountedObject o) => Object.op_Implicit((Object)(object)o) && o.Ready && o.Identity == identity); } return null; } internal static RailMountedObject? Find(ZDOID id) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) return Objects.FirstOrDefault((RailMountedObject o) => Object.op_Implicit((Object)(object)o) && o.Ready && o.View.GetZDO().m_uid == id); } internal static bool WasDestroyed(string identity) { if (identity.Length != 0) { return Destroyed.Contains(identity); } return false; } private void Awake() { _view = ((Component)this).GetComponent(); InitializeMotion(); Register(); } private void Start() { Register(); } private void Register() { if (!_registered && Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { _registered = true; Objects.Add(this); EnsureIdentity(); _view.Register("VR_MountedChange", (Method)RequestChange); EnsureDestructionTracking(); } } private void EnsureIdentity() { if (Object.op_Implicit((Object)(object)_view) && _view.IsValid() && _view.IsOwner() && Identity.Length == 0) { _view.GetZDO().Set("vikingrail_identity", Guid.NewGuid().ToString("N")); } } private void Update() { //IL_0138: Unknown result type (might be due to invalid IL or missing references) Register(); EnsureIdentity(); if (!Ready) { return; } if (ReturnPending && _view.IsOwner()) { ZDO zDO = _view.GetZDO(); string identity = zDO.GetString("vikingrail_object_detached_host", ""); int slot = zDO.GetInt("vikingrail_object_detached_slot", -1); RailMountCart railMountCart = RailMountCart.Find(identity); if (WasDestroyed(identity) || (Object.op_Implicit((Object)(object)railMountCart) && railMountCart.Ready && (railMountCart.Phase(slot) == 0 || railMountCart.Token(slot) != zDO.GetString("vikingrail_object_detached_token", "")))) { zDO.Set("vikingrail_object_detach_pending", false); } } if (IsLocked && _view.IsOwner()) { RailMountCart host = Host; if (WasDestroyed(HostIdentity)) { ClearLink(); } else if (Object.op_Implicit((Object)(object)host) && host.Ready) { if (host.Matches(this, Slot, requireActive: true)) { _view.GetZDO().Set("vikingrail_object_phase", 2); _view.GetZDO().Set("vikingrail_object_host", host.View.GetZDO().m_uid); } else if (_view.GetZDO().GetInt("vikingrail_object_phase", 0) == 1 && (host.Phase(Slot) == 0 || host.Token(Slot) != Token)) { ClearLink(); } } } UpdateMotionMount(); } private void LateUpdate() { if (Ready) { FollowMount(persist: false); } } private void OnDestroy() { RestoreMotion(); Objects.Remove(this); } internal static void Ensure(ZNetView view) { if (Object.op_Implicit((Object)(object)view) && view.IsValid() && RailMountPolicy.IsAllowed(Utils.GetPrefabName(((Component)view).gameObject)) && !Object.op_Implicit((Object)(object)((Component)view).GetComponent())) { ((Component)view).gameObject.AddComponent(); } } internal static void Discover(bool force = false) { if (!Object.op_Implicit((Object)(object)ZNetScene.instance) || (!force && Time.unscaledTime < _nextDiscovery)) { return; } _nextDiscovery = Time.unscaledTime + 2f; ZNetView[] array = Resources.FindObjectsOfTypeAll(); foreach (ZNetView val in array) { if (Object.op_Implicit((Object)(object)val) && val.IsValid() && (Object)(object)ZNetScene.instance.FindInstance(val.GetZDO()) == (Object)(object)val) { Ensure(val); } } } internal bool CanPrepare(out string reason) { //IL_0078: 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_0090: Unknown result type (might be due to invalid IL or missing references) reason = "This object is busy or unsupported."; if (!Ready || !Alive || IsLocked || !MotionCompatible || !NativeIdentityMatches() || !Object.op_Implicit((Object)(object)((Component)this).GetComponent()) || Object.op_Implicit((Object)(object)((Component)this).GetComponent()) || Object.op_Implicit((Object)(object)((Component)this).GetComponent()) || ((Component)this).GetComponentsInChildren(true).Length != 1) { return false; } if (!ContentsIdle() || !TryBounds(out var bounds) || !RailMountPolicy.Fits(((Bounds)(ref bounds)).size.x, ((Bounds)(ref bounds)).size.y, ((Bounds)(ref bounds)).size.z)) { return false; } reason = ""; return true; } private bool NativeIdentityMatches() { string prefabName = Utils.GetPrefabName(((Component)this).gameObject); if (!RailMountPolicy.IsAllowed(prefabName)) { return false; } switch (prefabName) { case "sign": return Object.op_Implicit((Object)(object)((Component)this).GetComponent()); case "itemstandh": return Object.op_Implicit((Object)(object)((Component)this).GetComponent()); case "piece_groundtorch": case "piece_groundtorch_wood": return Object.op_Implicit((Object)(object)((Component)this).GetComponent()); default: if (RailMountPolicy.IsDefender(prefabName)) { string marker = ((prefabName == "piece_DARE") ? "Dare.DareGuard" : "Dare.GnomeGuard"); if (Object.op_Implicit((Object)(object)((Component)this).GetComponent()) && Object.op_Implicit((Object)(object)((Component)this).GetComponent())) { return ((Component)this).GetComponents().Any((MonoBehaviour component) => Object.op_Implicit((Object)(object)component) && ((object)component).GetType().FullName == marker); } return false; } if (prefabName == "piece_TrainingDummy") { return Object.op_Implicit((Object)(object)((Component)this).GetComponent()); } return false; } } private bool ContentsIdle() { Container[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (Container val in componentsInChildren) { if (val.IsInUse() || _view.GetZDO().GetInt("InUse", 0) != 0) { return false; } if (Object.op_Implicit((Object)(object)InventoryGui.instance) && CurrentContainer?.GetValue(InventoryGui.instance) == val) { return false; } } ItemStand component = ((Component)this).GetComponent(); if (Object.op_Implicit((Object)(object)component) && (QueuedStandItem == null || QueuedStandItem.GetValue(component) != null)) { return false; } return true; } private void RequestChange(long sender, ZDOID hostId, int slot, string token, int attempt) { //IL_0037: 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_0162: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: 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_031a: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Unknown result type (might be due to invalid IL or missing references) //IL_033d: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_03aa: 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) if (!Ready || !_view.IsOwner() || token == null || !Guid.TryParseExact(token, "N", out var _) || slot < 0 || slot >= 2 || attempt < 1) { return; } RailMountCart railMountCart = RailMountCart.Find(hostId); if (!Object.op_Implicit((Object)(object)railMountCart) || !railMountCart.Ready || railMountCart.View.GetZDO().GetOwner() != sender || railMountCart.Token(slot) != token || railMountCart.ChildIdentity(slot) != Identity || railMountCart.Attempt(slot) != attempt) { return; } Player player; if (railMountCart.Phase(slot) == 3 && DetachedFrom(railMountCart.Identity, slot, token)) { Reply(railMountCart, sender, slot, token, attempt, success: true, "Object detached beside the cart."); } else if (Rejected(railMountCart.Identity, slot, token, attempt)) { Reply(railMountCart, sender, slot, token, attempt, success: false, "That attempt was canceled. Use the pad to try again."); } else if (!railMountCart.CanChange || railMountCart.Expires(slot) < RailMountCart.Now || railMountCart.Expires(slot) > RailMountCart.Now + 12000 + 1000 || !railMountCart.ValidRequester(slot, out player) || !ContentsIdle()) { Reject(railMountCart, sender, slot, token, attempt, "The cart or object became busy. Park it and retry the mounting pad."); } else if (!RailWardAccess.Allows(((Component)this).transform.position, player.GetPlayerID()) || Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position) > 4f) { Reject(railMountCart, sender, slot, token, attempt, "Stand beside the protected object with permission to move it."); } else if (railMountCart.Phase(slot) == 1) { if (railMountCart.Matches(this, slot, requireActive: false)) { Reply(railMountCart, sender, slot, token, attempt, success: true, ""); return; } if (!CanPrepare(out string _) || Vector3.Distance(((Component)this).transform.position, railMountCart.Socket(slot)) > 2.5f || !CanPlaceAt(railMountCart.Socket(slot), MountRotation(railMountCart), railMountCart.Vehicle, mounting: true)) { Reject(railMountCart, sender, slot, token, attempt, "The object does not fit this pad, its controls are open, or the pad is obstructed."); return; } ZDO zDO = _view.GetZDO(); zDO.Set("vikingrail_object_host", railMountCart.View.GetZDO().m_uid); zDO.Set("vikingrail_object_host_guid", railMountCart.Identity); zDO.Set("vikingrail_object_slot", slot); zDO.Set("vikingrail_object_token", token); zDO.Set("vikingrail_object_rotation", Quaternion.Inverse(((Component)railMountCart).transform.rotation) * MountRotation(railMountCart)); zDO.Set("vikingrail_object_phase", 1); UpdateMotionMount(); ZDOMan instance = ZDOMan.instance; if (instance != null) { instance.ForceSendZDO(sender, zDO.m_uid); } Reply(railMountCart, sender, slot, token, attempt, success: true, ""); } else { if (railMountCart.Phase(slot) != 3 || !railMountCart.Matches(this, slot, requireActive: true)) { return; } if (!FindDetachPose(railMountCart, player.GetPlayerID(), out var position, out var rotation)) { Reject(railMountCart, sender, slot, token, attempt, "Clear supported ground beside the cart before detaching this object."); return; } ZDO zDO2 = _view.GetZDO(); zDO2.SetPosition(position); zDO2.SetRotation(rotation); Rigidbody component = ((Component)this).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { component.position = position; component.rotation = rotation; } ((Component)this).transform.SetPositionAndRotation(position, rotation); zDO2.Set("vikingrail_object_detached_host", railMountCart.Identity); zDO2.Set("vikingrail_object_detached_slot", slot); zDO2.Set("vikingrail_object_detached_token", token); zDO2.Set("vikingrail_object_detach_pending", true); ClearLink(); ZDOMan instance2 = ZDOMan.instance; if (instance2 != null) { instance2.ForceSendZDO(sender, zDO2.m_uid); } Reply(railMountCart, sender, slot, token, attempt, success: true, "Object detached beside the cart; its original contents are unchanged."); } } private Quaternion MountRotation(RailMountCart host) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_001e: 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_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) if (!IsDummy) { return ((Component)host).transform.rotation * Quaternion.Euler(0f, Mathf.DeltaAngle(((Component)host).transform.eulerAngles.y, ((Component)this).transform.eulerAngles.y), 0f); } return Quaternion.Euler(0f, ((Component)this).transform.eulerAngles.y, 0f); } internal bool MountSpaceClear(RailMountCart host) { //IL_001a: 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_006d: 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_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_004c: Unknown result type (might be due to invalid IL or missing references) if (Slot >= 0 && Slot < 2) { return CanPlaceAt(host.Socket(Slot), IsDummy ? Quaternion.Euler(0f, ((Component)this).transform.eulerAngles.y, 0f) : (((Component)host).transform.rotation * _view.GetZDO().GetQuaternion("vikingrail_object_rotation", Quaternion.identity)), host.Vehicle, mounting: true); } return false; } private void Reply(RailMountCart host, long peer, int slot, string token, int attempt, bool success, string reason) { host.View.InvokeRPC(peer, "VR_MountChildReply", new object[5] { slot, token, attempt, success, reason }); } private void Reject(RailMountCart host, long peer, int slot, string token, int attempt, string reason) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) ZDO zDO = _view.GetZDO(); zDO.Set("vikingrail_object_reject_host", host.Identity); zDO.Set("vikingrail_object_reject_slot", slot); zDO.Set("vikingrail_object_reject_token", token); zDO.Set("vikingrail_object_reject_attempt", attempt); ZDOMan instance = ZDOMan.instance; if (instance != null) { instance.ForceSendZDO(peer, zDO.m_uid); } Reply(host, peer, slot, token, attempt, success: false, reason); } internal bool Rejected(string host, int slot, string token, int attempt) { if (Ready && _view.GetZDO().GetString("vikingrail_object_reject_host", "") == host && _view.GetZDO().GetInt("vikingrail_object_reject_slot", -1) == slot && _view.GetZDO().GetString("vikingrail_object_reject_token", "") == token) { return _view.GetZDO().GetInt("vikingrail_object_reject_attempt", 0) == attempt; } return false; } internal bool DetachedFrom(string host, int slot, string token) { if (Ready && _view.GetZDO().GetString("vikingrail_object_detached_host", "") == host && _view.GetZDO().GetInt("vikingrail_object_detached_slot", -1) == slot) { return _view.GetZDO().GetString("vikingrail_object_detached_token", "") == token; } return false; } private void ClearLink() { if (Object.op_Implicit((Object)(object)_view) && _view.IsValid() && _view.IsOwner()) { ClearSavedLink(_view.GetZDO()); RestoreMotion(); } } private static void ClearSavedLink(ZDO data) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) data.Set("vikingrail_object_host", ZDOID.None); data.Set("vikingrail_object_host_guid", ""); data.Set("vikingrail_object_slot", -1); data.Set("vikingrail_object_token", ""); data.Set("vikingrail_object_phase", 0); } internal bool TryGetMountPose(out Vector3 position, out Quaternion rotation, bool canonical = false) { //IL_0001: 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_000d: 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_0069: 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_009d: 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_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_00a4: 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_00ae: 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_00ca: 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) position = default(Vector3); rotation = Quaternion.identity; RailMountCart host = Host; if (!Ready || !Object.op_Implicit((Object)(object)host) || !host.Matches(this, Slot, requireActive: true)) { return false; } Vector3 vector = RailMountPolicy.Socket(Slot); Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(vector.X, vector.Y, vector.Z); Quaternion val2 = (canonical ? host.View.GetZDO().GetRotation() : ((Component)host).transform.rotation); position = (canonical ? host.View.GetZDO().GetPosition() : ((Component)host).transform.position) + val2 * val; rotation = val2 * _view.GetZDO().GetQuaternion("vikingrail_object_rotation", Quaternion.identity); if (_view.IsOwner()) { _view.GetZDO().Set("vikingrail_object_phase", 2); } return true; } internal bool TryBounds(out Bounds bounds) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0227: 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_0049: 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_006d: 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_0121: 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_009a: 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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: 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_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_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_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017c: 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_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018a: 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) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: 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_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) bounds = default(Bounds); bool flag = false; Collider[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); Bounds val3 = default(Bounds); foreach (Collider val in componentsInChildren) { if (!val.enabled || val.isTrigger) { continue; } BoxCollider val2 = (BoxCollider)(object)((val is BoxCollider) ? val : null); if (val2 != null) { ((Bounds)(ref val3))..ctor(val2.center, val2.size); } else { SphereCollider val4 = (SphereCollider)(object)((val is SphereCollider) ? val : null); if (val4 != null) { ((Bounds)(ref val3))..ctor(val4.center, Vector3.one * (val4.radius * 2f)); } else { CapsuleCollider val5 = (CapsuleCollider)(object)((val is CapsuleCollider) ? val : null); if (val5 != null) { Vector3 val6 = Vector3.one * (val5.radius * 2f); ((Vector3)(ref val6))[val5.direction] = Mathf.Max(((Vector3)(ref val6))[val5.direction], val5.height); ((Bounds)(ref val3))..ctor(val5.center, val6); } else { MeshCollider val7 = (MeshCollider)(object)((val is MeshCollider) ? val : null); val3 = (Bounds)((val7 == null || !Object.op_Implicit((Object)(object)val7.sharedMesh)) ? default(Bounds) : val7.sharedMesh.bounds); } } } bool flag2 = ((Bounds)(ref val3)).size == Vector3.zero; if (flag2) { val3 = val.bounds; } for (int j = -1; j <= 1; j += 2) { for (int k = -1; k <= 1; k += 2) { for (int l = -1; l <= 1; l += 2) { Vector3 val8 = ((Bounds)(ref val3)).center + Vector3.Scale(((Bounds)(ref val3)).extents, new Vector3((float)j, (float)k, (float)l)); Vector3 val9 = (flag2 ? val8 : ((Component)val).transform.TransformPoint(val8)); Vector3 val10 = Quaternion.Inverse(((Component)this).transform.rotation) * (val9 - ((Component)this).transform.position); if (!flag) { bounds = new Bounds(val10, Vector3.zero); flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val10); } } } } } if (flag && Finite(((Bounds)(ref bounds)).center)) { return Finite(((Bounds)(ref bounds)).extents); } return false; } private static bool Finite(Vector3 vector) { //IL_0000: 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_001a: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!float.IsNaN(vector.x) && !float.IsInfinity(vector.x) && !float.IsNaN(vector.y) && !float.IsInfinity(vector.y) && !float.IsNaN(vector.z)) { return !float.IsInfinity(vector.z); } return false; } private bool CanPlaceAt(Vector3 position, Quaternion rotation, RailVehicle? host, bool mounting) { //IL_000e: 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_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_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_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_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_004a: 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_0050: 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) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015e: 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_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017c: 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_00db: 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_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_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) if (!TryBounds(out var bounds)) { return false; } Vector3 val = Vector3.Max(((Bounds)(ref bounds)).extents - Vector3.one * 0.025f, Vector3.one * 0.025f); Collider[] array = Physics.OverlapBox(position + rotation * ((Bounds)(ref bounds)).center, val, rotation, -1, (QueryTriggerInteraction)1); foreach (Collider val2 in array) { if (!Object.op_Implicit((Object)(object)val2) || ((Component)val2).transform.IsChildOf(((Component)this).transform)) { continue; } Bounds bounds2; if (mounting && Object.op_Implicit((Object)(object)host) && (Object)(object)((Component)val2).GetComponentInParent() == (Object)(object)host) { float num = float.NegativeInfinity; BoxCollider val3 = (BoxCollider)(object)((val2 is BoxCollider) ? val2 : null); if (val3 != null) { for (int j = -1; j <= 1; j += 2) { for (int k = -1; k <= 1; k += 2) { for (int l = -1; l <= 1; l += 2) { Vector3 val4 = val3.center + Vector3.Scale(val3.size * 0.5f, new Vector3((float)j, (float)k, (float)l)); num = Mathf.Max(num, ((Component)host).transform.InverseTransformPoint(((Component)val3).transform.TransformPoint(val4)).y); } } } } else { Transform transform = ((Component)host).transform; bounds2 = val2.bounds; float y = transform.InverseTransformPoint(((Bounds)(ref bounds2)).center).y; bounds2 = val2.bounds; num = y + ((Bounds)(ref bounds2)).extents.y; } if (num <= 0.925f) { continue; } } if (Object.op_Implicit((Object)(object)((Component)val2).GetComponentInParent())) { bounds2 = val2.bounds; if (((Bounds)(ref bounds2)).max.y <= position.y + 0.05f) { continue; } } return false; } return true; } private bool FindDetachPose(RailMountCart host, long playerId, out Vector3 position, out Quaternion rotation) { //IL_0001: 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_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_0079: 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_008b: 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_00a5: 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_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_00c3: 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_010c: 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_01bb: 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_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: 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_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) position = default(Vector3); rotation = Quaternion.Euler(0f, ((Component)this).transform.eulerAngles.y, 0f); if (!TryBounds(out var bounds)) { return false; } int[] array = new int[2] { 1, -1 }; foreach (int num in array) { float[] array2 = new float[2] { 0f, 0.6f }; foreach (float num2 in array2) { RaycastHit[] array3 = Physics.RaycastAll(host.Socket(Slot) + ((Component)host).transform.right * (float)num * (1.05f + ((Bounds)(ref bounds)).extents.x + num2) + Vector3.up * 2f, Vector3.down, 6f, -1, (QueryTriggerInteraction)1); Array.Sort(array3, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); RaycastHit[] array4 = array3; for (int num3 = 0; num3 < array4.Length; num3++) { RaycastHit val = array4[num3]; if (Object.op_Implicit((Object)(object)((RaycastHit)(ref val)).collider) && !((Component)((RaycastHit)(ref val)).collider).transform.IsChildOf(((Component)this).transform) && !Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent()) && !Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent()) && !(((RaycastHit)(ref val)).normal.y < 0.65f) && !Object.op_Implicit((Object)(object)((RaycastHit)(ref val)).collider.attachedRigidbody) && (Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent()) || Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent()))) { Vector3 val2 = ((RaycastHit)(ref val)).point + Vector3.up * (0.035f - ((Bounds)(ref bounds)).min.y); if (RailWardAccess.Allows(val2, playerId) && !Location.IsInsideNoBuildLocation(val2) && CanPlaceAt(val2, rotation, null, mounting: false)) { position = val2; return true; } } } } } return false; } internal static void EnsureDestructionTracking() { if (_manager != ZDOMan.instance) { if (_manager != null) { ZDOMan? manager = _manager; manager.m_onZDODestroyed = (Action)Delegate.Remove(manager.m_onZDODestroyed, new Action(OnSavedDestroyed)); } Destroyed.Clear(); _manager = ZDOMan.instance; if (_manager != null) { ZDOMan? manager2 = _manager; manager2.m_onZDODestroyed = (Action)Delegate.Combine(manager2.m_onZDODestroyed, new Action(OnSavedDestroyed)); } } } private static void OnSavedDestroyed(ZDO destroyed) { //IL_00b4: 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_0231: Unknown result type (might be due to invalid IL or missing references) string text = destroyed.GetString("vikingrail_identity", ""); if (text.Length == 0) { return; } Destroyed.Add(text); RailMountCart.ChildDestroyed(text); RailMountedObject[] array = Objects.ToArray(); foreach (RailMountedObject railMountedObject in array) { if (Object.op_Implicit((Object)(object)railMountedObject) && railMountedObject.Ready && railMountedObject.HostIdentity == text && railMountedObject.View.IsOwner()) { railMountedObject.ClearLink(); } } if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer() || ZDOMan.instance == null) { return; } List list = new List(); ZDOMan.instance.FindSectorObjects(destroyed.GetSector(), new SimulationDistance(1, 0, false), list, (List)null); string text2 = destroyed.GetString("vikingrail_object_host_guid", ""); int num = destroyed.GetInt("vikingrail_object_slot", -1); string text3 = destroyed.GetString("vikingrail_object_token", ""); if (text2.Length == 0 && destroyed.GetBool("vikingrail_object_detach_pending", false)) { text2 = destroyed.GetString("vikingrail_object_detached_host", ""); num = destroyed.GetInt("vikingrail_object_detached_slot", -1); text3 = destroyed.GetString("vikingrail_object_detached_token", ""); } foreach (ZDO item in list) { if (item.GetString("vikingrail_object_host_guid", "") == text) { ClearSavedLink(item); } if (item.GetString("vikingrail_object_detached_host", "") == text) { item.Set("vikingrail_object_detach_pending", false); } if (num >= 0 && num < 2 && text2.Length != 0 && item.GetString("vikingrail_identity", "") == text2 && item.GetString(RailMountCart.Key(num, "guid"), "") == text && item.GetString(RailMountCart.Key(num, "token"), "") == text3) { item.Set(RailMountCart.Key(num, "phase"), 0); item.Set(RailMountCart.Key(num, "id"), ZDOID.None); item.Set(RailMountCart.Key(num, "guid"), ""); item.Set(RailMountCart.Key(num, "token"), ""); item.Set(RailMountCart.Key(num, "until"), 0L); } } } internal static void Cleanup() { if (_manager != null) { ZDOMan? manager = _manager; manager.m_onZDODestroyed = (Action)Delegate.Remove(manager.m_onZDODestroyed, new Action(OnSavedDestroyed)); } _manager = null; Destroyed.Clear(); Objects.Clear(); _nextDiscovery = 0f; RailMountCart.Cleanup(); } internal void InitializeMotion() { if (!_motionInitialized) { _motionInitialized = true; _mountBody = ((Component)this).GetComponent(); _mountCharacter = ((Component)this).GetComponent(); _mountSync = ((Component)this).GetComponent(); _mountWear = ((Component)this).GetComponent(); } } internal void UpdateMotionMount() { //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) InitializeMotion(); if (!Ready) { return; } if (!IsLocked) { RestoreMotion(); } else { if (_motionFailed) { return; } try { if (!_motionHeld) { if (!MotionCompatible) { return; } if (Object.op_Implicit((Object)(object)_mountBody)) { _bodyConstraints = _mountBody.constraints; _bodyGravity = _mountBody.useGravity; } if (Object.op_Implicit((Object)(object)_mountSync)) { _syncEnabled = ((Behaviour)_mountSync).enabled; _syncPosition = _mountSync.m_syncPosition; _syncRotation = _mountSync.m_syncRotation; _syncGravity = (bool)RailMountedMotionNative.SyncGravity.GetValue(_mountSync); } if (Object.op_Implicit((Object)(object)_mountWear)) { _wearSupport = _mountWear.m_noSupportWear; _wearSupports = _mountWear.m_supports; _wearStatic = _mountWear.m_staticPosition; } _motionHeld = true; } if (Object.op_Implicit((Object)(object)_mountSync)) { _mountSync.m_syncPosition = false; _mountSync.m_syncRotation = true; RailMountedMotionNative.SyncGravity.SetValue(_mountSync, false); ((Behaviour)_mountSync).enabled = true; } if (Object.op_Implicit((Object)(object)_mountWear)) { _mountWear.m_noSupportWear = false; _mountWear.m_supports = false; _mountWear.m_staticPosition = false; } HoldBody(); } catch (Exception error) { MotionError(error); } } } private void HoldBody() { //IL_0046: 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) if (!Object.op_Implicit((Object)(object)_mountBody)) { return; } _mountBody.constraints = (RigidbodyConstraints)(IsDummy ? 94 : 126); _mountBody.useGravity = false; if (!_mountBody.isKinematic) { _mountBody.linearVelocity = Vector3.zero; if (!IsDummy) { _mountBody.angularVelocity = Vector3.zero; } } } internal void FollowMount(bool persist) { //IL_0064: 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_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_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_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_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_015e: 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_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_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0137: 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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: 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_0196: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0110: 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_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: 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_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0225: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) UpdateMotionMount(); if (!_motionHeld || _motionFailed || !Ready || !IsAttached || !TryGetMountPose(out var position, out var rotation, persist && View.IsOwner())) { return; } try { if ((Object.op_Implicit((Object)(object)_mountCharacter) && _mountCharacter.IsDead()) || !RailMountedMotionNative.Finite(position) || !RailMountedMotionNative.Finite(rotation)) { return; } Vector3 val = ((Component)this).transform.position - position; bool num = ((Vector3)(ref val)).sqrMagnitude > 1E-06f; if (IsDummy) { if (Vector3.Dot(((Component)this).transform.up, Vector3.up) < 0.99999f) { Vector3 val2 = Vector3.ProjectOnPlane(((Component)this).transform.forward, Vector3.up); if (((Vector3)(ref val2)).sqrMagnitude < 0.0001f) { val2 = Vector3.forward; } Quaternion rotation2 = Quaternion.LookRotation(((Vector3)(ref val2)).normalized, Vector3.up); if (Object.op_Implicit((Object)(object)_mountBody)) { _mountBody.rotation = rotation2; } ((Component)this).transform.rotation = rotation2; } if (Object.op_Implicit((Object)(object)_mountBody)) { _mountBody.position = position; } ((Component)this).transform.position = position; } else { if (Object.op_Implicit((Object)(object)_mountBody)) { _mountBody.position = position; _mountBody.rotation = rotation; } ((Component)this).transform.SetPositionAndRotation(position, rotation); } HoldBody(); if (Object.op_Implicit((Object)(object)_mountCharacter)) { RailMountedMotionNative.ClearTranslation(_mountCharacter, position, mounted: true, !IsDefender); } if (num && Object.op_Implicit((Object)(object)_mountWear)) { RailMountedMotionNative.InvalidateWearLocation(_mountWear); } if (!View.IsOwner() || (!persist && Object.op_Implicit((Object)(object)_mountSync))) { return; } Vector3 position2 = position; Quaternion rotation3 = rotation; if ((persist || TryGetMountPose(out position2, out rotation3, canonical: true)) && RailMountedMotionNative.Finite(position2) && RailMountedMotionNative.Finite(rotation3)) { ZDO zDO = View.GetZDO(); val = zDO.GetPosition() - position2; if (((Vector3)(ref val)).sqrMagnitude > 1E-06f) { zDO.SetPosition(position2); } if (!IsDummy && Quaternion.Angle(zDO.GetRotation(), rotation3) > 0.001f) { zDO.SetRotation(rotation3); } } } catch (Exception error) { MotionError(error); } } internal void RestoreMotion() { //IL_0023: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) if (!_motionHeld) { return; } try { if (Object.op_Implicit((Object)(object)_mountCharacter)) { RailMountedMotionNative.ClearTranslation(_mountCharacter, ((Component)this).transform.position); } if (Object.op_Implicit((Object)(object)_mountBody)) { if (!_mountBody.isKinematic) { _mountBody.linearVelocity = Vector3.zero; _mountBody.angularVelocity = Vector3.zero; } _mountBody.constraints = _bodyConstraints; _mountBody.useGravity = _bodyGravity; } if (Object.op_Implicit((Object)(object)_mountSync)) { _mountSync.m_syncPosition = _syncPosition; _mountSync.m_syncRotation = _syncRotation; RailMountedMotionNative.SyncGravity.SetValue(_mountSync, _syncGravity); RailMountedMotionNative.ResetSyncPosition(_mountSync); ((Behaviour)_mountSync).enabled = _syncEnabled; } if (Object.op_Implicit((Object)(object)_mountWear)) { RailMountedMotionNative.SetupWear(_mountWear); RailMountedMotionNative.ClearWear(_mountWear); RailMountedMotionNative.InvalidateWearLocation(_mountWear); _mountWear.m_staticPosition = _wearStatic; _mountWear.m_supports = _wearSupports; _mountWear.m_noSupportWear = _wearSupport; } _motionHeld = false; } catch (Exception error) { MotionError(error); } } internal bool SuppressDefenderTranslation() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) UpdateMotionMount(); if (!_motionHeld || !IsLocked || !IsDefender || !Object.op_Implicit((Object)(object)_mountCharacter)) { return false; } FollowMount(persist: true); try { RailMountedMotionNative.ClearTranslation(_mountCharacter, ((Component)this).transform.position, mounted: true); if (View.IsOwner()) { RailMountedMotionNative.UpdateEyes?.Invoke(_mountCharacter); } } catch (Exception error) { MotionError(error); } return true; } private void MotionError(Exception error) { if (!_motionFailed) { RailPlugin.Warn("Mounted railway object motion could not be updated: " + error.GetBaseException().Message); } _motionFailed = true; } } [HarmonyPatch(typeof(ZNetView), "Awake")] internal static class RailMountedObjectDiscoveryPatch { [HarmonyPostfix] private static void Postfix(ZNetView __instance) { RailMountedObject.Ensure(__instance); } } internal static class RailMountedMotionNative { internal static readonly MethodInfo? OwnerSync = Method(typeof(ZSyncTransform), "OwnerSync"); internal static readonly MethodInfo? ClientSync = Method(typeof(ZSyncTransform), "ClientSync", typeof(float)); internal static readonly MethodInfo? CharacterUpdate = Method(typeof(Character), "CustomFixedUpdate", typeof(float)); internal static readonly MethodInfo? CharacterMotion = Method(typeof(Character), "UpdateMotion", typeof(float)); internal static readonly MethodInfo? UnderWorld = Method(typeof(Character), "UnderWorldCheck", typeof(float)); internal static readonly MethodInfo? AiUpdate = AccessTools.DeclaredMethod(typeof(MonsterAI), "UpdateAI", new Type[1] { typeof(float) }, (Type[])null); internal static readonly FieldInfo? SyncGravity = Field(typeof(ZSyncTransform), "m_useGravity", typeof(bool)); private static readonly FieldInfo? CachedPosition = Field(typeof(ZSyncTransform), "m_positionCached", typeof(Vector3)); private static readonly FieldInfo? CachedVelocity = Field(typeof(ZSyncTransform), "m_velocityCached", typeof(Vector3)); private static readonly FieldInfo? RelativePosition = Field(typeof(ZSyncTransform), "m_haveTempRelPos", typeof(bool)); private static readonly FieldInfo? PositionTimer = Field(typeof(ZSyncTransform), "m_targetPosTimer", typeof(float)); internal static readonly Action? SetupWear = Action("SetupColliders"); internal static readonly Action? ClearWear = Action("ClearCachedSupport"); internal static readonly Action? UpdateEyes = Action("UpdateEyeRotation"); private static readonly FieldInfo? WearHeightmap = Field(typeof(WearNTear), "m_heightmap", typeof(Heightmap)); private static readonly FieldInfo? WearBiome = Field(typeof(WearNTear), "m_biome", typeof(Biome)); private static readonly FieldInfo? MaxAltitude = Field(typeof(Character), "m_maxAirAltitude", typeof(float)); private static readonly FieldInfo? LastGround = Field(typeof(Character), "m_lastGroundPoint", typeof(Vector3)); private static readonly FieldInfo? LastAttach = Field(typeof(Character), "m_lastAttachPos", typeof(Vector3)); private static readonly FieldInfo? GroundTouch = Field(typeof(Character), "m_lastGroundTouch", typeof(float)); private static readonly KeyValuePair[] TranslationState = new KeyValuePair[14] { State("m_currentVel", typeof(Vector3), Vector3.zero), State("m_rootMotion", typeof(Vector3), Vector3.zero), State("m_moveDir", typeof(Vector3), Vector3.zero), State("m_pushForce", typeof(Vector3), Vector3.zero), State("m_fallTimer", typeof(float), 0f), State("m_groundForceTimer", typeof(float), 0f), State("m_groundContact", typeof(bool), false), State("m_lowestContactCollider", typeof(Collider), null), State("m_groundContactPoint", typeof(Vector3), Vector3.zero), State("m_groundContactNormal", typeof(Vector3), Vector3.zero), State("m_lastGroundNormal", typeof(Vector3), Vector3.up), State("m_lastGroundBody", typeof(Rigidbody), null), State("m_lastGroundCollider", typeof(Collider), null), State("m_lastAttachBody", typeof(Rigidbody), null) }; internal static bool SyncCompatible { get { if (OwnerSync != null && ClientSync != null) { return SyncGravity != null; } return false; } } internal static bool CharacterCompatible { get { if (CharacterUpdate != null && CharacterMotion != null && UnderWorld != null && AiUpdate != null && !AiUpdate.IsStatic && AiUpdate.ReturnType == typeof(bool) && UpdateEyes != null && MaxAltitude != null && LastGround != null && LastAttach != null && GroundTouch != null) { return Array.TrueForAll(TranslationState, (KeyValuePair value) => value.Key != null); } return false; } } internal static bool WearCompatible { get { if (SetupWear != null) { return ClearWear != null; } return false; } } private static KeyValuePair State(string name, Type type, object? value) { return new KeyValuePair(Field(typeof(Character), name, type), value); } internal static void ClearTranslation(Character character, Vector3 position, bool mounted = false, bool preserveMoveDir = false) { //IL_0089: 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_00bb: Unknown result type (might be due to invalid IL or missing references) KeyValuePair[] translationState = TranslationState; for (int i = 0; i < translationState.Length; i++) { KeyValuePair keyValuePair = translationState[i]; if (!preserveMoveDir || keyValuePair.Key?.Name != "m_moveDir") { keyValuePair.Key?.SetValue(character, keyValuePair.Value); } } GroundTouch?.SetValue(character, mounted ? 0f : 1f); MaxAltitude?.SetValue(character, position.y); LastGround?.SetValue(character, position); LastAttach?.SetValue(character, position); } internal static void ResetSyncPosition(ZSyncTransform sync) { //IL_000c: 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) CachedPosition?.SetValue(sync, Vector3.negativeInfinity); CachedVelocity?.SetValue(sync, Vector3.negativeInfinity); RelativePosition?.SetValue(sync, false); PositionTimer?.SetValue(sync, 0f); } internal static void InvalidateWearLocation(WearNTear wear) { WearHeightmap?.SetValue(wear, null); WearBiome?.SetValue(wear, (object)(Biome)0); } internal static bool Finite(Vector3 value) { //IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references) if (Finite(value.x) && Finite(value.y)) { return Finite(value.z); } return false; } internal static bool Finite(Quaternion value) { //IL_0000: 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_001a: 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) if (Finite(value.x) && Finite(value.y) && Finite(value.z)) { return Finite(value.w); } return false; } private static bool Finite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } private static FieldInfo? Field(Type type, string name, Type expected) { FieldInfo fieldInfo = AccessTools.Field(type, name); if (!(fieldInfo != null) || fieldInfo.IsStatic || !(fieldInfo.FieldType == expected)) { return null; } return fieldInfo; } private static MethodInfo? Method(Type type, string name, params Type[] parameters) { MethodInfo methodInfo = AccessTools.DeclaredMethod(type, name, parameters, (Type[])null); if (!(methodInfo != null) || methodInfo.IsStatic || !(methodInfo.ReturnType == typeof(void))) { return null; } return methodInfo; } private static Action? Action(string name) { MethodInfo methodInfo = Method(typeof(T), name); if (methodInfo == null) { return null; } try { return (Action)Delegate.CreateDelegate(typeof(Action), methodInfo); } catch { return null; } } } [HarmonyPatch] internal static class RailMountedObjectOwnerSync { [HarmonyPrepare] private static bool Prepare() { return RailMountedMotionNative.SyncCompatible; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailMountedMotionNative.OwnerSync; } [HarmonyPrefix] private static void Prefix(ZSyncTransform __instance) { ((Component)__instance).GetComponent()?.FollowMount(persist: true); } [HarmonyPostfix] private static void Postfix(ZSyncTransform __instance) { ((Component)__instance).GetComponent()?.FollowMount(persist: false); } } [HarmonyPatch] internal static class RailMountedObjectClientSync { [HarmonyPrepare] private static bool Prepare() { return RailMountedMotionNative.SyncCompatible; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailMountedMotionNative.ClientSync; } [HarmonyPrefix] private static void Prefix(ZSyncTransform __instance) { ((Component)__instance).GetComponent()?.UpdateMotionMount(); } [HarmonyPostfix] private static void Postfix(ZSyncTransform __instance) { ((Component)__instance).GetComponent()?.FollowMount(persist: false); } } [HarmonyPatch] internal static class RailMountedObjectAiPosition { [HarmonyPrepare] private static bool Prepare() { return RailMountedMotionNative.CharacterCompatible; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailMountedMotionNative.AiUpdate; } [HarmonyPrefix] [HarmonyPriority(800)] [HarmonyBefore(new string[] { "local.valheim.dare" })] private static void Prefix(MonsterAI __instance) { ((Component)__instance).GetComponent()?.FollowMount(persist: true); } } [HarmonyPatch] internal static class RailMountedObjectCharacterPosition { [HarmonyPrepare] private static bool Prepare() { return RailMountedMotionNative.CharacterCompatible; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailMountedMotionNative.CharacterUpdate; } [HarmonyPostfix] private static void Postfix(Character __instance) { ((Component)__instance).GetComponent()?.FollowMount(persist: true); } } [HarmonyPatch] internal static class RailMountedObjectDefenderMotion { [HarmonyPrepare] private static bool Prepare() { return RailMountedMotionNative.CharacterCompatible; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailMountedMotionNative.CharacterMotion; } [HarmonyPrefix] private static bool Prefix(Character __instance) { RailMountedObject component = ((Component)__instance).GetComponent(); if (component == null) { return true; } return !component.SuppressDefenderTranslation(); } } [HarmonyPatch] internal static class RailMountedObjectUnderWorld { [HarmonyPrepare] private static bool Prepare() { return RailMountedMotionNative.CharacterCompatible; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailMountedMotionNative.UnderWorld; } [HarmonyPrefix] private static bool Prefix(Character __instance) { RailMountedObject component = ((Component)__instance).GetComponent(); if (component == null) { return true; } return !component.HoldMountedCharacter; } } public sealed class RailMountedTorch : MonoBehaviour, IPlaced { public bool UnmountedSupportWear = true; internal const string ParentKey = "vikingrail_torch_parent"; internal const string IdentityKey = "vikingrail_torch_parent_guid"; internal const string SlotKey = "vikingrail_torch_slot"; internal const string RotationKey = "vikingrail_torch_rotation"; private static readonly HashSet Torches = new HashSet(); private ZNetView _view; private WearNTear _wear; private RailTorchMounts? _requested; private int _requestedSlot; private float _requestUntil; private float _nextRequest; internal static IEnumerable LoadedTorches => Torches; internal bool Ready { get { if (Object.op_Implicit((Object)(object)_view)) { return _view.IsValid(); } return false; } } internal ZNetView View => _view; internal ZDOID ParentId { get { //IL_001e: 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) if (!Ready) { return ZDOID.None; } return _view.GetZDO().GetZDOID("vikingrail_torch_parent"); } } internal string ParentIdentity { get { if (!Ready) { return ""; } return _view.GetZDO().GetString("vikingrail_torch_parent_guid", ""); } } internal string PersistentId { get { if (!Ready) { return ""; } return _view.GetZDO().GetString("vikingrail_identity", ""); } } internal int Slot { get { if (!Ready) { return -1; } return _view.GetZDO().GetInt("vikingrail_torch_slot", -1); } } internal RailTorchMounts? Host { get { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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) if (!Ready || ParentIdentity.Length == 0 || PersistentId.Length == 0) { return null; } RailTorchMounts railTorchMounts = RailTorchMounts.Find(ParentIdentity); if (!Object.op_Implicit((Object)(object)railTorchMounts) || !railTorchMounts.Ready || Slot < 0 || Slot >= railTorchMounts.Count || railTorchMounts.IdentityAt(Slot) != PersistentId) { return null; } if (_view.IsOwner() && ParentId != railTorchMounts.View.GetZDO().m_uid) { _view.GetZDO().Set("vikingrail_torch_parent", railTorchMounts.View.GetZDO().m_uid); } return railTorchMounts; } } internal RailVehicle? Vehicle { get { RailTorchMounts host = Host; if (!Object.op_Implicit((Object)(object)host)) { return null; } return host.Vehicle; } } internal static RailMountedTorch? Find(ZDOID id) { //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) foreach (RailMountedTorch torch in Torches) { if (Object.op_Implicit((Object)(object)torch) && torch.Ready && torch._view.GetZDO().m_uid == id) { return torch; } } return null; } internal static RailMountedTorch? Find(string identity) { if (identity.Length == 0) { return null; } foreach (RailMountedTorch torch in Torches) { if (Object.op_Implicit((Object)(object)torch) && torch.Ready && torch.PersistentId == identity) { return torch; } } return null; } private void Awake() { _view = ((Component)this).GetComponent(); _wear = ((Component)this).GetComponent(); RailTorchFuel.Ensure(this); } private void Start() { if (Ready) { EnsureIdentity(); Torches.Add(this); if (Object.op_Implicit((Object)(object)_wear)) { WearNTear wear = _wear; wear.m_onDestroyed = (Action)Delegate.Combine(wear.m_onDestroyed, new Action(OnDestroyedPermanently)); } } } public void OnPlaced() { //IL_004c: 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) if (!Ready || !_view.IsOwner()) { return; } EnsureIdentity(); RailTorchMounts target = RailTorchPlacementPatch.Target; if (Object.op_Implicit((Object)(object)target) && target.CanMount) { int targetSlot = RailTorchPlacementPatch.TargetSlot; if (targetSlot >= 0 && targetSlot < target.Count && !(Vector3.Distance(((Component)this).transform.position, target.Socket(targetSlot)) > 0.25f)) { _requested = target; _requestedSlot = targetSlot; _requestUntil = Time.time + 10f; _nextRequest = 0f; Torches.Add(this); RequestMount(); } } } private void RequestMount() { //IL_0082: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)_requested) && _requested.Ready && Ready && _view.IsOwner() && Object.op_Implicit((Object)(object)Player.m_localPlayer)) { _nextRequest = Time.time + 1f; _requested.View.InvokeRPC("VR_MountTorch", new object[3] { Player.m_localPlayer.GetPlayerID(), _view.GetZDO().m_uid, _requestedSlot }); } } private void Update() { EnsureIdentity(); if (Object.op_Implicit((Object)(object)_wear)) { _wear.m_noSupportWear = UnmountedSupportWear && ParentIdentity.Length == 0 && !Object.op_Implicit((Object)(object)_requested); } if (!Object.op_Implicit((Object)(object)_requested)) { return; } if (ParentIdentity.Length != 0) { _requested = null; } else if (Time.time > _requestUntil) { _requested = null; if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, "The torch could not attach. Remove it with the hammer, then rebuild on a free track socket or an empty, parked train.", 0, (Sprite)null, false); } } else if (Time.time >= _nextRequest) { RequestMount(); } } private void LateUpdate() { if (Ready && ParentIdentity.Length != 0) { RailTorchMounts host = Host; if (Object.op_Implicit((Object)(object)host)) { Follow(host); } else if (_view.IsOwner() && RailTorchMounts.IsDestroyed(ParentIdentity)) { ClearParent(); } } } private void EnsureIdentity() { if (Ready && _view.IsOwner() && PersistentId.Length == 0) { _view.GetZDO().Set("vikingrail_identity", Guid.NewGuid().ToString("N")); } } internal void Follow(RailVehicle vehicle) { RailTorchMounts component = ((Component)vehicle).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { Follow(component); } } internal void Follow(RailTorchMounts host) { //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_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_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_0068: 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_00a5: 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_008f: Unknown result type (might be due to invalid IL or missing references) //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_00cc: 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) if (!Ready || !host.Ready || Slot < 0 || Slot >= host.Count) { return; } ZDO zDO = _view.GetZDO(); Vector3 val = host.Socket(Slot); Quaternion val2 = ((Component)host).transform.rotation * zDO.GetQuaternion("vikingrail_torch_rotation", Quaternion.identity); ((Component)this).transform.SetPositionAndRotation(val, val2); if (!_view.IsOwner()) { return; } if (!Object.op_Implicit((Object)(object)host.Vehicle)) { Vector3 val3 = zDO.GetPosition() - val; if (!(((Vector3)(ref val3)).sqrMagnitude > 1E-06f)) { goto IL_00ab; } } zDO.SetPosition(val); goto IL_00ab; IL_00ab: if (Object.op_Implicit((Object)(object)host.Vehicle) || Quaternion.Angle(zDO.GetRotation(), val2) > 0.001f) { zDO.SetRotation(val2); } } internal void ClearParent() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (Ready && _view.IsOwner()) { _view.GetZDO().Set("vikingrail_torch_parent", ZDOID.None); _view.GetZDO().Set("vikingrail_torch_parent_guid", ""); _view.GetZDO().Set("vikingrail_torch_slot", -1); if (Object.op_Implicit((Object)(object)_wear)) { _wear.m_noSupportWear = UnmountedSupportWear; } } } private void OnDestroyedPermanently() { if (Ready && _view.IsOwner()) { RailTorchMounts host = Host; RailTorchMounts.RecordDestroyed(PersistentId); if (Object.op_Implicit((Object)(object)host)) { host.View.InvokeRPC("VR_UnmountTorch", new object[2] { PersistentId, Slot }); } } } private void OnDestroy() { if (Object.op_Implicit((Object)(object)_wear)) { WearNTear wear = _wear; wear.m_onDestroyed = (Action)Delegate.Remove(wear.m_onDestroyed, new Action(OnDestroyedPermanently)); } Torches.Remove(this); } } public sealed class RailTorchMounts : MonoBehaviour { internal const int SlotCount = 4; public Vector3[] TrackSockets = Array.Empty(); internal RailVehicle? Vehicle; private ZNetView _view; private string _registeredIdentity = ""; private static readonly Dictionary Hosts = new Dictionary(); private WearNTear _wear; private float _nextRefresh; private float _nextRemovalWarning; private float _hammerWaitUntil; private float _nextHammerPoll; private float _nextHammerChildRequest; private bool _hammerWaitingBlockDrops; private long _hammerRequesterPlayer; private long _hammerRequesterPeer; private static readonly Func? CreateExistingObject = BindExistingObjectCreation(); private static readonly FieldInfo? DestroyedCallback = AccessTools.Field(typeof(ZDOMan), "m_onZDODestroyed"); private static readonly HashSet DestroyedIdentities = new HashSet(); private static ZDOMan? _trackedManager; private static readonly FieldInfo? WardList = AccessTools.Field(typeof(PrivateArea), "m_allAreas"); private static readonly MethodInfo? WardEnabled = AccessTools.Method(typeof(PrivateArea), "IsEnabled", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo? WardInside = AccessTools.Method(typeof(PrivateArea), "IsInside", new Type[2] { typeof(Vector3), typeof(float) }, (Type[])null); private static readonly MethodInfo? WardPermitted = AccessTools.Method(typeof(PrivateArea), "IsPermitted", new Type[1] { typeof(long) }, (Type[])null); internal static IEnumerable LoadedHosts => Hosts.Values; internal int Count { get { if (!Object.op_Implicit((Object)(object)Vehicle)) { return TrackSockets.Length; } return 4; } } internal ZNetView View => _view; internal string PersistentId { get { if (!Object.op_Implicit((Object)(object)_view) || !_view.IsValid()) { return ""; } return _view.GetZDO().GetString("vikingrail_identity", ""); } } internal bool Ready { get { if (Object.op_Implicit((Object)(object)_view) && _view.IsValid() && PersistentId.Length != 0 && Count > 0) { if (Object.op_Implicit((Object)(object)Vehicle)) { return Vehicle.IsReady; } return true; } return false; } } internal bool CanMount { get { if (Ready) { if (Object.op_Implicit((Object)(object)Vehicle)) { return Parked(Vehicle); } return true; } return false; } } internal static RailTorchMounts? Find(string identity) { if (!Hosts.TryGetValue(identity, out RailTorchMounts value) || !Object.op_Implicit((Object)(object)value)) { return null; } return value; } internal static string Key(int slot) { return "vikingrail_torch_" + slot; } private static string GuidKey(int slot) { return Key(slot) + "_guid"; } private static string OwnerKey(int slot) { return Key(slot) + "_owner"; } internal static Vector3 LocalSocket(int slot) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) return new Vector3(((slot & 1) == 0) ? (-0.76f) : 0.76f, 0.87f, (slot < 2) ? (-0.89f) : 0.89f); } internal Vector3 LocalSocketAt(int slot) { //IL_001b: 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) if (!Object.op_Implicit((Object)(object)Vehicle)) { return TrackSockets[slot]; } return LocalSocket(slot); } internal Vector3 Socket(int slot) { //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) return ((Component)this).transform.TransformPoint(LocalSocketAt(slot)); } internal static bool Parked(RailVehicle? vehicle) { if (Object.op_Implicit((Object)(object)vehicle) && vehicle.IsReady && !vehicle.TrainOccupied && !vehicle.TrainHasPassengers && vehicle.PassengerBoardingAllowed) { return Mathf.Abs(vehicle.Speed) < 0.05f; } return false; } internal static bool IsDestroyed(string identity) { if (identity.Length != 0) { return DestroyedIdentities.Contains(identity); } return false; } internal static void RecordDestroyed(string identity) { if (identity.Length != 0) { DestroyedIdentities.Add(identity); } } private static Func? BindExistingObjectCreation() { try { MethodInfo methodInfo = AccessTools.Method(typeof(ZNetScene), "CreateObject", new Type[1] { typeof(ZDO) }, (Type[])null); return (methodInfo?.ReturnType == typeof(GameObject)) ? ((Func)Delegate.CreateDelegate(typeof(Func), methodInfo)) : null; } catch { return null; } } internal bool BeginHammerRemoval(long sender, bool blockDrops, out string error) { error = ""; if (!Object.op_Implicit((Object)(object)Vehicle) || !Ready || !View.IsOwner()) { return true; } if (_hammerWaitUntil > 0f && blockDrops != _hammerWaitingBlockDrops) { return false; } Piece component = ((Component)this).GetComponent(); if (!CanRemoveVehicleNow(component)) { _hammerWaitUntil = 0f; error = "The vehicle can no longer be removed. Empty and close its storage, clear riders, then retry."; return false; } if (_hammerWaitUntil > 0f && (!Parked(Vehicle) || !ValidHammerRequester(out error))) { _hammerWaitUntil = 0f; if (error.Length == 0) { error = "Vehicle removal stopped because the train is no longer parked and clear."; } return false; } if (!Object.op_Implicit((Object)(object)ZNetScene.instance) || ZDOMan.instance == null) { error = "Wait for the railway and its torch attachments to load before removing this vehicle."; return false; } List list = new List(); List nearby = null; try { for (int i = 0; i < Count; i++) { string text = IdentityAt(i); if (text.Length == 0) { continue; } if (IsDestroyed(text)) { ClearSlot(i); continue; } ZDO val = FindSavedChild(View.GetZDO(), text, i, ref nearby); if (val == null) { error = "Wait nearby for the attached torches to synchronize, then remove the vehicle again."; return false; } ZNetView val2 = ZNetScene.instance.FindInstance(val); if (val.GetFloat(ZDOVars.s_health, 1f) <= 0f) { if (Object.op_Implicit((Object)(object)val2) && val2.IsValid()) { error = "Wait for the attached torch to finish removal, then retry the vehicle."; return false; } RecordDestroyed(text); ClearSlot(i); continue; } if (!Object.op_Implicit((Object)(object)val2)) { GameObject prefab = ZNetScene.instance.GetPrefab(val.GetPrefab()); if (!Object.op_Implicit((Object)(object)prefab) || !Object.op_Implicit((Object)(object)prefab.GetComponent()) || CreateExistingObject == null || ZNetView.m_useInitZDO || ZNetView.m_initZDO != null) { error = "An attached torch cannot load safely. Wait nearby or remove it first, then retry the vehicle."; return false; } try { CreateExistingObject(ZNetScene.instance, val); } finally { ZNetView.m_useInitZDO = false; ZNetView.m_initZDO = null; } val2 = ZNetScene.instance.FindInstance(val); } RailMountedTorch railMountedTorch = (Object.op_Implicit((Object)(object)val2) ? ((Component)val2).GetComponent() : null); if (!Object.op_Implicit((Object)(object)railMountedTorch) || !railMountedTorch.Ready || !Object.op_Implicit((Object)(object)((Component)railMountedTorch).GetComponent()) || !MatchesSavedChild(railMountedTorch.View.GetZDO(), text, PersistentId, i)) { error = "An attached torch is not ready for removal. Wait nearby and try again."; return false; } list.Add(railMountedTorch); } if (list.Count > 0 && !Parked(Vehicle)) { error = "Park and clear the train before removing a vehicle with attached torches."; return false; } if (list.Count == 0) { if (_hammerWaitUntil > 0f && !ValidHammerRequester(out error)) { _hammerWaitUntil = 0f; return false; } _hammerWaitUntil = 0f; return true; } if (_hammerWaitUntil == 0f) { Player val3 = null; foreach (Player allPlayer in Player.GetAllPlayers()) { if (Object.op_Implicit((Object)(object)allPlayer) && ((Character)allPlayer).GetOwner() == sender) { val3 = allPlayer; break; } } _hammerRequesterPlayer = (Object.op_Implicit((Object)(object)val3) ? val3.GetPlayerID() : 0); _hammerRequesterPeer = sender; _hammerWaitingBlockDrops = blockDrops; _hammerWaitUntil = Time.unscaledTime + 10f; } if (!ValidHammerRequester(out error)) { _hammerWaitUntil = 0f; return false; } foreach (RailMountedTorch item in list) { if (!item.View.HasOwner()) { item.View.ClaimOwnership(); } } if (Time.unscaledTime >= _nextHammerChildRequest) { _nextHammerChildRequest = Time.unscaledTime + 1f; foreach (RailMountedTorch item2 in list) { string persistentId = item2.PersistentId; int slot = item2.Slot; item2.Follow(this); ((Component)item2).GetComponent().Remove(_hammerWaitingBlockDrops); if (!item2.Ready && slot >= 0 && slot < Count && IdentityAt(slot) == persistentId) { RecordDestroyed(persistentId); ClearSlot(slot); } } } foreach (RailMountedTorch item3 in list) { if (Object.op_Implicit((Object)(object)item3) && item3.Ready) { return false; } } if (!CanRemoveVehicleNow(component) || !Parked(Vehicle) || !ValidHammerRequester(out error)) { _hammerWaitUntil = 0f; return false; } _hammerWaitUntil = 0f; return true; } catch (Exception ex) { error = "The vehicle was kept because its attached torches could not be prepared for removal. " + ex.GetBaseException().Message; return false; } } internal void WarnRemovalBlocked(string reason) { if (reason.Length != 0 && !(Time.unscaledTime < _nextRemovalWarning)) { _nextRemovalWarning = Time.unscaledTime + 2f; RailPlugin.Warn(reason); if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, reason, 0, (Sprite)null, false); } } } private void ContinueHammerRemoval() { if (_hammerWaitUntil != 0f) { Piece component = ((Component)this).GetComponent(); string reason; if (!Ready || !View.IsOwner() || !Object.op_Implicit((Object)(object)Vehicle) || !Parked(Vehicle) || !CanRemoveVehicleNow(component)) { _hammerWaitUntil = 0f; WarnRemovalBlocked("Vehicle removal stopped because its owner, cargo or parked state changed. Empty and park the train, then retry."); } else if (!ValidHammerRequester(out reason)) { _hammerWaitUntil = 0f; WarnRemovalBlocked(reason); } else if (Time.unscaledTime >= _hammerWaitUntil) { _hammerWaitUntil = 0f; WarnRemovalBlocked("The vehicle was kept while an attached torch was still synchronizing. Wait nearby and remove the vehicle again."); } else if (!(Time.unscaledTime < _nextHammerPoll)) { _nextHammerPoll = Time.unscaledTime + 0.5f; _wear.Remove(_hammerWaitingBlockDrops); } } } private bool CanRemoveVehicleNow(Piece? piece) { if (!Object.op_Implicit((Object)(object)piece) || !piece.m_canBeRemoved || !piece.CanBeRemoved()) { return false; } Container component = ((Component)this).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { if (!component.IsInUse()) { return View.GetZDO().GetInt("InUse", 0) != 1; } return false; } return true; } private bool ValidHammerRequester(out string reason) { //IL_004b: 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_0076: 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) Player val = ((_hammerRequesterPlayer == 0L) ? null : Player.GetPlayer(_hammerRequesterPlayer)); if (!Object.op_Implicit((Object)(object)val) || ((Character)val).GetOwner() != _hammerRequesterPeer || ((Character)val).IsDead() || ((Character)val).IsTeleporting() || ((Character)val).IsAttached() || Vector3.Distance(((Component)val).transform.position, ((Component)this).transform.position) > 8f) { reason = "Vehicle removal stopped because the requesting player left. Stand nearby on foot and retry."; return false; } if (Location.IsInsideNoBuildLocation(((Component)this).transform.position) || !CanAccessWard(((Component)this).transform.position, _hammerRequesterPlayer)) { reason = "Vehicle removal stopped because build or ward access changed."; return false; } reason = ""; return true; } private static void TrackDestroyed(ZDO zdo) { string text = zdo.GetString("vikingrail_identity", ""); RecordDestroyed(text); if (text.Length != 0 && Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer()) { DetachSavedChildren(zdo); } string text2 = zdo.GetString("vikingrail_torch_parent_guid", ""); int num = zdo.GetInt("vikingrail_torch_slot", -1); if (text2.Length != 0 && num >= 0) { RailTorchMounts railTorchMounts = Find(text2); if (Object.op_Implicit((Object)(object)railTorchMounts) && railTorchMounts.Ready && railTorchMounts.View.IsOwner() && num < railTorchMounts.Count && railTorchMounts.IdentityAt(num) == text) { railTorchMounts.ClearSlot(num); } } } internal static void Cleanup() { if (DestroyedCallback != null && _trackedManager != null) { DestroyedCallback.SetValue(_trackedManager, Delegate.Remove(DestroyedCallback.GetValue(_trackedManager) as Delegate, new Action(TrackDestroyed))); } _trackedManager = null; DestroyedIdentities.Clear(); Hosts.Clear(); RailTorchPlacementPatch.Target = null; RailTorchPlacementPatch.TargetSlot = -1; RailTorchPlacementPatch.Active = false; } internal static void EnsureDestructionTracking() { if (_trackedManager != ZDOMan.instance && ZDOMan.instance != null) { if (DestroyedCallback != null && _trackedManager != null) { DestroyedCallback.SetValue(_trackedManager, Delegate.Remove(DestroyedCallback.GetValue(_trackedManager) as Delegate, new Action(TrackDestroyed))); } DestroyedIdentities.Clear(); _trackedManager = ZDOMan.instance; if (DestroyedCallback != null) { DestroyedCallback.SetValue(_trackedManager, Delegate.Combine(DestroyedCallback.GetValue(_trackedManager) as Delegate, new Action(TrackDestroyed))); } } } private static bool MatchesSavedChild(ZDO? child, string identity, string parentIdentity, int slot) { if (child != null && child.GetString("vikingrail_identity", "") == identity && child.GetString("vikingrail_torch_parent_guid", "") == parentIdentity) { return child.GetInt("vikingrail_torch_slot", -1) == slot; } return false; } private static ZDO? FindSavedChild(ZDO parent, string identity, int slot, ref List? nearby) { //IL_001d: 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_004e: Unknown result type (might be due to invalid IL or missing references) string parentIdentity = parent.GetString("vikingrail_identity", ""); ZDO zDO = ZDOMan.instance.GetZDO(parent.GetZDOID(Key(slot))); if (MatchesSavedChild(zDO, identity, parentIdentity, slot)) { return zDO; } if (nearby == null) { nearby = new List(); ZDOMan.instance.FindSectorObjects(parent.GetSector(), new SimulationDistance(1, 0, false), nearby, (List)null); } foreach (ZDO item in nearby) { if (MatchesSavedChild(item, identity, parentIdentity, slot)) { return item; } } return null; } private static void ClearSavedParent(ZDO child) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) child.Set("vikingrail_torch_parent", ZDOID.None); child.Set("vikingrail_torch_parent_guid", ""); child.Set("vikingrail_torch_slot", -1); } private static void DetachSavedChildren(ZDO parent) { List nearby = null; for (int i = 0; i < 4; i++) { string text = parent.GetString(GuidKey(i), ""); if (text.Length != 0) { ZDO val = FindSavedChild(parent, text, i, ref nearby); if (val != null) { val.SetOwner(ZDOMan.GetSessionID()); ClearSavedParent(val); } } } } internal ZDOID IdAt(int slot) { //IL_0015: 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) if (!Ready || slot < 0 || slot >= Count) { return ZDOID.None; } return View.GetZDO().GetZDOID(Key(slot)); } internal string IdentityAt(int slot) { if (!Ready || slot < 0 || slot >= Count) { return ""; } return View.GetZDO().GetString(GuidKey(slot), ""); } internal bool Free(int slot) { if (slot >= 0 && slot < Count) { if (IdentityAt(slot).Length != 0) { return IsDestroyed(IdentityAt(slot)); } return true; } return false; } private void Awake() { Vehicle = ((Component)this).GetComponent(); _view = ((Component)this).GetComponent(); _wear = ((Component)this).GetComponent(); } private void Start() { if (Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { EnsureRegistration(); EnsureDestructionTracking(); View.Register("VR_MountTorch", (Action)RequestMount); View.Register("VR_UnmountTorch", (Action)RequestUnmount); if (Object.op_Implicit((Object)(object)_wear)) { WearNTear wear = _wear; wear.m_onDestroyed = (Action)Delegate.Combine(wear.m_onDestroyed, new Action(OnDestroyedPermanently)); } } } private void EnsureRegistration() { if (!Object.op_Implicit((Object)(object)_view) || !_view.IsValid()) { return; } if (_view.IsOwner() && PersistentId.Length == 0) { _view.GetZDO().Set("vikingrail_identity", Guid.NewGuid().ToString("N")); } if (!Ready) { return; } string persistentId = PersistentId; if (_registeredIdentity != persistentId) { if (_registeredIdentity.Length != 0 && (Object)(object)Find(_registeredIdentity) == (Object)(object)this) { Hosts.Remove(_registeredIdentity); } _registeredIdentity = persistentId; } if ((Object)(object)Find(persistentId) != (Object)(object)this) { Hosts[persistentId] = this; } } private void Update() { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) EnsureRegistration(); ContinueHammerRemoval(); if (!Ready || !View.IsOwner() || Time.time < _nextRefresh) { return; } _nextRefresh = Time.time + 1f; for (int i = 0; i < Count; i++) { string text = IdentityAt(i); if (text.Length == 0) { continue; } if (IsDestroyed(text)) { ClearSlot(i); continue; } RailMountedTorch railMountedTorch = RailMountedTorch.Find(text); if (Object.op_Implicit((Object)(object)railMountedTorch) && !(railMountedTorch.ParentIdentity != PersistentId) && railMountedTorch.Slot == i) { View.GetZDO().Set(Key(i), railMountedTorch.View.GetZDO().m_uid); View.GetZDO().Set(OwnerKey(i), railMountedTorch.View.GetZDO().GetOwner()); } } } private void RequestMount(long sender, long playerId, ZDOID id, int slot) { //IL_0025: 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_0119: 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_0138: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: 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_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !View.IsOwner() || slot < 0 || slot >= Count) { return; } RailMountedTorch railMountedTorch = RailMountedTorch.Find(id); if (Object.op_Implicit((Object)(object)railMountedTorch) && railMountedTorch.PersistentId.Length != 0 && IdentityAt(slot) == railMountedTorch.PersistentId && railMountedTorch.ParentIdentity == PersistentId && railMountedTorch.Slot == slot) { return; } Player player = Player.GetPlayer(playerId); if (Object.op_Implicit((Object)(object)player) && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && ((Character)player).GetOwner() == sender && !((Character)player).IsAttached() && CanMount && Free(slot) && Object.op_Implicit((Object)(object)railMountedTorch) && railMountedTorch.Ready && railMountedTorch.View.GetZDO().GetOwner() == sender && railMountedTorch.ParentIdentity.Length == 0 && railMountedTorch.PersistentId.Length != 0 && !(Vector3.Distance(((Component)player).transform.position, Socket(slot)) > 8f) && !(Vector3.Distance(((Component)railMountedTorch).transform.position, Socket(slot)) > 0.3f) && CanAccessWard(Socket(slot), playerId)) { ZDO zDO = railMountedTorch.View.GetZDO(); ZDO zDO2 = View.GetZDO(); Quaternion val = Quaternion.Inverse(((Component)this).transform.rotation) * ((Component)railMountedTorch).transform.rotation; railMountedTorch.View.ClaimOwnership(); if (railMountedTorch.View.IsOwner()) { zDO.Set("vikingrail_torch_parent", zDO2.m_uid); zDO.Set("vikingrail_torch_parent_guid", PersistentId); zDO.Set("vikingrail_torch_slot", slot); zDO.Set("vikingrail_torch_rotation", val); zDO2.Set(Key(slot), id); zDO2.Set(GuidKey(slot), railMountedTorch.PersistentId); zDO2.Set(OwnerKey(slot), zDO.GetOwner()); railMountedTorch.Follow(this); ZDOMan.instance.ForceSendZDO(sender, zDO2.m_uid); ZDOMan.instance.ForceSendZDO(sender, id); } } } private void RequestUnmount(long sender, string identity, int slot) { if (Ready && View.IsOwner() && slot >= 0 && slot < Count && !(IdentityAt(slot) != identity)) { RailMountedTorch railMountedTorch = RailMountedTorch.Find(identity); ZDO val = (Object.op_Implicit((Object)(object)railMountedTorch) ? railMountedTorch.View.GetZDO() : null); if ((val != null && val.GetOwner() == sender) || View.GetZDO().GetLong(OwnerKey(slot), 0L) == sender || IsDestroyed(identity)) { ClearSlot(slot); } } } private void ClearSlot(int slot) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) View.GetZDO().Set(Key(slot), ZDOID.None); View.GetZDO().Set(GuidKey(slot), ""); View.GetZDO().Set(OwnerKey(slot), 0L); } internal static bool PrepareTrain(IReadOnlyList train, out string reason) { //IL_0126: Unknown result type (might be due to invalid IL or missing references) reason = ""; foreach (RailVehicle item in train) { RailTorchMounts component = ((Component)item).GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { continue; } for (int i = 0; i < 4; i++) { string text = component.IdentityAt(i); if (text.Length == 0) { continue; } if (IsDestroyed(text)) { if (item.View.IsOwner()) { component.ClearSlot(i); } continue; } RailMountedTorch railMountedTorch = RailMountedTorch.Find(text); if (!Object.op_Implicit((Object)(object)railMountedTorch) || !railMountedTorch.Ready) { reason = "A mounted torch is not loaded. Wait nearby for it to appear."; return false; } if (railMountedTorch.ParentIdentity != item.PersistentId || (Object)(object)railMountedTorch.Vehicle != (Object)(object)item || railMountedTorch.Slot != i) { reason = "A torch attachment is still synchronizing. Wait before moving."; return false; } railMountedTorch.View.ClaimOwnership(); if (!railMountedTorch.View.IsOwner()) { reason = "Waiting for a mounted torch's network owner."; return false; } if (item.View.IsOwner()) { item.View.GetZDO().Set(Key(i), railMountedTorch.View.GetZDO().m_uid); item.View.GetZDO().Set(OwnerKey(i), railMountedTorch.View.GetZDO().GetOwner()); } railMountedTorch.Follow(item); } } return true; } private void OnDestroyedPermanently() { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !View.IsOwner()) { return; } RecordDestroyed(PersistentId); List nearby = null; for (int i = 0; i < Count; i++) { string text = IdentityAt(i); if (text.Length == 0) { continue; } RailMountedTorch railMountedTorch = RailMountedTorch.Find(text); ZDO val = (ZDO)(Object.op_Implicit((Object)(object)railMountedTorch) ? ((object)railMountedTorch.View.GetZDO()) : ((object)FindSavedChild(View.GetZDO(), text, i, ref nearby))); if (MatchesSavedChild(val, text, PersistentId, i)) { if (Object.op_Implicit((Object)(object)railMountedTorch)) { railMountedTorch.View.ClaimOwnership(); railMountedTorch.Follow(this); railMountedTorch.ClearParent(); } else { val.SetOwner(View.GetZDO().GetOwner()); val.SetPosition(Socket(i)); ClearSavedParent(val); } ClearSlot(i); } } } private void OnDestroy() { if (Object.op_Implicit((Object)(object)_wear)) { WearNTear wear = _wear; wear.m_onDestroyed = (Action)Delegate.Remove(wear.m_onDestroyed, new Action(OnDestroyedPermanently)); } if (_registeredIdentity.Length != 0 && (Object)(object)Find(_registeredIdentity) == (Object)(object)this) { Hosts.Remove(_registeredIdentity); } } private static bool CanAccessWard(Vector3 point, long playerId) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) if (WardList == null || WardEnabled == null || WardInside == null || WardPermitted == null) { return false; } if (!(WardList.GetValue(null) is IEnumerable enumerable)) { return false; } bool flag = false; foreach (PrivateArea item in enumerable) { if (Object.op_Implicit((Object)(object)item) && true.Equals(WardEnabled.Invoke(item, null)) && true.Equals(WardInside.Invoke(item, new object[2] { point, 0f }))) { Piece component = ((Component)item).GetComponent(); if ((Object.op_Implicit((Object)(object)component) && component.GetCreator() == playerId) || true.Equals(WardPermitted.Invoke(item, new object[1] { playerId }))) { return true; } flag = true; } } return !flag; } } [HarmonyPatch(typeof(Player), "UpdatePlacementGhost")] internal static class RailTorchPlacementPatch { internal static RailTorchMounts? Target; internal static int TargetSlot = -1; internal static bool Active; internal static readonly bool Compatible = AccessTools.Method(typeof(Player), "UpdatePlacementGhost", new Type[1] { typeof(bool) }, (Type[])null) != null && AccessTools.Method(typeof(Player), "PieceRayTest", new Type[6] { typeof(Vector3).MakeByRefType(), typeof(Vector3).MakeByRefType(), typeof(Piece).MakeByRefType(), typeof(Heightmap).MakeByRefType(), typeof(Collider).MakeByRefType(), typeof(bool) }, (Type[])null) != null && AccessTools.Field(typeof(Player), "m_placementGhost")?.FieldType == typeof(GameObject) && AccessTools.Field(typeof(Player), "m_placeRayMask")?.FieldType == typeof(int) && AccessTools.Field(typeof(Player), "m_maxPlaceDistance")?.FieldType == typeof(float) && AccessTools.Field(typeof(Player), "m_eye")?.FieldType == typeof(Transform); [HarmonyPrepare] private static bool Prepare() { return Compatible; } [HarmonyPrefix] private static void Prefix(GameObject ___m_placementGhost, out List __state) { __state = new List(); Target = null; TargetSlot = -1; Active = Object.op_Implicit((Object)(object)___m_placementGhost) && Object.op_Implicit((Object)(object)___m_placementGhost.GetComponent()); if (!Active) { return; } foreach (RailVehicle loadedVehicle in RailVehicle.LoadedVehicles) { if (RailTorchMounts.Parked(loadedVehicle)) { WearNTear component = ((Component)loadedVehicle).GetComponent(); if (Object.op_Implicit((Object)(object)component) && !component.m_supports) { component.m_supports = true; __state.Add(component); } } } } [HarmonyFinalizer] private static void Finalizer(List? __state) { if (__state != null) { foreach (WearNTear item in __state) { if (Object.op_Implicit((Object)(object)item)) { item.m_supports = false; } } } Active = false; } } [HarmonyPatch(typeof(Player), "PieceRayTest")] internal static class RailTorchPlacementRayPatch { [HarmonyPrepare] private static bool Prepare() { return RailTorchPlacementPatch.Compatible; } [HarmonyPrefix] private static bool Prefix(Player __instance, ref Vector3 point, ref Vector3 normal, ref Piece piece, ref Heightmap heightmap, ref Collider waterSurface, ref bool __result, int ___m_placeRayMask, float ___m_maxPlaceDistance, Transform ___m_eye) { //IL_000a: 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_0015: 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_004e: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_00ab: 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_00e6: 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_00fd: 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_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) if (!RailTorchPlacementPatch.Active) { return true; } point = Vector3.zero; normal = Vector3.up; piece = null; heightmap = null; waterSurface = null; __result = false; if (!Object.op_Implicit((Object)(object)GameCamera.instance) || ((Character)__instance).IsAttached()) { return false; } RaycastHit val = default(RaycastHit); if (!Physics.Raycast(((Component)GameCamera.instance).transform.position, ((Component)GameCamera.instance).transform.forward, ref val, 50f, ___m_placeRayMask, (QueryTriggerInteraction)1)) { return false; } RailTorchMounts componentInParent = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent(); if (!Object.op_Implicit((Object)(object)componentInParent) || !componentInParent.CanMount) { return false; } int num = -1; float num2 = float.MaxValue; for (int i = 0; i < componentInParent.Count; i++) { float num3 = Vector3.SqrMagnitude(((RaycastHit)(ref val)).point - componentInParent.Socket(i)); if (!(num3 >= num2)) { num2 = num3; num = i; } } if (num < 0 || !componentInParent.Free(num) || Vector3.Distance(___m_eye.position, ((RaycastHit)(ref val)).point) >= ___m_maxPlaceDistance || Vector3.Distance(___m_eye.position, componentInParent.Socket(num)) >= ___m_maxPlaceDistance) { return false; } point = componentInParent.Socket(num); piece = ((Component)componentInParent).GetComponent(); RailTorchPlacementPatch.Target = componentInParent; RailTorchPlacementPatch.TargetSlot = num; __result = true; return false; } } [HarmonyPatch(typeof(Piece), "CanBeRemoved")] internal static class MountedRailTorchRemovalPatch { [HarmonyPostfix] private static void Postfix(Piece __instance, ref bool __result) { RailMountedTorch component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.Vehicle) && !RailTorchMounts.Parked(component.Vehicle)) { __result = false; } } } [HarmonyPatch(typeof(WearNTear), "RPC_Remove")] internal static class MountedRailTorchRemovalRequestPatch { [HarmonyPrefix] private static bool Prefix(WearNTear __instance) { RailMountedTorch component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.Vehicle)) { return RailTorchMounts.Parked(component.Vehicle); } return true; } } [HarmonyPatch(typeof(WearNTear), "RPC_Remove")] internal static class RailVehicleHammerTorchRemovalPatch { [HarmonyPrefix] [HarmonyPriority(0)] private static bool Prefix(WearNTear __instance, long __0, bool __1) { RailTorchMounts component = ((Component)__instance).GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component.Vehicle) || !component.Ready || !component.View.IsOwner()) { return true; } if (!component.BeginHammerRemoval(__0, __1, out string error)) { component.WarnRemovalBlocked(error); return false; } return true; } } internal static class RailMusicAudio { private sealed class CachedTrack { internal Task? Decode; internal AudioClip? Clip; internal bool Failed; } private static readonly Dictionary Tracks = new Dictionary(StringComparer.Ordinal); internal static AudioClip? GetClip(RailMusicTrack track) { if (track == null || !RailMusicTracks.TryForTrackId(track.TrackId, out RailMusicTrack track2) || track != track2) { return null; } if (!Tracks.TryGetValue(track.TrackId, out CachedTrack value)) { Tracks.Add(track.TrackId, value = new CachedTrack()); } if (Object.op_Implicit((Object)(object)value.Clip) || value.Failed) { return value.Clip; } if (value.Decode == null) { value.Decode = Task.Run(delegate { using Stream stream = typeof(RailMusicAudio).Assembly.GetManifestResourceStream(track.ResourceName); if (stream == null || stream.Length > 16777216) { throw new InvalidDataException("Bundled soundtrack is unavailable."); } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); RailMusicPcm railMusicPcm = RailMusicWave.Decode(memoryStream.ToArray()); if (Math.Abs((double)railMusicPcm.Samples.Length / (double)railMusicPcm.SampleRate - track.Duration) > 1.0 / (double)railMusicPcm.SampleRate + 1E-06) { throw new InvalidDataException("Bundled soundtrack length does not match its music clock."); } return railMusicPcm; }); return null; } if (!value.Decode.IsCompleted) { return null; } try { RailMusicPcm result = value.Decode.GetAwaiter().GetResult(); value.Clip = AudioClip.Create(track.Title, result.Samples.Length, 1, result.SampleRate, false); MethodInfo methodInfo = AccessTools.Method(typeof(AudioClip), "SetData", new Type[2] { typeof(float[]), typeof(int) }, (Type[])null); if (methodInfo == null || !(bool)methodInfo.Invoke(value.Clip, new object[2] { result.Samples, 0 })) { throw new InvalidOperationException("Unity could not load the soundtrack PCM."); } } catch (Exception ex) { if (Object.op_Implicit((Object)(object)value.Clip)) { Object.Destroy((Object)(object)value.Clip); } value.Clip = null; value.Failed = true; RailPlugin.Warn(track.Title + " is unavailable: " + ex.GetBaseException().Message); } value.Decode = null; return value.Clip; } internal static void Cleanup() { foreach (CachedTrack value in Tracks.Values) { if (value.Decode != null) { value.Decode.ContinueWith(delegate(Task t) { _ = t.Exception; }, TaskContinuationOptions.OnlyOnFaulted); } if (Object.op_Implicit((Object)(object)value.Clip)) { Object.Destroy((Object)(object)value.Clip); } } Tracks.Clear(); } } public sealed class RailMusicCart : MonoBehaviour { private sealed class Performance { internal RailMusicTrack Track = RailMusicTracks.Techno; internal string Group = ""; internal bool Playing; internal long Session; internal long Start; internal long Changed; internal long VolumeChanged; internal int Volume = 100; internal bool Mixed; } private const string PlayingKey = "vr_music_playing"; private const string SessionKey = "vr_music_session"; private const string StartKey = "vr_music_start"; private static readonly HashSet Carts = new HashSet(); private static readonly HashSet Audible = new HashSet(); private static float _nextSelection; private RailVehicle _cart; private ZNetView _view; private RailMusicTrack? _track; private AudioSource? _source; private float _gain; private float _nextDriftCheck; private float _sourceStartedAt; private float _nextPlaybackReport = -1f; private long _heardStart; private Transform? _dancer; private Transform? _arm; private Transform? _leftDisc; private Transform? _rightDisc; private Transform? _lever; private Quaternion _dancerRest; private Quaternion _armRest; private Quaternion _leftRest; private Quaternion _rightRest; private Quaternion _leverRest; private Renderer[] _runes = Array.Empty(); private readonly MaterialPropertyBlock _runeBlock = new MaterialPropertyBlock(); private static readonly int Emission = Shader.PropertyToID("_EmissionColor"); private const string ChangedKey = "vr_music_changed"; private const string VolumeKey = "vr_music_volume"; private const string VolumeChangedKey = "vr_music_volume_changed"; private static readonly Dictionary Performances = new Dictionary(); private static float _nextMixRefresh; private RailMusicTrack? Track => _track ?? (_track = ResolveTrack(((Component)this).gameObject)); internal string DisplayName => Track?.DisplayName ?? "Rail music cart"; internal bool SupportsBanner { get { RailMusicTrack? track = Track; if (track != null && track.SupportsBanner) { return Object.op_Implicit((Object)(object)((Component)this).GetComponent()); } return false; } } internal bool Ready { get { if (Object.op_Implicit((Object)(object)_cart) && _cart.IsReady && Object.op_Implicit((Object)(object)_view) && _view.IsValid() && Track != null) { return _view.GetZDO().GetPrefab() == StringExtensionMethods.GetStableHashCode(Track.PrefabName); } return false; } } internal RailVehicle Cart => _cart; internal ZNetView View => _view; internal static long Session { get { if (Object.op_Implicit((Object)(object)ZNet.instance)) { if (!ZNet.instance.IsServer()) { return ZNet.instance.GetServerPeer()?.m_uid ?? 0; } return ZNet.GetUID(); } return 0L; } } private static long Now { get { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return 0L; } return ZNet.instance.GetTime().Ticks; } } internal bool Playing { get { double seconds; if (Track != null) { return Position(Track.Duration, out seconds); } return false; } } private bool SuppressedByVoiceLimit { get { //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) if (Object.op_Implicit((Object)(object)_source) && _source.isPlaying && _source.isVirtual && Playing && Audible.Contains(this) && _source.volume > 0f && !_source.mute && !RailSettings.MusicMuted && !AudioListener.pause && AudioListener.volume > 0f && AudioMan.GetSFXVolume() > 0f && Time.unscaledTime - _sourceStartedAt >= 1f && Listener(out var position)) { return (double)Vector3.Distance(((Component)this).transform.position, position) < RailSettings.MusicCartRange; } return false; } } private string MusicIdentity => ((object)Unsafe.As(ref _view.GetZDO().m_uid)/*cast due to .constrained prefix*/).ToString(); internal int VolumePercent => CurrentPerformance.Volume; private int OwnVolume => RailMusicVolume.NormalizeSaved(_view.GetZDO().GetInt("vr_music_volume", 100)); private Performance CurrentPerformance { get { RefreshPerformances(); if (!Performances.TryGetValue(this, out Performance value)) { return new Performance { Track = (Track ?? RailMusicTracks.Techno) }; } return value; } } private double PlaybackGain => RailMusicVolume.Gain(RailSettings.MusicVolume, PersonalModeVolume(CurrentPerformance.Track), RailSettings.MusicCartMaxVolume, VolumePercent, RailSettings.MusicMuted); private static RailMusicTrack? ResolveTrack(GameObject obj) { if (!RailMusicTracks.TryForPrefab(Utils.GetPrefabName(obj), out RailMusicTrack track)) { return null; } return track; } private void Awake() { //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_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_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_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_00f2: 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) _cart = ((Component)this).GetComponent(); _view = ((Component)this).GetComponent(); _track = ResolveTrack(((Component)this).gameObject); _dancer = ((Component)this).transform.Find("visual/vr_music_dancer"); _arm = (Object.op_Implicit((Object)(object)_dancer) ? _dancer.Find("vr_music_point_arm") : null); _leftDisc = ((Component)this).transform.Find("visual/vr_music_disc_left"); _rightDisc = ((Component)this).transform.Find("visual/vr_music_disc_right"); _lever = ((Component)this).transform.Find("visual/vr_music_lever"); _dancerRest = Rest(_dancer); _armRest = Rest(_arm); _leftRest = Rest(_leftDisc); _rightRest = Rest(_rightDisc); _leverRest = Rest(_lever); Transform val = ((Component)this).transform.Find("visual/vr_music_runes"); if (Object.op_Implicit((Object)(object)val)) { _runes = ((Component)val).GetComponentsInChildren(true); } } private static Quaternion Rest(Transform? part) { //IL_000f: 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) if (!Object.op_Implicit((Object)(object)part)) { return Quaternion.identity; } return part.localRotation; } private void Start() { if (Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { Carts.Add(this); } } private void OnDisable() { Carts.Remove(this); Audible.Remove(this); InvalidatePerformances(); StopAudio(); } private void OnEnable() { if (Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { Carts.Add(this); } } private void OnDestroy() { Carts.Remove(this); Audible.Remove(this); InvalidatePerformances(); StopAudio(); } private void StopAudio() { if (Object.op_Implicit((Object)(object)_source)) { _source.Stop(); Object.Destroy((Object)(object)_source); } _source = null; _gain = 0f; _heardStart = 0L; _nextPlaybackReport = -1f; } private bool Position(double length, out double seconds) { seconds = 0.0; if (!Ready || !RailSettings.Ready || !RailSettings.MusicCartsEnabled) { return false; } Performance currentPerformance = CurrentPerformance; return RailMusicPlayback.TryPosition(currentPerformance.Playing, currentPerformance.Session, Session, currentPerformance.Start, Now, length, out seconds); } internal static bool Listener(out Vector3 position) { //IL_0001: 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_003d: Invalid comparison between Unknown and I4 //IL_0065: 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) position = default(Vector3); if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)AudioMan.instance) || !Object.op_Implicit((Object)(object)ZNet.instance) || ZNet.instance.IsDedicated() || (int)SystemInfo.graphicsDeviceType == 4) { return false; } AudioListener activeAudioListener = AudioMan.instance.GetActiveAudioListener(); if (!Object.op_Implicit((Object)(object)activeAudioListener) || !((Behaviour)activeAudioListener).isActiveAndEnabled) { return false; } position = ((Component)activeAudioListener).transform.position; return true; } internal static void SelectAudible() { RefreshPerformances(); if (Time.unscaledTime < _nextSelection) { return; } _nextSelection = Time.unscaledTime + 0.25f; if (!RailSettings.Ready || !RailSettings.MusicCartsEnabled || RailSettings.MusicMuted || RailSettings.MusicVolume <= 0.0 || RailSettings.MusicCartMaxVolume <= 0.0 || !Listener(out var listener)) { Audible.Clear(); return; } float range = (float)RailSettings.MusicCartRange; RailMusicCart[] array = (from @group in (from c in Carts where Object.op_Implicit((Object)(object)c) && ((Behaviour)c).isActiveAndEnabled && c.Playing && c.PlaybackGain > 0.0 && Vector3.Distance(((Component)c).transform.position, listener) < range orderby Vector3.Distance(((Component)c).transform.position, listener) - (Audible.Contains(c) ? 2f : 0f) select c).ThenBy((RailMusicCart c) => ((object)Unsafe.As(ref c._view.GetZDO().m_uid)/*cast due to .constrained prefix*/).ToString(), StringComparer.Ordinal).GroupBy((RailMusicCart c) => c.CurrentPerformance.Group, StringComparer.Ordinal) select @group.First()).Take(RailSettings.MusicMaxAudibleCarts).ToArray(); foreach (RailMusicCart previous in Carts) { if (Object.op_Implicit((Object)(object)previous) && Object.op_Implicit((Object)(object)previous._source) && !array.Contains(previous) && previous.CurrentPerformance.Mixed && array.Any((RailMusicCart next) => next.CurrentPerformance.Group == previous.CurrentPerformance.Group)) { previous.StopAudio(); } } Audible.Clear(); RailMusicCart[] array2 = array; foreach (RailMusicCart item in array2) { Audible.Add(item); } } private void Update() { //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_0414: Unknown result type (might be due to invalid IL or missing references) if (Ready) { Carts.Add(this); } else { Carts.Remove(this); Audible.Remove(this); } Vector3 position; bool flag = Listener(out position); RailMusicTrack track = CurrentPerformance.Track; SelectAudible(); double seconds = 0.0; bool flag2 = track != null && Position(track.Duration, out seconds); if (flag) { Animate(flag2, seconds, track); } bool flag3 = flag2 && flag && Audible.Contains(this) && !RailSettings.MusicMuted && PlaybackGain > 0.0; if (flag3 && (double)Vector3.Distance(((Component)this).transform.position, position) >= RailSettings.MusicCartRange) { flag3 = false; } AudioClip val = (flag3 ? RailMusicAudio.GetClip(track) : null); if (flag3 && Object.op_Implicit((Object)(object)val) && Position(val.length, out var seconds2)) { if (!Object.op_Implicit((Object)(object)_source)) { _source = ((Component)this).gameObject.AddComponent(); _source.playOnAwake = false; _source.clip = val; _source.loop = true; _source.spatialBlend = 1f; _source.dopplerLevel = 0f; _source.pitch = 1f; _source.priority = 32; _source.rolloffMode = (AudioRolloffMode)1; _source.minDistance = 3f; _source.outputAudioMixerGroup = RailAudioClips.FindEffectsMixer(); } _source.maxDistance = (float)RailSettings.MusicCartRange; long start = CurrentPerformance.Start; bool flag4 = (Object)(object)_source.clip != (Object)(object)val; if (flag4) { _source.Stop(); _source.clip = val; _gain = 0f; } if (!_source.isPlaying || start != _heardStart || flag4) { if (start != _heardStart || flag4) { _sourceStartedAt = Time.unscaledTime; _nextPlaybackReport = _sourceStartedAt + 1f; } _source.time = (float)Math.Min(seconds2, (double)val.length - 1.0 / (double)val.frequency); _source.volume = 0f; _source.Play(); _heardStart = start; _nextDriftCheck = Time.unscaledTime + 3f; } else if (Time.unscaledTime >= _nextDriftCheck) { _nextDriftCheck = Time.unscaledTime + 3f; double num = Math.Min(_source.time, (double)val.length - 1.0 / (double)val.frequency); if (num >= 0.0 && RailMusicPlayback.Drift(num, seconds2, val.length) > 0.35) { _source.time = (float)Math.Min(seconds2, (double)val.length - 1.0 / (double)val.frequency); } } } if (!Object.op_Implicit((Object)(object)_source)) { return; } _gain = Mathf.MoveTowards(_gain, (float)((flag3 && Object.op_Implicit((Object)(object)val)) ? 1 : 0), Time.unscaledDeltaTime * 2f); float num2 = (Object.op_Implicit((Object)(object)_source.outputAudioMixerGroup) ? 1f : Mathf.Clamp01(AudioMan.GetSFXVolume())); _source.volume = _gain * (float)PlaybackGain * num2; if (_nextPlaybackReport >= 0f && Time.unscaledTime >= _nextPlaybackReport) { _nextPlaybackReport = -1f; if (flag3 && Object.op_Implicit((Object)(object)val)) { ReportPlayback(position); } } if (_gain <= 0f && !flag3) { StopAudio(); } } private void ReportPlayback(Vector3 listener) { //IL_000e: 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_00e7: 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_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0141: 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) if (Object.op_Implicit((Object)(object)_source)) { AudioConfiguration configuration = AudioSettings.GetConfiguration(); AudioMixerGroup outputAudioMixerGroup = _source.outputAudioMixerGroup; RailPlugin.LogInfo(string.Format(CultureInfo.InvariantCulture, "Music playback: {0}; playing={1}; virtual={2}; priority={3}; time={4:0.00}s; gain={5:0.###}; muted={6}; SFX={7:0.###}; listenerVolume={8:0.###}; paused={9}; distance={10:0.0}/{11:0.0}m; clip={12}; mixer={13}; realVoices={14}; virtualVoices={15}.", CurrentPerformance.Track.Title, _source.isPlaying, _source.isVirtual, _source.priority, _source.time, _source.volume, _source.mute, AudioMan.GetSFXVolume(), AudioListener.volume, AudioListener.pause, Vector3.Distance(((Component)this).transform.position, listener), _source.maxDistance, _source.clip.loadState, Object.op_Implicit((Object)(object)outputAudioMixerGroup) ? ((Object)outputAudioMixerGroup).name : "direct", configuration.numRealVoices, configuration.numVirtualVoices)); } } private void Animate(bool playing, double phase, RailMusicTrack? track) { //IL_0051: 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_008c: 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_00a7: 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_00f2: 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_0115: 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_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0161: 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_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) double num = phase * (track?.BeatsPerMinute ?? 0.0) / 60.0; float num2 = (playing ? ((float)Math.Sin(num * Math.PI)) : 0f); if (Object.op_Implicit((Object)(object)_dancer)) { _dancer.localRotation = _dancerRest * Quaternion.Euler(0f, num2 * 7f, num2 * 3f); } if (Object.op_Implicit((Object)(object)_arm)) { _arm.localRotation = _armRest * Quaternion.Euler(num2 * 8f, 0f, 0f); } float num3 = (playing ? ((float)(num % 8.0) * 45f) : 0f); if (Object.op_Implicit((Object)(object)_leftDisc)) { _leftDisc.localRotation = _leftRest * Quaternion.Euler(0f, num3, 0f); } if (Object.op_Implicit((Object)(object)_rightDisc)) { _rightDisc.localRotation = _rightRest * Quaternion.Euler(0f, 0f - num3, 0f); } if (Object.op_Implicit((Object)(object)_lever)) { _lever.localRotation = _leverRest * Quaternion.Euler((float)(playing ? (-25) : 0), 0f, 0f); } float num4 = ((playing && RailSettings.MusicBeatLights && !RailSettings.MusicMuted) ? (0.6f + 0.3f * (float)Math.Sin(num * 2.0 * Math.PI)) : 0.65f); Renderer[] runes = _runes; foreach (Renderer val in runes) { if (Object.op_Implicit((Object)(object)val)) { val.GetPropertyBlock(_runeBlock); _runeBlock.SetColor(Emission, new Color(0.12f, 0.48f, 0.65f) * num4); val.SetPropertyBlock(_runeBlock); } } } internal bool CanUse(Player player) { //IL_003a: 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_0069: Unknown result type (might be due to invalid IL or missing references) if (Ready && RailSettings.Ready && Object.op_Implicit((Object)(object)player) && (Object)(object)player == (Object)(object)Player.m_localPlayer && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position) <= 5f && !_cart.CouplingServiceBusy) { return RailWardAccess.Allows(((Component)this).transform.position, player.GetPlayerID()); } return false; } internal bool CanEditBanner(Player player) { if (SupportsBanner && CanUse(player) && !((Character)player).IsAttached() && player.GetDoodadController() == null) { return RailTorchMounts.Parked(_cart); } return false; } internal bool Interact(Humanoid user, bool hold) { if (!hold) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null) { if (!CanUse(val)) { ((Character)val).Message((MessageType)2, "Wait for the cart to synchronize and stand within reach with ward access.", 0, (Sprite)null, false); return false; } if (!RailSettings.MusicCartsEnabled) { ((Character)val).Message((MessageType)2, "Sound cart music is disabled by this server.", 0, (Sprite)null, false); return false; } return RailMusicNetwork.Request(this, val, !Playing); } } return false; } internal string HoverText() { return Localization.instance.Localize(DisplayName + "\n" + CurrentPerformance.Track.Title + (CurrentPerformance.Mixed ? "\nHalloween mix — linked Techno + Pumpkin carts" : "") + "\nMusic volume: " + VolumePercent + "% (use the brass volume dial)\n[$KEY_Use] " + (Playing ? "Stop music" : "Play music") + "\n[$KEY_AltPlace + $KEY_Use] Couple / uncouple" + ((Track == RailMusicTracks.Pumpkin) ? "\nUse the chair to sit (1 seat, comfort 3)" : "") + ((!RailSettings.MusicCartsEnabled) ? "\nMusic disabled by server" : (RailSettings.MusicMuted ? "\nMuted for you (MusicClient settings)" : ((PlaybackGain <= 0.0) ? "\nSilent at current dial or config volume settings" : (SuppressedByVoiceLimit ? "\nMusic suppressed by the game's audio voice limit" : ""))))); } private bool OwnerCanUse(long peer, long playerId, out Player player) { //IL_0091: 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_00b7: Unknown result type (might be due to invalid IL or missing references) player = Player.GetPlayer(playerId); ZNetView val = (Object.op_Implicit((Object)(object)player) ? ((Component)player).GetComponent() : null); if (!Ready || !_view.IsOwner() || !((Behaviour)_cart).isActiveAndEnabled || _cart.CouplingServiceBusy || !RailSettings.Ready || !Object.op_Implicit((Object)(object)player) || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || !Object.op_Implicit((Object)(object)val) || !val.IsValid() || val.GetZDO().GetOwner() != peer || !RailWardAccess.Allows(((Component)this).transform.position, playerId)) { return false; } float num = Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position); if (num >= 0f) { return num <= 5f; } return false; } internal string ApplyBanner(long peer, long playerId, string text, string author, string authorName) { if (!SupportsBanner) { return "This carriage does not have an editable banner."; } if (!OwnerCanUse(peer, playerId, out Player player) || ((Character)player).IsAttached() || player.GetDoodadController() != null || !RailTorchMounts.Parked(_cart) || _cart.CargoServiceBusy || _cart.MountServiceBusy) { return "Park, dismount and finish other interactions before changing the banner."; } RailMusicMetadata railMusicMetadata; try { railMusicMetadata = new RailMusicMetadata(text, author, authorName); } catch (FormatException) { return "The banner text or author identity is invalid."; } if (railMusicMetadata.Author.Length == 0) { return "Waiting for your banner author identity. Try again shortly."; } ZDO zDO = _view.GetZDO(); zDO.Set(ZDOVars.s_text, railMusicMetadata.Banner); zDO.Set(ZDOVars.s_author, railMusicMetadata.Author); zDO.Set(ZDOVars.s_authorDisplayName, railMusicMetadata.AuthorName); return "Sound cart banner updated."; } internal string Apply(long peer, long playerId, bool play) { if (!OwnerCanUse(peer, playerId, out Player _)) { return "The sound cart is busy or out of reach. Try again beside it."; } if (play && !RailSettings.MusicCartsEnabled) { return "Sound cart music is disabled by this server."; } InvalidatePerformances(); Performance currentPerformance = CurrentPerformance; ZDO zDO = _view.GetZDO(); zDO.Set("vr_music_start", (play && currentPerformance.Playing && currentPerformance.Start > 0) ? currentPerformance.Start : Now); zDO.Set("vr_music_session", Session); zDO.Set("vr_music_changed", NextCommandStamp(currentPerformance.Changed)); zDO.Set("vr_music_playing", play); InvalidatePerformances(); if (!play) { return "Music stopped."; } return "Playing: " + currentPerformance.Track.Title; } internal void Capture(IDictionary data) { if (!Ready || !_view.IsOwner()) { throw new InvalidOperationException("The sound cart must finish synchronizing before packing."); } ZDO zDO = _view.GetZDO(); RailMusicTrack track = Track; (track.SupportsBanner ? new RailMusicMetadata(track, zDO.GetString(ZDOVars.s_text, "Techno Viking Express"), zDO.GetString(ZDOVars.s_author, ""), zDO.GetString(ZDOVars.s_authorDisplayName, ""), OwnVolume) : new RailMusicMetadata(track, null, "", "", OwnVolume)).Capture(data); } internal static RailMusicMetadata ReadPacked(GameObject prefab, IReadOnlyDictionary data) { if (!Object.op_Implicit((Object)(object)prefab.GetComponent())) { return RailMusicMetadata.Read(data, null); } RailMusicTrack railMusicTrack = ResolveTrack(prefab); if (railMusicTrack == null) { throw new FormatException("This vehicle has no supported soundtrack."); } return RailMusicMetadata.Read(data, railMusicTrack.PrefabName); } internal static void Restore(GameObject placed, RailMusicMetadata state) { if (Object.op_Implicit((Object)(object)placed.GetComponent())) { RailMusicTrack railMusicTrack = ResolveTrack(placed); if (railMusicTrack == null || state.Track != railMusicTrack) { throw new FormatException("The saved soundtrack does not match this carriage."); } ZNetView component = placed.GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || !component.IsOwner()) { throw new InvalidOperationException("Could not restore the music cart."); } ZDO zDO = component.GetZDO(); if (railMusicTrack.SupportsBanner) { zDO.Set(ZDOVars.s_text, state.Banner); zDO.Set(ZDOVars.s_author, state.Author); zDO.Set(ZDOVars.s_authorDisplayName, state.AuthorName); } zDO.Set("vr_music_playing", false); zDO.Set("vr_music_session", 0L); zDO.Set("vr_music_start", 0L); zDO.Set("vr_music_changed", 0L); zDO.Set("vr_music_volume", state.VolumePercent); zDO.Set("vr_music_volume_changed", 0L); InvalidatePerformances(); } } internal static void Shutdown() { RailMusicCart[] array = Carts.ToArray(); foreach (RailMusicCart railMusicCart in array) { if (Object.op_Implicit((Object)(object)railMusicCart)) { railMusicCart.StopAudio(); } } Carts.Clear(); Audible.Clear(); _nextSelection = 0f; RailMusicAudio.Cleanup(); InvalidatePerformances(); } private double PersonalModeVolume(RailMusicTrack track) { if (track != RailMusicTracks.HalloweenTechno) { if (track != RailMusicTracks.Pumpkin) { return RailSettings.MusicTechnoVolume; } return RailSettings.MusicPumpkinVolume; } return RailSettings.MusicHalloweenTechnoVolume; } private static void InvalidatePerformances() { _nextMixRefresh = (_nextSelection = 0f); Performances.Clear(); } private static void RefreshPerformances() { if (Time.unscaledTime < _nextMixRefresh) { return; } _nextMixRefresh = Time.unscaledTime + 0.1f; Dictionary dictionary = new Dictionary(Performances); Performances.Clear(); foreach (RailMusicCart cart in Carts) { if (!Object.op_Implicit((Object)(object)cart) || !cart.Ready || Performances.ContainsKey(cart)) { continue; } List list = new List { cart }; if (cart._cart.TryMusicTrain(out List train)) { List list2 = (from v in train select ((Component)v).GetComponent() into m where Object.op_Implicit((Object)(object)m) && m.Ready && ((Behaviour)m).isActiveAndEnabled select m).ToList(); if (list2.Any((RailMusicCart m) => m.Track == RailMusicTracks.Techno) && list2.Any((RailMusicCart m) => m.Track == RailMusicTracks.Pumpkin)) { list = list2; } } bool flag = list.Count > 1; RailMusicCommand[] array = list.Select((RailMusicCart m) => m.ReadCommand()).ToArray(); int num = RailMusicMix.LatestPlayback(array, Session, Now); int num2 = RailMusicMix.LatestVolume(array, Now); Performance performance = new Performance { Track = (flag ? RailMusicTracks.HalloweenTechno : cart.Track), Group = string.Join("/", list.Select((RailMusicCart m) => m.MusicIdentity).OrderBy((string id) => id, StringComparer.Ordinal)), Mixed = flag, Volume = ((num2 >= 0) ? array[num2].VolumePercent : 100), VolumeChanged = ((num2 >= 0) ? array[num2].VolumeChangedTicks : 0) }; if (num >= 0) { RailMusicCommand railMusicCommand = array[num]; performance.Playing = railMusicCommand.Playing; performance.Session = railMusicCommand.Session; performance.Start = railMusicCommand.StartTicks; performance.Changed = ((railMusicCommand.ChangedTicks > 0) ? railMusicCommand.ChangedTicks : railMusicCommand.StartTicks); } foreach (RailMusicCart item in list) { Performances[item] = performance; if (!dictionary.TryGetValue(item, out var value) || value.Group != performance.Group || value.Playing != performance.Playing || value.Volume != performance.Volume) { _nextSelection = 0f; } } } } private RailMusicCommand ReadCommand() { ZDO zDO = _view.GetZDO(); return new RailMusicCommand(MusicIdentity, zDO.GetBool("vr_music_playing", false), zDO.GetLong("vr_music_session", 0L), zDO.GetLong("vr_music_start", 0L), zDO.GetLong("vr_music_changed", 0L), OwnVolume, zDO.GetLong("vr_music_volume_changed", 0L)); } private static long NextCommandStamp(long last) { long now = Now; if (last < now || last >= now + 10000000) { return now; } return last + 1; } internal bool AdjustVolume(Humanoid user, bool hold, bool lower) { if (!hold) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null) { if (!CanUse(val)) { ((Character)val).Message((MessageType)2, "Stand beside the cart's volume dial with ward access.", 0, (Sprite)null, false); return false; } return RailMusicNetwork.RequestVolume(this, val, (!lower) ? 1 : (-1)); } } return false; } internal string ApplyVolume(long peer, long playerId, int direction) { if (!OwnerCanUse(peer, playerId, out Player _)) { return "The sound cart is busy or out of reach. Try again beside its dial."; } InvalidatePerformances(); Performance currentPerformance = CurrentPerformance; if (!RailMusicVolume.TryAdjust(currentPerformance.Volume, direction, out var nextPercent)) { return "Invalid volume adjustment."; } ZDO zDO = _view.GetZDO(); zDO.Set("vr_music_volume", nextPercent); zDO.Set("vr_music_volume_changed", NextCommandStamp(currentPerformance.VolumeChanged)); InvalidatePerformances(); return (currentPerformance.Mixed ? "Halloween train music volume: " : "Cart music volume: ") + nextPercent + "%"; } internal string VolumeHover() { return Localization.instance.Localize((CurrentPerformance.Mixed ? "Halloween train volume" : "Cart music volume") + ": " + VolumePercent + "%\n[$KEY_Use] Louder (+10%)\n[$KEY_AltPlace + $KEY_Use] Quieter (−10%)\nPersonal config volume and the server limit also apply."); } } public sealed class RailMusicConsole : MonoBehaviour, Hoverable, Interactable { private RailMusicCart? Cart => ((Component)this).GetComponentInParent(); public float GetHoverOffset() { return 0f; } public string GetHoverName() { if (!Object.op_Implicit((Object)(object)Cart)) { return "Rail music cart"; } return Cart.DisplayName; } public string GetHoverText() { if (!Object.op_Implicit((Object)(object)Cart)) { return GetHoverName(); } return Cart.HoverText(); } public bool Interact(Humanoid user, bool hold, bool alt) { if (Object.op_Implicit((Object)(object)Cart)) { if (alt && !hold) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null) { return Cart.Cart.ToggleCoupling(val); } } return Cart.Interact(user, hold); } return false; } public bool UseItem(Humanoid user, ItemData item) { return false; } } public sealed class RailMusicBanner : MonoBehaviour, Hoverable, Interactable { private RailMusicCart? Cart => ((Component)this).GetComponentInParent(); private Sign? Sign => ((Component)this).GetComponentInParent(); public float GetHoverOffset() { return 0f; } public string GetHoverName() { return "Sound cart banner"; } public string GetHoverText() { return Localization.instance.Localize("Sound cart banner\n[$KEY_Use] Edit (park first)"); } public bool Interact(Humanoid user, bool hold, bool alt) { if (!hold) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null && Object.op_Implicit((Object)(object)Cart) && Object.op_Implicit((Object)(object)Sign)) { if (!Cart.CanEditBanner(val)) { ((Character)val).Message((MessageType)2, "Park and dismount the train before editing its banner.", 0, (Sprite)null, false); return false; } return Sign.Interact(user, false, false); } } return false; } public bool UseItem(Humanoid user, ItemData item) { return false; } } [HarmonyPatch(typeof(Sign), "SetText")] internal static class RailMusicBannerEditPatch { [HarmonyPrefix] private static bool Prefix(Sign __instance, string text) { RailMusicCart component = ((Component)__instance).GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return true; } if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { RailMusicNetwork.RequestBanner(component, Player.m_localPlayer, text); } return false; } } public sealed class RailMusicVolumeDial : MonoBehaviour, Hoverable, Interactable { private RailMusicCart? Cart => ((Component)this).GetComponentInParent(); private void Update() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) Transform val = ((Component)this).transform.Find("knob"); if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)Cart) && Cart.Ready) { val.localRotation = Quaternion.Euler(0f, 0f, 120f - (float)Cart.VolumePercent * 2.4f); } } public float GetHoverOffset() { return 0f; } public string GetHoverName() { return "Music volume dial"; } public string GetHoverText() { if (!Object.op_Implicit((Object)(object)Cart)) { return GetHoverName(); } return Cart.VolumeHover(); } public bool Interact(Humanoid user, bool hold, bool alt) { if (Object.op_Implicit((Object)(object)Cart)) { return Cart.AdjustVolume(user, hold, alt); } return false; } public bool UseItem(Humanoid user, ItemData item) { return false; } } internal static class RailMusicNetwork { private enum Operation { Playback, Banner, Volume } private sealed class Pending { internal long Peer; internal long Owner; internal float Until; internal ZDOID Cart; } private const string RequestRpc = "VR_MusicRequest_v1"; private const string ApplyRpc = "VR_MusicApply_v1"; private const string ResultRpc = "VR_MusicResult_v1"; private const string ReplyRpc = "VR_MusicReply_v1"; private static readonly FieldInfo? AuthorId = AccessTools.Field(typeof(CrossNetworkUserInfo), "m_id"); private static readonly FieldInfo? AssignedUserName = AccessTools.Field(typeof(CrossNetworkUserInfo), "m_serverAssignedDisplayName"); private static readonly FieldInfo? AssignedPlayerName = AccessTools.Field(typeof(PlayerInfo), "m_serverAssignedDisplayName"); private static readonly FieldInfo? DisplayName = AccessTools.Field(typeof(CrossNetworkUserInfo), "m_displayName"); private static ZNet? _network; private static readonly HashSet Registered = new HashSet(); private static readonly Dictionary PendingRequests = new Dictionary(); private static readonly Dictionary NextRequest = new Dictionary(); private static string _localToken = ""; private static float _localUntil; internal static void Update() { if (_network != ZNet.instance) { Reset(); _network = ZNet.instance; } if (!Object.op_Implicit((Object)(object)_network) || !Object.op_Implicit((Object)(object)ZNetScene.instance) || ZDOMan.instance == null) { return; } ZRpc[] array = Registered.Where((ZRpc r) => !_network.GetPeers().Any((ZNetPeer p) => p.IsReady() && p.m_rpc == r && r.IsConnected())).ToArray(); foreach (ZRpc val in array) { Unregister(val); Registered.Remove(val); } foreach (ZNetPeer peer in _network.GetPeers()) { if (!peer.IsReady() || !peer.m_rpc.IsConnected() || !Registered.Add(peer.m_rpc)) { continue; } if (_network.IsServer()) { peer.m_rpc.Register("VR_MusicRequest_v1", (Action)delegate(ZRpc rpc, ZPackage p) { WithClient(rpc, delegate(long uid) { ReceiveRequest(uid, p); }); }); peer.m_rpc.Register("VR_MusicResult_v1", (Action)delegate(ZRpc rpc, ZPackage p) { WithClient(rpc, delegate(long uid) { ReceiveResult(uid, p); }); }); } else { if (peer != _network.GetServerPeer()) { continue; } peer.m_rpc.Register("VR_MusicApply_v1", (Action)delegate(ZRpc rpc, ZPackage p) { if (FromServer(rpc)) { ReceiveApply(p); } }); peer.m_rpc.Register("VR_MusicReply_v1", (Action)delegate(ZRpc rpc, ZPackage p) { if (FromServer(rpc)) { ReceiveReply(p); } }); } } if (_localToken.Length != 0 && Time.unscaledTime >= _localUntil) { _localToken = ""; Tell("Music request timed out. Stand beside the loaded sound cart and try again."); } string[] array2 = (from p in PendingRequests where Time.unscaledTime >= p.Value.Until select p.Key).ToArray(); foreach (string text in array2) { Pending pending = PendingRequests[text]; PendingRequests.Remove(text); Reply(pending.Peer, text, "Sound cart ownership changed or its owner did not respond. Try again."); } long[] array3 = (from p in NextRequest where Time.unscaledTime >= p.Value + 10f select p.Key).ToArray(); foreach (long key in array3) { NextRequest.Remove(key); } RailMusicCart.SelectAudible(); } private static void WithClient(ZRpc rpc, Action action) { if (Object.op_Implicit((Object)(object)_network) && _network == ZNet.instance && _network.IsServer()) { ZNetPeer val = ((IEnumerable)_network.GetPeers()).FirstOrDefault((Func)((ZNetPeer p) => p.IsReady() && p.m_rpc == rpc && rpc.IsConnected())); if (val != null) { action(val.m_uid); } } } private static bool FromServer(ZRpc rpc) { if (Object.op_Implicit((Object)(object)_network) && _network == ZNet.instance && !_network.IsServer() && _network.GetServerPeer()?.m_rpc == rpc) { return rpc.IsConnected(); } return false; } private static bool Readable(ZPackage p) { if (p != null && p.Size() > 0) { return p.Size() <= 4096; } return false; } private static bool Token(string token) { Guid result; if (token.Length == 32) { return Guid.TryParseExact(token, "N", out result); } return false; } private static RailMusicCart? Cart(ZDOID id) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.FindInstance(id) : null); if (!Object.op_Implicit((Object)(object)val)) { return null; } return val.GetComponent(); } internal static bool Request(RailMusicCart cart, Player player, bool play) { return Request(cart, player, Operation.Playback, play, ""); } internal static bool RequestVolume(RailMusicCart cart, Player player, int direction) { if (direction == -1 || direction == 1) { return Request(cart, player, Operation.Volume, direction > 0, ""); } return false; } internal static bool RequestBanner(RailMusicCart cart, Player player, string text) { if (!cart.CanEditBanner(player)) { Tell("Park and dismount the train before changing its banner."); return false; } if (!ValidBanner(text)) { Tell("Use at most 50 characters for the banner."); return false; } return Request(cart, player, Operation.Banner, play: false, text); } private static bool Request(RailMusicCart cart, Player player, Operation operation, bool play, string text) { //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown //IL_00b9: 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_0111: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)ZNet.instance) || !cart.CanUse(player) || RailMusicCart.Session == 0L) { return false; } if (_localToken.Length != 0) { Tell("Wait for the previous sound cart request to finish."); return false; } ZNetPeer val = (ZNet.instance.IsServer() ? null : ZNet.instance.GetServerPeer()); if (!ZNet.instance.IsServer() && (val == null || !val.IsReady() || !val.m_rpc.IsConnected())) { Tell("Waiting for the server connection. Try again shortly."); return false; } _localToken = Guid.NewGuid().ToString("N"); _localUntil = Time.unscaledTime + 7f; ZPackage val2 = new ZPackage(); val2.Write(cart.View.GetZDO().m_uid); val2.Write(player.GetPlayerID()); val2.Write((int)operation); val2.Write(play); val2.Write(text); val2.Write(_localToken); if (ZNet.instance.IsServer()) { ReceiveRequest(ZNet.GetUID(), new ZPackage(val2.GetArray())); } else { val.m_rpc.Invoke("VR_MusicRequest_v1", new object[1] { val2 }); } return true; } private static bool ValidBanner(string text) { if (text != null && text.Length <= 50) { return text.IndexOf('\0') < 0; } return false; } private static bool ValidCommand(Operation operation, bool play, string text) { if (operation != Operation.Playback && operation != Operation.Volume) { if (operation == Operation.Banner && !play) { return ValidBanner(text); } return false; } return text.Length == 0; } private static bool BannerAuthor(ZDOID character, out string author, out string name) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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_007a: Unknown result type (might be due to invalid IL or missing references) author = (name = ""); if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer() || AuthorId == null) { return false; } List playerList = ZNet.instance.GetPlayerList(); int num = playerList.FindIndex((PlayerInfo info) => info.m_characterID == character); if (num < 0) { return false; } object obj = playerList[num]; object obj2 = playerList[num].m_userInfo; author = AuthorId.GetValue(obj2)?.ToString() ?? ""; name = (AssignedUserName?.GetValue(obj2) as string) ?? (AssignedPlayerName?.GetValue(obj) as string) ?? ""; if (name.Length == 0) { name = (DisplayName?.GetValue(obj2) as string) ?? ""; } if (author.Length == 0) { return false; } try { new RailMusicMetadata("", author, name); return true; } catch (FormatException) { return false; } } private static bool AllowedCart(ZDO cart, Operation operation) { foreach (RailMusicTrack item in RailMusicTracks.All) { if (cart.GetPrefab() == StringExtensionMethods.GetStableHashCode(item.PrefabName)) { int result; switch (operation) { case Operation.Banner: result = (item.SupportsBanner ? 1 : 0); break; default: result = 0; break; case Operation.Playback: case Operation.Volume: result = 1; break; } return (byte)result != 0; } } return false; } private static bool Requester(long peer, long playerId, ZDOID cartId, Operation operation, out ZDOID character) { //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_0070: 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_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_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) character = ZDOID.None; ZDO val2; if (peer == ZNet.GetUID()) { Player localPlayer = Player.m_localPlayer; ZNetView val = (Object.op_Implicit((Object)(object)localPlayer) ? ((Component)localPlayer).GetComponent() : null); val2 = ((Object.op_Implicit((Object)(object)val) && val.IsValid()) ? val.GetZDO() : null); } else { ZNetPeer peer2 = ZNet.instance.GetPeer(peer); val2 = ((peer2 != null && peer2.IsReady()) ? ZDOMan.instance.GetZDO(peer2.m_characterID) : null); } ZDO zDO = ZDOMan.instance.GetZDO(cartId); if (val2 == null || zDO == null || val2.GetOwner() != peer || val2.GetPrefab() != StringExtensionMethods.GetStableHashCode("Player") || val2.GetLong(ZDOVars.s_playerID, 0L) != playerId || val2.GetBool(ZDOVars.s_dead, false) || val2.GetFloat(ZDOVars.s_health, 0f) <= 0f || !AllowedCart(zDO, operation)) { return false; } character = val2.m_uid; float num = Vector3.Distance(val2.GetPosition(), zDO.GetPosition()); if (!float.IsNaN(num) && !float.IsInfinity(num)) { return num <= 5f; } return false; } private static void ReceiveRequest(long peer, ZPackage p) { //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_00fe: 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_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_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_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Expected O, but got Unknown //IL_0238: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer() || !Readable(p)) { return; } try { ZDOID val = p.ReadZDOID(); long num = p.ReadLong(); Operation operation = (Operation)p.ReadInt(); bool flag = p.ReadBool(); string text = p.ReadString(); string text2 = p.ReadString(); if (p.GetPos() != p.Size() || !Token(text2) || !ValidCommand(operation, flag, text)) { return; } if ((NextRequest.TryGetValue(peer, out var value) && value > Time.unscaledTime) || PendingRequests.Values.Any((Pending r) => r.Peer == peer)) { Reply(peer, text2, "Wait for the previous music request to finish."); return; } NextRequest[peer] = Time.unscaledTime + 0.25f; if (!RailSettings.Ready || !Requester(peer, num, val, operation, out var character)) { Reply(peer, text2, "Stand beside the sound cart with your living character before using it."); return; } string author = ""; string name = ""; if (operation == Operation.Banner && !BannerAuthor(character, out author, out name)) { Reply(peer, text2, "Waiting for your banner author identity. Try again shortly."); return; } long owner = ZDOMan.instance.GetZDO(val).GetOwner(); if (owner == ZNet.GetUID()) { RailMusicCart railMusicCart = Cart(val); Reply(peer, text2, Object.op_Implicit((Object)(object)railMusicCart) ? Apply(railMusicCart, peer, num, operation, flag, text, author, name) : "The sound cart is not loaded. Try again nearby."); return; } ZNetPeer peer2 = ZNet.instance.GetPeer(owner); if (peer2 == null || !peer2.IsReady() || !peer2.m_rpc.IsConnected()) { Reply(peer, text2, "The sound cart is waiting for its network owner."); return; } PendingRequests[text2] = new Pending { Peer = peer, Owner = owner, Cart = val, Until = Time.unscaledTime + 5f }; ZPackage val2 = new ZPackage(); val2.Write(val); val2.Write(peer); val2.Write(num); val2.Write((int)operation); val2.Write(flag); val2.Write(text); val2.Write(author); val2.Write(name); val2.Write(text2); peer2.m_rpc.Invoke("VR_MusicApply_v1", new object[1] { val2 }); } catch (Exception ex) { RailPlugin.Warn("Ignored invalid sound cart request: " + ex.GetBaseException().Message); } } private static void ReceiveApply(ZPackage p) { //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_00b7: 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_00ea: Expected O, but got Unknown if (!Readable(p) || !Object.op_Implicit((Object)(object)ZNet.instance) || ZNet.instance.IsServer()) { return; } try { ZDOID id = p.ReadZDOID(); long peer = p.ReadLong(); long player = p.ReadLong(); Operation operation = (Operation)p.ReadInt(); bool play = p.ReadBool(); string text = p.ReadString(); string text2 = p.ReadString(); string text3 = p.ReadString(); string text4 = p.ReadString(); if (p.GetPos() == p.Size() && Token(text4) && ValidCommand(operation, play, text)) { if (operation == Operation.Banner) { new RailMusicMetadata(text, text2, text3); } else if (text2.Length != 0 || text3.Length != 0) { return; } RailMusicCart railMusicCart = Cart(id); string text5 = (Object.op_Implicit((Object)(object)railMusicCart) ? Apply(railMusicCart, peer, player, operation, play, text, text2, text3) : "The sound cart is not loaded by its owner. Try again nearby."); ZPackage val = new ZPackage(); val.Write(text4); val.Write(text5); ZNet.instance.GetServerPeer().m_rpc.Invoke("VR_MusicResult_v1", new object[1] { val }); } } catch (Exception ex) { RailPlugin.Warn("Ignored invalid sound cart command: " + ex.GetBaseException().Message); } } private static string Apply(RailMusicCart cart, long peer, long player, Operation operation, bool play, string text, string author, string authorName) { return operation switch { Operation.Volume => cart.ApplyVolume(peer, player, play ? 1 : (-1)), Operation.Banner => cart.ApplyBanner(peer, player, text, author, authorName), _ => cart.Apply(peer, player, play), }; } private static void ReceiveResult(long owner, ZPackage p) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) if (!Readable(p)) { return; } try { string text = p.ReadString(); string text2 = p.ReadString(); if (p.GetPos() == p.Size() && Token(text) && text2.Length <= 200 && PendingRequests.TryGetValue(text, out Pending value) && value.Owner == owner) { PendingRequests.Remove(text); ZDO zDO = ZDOMan.instance.GetZDO(value.Cart); if (zDO == null || zDO.GetOwner() != owner) { text2 = "Sound cart ownership changed. Check its console and try again."; } Reply(value.Peer, text, text2); } } catch (Exception ex) { RailPlugin.Warn("Ignored invalid sound cart result: " + ex.GetBaseException().Message); } } private static void Reply(long peer, string token, string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(token); val.Write(message); if (peer == ZNet.GetUID()) { ReceiveReply(new ZPackage(val.GetArray())); return; } ZNetPeer peer2 = ZNet.instance.GetPeer(peer); if (peer2 != null) { peer2.m_rpc.Invoke("VR_MusicReply_v1", new object[1] { val }); } } private static void ReceiveReply(ZPackage p) { if (!Readable(p)) { return; } try { string text = p.ReadString(); string text2 = p.ReadString(); if (p.GetPos() == p.Size() && !(text != _localToken) && text2.Length <= 200) { _localToken = ""; Tell(text2); } } catch (Exception ex) { RailPlugin.Warn("Ignored invalid sound cart reply: " + ex.GetBaseException().Message); } } private static void Tell(string message) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false); } } private static void Unregister(ZRpc rpc) { rpc.Unregister("VR_MusicRequest_v1"); rpc.Unregister("VR_MusicApply_v1"); rpc.Unregister("VR_MusicResult_v1"); rpc.Unregister("VR_MusicReply_v1"); } internal static void Reset() { foreach (ZRpc item in Registered) { Unregister(item); } Registered.Clear(); PendingRequests.Clear(); NextRequest.Clear(); _network = null; _localToken = ""; RailMusicCart.Shutdown(); } } internal sealed class RailNaturalResource : MonoBehaviour { private static readonly FieldInfo? AttachPosition = AccessTools.Field(typeof(Plant), "m_attachPos"); private static readonly FieldInfo? AttachNormal = AccessTools.Field(typeof(Plant), "m_attachNormal"); private readonly HashSet _hiddenRenderers = new HashSet(); private readonly HashSet _hiddenColliders = new HashSet(); private Component? _resource; private Bounds _bounds; private Matrix4x4 _boundsMatrix; private bool _hasBounds; private float _nextCheck; private int _revision = -1; private int _nativeVisualDepth; internal static void Register(Component resource) { if (IsCandidate(resource)) { RailNaturalResource obj = resource.GetComponent() ?? resource.gameObject.AddComponent(); obj._resource = resource; obj.RefreshNow(); } } internal static void RegisterHierarchy(GameObject root) { if (Object.op_Implicit((Object)(object)root)) { Pickable[] componentsInChildren = root.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { Register((Component)(object)componentsInChildren[i]); } PickableItem[] componentsInChildren2 = root.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Register((Component)(object)componentsInChildren2[i]); } Plant[] componentsInChildren3 = root.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren3.Length; i++) { Register((Component)(object)componentsInChildren3[i]); } Destructible[] componentsInChildren4 = root.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren4.Length; i++) { Register((Component)(object)componentsInChildren4[i]); } MineRock[] componentsInChildren5 = root.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren5.Length; i++) { Register((Component)(object)componentsInChildren5[i]); } MineRock5[] componentsInChildren6 = root.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren6.Length; i++) { Register((Component)(object)componentsInChildren6[i]); } } } internal static bool Covered(Component resource) { //IL_004b: 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_005a: 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_0099: 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_008b: 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_0067: 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_0073: 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_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: 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_016d: Unknown result type (might be due to invalid IL or missing references) if (!IsWorldResource(resource)) { return false; } bool flag = IsRock(resource); RailNaturalResource component = resource.GetComponent(); Bounds bounds; bool flag2 = (Object.op_Implicit((Object)(object)component) ? component.TryBounds(out bounds) : MeasureBounds(resource, out bounds)); if (flag && (!flag2 || !SmallRock(bounds))) { return false; } if (IsSoftVegetation(resource)) { Vector3 val = Vector3.up * 2.9f; if (flag2) { ((Bounds)(ref bounds)).center = ((Bounds)(ref bounds)).center - val; if (RailSpawnHooks.Blocks(bounds, onlyNearBed: false)) { return true; } } return RailSpawnHooks.Blocks(resource.transform.position - val); } if (flag2 && RailSpawnHooks.Blocks(bounds, flag)) { return true; } if (!flag && RailSpawnHooks.Blocks(resource.transform.position)) { return true; } Plant val2 = (Plant)(object)((resource is Plant) ? resource : null); if (val2 != null && val2.m_attachDistance > 0f && AttachPosition?.FieldType == typeof(Vector3) && AttachNormal?.FieldType == typeof(Vector3) && AttachNormal.GetValue(val2) is Vector3 val3 && ((Vector3)(ref val3)).sqrMagnitude > 0.25f && AttachPosition.GetValue(val2) is Vector3 point && RailSpawnHooks.Blocks(point)) { return true; } return false; } internal static bool IgnoreRailObstacle(Collider collider) { if (!Object.op_Implicit((Object)(object)collider)) { return false; } Component componentInParent = (Component)(object)((Component)collider).GetComponentInParent(); componentInParent = (Component)(((object)componentInParent) ?? ((object)((Component)collider).GetComponentInParent())); componentInParent = (Component)(((object)componentInParent) ?? ((object)((Component)collider).GetComponentInParent())); componentInParent = (Component)(((object)componentInParent) ?? ((object)((Component)collider).GetComponentInParent())); componentInParent = (Component)(((object)componentInParent) ?? ((object)((Component)collider).GetComponentInParent())); componentInParent = (Component)(((object)componentInParent) ?? ((object)((Component)collider).GetComponentInParent())); if (!Object.op_Implicit((Object)(object)componentInParent) || !IsWorldResource(componentInParent) || !OwnsVisual(componentInParent, (Component)(object)collider) || (!IsSoftVegetation(componentInParent) && !Covered(componentInParent))) { return false; } Register(componentInParent); return true; } private static string PrefabName(Component resource) { ZNetView componentInParent = resource.GetComponentInParent(); return Utils.GetPrefabName(((componentInParent != null) ? ((Component)componentInParent).gameObject : null) ?? resource.gameObject); } private static bool IsSoftVegetation(Component resource) { if ((resource is Pickable || resource is Destructible) && !Object.op_Implicit((Object)(object)resource.GetComponentInParent()) && !Object.op_Implicit((Object)(object)resource.GetComponentInParent())) { return RailNaturalResourcePolicy.IsSoftVegetationPrefab(PrefabName(resource)); } return false; } private static bool IsShrub(Component resource) { if (resource is Destructible) { return RailNaturalResourcePolicy.IsSmallPlantPrefab(PrefabName(resource)); } return false; } private static bool IsCandidate(Component resource) { if (!Object.op_Implicit((Object)(object)resource) || (!(resource is Pickable) && !(resource is PickableItem) && !(resource is Plant) && !IsRock(resource) && !IsShrub(resource))) { return false; } if (ProtectedHierarchy(resource)) { return false; } if (!(resource is Plant)) { return !Object.op_Implicit((Object)(object)resource.GetComponentInParent()); } return true; } private static bool ProtectedHierarchy(Component resource) { if (!Object.op_Implicit((Object)(object)resource.GetComponentInParent()) && !Object.op_Implicit((Object)(object)resource.GetComponentInParent()) && !Object.op_Implicit((Object)(object)resource.GetComponentInParent()) && !Object.op_Implicit((Object)(object)resource.GetComponentInParent()) && !Object.op_Implicit((Object)(object)resource.GetComponentInParent()) && !Object.op_Implicit((Object)(object)resource.GetComponentInParent())) { return Object.op_Implicit((Object)(object)resource.GetComponentInParent()); } return true; } private static bool IsWorldResource(Component resource) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (!IsCandidate(resource)) { return false; } ZNetView componentInParent = resource.GetComponentInParent(); if (!Object.op_Implicit((Object)(object)componentInParent) || !componentInParent.IsValid() || ZDOMan.instance == null || ZDOMan.instance.GetZDO(componentInParent.GetZDO().m_uid) != componentInParent.GetZDO()) { return false; } if (!(resource is Plant) && (Object.op_Implicit((Object)(object)resource.GetComponentInParent()) || componentInParent.GetZDO().GetLong(ZDOVars.s_creator, 0L) != 0L)) { return false; } if (IsRock(resource) || RailNaturalResourcePolicy.IsSmallPlantPrefab(PrefabName(resource))) { Rigidbody componentInParent2 = resource.GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent2) && !componentInParent2.isKinematic) { return false; } } return true; } private static bool IsRock(Component resource) { if (resource is Destructible || resource is MineRock || resource is MineRock5) { ZNetView componentInParent = resource.GetComponentInParent(); return RailNaturalResourcePolicy.IsSceneryRock(Utils.GetPrefabName(((componentInParent != null) ? ((Component)componentInParent).gameObject : null) ?? resource.gameObject)); } return false; } private static bool SmallRock(Bounds bounds) { //IL_0002: 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_001c: Unknown result type (might be due to invalid IL or missing references) return RailNaturalResourcePolicy.IsSmallRock(((Bounds)(ref bounds)).size.x, ((Bounds)(ref bounds)).size.y, ((Bounds)(ref bounds)).size.z); } private static bool OwnsVisual(Component resource, Component visual) { if (!ProtectedHierarchy(visual) && (Object)(object)visual.GetComponentInParent() == (Object)(object)resource.GetComponentInParent()) { return (Object)(object)visual.GetComponentInParent() == (Object)(object)resource.GetComponentInParent(); } return false; } private static bool ValidBounds(Bounds bounds) { //IL_0002: 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_001e: 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_0044: 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_005c: Unknown result type (might be due to invalid IL or missing references) if (Finite(((Bounds)(ref bounds)).center) && Finite(((Bounds)(ref bounds)).size) && ((Bounds)(ref bounds)).size.x >= 0f && ((Bounds)(ref bounds)).size.y >= 0f && ((Bounds)(ref bounds)).size.z >= 0f) { Vector3 size = ((Bounds)(ref bounds)).size; return ((Vector3)(ref size)).sqrMagnitude > 1E-06f; } return false; } private static bool Finite(Vector3 value) { //IL_0000: 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_001a: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!float.IsNaN(value.x) && !float.IsInfinity(value.x) && !float.IsNaN(value.y) && !float.IsInfinity(value.y) && !float.IsNaN(value.z)) { return !float.IsInfinity(value.z); } return false; } private bool TryBounds(out Bounds bounds) { //IL_0016: 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_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_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_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) if (_hasBounds && _hiddenColliders.Count != 0 && _boundsMatrix == ((Component)this).transform.localToWorldMatrix) { bounds = _bounds; return true; } _hasBounds = Object.op_Implicit((Object)(object)_resource) && MeasureBounds(_resource, out _bounds); _boundsMatrix = ((Component)this).transform.localToWorldMatrix; bounds = _bounds; return _hasBounds; } private static bool MeasureBounds(Component resource, out Bounds bounds) { //IL_0001: 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_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_0068: 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_005e: 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_00c7: 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) bounds = default(Bounds); bool flag = false; Collider[] componentsInChildren = resource.GetComponentsInChildren(true); foreach (Collider val in componentsInChildren) { if (!Object.op_Implicit((Object)(object)val) || !val.enabled || val.isTrigger || !((Component)val).gameObject.activeInHierarchy || !OwnsVisual(resource, (Component)(object)val)) { continue; } Bounds bounds2 = val.bounds; if (ValidBounds(bounds2)) { if (!flag) { bounds = bounds2; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(bounds2); } } } Renderer[] componentsInChildren2 = resource.GetComponentsInChildren(true); foreach (Renderer val2 in componentsInChildren2) { if (!Object.op_Implicit((Object)(object)val2) || (!(val2 is MeshRenderer) && !(val2 is SkinnedMeshRenderer)) || !OwnsVisual(resource, (Component)(object)val2)) { continue; } Bounds bounds3 = val2.bounds; if (ValidBounds(bounds3)) { if (!flag) { bounds = bounds3; flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(bounds3); } } } return flag; } private void LateUpdate() { if (RailSpawnProtection.Revision != _revision || !(Time.unscaledTime < _nextCheck)) { RefreshNow(); } } internal void RefreshNow() { if (_nativeVisualDepth != 0) { return; } _nextCheck = Time.unscaledTime + 0.5f; try { _revision = RailSpawnProtection.Revision; if (!Object.op_Implicit((Object)(object)_resource) || !Covered(_resource)) { Restore(); return; } Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if (Object.op_Implicit((Object)(object)val) && !val.forceRenderingOff && OwnsVisual(_resource, (Component)(object)val)) { _hiddenRenderers.Add(val); val.forceRenderingOff = true; } } Collider[] componentsInChildren2 = ((Component)this).GetComponentsInChildren(true); foreach (Collider val2 in componentsInChildren2) { if (Object.op_Implicit((Object)(object)val2) && val2.enabled && OwnsVisual(_resource, (Component)(object)val2)) { _hiddenColliders.Add(val2); val2.enabled = false; } } } catch (Exception ex) { Restore(); _nextCheck = Time.unscaledTime + 2f; RailSpawnHooks.Warn("Resource visibility", ex.Message); } } internal void Restore() { foreach (Renderer hiddenRenderer in _hiddenRenderers) { if (Object.op_Implicit((Object)(object)hiddenRenderer)) { hiddenRenderer.forceRenderingOff = false; } } foreach (Collider hiddenCollider in _hiddenColliders) { if (Object.op_Implicit((Object)(object)hiddenCollider)) { hiddenCollider.enabled = true; } } _hiddenRenderers.Clear(); _hiddenColliders.Clear(); } internal void BeginNativeVisualUpdate() { if (_nativeVisualDepth++ == 0) { Restore(); } } internal void EndNativeVisualUpdate() { if (_nativeVisualDepth > 0) { _nativeVisualDepth--; } if (_nativeVisualDepth == 0) { RefreshNow(); } } private void OnDisable() { Restore(); } private void Start() { RefreshNow(); } private void OnEnable() { _nextCheck = 0f; _revision = -1; RefreshNow(); } private void OnDestroy() { Restore(); } } internal static class RailPackedInventory { internal const string CountKey = "vikingrail_vehicle_inventory_count"; internal const int MaximumPayloadBytes = 262144; private const int MaximumItemCount = 256; private const float InvalidCargoWeight = 1000000f; private static readonly MethodInfo? SaveContainer = AccessTools.Method(typeof(Container), "Save", Type.EmptyTypes, (Type[])null); private static readonly FieldInfo? ContainerLoading = AccessTools.Field(typeof(Container), "m_loading"); private static readonly FieldInfo? InventoryWeight = AccessTools.Field(typeof(Inventory), "m_totalWeight"); internal static void Capture(Container? container, ItemData bundle) { RequireContainerType(PieceName(bundle), container); Inventory val; if (Object.op_Implicit((Object)(object)container)) { RequireOwner(container); if (container.IsInUse() || ((Component)container).GetComponent().GetZDO().GetInt("InUse", 0) != 0) { throw new InvalidOperationException("Close the cargo container before picking up this vehicle."); } if (!RailCargoInventory.TryRefresh(container, out string error)) { throw new InvalidOperationException(error); } val = container.GetInventory() ?? throw new InvalidOperationException("The cargo inventory is not ready."); } else { val = NewInventory(null); } CheckItems(val); byte[] payload = Save(val); int count = val.NrOfItems(); Inventory inventory = LoadChecked(payload, container, count); float totalWeight = val.GetTotalWeight(); if (float.IsNaN(totalWeight) || float.IsInfinity(totalWeight) || totalWeight < 0f) { throw new InvalidOperationException("The cargo has an invalid weight and cannot be packed."); } bool value = IntrinsicallyTeleportable(inventory); if (bundle.m_customData == null) { bundle.m_customData = new Dictionary(); } bundle.m_customData["vikingrail_vehicle_inventory"] = PackedVehicleCargo.EncodePayload(payload); bundle.m_customData["vikingrail_vehicle_inventory_count"] = count.ToString(CultureInfo.InvariantCulture); bundle.m_customData["vikingrail_vehicle_cargo_weight"] = PackedVehicle.EncodeCargoWeight(totalWeight); bundle.m_customData["vikingrail_vehicle_teleportable"] = PackedVehicle.EncodeBoolean(value); } internal static bool Validate(ItemData bundle, Container? prefab, out Inventory? staged, out string error) { staged = null; error = ""; try { RequireContainerType(PieceName(bundle), prefab); float weight; bool teleportable; int num = ReadMetadata(bundle, out weight, out teleportable); Inventory val = LoadChecked(PackedVehicleCargo.DecodePayload(bundle.m_customData["vikingrail_vehicle_inventory"]), prefab, num); if (!Object.op_Implicit((Object)(object)prefab) && num != 0) { throw new FormatException("This vehicle has no cargo container."); } staged = (Object.op_Implicit((Object)(object)prefab) ? val : null); return true; } catch (Exception ex) { error = "This vehicle cannot be unpacked safely. Its bundle has been kept: " + ex.GetBaseException().Message; return false; } } internal static void Restore(Container? container, Inventory? staged) { //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)container)) { if (staged != null && staged.NrOfItems() != 0) { throw new InvalidOperationException("The placed vehicle has no cargo container."); } return; } RequireOwner(container); if (staged == null || staged.GetWidth() != container.m_width || staged.GetHeight() != container.m_height) { throw new InvalidOperationException("The packed cargo does not fit the placed vehicle."); } if (SaveContainer == null) { throw new MissingMethodException(typeof(Container).FullName, "Save"); } if (ContainerLoading?.FieldType != typeof(bool) || InventoryWeight?.FieldType != typeof(float)) { throw new InvalidOperationException("This Valheim build's cargo restore guard is unavailable."); } if (!RailCargoInventory.TryRefresh(container, out string error)) { throw new InvalidOperationException(error); } byte[] array = Save(staged); Inventory val = container.GetInventory() ?? throw new InvalidOperationException("The placed cargo inventory is not ready."); List collection = new List(val.GetAllItems()); float totalWeight = val.GetTotalWeight(); bool flag = (bool)ContainerLoading.GetValue(container); try { ContainerLoading.SetValue(container, true); val.Load(new ZPackage(array)); if (!array.SequenceEqual(Save(val))) { throw new InvalidOperationException("The cargo could not be restored without changing its contents."); } } catch { val.GetAllItems().Clear(); val.GetAllItems().AddRange(collection); InventoryWeight.SetValue(val, totalWeight); throw; } finally { ContainerLoading.SetValue(container, flag); } SaveContainer.Invoke(container, null); } internal static bool IsPackedVehicle(ItemData? item) { if (item != null && Object.op_Implicit((Object)(object)item.m_dropPrefab)) { return PackedVehicle.PieceName(Utils.GetPrefabName(((Object)item.m_dropPrefab).name)).Length != 0; } return false; } internal static float CargoWeight(ItemData item) { try { ReadMetadata(item, out var weight, out var _); return weight; } catch { return 1000000f; } } internal static bool CanTeleport(ItemData item) { try { ReadMetadata(item, out var _, out var teleportable); return teleportable; } catch { return false; } } private static string PieceName(ItemData bundle) { if (!IsPackedVehicle(bundle)) { throw new ArgumentException("This is not a registered packed railway vehicle."); } return PackedVehicle.PieceName(Utils.GetPrefabName(((Object)bundle.m_dropPrefab).name)); } private static void RequireContainerType(string pieceName, Container? container) { int num; switch (pieceName) { default: num = ((pieceName == "vr_storagecart") ? 1 : 0); break; case "vr_locomotive": case "vr_bronze_engine": case "vr_eitr_engine": num = 1; break; } if (num != (Object.op_Implicit((Object)(object)container) ? 1 : 0)) { throw new InvalidOperationException("The vehicle's expected cargo container is unavailable."); } } private static void RequireOwner(Container container) { ZNetView component = ((Component)container).GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || !component.IsOwner()) { throw new InvalidOperationException("Wait for the vehicle's cargo owner and try again."); } } private static Inventory NewInventory(Container? prefab) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Expected O, but got Unknown int num = ((!Object.op_Implicit((Object)(object)prefab)) ? 1 : prefab.m_width); int num2 = ((!Object.op_Implicit((Object)(object)prefab)) ? 1 : prefab.m_height); if (num <= 0 || num2 <= 0 || num > 256 || num2 > 256 || (long)num * (long)num2 > 256) { throw new InvalidOperationException("The vehicle's cargo dimensions are unsupported."); } return new Inventory("Packed railway cargo", (Sprite)null, num, num2); } private static Inventory LoadChecked(byte[] payload, Container? prefab, int count) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown Inventory val = NewInventory(prefab); if (count > val.GetWidth() * val.GetHeight()) { throw new FormatException("The packed cargo exceeds this vehicle's capacity."); } ZPackage val2 = new ZPackage(payload); val.Load(val2); if (val2.GetPos() != val2.Size() || val.NrOfItems() != count) { throw new FormatException("Some packed cargo is missing or could not be loaded. Restore its item mods before unpacking."); } CheckItems(val); if (!payload.SequenceEqual(Save(val))) { throw new FormatException("The packed cargo no longer matches its saved item data. Restore its item mods before unpacking."); } return val; } private static void CheckItems(Inventory inventory) { if (inventory.NrOfItems() > 256) { throw new InvalidOperationException("There are too many items to pack safely."); } foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem == null || !Object.op_Implicit((Object)(object)allItem.m_dropPrefab) || allItem.m_stack <= 0) { throw new InvalidOperationException("An item is missing its native prefab or stack data."); } if (IsPackedVehicle(allItem)) { throw new InvalidOperationException("Remove packed railway vehicles from the cargo before picking up this vehicle."); } } } private static bool IntrinsicallyTeleportable(Inventory inventory) { foreach (ItemData allItem in inventory.GetAllItems()) { if (!allItem.m_shared.m_teleportable) { return false; } } return inventory.IsTeleportable(false); } private static byte[] Save(Inventory inventory) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); inventory.Save(val); byte[] array = val.GetArray(); if (array.Length == 0 || array.Length > 262144) { throw new InvalidOperationException("The cargo's saved data is too large to pack safely."); } return array; } private static int ReadMetadata(ItemData item, out float weight, out bool teleportable) { return PackedVehicleCargo.ReadMetadata(item.m_customData, out weight, out teleportable); } } [HarmonyPatch(typeof(ItemData), "GetWeight", new Type[] { typeof(int) })] internal static class PackedRailVehicleWeightPatch { [HarmonyPostfix] private static void Postfix(ItemData __instance, int __0, ref float __result) { if (RailPackedInventory.IsPackedVehicle(__instance)) { int num = Math.Max(0, (__0 < 0) ? __instance.m_stack : __0); double num2 = (double)RailPackedInventory.CargoWeight(__instance) * (double)num; if (!float.IsNaN(__result) && !float.IsInfinity(__result) && __result >= 0f) { num2 += (double)__result; } __result = (float)Math.Min(3.4028234663852886E+38, num2); } } } [HarmonyPatch(typeof(Inventory), "IsTeleportable", new Type[] { typeof(bool) })] internal static class PackedRailVehicleTeleportPatch { [HarmonyPostfix] private static void Postfix(Inventory __instance, bool __0, ref bool __result) { if (!__result || __0 || (Object.op_Implicit((Object)(object)ZoneSystem.instance) && ZoneSystem.instance.GetGlobalKey((GlobalKeys)35))) { return; } foreach (ItemData allItem in __instance.GetAllItems()) { if (RailPackedInventory.IsPackedVehicle(allItem) && !RailPackedInventory.CanTeleport(allItem)) { __result = false; break; } } } } internal static class RailPassengerComfort { internal sealed class EnvironmentUpdate { internal readonly Player Player; internal readonly SEMan Effects; internal readonly EnvironmentUpdate? Previous; internal bool NativeWouldRemoveResting; internal bool PreservedResting; internal EnvironmentUpdate(Player player, EnvironmentUpdate? previous) { Player = player; Effects = ((Character)player).GetSEMan(); Previous = previous; } } internal const int ComfortLevel = 3; internal static readonly MethodInfo? EnvironmentMethod = AccessTools.DeclaredMethod(typeof(Player), "UpdateEnvStatusEffects", new Type[1] { typeof(float) }, (Type[])null); internal static readonly MethodInfo? ComfortMethod = AccessTools.DeclaredMethod(typeof(Player), "GetComfortLevel", Type.EmptyTypes, (Type[])null); internal static readonly MethodInfo? RemoveMethod = AccessTools.DeclaredMethod(typeof(SEMan), "RemoveStatusEffect", new Type[2] { typeof(int), typeof(bool) }, (Type[])null); private static bool _warned; [ThreadStatic] private static EnvironmentUpdate? _current; private static Player? _supportedPlayer; private static StatusEffect? _supportedResting; internal static bool Prepare() { int num; if (EnvironmentMethod?.ReturnType == typeof(void) && ComfortMethod?.ReturnType == typeof(int)) { num = ((RemoveMethod?.ReturnType == typeof(bool)) ? 1 : 0); if (num != 0) { goto IL_0081; } } else { num = 0; } if (!_warned) { _warned = true; RailPlugin.Warn("Passenger comfort is unavailable on this Valheim build: the native resting API changed."); } goto IL_0081; IL_0081: return (byte)num != 0; } internal static bool IsRiding(Player player) { RailPassengerSeat localSeat = RailPassengerSeat.LocalSeat; if (Object.op_Implicit((Object)(object)localSeat)) { return localSeat.HasLocalRider(player); } return false; } private static bool CanRest(EnvironmentUpdate update) { if (IsRiding(update.Player) && !update.Player.IsSensed() && !update.Effects.HaveStatusEffect(SEMan.s_statusEffectWet) && !update.Effects.HaveStatusEffect(SEMan.s_statusEffectBurning) && !update.Effects.HaveStatusEffect(SEMan.s_statusEffectCold)) { return !update.Effects.HaveStatusEffect(SEMan.s_statusEffectFreezing); } return false; } internal static EnvironmentUpdate? Enter(Player player) { if (!IsRiding(player)) { return null; } return _current = new EnvironmentUpdate(player, _current); } internal static void Leave(EnvironmentUpdate? update) { if (update != null) { _current = update.Previous; } } internal static bool AllowRemoval(SEMan effects, int hash) { EnvironmentUpdate current = _current; if (current == null || effects != current.Effects || hash != SEMan.s_statusEffectResting || !IsRiding(current.Player)) { return true; } current.NativeWouldRemoveResting = true; if (!CanRest(current)) { return true; } current.PreservedResting = true; return false; } internal static void Complete(EnvironmentUpdate? update) { if (update == null) { return; } if (!update.NativeWouldRemoveResting) { if ((Object)(object)_supportedPlayer == (Object)(object)update.Player) { _supportedPlayer = null; _supportedResting = null; } return; } if (CanRest(update)) { update.Effects.AddStatusEffect(SEMan.s_statusEffectResting, false, 0, 0f, (short)(-1)); _supportedPlayer = update.Player; _supportedResting = update.Effects.GetStatusEffect(SEMan.s_statusEffectResting); return; } if (update.PreservedResting) { EnvironmentUpdate current = _current; _current = null; try { update.Effects.RemoveStatusEffect(SEMan.s_statusEffectResting, false); } finally { _current = current; } } if ((Object)(object)_supportedPlayer == (Object)(object)update.Player) { _supportedPlayer = null; _supportedResting = null; } } internal static void Stop(Player? player) { if (Object.op_Implicit((Object)(object)player) && !((Object)(object)_supportedPlayer != (Object)(object)player)) { SEMan sEMan = ((Character)player).GetSEMan(); if (Object.op_Implicit((Object)(object)_supportedResting) && sEMan.GetStatusEffect(SEMan.s_statusEffectResting) == _supportedResting) { sEMan.RemoveStatusEffect(SEMan.s_statusEffectResting, false); } _supportedPlayer = null; _supportedResting = null; } } } [HarmonyPatch] internal static class PassengerComfortLevelPatch { [HarmonyPrepare] private static bool Prepare() { return RailPassengerComfort.Prepare(); } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailPassengerComfort.ComfortMethod; } [HarmonyPostfix] private static void Postfix(Player __instance, ref int __result) { if (RailPassengerComfort.IsRiding(__instance)) { __result = Math.Max(__result, 3); } } } [HarmonyPatch] internal static class PassengerRestingEnvironmentPatch { [HarmonyPrepare] private static bool Prepare() { return RailPassengerComfort.Prepare(); } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailPassengerComfort.EnvironmentMethod; } [HarmonyPrefix] private static void Prefix(Player __instance, out RailPassengerComfort.EnvironmentUpdate? __state) { __state = RailPassengerComfort.Enter(__instance); } [HarmonyPostfix] private static void Postfix(RailPassengerComfort.EnvironmentUpdate? __state) { RailPassengerComfort.Complete(__state); } [HarmonyFinalizer] private static void Finalizer(RailPassengerComfort.EnvironmentUpdate? __state) { RailPassengerComfort.Leave(__state); } } [HarmonyPatch] internal static class PassengerRestingRemovalPatch { [HarmonyPrepare] private static bool Prepare() { return RailPassengerComfort.Prepare(); } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailPassengerComfort.RemoveMethod; } [HarmonyPrefix] private static bool Prefix(SEMan __instance, int __0, ref bool __result) { if (RailPassengerComfort.AllowRemoval(__instance, __0)) { return true; } __result = false; return false; } } public sealed class RailPassengerFire : MonoBehaviour { private static readonly MethodInfo? UpdateFire = AccessTools.DeclaredMethod(typeof(Fireplace), "UpdateFireplace", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo? UpdateState = AccessTools.DeclaredMethod(typeof(Fireplace), "UpdateState", Type.EmptyTypes, (Type[])null); private static readonly FieldInfo? WaterCheck = AccessTools.Field(typeof(Fireplace), "m_checkWaterLevel"); private RailVehicle _cart; private ZNetView _view; private Fireplace _fire; private Transform _anchor; internal static bool Compatible { get { if (UpdateFire?.ReturnType == typeof(void) && UpdateState?.ReturnType == typeof(void) && WaterCheck?.FieldType == typeof(bool)) { return RailPassengerFireWeather.Compatible; } return false; } } private bool Ready { get { if (Object.op_Implicit((Object)(object)_cart) && _cart.IsReady && Object.op_Implicit((Object)(object)_fire) && Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { return Object.op_Implicit((Object)(object)_anchor); } return false; } } private void Awake() { _cart = ((Component)this).GetComponent(); _view = ((Component)this).GetComponent(); _fire = ((Component)this).GetComponent(); _anchor = ((Component)this).transform.Find("vr_passenger_fire"); } private void Start() { if (Object.op_Implicit((Object)(object)_fire) && Compatible) { WaterCheck.SetValue(_fire, true); } } private void Update() { //IL_0079: 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_00a1: Unknown result type (might be due to invalid IL or missing references) if (Ready && Object.op_Implicit((Object)(object)_fire.m_enabledObject) && _fire.m_enabledObject.activeInHierarchy && _fire.IsBurning()) { Player localPlayer = Player.m_localPlayer; RailPassengerSeat localSeat = RailPassengerSeat.LocalSeat; if (Object.op_Implicit((Object)(object)localPlayer) && Object.op_Implicit((Object)(object)localSeat) && !((Object)(object)((Component)localSeat).GetComponentInParent() != (Object)(object)_cart) && localSeat.HasLocalRider(localPlayer) && Vector3.SqrMagnitude(((Component)localPlayer).transform.position - _anchor.position) <= 6.25f) { ((Character)localPlayer).OnNearFire(_anchor.position); } } } private bool CanUse(Player player) { //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_0062: Unknown result type (might be due to invalid IL or missing references) if (Ready && _cart.PassengerFireServiceAllowed && Object.op_Implicit((Object)(object)player) && (Object)(object)player == (Object)(object)Player.m_localPlayer && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && Vector3.Distance(((Component)player).transform.position, _anchor.position) <= 4f && RailWardAccess.Allows(_anchor.position, player.GetPlayerID())) { return _view.HasOwner(); } return false; } internal string HoverText() { if (!Ready) { return "Passenger chiminea"; } string text = ((_view.GetZDO().GetInt(ZDOVars.s_state, 1) == 1) ? "Extinguish" : "Light"); return Localization.instance.Localize(_fire.GetHoverText() + "\n[$KEY_AltPlace + $KEY_Use] " + text + "\nRain-protected. Park the train to tend the chiminea."); } internal bool Interact(Humanoid user, bool hold, bool alt) { Player val = (Player)(object)((user is Player) ? user : null); if (val == null || !CanUse(val)) { Player val2 = (Player)(object)((user is Player) ? user : null); if (val2 != null && (Object)(object)val2 == (Object)(object)Player.m_localPlayer) { ((Character)val2).Message((MessageType)2, "Park the train before tending its chiminea.", 0, (Sprite)null, false); } return false; } if (alt) { if (hold) { return false; } _view.InvokeRPC("RPC_ToggleOn", Array.Empty()); return true; } return _fire.Interact(user, hold, false); } internal bool UseItem(Humanoid user, ItemData item) { Player val = (Player)(object)((user is Player) ? user : null); if (val == null || !CanUse(val) || item == null || !Object.op_Implicit((Object)(object)item.m_dropPrefab) || ((Object)item.m_dropPrefab).name != "Wood") { return false; } return _fire.UseItem(user, item); } internal void Capture(IDictionary data) { if (!Ready || !_view.IsOwner() || !Compatible) { throw new InvalidOperationException("The chiminea must finish synchronizing before packing."); } UpdateFire.Invoke(_fire, Array.Empty()); PassengerFireFuel.Capture(data, _view.GetZDO().GetFloat(ZDOVars.s_fuel, 0f), _view.GetZDO().GetInt(ZDOVars.s_state, 1) == 1, _fire.m_maxFuel); } internal static PassengerFireState ReadPacked(GameObject prefab, IReadOnlyDictionary data) { Fireplace component = prefab.GetComponent(); PassengerFireState result = PassengerFireFuel.Read(data, Object.op_Implicit((Object)(object)component) ? component.m_maxFuel : 10f); if (!Object.op_Implicit((Object)(object)prefab.GetComponent()) && (result.Fuel != 0f || !result.IsOn)) { throw new FormatException("This vehicle cannot hold passenger chiminea fuel."); } return result; } internal static void Restore(GameObject placed, PassengerFireState state) { if (Object.op_Implicit((Object)(object)placed.GetComponent())) { ZNetView component = placed.GetComponent(); Fireplace component2 = placed.GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || !component.IsOwner() || !Object.op_Implicit((Object)(object)component2) || !Object.op_Implicit((Object)(object)ZNet.instance) || !Compatible) { throw new InvalidOperationException("Could not restore the passenger chiminea."); } component.GetZDO().Set(ZDOVars.s_fuel, state.Fuel); component.GetZDO().Set(ZDOVars.s_state, state.IsOn ? 1 : 2, false); component.GetZDO().Set(ZDOVars.s_lastTime, ZNet.instance.GetTime().Ticks); UpdateState.Invoke(component2, Array.Empty()); } } } public sealed class RailPassengerHearthInteract : MonoBehaviour, Hoverable, Interactable { private RailPassengerFire? Hearth => ((Component)this).GetComponentInParent(); public float GetHoverOffset() { return 0f; } public string GetHoverName() { return "Passenger chiminea"; } public string GetHoverText() { if (!Object.op_Implicit((Object)(object)Hearth)) { return GetHoverName(); } return Hearth.HoverText(); } public bool Interact(Humanoid user, bool hold, bool alt) { if (Object.op_Implicit((Object)(object)Hearth)) { return Hearth.Interact(user, hold, alt); } return false; } public bool UseItem(Humanoid user, ItemData item) { if (Object.op_Implicit((Object)(object)Hearth)) { return Hearth.UseItem(user, item); } return false; } } internal static class RailPassengerFireWeather { internal static readonly MethodInfo? CheckWet = AccessTools.DeclaredMethod(typeof(Fireplace), "CheckWet", Type.EmptyTypes, (Type[])null); private static readonly FieldInfo? Wet = AccessTools.Field(typeof(Fireplace), "m_wet"); internal static bool Compatible { get { if (CheckWet?.ReturnType == typeof(void)) { return Wet?.FieldType == typeof(bool); } return false; } } internal static bool Check(Fireplace fire) { if (!Object.op_Implicit((Object)(object)((Component)fire).GetComponent())) { return true; } Wet.SetValue(fire, false); return false; } } [HarmonyPatch] internal static class RailPassengerChimineaWeatherPatch { [HarmonyPrepare] private static bool Prepare() { return RailPassengerFireWeather.Compatible; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailPassengerFireWeather.CheckWet; } [HarmonyPrefix] private static bool Prefix(Fireplace __instance) { return RailPassengerFireWeather.Check(__instance); } } public sealed class RailVehicle : MonoBehaviour, Hoverable, Interactable, IDoodadController { private sealed class BeamAim { internal readonly Light Light; internal readonly Transform Transform; internal readonly Quaternion RestLocalRotation; internal Quaternion WorldRotation; internal Vector3 LastPosition; internal int LastFrame; internal bool HasPose; internal BeamAim(Light light) { //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) Light = light; Transform = ((Component)light).transform; RestLocalRotation = Transform.localRotation; } } private sealed class ConsistDriveMember { internal RailVehicle Cart; internal ZNetView View; internal ZDOID Id; internal long PreviousOwner; internal long Stamp = -1L; internal string Digest = ""; } private sealed class ConsistDriveCart { internal RailVehicle Cart; internal string Parent = ""; internal string Next = ""; internal string Front = ""; internal string Plow = ""; internal string Controller = ""; internal bool ParentFront; internal bool PlowFront; } private sealed class ConsistDriveOperation { internal string Token = ""; internal long Peer; internal long Player; internal long Owner; internal ushort OwnerRevision; internal ZDOID Cab; internal float Expires; internal float NextRequest; internal readonly List Members = new List(); internal readonly List Carts = new List(); } private sealed class ConsistFuelDebit { internal RailVehicle Engine; internal FuelPlan Plan; internal long PreviousCredit; internal ItemData[]? Items; internal float Weight; internal bool Loading; internal string SavedItems = ""; internal byte[]? SavedBytes; } private sealed class ContactCoupling { internal RailVehicle Root; internal RailVehicle Parent; internal RailVehicle Wagon; internal bool ParentFront; internal bool WagonFront; internal double Distance; } private sealed class ContactCouplingClient { internal Player Player; internal RailVehicle Mover; internal RailVehicle Parent; internal RailVehicle Wagon; internal bool ParentFront; internal bool WagonFront; internal float Expires; internal float NextAttempt; internal string Failure = "Coupling timed out. Check that the carts are stopped, empty of riders, and their storage is closed."; } private sealed class CouplingMember { internal RailVehicle Cart; internal ZDOID Id; internal string Parent = ""; internal string Next = ""; internal string Front = ""; internal bool ParentFront; internal string Plow = ""; internal bool PlowFront; internal long PreviousOwner; internal long Stamp = -1L; internal string Digest = ""; } private sealed class CouplingOperation { internal string Token = ""; internal long Peer; internal long Player; internal long Owner; internal ushort OwnerRevision; internal ZDOID Wagon; internal ZDOID Parent; internal ZDOID ContactMover; internal string ExpectedParent = ""; internal bool ParentFront; internal bool WagonFront; internal float Expires; internal float NextRequest; internal readonly List Members = new List(); } internal sealed class GateTrain { internal string Identity = ""; internal List Cars = new List(); internal bool Complete; internal RailVehicle? Root; internal Dictionary? Reversed; internal IReadOnlyList Bodies(Transform gate) { //IL_0073: 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_009e: 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_00b4: 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_008e: Unknown result type (might be due to invalid IL or missing references) List list = new List(Cars.Count); float num = (Object.op_Implicit((Object)(object)Root) ? Root.GateSignedSpeed() : 0f); foreach (RailVehicle car in Cars) { if (!Object.op_Implicit((Object)(object)car)) { Complete = false; continue; } bool value; Vector3 velocity = ((Reversed != null && Reversed.TryGetValue(car, out value)) ? (((Component)car).transform.forward * (value ? (0f - num) : num)) : Vector3.zero); list.Add(car.GateBody(gate, ((Component)car).transform.position, ((Component)car).transform.rotation, Identity, velocity)); if (!car.GateBoundsComplete) { Complete = false; } } return list; } } private readonly struct GateApproachScan { internal readonly bool Forward; internal readonly bool Approaching; internal readonly float Until; internal GateApproachScan(bool forward, bool approaching, float until) { Forward = forward; Approaching = approaching; Until = until; } } internal sealed class TurntableMember { internal RailVehicle Cart; internal RailCursor Cursor; internal Bounds Bounds; internal string Links = ""; internal readonly List Objects = new List(); internal readonly Dictionary Revisions = new Dictionary(); } private const string AudioOwnerKey = "vikingrail_audio_owner"; private const string AudioUntilKey = "vikingrail_audio_until"; private const string AudioSpeedKey = "vikingrail_audio_speed"; private const string AudioPoweredKey = "vikingrail_audio_powered"; private long _audioKnownOwner; private float _audioStepSpeed; private bool _audioStepPowered; private float _audioStepAt; private float _nextAudioPublish; private bool _audioPublishedMoving; private bool _audioPublishedPowered; private GameObject? _audioObject; private AudioSource? _rollingSound; private AudioSource? _steamSound; private AudioSource? _chuffSound; private AudioMixerGroup? _soundMixer; private float _heardSpeed; private float _chuffPhase; private float _chuffGain; private bool _audioFailed; private const string AutoControllerKey = "vikingrail_autodrive_controller"; private const string AutoActiveKey = "vikingrail_autodrive_active"; private const string AutoOwnerKey = "vikingrail_autodrive_owner"; private const string AutoOwnerRevisionKey = "vikingrail_autodrive_owner_revision"; private const string AutoStatusKey = "vikingrail_autodrive_status"; private bool _autoRequestPending; private float _autoRequestTime; private long _autoRequestOwner; private BeamAim[] _beamAims = Array.Empty(); private const string CargoTokenKey = "vikingrail_cargo_token"; private const string CargoCartKey = "vikingrail_cargo_cart"; private const string CargoPeerKey = "vikingrail_cargo_peer"; private const string CargoPlayerKey = "vikingrail_cargo_player"; private const string CargoUntilKey = "vikingrail_cargo_until"; private const string CargoPhaseKey = "vikingrail_cargo_phase"; private const string CargoAuthorityKey = "vikingrail_cargo_authority"; private const string CargoAuthorityRevisionKey = "vikingrail_cargo_authority_revision"; private const string CargoOriginKey = "vikingrail_cargo_origin"; private const string CargoOriginTokenKey = "vikingrail_cargo_origin_token"; private const string CargoOriginIdentityKey = "vikingrail_cargo_origin_identity"; private const long CargoLeaseMilliseconds = 10000L; private float _nextCargoSeal; private long _cargoSnapshotPeer; private int _cargoSnapshotOwnerRevision; private uint _cargoSnapshotDataRevision; private string _cargoSnapshotDigest = ""; private const string ConsistDriveRequestRpc = "VR_ConsistDrive"; private const string ConsistDriveYieldRpc = "VR_ConsistDriveYield"; private const string ConsistDriveYieldReplyRpc = "VR_ConsistDriveYieldReply"; private const string ConsistDriveTokenKey = "vikingrail_drive_prepare_token"; private const string ConsistDriveRootKey = "vikingrail_drive_prepare_root"; private const string ConsistDriveUntilKey = "vikingrail_drive_prepare_until"; private const string ConsistDriveCabKey = "vikingrail_drive_prepare_cab"; private const string ConsistDrivePlayerKey = "vikingrail_drive_prepare_player"; private const string ConsistDrivePeerKey = "vikingrail_drive_prepare_peer"; private const string ConsistDriveOwnerKey = "vikingrail_drive_prepare_owner"; private const string ConsistDriveRevisionKey = "vikingrail_drive_prepare_revision"; private const float ConsistDriveTimeout = 8f; private ConsistDriveOperation? _consistDriveOperation; private ZDOID _consistMountRequestRoot = ZDOID.None; private static readonly FieldInfo? ConsistContainerLoading = AccessTools.Field(typeof(Container), "m_loading"); private static readonly FieldInfo? ConsistInventoryWeight = AccessTools.Field(typeof(Inventory), "m_totalWeight"); private static readonly MethodInfo? ConsistContainerSave = AccessTools.Method(typeof(Container), "Save", Type.EmptyTypes, (Type[])null); private const string ReleasedCouplerKey = "vikingrail_released_coupler"; private const float CouplerResetDistance = 3.1499999f; private ContactCouplingClient? _contactCouplingClient; private const string CoupleRequestRpc = "VR_CoupleAtEnds_v2"; private const string CoupleYieldRpc = "VR_CoupleYield"; private const string CoupleYieldReplyRpc = "VR_CoupleYieldReply"; private const string CoupleReplyRpc = "VR_CoupleReply"; private const string CoupleTokenKey = "vikingrail_couple_token"; private const string CoupleRootKey = "vikingrail_couple_root"; private const string CoupleUntilKey = "vikingrail_couple_until"; private const string CouplePlayerKey = "vikingrail_couple_player"; private const string CouplePeerKey = "vikingrail_couple_peer"; private const string CoupleWagonKey = "vikingrail_couple_wagon"; private const string CoupleParentKey = "vikingrail_couple_parent"; private const string CoupleExpectedKey = "vikingrail_couple_expected"; private const string CoupleMoverKey = "vikingrail_couple_mover"; private const string CoupleEndsKey = "vikingrail_couple_ends"; private const float CoupleTimeout = 8f; private CouplingOperation? _couplingOperation; private ZDOID _couplingClientWagon = ZDOID.None; private long _couplingClientOwner; private float _couplingClientUntil; public bool IsEngine; public bool IsTandemHandcart; public const float CouplerSpacing = 2.8f; private const string ParentKey = "vikingrail_parent"; private const string NextKey = "vikingrail_next"; private const string FrontKey = "vikingrail_front"; private const string ParentFrontKey = "vikingrail_parent_front"; private const string DriverKey = "vikingrail_driver"; private const string TrackKey = "vikingrail_track"; private const string DirectionKey = "vikingrail_direction"; private const string DistanceKey = "vikingrail_distance"; private static readonly HashSet Vehicles = new HashSet(); private ZNetView _view; private Rigidbody _body; private Container? _container; private RailWorkshopCart? _workshop; private RailMusicCart? _music; private RailPumpPartner? _pumpPartner; private bool _teamwork; private Transform _seat; private Transform? _pump; private Transform? _bronzeFlywheel; private string _identity = ""; private RailCursor? _cursor; private Player? _driver; private bool _ready; private bool _pendingMount; private bool _mountGranted; private float _requestTime; private float _inputTime; private float _throttle; private bool _brake; private bool _serviceNeedsNeutral; private float _orphanTimer; private float _pumpPhase; public bool CoalPowered; public bool BronzePowered; public bool EitrPowered; private const string FuelKey = "vikingrail_fuel_seconds_bits"; private Bounds _gateBounds; private bool _gateBoundsComplete; private float _gateBoundsAt = float.NegativeInfinity; private string _gateBoundsLinks = ""; private readonly Dictionary _gateApproaches = new Dictionary(); private long _requestOwner; private const string LightsKey = "vikingrail_lights_on"; private Light[] _railLights = Array.Empty(); private float[] _railLightIntensities = Array.Empty(); private Renderer[] _railLenses = Array.Empty(); private Color[] _railLensEmission = Array.Empty(); private MaterialPropertyBlock? _lampProperties; private float _lampBrightness = -1f; private float _nextLightRequest; private static ZDOMan? _linkCleanupManager; public bool IsPassengerCart; public bool IsPumpkinCart; private const string MovingUntilKey = "vikingrail_moving_until"; private RailPassengerSeat[] _passengerSeats = Array.Empty(); private float _nextMotionUpdate; private const float PackedPlacementRange = 5f; private static readonly FieldInfo? PackedPlacementPlatformUser = AccessTools.Field(typeof(CrossNetworkUserInfo), "m_id"); private static readonly MethodInfo? PackedPlacementSetCreator = ((PackedPlacementPlatformUser == null) ? null : AccessTools.Method(typeof(Piece), "SetCreator", new Type[2] { typeof(long), PackedPlacementPlatformUser.FieldType }, (Type[])null)); private const string PlowKey = "vikingrail_plow"; private const string PlowFrontKey = "vikingrail_plow_front"; internal const string PlowIntentUntilKey = "vikingrail_plow_intent_until"; internal const string PlowIntentSpeedKey = "vikingrail_plow_intent_speed"; internal const string PlowIntentTravelKey = "vikingrail_plow_intent_travel"; internal const string PlowIntentForwardKey = "vikingrail_plow_intent_forward"; internal const string PlowDriveForwardKey = "vikingrail_plow_drive_forward"; private float _plowContactSpeed; private float _plowContactTravel; private RailVehicle? _activePlowCarrier; private const string PackedKey = "vikingrail_vehicle_packed"; private const string PackedItemKey = "vikingrail_vehicle_packed_item"; private bool _packing; private bool _packPending; private float _packRequestTime; private long _packRequestOwner; internal const string RemoteTokenKey = "vikingrail_remote_session"; internal const string RemoteLeaseKey = "vikingrail_remote_prepare_until"; private const string SmokeOwnerKey = "vikingrail_smoke_owner"; private const string SmokeUntilKey = "vikingrail_smoke_until"; private const float SmokeRange = 64f; private const float SmokeLeaseSeconds = 2f; private static readonly FieldInfo? SmokeTemplateField = AccessTools.Field(typeof(SmokeRenderer), "_particleSystemPrefab"); private ParticleSystem? _chimneySmoke; private Material? _ownedSmokeMaterial; private Texture2D? _ownedSmokeTexture; private long _smokeKnownOwner; private bool _smokeStepPowered; private float _smokeStepTime; private bool _smokePublished; private float _nextSmokePublish; private bool _smokeFailed; private Transform? _steamLeftFront; private Transform? _steamLeftRear; private Transform? _steamRightFront; private Transform? _steamRightRear; private Transform? _steamLeftRod; private Transform? _steamRightRod; private Transform? _steamLeftPiston; private Transform? _steamRightPiston; private Transform? _steamFlywheel; private Vector3 _steamLastPosition; private Vector3 _steamLastForward; private bool _steamMotionBaseline; private long _steamMotionOwner; private int _steamMotionOwnerRevision; private double _steamPhase; private double _steamLastTime; private bool _steamPoseApplied; private readonly HashSet _brakeBypass = new HashSet(); private string? _brakeStop; private bool _neutralAfterStop; private readonly RailManualThrottle _manualThrottle = new RailManualThrottle(); private const double LocomotiveHalfLength = 1.4; private const string MetalTrackRequired = "Coal and Eitr engines require metal track. Wooden track supports handcarts, bronze engines and wagons."; internal bool PassengerFireServiceAllowed { get { if (Ready && !_packing && !_packPending && !CargoServiceBusy && !CouplingServiceBusy) { return PassengerBoardingAllowed; } return false; } } internal bool RepairStationAvailable { get { if (!WorkshopTrainParked || !TryWorkshopTrain(out List train)) { return false; } foreach (RailVehicle item in train) { if (item.Speed != 0f || item._packing || item._packPending || item.IsPacked || item.CargoBusy || item.CargoServiceBusy || item.CouplingServiceBusy) { return false; } } return true; } } private float PumpVisualSpeed { get { if (!Ready) { return 0f; } if (_view.IsOwner()) { return Mathf.Abs(Speed); } if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return 0f; } ZDO zDO = _view.GetZDO(); if (!HasMotionAuthority || !RailAudioMotion.LeaseActive(ZNet.instance.GetTime().Ticks, zDO.GetLong("vikingrail_audio_until", 0L), zDO.GetOwner(), zDO.GetLong("vikingrail_audio_owner", 0L), zDO.GetOwner())) { return 0f; } return RailAudioMotion.ValidSpeed(zDO.GetFloat("vikingrail_audio_speed", 0f)); } } private float PumpAnimationSpeed { get { if (!IsEngine || FuelPowered || !Ready) { return 0f; } if (_view.IsOwner()) { if (!RecentMovementAudioStep || !_audioStepPowered || !(RailAudioMotion.ValidSpeed(_audioStepSpeed) > 0f)) { return 0f; } return PumpVisualSpeed; } if (!_view.GetZDO().GetBool("vikingrail_audio_powered", false)) { return 0f; } return PumpVisualSpeed; } } private bool RecentMovementAudioStep { get { if (IsLocallySimulatedMotion && HasMotionAuthority && Mathf.Abs(Speed) > 0.025f) { return Time.time - _audioStepAt <= Mathf.Max(0.1f, Time.fixedDeltaTime * 2.5f); } return false; } } internal bool SupportsAutoDrive => RailAutomaticDrive.Supports(IsEngine, CoalPowered, EitrPowered); internal string AttachedAutoDriveId { get { if (!Ready) { return ""; } return _view.GetZDO().GetString("vikingrail_autodrive_controller", ""); } } internal RailAutoDrive? MountedAutoDrive { get { if (!SupportsAutoDrive || AttachedAutoDriveId.Length == 0) { return null; } RailAutoDrive railAutoDrive = RailAutoDrive.Find(AttachedAutoDriveId); if (!Object.op_Implicit((Object)(object)railAutoDrive) || !(railAutoDrive.EngineIdentity == _identity)) { return null; } return railAutoDrive; } } internal bool AutomaticDriveRequested { get { if (Ready) { return _view.GetZDO().GetBool("vikingrail_autodrive_active", false); } return false; } } internal bool AutoDriveActive { get { if (!Ready || ParentId.Length != 0) { return false; } ZDO zDO = _view.GetZDO(); return RailAutomaticDrive.SessionValid(AutomaticDriveRequested, SupportsAutoDrive, Object.op_Implicit((Object)(object)MountedAutoDrive), DriverId, zDO.GetOwner(), zDO.OwnerRevision, zDO.GetLong("vikingrail_autodrive_owner", 0L), zDO.GetInt("vikingrail_autodrive_owner_revision", -1)); } } internal bool HasDriveAuthority { get { if (Ready && ParentId.Length == 0) { if (DriverId == 0L) { return AutoDriveActive; } return true; } return false; } } internal bool IsLocallySimulatedDrive { get { if (Ready && ParentId.Length == 0 && _view.IsOwner()) { if (!Object.op_Implicit((Object)(object)_driver) || DriverId != _driver.GetPlayerID()) { return AutoDriveActive; } return true; } return false; } } internal string AutoDriveStatus { get { if (!Ready) { return "Controller unavailable."; } return _view.GetZDO().GetString("vikingrail_autodrive_status", "Automatic drive stopped."); } } internal bool AutoDriveAttachmentChangesAllowed { get { if (!Ready || !SupportsAutoDrive || !FindRoot(out RailVehicle root) || !ReadCouplingChain(root, out List chain) || !chain.Contains(this)) { return false; } return chain.All((RailVehicle cart) => cart.Ready && !cart.AutomaticDriveRequested && cart.DriverId == 0L && !Object.op_Implicit((Object)(object)cart._driver) && !cart._pendingMount && !cart._packing && !cart._packPending && (!cart.IsEngine || !cart.HasPassengers) && !cart.CargoBusy && !cart.CargoServiceBusy && !cart.CouplingServiceBusy && !cart.MountServiceBusy && Mathf.Abs(cart.Speed) < 0.05f && (!Object.op_Implicit((Object)(object)ZNet.instance) || cart._view.GetZDO().GetLong("vikingrail_moving_until", 0L) <= CargoNow)); } } private static long CargoNow { get { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return 0L; } return (long)(ZNet.instance.GetTimeSeconds() * 1000.0); } } private string CargoToken { get { if (!Ready) { return ""; } return _view.GetZDO().GetString("vikingrail_cargo_token", ""); } } internal bool CargoServiceBusy { get { if (Ready) { if (CargoToken.Length == 0 && (!FindRoot(out RailVehicle root) || root.CargoToken.Length == 0) && !HasCargoOrigin) { return RailCargoInventory.HasPending(this); } return true; } return false; } } private bool HasCargoOrigin { get { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (!Ready) { return false; } string text = _view.GetZDO().GetString("vikingrail_cargo_origin_token", ""); if (text.Length == 0) { return false; } RailVehicle railVehicle = FindSession(_view.GetZDO().GetZDOID("vikingrail_cargo_origin")); if (Object.op_Implicit((Object)(object)railVehicle) && railVehicle.Ready) { return railVehicle.CargoToken == text; } return true; } } internal bool CargoStationary { get { if (!Ready || !FindRoot(out RailVehicle root) || !root.CargoChain(out List train) || !train.Contains(this)) { return false; } if (root.AutomaticDriveRequested) { return false; } if (!root.IsEngine && (root.DriverId != 0L || root._pendingMount)) { return false; } if (root._pendingMount) { return false; } if (!root._view.IsOwner()) { if (Object.op_Implicit((Object)(object)ZNet.instance)) { return root._view.GetZDO().GetLong("vikingrail_moving_until", 0L) <= CargoNow; } return false; } return root.Speed == 0f; } } private bool ConsistMountRequestPending => !((ZDOID)(ref _consistMountRequestRoot)).IsNone(); private bool HasConsistDriveLease { get { if (Ready && Object.op_Implicit((Object)(object)ZNet.instance) && _view.GetZDO().GetLong("vikingrail_drive_prepare_until", 0L) > CouplingNow && _view.GetZDO().GetLong("vikingrail_drive_prepare_until", 0L) <= CouplingNow + 12000) { return _view.GetZDO().GetString("vikingrail_drive_prepare_token", "").Length == 32; } return false; } } internal bool ConsistDriveBusy { get { //IL_002c: Unknown result type (might be due to invalid IL or missing references) if (_consistDriveOperation != null) { return true; } if (!Ready) { return false; } if (HasConsistDriveLease) { RailVehicle railVehicle = FindSession(_view.GetZDO().GetZDOID("vikingrail_drive_prepare_root")); if (!Object.op_Implicit((Object)(object)railVehicle) || (railVehicle.HasConsistDriveLease && railVehicle._view.GetZDO().GetString("vikingrail_drive_prepare_token", "") == _view.GetZDO().GetString("vikingrail_drive_prepare_token", ""))) { return true; } } if (FindRoot(out RailVehicle root) && (Object)(object)root != (Object)(object)this) { if (root._consistDriveOperation == null) { return root.HasConsistDriveLease; } return true; } return false; } } internal int ActiveEngineCount { get; private set; } = 1; private bool HasMotionAuthority { get { RailVehicle root; if (!HasDriveAuthority) { return TryConsistMotionRoot(out root); } return true; } } private bool IsLocallySimulatedMotion { get { if (!IsLocallySimulatedDrive) { if (TryConsistMotionRoot(out RailVehicle root) && _view.IsOwner()) { return root.IsLocallySimulatedDrive; } return false; } return true; } } private static long CouplingNow { get { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return 0L; } return (long)(ZNet.instance.GetTimeSeconds() * 1000.0); } } private bool HasCouplingLease { get { if (Ready && Object.op_Implicit((Object)(object)ZNet.instance) && _view.GetZDO().GetLong("vikingrail_couple_until", 0L) > CouplingNow && _view.GetZDO().GetLong("vikingrail_couple_until", 0L) <= CouplingNow + 12000) { return _view.GetZDO().GetString("vikingrail_couple_token", "").Length == 32; } return false; } } internal bool CouplingServiceBusy { get { //IL_0042: Unknown result type (might be due to invalid IL or missing references) if (ConsistDriveBusy) { return true; } if (RailTurntable.BlocksVehicle(this)) { return true; } if (RailRemoteDrive.IsPreparing(this)) { return true; } if (_couplingOperation != null) { return true; } if (!HasCouplingLease) { return false; } RailVehicle railVehicle = FindSession(_view.GetZDO().GetZDOID("vikingrail_couple_root")); if (Object.op_Implicit((Object)(object)railVehicle)) { if (railVehicle.HasCouplingLease) { return railVehicle._view.GetZDO().GetString("vikingrail_couple_token", "") == _view.GetZDO().GetString("vikingrail_couple_token", ""); } return false; } return true; } } private bool CouplingBlocksMovement { get { if (!CouplingServiceBusy) { return _contactCouplingClient != null; } return true; } } private bool IsCouplingRootEngine { get { if (IsEngine) { return ParentId.Length == 0; } return false; } } public static RailVehicle? LocalDriven { get; private set; } public float Speed { get; private set; } public int WagonCount { get; private set; } public string Status { get; private set; } = "Build the cart on a railway."; private bool Ready { get { if (_ready && Object.op_Implicit((Object)(object)_view) && _view.IsValid() && _identity.Length != 0) { return !IsPacked; } return false; } } private ZDOID Id { get { //IL_0019: 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) if (!Ready) { return ZDOID.None; } return _view.GetZDO().m_uid; } } private string ParentId { get { if (!Ready) { return ""; } return _view.GetZDO().GetString("vikingrail_parent", ""); } } private string NextId { get { if (!Ready) { return ""; } return _view.GetZDO().GetString("vikingrail_next", ""); } } private string FrontId { get { if (!Ready || !IsEngine) { return ""; } return _view.GetZDO().GetString("vikingrail_front", ""); } } private bool ParentFront { get { if (Ready) { return _view.GetZDO().GetBool("vikingrail_parent_front", true); } return true; } } private long DriverId { get { if (!Ready) { return 0L; } return _view.GetZDO().GetLong("vikingrail_driver", 0L); } } public bool IsCoupled => ParentId.Length != 0; public bool TrainOccupied { get { if (FindRoot(out RailVehicle root)) { if (root.DriverId == 0L) { return root.AutomaticDriveRequested; } return true; } return false; } } private int CartLimit { get { if (!EitrPowered) { if (!CoalPowered) { if (!BronzePowered) { if (!IsTandemHandcart) { return RailSettings.HandcartMaxCarts; } return RailSettings.TandemHandcartMaxCarts; } return RailSettings.BronzeEngineMaxCarts; } return RailSettings.LocomotiveMaxCarts; } return RailSettings.EitrEngineMaxCarts; } } private double TrainSpeedLimit { get { if (!EitrPowered) { if (!CoalPowered) { if (!BronzePowered) { if (!IsTandemHandcart || !_teamwork) { return RailSettings.HandcartMaxSpeed; } return RailSettings.TandemHandcartMaxSpeed; } return RailSettings.BronzeEngineMaxSpeed; } return RailSettings.LocomotiveMaxSpeed; } return RailSettings.EitrEngineMaxSpeed; } } internal double PumpingStaminaRate { get { if (!IsTandemHandcart || !_teamwork) { return RailSettings.HandcartStaminaPerSecond; } return RailSettings.TandemHandcartStaminaPerSecond; } } internal RailPumpPartner? PumpPartner => _pumpPartner; private bool CargoBusy { get { if (Object.op_Implicit((Object)(object)_container)) { if (!_container.IsInUse()) { return _view.GetZDO().GetInt("InUse", 0) == 1; } return true; } return false; } } private static bool DrivingControlsAvailable { get { if (Application.isFocused) { if (!Menu.IsVisible() && !InventoryGui.IsVisible() && !Console.IsVisible() && !TextInput.IsVisible() && !Minimap.IsOpen() && !StoreGui.IsVisible() && !Hud.InRadial() && !Hud.IsPieceSelectionVisible() && !GameCamera.InFreeFly() && !PlayerCustomizaton.IsBarberGuiVisible() && (!Object.op_Implicit((Object)(object)TextViewer.instance) || !TextViewer.instance.IsVisible()) && (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || !((Character)Player.m_localPlayer).InCutscene())) { if (Object.op_Implicit((Object)(object)Chat.instance)) { return !Chat.instance.HasFocus(); } return true; } return false; } return false; } } public bool FuelPowered { get { if (!CoalPowered && !BronzePowered) { return EitrPowered; } return true; } } private bool CombustionPowered { get { if (!CoalPowered) { return BronzePowered; } return true; } } private RailFuelType FuelType { get { if (!EitrPowered) { if (!BronzePowered) { return RailFuelType.Coal; } return RailFuelType.Wood; } return RailFuelType.Eitr; } } private string FuelName { get { if (!EitrPowered) { if (!BronzePowered) { return "coal"; } return "wood"; } return "refined Eitr"; } } private double SecondsPerFuelItem { get { if (!EitrPowered) { if (!BronzePowered) { return RailSettings.CoalSecondsPerItem; } return RailSettings.BronzeFuelSecondsPerItem; } return RailSettings.EitrFuelSecondsPerItem; } } public double FuelSeconds { get { if (!FuelPowered || !Ready) { return 0.0; } double num = BitConverter.Int64BitsToDouble(_view.GetZDO().GetLong("vikingrail_fuel_seconds_bits", 0L)); if (!double.IsNaN(num) && !double.IsInfinity(num)) { return Math.Max(0.0, Math.Min(86400.0, num)); } return 0.0; } } public int FuelCount { get { if (!FuelPowered || !Ready || !Object.op_Implicit((Object)(object)_container)) { return 0; } return _container.GetInventory().GetAllItems().Where(IsFuel) .Sum((ItemData item) => item.m_stack); } } public int CoalCount { get { if (!CoalPowered) { return 0; } return FuelCount; } } public string FuelStatus => FuelCount + " " + FuelName + " + " + FuelSeconds.ToString("0.0") + " s burn time remaining"; internal bool GateBoundsComplete { get { RefreshGateBounds(); return _gateBoundsComplete; } } private static Bounds GateFallbackBounds => new Bounds(new Vector3(0f, 2.4f, 0f), new Vector3(5f, 5f, 7f)); private string GateIdentity { get { if (_identity.Length == 0) { return "unready:" + ((Object)this).GetInstanceID(); } return _identity; } } internal bool CanHandPush { get { if (!IsEngine && Object.op_Implicit((Object)(object)_seat)) { return ((Object)_seat).name == "vr_push_anchor"; } return false; } } internal bool CanControlRoute { get { if (!IsEngine) { if (CanHandPush && ParentId.Length == 0) { return NextId.Length == 0; } return false; } return true; } } internal bool LightsOn { get { if (Ready) { return _view.GetZDO().GetBool("vikingrail_lights_on", true); } return false; } } internal Vector3 HeadlampLocalPosition => new Vector3(IsTandemHandcart ? 0.52f : 0f, FuelPowered ? 1.55f : 1.27f, FuelPowered ? 1.22f : 1.1f); private RailMountCart? MountCart => ((Component)this).GetComponent(); internal bool IsMountCart => Object.op_Implicit((Object)(object)MountCart); internal bool MountServiceBusy { get { if (Object.op_Implicit((Object)(object)MountCart)) { return MountCart.Busy; } return false; } } internal bool HasMountedObjects { get { if (Object.op_Implicit((Object)(object)MountCart)) { return MountCart.HasOccupants; } return false; } } internal bool MountChangesAllowed { get { if (Ready && !_packing && !_packPending && !_pendingMount && !Object.op_Implicit((Object)(object)_driver) && DriverId == 0L && !HasPassengers && ParentId.Length == 0 && NextId.Length == 0 && !CargoBusy && !CargoServiceBusy) { return !CouplingServiceBusy; } return false; } } private float MountedWeight { get { RailMountCart mountCart = MountCart; if (!Object.op_Implicit((Object)(object)mountCart)) { return 0f; } float num = 0f; foreach (RailMountedObject attachment in mountCart.Attachments) { Rigidbody component = ((Component)attachment).GetComponent(); float num2 = (Object.op_Implicit((Object)(object)component) ? component.mass : 10f); Container component2 = ((Component)attachment).GetComponent(); float num3 = (Object.op_Implicit((Object)(object)component2) ? component2.GetInventory().GetTotalWeight() : 0f); if (!float.IsNaN(num2) && !float.IsInfinity(num2)) { num += Mathf.Clamp(num2, 0f, 10000f); } if (!float.IsNaN(num3) && !float.IsInfinity(num3)) { num += Mathf.Clamp(num3, 0f, 100000f); } } return num; } } internal RailPassengerSeat[] PassengerSeats => _passengerSeats; internal int PassengerCount { get { int num = 0; RailPassengerSeat[] passengerSeats = _passengerSeats; foreach (RailPassengerSeat railPassengerSeat in passengerSeats) { if (Object.op_Implicit((Object)(object)railPassengerSeat) && railPassengerSeat.IsOccupied) { num++; } } return num; } } internal bool HasPassengers { get { if (PassengerCount == 0) { if (Object.op_Implicit((Object)(object)_pumpPartner)) { return _pumpPartner.IsOccupied; } return false; } return true; } } internal bool TrainHasPassengers { get { if (!FindRoot(out RailVehicle root) || !ReadCouplingChain(root, out List chain) || !chain.Contains(this)) { return true; } foreach (RailVehicle item in chain) { if (item.HasPassengers) { return true; } } return false; } } internal bool PassengerBoardingAllowed { get { if (!Ready || CargoServiceBusy || CouplingServiceBusy || MountServiceBusy || !FindRoot(out RailVehicle root)) { return false; } if (root.AutomaticDriveRequested) { return false; } if (!root.IsEngine && (root.DriverId != 0L || root._pendingMount)) { return false; } if (root._view.IsOwner()) { return Mathf.Abs(root.Speed) < 0.05f; } if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return false; } return root._view.GetZDO().GetLong("vikingrail_moving_until", 0L) <= (long)(ZNet.instance.GetTimeSeconds() * 1000.0); } } internal bool IsReady => Ready; internal ZNetView View => _view; internal string PersistentId => _identity; internal long ReservedDriver => DriverId; internal static IEnumerable LoadedVehicles => Vehicles; internal string AttachedPlowId { get { if (!Ready) { return ""; } return _view.GetZDO().GetString("vikingrail_plow", ""); } } internal bool MountedPlowFront { get { if (Ready) { return _view.GetZDO().GetBool("vikingrail_plow_front", true); } return true; } } internal Vector3 PlowPosition => ((Component)this).transform.position; internal Quaternion PlowRotation => ((Component)this).transform.rotation * RailPlow.SocketRotationAt(MountedPlowFront); internal Vector3 PlowForward => PlowRotation * Vector3.forward; internal RailPlow? MountedPlow { get { if (AttachedPlowId.Length == 0) { return null; } RailPlow railPlow = RailPlow.Find(AttachedPlowId); if (!Object.op_Implicit((Object)(object)railPlow) || !(railPlow.EngineIdentity == _identity) || railPlow.Front != MountedPlowFront) { return null; } return railPlow; } } public bool HasPlow => Object.op_Implicit((Object)(object)MountedPlow); internal bool IsPacked { get { if (Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { return _view.GetZDO().GetBool("vikingrail_vehicle_packed", false); } return false; } } internal bool RemoteManaged { get { if (Ready) { return _view.GetZDO().GetString("vikingrail_remote_session", "").Length == 32; } return false; } } private float ManualDriveInput { get { if (!IsEngine) { return _throttle; } return _manualThrottle.NormalizedThrottle; } } internal string ThrottleStatus { get { if (_manualThrottle.Notch != 0) { return "Throttle: " + ((_manualThrottle.Direction > 0) ? "forward " : "reverse ") + Mathf.Abs(_manualThrottle.Notch) + "/" + 5; } return "Throttle: neutral (coast)"; } } private bool ManualThrottleAvailable { get { if (((Behaviour)this).isActiveAndEnabled && IsEngine && Ready && _view.IsOwner() && Object.op_Implicit((Object)(object)_driver) && (Object)(object)_driver == (Object)(object)Player.m_localPlayer && DriverId == _driver.GetPlayerID() && !((Character)_driver).IsDead() && !((Character)_driver).IsTeleporting() && ((Character)_driver).IsAttached() && (object)_driver.GetDoodadController() == this && !AutomaticDriveRequested && !_serviceNeedsNeutral) { return DrivingControlsAvailable; } return false; } } private bool RequiresMetalTrack { get { if (!CoalPowered) { return EitrPowered; } return true; } } internal bool WorkshopTrainParked { get { if (!TryWorkshopTrain(out List train)) { return false; } long num = (Object.op_Implicit((Object)(object)ZNet.instance) ? ((long)(ZNet.instance.GetTimeSeconds() * 1000.0)) : 0); foreach (RailVehicle item in train) { if (item.AutomaticDriveRequested || item.DriverId != 0L || Object.op_Implicit((Object)(object)item._driver) || item._pendingMount || Mathf.Abs(item.Speed) >= 0.05f || item._view.GetZDO().GetLong("vikingrail_moving_until", 0L) > num) { return false; } } return true; } } internal bool TryDriverAnchor(Player player, out Transform anchor) { //IL_00db: 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_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) anchor = _seat; if (!Ready || (!IsEngine && !CanHandPush) || !Object.op_Implicit((Object)(object)_seat) || DriverId == 0L || DriverId != player.GetPlayerID()) { return false; } if ((Object)(object)player == (Object)(object)Player.m_localPlayer) { if ((Object)(object)_driver == (Object)(object)player && (Object)(object)LocalDriven == (Object)(object)this && _view.IsOwner() && ((Character)player).IsAttached() && (Object)(object)player.GetAttachPoint() == (Object)(object)_seat) { return (object)player.GetDoodadController() == this; } return false; } ZNetView component = ((Component)player).GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid()) { return false; } ZDO zDO = component.GetZDO(); if (zDO.GetOwner() == _view.GetZDO().GetOwner() && zDO.GetConnectionZDOID((ConnectionType)2) == _view.GetZDO().m_uid) { return Vector3.Distance(zDO.GetVec3(ZDOVars.s_relPosHash, Vector3.positiveInfinity), ((Component)this).transform.InverseTransformPoint(_seat.position)) <= 0.3f; } return false; } private void FollowMountedTorches() { foreach (RailMountedTorch loadedTorch in RailMountedTorch.LoadedTorches) { if (Object.op_Implicit((Object)(object)loadedTorch) && (Object)(object)loadedTorch.Vehicle == (Object)(object)this) { loadedTorch.Follow(this); } } } private void AddAttachmentObstacleVolumes(List hits, Vector3 nextPosition, Quaternion nextRotation) { //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_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) //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_0032: 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_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_0045: 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_0067: 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_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_007f: 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_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_0088: 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_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) //IL_0099: 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_00b6: 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_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_00bf: 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_00c6: 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_00df: 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_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_023d: 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_0247: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: 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_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_03e8: Unknown result type (might be due to invalid IL or missing references) //IL_03ef: Unknown result type (might be due to invalid IL or missing references) //IL_03f4: Unknown result type (might be due to invalid IL or missing references) //IL_03f9: Unknown result type (might be due to invalid IL or missing references) //IL_0405: Unknown result type (might be due to invalid IL or missing references) //IL_040a: Unknown result type (might be due to invalid IL or missing references) //IL_040f: Unknown result type (might be due to invalid IL or missing references) //IL_0411: Unknown result type (might be due to invalid IL or missing references) //IL_0412: Unknown result type (might be due to invalid IL or missing references) //IL_0413: Unknown result type (might be due to invalid IL or missing references) //IL_0415: Unknown result type (might be due to invalid IL or missing references) //IL_041a: Unknown result type (might be due to invalid IL or missing references) //IL_041f: Unknown result type (might be due to invalid IL or missing references) //IL_0423: Unknown result type (might be due to invalid IL or missing references) //IL_0428: Unknown result type (might be due to invalid IL or missing references) //IL_042d: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Unknown result type (might be due to invalid IL or missing references) //IL_0436: Unknown result type (might be due to invalid IL or missing references) //IL_043b: Unknown result type (might be due to invalid IL or missing references) //IL_0445: Unknown result type (might be due to invalid IL or missing references) //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_044f: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_0329: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_034f: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_037f: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_0389: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Unknown result type (might be due to invalid IL or missing references) //IL_0397: Unknown result type (might be due to invalid IL or missing references) //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03ad: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_03b4: Unknown result type (might be due to invalid IL or missing references) //IL_03b5: Unknown result type (might be due to invalid IL or missing references) //IL_03b6: Unknown result type (might be due to invalid IL or missing references) //IL_03b8: Unknown result type (might be due to invalid IL or missing references) //IL_03bd: Unknown result type (might be due to invalid IL or missing references) //IL_03c2: Unknown result type (might be due to invalid IL or missing references) //IL_03c9: Unknown result type (might be due to invalid IL or missing references) //IL_03d3: Unknown result type (might be due to invalid IL or missing references) //IL_03d8: Unknown result type (might be due to invalid IL or missing references) //IL_03dd: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: Unknown result type (might be due to invalid IL or missing references) //IL_0452: Unknown result type (might be due to invalid IL or missing references) //IL_0454: Unknown result type (might be due to invalid IL or missing references) //IL_0456: Unknown result type (might be due to invalid IL or missing references) //IL_0458: Unknown result type (might be due to invalid IL or missing references) //IL_0172: 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_0187: 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_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: 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) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: 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) Vector3[] array = (Vector3[])(object)new Vector3[2] { RailCouplingLever.Offset, RailCouplingLever.RearOffset }; foreach (Vector3 val in array) { AddVolumeHits(hits, ((Component)this).transform.TransformPoint(val), nextPosition + nextRotation * val, RailCouplingLever.HalfExtents, nextRotation); } if (Object.op_Implicit((Object)(object)MountedAutoDrive)) { Vector3 val2 = RailAutoDrive.SocketOffset + RailAutoDrive.LocalBoundsCenter; AddVolumeHits(hits, ((Component)this).transform.TransformPoint(val2), nextPosition + nextRotation * val2, RailAutoDrive.LocalBoundsHalfSize, nextRotation); } if (IsEngine) { Vector3 headlampLocalPosition = HeadlampLocalPosition; AddVolumeHits(hits, ((Component)this).transform.TransformPoint(headlampLocalPosition), nextPosition + nextRotation * headlampLocalPosition, new Vector3(0.18f, 0.18f, 0.14f), nextRotation); } foreach (RailMountedTorch loadedTorch in RailMountedTorch.LoadedTorches) { if (!Object.op_Implicit((Object)(object)loadedTorch) || (Object)(object)loadedTorch.Vehicle != (Object)(object)this) { continue; } bool flag = false; Bounds val3 = default(Bounds); MeshFilter[] componentsInChildren = ((Component)loadedTorch).GetComponentsInChildren(true); foreach (MeshFilter val4 in componentsInChildren) { if (!Object.op_Implicit((Object)(object)val4.sharedMesh)) { continue; } Bounds bounds = val4.sharedMesh.bounds; for (int j = -1; j <= 1; j += 2) { for (int k = -1; k <= 1; k += 2) { for (int l = -1; l <= 1; l += 2) { Vector3 val5 = ((Bounds)(ref bounds)).center + Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3((float)j, (float)k, (float)l)); Vector3 val6 = ((Component)this).transform.InverseTransformPoint(((Component)val4).transform.TransformPoint(val5)); if (!flag) { ((Bounds)(ref val3))..ctor(val6, Vector3.zero); flag = true; } else { ((Bounds)(ref val3)).Encapsulate(val6); } } } } } if (flag) { Vector3 half = ((Bounds)(ref val3)).extents + Vector3.one * 0.035f; AddVolumeHits(hits, ((Component)this).transform.TransformPoint(((Bounds)(ref val3)).center), nextPosition + nextRotation * ((Bounds)(ref val3)).center, half, nextRotation); } } RailMountCart mountCart = MountCart; if (!Object.op_Implicit((Object)(object)mountCart)) { return; } foreach (RailMountedObject attachment in mountCart.Attachments) { if (attachment.TryBounds(out var bounds2)) { Vector3 start = ((Component)attachment).transform.position + ((Component)attachment).transform.rotation * ((Bounds)(ref bounds2)).center; Vector3 val7 = Quaternion.Inverse(((Component)this).transform.rotation) * (((Component)attachment).transform.position - ((Component)this).transform.position); Vector3 half2; Vector3 end; Quaternion val9; if (attachment.IsDummy) { Vector2 val8 = new Vector2(((Bounds)(ref bounds2)).center.x, ((Bounds)(ref bounds2)).center.z); float magnitude = ((Vector2)(ref val8)).magnitude; val8 = new Vector2(((Bounds)(ref bounds2)).extents.x, ((Bounds)(ref bounds2)).extents.z); float num = magnitude + ((Vector2)(ref val8)).magnitude; half2 = new Vector3(num, ((Bounds)(ref bounds2)).extents.y, num) + Vector3.one * 0.025f; start = ((Component)attachment).transform.position + Vector3.up * ((Bounds)(ref bounds2)).center.y; end = nextPosition + nextRotation * val7 + Vector3.up * ((Bounds)(ref bounds2)).center.y; val9 = Quaternion.identity; } else { val9 = nextRotation * Quaternion.Inverse(((Component)this).transform.rotation) * ((Component)attachment).transform.rotation; end = nextPosition + nextRotation * val7 + val9 * ((Bounds)(ref bounds2)).center; half2 = ((Bounds)(ref bounds2)).extents + Vector3.one * 0.025f; } AddVolumeHits(hits, start, end, half2, val9); } } } private void InitializeMovementAudio() { if (IsEngine && Ready) { _audioKnownOwner = _view.GetZDO().GetOwner(); if (_view.IsOwner()) { PublishMovementAudio(0f, powered: false); } } } private void BeginMovementAudioStep() { _audioStepSpeed = 0f; _audioStepPowered = false; _audioStepAt = Time.time; } private void NotifyMovementAudio(float distance, float seconds, bool powered) { if (IsEngine && Ready && _view.IsOwner() && !(seconds <= 0f)) { _audioStepSpeed = RailAudioMotion.ValidSpeed(Mathf.Min(Mathf.Abs(Speed), distance / seconds)); _audioStepPowered = powered && _audioStepSpeed > 0f; _audioStepAt = Time.time; } } private void UpdateMovementAudio() { //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) if (!IsEngine || !Ready || !Object.op_Implicit((Object)(object)ZNet.instance)) { SilenceMovementSources(); return; } ZDO zDO = _view.GetZDO(); long owner = zDO.GetOwner(); if (_audioKnownOwner != owner) { _audioKnownOwner = owner; BeginMovementAudioStep(); _nextAudioPublish = 0f; _audioPublishedMoving = (_audioPublishedPowered = false); SilenceMovementSources(); if (_view.IsOwner()) { PublishMovementAudio(0f, powered: false); } } float num; bool flag; if (_view.IsOwner()) { num = (RecentMovementAudioStep ? RailAudioMotion.ValidSpeed(_audioStepSpeed) : 0f); flag = num > 0f && _audioStepPowered; if (num > 0f != _audioPublishedMoving || flag != _audioPublishedPowered || (num > 0f && Time.time >= _nextAudioPublish)) { PublishMovementAudio(num, flag); } } else { num = ((HasMotionAuthority && RailAudioMotion.LeaseActive(ZNet.instance.GetTime().Ticks, zDO.GetLong("vikingrail_audio_until", 0L), owner, zDO.GetLong("vikingrail_audio_owner", 0L), owner)) ? RailAudioMotion.ValidSpeed(zDO.GetFloat("vikingrail_audio_speed", 0f)) : 0f); flag = num > 0f && zDO.GetBool("vikingrail_audio_powered", false); } float num2 = (CoalPowered ? 48f : ((BronzePowered || EitrPowered) ? 36f : 28f)); if (TryGetMovementListener(out var position) && !AudioListener.pause && !(Time.timeScale <= 0f)) { Vector3 val = position - ((Component)this).transform.position; if (!(((Vector3)(ref val)).sqrMagnitude >= num2 * num2) && !_audioFailed) { if ((num <= 0f || (!FuelPowered && !flag)) && !Object.op_Implicit((Object)(object)_audioObject)) { return; } try { if (!Object.op_Implicit((Object)(object)_audioObject)) { CreateMovementSources(num2); } UpdateMovementSources(num, flag); return; } catch (Exception ex) { _audioFailed = true; CleanupMovementAudio(); RailPlugin.Warn("Vehicle sounds are unavailable; the railway can still operate. " + ex.Message); return; } } } SilenceMovementSources(); } private static bool TryGetMovementListener(out Vector3 position) { //IL_0001: 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: Invalid comparison between Unknown and I4 //IL_0065: 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) position = default(Vector3); if (!Object.op_Implicit((Object)(object)Player.m_localPlayer) || !Object.op_Implicit((Object)(object)AudioMan.instance) || (int)SystemInfo.graphicsDeviceType == 4 || (Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsDedicated())) { return false; } AudioListener activeAudioListener = AudioMan.instance.GetActiveAudioListener(); if (!Object.op_Implicit((Object)(object)activeAudioListener) || !((Behaviour)activeAudioListener).isActiveAndEnabled) { return false; } position = ((Component)activeAudioListener).transform.position; return true; } private void PublishMovementAudio(float speed, bool powered) { if (IsEngine && Ready && _view.IsOwner()) { speed = RailAudioMotion.ValidSpeed(speed); powered = powered && speed > 0f; ZDO zDO = _view.GetZDO(); zDO.Set("vikingrail_audio_owner", zDO.GetOwner()); zDO.Set("vikingrail_audio_speed", speed); zDO.Set("vikingrail_audio_powered", powered); zDO.Set("vikingrail_audio_until", (speed > 0f && Object.op_Implicit((Object)(object)ZNet.instance)) ? (ZNet.instance.GetTime().Ticks + 20000000) : 0); _audioPublishedMoving = speed > 0f; _audioPublishedPowered = powered; _nextAudioPublish = Time.time + 0.25f; } } private void CreateMovementSources(float range) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0054: 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_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) _audioObject = new GameObject("vr_movement_audio"); _audioObject.SetActive(false); _audioObject.transform.SetParent(((Component)this).transform, false); _soundMixer = RailAudioClips.FindEffectsMixer(); _rollingSound = CreateMovementSource("wheels", new Vector3(0f, 0.45f, 0f), range, loop: true); _rollingSound.clip = RailAudioClips.Rolling(FuelPowered); if (EitrPowered) { _steamSound = CreateMovementSource("eitr_resonance", new Vector3(0f, 1.58f, 0.34f), range, loop: true); _steamSound.clip = RailAudioClips.EitrHum; } else if (CombustionPowered) { _steamSound = CreateMovementSource("steam", new Vector3(0f, 1.6f, 0.55f), range, loop: true); _steamSound.clip = RailAudioClips.Hiss; _chuffSound = CreateMovementSource("chuffs", BronzePowered ? new Vector3(0f, 2.25f, 0.48f) : new Vector3(0f, 2.3f, 0.8f), range, loop: false); } _audioObject.SetActive(true); } private AudioSource CreateMovementSource(string name, Vector3 position, float range, bool loop) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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_0023: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name); val.transform.SetParent(_audioObject.transform, false); val.transform.localPosition = position; AudioSource obj = val.AddComponent(); obj.playOnAwake = false; obj.loop = loop; obj.spatialBlend = 1f; obj.rolloffMode = (AudioRolloffMode)1; obj.minDistance = 2.5f; obj.maxDistance = range; obj.dopplerLevel = 0f; obj.spread = 25f; obj.priority = 160; obj.volume = 0f; obj.outputAudioMixerGroup = _soundMixer; return obj; } private void UpdateMovementSources(float speed, bool powered) { float num = Mathf.Min(Time.deltaTime, 0.1f); _heardSpeed = Mathf.MoveTowards(_heardSpeed, speed, num * 12f); float num2 = (Object.op_Implicit((Object)(object)_soundMixer) ? 1f : Mathf.Clamp01(AudioMan.GetSFXVolume())); if (float.IsNaN(num2) || float.IsInfinity(num2)) { num2 = 0f; } float num3 = ((speed > 0f) ? Mathf.Clamp01(speed / 0.6f) : 0f); float num4 = ((FuelPowered || powered) ? (num3 * (EitrPowered ? 0.2f : (CoalPowered ? 0.36f : (BronzePowered ? 0.26f : 0.32f)))) : 0f); UpdateMovementLoop(_rollingSound, num4 * num2, RailAudioMotion.RollingPitch(_heardSpeed, FuelPowered), num); if (!FuelPowered) { return; } if (EitrPowered) { UpdateMovementLoop(_steamSound, powered ? (num3 * num2 * 0.24f) : 0f, 0.9f + Mathf.Clamp01(_heardSpeed / 7f) * 0.2f, num); return; } float num5 = (powered ? (num3 * (0.08f + Mathf.Clamp01(speed / 5f) * 0.06f) * (BronzePowered ? 0.45f : 1f)) : 0f); UpdateMovementLoop(_steamSound, num5 * num2, 1f, num); _chuffGain = Mathf.MoveTowards(_chuffGain, powered ? ((BronzePowered ? 0.27f : 0.42f) * num3 * num2) : 0f, num * 4f); if (Object.op_Implicit((Object)(object)_chuffSound)) { _chuffSound.volume = _chuffGain; } if (!powered || speed <= 0f || num2 <= 0f) { _chuffPhase = 0f; if (Object.op_Implicit((Object)(object)_chuffSound) && _chuffGain <= 0.001f) { _chuffSound.Stop(); } return; } _chuffPhase += num * RailAudioMotion.ChuffsPerSecond(_heardSpeed); if (_chuffPhase >= 1f && Object.op_Implicit((Object)(object)_chuffSound)) { _chuffPhase %= 1f; _chuffSound.pitch = (BronzePowered ? 1.15f : 0.9f) + Mathf.Clamp01(_heardSpeed / 5f) * 0.15f; _chuffSound.PlayOneShot(RailAudioClips.Chuff); } } private static void UpdateMovementLoop(AudioSource? source, float target, float pitch, float dt) { if (Object.op_Implicit((Object)(object)source)) { source.pitch = pitch; source.volume = Mathf.MoveTowards(source.volume, target, dt * 2.5f); if (target > 0f && !source.isPlaying) { source.Play(); } else if (target <= 0f && source.volume <= 0.001f) { source.Stop(); } } } private void StopMovementAudio(bool immediate = false) { BeginMovementAudioStep(); if (_audioPublishedMoving || _audioPublishedPowered) { PublishMovementAudio(0f, powered: false); } if (immediate) { SilenceMovementSources(); } } private void SilenceMovementSources() { if (Object.op_Implicit((Object)(object)_rollingSound)) { _rollingSound.Stop(); _rollingSound.volume = 0f; } if (Object.op_Implicit((Object)(object)_steamSound)) { _steamSound.Stop(); _steamSound.volume = 0f; } if (Object.op_Implicit((Object)(object)_chuffSound)) { _chuffSound.Stop(); _chuffSound.volume = 0f; } _heardSpeed = (_chuffPhase = (_chuffGain = 0f)); } private void CleanupMovementAudio() { StopMovementAudio(immediate: true); if (Object.op_Implicit((Object)(object)_audioObject)) { Object.Destroy((Object)(object)_audioObject); } _audioObject = null; _rollingSound = (_steamSound = (_chuffSound = null)); _soundMixer = null; } internal static void ShutdownMovementAudio() { foreach (RailVehicle vehicle in Vehicles) { if (Object.op_Implicit((Object)(object)vehicle)) { vehicle._audioFailed = true; vehicle.CleanupMovementAudio(); } } RailAudioClips.Cleanup(); } internal void SetAutoDriveId(string identity) { if (Ready && _view.IsOwner()) { if (AttachedAutoDriveId != identity) { StopAutomaticDrive((identity.Length == 0) ? "Automatic controller detached." : "Automatic drive stopped. Use the controller to depart."); } _view.GetZDO().Set("vikingrail_autodrive_controller", identity); } } private void InitializeAutoDrive() { if (SupportsAutoDrive) { _view.Register("VR_AutoDrive", (Action)SetAutomaticDrive); _view.Register("VR_AutoDriveReply", (Action)AutoDriveReply); if (_view.IsOwner()) { ClearAutomaticDrive("Automatic drive stopped. Activate the controller to depart."); } } } private void UpdateAutoDrive() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) if (_view.IsOwner() && RailAutoDrive.WasDestroyed(AttachedAutoDriveId)) { SetAutoDriveId(""); _view.GetZDO().Set("vikingrail_autodrive_controller_zdo", ZDOID.None); StopAutomaticDrive("The automatic controller was destroyed."); } if (_autoRequestPending && Time.unscaledTime - _autoRequestTime > 6f) { _autoRequestPending = false; Tell(Player.m_localPlayer, "Controller request timed out. Check the lever's status before trying again."); } if (AutomaticDriveRequested && _view.IsOwner() && !AutoDriveActive) { StopAutomaticDrive("Automatic drive stopped after its owner or attachment changed. Activate it again when ready."); } } internal bool RequestAutoDriveToggle(Player player) { if (!Ready || !SupportsAutoDrive || _autoRequestPending || !_view.HasOwner() || !Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return false; } if (RemoteManaged || (RailSettings.RemoteSimulationEnabled && !AutomaticDriveRequested)) { return RailRemoteDrive.Request(this, player, !AutomaticDriveRequested); } _autoRequestPending = true; _autoRequestTime = Time.unscaledTime; _autoRequestOwner = _view.GetZDO().GetOwner(); _view.InvokeRPC("VR_AutoDrive", new object[2] { player.GetPlayerID(), !AutomaticDriveRequested }); return true; } private void SetAutomaticDrive(long sender, long playerId, bool start) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_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) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !_view.IsOwner() || !SupportsAutoDrive || !ValidRequester(sender, playerId, out Player player)) { return; } RailAutoDrive mountedAutoDrive = MountedAutoDrive; if (!Object.op_Implicit((Object)(object)mountedAutoDrive) || ((Character)player).IsTeleporting() || !RailWardAccess.Allows(((Component)this).transform.position, playerId) || !RailWardAccess.Allows(((Component)mountedAutoDrive).transform.position, playerId) || Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.TransformPoint(RailAutoDrive.SocketOffset)) > 4f) { _view.InvokeRPC(sender, "VR_AutoDriveReply", new object[1] { "Stand beside the attached controller with permission to use it." }); return; } if (!start) { StopAutomaticDrive("Automatic drive stopped by its controller."); _view.InvokeRPC(sender, "VR_AutoDriveReply", new object[1] { AutoDriveStatus }); return; } if (AutoDriveActive) { _view.InvokeRPC(sender, "VR_AutoDriveReply", new object[1] { "Automatic drive is already active." }); return; } string failure; List train; if (((Character)player).IsAttached() || player.GetDoodadController() != null) { failure = "Dismount before starting automatic drive."; } else if (ParentId.Length != 0) { failure = "Take controls on this engine first, then park, dismount and activate its controller."; } else if (!RailSettings.Ready || !AutoDriveAttachmentChangesAllowed) { failure = "Park the engine, dismount, and finish storage or coupling before starting automatic drive."; } else if (!TryCursor() || !HasCompatibleTrack()) { failure = "Place the whole engine on connected metal track."; } else if (AttachedPlowId.Length != 0 && !Object.op_Implicit((Object)(object)MountedPlow)) { failure = "Wait for the attached plow to load."; } else if (BuildTrain(out train, out failure)) { if (train.Any((RailVehicle v) => v.AttachedPlowId.Length != 0 && !Object.op_Implicit((Object)(object)v.MountedPlow))) { failure = "Wait for every attached plow to load."; } else if (train.Any((RailVehicle v) => v.CargoBusy || v.CargoServiceBusy || v.CouplingServiceBusy || v.MountServiceBusy)) { failure = "Close all train storage and finish attachment or coupling changes."; } else if (train.Any((RailVehicle v) => v.DriverId != 0L || Object.op_Implicit((Object)(object)v._driver) || v._pendingMount || v.AutomaticDriveRequested || (v.IsEngine && v.HasPassengers))) { failure = "Dismount every engine operator and stop all other automatic controllers first."; } else if (train.Any((RailVehicle v) => v.AttachedAutoDriveId.Length != 0 && !Object.op_Implicit((Object)(object)v.MountedAutoDrive))) { failure = "Wait for every attached automatic controller to load."; } else if (train.Any((RailVehicle v) => v.FuelPowered && !v.RefreshFuelInventory())) { failure = "Wait for every engine's fuel inventory and ownership to synchronize. Take the controls first if needed."; } else if (!ConsistHasFuel(0.05)) { failure = "Load " + FuelName + " into at least one matching engine's hopper first."; } else { failure = "Automatic drive active. Use the controller to stop. Runs only on loaded tracks."; ActivateAutomaticDrive(train, failure); } } ZDOMan.instance.ForceSendZDO(sender, Id); _view.InvokeRPC(sender, "VR_AutoDriveReply", new object[1] { failure }); } private void ActivateAutomaticDrive(List train, string reason) { ResetTrackStops(); foreach (RailStopMarker marker in RailSegment.StopMarkers) { if (!marker.IsBumper && train.Any((RailVehicle v) => v._cursor.HasValue && v._cursor.Value.SegmentId == marker.Cursor.SegmentId)) { _brakeBypass.Add(marker.Id); } } _serviceNeedsNeutral = false; _throttle = 0f; _brake = false; Speed = 0f; StopFollowerMotion(); ZDO zDO = _view.GetZDO(); zDO.Set("vikingrail_autodrive_owner", zDO.GetOwner()); zDO.Set("vikingrail_autodrive_owner_revision", (int)zDO.OwnerRevision); zDO.Set("vikingrail_autodrive_active", true); zDO.Set("vikingrail_autodrive_status", reason); Status = reason; } private void AutoDriveReply(long sender, string message) { if (_autoRequestPending && sender == _autoRequestOwner) { _autoRequestPending = false; Tell(Player.m_localPlayer, message); } } private void ClearAutomaticDrive(string reason) { if (SupportsAutoDrive && Ready && _view.IsOwner()) { ZDO zDO = _view.GetZDO(); bool flag = zDO.GetBool("vikingrail_autodrive_active", false); zDO.Set("vikingrail_autodrive_active", false); zDO.Set("vikingrail_autodrive_owner", 0L); zDO.Set("vikingrail_autodrive_owner_revision", -1); zDO.Set("vikingrail_autodrive_status", reason); if (flag) { RailSwitch.ReleaseTrainRoute(this); StopFollowerMotion(); } } } internal void StopAutomaticDrive(string reason) { if (Ready && _view.IsOwner()) { ClearAutomaticDrive(reason); Halt(reason); } } private void FollowAutomaticController() { RailAutoDrive mountedAutoDrive = MountedAutoDrive; if (Object.op_Implicit((Object)(object)mountedAutoDrive)) { mountedAutoDrive.Follow(this); } } private void InitializeBeamSmoothing() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) List list = new List(); Light[] railLights = _railLights; foreach (Light val in railLights) { if (Object.op_Implicit((Object)(object)val) && (int)val.type == 0 && ((Object)val).name == "vr_lamp_beam" && Object.op_Implicit((Object)(object)((Component)val).transform.parent)) { list.Add(new BeamAim(val)); } } _beamAims = list.ToArray(); } private void UpdateBeamSmoothing() { //IL_0088: 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_00c1: 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_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: 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_0136: 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_012f: 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_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) float num = (float)RailLightingMath.SmoothFactor(Time.deltaTime, 0.06); BeamAim[] beamAims = _beamAims; foreach (BeamAim beamAim in beamAims) { if (Object.op_Implicit((Object)(object)beamAim.Light) && Object.op_Implicit((Object)(object)beamAim.Transform)) { if (!Ready || !((Behaviour)beamAim.Light).enabled || !((Component)beamAim.Light).gameObject.activeInHierarchy || !Object.op_Implicit((Object)(object)beamAim.Transform.parent)) { beamAim.Transform.localRotation = beamAim.RestLocalRotation; beamAim.HasPose = false; beamAim.LastFrame = Time.frameCount; continue; } Vector3 position = beamAim.Transform.position; Quaternion val = beamAim.Transform.parent.rotation * beamAim.RestLocalRotation; bool flag = !beamAim.HasPose || Time.frameCount > beamAim.LastFrame + 1 || (double)Vector3.Distance(position, beamAim.LastPosition) > 5.0 || (double)Quaternion.Angle(beamAim.WorldRotation, val) > 45.0; beamAim.WorldRotation = (flag ? val : Quaternion.Slerp(beamAim.WorldRotation, val, num)); beamAim.Transform.rotation = beamAim.WorldRotation; beamAim.LastPosition = position; beamAim.LastFrame = Time.frameCount; beamAim.HasPose = true; } } } internal void MarkCargoOrigin(string token) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (Ready && _view.IsOwner() && FindRoot(out RailVehicle root) && !(root.CargoToken != token)) { _view.GetZDO().Set("vikingrail_cargo_origin", root.Id); _view.GetZDO().Set("vikingrail_cargo_origin_token", token); _view.GetZDO().Set("vikingrail_cargo_origin_identity", root.PersistentId); } } private void InitializeCargoAccess() { if (Ready) { _view.Register("VR_CargoReserve", (Action)ReserveCargo); _view.Register("VR_CargoReply", (Method)CargoReply); _view.Register("VR_CargoRenew", (Action)RenewCargo); _view.Register("VR_CargoEnd", (Action)EndCargo); _view.Register("VR_CargoSeal", (Action)SealCargo); _view.Register("VR_CargoSnapshot", (Action)ReceiveCargoSnapshot); if (Object.op_Implicit((Object)(object)_container)) { RailCargoInventory.Ensure(_container); } } } internal bool TryCargoRoot(out RailVehicle root) { return FindRoot(out root); } private bool CargoChain(out List train) { return ReadCouplingChain(this, out train); } internal bool CanRequestCargo(Player player, out string reason) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) reason = "Stop the train before opening storage."; if (!CargoStationary || !FindRoot(out RailVehicle root)) { return false; } if (CouplingServiceBusy || root.CouplingServiceBusy) { reason = "Wait for the coupling operation to finish."; return false; } if (HasCargoOrigin && _view.GetZDO().GetZDOID("vikingrail_cargo_origin") != root.Id) { reason = "Wait for storage to return to its previous train."; return false; } if (IsEngine && root.DriverId != 0L && _view.GetZDO().GetOwner() != ((Character)player).GetOwner()) { reason = "The occupied engine's fuel hopper cannot transfer owners. Its driver must dismount first."; return false; } reason = ""; return true; } internal void RequestCargoAccess(long playerId, string token) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (Ready && FindRoot(out RailVehicle root)) { root._view.InvokeRPC("VR_CargoReserve", new object[3] { playerId, Id, token }); } } internal bool CargoGrantMatches(long peer, long playerId, string token) { if (!Ready || token.Length != 32 || !FindRoot(out RailVehicle root) || !root.Ready) { return false; } root.AdoptLocalCargoAuthority(this); ZDO zDO = root._view.GetZDO(); if (root.CargoToken == token && zDO.GetString("vikingrail_cargo_cart", "") == PersistentId && zDO.GetLong("vikingrail_cargo_peer", 0L) == peer && zDO.GetLong("vikingrail_cargo_player", 0L) == playerId && zDO.GetInt("vikingrail_cargo_phase", 0) == 1 && zDO.GetLong("vikingrail_cargo_until", 0L) > CargoNow && zDO.GetLong("vikingrail_cargo_authority", 0L) == zDO.GetOwner()) { return zDO.GetInt("vikingrail_cargo_authority_revision", -1) == zDO.OwnerRevision; } return false; } internal bool CargoTokenMatches(string token) { if (Ready && FindRoot(out RailVehicle root) && root.CargoToken == token) { return root._view.GetZDO().GetString("vikingrail_cargo_cart", "") == PersistentId; } return false; } internal void RenewCargoAccess(string token) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) if (Ready && FindRoot(out RailVehicle root)) { root._view.InvokeRPC("VR_CargoRenew", new object[2] { Id, token }); } } internal void EndCargoAccess(string token, RailVehicle? authority = null) { //IL_0060: 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) if (Ready) { RailVehicle root; if (Object.op_Implicit((Object)(object)authority) && authority.Ready) { authority._view.InvokeRPC("VR_CargoEnd", new object[2] { Id, token }); } else if (FindRoot(out root)) { root._view.InvokeRPC("VR_CargoEnd", new object[2] { Id, token }); } } } private void ReserveCargo(long sender, long playerId, ZDOID cartId, string token) { //IL_004f: 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_0120: 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_0269: 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_0296: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !_view.IsOwner() || token == null || token.Length != 32 || !Guid.TryParseExact(token, "N", out var _)) { return; } RailVehicle railVehicle = FindSession(cartId); string reason = "Stop the train and wait for its storage to become available."; if (!Object.op_Implicit((Object)(object)railVehicle) || !Object.op_Implicit((Object)(object)railVehicle._container) || !railVehicle.FindRoot(out RailVehicle root) || !((Object)(object)root == (Object)(object)this) || !CargoChain(out List train) || !train.Contains(railVehicle) || !RailCargoInventory.ValidRequester(railVehicle._container, sender, playerId, out Player player) || !railVehicle.CanRequestCargo(player, out reason)) { _view.InvokeRPC(sender, "VR_CargoReply", new object[4] { cartId, token, false, reason }); return; } if (CargoToken.Length != 0) { bool flag = railVehicle.CargoGrantMatches(sender, playerId, token); _view.InvokeRPC(sender, "VR_CargoReply", new object[4] { cartId, token, flag, flag ? "" : "Another storage operation is still open or returning its inventory." }); return; } if (!CargoChain(out List train2) || train2.Exists((RailVehicle v) => v.CouplingServiceBusy || v.MountServiceBusy || v.CargoBusy || v.HasCargoOrigin || RailCargoInventory.HasConflictingPending(v, token))) { _view.InvokeRPC(sender, "VR_CargoReply", new object[4] { cartId, token, false, "Close other storage and wait for coupling to finish." }); return; } ZDO zDO = _view.GetZDO(); zDO.Set("vikingrail_cargo_token", token); zDO.Set("vikingrail_cargo_cart", railVehicle.PersistentId); zDO.Set("vikingrail_cargo_peer", sender); zDO.Set("vikingrail_cargo_player", playerId); zDO.Set("vikingrail_cargo_until", CargoNow + 10000); zDO.Set("vikingrail_cargo_phase", 1); zDO.Set("vikingrail_cargo_authority", zDO.GetOwner()); zDO.Set("vikingrail_cargo_authority_revision", (int)zDO.OwnerRevision); _cargoSnapshotDigest = ""; _serviceNeedsNeutral = true; Halt("Storage access reserved. Close storage before moving."); ZDOMan.instance.ForceSendZDO(sender, Id); long owner = railVehicle._view.GetZDO().GetOwner(); if (owner != 0L && owner != sender) { ZDOMan.instance.ForceSendZDO(owner, Id); } _view.InvokeRPC(sender, "VR_CargoReply", new object[4] { cartId, token, true, "" }); } private void CargoReply(long sender, ZDOID cartId, string token, bool granted, string reason) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (Ready && sender == _view.GetZDO().GetOwner()) { RailVehicle railVehicle = FindSession(cartId); if (Object.op_Implicit((Object)(object)railVehicle) && Object.op_Implicit((Object)(object)railVehicle._container)) { RailCargoInventory.LeaseReply(railVehicle._container, this, sender, token, granted, reason); } } } private bool CargoMessageMatches(long sender, ZDOID cartId, string token, out RailVehicle cart) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) cart = FindSession(cartId); if (Ready && _view.IsOwner() && Object.op_Implicit((Object)(object)cart) && token.Length == 32 && CargoToken == token && _view.GetZDO().GetString("vikingrail_cargo_cart", "") == cart.PersistentId) { return _view.GetZDO().GetLong("vikingrail_cargo_peer", 0L) == sender; } return false; } private void RenewCargo(long sender, ZDOID cartId, string token) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) if (CargoMessageMatches(sender, cartId, token, out RailVehicle cart)) { ZDO zDO = _view.GetZDO(); if (!cart.CargoGrantMatches(sender, zDO.GetLong("vikingrail_cargo_player", 0L), token) || !cart.CargoStationary || !RailCargoInventory.ValidRequester(cart._container, sender, zDO.GetLong("vikingrail_cargo_player", 0L), out Player _)) { CloseCargoLease(); } else { zDO.Set("vikingrail_cargo_until", CargoNow + 10000); } } } private void EndCargo(long sender, ZDOID cartId, string token) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) if (CargoMessageMatches(sender, cartId, token, out RailVehicle _)) { CloseCargoLease(); } } private void CloseCargoLease() { if (Ready && _view.IsOwner() && CargoToken.Length != 0) { _view.GetZDO().Set("vikingrail_cargo_phase", 2); _serviceNeedsNeutral = true; _nextCargoSeal = 0f; Halt("Waiting for storage to close and return its saved inventory."); } } private void SealCargo(long sender, ZDOID rootId, string token) { //IL_0000: 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_00d1: Expected O, but got Unknown //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) RailVehicle railVehicle = FindSession(rootId); if (Ready && _view.IsOwner() && Object.op_Implicit((Object)(object)_container) && Object.op_Implicit((Object)(object)railVehicle) && railVehicle.Ready && sender == railVehicle._view.GetZDO().GetOwner() && token.Length == 32 && !(railVehicle.CargoToken != token) && !(railVehicle._view.GetZDO().GetString("vikingrail_cargo_cart", "") != PersistentId)) { RailCargoInventory.Seal(_container, token); if (!_container.IsInUse() && _view.GetZDO().GetInt("InUse", 0) != 1) { ZDO zDO = _view.GetZDO(); ZPackage val = new ZPackage(); val.Write(token); val.Write(Id); val.Write((int)zDO.OwnerRevision); val.Write((long)zDO.DataRevision); val.Write(RailCargoInventory.InventoryDigest(zDO)); ZDOMan.instance.ForceSendZDO(sender, Id); railVehicle._view.InvokeRPC(sender, "VR_CargoSnapshot", new object[1] { val }); } } } private void ReceiveCargoSnapshot(long sender, ZPackage package) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !_view.IsOwner() || package == null || package.Size() > 256 || CargoToken.Length == 0) { return; } try { string text = package.ReadString(); RailVehicle railVehicle = FindSession(package.ReadZDOID()); int num = package.ReadInt(); long num2 = package.ReadLong(); string text2 = package.ReadString(); if (package.GetPos() == package.Size() && !(text != CargoToken) && Object.op_Implicit((Object)(object)railVehicle) && _view.GetZDO().GetInt("vikingrail_cargo_phase", 0) == 2 && !(_view.GetZDO().GetString("vikingrail_cargo_cart", "") != railVehicle.PersistentId) && railVehicle._view.GetZDO().GetOwner() == sender && num >= 0 && num <= 65535 && num2 >= 0 && num2 <= uint.MaxValue && text2.Length == 64) { _cargoSnapshotPeer = sender; _cargoSnapshotOwnerRevision = num; _cargoSnapshotDataRevision = (uint)num2; _cargoSnapshotDigest = text2; } } catch (Exception ex) { RailPlugin.Warn("Ignored an invalid cargo-return acknowledgment: " + ex.GetBaseException().Message); } } private void UpdateCargoAccess() { //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02df: 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) if (!Ready || !_view.IsOwner() || CargoToken.Length == 0) { return; } ZDO zDO = _view.GetZDO(); RailVehicle railVehicle = Find(zDO.GetString("vikingrail_cargo_cart", "")); if (!Object.op_Implicit((Object)(object)railVehicle) || !Object.op_Implicit((Object)(object)railVehicle._container)) { Halt("Waiting for the reserved storage wagon to load."); return; } long peer = zDO.GetLong("vikingrail_cargo_peer", 0L); long num = zDO.GetLong("vikingrail_cargo_player", 0L); AdoptLocalCargoAuthority(railVehicle); if (zDO.GetInt("vikingrail_cargo_phase", 0) == 1 && (zDO.GetLong("vikingrail_cargo_until", 0L) <= CargoNow || zDO.GetLong("vikingrail_cargo_authority", 0L) != zDO.GetOwner() || zDO.GetInt("vikingrail_cargo_authority_revision", -1) != zDO.OwnerRevision || !railVehicle.CargoStationary || !railVehicle.FindRoot(out RailVehicle root) || (Object)(object)root != (Object)(object)this || !RailCargoInventory.ValidRequester(railVehicle._container, peer, num, out Player _))) { CloseCargoLease(); } if (zDO.GetInt("vikingrail_cargo_phase", 0) != 2) { return; } ZDO zDO2 = railVehicle._view.GetZDO(); if (_cargoSnapshotDigest.Length != 0 && RailCargoSnapshot.CanAdopt(_cargoSnapshotPeer, zDO2.GetOwner(), _cargoSnapshotOwnerRevision, zDO2.OwnerRevision, _cargoSnapshotDataRevision, zDO2.DataRevision, _cargoSnapshotDigest, RailCargoInventory.InventoryDigest(zDO2), railVehicle._container.IsInUse() || zDO2.GetInt("InUse", 0) == 1)) { if (!RailCargoInventory.TryRefresh(railVehicle._container, out string error, requireOwner: false)) { Halt(error); return; } if (!railVehicle._view.IsOwner()) { railVehicle._view.ClaimOwnership(); } if (railVehicle._view.IsOwner()) { if (!RailCargoInventory.TryRefresh(railVehicle._container, out error)) { Halt(error); return; } zDO.Set("vikingrail_cargo_token", ""); zDO.Set("vikingrail_cargo_cart", ""); zDO.Set("vikingrail_cargo_phase", 0); zDO.Set("vikingrail_cargo_until", 0L); zDO2.Set("vikingrail_cargo_origin_token", ""); zDO2.Set("vikingrail_cargo_origin", ZDOID.None); zDO2.Set("vikingrail_cargo_origin_identity", ""); _cargoSnapshotDigest = ""; _serviceNeedsNeutral = true; } } else if (!(Time.unscaledTime < _nextCargoSeal)) { _nextCargoSeal = Time.unscaledTime + 0.5f; if (!railVehicle._view.HasOwner() && !Object.op_Implicit((Object)(object)Player.GetPlayer(num))) { railVehicle._view.ClaimOwnership(); } ZDOMan.instance.ForceSendZDO(zDO2.GetOwner(), Id); railVehicle._view.InvokeRPC("VR_CargoSeal", new object[2] { Id, CargoToken }); } } private bool CargoAccessBlocksMovement(List train) { foreach (RailVehicle item in train) { if (item.CargoServiceBusy || item.CargoBusy) { return true; } } return false; } private void AdoptLocalCargoAuthority(RailVehicle cart) { if (Ready && _view.IsOwner() && !((Object)(object)cart != (Object)(object)this) && DriverId == 0L && CargoToken.Length != 0) { ZDO zDO = _view.GetZDO(); long num = zDO.GetLong("vikingrail_cargo_peer", 0L); if (zDO.GetOwner() == num && zDO.GetInt("vikingrail_cargo_phase", 0) == 1 && RailCargoInventory.HasLocalLease(this, CargoToken)) { zDO.Set("vikingrail_cargo_authority", num); zDO.Set("vikingrail_cargo_authority_revision", (int)zDO.OwnerRevision); } } } private void CargoTargetDestroyed(string persistentId) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !_view.IsOwner()) { return; } ZDO zDO = _view.GetZDO(); if (zDO.GetString("vikingrail_cargo_origin_identity", "") == persistentId) { if (Object.op_Implicit((Object)(object)_container)) { RailCargoInventory.Seal(_container, zDO.GetString("vikingrail_cargo_origin_token", "")); } zDO.Set("vikingrail_cargo_origin", ZDOID.None); zDO.Set("vikingrail_cargo_origin_token", ""); zDO.Set("vikingrail_cargo_origin_identity", ""); _serviceNeedsNeutral = true; } if (CargoToken.Length != 0 && !(zDO.GetString("vikingrail_cargo_cart", "") != persistentId)) { zDO.Set("vikingrail_cargo_token", ""); zDO.Set("vikingrail_cargo_cart", ""); zDO.Set("vikingrail_cargo_phase", 0); zDO.Set("vikingrail_cargo_until", 0L); _cargoSnapshotDigest = ""; _serviceNeedsNeutral = true; Halt("The reserved storage wagon was destroyed."); } } private void InitializeConsistDrive() { _view.Register("VR_ConsistDrive", (Action)RequestConsistDrive); _view.Register("VR_ConsistDriveYield", (Action)RequestConsistDriveYield); _view.Register("VR_ConsistDriveYieldReply", (Method)ConsistDriveYieldReply); } private bool BeginConsistDrive(Player player) { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) if (!Ready || _pendingMount || !Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer || !FindRoot(out RailVehicle root) || !root._view.HasOwner()) { return false; } if (!root.ValidateConsistDrive(((Character)player).GetOwner(), player.GetPlayerID(), this, "", out List _, out List _, out string reason)) { Tell(player, reason); return false; } _pendingMount = true; _mountGranted = false; _requestTime = Time.time; _requestOwner = root._view.GetZDO().GetOwner(); _consistMountRequestRoot = root.Id; root._view.InvokeRPC(_requestOwner, "VR_ConsistDrive", new object[2] { player.GetPlayerID(), Id }); return false; } private bool ValidateConsistDrive(long peer, long playerId, RailVehicle cab, string token, out List train, out List members, out string reason) { //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Unknown result type (might be due to invalid IL or missing references) //IL_036e: Unknown result type (might be due to invalid IL or missing references) train = new List(); members = new List(); reason = "Park the entire train, close storage, and release its other engine controls first."; if (!Ready || !RailSettings.Ready || !Object.op_Implicit((Object)(object)ZNet.instance) || ZDOMan.instance == null || !Object.op_Implicit((Object)(object)cab) || !cab.Ready || !cab.IsEngine || !cab.FuelPowered || !cab.ValidRequester(peer, playerId, out Player player) || ((Character)player).IsTeleporting() || ((Character)player).IsAttached() || player.GetDoodadController() != null || ((Character)player).InPlaceMode() || !cab.FindRoot(out RailVehicle root) || (Object)(object)root != (Object)(object)this || !ReadCouplingChain(this, out train) || !train.Contains(cab) || train.Count > 128 || !RailWardAccess.Allows(cab.GetPosition(), playerId)) { return false; } if (train.Count((RailVehicle c) => c.IsEngine) > 21) { reason = "This train has too many engines. Uncouple an engine before taking the controls."; return false; } if (train.Any((RailVehicle c) => c.IsEngine && !MultiEngineCompatible(cab, c))) { reason = "Only matching powered engines can share this train's controls."; return false; } if (ConsistDriveBusy && (token.Length == 0 || _view.GetZDO().GetString("vikingrail_drive_prepare_token", "") != token)) { return false; } foreach (RailVehicle item in train) { if (!item.Ready || item.DriverId != 0L || Object.op_Implicit((Object)(object)item._driver) || item.AutomaticDriveRequested || item._packing || item._packPending || (item._pendingMount && (Object)(object)item != (Object)(object)cab) || (item.IsEngine && item.HasPassengers) || item.CargoBusy || item.CargoServiceBusy || item.MountServiceBusy || RailCargoInventory.HasPending(item) || item._couplingOperation != null || item.HasCouplingLease || item._contactCouplingClient != null || RailTurntable.BlocksVehicle(item) || RailRemoteDrive.IsPreparing(item) || !item.TryCursor() || !item.HasCompatibleTrack() || !RailWardAccess.Allows(((Component)item).transform.position, playerId)) { return false; } if (item._view.IsOwner() ? (Mathf.Abs(item.Speed) > 0.0001f) : (item._view.GetZDO().GetLong("vikingrail_moving_until", 0L) > CouplingNow)) { return false; } if (item.HasConsistDriveLease && (token.Length == 0 || item._view.GetZDO().GetString("vikingrail_drive_prepare_token", "") != token)) { return false; } members.Add(new ConsistDriveMember { Cart = item, View = item._view, Id = item.Id, PreviousOwner = item._view.GetZDO().GetOwner() }); if (item.AttachedPlowId.Length != 0) { RailPlow mountedPlow = item.MountedPlow; if (!Object.op_Implicit((Object)(object)mountedPlow) || !AddConsistDriveMember(members, item, mountedPlow.View, playerId)) { reason = "Wait for every attached plow to load."; return false; } } if (item.AttachedAutoDriveId.Length != 0) { RailAutoDrive mountedAutoDrive = item.MountedAutoDrive; if (!Object.op_Implicit((Object)(object)mountedAutoDrive) || !mountedAutoDrive.IsReady || !AddConsistDriveMember(members, item, mountedAutoDrive.View, playerId)) { reason = "Wait for every attached automatic controller to load."; return false; } } } if (!TryFormation(train, out Dictionary _, out Dictionary _) || members.Any((ConsistDriveMember m) => !m.View.HasOwner()) || members.Select((ConsistDriveMember m) => m.Id).Distinct().Count() != members.Count) { return false; } reason = ""; return true; } private static bool AddConsistDriveMember(List members, RailVehicle cart, ZNetView view, long playerId) { //IL_0016: 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_004a: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)view) || !view.IsValid() || !RailWardAccess.Allows(((Component)view).transform.position, playerId)) { return false; } members.Add(new ConsistDriveMember { Cart = cart, View = view, Id = view.GetZDO().m_uid, PreviousOwner = view.GetZDO().GetOwner() }); return true; } private void RequestConsistDrive(long sender, long playerId, ZDOID cabId) { //IL_0016: 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_01b2: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !_view.IsOwner()) { return; } RailVehicle railVehicle = FindSession(cabId); if (!Object.op_Implicit((Object)(object)railVehicle)) { return; } if (!ValidateConsistDrive(sender, playerId, railVehicle, "", out List train, out List members, out string _)) { railVehicle._view.InvokeRPC(sender, "VR_DriveResponse", new object[1] { false }); return; } ConsistDriveOperation consistDriveOperation = new ConsistDriveOperation { Token = Guid.NewGuid().ToString("N"), Peer = sender, Player = playerId, Owner = _view.GetZDO().GetOwner(), OwnerRevision = _view.GetZDO().OwnerRevision, Cab = cabId, Expires = Time.unscaledTime + 8f }; consistDriveOperation.Members.AddRange(members); foreach (RailVehicle item in train) { consistDriveOperation.Carts.Add(new ConsistDriveCart { Cart = item, Parent = item.ParentId, Next = item.NextId, Front = item.FrontId, ParentFront = item.ParentFront, Plow = item.AttachedPlowId, PlowFront = item.MountedPlowFront, Controller = item.AttachedAutoDriveId }); } _consistDriveOperation = consistDriveOperation; WriteConsistDriveLease(this, consistDriveOperation.Token, CouplingNow + 8000); ZDO zDO = _view.GetZDO(); zDO.Set("vikingrail_drive_prepare_cab", cabId); zDO.Set("vikingrail_drive_prepare_player", playerId); zDO.Set("vikingrail_drive_prepare_peer", sender); zDO.Set("vikingrail_drive_prepare_owner", consistDriveOperation.Owner); zDO.Set("vikingrail_drive_prepare_revision", (int)consistDriveOperation.OwnerRevision); UpdateConsistDrive(); } private void WriteConsistDriveLease(RailVehicle root, string token, long until) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) ZDO zDO = _view.GetZDO(); zDO.Set("vikingrail_drive_prepare_root", root.Id); zDO.Set("vikingrail_drive_prepare_token", token); zDO.Set("vikingrail_drive_prepare_until", until); } private void UpdateConsistDrive() { //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_009d: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) if (!_pendingMount) { _consistMountRequestRoot = ZDOID.None; } ConsistDriveOperation operation = _consistDriveOperation; if (operation == null) { return; } if (!Ready || !_view.IsOwner() || _view.GetZDO().GetOwner() != operation.Owner || _view.GetZDO().OwnerRevision != operation.OwnerRevision || Time.unscaledTime >= operation.Expires) { FinishConsistDrive(granted: false); return; } RailVehicle railVehicle = FindSession(operation.Cab); if (!Object.op_Implicit((Object)(object)railVehicle) || !ValidateConsistDrive(operation.Peer, operation.Player, railVehicle, operation.Token, out List train, out List members, out string reason) || members.Count != operation.Members.Count || members.Any((ConsistDriveMember m) => !operation.Members.Any((ConsistDriveMember old) => old.Id == m.Id && (Object)(object)old.Cart == (Object)(object)m.Cart && (Object)(object)old.View == (Object)(object)m.View)) || train.Count != operation.Carts.Count || operation.Carts.Any((ConsistDriveCart s) => !Object.op_Implicit((Object)(object)s.Cart) || !train.Contains(s.Cart) || s.Cart.ParentId != s.Parent || s.Cart.NextId != s.Next || s.Cart.FrontId != s.Front || s.Cart.ParentFront != s.ParentFront || s.Cart.AttachedPlowId != s.Plow || s.Cart.MountedPlowFront != s.PlowFront || s.Cart.AttachedAutoDriveId != s.Controller)) { FinishConsistDrive(granted: false); return; } bool flag = true; bool flag2 = Time.unscaledTime >= operation.NextRequest; if (flag2) { operation.NextRequest = Time.unscaledTime + 0.4f; } foreach (ConsistDriveMember member in operation.Members) { if (member.PreviousOwner == operation.Owner) { if (!member.View.IsOwner()) { FinishConsistDrive(granted: false); return; } if (member.Stamp < 0) { if (member.Cart._view.IsOwner()) { member.Cart.WriteConsistDriveLease(this, operation.Token, _view.GetZDO().GetLong("vikingrail_drive_prepare_until", 0L)); } Container component = ((Component)member.View).GetComponent(); if (Object.op_Implicit((Object)(object)component) && !RailCargoInventory.TryRefreshForOwnership(component, out reason)) { FinishConsistDrive(granted: false); return; } member.Digest = RailCargoInventory.InventoryDigest(member.View.GetZDO()); member.Stamp = CouplingStamp(member.View.GetZDO()); } } else if (member.Stamp < 0) { flag = false; if (flag2) { ZDOMan.instance.ForceSendZDO(member.PreviousOwner, Id); member.Cart._view.InvokeRPC(member.PreviousOwner, "VR_ConsistDriveYield", new object[3] { Id, operation.Token, member.Id }); } continue; } ZDO zDO = member.View.GetZDO(); if (!member.View.IsOwner() || zDO.OwnerRevision != (ushort)(member.Stamp >> 32) || zDO.DataRevision < (uint)member.Stamp || RailCargoInventory.InventoryDigest(zDO) != member.Digest) { flag = false; continue; } Container component2 = ((Component)member.View).GetComponent(); if (!Object.op_Implicit((Object)(object)component2) || RailCargoInventory.TryRefreshForOwnership(component2, out reason)) { continue; } FinishConsistDrive(granted: false); return; } if (!flag) { return; } foreach (RailVehicle item in train) { item.SaveCursor(item._cursor.Value, RailVehiclePose.Sample(RailSegment.Network, item._cursor.Value)); } if (!TryRerootTrain(railVehicle, train, out reason)) { FinishConsistDrive(granted: false); return; } railVehicle._view.GetZDO().Set("vikingrail_driver", operation.Player); railVehicle._orphanTimer = 0f; FinishConsistDrive(granted: true); } private void RequestConsistDriveYield(long sender, ZDOID rootId, string token, ZDOID memberId) { //IL_0007: 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_002b: 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_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) if (!Ready || token == null || token.Length != 32) { return; } RailVehicle railVehicle = FindSession(rootId); if (!Object.op_Implicit((Object)(object)railVehicle) || !railVehicle.HasConsistDriveLease || railVehicle._view.GetZDO().GetOwner() != sender) { return; } ZDO zDO = railVehicle._view.GetZDO(); if (zDO.GetString("vikingrail_drive_prepare_token", "") != token || zDO.GetLong("vikingrail_drive_prepare_owner", 0L) != sender || zDO.GetInt("vikingrail_drive_prepare_revision", -1) != zDO.OwnerRevision) { return; } RailVehicle railVehicle2 = FindSession(zDO.GetZDOID("vikingrail_drive_prepare_cab")); if (!Object.op_Implicit((Object)(object)railVehicle2) || !railVehicle.ValidateConsistDrive(zDO.GetLong("vikingrail_drive_prepare_peer", 0L), zDO.GetLong("vikingrail_drive_prepare_player", 0L), railVehicle2, token, out List _, out List members, out string error)) { return; } ConsistDriveMember consistDriveMember = members.Find((ConsistDriveMember m) => m.Id == memberId && (Object)(object)m.Cart == (Object)(object)this); if (consistDriveMember == null || !consistDriveMember.View.IsOwner()) { return; } Container component = ((Component)consistDriveMember.View).GetComponent(); if (Object.op_Implicit((Object)(object)component) && !RailCargoInventory.TryRefresh(component, out error)) { railVehicle._view.InvokeRPC(sender, "VR_ConsistDriveYieldReply", new object[4] { token, memberId, -1L, "" }); return; } if (_view.IsOwner()) { WriteConsistDriveLease(railVehicle, token, zDO.GetLong("vikingrail_drive_prepare_until", 0L)); if (TryCursor()) { SaveCursor(_cursor.Value, RailVehiclePose.Sample(RailSegment.Network, _cursor.Value)); } } string text = RailCargoInventory.InventoryDigest(consistDriveMember.View.GetZDO()); consistDriveMember.View.GetZDO().SetOwner(sender); long num = CouplingStamp(consistDriveMember.View.GetZDO()); ZDOMan.instance.ForceSendZDO(sender, memberId); railVehicle._view.InvokeRPC(sender, "VR_ConsistDriveYieldReply", new object[4] { token, memberId, num, text }); } private void ConsistDriveYieldReply(long sender, string token, ZDOID memberId, long stamp, string digest) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) ConsistDriveOperation consistDriveOperation = _consistDriveOperation; if (consistDriveOperation == null || !Ready || !_view.IsOwner() || consistDriveOperation.Token != token) { return; } ConsistDriveMember consistDriveMember = consistDriveOperation.Members.Find((ConsistDriveMember m) => m.Id == memberId && m.PreviousOwner == sender); if (consistDriveMember != null && consistDriveMember.Stamp < 0) { if (stamp < 0 || stamp >> 48 != 0L || digest == null || digest.Length != 64) { FinishConsistDrive(granted: false); return; } consistDriveMember.Stamp = stamp; consistDriveMember.Digest = digest; } } private void FinishConsistDrive(bool granted) { //IL_01a9: 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_0185: Unknown result type (might be due to invalid IL or missing references) ConsistDriveOperation consistDriveOperation = _consistDriveOperation; if (consistDriveOperation == null) { return; } _consistDriveOperation = null; foreach (ConsistDriveCart cart2 in consistDriveOperation.Carts) { RailVehicle cart = cart2.Cart; if (Object.op_Implicit((Object)(object)cart) && cart.Ready && cart._view.IsOwner() && !(cart._view.GetZDO().GetString("vikingrail_drive_prepare_token", "") != consistDriveOperation.Token)) { cart._view.GetZDO().Set("vikingrail_drive_prepare_until", 0L); cart._view.GetZDO().Set("vikingrail_drive_prepare_token", ""); } } if (granted) { foreach (ConsistDriveMember member in consistDriveOperation.Members) { member.View.GetZDO().SetOwner(consistDriveOperation.Peer); ZDOMan.instance.ForceSendZDO(consistDriveOperation.Peer, member.Id); } } else if (ZDOMan.instance != null) { foreach (ConsistDriveCart cart3 in consistDriveOperation.Carts) { if (Object.op_Implicit((Object)(object)cart3.Cart) && cart3.Cart.Ready && cart3.Cart._view.IsOwner()) { ZDOMan.instance.ForceSendZDO(consistDriveOperation.Peer, cart3.Cart.Id); } } } RailVehicle railVehicle = FindSession(consistDriveOperation.Cab); if (Object.op_Implicit((Object)(object)railVehicle) && railVehicle.Ready) { railVehicle._view.InvokeRPC(consistDriveOperation.Peer, "VR_DriveResponse", new object[1] { granted }); } } private bool BurnConsistFuel(List suppliers, double seconds) { if (suppliers.Count == 0 || suppliers.Count > 21 || suppliers.Distinct().Count() != suppliers.Count || suppliers.Any((RailVehicle railVehicle) => !Object.op_Implicit((Object)(object)railVehicle) || !railVehicle.Ready || !railVehicle._view.IsOwner() || !Object.op_Implicit((Object)(object)railVehicle._container) || railVehicle.CargoBusy || !MultiEngineCompatible(this, railVehicle))) { return false; } if (suppliers.Count == 1) { return suppliers[0].BurnFuelFor(seconds); } List list = new List(); foreach (RailVehicle supplier in suppliers) { FuelPlan plan = FuelBudget.Plan(supplier.FuelSeconds, supplier.FuelCount, seconds, supplier.SecondsPerFuelItem); if (!plan.CanPower) { return false; } list.Add(new ConsistFuelDebit { Engine = supplier, Plan = plan, PreviousCredit = supplier._view.GetZDO().GetLong("vikingrail_fuel_seconds_bits", 0L) }); } if (list.Any((ConsistFuelDebit d) => d.Plan.ItemsToConsume > 0) && (ConsistContainerLoading?.FieldType != typeof(bool) || ConsistInventoryWeight?.FieldType != typeof(float) || ConsistContainerSave == null)) { return false; } try { foreach (ConsistFuelDebit item in list.Where((ConsistFuelDebit d) => d.Plan.ItemsToConsume > 0)) { Container container = item.Engine._container; Inventory inventory = container.GetInventory(); item.Loading = (bool)ConsistContainerLoading.GetValue(container); if (item.Loading) { throw new InvalidOperationException("An engine hopper is already loading."); } ItemData[] items = (from item in inventory.GetAllItems() select item.Clone()).ToArray(); item.Weight = inventory.GetTotalWeight(); ZDO zDO = item.Engine._view.GetZDO(); item.SavedItems = zDO.GetString(ZDOVars.s_items, ""); byte[] byteArray = zDO.GetByteArray(ZDOVars.s_items, (byte[])null); item.SavedBytes = ((byteArray == null) ? null : ((byte[])byteArray.Clone())); item.Items = items; } foreach (ConsistFuelDebit item2 in list.Where((ConsistFuelDebit d) => d.Items != null)) { ConsistContainerLoading.SetValue(item2.Engine._container, true); } foreach (ConsistFuelDebit item3 in list.Where((ConsistFuelDebit d) => d.Items != null)) { RailVehicle engine = item3.Engine; Inventory inventory2 = engine._container.GetInventory(); int num = item3.Plan.ItemsToConsume; ItemData[] array = inventory2.GetAllItems().Where(engine.IsFuel).ToArray(); foreach (ItemData val in array) { if (num == 0) { break; } int num3 = Math.Min(num, val.m_stack); if (!inventory2.RemoveItem(val, num3)) { throw new InvalidOperationException("A fuel stack changed during payment."); } num -= num3; } if (num != 0) { throw new InvalidOperationException("An engine's fuel changed during payment."); } } foreach (ConsistFuelDebit item4 in list) { item4.Engine._view.GetZDO().Set("vikingrail_fuel_seconds_bits", BitConverter.DoubleToInt64Bits(item4.Plan.RemainingSeconds)); } foreach (ConsistFuelDebit item5 in list.Where((ConsistFuelDebit d) => d.Items != null)) { ConsistContainerSave.Invoke(item5.Engine._container, null); } return true; } catch (Exception ex) { foreach (ConsistFuelDebit item6 in list) { RailVehicle engine2 = item6.Engine; if (!engine2.Ready || !engine2._view.IsOwner()) { continue; } engine2._view.GetZDO().Set("vikingrail_fuel_seconds_bits", item6.PreviousCredit); if (item6.Items == null) { continue; } Inventory inventory3 = engine2._container.GetInventory(); inventory3.GetAllItems().Clear(); inventory3.GetAllItems().AddRange(item6.Items); ConsistInventoryWeight.SetValue(inventory3, item6.Weight); try { ConsistContainerSave.Invoke(engine2._container, null); } catch { } finally { ZDO zDO2 = engine2._view.GetZDO(); zDO2.Set(ZDOVars.s_items, item6.SavedItems); if (item6.SavedBytes != null) { zDO2.Set(ZDOVars.s_items, item6.SavedBytes); } else { zDO2.RemoveByteArray(ZDOVars.s_items); } } } RailPlugin.Warn("Train fuel payment failed; movement was stopped and fuel restored. " + ex.GetBaseException().Message); return false; } finally { foreach (ConsistFuelDebit item7 in list.Where((ConsistFuelDebit d) => d.Items != null)) { ConsistContainerLoading.SetValue(item7.Engine._container, item7.Loading); } } } private static bool MultiEngineCompatible(RailVehicle first, RailVehicle other) { if (Object.op_Implicit((Object)(object)first) && Object.op_Implicit((Object)(object)other) && first.IsEngine && other.IsEngine && first.FuelPowered && other.FuelPowered) { return first.FuelType == other.FuelType; } return false; } private bool TryConsistMotionRoot(out RailVehicle root) { root = null; if (Ready && IsEngine && ParentId.Length != 0 && FindRoot(out root) && (Object)(object)root != (Object)(object)this && MultiEngineCompatible(root, this) && root.HasDriveAuthority) { return root._view.GetZDO().GetOwner() == _view.GetZDO().GetOwner(); } return false; } private List AvailableEngines(List train, double seconds) { return train.Where((RailVehicle cart) => ((Object)(object)cart == (Object)(object)this || MultiEngineCompatible(this, cart)) && cart.Ready && cart._view.IsOwner() && cart.FuelPowered && !cart.CargoBusy && cart.CanPowerFor(seconds)).ToList(); } private bool ConsistHasFuel(double seconds) { if (FindRoot(out RailVehicle root) && ReadCouplingChain(root, out List chain)) { return AvailableEngines(chain, seconds).Count != 0; } return false; } private bool StopFollowerSimulation() { if (!Ready || !IsEngine || ParentId.Length == 0) { return false; } if (Object.op_Implicit((Object)(object)_driver)) { StopLocalDriver(); } if (!TryConsistMotionRoot(out RailVehicle _)) { Speed = 0f; BeginSmokeStep(); BeginMovementAudioStep(); if (_view.IsOwner()) { PublishMotion(moving: false); StopSmoke(); StopMovementAudio(); } } return true; } private void BeginFollowerMotion(List train) { foreach (RailVehicle item in train) { if ((Object)(object)item != (Object)(object)this && item.IsEngine && item._view.IsOwner()) { item.BeginSmokeStep(); item.BeginMovementAudioStep(); } } } private void PublishConsistMotion(List train, Dictionary reversed, List suppliers, float distance, float seconds, bool powered) { foreach (RailVehicle item in train) { if ((Object)(object)item != (Object)(object)this) { item.Speed = (reversed[item] ? (0f - Speed) : Speed); } item.PublishMotion(distance > 0f && Mathf.Abs(Speed) >= 0.05f); if (item.IsEngine) { bool flag = powered && ((!FuelPowered) ? ((Object)(object)item == (Object)(object)this) : suppliers.Contains(item)); item.NotifyMovementAudio(distance, seconds, flag); if (flag && item.FuelPowered) { item.NotifySmokePowered(); } } } } private void StopFollowerMotion() { if (!Ready || ParentId.Length != 0 || !ReadCouplingChain(this, out List chain)) { return; } foreach (RailVehicle item in chain) { if (!((Object)(object)item == (Object)(object)this) && item.Ready && item._view.IsOwner()) { item.Speed = 0f; item.PublishMotion(moving: false); if (item.IsEngine) { item.StopSmoke(); item.StopMovementAudio(); } } } } private double LimitTrainAtWoodenTrack(List train, Dictionary reversed, bool forward, double distance, out bool restricted) { restricted = false; double num = distance; foreach (RailVehicle item in train) { bool restricted2; double val = item.LimitAtWoodenTrack(forward != reversed[item], distance, out restricted2); if (restricted2) { restricted = true; num = Math.Min(num, val); } } return num; } internal bool UncoupleFromLever(Player player) { if (!IsCoupled) { Tell(player, "This cart's front coupling is already open."); return false; } return ToggleCoupling(player); } private static RailVehicle CouplingLimitEngine(RailVehicle root, IEnumerable incoming) { if (root.IsEngine) { return root; } if (ReadCouplingChain(root, out List chain)) { RailVehicle railVehicle = chain.FirstOrDefault((RailVehicle cart) => cart.IsEngine); if (Object.op_Implicit((Object)(object)railVehicle)) { return railVehicle; } } return incoming.FirstOrDefault((RailVehicle cart) => cart.IsEngine) ?? root; } private static bool CanAttachCoupling(RailVehicle root, List train, List incoming) { RailVehicle railVehicle = train.Concat(incoming).FirstOrDefault((RailVehicle cart) => cart.IsEngine); int num = train.Count((RailVehicle cart) => cart.IsEngine); int num2 = incoming.Count((RailVehicle cart) => cart.IsEngine); if (!Object.op_Implicit((Object)(object)railVehicle)) { return RailTrainLimits.CanAttachDetached(train.Count, incoming.Count); } return RailTrainLimits.CanAttach(train.Count - num, num, incoming.Count - num2, num2, railVehicle.CartLimit); } private static string CouplingLimitMessage(RailVehicle root) { if (!root.IsEngine) { return "A parked wagon group can contain at most " + 20 + " carts."; } return root.GetHoverName() + " limits: " + root.CartLimit + " carts and " + 21 + " engines. Engines do not use cart slots."; } private bool CouplingRequesterInRange(Player player, long peer, RailVehicle wagon, ZDOID contactMover) { //IL_0086: 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_0009: 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_0058: 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) if (!((ZDOID)(ref contactMover)).IsNone() && contactMover == Id && IsEngine) { Transform anchor; if (DriverId == player.GetPlayerID() && _view.GetZDO().GetOwner() == peer && ((Character)player).GetOwner() == peer && !AutomaticDriveRequested && Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position) < 5f) { return TryDriverAnchor(player, out anchor); } return false; } if (Vector3.Distance(((Component)player).transform.position, ((Component)wagon).transform.position) < 5f) { if (!((ZDOID)(ref contactMover)).IsNone()) { if (!((Character)player).IsAttached()) { return player.GetDoodadController() == null; } return false; } return true; } return false; } private bool ValidateContactCouplers(ZDOID moverId, RailVehicle parent, bool parentFront, RailVehicle wagon, bool wagonFront) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) RailVehicle railVehicle = FindSession(moverId); if (Object.op_Implicit((Object)(object)railVehicle)) { bool num; if (!railVehicle.IsEngine) { if (!((Object)(object)railVehicle != (Object)(object)wagon)) { goto IL_0042; } if ((Object)(object)railVehicle != (Object)(object)this) { goto IL_0071; } num = (Object)(object)railVehicle != (Object)(object)parent; } else { num = (Object)(object)railVehicle != (Object)(object)this; } if (!num) { goto IL_0042; } } goto IL_0071; IL_0071: return false; IL_0042: if (!ContactCouplingBlocked(parent, wagon) && !parent.HasPlowAt(parentFront) && !wagon.HasPlowAt(wagonFront) && parent.TryCursor() && wagon.TryCursor()) { return RailAutoCoupling.AreCouplersTouching(RailSegment.Network, parent._cursor.Value, parentFront, wagon._cursor.Value, wagonFront, 2.799999952316284); } goto IL_0071; } private ContactCoupling? FindContactCoupling(List train, bool forward, double distance) { if (AutomaticDriveRequested || !Object.op_Implicit((Object)(object)_driver) || (Object)(object)_driver != (Object)(object)Player.m_localPlayer || distance <= 0.0 || (!IsEngine && train.Count != 1) || !TryFormation(train, out Dictionary slots, out Dictionary reversed)) { return null; } RailVehicle railVehicle = train[LeadingIndex(train, slots, forward)]; bool flag = forward != reversed[railVehicle]; if (railVehicle.HasPlowAt(flag) || !railVehicle.TryCursor()) { return null; } ContactCoupling contactCoupling = null; foreach (RailVehicle vehicle in Vehicles) { if (!Object.op_Implicit((Object)(object)vehicle) || !vehicle.Ready || train.Contains(vehicle) || !vehicle.TryCursor()) { continue; } bool[] array = new bool[2] { false, true }; foreach (bool flag2 in array) { if (!RailAutoCoupling.TryContact(RailSegment.Network, railVehicle._cursor.Value, flag, vehicle._cursor.Value, flag2, distance, 2.799999952316284, out var distanceToContact)) { continue; } RailVehicle root; RailVehicle parent; RailVehicle railVehicle2; bool parentFront; bool wagonFront; if (railVehicle.CanReceiveAt(flag) && TryIncomingChain(vehicle, flag2, out List _)) { root = this; parent = railVehicle; railVehicle2 = vehicle; parentFront = flag; wagonFront = flag2; } else { if (IsEngine || !vehicle.CanReceiveAt(flag2) || !vehicle.FindRoot(out root) || !CouplingRootStopped(root)) { continue; } parent = vehicle; railVehicle2 = this; parentFront = flag2; wagonFront = flag; } if (root.FindRoot(out RailVehicle root2) && ReadCouplingChain(root2, out List chain2) && railVehicle2.FindRoot(out RailVehicle root3) && ReadCouplingChain(root3, out List chain3) && CompatibleCouplingEngines(chain2.Concat(chain3)) && (contactCoupling == null || distanceToContact < contactCoupling.Distance)) { contactCoupling = new ContactCoupling { Root = root, Parent = parent, Wagon = railVehicle2, Distance = distanceToContact, ParentFront = parentFront, WagonFront = wagonFront }; } } } return contactCoupling; } private void BeginContactCoupling(ContactCoupling contact) { Player driver = _driver; Halt("Couplers touching. Waiting for the cart owners to connect them."); _serviceNeedsNeutral = true; if (ContactCouplingBlocked(contact.Parent, contact.Wagon)) { Status = "Coupling released. Move the cars apart before bringing them together again, or couple manually."; } else if (Object.op_Implicit((Object)(object)driver) && !((Object)(object)driver != (Object)(object)Player.m_localPlayer) && Object.op_Implicit((Object)(object)contact.Root) && contact.Root.Ready) { if (!IsEngine) { StopLocalDriver(); } RailVehicle root = contact.Root; if (!ReadCouplingChain(root, out List chain) || !TryIncomingChain(contact.Wagon, contact.WagonFront, out List chain2)) { Tell(driver, "Wait for the entire train and wagon group to load."); return; } if (!CompatibleCouplingEngines(chain.Concat(chain2))) { Tell(driver, "Only powered engines of the same type can share a train."); return; } if (!CanAttachCoupling(root, chain, chain2)) { Status = CouplingLimitMessage(CouplingLimitEngine(root, chain2)); Tell(driver, Status); return; } if (root._contactCouplingClient != null || !((ZDOID)(ref root._couplingClientWagon)).IsNone()) { Tell(driver, "Wait for the current coupling request to finish."); return; } root._contactCouplingClient = new ContactCouplingClient { Player = driver, Mover = this, Parent = contact.Parent, Wagon = contact.Wagon, ParentFront = contact.ParentFront, WagonFront = contact.WagonFront, Expires = Time.unscaledTime + 8f + 2f }; root.UpdateContactCoupling(); } } private void UpdateContactCoupling() { //IL_0122: 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_01b1: 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_0224: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) UpdateReleasedCoupler(); ContactCouplingClient contactCouplingClient = _contactCouplingClient; if (contactCouplingClient == null) { return; } if (!Ready || !Object.op_Implicit((Object)(object)contactCouplingClient.Player) || (Object)(object)contactCouplingClient.Player != (Object)(object)Player.m_localPlayer || ((Character)contactCouplingClient.Player).IsDead() || ((Character)contactCouplingClient.Player).IsTeleporting() || !Object.op_Implicit((Object)(object)contactCouplingClient.Mover) || !Object.op_Implicit((Object)(object)contactCouplingClient.Parent) || !Object.op_Implicit((Object)(object)contactCouplingClient.Wagon) || !contactCouplingClient.Parent.Ready || !contactCouplingClient.Wagon.Ready || Time.unscaledTime >= contactCouplingClient.Expires) { _contactCouplingClient = null; Tell(contactCouplingClient.Player, contactCouplingClient.Failure); } else if (contactCouplingClient.Wagon.ParentId == contactCouplingClient.Parent._identity && contactCouplingClient.Parent.LinkAtEnd(contactCouplingClient.ParentFront) == contactCouplingClient.Wagon._identity) { _contactCouplingClient = null; } else if (!CouplingRequesterInRange(contactCouplingClient.Player, ((Character)contactCouplingClient.Player).GetOwner(), contactCouplingClient.Wagon, contactCouplingClient.Mover.Id) || !ValidateContactCouplers(contactCouplingClient.Mover.Id, contactCouplingClient.Parent, contactCouplingClient.ParentFront, contactCouplingClient.Wagon, contactCouplingClient.WagonFront)) { _contactCouplingClient = null; Tell(contactCouplingClient.Player, "Automatic coupling cancelled: the driver or couplers moved away."); } else if (((ZDOID)(ref _couplingClientWagon)).IsNone() && !(Time.unscaledTime < contactCouplingClient.NextAttempt) && _view.HasOwner()) { contactCouplingClient.NextAttempt = Time.unscaledTime + 0.4f; _couplingClientWagon = contactCouplingClient.Wagon.Id; _couplingClientOwner = _view.GetZDO().GetOwner(); _couplingClientUntil = contactCouplingClient.Expires; if (ZDOMan.instance != null) { ZDOMan.instance.ForceSendZDO(_couplingClientOwner, contactCouplingClient.Mover.Id); } SendCouplingRequest(contactCouplingClient.Player, contactCouplingClient.Wagon, contactCouplingClient.Parent, contactCouplingClient.ParentFront, contactCouplingClient.WagonFront, contactCouplingClient.Mover.Id); } } private static bool ContactCouplingBlocked(RailVehicle parent, RailVehicle wagon) { if (!(parent._view.GetZDO().GetString("vikingrail_released_coupler", "") == wagon._identity)) { return wagon._view.GetZDO().GetString("vikingrail_released_coupler", "") == parent._identity; } return true; } private static void BlockContactRecoupling(RailVehicle parent, RailVehicle wagon) { parent._view.GetZDO().Set("vikingrail_released_coupler", wagon._identity); wagon._view.GetZDO().Set("vikingrail_released_coupler", parent._identity); } private void UpdateReleasedCoupler() { //IL_0058: 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) if (!Ready || !_view.IsOwner()) { return; } string text = _view.GetZDO().GetString("vikingrail_released_coupler", ""); if (text.Length == 0) { return; } RailVehicle railVehicle = Find(text); if (!Object.op_Implicit((Object)(object)railVehicle) || !railVehicle.Ready) { return; } double num = Vector3.Distance(((Component)this).transform.position, ((Component)railVehicle).transform.position); double? forwardRouteDistance = null; double? reverseRouteDistance = null; if (num <= 3.1499998569488525 && TryCursor() && railVehicle.TryCursor()) { double distance; bool flag = RailSegment.Network.TryDistanceAlongRoute(_cursor.Value, railVehicle._cursor.Value, 32.0, out distance); double distance2; bool num2 = RailSegment.Network.TryDistanceAlongRoute(_cursor.Value.Reversed(), railVehicle._cursor.Value, 32.0, out distance2); if (flag) { forwardRouteDistance = distance; } if (num2) { reverseRouteDistance = distance2; } } if (RailAutoCoupling.CanResetReleasedPair(num, forwardRouteDistance, reverseRouteDistance, 3.1499998569488525)) { _view.GetZDO().Set("vikingrail_released_coupler", ""); } } private void InitializeCoupling() { _view.Register("VR_CoupleAtEnds_v2", (Action)RequestRootCoupling); _view.Register("VR_CoupleYield", (Action)RequestCouplingYield); _view.Register("VR_CoupleYieldReply", (Method)CouplingYieldReply); _view.Register("VR_CoupleReply", (Action)CouplingReply); } public bool ToggleCoupling(Player? player) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_03a9: Unknown result type (might be due to invalid IL or missing references) //IL_03ae: Unknown result type (might be due to invalid IL or missing references) //IL_03e6: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || !PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return false; } if (!RailSettings.Ready) { Tell(player, "Waiting for server railroad settings."); return false; } if (CouplingServiceBusy || CargoServiceBusy || CargoBusy) { Tell(player, "Finish storage access or the current coupling change first."); return false; } RailVehicle railVehicle = null; RailVehicle railVehicle2 = null; bool parentFront = false; bool wagonFront = ParentFront; if (IsCoupled) { if (!FindRoot(out RailVehicle root)) { Tell(player, "Wait for the whole train to load."); return false; } railVehicle = root; } else { if (!ReadCouplingChain(this, out List chain) || chain.Any((RailVehicle c) => !CouplingWagonIdle(c))) { Tell(player, "Have riders leave the wagons and close cargo before coupling."); return false; } if (!TryCursor()) { Tell(player, "Build the wagon directly on a railway."); return false; } float num = 0.8f; RailVehicle railVehicle3 = null; foreach (RailVehicle vehicle in Vehicles) { if (!Object.op_Implicit((Object)(object)vehicle) || (Object)(object)vehicle == (Object)(object)this || !vehicle.Ready || !vehicle.FindRoot(out RailVehicle root2) || !CouplingRootStopped(root2) || root2.CouplingServiceBusy || root2.CargoServiceBusy || !ReadCouplingChain(root2, out List chain2) || chain2.Any((RailVehicle c) => !c.TryCursor()) || chain.Any(chain2.Contains) || chain2.Any((RailVehicle c) => !CouplingWagonIdle(c))) { continue; } bool[] array = new bool[2] { false, true }; foreach (bool flag in array) { bool[] array2 = new bool[2] { false, true }; foreach (bool flag2 in array2) { if (!vehicle.CanReceiveAt(flag) || !TryIncomingChain(this, flag2, out List chain3) || !CompatibleCouplingEngines(chain2.Concat(chain3)) || !TryCouplingPosition(vehicle, flag, this, flag2, out var cursor)) { continue; } float num4 = Vector3.Distance(((Component)this).transform.position, RailSegment.ToUnity(RailVehiclePose.Sample(RailSegment.Network, cursor).Position)); if (!(num4 >= num)) { if (!CanAttachCoupling(root2, chain2, chain3)) { railVehicle3 = CouplingLimitEngine(root2, chain3); continue; } num = num4; railVehicle2 = vehicle; railVehicle = root2; parentFront = flag; wagonFront = flag2; } } } } if (!Object.op_Implicit((Object)(object)railVehicle)) { Tell(player, Object.op_Implicit((Object)(object)railVehicle3) ? CouplingLimitMessage(railVehicle3) : "Place either end of this cart about 2.8 m from an open train coupler. Close cargo and clear wagon riders."); return false; } } if (!Object.op_Implicit((Object)(object)railVehicle) || !CouplingRootStopped(railVehicle) || railVehicle.CouplingServiceBusy || railVehicle.CargoServiceBusy) { Tell(player, "Stop the train and finish storage access before changing couplings."); return false; } if (!railVehicle._view.HasOwner() || Time.unscaledTime < railVehicle._couplingClientUntil || railVehicle._contactCouplingClient != null) { return false; } if (Object.op_Implicit((Object)(object)railVehicle2) && !PrivateArea.CheckAccess(((Component)railVehicle2).transform.position, 0f, true, false)) { return false; } railVehicle._couplingClientWagon = Id; railVehicle._couplingClientOwner = railVehicle._view.GetZDO().GetOwner(); railVehicle._couplingClientUntil = Time.unscaledTime + 8f + 2f; railVehicle.SendCouplingRequest(player, this, railVehicle2, parentFront, wagonFront, ZDOID.None); return true; } private static bool CouplingRootStopped(RailVehicle root) { if (!root.Ready || root.AutomaticDriveRequested || root._packing || root._packPending || root._pendingMount || (!root.IsEngine && (root.DriverId != 0L || Object.op_Implicit((Object)(object)root._driver)))) { return false; } if (root._view.IsOwner()) { return root.Speed == 0f; } if (Object.op_Implicit((Object)(object)ZNet.instance)) { return root._view.GetZDO().GetLong("vikingrail_moving_until", 0L) <= CouplingNow; } return false; } private static bool CouplingWagonIdle(RailVehicle cart) { if (cart.Ready && !cart._packing && !cart._packPending && !cart.CargoBusy && !cart.CargoServiceBusy && !cart.MountServiceBusy && !cart.AutomaticDriveRequested) { if (!cart.IsCouplingRootEngine) { if (cart.DriverId == 0L && !Object.op_Implicit((Object)(object)cart._driver) && !cart._pendingMount) { return !cart.HasPassengers; } return false; } return true; } return false; } private static bool ReadCouplingChain(RailVehicle first, out List chain) { chain = new List(); HashSet visited = new HashSet(); Stack stack = new Stack(); stack.Push(first); while (stack.Count != 0) { RailVehicle railVehicle = stack.Pop(); if (!railVehicle.Ready || (railVehicle.ParentId.Length != 0 && railVehicle.FrontId.Length != 0) || !RailTrainLimits.TryVisit(visited, railVehicle._identity)) { return false; } chain.Add(railVehicle); string[] array = new string[2] { railVehicle.FrontId, railVehicle.NextId }; foreach (string text in array) { if (text.Length != 0) { RailVehicle railVehicle2 = Find(text); if (!Object.op_Implicit((Object)(object)railVehicle2) || railVehicle2.ParentId != railVehicle._identity) { return false; } stack.Push(railVehicle2); } } } return true; } private string LinkAtEnd(bool front) { if (!IsCouplingRootEngine) { if (front != ParentFront) { return NextId; } return ParentId; } if (!front) { return NextId; } return FrontId; } internal bool HasCouplingAt(bool front) { if (Ready) { return LinkAtEnd(front).Length != 0; } return false; } internal bool UseCouplingEnd(Player player, bool front) { //IL_003a: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_039a: Unknown result type (might be due to invalid IL or missing references) //IL_039f: Unknown result type (might be due to invalid IL or missing references) //IL_03eb: 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_02c2: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !RailSettings.Ready || !Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position) > 5f || !PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return false; } if (CouplingServiceBusy || CargoServiceBusy || CargoBusy) { Tell(player, "Finish storage access or the current coupling change first."); return false; } if (HasCouplingAt(front)) { RailVehicle railVehicle = ((ParentId.Length != 0 && front == ParentFront) ? this : Find(LinkAtEnd(front))); if (Object.op_Implicit((Object)(object)railVehicle)) { return railVehicle.ToggleCoupling(player); } return false; } if (HasPlowAt(front)) { Tell(player, "Detach the plow from this end before coupling here."); return false; } if (!FindRoot(out RailVehicle root) || !CouplingRootStopped(root)) { Tell(player, "Stop the whole train before changing couplings."); return false; } ContactCoupling contactCoupling = null; string text = "Line up this open coupler with either end of a stopped cart, about 2.8 m between centers."; foreach (RailVehicle vehicle in Vehicles) { if (!Object.op_Implicit((Object)(object)vehicle) || (Object)(object)vehicle == (Object)(object)this || !vehicle.Ready) { continue; } bool[] array = new bool[2] { false, true }; foreach (bool flag in array) { RailVehicle parent; RailVehicle railVehicle2; RailVehicle root2; bool parentFront; bool wagonFront; if (CanReceiveAt(front) && TryIncomingChain(vehicle, flag, out List chain)) { parent = this; railVehicle2 = vehicle; root2 = root; parentFront = front; wagonFront = flag; } else { if (!vehicle.CanReceiveAt(flag) || !vehicle.FindRoot(out root2) || !CouplingRootStopped(root2) || !TryIncomingChain(this, front, out chain)) { continue; } parent = vehicle; railVehicle2 = this; parentFront = flag; wagonFront = front; } if (!ReadCouplingChain(root2, out List chain2) || chain.Any(chain2.Contains) || !CompatibleCouplingEngines(chain2.Concat(chain)) || chain2.Any((RailVehicle c) => !CouplingWagonIdle(c)) || chain.Any((RailVehicle c) => !CouplingWagonIdle(c)) || !TryCouplingPosition(parent, parentFront, railVehicle2, wagonFront, out var cursor)) { continue; } if (!CanAttachCoupling(root2, chain2, chain)) { text = CouplingLimitMessage(CouplingLimitEngine(root2, chain)); continue; } double num = Vector3.Distance(((Component)railVehicle2).transform.position, RailSegment.ToUnity(RailVehiclePose.Sample(RailSegment.Network, cursor).Position)); if (!(num > 0.8) && (contactCoupling == null || !(num >= contactCoupling.Distance))) { contactCoupling = new ContactCoupling { Root = root2, Parent = parent, Wagon = railVehicle2, Distance = num, ParentFront = parentFront, WagonFront = wagonFront }; } } } if (contactCoupling == null) { Tell(player, text); return false; } RailVehicle root3 = contactCoupling.Root; if (!root3._view.HasOwner() || root3.CouplingServiceBusy || root3.CargoServiceBusy || Time.unscaledTime < root3._couplingClientUntil || root3._contactCouplingClient != null) { return false; } root3._couplingClientWagon = contactCoupling.Wagon.Id; root3._couplingClientOwner = root3._view.GetZDO().GetOwner(); root3._couplingClientUntil = Time.unscaledTime + 8f + 2f; root3.SendCouplingRequest(player, contactCoupling.Wagon, contactCoupling.Parent, contactCoupling.ParentFront, contactCoupling.WagonFront, ZDOID.None); return true; } private bool CanReceiveAt(bool front) { if (LinkAtEnd(front).Length == 0 && !HasPlowAt(front)) { if (!IsCouplingRootEngine && front == ParentFront) { return ParentId.Length == 0; } return true; } return false; } private static bool TryIncomingChain(RailVehicle end, bool front, out List chain) { chain = new List(); if (!end.Ready || end.LinkAtEnd(front).Length != 0 || end.HasPlowAt(front) || !end.FindRoot(out RailVehicle root) || !CouplingRootStopped(root) || !ReadCouplingChain(root, out List chain2) || chain2.Any((RailVehicle cart) => cart.DriverId != 0L || Object.op_Implicit((Object)(object)cart._driver) || cart._pendingMount || cart.AutomaticDriveRequested || (cart.IsEngine && cart.HasPassengers)) || !CompatibleCouplingEngines(chain2)) { return false; } HashSet visited = new HashSet(); RailVehicle railVehicle = end; string text = ""; while (Object.op_Implicit((Object)(object)railVehicle)) { if (!chain2.Contains(railVehicle) || !RailTrainLimits.TryVisit(visited, railVehicle._identity)) { return false; } chain.Add(railVehicle); string text2 = railVehicle.LinkAtEnd(front: true); string text3 = railVehicle.LinkAtEnd(front: false); string text4 = ((text2 != text && text2.Length != 0) ? text2 : ((text3 != text) ? text3 : "")); text = railVehicle._identity; railVehicle = ((text4.Length == 0) ? null : Find(text4)); if (text4.Length != 0 && !Object.op_Implicit((Object)(object)railVehicle)) { return false; } } return chain.Count == chain2.Count; } private static RailCursor Outward(RailVehicle cart, bool front) { if (!front) { return cart._cursor.Value.Reversed(); } return cart._cursor.Value; } private static bool TryCouplingPosition(RailVehicle parent, bool parentFront, RailVehicle wagon, bool wagonFront, out RailCursor cursor) { cursor = default(RailCursor); if (!parent.TryCursor() || !wagon.TryCursor()) { return false; } RailCursor railCursor = Outward(parent, parentFront); if (!RailSegment.Network.TryDistanceAlongRoute(railCursor, wagon._cursor.Value, 3.449999952316284, out var distance) || Math.Abs(distance - 2.799999952316284) > 0.65 || !RailSegment.Network.TryDistanceAlongRoute(Outward(wagon, wagonFront), parent._cursor.Value, distance + 0.001, out var distance2) || Math.Abs(distance2 - distance) > 0.001) { return false; } RailAdvanceResult railAdvanceResult = RailSegment.Network.Advance(railCursor, 2.799999952316284); if (railAdvanceResult.DistanceTravelled < 2.7989999523162843) { return false; } cursor = (wagonFront ? railAdvanceResult.Cursor.Reversed() : railAdvanceResult.Cursor); return RailVector.Dot(RailVehiclePose.Sample(RailSegment.Network, cursor).Tangent, RailVehiclePose.Sample(RailSegment.Network, wagon._cursor.Value).Tangent) > 0.9; } private bool OtherCouplingBusy(string token) { if (!RailTurntable.BlocksVehicle(this)) { if (CouplingServiceBusy) { if (!(_view.GetZDO().GetString("vikingrail_couple_token", "") != token)) { return token.Length == 0; } return true; } return false; } return true; } private bool ValidateCoupling(long peer, long playerId, ZDOID wagonId, ZDOID parentId, string expectedParent, string token, ZDOID contactMover, bool parentFront, bool wagonFront, out List affected, out List suffix, out List proposed, out string reason) { //IL_0035: 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) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: 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_021c: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_0404: Unknown result type (might be due to invalid IL or missing references) //IL_0410: Unknown result type (might be due to invalid IL or missing references) //IL_042b: Unknown result type (might be due to invalid IL or missing references) affected = new List(); suffix = new List(); proposed = new List(); reason = "Stop the train, close cargo, and have riders leave the affected wagons."; RailVehicle railVehicle = FindSession(wagonId); Player player = Player.GetPlayer(playerId); if (!Ready || !_view.IsOwner() || !RailSettings.Ready || !Object.op_Implicit((Object)(object)railVehicle) || !Object.op_Implicit((Object)(object)player) || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || ((Character)player).GetOwner() != peer || !CouplingRequesterInRange(player, peer, railVehicle, contactMover) || expectedParent.Length > 64 || railVehicle.ParentId != expectedParent || !CouplingRootStopped(this) || OtherCouplingBusy(token) || CargoServiceBusy || !ReadCouplingChain(this, out List chain)) { return false; } if (!RailWardAccess.Allows(((Component)railVehicle).transform.position, playerId)) { reason = "You do not have permission to change these couplings."; return false; } if (((ZDOID)(ref parentId)).IsNone()) { if (!((ZDOID)(ref contactMover)).IsNone()) { return false; } RailVehicle railVehicle2 = Find(railVehicle.ParentId); if (!ReadCouplingChain(railVehicle, out suffix) || !Object.op_Implicit((Object)(object)railVehicle2) || (railVehicle2.NextId != railVehicle._identity && railVehicle2.FrontId != railVehicle._identity) || !railVehicle.FindRoot(out RailVehicle root) || (Object)(object)root != (Object)(object)this || !RailWardAccess.Allows(((Component)railVehicle2).transform.position, playerId)) { return false; } affected.AddRange(chain); } else { RailVehicle railVehicle3 = FindSession(parentId); if (ParentId.Length != 0 || !Object.op_Implicit((Object)(object)railVehicle3) || !railVehicle3.CanReceiveAt(parentFront) || !TryIncomingChain(railVehicle, wagonFront, out suffix) || !railVehicle3.FindRoot(out RailVehicle root2) || (Object)(object)root2 != (Object)(object)this || !chain.Contains(railVehicle3) || suffix.Any(chain.Contains) || !RailWardAccess.Allows(((Component)railVehicle3).transform.position, playerId)) { return false; } if (!CanAttachCoupling(this, chain, suffix)) { reason = CouplingLimitMessage(CouplingLimitEngine(this, suffix)); return false; } affected.AddRange(chain); affected.AddRange(suffix); if (!CompatibleCouplingEngines(affected)) { reason = "Only powered engines of the same type can share a train."; return false; } if (affected.Any((RailVehicle c) => !c.TryCursor()) || !HasCompatibleTrack()) { reason = "The whole train needs compatible, connected railway track."; return false; } if (!TryCouplingPosition(railVehicle3, parentFront, railVehicle, wagonFront, out var _) || (!((ZDOID)(ref contactMover)).IsNone() && !ValidateContactCouplers(contactMover, railVehicle3, parentFront, railVehicle, wagonFront))) { reason = "Line up the open couplers on the same track before pushing them together."; return false; } for (int num = 0; num < suffix.Count; num++) { double num2 = (float)(num + 1) * 2.8f; if (!RailSegment.Network.TryDistanceAlongRoute(Outward(railVehicle3, parentFront), suffix[num]._cursor.Value, num2 + 0.65, out var distance) || Math.Abs(distance - num2) > 0.65) { return false; } RailAdvanceResult railAdvanceResult = RailSegment.Network.Advance(Outward(railVehicle3, parentFront), num2); if (railAdvanceResult.DistanceTravelled < num2 - 0.01) { return false; } RailCursor railCursor = (IncomingParentEnd(suffix, num, wagonFront) ? railAdvanceResult.Cursor.Reversed() : railAdvanceResult.Cursor); RailPose pose = RailVehiclePose.Sample(RailSegment.Network, railCursor); if (RailVector.Dot(pose.Tangent, RailVehiclePose.Sample(RailSegment.Network, suffix[num]._cursor.Value).Tangent) <= 0.9 || Vector3.Distance(((Component)suffix[num]).transform.position, RailSegment.ToUnity(pose.Position)) > 0.8f || !RailWardAccess.Allows(RailSegment.ToUnity(pose.Position), playerId) || suffix[num].IsObstructed(pose, affected, player) || !RailSafety.CanRelocate(RailSegment.Network, suffix[num]._cursor.Value, railCursor, 0.8, includeBrakes: false, RailSegment.StopMarkers, _brakeBypass, out var _)) { return false; } proposed.Add(railCursor); } } if (RailMountCart.PrepareTrain(affected, out reason)) { return affected.All((RailVehicle c) => CouplingWagonIdle(c) && !c.OtherCouplingBusy(token) && RailWardAccess.Allows(((Component)c).transform.position, playerId)); } return false; } private void SendCouplingRequest(Player player, RailVehicle wagon, RailVehicle? parent, bool parentFront, bool wagonFront, ZDOID mover) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0014: 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_0027: 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) ZPackage val = new ZPackage(); val.Write(player.GetPlayerID()); val.Write(wagon.Id); val.Write(Object.op_Implicit((Object)(object)parent) ? parent.Id : ZDOID.None); val.Write(wagon.ParentId); val.Write(parentFront); val.Write(wagonFront); val.Write(mover); _view.InvokeRPC("VR_CoupleAtEnds_v2", new object[1] { val }); } private void RequestRootCoupling(long sender, ZPackage package) { //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_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_003f: 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_006d: 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_0070: Unknown result type (might be due to invalid IL or missing references) try { if (package.Size() <= 256) { long playerId = package.ReadLong(); ZDOID wagon = package.ReadZDOID(); ZDOID parent = package.ReadZDOID(); string expectedParent = package.ReadString(); bool parentFront = package.ReadBool(); bool wagonFront = package.ReadBool(); ZDOID contactMover = package.ReadZDOID(); if (package.GetPos() == package.Size() && (((ZDOID)(ref contactMover)).IsNone() || !((ZDOID)(ref parent)).IsNone())) { StartCouplingOperation(sender, playerId, wagon, parent, expectedParent, contactMover, parentFront, wagonFront); } } } catch (Exception ex) { RailPlugin.Warn("Invalid railway coupling request: " + ex.Message); } } private void StartCouplingOperation(long sender, long playerId, ZDOID wagon, ZDOID parent, string expectedParent, ZDOID contactMover, bool parentFront, bool wagonFront) { //IL_0019: 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_0023: 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_009d: 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) //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_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !_view.IsOwner()) { return; } if (!ValidateCoupling(sender, playerId, wagon, parent, expectedParent, "", contactMover, parentFront, wagonFront, out List affected, out List _, out List _, out string reason)) { ReplyCoupling(sender, wagon, success: false, reason); return; } CouplingOperation couplingOperation = new CouplingOperation { Token = Guid.NewGuid().ToString("N"), Peer = sender, Player = playerId, Owner = _view.GetZDO().GetOwner(), OwnerRevision = _view.GetZDO().OwnerRevision, Wagon = wagon, Parent = parent, ExpectedParent = expectedParent, ContactMover = contactMover, ParentFront = parentFront, WagonFront = wagonFront, Expires = Time.unscaledTime + 8f }; foreach (RailVehicle item in affected) { couplingOperation.Members.Add(new CouplingMember { Cart = item, Id = item.Id, Parent = item.ParentId, Next = item.NextId, Front = item.FrontId, ParentFront = item.ParentFront, Plow = item.AttachedPlowId, PlowFront = item.MountedPlowFront, PreviousOwner = item._view.GetZDO().GetOwner() }); } _couplingOperation = couplingOperation; _serviceNeedsNeutral = true; WriteCouplingLease(this, couplingOperation.Token, CouplingNow + 8000); ZDO zDO = _view.GetZDO(); zDO.Set("vikingrail_couple_player", playerId); zDO.Set("vikingrail_couple_peer", sender); zDO.Set("vikingrail_couple_wagon", wagon); zDO.Set("vikingrail_couple_parent", parent); zDO.Set("vikingrail_couple_expected", expectedParent); zDO.Set("vikingrail_couple_mover", contactMover); zDO.Set("vikingrail_couple_ends", (parentFront ? 1 : 0) | (wagonFront ? 2 : 0)); Halt("Changing railway couplings. Release movement controls before departing."); UpdateCoupling(); } private void WriteCouplingLease(RailVehicle root, string token, long until) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) _view.GetZDO().Set("vikingrail_couple_token", token); _view.GetZDO().Set("vikingrail_couple_root", root.Id); _view.GetZDO().Set("vikingrail_couple_until", until); } private static long CouplingStamp(ZDO zdo) { return (long)(((ulong)zdo.OwnerRevision << 32) | zdo.DataRevision); } private void UpdateCoupling() { //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_00bd: 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_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0409: Unknown result type (might be due to invalid IL or missing references) if (!((ZDOID)(ref _couplingClientWagon)).IsNone() && Time.unscaledTime >= _couplingClientUntil) { _couplingClientWagon = ZDOID.None; _couplingClientUntil = 0f; Tell(Player.m_localPlayer, "Coupling request timed out. Check the couplings before trying again."); } CouplingOperation couplingOperation = _couplingOperation; if (couplingOperation == null) { return; } if (!Ready || !_view.IsOwner() || _view.GetZDO().GetOwner() != couplingOperation.Owner || _view.GetZDO().OwnerRevision != couplingOperation.OwnerRevision || Time.unscaledTime >= couplingOperation.Expires) { FinishCoupling(success: false, "Coupling change stopped because ownership changed or a wagon did not respond."); return; } if (!ValidateCoupling(couplingOperation.Peer, couplingOperation.Player, couplingOperation.Wagon, couplingOperation.Parent, couplingOperation.ExpectedParent, couplingOperation.Token, couplingOperation.ContactMover, couplingOperation.ParentFront, couplingOperation.WagonFront, out List affected, out List suffix, out List proposed, out string reason) || affected.Count != couplingOperation.Members.Count || couplingOperation.Members.Any((CouplingMember m) => !Object.op_Implicit((Object)(object)m.Cart) || m.Cart.Id != m.Id || !affected.Contains(m.Cart) || m.Cart.ParentId != m.Parent || m.Cart.NextId != m.Next || m.Cart.FrontId != m.Front || m.Cart.ParentFront != m.ParentFront || m.Cart.AttachedPlowId != m.Plow || m.Cart.MountedPlowFront != m.PlowFront)) { FinishCoupling(success: false, reason); return; } bool flag = true; bool flag2 = Time.unscaledTime >= couplingOperation.NextRequest; if (flag2) { couplingOperation.NextRequest = Time.unscaledTime + 0.4f; } foreach (CouplingMember member in couplingOperation.Members) { RailVehicle cart = member.Cart; if (member.PreviousOwner == couplingOperation.Owner) { if (!cart._view.IsOwner()) { FinishCoupling(success: false, "A wagon's ownership changed. Try again."); return; } if (member.Stamp < 0) { cart.WriteCouplingLease(this, couplingOperation.Token, _view.GetZDO().GetLong("vikingrail_couple_until", 0L)); member.Digest = RailCargoInventory.InventoryDigest(cart._view.GetZDO()); member.Stamp = CouplingStamp(cart._view.GetZDO()); } } else if (member.Stamp < 0) { flag = false; if (flag2) { if (ZDOMan.instance != null) { ZDOMan.instance.ForceSendZDO(member.PreviousOwner, Id); } cart._view.InvokeRPC(member.PreviousOwner, "VR_CoupleYield", new object[2] { Id, couplingOperation.Token }); } continue; } ZDO zDO = cart._view.GetZDO(); if (!cart._view.IsOwner() || zDO.OwnerRevision != (ushort)(member.Stamp >> 32) || zDO.DataRevision < (uint)member.Stamp || RailCargoInventory.InventoryDigest(zDO) != member.Digest) { flag = false; } else if (Object.op_Implicit((Object)(object)cart._container) && !RailCargoInventory.TryRefreshForOwnership(cart._container, out reason)) { FinishCoupling(success: false, reason); return; } } if (!flag) { return; } RailVehicle railVehicle = FindSession(couplingOperation.Wagon); if (!Object.op_Implicit((Object)(object)railVehicle)) { FinishCoupling(success: false, "The wagon is no longer loaded."); return; } if (((ZDOID)(ref couplingOperation.Parent)).IsNone()) { RailVehicle railVehicle2 = Find(railVehicle.ParentId); if (!Object.op_Implicit((Object)(object)railVehicle2) || !railVehicle2._view.IsOwner() || (railVehicle2.NextId != railVehicle._identity && railVehicle2.FrontId != railVehicle._identity)) { FinishCoupling(success: false, "The coupling changed before the request finished."); return; } railVehicle2._view.GetZDO().Set((railVehicle2.FrontId == railVehicle._identity) ? "vikingrail_front" : "vikingrail_next", ""); railVehicle.DetachCouplingParent(); BlockContactRecoupling(railVehicle2, railVehicle); } else { RailVehicle railVehicle3 = FindSession(couplingOperation.Parent); if (!Object.op_Implicit((Object)(object)railVehicle3) || !railVehicle3._view.IsOwner()) { FinishCoupling(success: false, "The parent wagon is unavailable."); return; } if (!TryMergedCouplingPlan(this, railVehicle3, couplingOperation.ParentFront, railVehicle, couplingOperation.WagonFront, affected, out Dictionary plan)) { FinishCoupling(success: false, "The full train's physical couplers are inconsistent."); return; } ApplyCouplingPlan(affected, plan); for (int num = 0; num < suffix.Count; num++) { suffix[num].MoveTo(proposed[num]); } } FinishCoupling(success: true, ((ZDOID)(ref couplingOperation.Parent)).IsNone() ? "Wagon uncoupled." : "Wagon coupled."); } private void RequestCouplingYield(long sender, ZDOID rootId, string token) { //IL_0020: 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_020d: 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_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_015e: 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) if (!Ready || !_view.IsOwner() || token.Length != 32) { return; } RailVehicle railVehicle = FindSession(rootId); if (!Object.op_Implicit((Object)(object)railVehicle) || !railVehicle.Ready || railVehicle._view.GetZDO().GetOwner() != sender || !railVehicle.HasCouplingLease || railVehicle._view.GetZDO().GetString("vikingrail_couple_token", "") != token) { return; } ZDO zDO = railVehicle._view.GetZDO(); RailVehicle railVehicle2 = FindSession(zDO.GetZDOID("vikingrail_couple_wagon")); Player player = Player.GetPlayer(zDO.GetLong("vikingrail_couple_player", 0L)); if (Object.op_Implicit((Object)(object)railVehicle2) && Object.op_Implicit((Object)(object)player) && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && ((Character)player).GetOwner() == zDO.GetLong("vikingrail_couple_peer", 0L) && railVehicle.CouplingRequesterInRange(player, zDO.GetLong("vikingrail_couple_peer", 0L), railVehicle2, zDO.GetZDOID("vikingrail_couple_mover")) && railVehicle2.ParentId == zDO.GetString("vikingrail_couple_expected", "") && CouplingWagonIdle(this) && !OtherCouplingBusy(token) && !railVehicle.CargoServiceBusy && CouplingRootStopped(railVehicle) && RailWardAccess.Allows(((Component)this).transform.position, player.GetPlayerID())) { ZDOID zDOID = zDO.GetZDOID("vikingrail_couple_parent"); if ((((((ZDOID)(ref zDOID)).IsNone() ? ReadCouplingChain(railVehicle2, out List chain) : TryIncomingChain(railVehicle2, (zDO.GetInt("vikingrail_couple_ends", 0) & 2) != 0, out chain)) && chain.Contains(this)) || (ReadCouplingChain(railVehicle, out List chain2) && chain2.Contains(this))) && (!Object.op_Implicit((Object)(object)_container) || RailCargoInventory.TryRefresh(_container, out string _))) { WriteCouplingLease(railVehicle, token, zDO.GetLong("vikingrail_couple_until", 0L)); if (TryCursor()) { SaveCursor(_cursor.Value, RailVehiclePose.Sample(RailSegment.Network, _cursor.Value)); } string text = RailCargoInventory.InventoryDigest(_view.GetZDO()); _view.GetZDO().SetOwner(sender); long num = CouplingStamp(_view.GetZDO()); if (ZDOMan.instance != null) { ZDOMan.instance.ForceSendZDO(sender, Id); } railVehicle._view.InvokeRPC(sender, "VR_CoupleYieldReply", new object[4] { token, Id, num, text }); return; } } railVehicle._view.InvokeRPC(sender, "VR_CoupleYieldReply", new object[4] { token, Id, -1L, "A wagon is busy or unavailable." }); } private void CouplingYieldReply(long sender, string token, ZDOID wagon, long stamp, string digest) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) CouplingOperation couplingOperation = _couplingOperation; if (couplingOperation == null || !Ready || !_view.IsOwner() || couplingOperation.Token != token) { return; } CouplingMember couplingMember = couplingOperation.Members.Find((CouplingMember m) => m.Id == wagon && m.PreviousOwner == sender); if (couplingMember != null && couplingMember.Stamp < 0) { if (stamp < 0 || stamp >> 48 != 0L || digest.Length != 64) { FinishCoupling(success: false, "The wagon owner could not release a closed, unoccupied wagon."); return; } couplingMember.Stamp = stamp; couplingMember.Digest = digest; } } private void FinishCoupling(bool success, string reason) { //IL_00fb: 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) CouplingOperation couplingOperation = _couplingOperation; if (couplingOperation == null) { return; } _couplingOperation = null; _serviceNeedsNeutral = true; foreach (CouplingMember member in couplingOperation.Members) { RailVehicle cart = member.Cart; if (Object.op_Implicit((Object)(object)cart) && cart.Ready && cart._view.IsOwner() && !(cart._view.GetZDO().GetString("vikingrail_couple_token", "") != couplingOperation.Token)) { cart._view.GetZDO().Set("vikingrail_couple_until", 0L); cart._view.GetZDO().Set("vikingrail_couple_token", ""); if (ZDOMan.instance != null) { ZDOMan.instance.ForceSendZDO(couplingOperation.Peer, cart.Id); } } } if (Ready) { ReplyCoupling(couplingOperation.Peer, couplingOperation.Wagon, success, reason); } } private void ReplyCoupling(long peer, ZDOID wagon, bool success, string reason) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) _view.InvokeRPC(peer, "VR_CoupleReply", new object[3] { wagon, success, reason }); } private void CouplingReply(long sender, ZDOID wagon, bool success, string reason) { //IL_0009: 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_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 (sender != _couplingClientOwner || wagon != _couplingClientWagon || ((ZDOID)(ref _couplingClientWagon)).IsNone()) { return; } _couplingClientWagon = ZDOID.None; _couplingClientUntil = 0f; if (_contactCouplingClient != null) { if (success) { _contactCouplingClient = null; Tell(Player.m_localPlayer, reason); } else { _contactCouplingClient.Failure = reason; _contactCouplingClient.NextAttempt = Time.unscaledTime + 0.4f; } } else { Tell(Player.m_localPlayer, reason); } } private static bool CompatibleCouplingEngines(IEnumerable members) { RailVehicle railVehicle = null; foreach (RailVehicle member in members) { if (member.IsEngine) { if (!Object.op_Implicit((Object)(object)railVehicle)) { railVehicle = member; } else if (!MultiEngineCompatible(railVehicle, member)) { return false; } } } return true; } private static List PhysicalCouplingNodes(IEnumerable members) { return members.Select((RailVehicle cart) => new RailCouplingNode(cart._identity, cart.IsEngine, cart.LinkAtEnd(front: true), cart.LinkAtEnd(front: false))).ToList(); } private static void ApplyCouplingPlan(IEnumerable members, Dictionary plan) { foreach (RailVehicle member in members) { RailCouplingLinks railCouplingLinks = plan[member._identity]; ZDO zDO = member._view.GetZDO(); zDO.Set("vikingrail_parent", railCouplingLinks.Parent); zDO.Set("vikingrail_next", railCouplingLinks.Next); zDO.Set("vikingrail_front", railCouplingLinks.Front); zDO.Set("vikingrail_parent_front", railCouplingLinks.ParentFront); } } internal static bool TryRerootTrain(RailVehicle newRoot, IReadOnlyList members, out string reason) { reason = "Stop every engine, close cargo, and load the whole train before changing the driving cab."; if (!Object.op_Implicit((Object)(object)newRoot) || !newRoot.Ready || !newRoot.IsEngine || !newRoot.FindRoot(out RailVehicle root) || !ReadCouplingChain(root, out List chain) || members.Count != chain.Count || members.Distinct().Count() != chain.Count || chain.Any((RailVehicle cart) => !members.Contains(cart)) || !CompatibleCouplingEngines(chain)) { return false; } long owner = newRoot._view.GetZDO().GetOwner(); if (owner == 0L || chain.Any((RailVehicle cart) => !cart._view.IsOwner() || cart._view.GetZDO().GetOwner() != owner || cart.DriverId != 0L || Object.op_Implicit((Object)(object)cart._driver) || cart.AutomaticDriveRequested || cart.Speed != 0f || (cart.IsEngine && cart.HasPassengers) || (cart._pendingMount && (Object)(object)cart != (Object)(object)newRoot) || cart._packing || cart._packPending || cart._couplingOperation != null || cart.HasCouplingLease || cart._contactCouplingClient != null || cart.CargoBusy || cart.CargoServiceBusy || cart.MountServiceBusy || RailTurntable.BlocksVehicle(cart) || !cart.TryCursor())) { return false; } if (!RailCouplingGraph.TryRoot(PhysicalCouplingNodes(chain), newRoot._identity, out Dictionary links)) { return false; } ApplyCouplingPlan(chain, links); reason = ""; return true; } private void DetachCouplingParent() { ZDO zDO = _view.GetZDO(); if (IsEngine && !ParentFront) { zDO.Set("vikingrail_front", NextId); zDO.Set("vikingrail_next", ""); } zDO.Set("vikingrail_parent", ""); } private static bool IncomingParentEnd(List chain, int index, bool firstEnd) { if (index != 0) { return chain[index].LinkAtEnd(front: true) == chain[index - 1]._identity; } return firstEnd; } private static bool TryMergedCouplingPlan(RailVehicle authority, RailVehicle parent, bool parentFront, RailVehicle source, bool sourceFront, List all, out Dictionary plan) { List list = PhysicalCouplingNodes(all); for (int i = 0; i < list.Count; i++) { RailCouplingNode railCouplingNode = list[i]; if (railCouplingNode.Identity == parent._identity) { list[i] = new RailCouplingNode(railCouplingNode.Identity, railCouplingNode.Engine, parentFront ? source._identity : railCouplingNode.Front, parentFront ? railCouplingNode.Rear : source._identity); } else if (railCouplingNode.Identity == source._identity) { list[i] = new RailCouplingNode(railCouplingNode.Identity, railCouplingNode.Engine, sourceFront ? parent._identity : railCouplingNode.Front, sourceFront ? railCouplingNode.Rear : parent._identity); } } string root = authority._identity; if (!authority.IsEngine) { RailVehicle railVehicle = all.FirstOrDefault((RailVehicle cart) => cart.IsEngine); if (Object.op_Implicit((Object)(object)railVehicle)) { root = railVehicle._identity; } else if (list.Any((RailCouplingNode node) => node.Identity == root && node.Front.Length != 0 && node.Rear.Length != 0)) { root = list.First((RailCouplingNode node) => node.Front.Length == 0 || node.Rear.Length == 0).Identity; } } return RailCouplingGraph.TryRoot(list, root, out plan); } private void Awake() { _view = ((Component)this).GetComponent(); _body = ((Component)this).GetComponent(); _container = ((Component)this).GetComponent(); _workshop = ((Component)this).GetComponent(); _music = ((Component)this).GetComponent(); _pumpPartner = ((Component)this).GetComponentInChildren(true); _seat = ((Component)this).transform.Find(IsEngine ? "vr_driver" : "vr_push_anchor") ?? ((Component)this).transform; _pump = ((Component)this).transform.Find("vr_pump"); _bronzeFlywheel = ((Component)this).transform.Find("visual/vr_bronze_flywheel"); InitializePassengerCart(); InitializeSteamMachinery(); } private void Start() { if (Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { _ready = true; EnsureIdentity(); Vehicles.Add(this); _view.Register("VR_RequestDrive", (Action)RequestDrive); _view.Register("VR_DriveResponse", (Action)DriveResponse); _view.Register("VR_ReleaseDrive", (Action)ReleaseDrive); InitializeCoupling(); InitializeConsistDrive(); InitializeCargoAccess(); InitializeLinkCleanup(); InitializePacking(); InitializeAutoDrive(); WearNTear component = ((Component)this).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { component.m_onDestroyed = (Action)Delegate.Combine(component.m_onDestroyed, new Action(OnDestroyedPermanently)); } if (Object.op_Implicit((Object)(object)_body)) { _body.isKinematic = true; _body.useGravity = false; } if (_view.IsOwner()) { _view.GetZDO().Set("vikingrail_driver", 0L); PublishMotion(moving: false); } InitializeSmoke(); InitializeLights(); InitializeMovementAudio(); } } private void Update() { //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_038d: 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_02ca: Unknown result type (might be due to invalid IL or missing references) ValidateManualThrottle(); UpdateSmoke(); UpdateMovementAudio(); UpdateSteamMachinery(); if (!_ready || (Object)(object)_view == (Object)null || !_view.IsValid() || UpdatePacking()) { return; } if (_identity.Length == 0) { EnsureIdentity(); } if (!Ready) { return; } UpdateAutoDrive(); UpdateConsistDrive(); UpdateContactCoupling(); UpdateCoupling(); UpdateCargoAccess(); RefreshHandPushAnchor(); if (Object.op_Implicit((Object)(object)_driver) && (!_view.IsOwner() || DriverId != _driver.GetPlayerID())) { StopLocalDriver(); } if (_pendingMount) { Player localPlayer = Player.m_localPlayer; if (Time.time - _requestTime > (ConsistMountRequestPending ? 12f : 6f) || !Object.op_Implicit((Object)(object)localPlayer) || ((Character)localPlayer).IsDead()) { _pendingMount = false; if (Object.op_Implicit((Object)(object)localPlayer)) { _view.InvokeRPC("VR_ReleaseDrive", new object[1] { localPlayer.GetPlayerID() }); } Tell(localPlayer, "Could not take the train controls. Try again."); } else if (_mountGranted && _view.IsOwner() && DriverId == localPlayer.GetPlayerID()) { _pendingMount = false; if (CargoServiceBusy || CouplingServiceBusy || MountServiceBusy) { _view.GetZDO().Set("vikingrail_driver", 0L); Tell(localPlayer, "Wait for storage or coupling to finish before taking the controls."); return; } _cursor = null; if (!TryCursor() || ((Character)localPlayer).IsAttached() || localPlayer.GetDoodadController() != null) { _view.GetZDO().Set("vikingrail_driver", 0L); Tell(localPlayer, "Place the engine on connected track before riding."); return; } if (!HasCompatibleTrack()) { _view.GetZDO().Set("vikingrail_driver", 0L); Tell(localPlayer, "Coal and Eitr engines require metal track. Wooden track supports handcarts, bronze engines and wagons."); return; } if (!IsEngine && (!HandPushAvailable(out string _) || !CanGrantHandPush(localPlayer))) { _view.GetZDO().Set("vikingrail_driver", 0L); Tell(localPlayer, "The cart is no longer available for pushing. Uncouple both ends and clear its rear handle."); return; } _driver = localPlayer; LocalDriven = this; _manualThrottle.Clear(); ResetTrackStops(); _inputTime = Time.time; if (!RefreshFuelInventory()) { OnUseStop(localPlayer); Tell(localPlayer, "Could not synchronize the fuel hopper. Check the mod log."); return; } localPlayer.StartDoodadControl((IDoodadController)(object)this); RailRiderAttachment.ClearWalkingInput(localPlayer); ((Character)localPlayer).AttachStart(_seat, ((Component)this).gameObject, true, false, true, "standing", (Vector3)(IsEngine ? new Vector3(1.4f, 0.2f, 0f) : Vector3.zero), (Transform)null); Status = ((!IsEngine) ? "Hold forward or backward to push slowly. Jump to release the handle." : "Tap forward/backward to adjust throttle. Neutral coasts; Block resets throttle and brakes."); } } if (Object.op_Implicit((Object)(object)_pump) && IsEngine) { float pumpAnimationSpeed = PumpAnimationSpeed; _pumpPhase += pumpAnimationSpeed * Time.deltaTime * 3f; _pump.localRotation = Quaternion.Euler(Mathf.Sin(_pumpPhase) * Mathf.Min(18f, pumpAnimationSpeed * 12f), 0f, 0f); } if (Object.op_Implicit((Object)(object)_bronzeFlywheel) && BronzePowered) { _bronzeFlywheel.Rotate(Vector3.right, PumpVisualSpeed * Time.deltaTime * 180f, (Space)1); } } private void FixedUpdate() { ValidateManualThrottle(); if (StopFollowerSimulation()) { return; } BeginSmokeStep(); BeginMovementAudioStep(); if (!Ready || (!IsEngine && !CanControlRoute) || !_view.IsOwner()) { return; } if (AutomaticDriveRequested && !AutoDriveActive) { StopAutomaticDrive("Automatic drive stopped: its controller or owner is unavailable."); return; } bool autoDriveActive = AutoDriveActive; if (!Object.op_Implicit((Object)(object)_driver) && !autoDriveActive) { _serviceNeedsNeutral = false; ClearPlowIntent(); Speed = 0f; PublishMotion(moving: false); StopFollowerMotion(); _orphanTimer += Time.fixedDeltaTime; if (_orphanTimer > 8f && DriverId != 0L && !_pendingMount) { _view.GetZDO().Set("vikingrail_driver", 0L); } return; } _orphanTimer = 0f; string reason; if (!autoDriveActive && (((Character)_driver).IsDead() || ((Character)_driver).IsTeleporting() || (object)_driver.GetDoodadController() != this || !((Character)_driver).IsAttached())) { StopLocalDriver(); } else if (!IsEngine && !HandPushAvailable(out reason)) { Tell(_driver, reason); StopLocalDriver(); } else if (!RailSettings.Ready) { Halt("Waiting for server railroad settings."); } else { if (autoDriveActive && !RemoteRouteReady()) { return; } if (!TryCursor()) { Halt("Track is missing or not loaded."); return; } if (!HasCompatibleTrack()) { Halt("Coal and Eitr engines require metal track. Wooden track supports handcarts, bronze engines and wagons."); return; } if (AttachedPlowId.Length != 0 && !Object.op_Implicit((Object)(object)MountedPlow)) { Halt("Attached plow is not loaded. Wait nearby for it to appear."); return; } if (AttachedAutoDriveId.Length != 0 && !Object.op_Implicit((Object)(object)MountedAutoDrive)) { Halt("Automatic controller is not loaded. Wait nearby for it to appear."); return; } RailAutoDrive mountedAutoDrive = MountedAutoDrive; if (Object.op_Implicit((Object)(object)mountedAutoDrive) && !mountedAutoDrive.View.IsOwner()) { mountedAutoDrive.View.ClaimOwnership(); if (!mountedAutoDrive.View.IsOwner()) { Halt("Waiting for the automatic controller's network owner.", keepPlowIntent: false, keepAutomaticDrive: true); return; } } if (!BuildTrain(out List train, out string failure)) { Halt(failure); return; } if (CouplingBlocksMovement || CargoAccessBlocksMovement(train) || RailMountCart.TrainBusy(train)) { _serviceNeedsNeutral = true; Halt("Train parked for coupling or storage access. Close storage before departing."); return; } if (_serviceNeedsNeutral) { Halt("Release forward/backward controls, then press again to depart."); if (DrivingControlsAvailable && Time.time - _inputTime < 0.3f && Mathf.Abs(_throttle) <= 0.05f) { _serviceNeedsNeutral = false; } return; } if (!RailMountCart.PrepareTrain(train, out string reason2)) { Halt(reason2); return; } if (!RailSwitch.TryReserveTrainRoute(this, train, out string reason3)) { Halt(reason3, keepPlowIntent: false, keepAutomaticDrive: true); return; } WagonCount = train.Count((RailVehicle cart) => (Object)(object)cart != (Object)(object)this && !cart.IsEngine); if (!TryFormation(train, out Dictionary slots, out Dictionary reversed)) { Halt("Coupling layout is inconsistent. Uncouple and reconnect the wagons."); return; } for (int num = 1; num < train.Count; num++) { double num2 = (float)Math.Abs(slots[train[num]]) * 2.8f; RailCursor railCursor = ((slots[train[num]] > 0) ? _cursor.Value : _cursor.Value.Reversed()); if (!RailSegment.Network.TryDistanceAlongRoute(railCursor, train[num]._cursor.Value, num2 + 0.65, out var distance) || Math.Abs(distance - num2) > 0.65) { Halt("A wagon is out of alignment. Uncouple and reconnect it on this route."); return; } } foreach (RailVehicle item in train) { if (!item.HasCompatibleTrack()) { Halt("Coal and Eitr engines require metal track. Wooden track supports handcarts, bronze engines and wagons."); return; } if ((Object)(object)item != (Object)(object)this && item.IsEngine && (!MultiEngineCompatible(this, item) || item.DriverId != 0L || Object.op_Implicit((Object)(object)item._driver) || item._pendingMount || item.AutomaticDriveRequested)) { Halt("Use one driver and matching engine types throughout the train."); return; } if (item.AttachedPlowId.Length != 0 && !Object.op_Implicit((Object)(object)item.MountedPlow)) { Halt("Wait for every attached plow to load."); return; } if ((item.HasPlowAt(front: true) && item.HasCouplingAt(front: true)) || (item.HasPlowAt(front: false) && item.HasCouplingAt(front: false))) { Halt("A plow overlaps a coupling. Detach the plow or uncouple that end."); return; } if (item.CargoBusy) { Halt("Close all cargo containers before moving."); return; } if (!item._view.IsOwner()) { if (item.IsEngine) { Halt("An engine's ownership changed. Park and take the controls again."); return; } item._view.ClaimOwnership(); item._cursor = null; Halt("Taking control of cargo wagons…", keepPlowIntent: false, keepAutomaticDrive: true); return; } if (Object.op_Implicit((Object)(object)item._container) && !RailCargoInventory.TryRefreshForOwnership(item._container, out string error)) { Halt(error); return; } if (Object.op_Implicit((Object)(object)item.MountedPlow) && !item.MountedPlow.View.IsOwner()) { item.MountedPlow.View.ClaimOwnership(); if (!item.MountedPlow.View.IsOwner()) { Halt("Waiting for the plow's network owner.", keepPlowIntent: false, keepAutomaticDrive: true); return; } } } BeginFollowerMotion(train); if (!RailTorchMounts.PrepareTrain(train, out string reason4)) { Halt(reason4); return; } float num3 = Mathf.Min(Time.fixedDeltaTime, 0.05f); bool flag = autoDriveActive || Time.time - _inputTime < 0.3f; float num4 = (autoDriveActive ? 1f : (flag ? ManualDriveInput : 0f)); bool flag2 = autoDriveActive || DrivingControlsAvailable; if (!flag2) { num4 = 0f; } bool flag3 = (!autoDriveActive && _brake) || !flag2 || !flag; if (HoldAtBrakeTrack(train, num4, flag2 && flag)) { return; } int num5 = train.Sum((RailVehicle v) => v.PassengerCount); float num6 = train.Sum((RailVehicle v) => (Object.op_Implicit((Object)(object)v._container) ? v._container.GetInventory().GetTotalWeight() : 0f) + v.MountedWeight) + (float)num5 * 80f; float num7 = 1f + (float)WagonCount * 0.12f + num6 / 600f; Player player = null; _teamwork = IsTandemHandcart && Object.op_Implicit((Object)(object)_pumpPartner) && _pumpPartner.TryGetPoweredPartner((float)RailSettings.TandemHandcartStaminaPerSecond * num7 * num3, out player); float num8 = (IsEngine ? ((float)PumpingStaminaRate * num7 * num3) : 0f); List list = (FuelPowered ? AvailableEngines(train, num3) : new List()); float cost; bool flag4 = (FuelPowered ? (list.Count > 0) : (RailPumpPartner.NativeCost(num8, out cost) && (cost <= 0f || (Object.op_Implicit((Object)(object)_driver) && ((Character)_driver).HaveStamina(cost))))); ActiveEngineCount = (FuelPowered ? list.Count : (flag4 ? 1 : 0)); if (ActiveEngineCount > 21) { Halt("Too many engines in this train. Uncouple extra engines before driving."); return; } if (autoDriveActive && !flag4) { Halt("Automatic drive stopped: out of " + FuelName + ". Refill and activate the controller again."); return; } if (!autoDriveActive && IsEngine && !flag4) { _manualThrottle.Clear(); } bool flag5 = Mathf.Abs(num4) > 0.05f && !flag3 && flag4; RailPose railPose = RailVehiclePose.Sample(RailSegment.Network, _cursor.Value); RailEngineKind engine = RailTraction.Resolve(CoalPowered, BronzePowered, IsTandemHandcart, _teamwork, EitrPowered); int wagonCount = train.Count - 1 - Math.Max(0, ActiveEngineCount - 1); RailConsistPowerResult railConsistPowerResult = (IsEngine ? RailConsistPower.Evaluate(engine, RailSettings.Current, wagonCount, num6, railPose.Tangent.Y, num4, ActiveEngineCount) : default(RailConsistPowerResult)); RailTractionResult traction = railConsistPowerResult.Traction; double num9; if (IsEngine) { RailMomentumResult railMomentumResult = RailMomentum.Step(Speed, num4, flag4, flag3, traction.TargetSpeed, traction.PoweredAcceleration, (float)railConsistPowerResult.MaximumSpeed, TrainGrade(train, reversed), num3); Speed = (float)railMomentumResult.Speed; num9 = railMomentumResult.PoweredSeconds; } else { Speed = (float)RailHandPush.StepSpeed(Speed, flag5 ? num4 : 0f, flag3, num3); num9 = (flag5 ? num3 : 0f); } bool flag6 = num9 > 0.0; if (IsTandemHandcart) { Speed = (float)RailTandemPolicy.LimitSoloSpeed(Speed, _teamwork, RailSettings.HandcartMaxSpeed); } if (Speed == 0f && !flag6) { ClearPlowIntent(); Speed = 0f; PublishMotion(moving: false); StopFollowerMotion(); Status = ((!(Mathf.Abs(num4) > 0.05f) || flag6 || flag3) ? (IsEngine ? "Stopped. Jump to dismount." : "Stopped. Jump to release the handle.") : (FuelPowered ? ("Out of " + FuelName + ". Dismount, then alternate-use the engine to refill its hopper.") : "Rest to recover stamina.")); return; } bool flag7 = Speed >= 0f; _view.GetZDO().Set("vikingrail_plow_drive_forward", flag7); int num10 = LeadingIndex(train, slots, flag7); RailCursor cursor = (flag7 ? _cursor.Value : _cursor.Value.Reversed()); float num11 = Mathf.Abs(Speed) * num3; if (num11 <= 0f) { ClearPlowIntent(); return; } bool restricted; double num12 = LimitTrainAtWoodenTrack(train, reversed, flag7, num11, out restricted); if (restricted && num12 <= 1E-06) { Halt("Coal and Eitr engines require metal track. Wooden track supports handcarts, bronze engines and wagons."); return; } RailCursor cursor2 = train[num10]._cursor.Value; if (flag7 == reversed[train[num10]]) { cursor2 = cursor2.Reversed(); } RailAdvanceResult railAdvanceResult = RailSegment.Network.Advance(cursor2, num12); RailSafetyResult stop = LimitAtTrackStops(train, flag7, railAdvanceResult.DistanceTravelled); if (stop.HasStop && stop.Distance <= 1E-06) { ArriveAtTrackStop(stop); return; } if (railAdvanceResult.Stopped && stop.Distance <= 1E-06) { Halt("End of connected track."); return; } ContactCoupling contactCoupling = (autoDriveActive ? null : FindContactCoupling(train, flag7, stop.Distance)); RailAdvanceResult railAdvanceResult2 = RailSegment.Network.Advance(cursor, contactCoupling?.Distance ?? stop.Distance); RailCursor railCursor2 = (flag7 ? railAdvanceResult2.Cursor : railAdvanceResult2.Cursor.Reversed()); List list2 = new List { railCursor2 }; for (int num13 = 1; num13 < train.Count; num13++) { if (!RailCoupledLayout.TryCursor(RailSegment.Network, railCursor2, slots[train[num13]], reversed[train[num13]], 2.799999952316284, out var cursor3)) { Halt("Not enough connected track beneath the whole train."); return; } list2.Add(cursor3); } if (!CheckRelocations(train, list2, flag7, railAdvanceResult2.DistanceTravelled) || !RailGate.AllowTrainStep(this, train, list2, flag7)) { return; } RailVehicle railVehicle = train[num10]; bool num14 = Object.op_Implicit((Object)(object)railVehicle.MountedPlow) && railVehicle.MountedPlowFront == (flag7 != reversed[railVehicle]); if ((Object)(object)_activePlowCarrier != (Object)(object)railVehicle || (Object.op_Implicit((Object)(object)_activePlowCarrier) && _activePlowCarrier._view.GetZDO().GetBool("vikingrail_plow_intent_forward", true) != flag7)) { ClearPlowIntent(); } float num15 = ((num14 && (Mathf.Abs(Speed) > 0.05f || (flag6 && (flag7 ? (num4 > 0f) : (num4 < 0f))))) ? Mathf.Max(0.1f, Mathf.Abs(Speed)) : 0f); float num16 = ((num15 > 0f) ? Mathf.Max((float)railAdvanceResult2.DistanceTravelled, railVehicle._plowContactTravel) : 0f); if (num15 > 0f) { num15 = Mathf.Max(num15, railVehicle._plowContactSpeed); } HashSet hashSet = new HashSet(); for (int num17 = 0; num17 < train.Count; num17++) { RailPose pose = RailVehiclePose.Sample(RailSegment.Network, list2[num17]); if (!IsEngine && PushOperatorPathBlocked(list2[num17], _driver)) { Halt("No room for the person pushing. Clear the way or push in the other direction."); return; } if (train[num17].IsObstructed(pose, train, _driver, (num17 == num10) ? hashSet : null, (num17 == num10) ? num15 : 0f, num17 == num10, flag7 != reversed[train[num17]], num16)) { ClearPlowIntent(); Halt("Track obstructed. Clear the way."); return; } } if (hashSet.Count != 0) { _activePlowCarrier = railVehicle; railVehicle.NudgeWithPlow(hashSet, num15, num16, flag7); Halt("Plow clearing creatures to the side. Waiting for the track to clear.", keepPlowIntent: true, keepAutomaticDrive: true); return; } ClearPlowIntent(); double num18 = num9 * Math.Min(1.0, railAdvanceResult2.DistanceTravelled / (double)num11); if (flag6 && railAdvanceResult2.DistanceTravelled > 0.0 && FuelPowered && !BurnConsistFuel(list, num18)) { Halt("Out of " + FuelName + ". Refill the engine's hopper while stopped."); return; } for (int num19 = 0; num19 < train.Count; num19++) { train[num19].MoveTo(list2[num19]); } PublishConsistMotion(train, reversed, list, (float)railAdvanceResult2.DistanceTravelled, num3, flag6); if (flag6 && railAdvanceResult2.DistanceTravelled > 0.0 && !FuelPowered && num8 > 0f) { float num20 = num8 * (float)(num18 / (double)num3); ((Character)_driver).UseStamina(num20); if (_teamwork && Object.op_Implicit((Object)(object)player) && Object.op_Implicit((Object)(object)_pumpPartner)) { _pumpPartner.UsePartnerStamina(player, num20); } } if (contactCoupling != null) { BeginContactCoupling(contactCoupling); return; } if (railAdvanceResult2.Stopped) { Halt((railAdvanceResult2.StopReason == RailStopReason.AmbiguousJunction) ? "Ambiguous junction. Use one continuous route." : "End of connected track."); return; } if (stop.HasStop) { ArriveAtTrackStop(stop); return; } if (railAdvanceResult.Stopped) { Halt("End of connected track."); return; } if (restricted && railAdvanceResult2.DistanceTravelled >= num12 - 1E-06) { Halt("Coal and Eitr engines require metal track. Wooden track supports handcarts, bronze engines and wagons."); return; } Status = ((!IsEngine) ? "Pushing cart slowly. Push forward into a parked train's rear to couple." : ("Load: " + num6.ToString("0") + " weight | " + num5 + " passengers | " + (FuelPowered ? ("Available engines: " + ActiveEngineCount + " | ") : "") + (IsTandemHandcart ? ((_teamwork ? "Two pumping" : "Solo pumping") + " | ") : "") + ((!flag6) ? (flag3 ? "Braking" : "Coasting") : (EitrPowered ? "Eitr power" : ((!FuelPowered) ? "Pumping" : (BronzePowered ? "Wood power" : "Coal power")))))); } } private static double TrainGrade(List train, Dictionary reversed) { List list = new List(train.Count); List list2 = new List(train.Count); foreach (RailVehicle item in train) { list.Add(RailVehiclePose.Sample(RailSegment.Network, item._cursor.Value).Tangent.Y * (double)((!reversed[item]) ? 1 : (-1))); double num = (Object.op_Implicit((Object)(object)item._body) ? Math.Max(1f, item._body.mass) : 100f); double num2 = (Object.op_Implicit((Object)(object)item._container) ? Math.Max(0f, item._container.GetInventory().GetTotalWeight()) : 0f); list2.Add(num + num2 + (double)item.MountedWeight + (double)(item.PassengerCount * 80)); } return RailMomentum.WeightedGrade(list, list2); } private bool TryCursor() { //IL_00a4: 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_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) if (!Ready) { return false; } RailPath path; if (_cursor.HasValue && IsLocallySimulatedDrive) { return RailSegment.Network.TryGetPath(_cursor.Value.SegmentId, out path); } if (_cursor.HasValue && _view.IsOwner() && RailVehicleAnchor.TryRestore(RailSegment.Network, _cursor.Value.SegmentId, _cursor.Value.Distance, _cursor.Value.Direction, RailSegment.ToRail(((Component)this).transform.position), RailSegment.ToRail(((Component)this).transform.forward), out var cursor)) { _cursor = cursor; return true; } _cursor = null; ZDO zDO = _view.GetZDO(); string text = zDO.GetString("vikingrail_track", ""); if (!string.IsNullOrEmpty(text) && RailSegment.Network.TryGetPath(text, out RailPath path2)) { if (Vector3.Distance(((Component)this).transform.position, zDO.GetPosition()) <= 0.75f && RailVehicleAnchor.TryRestore(RailSegment.Network, text, zDO.GetFloat("vikingrail_distance", float.NaN), zDO.GetInt("vikingrail_direction", 1), RailSegment.ToRail(zDO.GetPosition()), RailSegment.ToRail(zDO.GetRotation() * Vector3.forward), out var cursor2)) { _cursor = cursor2; return true; } RailProjection railProjection = path2.Project(RailSegment.ToRail(((Component)this).transform.position)); if (railProjection.Separation > 0.75) { return false; } _cursor = new RailCursor(text, railProjection.Distance, (_view.GetZDO().GetInt("vikingrail_direction", 1) >= 0) ? 1 : (-1)); } else { if (text.Length != 0 && (Object.op_Implicit((Object)(object)_driver) || TrainOccupied)) { return false; } if (!RailSegment.Network.TryProject(RailSegment.ToRail(((Component)this).transform.position), (text.Length == 0) ? 0.75 : 0.3, out var cursor3, out var _)) { return false; } Vector3 val = RailSegment.ToUnity(RailSegment.Network.Sample(cursor3).Tangent); _cursor = ((Vector3.Dot(((Component)this).transform.forward, val) >= 0f) ? cursor3 : cursor3.Reversed()); } return true; } private void MoveTo(RailCursor cursor) { //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) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_0067: 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_004f: 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) _cursor = cursor; RailPose pose = RailVehiclePose.Sample(RailSegment.Network, cursor); Vector3 val = RailSegment.ToUnity(pose.Position); Quaternion val2 = Quaternion.LookRotation(RailSegment.ToUnity(pose.Tangent), Vector3.up); if (Object.op_Implicit((Object)(object)_body)) { _body.position = val; _body.rotation = val2; } ((Component)this).transform.SetPositionAndRotation(val, val2); SaveCursor(cursor, pose); RefreshHandPushAnchor(); if (Object.op_Implicit((Object)(object)_driver)) { RailRiderAttachment.Synchronize(_driver); } FollowMountedTorches(); FollowMountedObjects(); FollowAutomaticController(); } private void SaveCursor(RailCursor cursor, RailPose pose) { //IL_004a: 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_0065: Unknown result type (might be due to invalid IL or missing references) ZDO zDO = _view.GetZDO(); zDO.Set("vikingrail_track", cursor.SegmentId); zDO.Set("vikingrail_direction", cursor.Direction); zDO.Set("vikingrail_distance", (float)cursor.Distance); zDO.SetPosition(RailSegment.ToUnity(pose.Position)); zDO.SetRotation(Quaternion.LookRotation(RailSegment.ToUnity(pose.Tangent), Vector3.up)); } private bool IsObstructed(RailPose pose, List train, Player? driver, HashSet? plowTargets = null, float approachSpeed = 0f, bool? leading = null, bool movingForward = true, float plowSweepDistance = 0f) { //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) //IL_0078: 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_007e: 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_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_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019b: 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) //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) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: 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_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0294: 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_029a: 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_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Unknown result type (might be due to invalid IL or missing references) //IL_036e: Unknown result type (might be due to invalid IL or missing references) //IL_036f: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Unknown result type (might be due to invalid IL or missing references) //IL_038f: Unknown result type (might be due to invalid IL or missing references) //IL_03c3: Unknown result type (might be due to invalid IL or missing references) //IL_03c5: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Unknown result type (might be due to invalid IL or missing references) //IL_03cf: Unknown result type (might be due to invalid IL or missing references) //IL_03d2: Unknown result type (might be due to invalid IL or missing references) //IL_03d9: Unknown result type (might be due to invalid IL or missing references) //IL_03de: Unknown result type (might be due to invalid IL or missing references) //IL_03f2: Unknown result type (might be due to invalid IL or missing references) //IL_03fd: Unknown result type (might be due to invalid IL or missing references) //IL_0694: Unknown result type (might be due to invalid IL or missing references) //IL_0699: Unknown result type (might be due to invalid IL or missing references) //IL_06aa: Unknown result type (might be due to invalid IL or missing references) //IL_06ac: Unknown result type (might be due to invalid IL or missing references) //IL_06b8: Unknown result type (might be due to invalid IL or missing references) //IL_06b9: Unknown result type (might be due to invalid IL or missing references) //IL_06be: Unknown result type (might be due to invalid IL or missing references) //IL_06c7: Unknown result type (might be due to invalid IL or missing references) //IL_06cc: Unknown result type (might be due to invalid IL or missing references) //IL_06d1: Unknown result type (might be due to invalid IL or missing references) //IL_06eb: Unknown result type (might be due to invalid IL or missing references) //IL_0707: Unknown result type (might be due to invalid IL or missing references) Quaternion val = Quaternion.LookRotation(RailSegment.ToUnity(pose.Tangent), Vector3.up); Vector3 center = default(Vector3); ((Vector3)(ref center))..ctor(0f, CoalPowered ? 1.5f : ((BronzePowered || EitrPowered) ? 1.4f : (IsPassengerCart ? 1.6f : (IsTandemHandcart ? 1.1f : 0.9f))), 0f); Vector3 end = RailSegment.ToUnity(pose.Position) + val * center; Vector3 extents = default(Vector3); ((Vector3)(ref extents))..ctor((IsPassengerCart || BronzePowered || EitrPowered || IsTandemHandcart) ? 0.82f : 0.65f, CoalPowered ? 1.15f : ((BronzePowered || EitrPowered) ? 1.05f : (IsPassengerCart ? 1.25f : (IsTandemHandcart ? 0.75f : 0.5f))), IsTandemHandcart ? 1.35f : 1.05f); if (CoalPowered) { ((Vector3)(ref extents))..ctor(0.91f, 1.15f, 1.13f); } if (IsMountCart) { ((Vector3)(ref extents))..ctor(0.82f, 0.5f, 1.2f); } if (Object.op_Implicit((Object)(object)_music)) { ((Vector3)(ref center))..ctor(0f, 1.5f, 0f); ((Vector3)(ref extents))..ctor(0.85f, 1.15f, 1.2f); end = RailSegment.ToUnity(pose.Position) + val * center; } if (IsPassengerCart) { ((Vector3)(ref center))..ctor(0f, 1.9f, 0f); ((Vector3)(ref extents))..ctor(1.28f, 1.55f, 1.38f); end = RailSegment.ToUnity(pose.Position) + val * center; } if (IsPumpkinCart) { ((Vector3)(ref center))..ctor(0f, 1.72f, 0f); ((Vector3)(ref extents))..ctor(1.13f, 1.41f, 1.2f); end = RailSegment.ToUnity(pose.Position) + val * center; } if (Object.op_Implicit((Object)(object)_workshop) && _workshop.TryGetCollisionBounds(out var bounds)) { center = ((Bounds)(ref bounds)).center; extents = ((Bounds)(ref bounds)).extents; end = RailSegment.ToUnity(pose.Position) + val * center; } List list = new List(); Vector3 start = ((Component)this).transform.TransformPoint(center); AddVolumeHits(list, start, end, extents, val); AddAttachmentObstacleVolumes(list, RailSegment.ToUnity(pose.Position), val); if (CanHandPush) { Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(0f, 0.975f, -1.145f); AddVolumeHits(list, ((Component)this).transform.TransformPoint(val2), RailSegment.ToUnity(pose.Position) + val * val2, new Vector3(0.47f, 0.105f, 0.145f), val); } if (Object.op_Implicit((Object)(object)MountedPlow)) { Vector3 val3 = RailPlow.SocketOffsetAt(MountedPlowFront) + new Vector3(0f, 0.625f, 0f); AddVolumeHits(list, ((Component)this).transform.TransformPoint(val3), RailSegment.ToUnity(pose.Position) + val * val3, new Vector3(1.05f, 0.4f, 0.32f), val); if (plowTargets != null && approachSpeed > 0f && _plowContactTravel > 0f) { List list2 = new List(); Vector3 val4 = ((Component)this).transform.TransformPoint(val3); AddVolumeHits(list2, val4, val4 + PlowForward * plowSweepDistance, new Vector3(1.05f, 0.4f, 0.32f), ((Component)this).transform.rotation); foreach (Collider item in list2) { if (Object.op_Implicit((Object)(object)item) && Object.op_Implicit((Object)(object)((Component)item).GetComponentInParent())) { list.Add(item); } } } } foreach (Collider item2 in list) { if (!Object.op_Implicit((Object)(object)item2) || Object.op_Implicit((Object)(object)((Component)item2).GetComponentInParent()) || Object.op_Implicit((Object)(object)((Component)item2).GetComponentInParent())) { continue; } RailVehicle componentInParent = ((Component)item2).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent) && train.Contains(componentInParent)) { continue; } RailPlow componentInParent2 = ((Component)item2).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent2) && Object.op_Implicit((Object)(object)componentInParent2.Engine) && train.Contains(componentInParent2.Engine) && (Object)(object)componentInParent2.Engine.MountedPlow == (Object)(object)componentInParent2) { continue; } RailAutoDrive componentInParent3 = ((Component)item2).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent3) && Object.op_Implicit((Object)(object)componentInParent3.Engine) && train.Contains(componentInParent3.Engine) && (Object)(object)componentInParent3.Engine.MountedAutoDrive == (Object)(object)componentInParent3) { continue; } RailMountedTorch componentInParent4 = ((Component)item2).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent4) && Object.op_Implicit((Object)(object)componentInParent4.Vehicle) && train.Contains(componentInParent4.Vehicle)) { continue; } RailMountedObject componentInParent5 = ((Component)item2).GetComponentInParent(); if ((Object.op_Implicit((Object)(object)componentInParent5) && componentInParent5.IsAttached && Object.op_Implicit((Object)(object)componentInParent5.Vehicle) && train.Contains(componentInParent5.Vehicle)) || (Object.op_Implicit((Object)(object)driver) && (Object)(object)((Component)item2).GetComponentInParent() == (Object)(object)driver)) { continue; } Player passenger = ((Component)item2).GetComponentInParent(); if ((Object.op_Implicit((Object)(object)passenger) && RailPassengerSeat.IsPassenger(passenger, train)) || (Object.op_Implicit((Object)(object)passenger) && train.Any((RailVehicle v) => Object.op_Implicit((Object)(object)v._pumpPartner) && v._pumpPartner.TryRider(passenger, out Transform _)))) { continue; } Character componentInParent6 = ((Component)item2).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent6)) { if (!componentInParent6.IsPlayer() && componentInParent6.IsDead()) { continue; } if (plowTargets == null || !(approachSpeed > 0f) || !CanPlow(componentInParent6, approachSpeed, plowSweepDistance)) { if (!componentInParent6.IsPlayer() && leading.HasValue) { Vector3 centerPoint = componentInParent6.GetCenterPoint(); float radius = componentInParent6.GetRadius(); RailVector localCenter = RailSegment.ToRail(((Component)this).transform.InverseTransformPoint(centerPoint)); RailVector localCenter2 = RailSegment.ToRail(Quaternion.Inverse(val) * (centerPoint - RailSegment.ToUnity(pose.Position))); if (!RailCreatureClearance.BlocksLeadingEnd(leading.Value, movingForward, localCenter, radius, extents.z) && !RailCreatureClearance.BlocksLeadingEnd(leading.Value, movingForward, localCenter2, radius, extents.z)) { continue; } } return true; } plowTargets.Add(componentInParent6); } else if (!Object.op_Implicit((Object)(object)((Component)item2).GetComponentInParent()) && !Object.op_Implicit((Object)(object)((Component)item2).GetComponentInParent()) && !RailNaturalResource.IgnoreRailObstacle(item2) && (!Object.op_Implicit((Object)(object)_body) || !Physics.GetIgnoreLayerCollision(((Component)this).gameObject.layer, ((Component)item2).gameObject.layer))) { return true; } } return false; } private bool BuildTrain(out List train, out string failure) { failure = "A coupled wagon is missing or its links are inconsistent. Load the whole train before moving."; if (!ReadCouplingChain(this, out train)) { return false; } failure = "A wagon's track is missing or not loaded."; if (train.Any((RailVehicle cart) => !cart.TryCursor())) { return false; } failure = ""; return true; } private bool FindRoot(out RailVehicle root) { root = this; HashSet visited = new HashSet(); while (root.Ready) { if (!RailTrainLimits.TryVisit(visited, root._identity)) { return false; } if (root.ParentId.Length == 0) { return true; } RailVehicle railVehicle = Find(root.ParentId); if (!Object.op_Implicit((Object)(object)railVehicle) || (railVehicle.NextId != root._identity && railVehicle.FrontId != root._identity)) { return false; } root = railVehicle; } return false; } private static RailVehicle? Find(string id) { return Vehicles.FirstOrDefault((RailVehicle v) => Object.op_Implicit((Object)(object)v) && v.Ready && v._identity == id); } private static RailVehicle? FindSession(ZDOID id) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) return Vehicles.FirstOrDefault((RailVehicle v) => Object.op_Implicit((Object)(object)v) && v.Ready && v.Id == id); } private void Halt(string reason, bool keepPlowIntent = false, bool keepAutomaticDrive = false) { if (!keepPlowIntent && _manualThrottle.Notch != 0) { _manualThrottle.Clear(); } if (AutomaticDriveRequested && !keepAutomaticDrive) { ClearAutomaticDrive(reason + " Activate the controller to depart again."); } if (!keepPlowIntent) { ClearPlowIntent(); } Speed = 0f; PublishMotion(moving: false); StopSmoke(); StopMovementAudio(); StopFollowerMotion(); Status = reason; } private static void Tell(Player? player, string text) { if (Object.op_Implicit((Object)(object)player)) { ((Character)player).Message((MessageType)2, text, 0, (Sprite)null, false); } } public float GetHoverOffset() { return 0f; } public string GetHoverName() { if (!Object.op_Implicit((Object)(object)_music)) { if (!Object.op_Implicit((Object)(object)_workshop)) { if (!EitrPowered) { if (!CoalPowered) { if (!BronzePowered) { if (!IsTandemHandcart) { if (!IsEngine) { if (!IsPassengerCart) { if (!IsMountCart) { return "Rail cargo wagon"; } return "Rail mounting cart"; } return "Rail passenger cart"; } return "Rail handcart"; } return "Two-person rail handcart"; } return "Bronze rail engine"; } return "Coal locomotive"; } return "Eitr rail engine"; } return _workshop.DisplayName; } return _music.DisplayName; } public string GetHoverText() { if (!Object.op_Implicit((Object)(object)_music)) { if (!Object.op_Implicit((Object)(object)_workshop)) { return Localization.instance.Localize(GetHoverName() + (IsEngine ? ((FuelPowered ? ("\nFuel: " + FuelStatus) : "") + (HasPlow ? ("\n" + (MountedPlowFront ? "Front" : "Rear") + " plow attached") : "") + ((AttachedAutoDriveId.Length != 0) ? ("\n" + (AutomaticDriveRequested ? "Automatic drive active — stop using its lever." : AutoDriveStatus)) : "") + "\n[$KEY_Use] Take controls" + (FuelPowered ? ("\n[$KEY_AltPlace + $KEY_Use] Open fuel hopper (" + FuelName + ")") : "")) : ((IsPassengerCart ? "\nUse either chair to sit (2 seats)." : (IsMountCart ? "\nUse either mounting pad to attach or detach a nearby piece." : "\n[$KEY_Use] Open cargo")) + "\n[$KEY_AltPlace + $KEY_Use] Couple / uncouple"))); } return _workshop.HoverText(); } return _music.HoverText(); } public bool UseItem(Humanoid user, ItemData item) { return false; } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_0175: Unknown result type (might be due to invalid IL or missing references) if (hold || !Ready) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val != (Object)(object)Player.m_localPlayer) { return false; } if (Object.op_Implicit((Object)(object)_workshop)) { return _workshop.Interact(val, alt); } if (Object.op_Implicit((Object)(object)_music)) { if (!alt) { return _music.Interact((Humanoid)(object)val, hold: false); } return ToggleCoupling(val); } if (!IsEngine) { if (!alt) { if (Object.op_Implicit((Object)(object)_container)) { return _container.Interact(user, false, false); } return false; } return ToggleCoupling(val); } if (FuelPowered && alt) { if (Object.op_Implicit((Object)(object)_container)) { return _container.Interact(user, false, true); } return false; } if (FuelPowered && FindRoot(out RailVehicle root) && ReadCouplingChain(root, out List chain) && chain.Count((RailVehicle cart) => cart.IsEngine) > 1) { return BeginConsistDrive(val); } if (_pendingMount) { return false; } if (AutomaticDriveRequested) { Tell(val, "Stop automatic drive with its controller before taking the controls."); return false; } if (CargoServiceBusy || CouplingServiceBusy || MountServiceBusy) { Tell(val, "Wait for storage or coupling to finish before taking the controls."); return false; } if (((Character)val).IsAttached() || val.GetDoodadController() != null || ((Character)val).InPlaceMode()) { return false; } if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return false; } if (AttachedPlowId.Length != 0 && !Object.op_Implicit((Object)(object)MountedPlow)) { Tell(val, "Wait for the attached plow to load before boarding."); return false; } if (AttachedAutoDriveId.Length != 0 && !Object.op_Implicit((Object)(object)MountedAutoDrive)) { Tell(val, "Wait for the automatic controller to load before boarding."); return false; } if (!TryCursor()) { Tell(val, "Build the engine directly on a railway."); return false; } if (!HasCompatibleTrack()) { Tell(val, "Coal and Eitr engines require metal track. Wooden track supports handcarts, bronze engines and wagons."); return false; } if (!BuildTrain(out List train, out string failure)) { Tell(val, failure); return false; } if (train.Any((RailVehicle v) => v.AttachedPlowId.Length != 0 && !Object.op_Implicit((Object)(object)v.MountedPlow))) { Tell(val, "Wait for every attached plow to load before boarding."); return false; } if (train.Any((RailVehicle v) => v.CargoBusy || v.MountServiceBusy)) { Tell(val, "Close all cargo containers first."); return false; } _pendingMount = true; _mountGranted = false; _requestTime = Time.time; _requestOwner = _view.GetZDO().GetOwner(); _view.InvokeRPC("VR_RequestDrive", new object[1] { val.GetPlayerID() }); return false; } private bool ValidRequester(long sender, long playerId, out Player player) { //IL_002b: 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) player = Player.GetPlayer(playerId); if (Object.op_Implicit((Object)(object)player) && !((Character)player).IsDead() && ((Character)player).GetOwner() == sender) { return Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position) < 5f; } return false; } private void RequestDrive(long sender, long playerId) { //IL_0202: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !_view.IsOwner() || (!IsEngine && !CanHandPush) || !ValidRequester(sender, playerId, out Player player)) { return; } if (ParentId.Length != 0 || (ReadCouplingChain(this, out List chain) && chain.Count((RailVehicle c) => c.IsEngine) > 1)) { _view.InvokeRPC(sender, "VR_DriveResponse", new object[1] { false }); return; } if (AutomaticDriveRequested || DriverId != 0L || CargoServiceBusy || CouplingServiceBusy || MountServiceBusy || (AttachedPlowId.Length != 0 && !Object.op_Implicit((Object)(object)MountedPlow)) || (AttachedAutoDriveId.Length != 0 && !Object.op_Implicit((Object)(object)MountedAutoDrive)) || !BuildTrain(out List train, out string failure) || !HasCompatibleTrack() || train.Any((RailVehicle v) => v.CargoBusy || v.MountServiceBusy || (v.AttachedPlowId.Length != 0 && !Object.op_Implicit((Object)(object)v.MountedPlow))) || !RailMountCart.PrepareTrain(train, out failure) || (!IsEngine && !CanGrantHandPush(player))) { _view.InvokeRPC(sender, "VR_DriveResponse", new object[1] { false }); return; } _view.GetZDO().Set("vikingrail_driver", playerId); foreach (RailVehicle item in train) { item.TransferPlowOwnership(sender); if (!item._view.IsOwner()) { item._view.ClaimOwnership(); } item.SaveCursor(item._cursor.Value, RailVehiclePose.Sample(RailSegment.Network, item._cursor.Value)); item._view.GetZDO().SetOwner(sender); ZDOMan.instance.ForceSendZDO(sender, item.Id); } _view.InvokeRPC(sender, "VR_DriveResponse", new object[1] { true }); _orphanTimer = 0f; } private void DriveResponse(long sender, bool granted) { if (_pendingMount && sender == _requestOwner) { _mountGranted = granted; if (!granted) { _pendingMount = false; Tell(Player.m_localPlayer, IsEngine ? "This engine is occupied or its cargo is unavailable." : "This cart cannot be pushed now. Uncouple both ends, close cargo, and have everyone dismount."); } } } private void ReleaseDrive(long sender, long playerId) { if (Ready && _view.IsOwner() && DriverId == playerId) { Player player = Player.GetPlayer(playerId); if (Object.op_Implicit((Object)(object)player) && ((Character)player).GetOwner() == sender) { _view.GetZDO().Set("vikingrail_driver", 0L); } } } public void ApplyControlls(Vector3 moveDir, Vector3 lookDir, bool run, bool autoRun, bool block) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) _throttle = Mathf.Clamp(moveDir.z, -1f, 1f); _brake = block; if (IsEngine) { ApplyManualThrottle(); } if (Mathf.Abs(ManualDriveInput) <= 0.05f || block || !DrivingControlsAvailable) { ClearPlowIntent(); } _inputTime = Time.time; } public Component GetControlledComponent() { return (Component)(object)this; } public Vector3 GetPosition() { //IL_001f: 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) if (!Object.op_Implicit((Object)(object)_seat)) { return ((Component)this).transform.position; } return _seat.position; } public bool IsValid() { if (Object.op_Implicit((Object)(object)this)) { return Ready; } return false; } public void OnUseStop(Player player) { _manualThrottle.Clear(); _teamwork = false; RailSwitch.ReleaseTrainRoute(this); ClearPlowIntent(); ResetTrackStops(); Speed = 0f; PublishMotion(moving: false); StopSmoke(); StopMovementAudio(); StopFollowerMotion(); _throttle = 0f; _brake = false; if (Ready) { if (_view.IsOwner() && DriverId == player.GetPlayerID()) { _view.GetZDO().Set("vikingrail_driver", 0L); } else { _view.InvokeRPC("VR_ReleaseDrive", new object[1] { player.GetPlayerID() }); } } ((Character)player).AttachStop(); _driver = null; if ((Object)(object)LocalDriven == (Object)(object)this) { LocalDriven = null; } } public void StopLocalDriver() { _manualThrottle.Clear(); Player driver = _driver; if (Object.op_Implicit((Object)(object)driver)) { if ((object)driver.GetDoodadController() == this) { driver.StopDoodadControl(); } else { OnUseStop(driver); } } } private void EnsureIdentity() { _identity = _view.GetZDO().GetString("vikingrail_identity", ""); if (_identity.Length == 0 && _view.IsOwner()) { _identity = Guid.NewGuid().ToString("N"); _view.GetZDO().Set("vikingrail_identity", _identity); } } private void OnDestroyedPermanently() { StopAutomaticDrive("Engine destroyed."); StopLocalDriver(); StopPassengers(); RailPlow mountedPlow = MountedPlow; if (Object.op_Implicit((Object)(object)mountedPlow)) { mountedPlow.DetachFromDestroyedEngine(this); } RailAutoDrive mountedAutoDrive = MountedAutoDrive; if (Object.op_Implicit((Object)(object)mountedAutoDrive)) { mountedAutoDrive.DetachFromDestroyedEngine(this); } UnlinkDestroyedVehicle(); } private void OnDestroy() { StopAutomaticDrive("Automatic drive stopped because the engine unloaded."); RailSwitch.ReleaseTrainRoute(this); StopLocalDriver(); StopPassengers(); CleanupSmoke(); CleanupMovementAudio(); Vehicles.Remove(this); CleanupLinkCleanup(); } private bool TryFormation(List train, out Dictionary slots, out Dictionary reversed) { slots = new Dictionary(); reversed = new Dictionary(); if (!Ready || ParentId.Length != 0 || train.Count == 0 || (Object)(object)train[0] != (Object)(object)this) { return false; } HashSet hashSet = new HashSet(train); if (hashSet.Count != train.Count) { return false; } HashSet hashSet2 = new HashSet(); if (!RailTrainLimits.TryVisit(hashSet2, _identity)) { return false; } slots.Add(this, 0); reversed.Add(this, value: false); int direction = ((!IsEngine && !ParentFront) ? 1 : (-1)); if (!AddFormationBranch(this, NextId, direction, hashSet, hashSet2, slots, reversed) || (IsEngine && !AddFormationBranch(this, FrontId, 1, hashSet, hashSet2, slots, reversed))) { return false; } return slots.Count == hashSet.Count; } private static bool AddFormationBranch(RailVehicle root, string nextId, int direction, HashSet expected, HashSet seen, Dictionary slots, Dictionary reversed) { RailVehicle railVehicle = root; int num = direction; while (nextId.Length != 0) { RailVehicle railVehicle2 = Find(nextId); if (!Object.op_Implicit((Object)(object)railVehicle2) || !railVehicle2.Ready || railVehicle2.FrontId.Length != 0 || !expected.Contains(railVehicle2) || railVehicle2.ParentId != railVehicle._identity || !RailTrainLimits.TryVisit(seen, railVehicle2._identity)) { return false; } slots.Add(railVehicle2, num); reversed.Add(railVehicle2, (direction > 0) ? railVehicle2.ParentFront : (!railVehicle2.ParentFront)); railVehicle = railVehicle2; nextId = railVehicle2.NextId; num += direction; } return true; } private static int LeadingIndex(List train, Dictionary slots, bool forward) { int num = 0; for (int i = 1; i < train.Count; i++) { if (forward ? (slots[train[i]] > slots[train[num]]) : (slots[train[i]] < slots[train[num]])) { num = i; } } return num; } private bool IsFuel(ItemData item) { if (item.m_stack > 0 && Object.op_Implicit((Object)(object)item.m_dropPrefab)) { return RailFuelPolicy.AcceptsItem(FuelType, ((Object)item.m_dropPrefab).name); } return false; } internal bool RefreshFuelInventory() { if (!FuelPowered) { return true; } if (!Object.op_Implicit((Object)(object)_container) || !Ready || !_view.IsOwner()) { return false; } string error; return RailCargoInventory.TryRefresh(_container, out error); } private bool CanPowerFor(double seconds) { if (FuelPowered) { return FuelBudget.Plan(FuelSeconds, FuelCount, seconds, SecondsPerFuelItem).CanPower; } return true; } private bool BurnFuelFor(double seconds) { if (!FuelPowered) { return true; } if (!Ready || !_view.IsOwner() || !Object.op_Implicit((Object)(object)_container) || CargoBusy) { return false; } FuelPlan fuelPlan = FuelBudget.Plan(FuelSeconds, FuelCount, seconds, SecondsPerFuelItem); if (!fuelPlan.CanPower) { return false; } int num = fuelPlan.ItemsToConsume; ItemData[] array = _container.GetInventory().GetAllItems().Where(IsFuel) .ToArray(); foreach (ItemData val in array) { if (num == 0) { break; } int num2 = Math.Min(num, val.m_stack); if (!_container.GetInventory().RemoveItem(val, num2)) { return false; } num -= num2; } if (num != 0) { return false; } _view.GetZDO().Set("vikingrail_fuel_seconds_bits", BitConverter.DoubleToInt64Bits(fuelPlan.RemainingSeconds)); return true; } internal static List GateTrains() { List list = new List(); HashSet visited = new HashSet(); foreach (RailVehicle vehicle in Vehicles) { if (!Object.op_Implicit((Object)(object)vehicle) || visited.Contains(vehicle)) { continue; } if (vehicle.Ready && vehicle.FindRoot(out RailVehicle root) && ReadCouplingChain(root, out List chain) && root.TryFormation(chain, out Dictionary slots, out Dictionary reversed) && chain.All((RailVehicle c) => !visited.Contains(c))) { GateTrain gateTrain = new GateTrain { Identity = root.GateIdentity, Cars = chain.OrderBy((RailVehicle c) => slots[c]).ToList(), Complete = true, Root = root, Reversed = reversed }; foreach (RailVehicle car in gateTrain.Cars) { visited.Add(car); if (!car.GateBoundsComplete) { gateTrain.Complete = false; } } list.Add(gateTrain); } else { visited.Add(vehicle); list.Add(new GateTrain { Identity = vehicle.GateIdentity, Cars = new List { vehicle }, Complete = false }); } } return list; } private float GateSignedSpeed() { if (!Ready) { return 0f; } float num = (_view.IsOwner() ? Speed : (PumpVisualSpeed * (float)(_view.GetZDO().GetBool("vikingrail_plow_drive_forward", true) ? 1 : (-1)))); if (!float.IsNaN(num) && !float.IsInfinity(num)) { return num; } return 0f; } private string GateBoundsLinks() { StringBuilder stringBuilder = new StringBuilder(TurntableLinks()); RailTorchMounts component = ((Component)this).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { for (int i = 0; i < component.Count; i++) { stringBuilder.Append('/').Append(component.IdentityAt(i)); } } RailMountCart mountCart = MountCart; if (Object.op_Implicit((Object)(object)mountCart)) { for (int j = 0; j < 2; j++) { stringBuilder.Append('/').Append(mountCart.Phase(j)).Append(':') .Append(mountCart.ChildIdentity(j)); } } return stringBuilder.ToString(); } private void RefreshGateBounds() { //IL_004b: 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_02cd: 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_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_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_0368: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: 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_010c: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0328: Unknown result type (might be due to invalid IL or missing references) //IL_032d: Unknown result type (might be due to invalid IL or missing references) //IL_0346: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: 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_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: 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_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //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_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_0286: 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_028d: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) string text = GateBoundsLinks(); if (Time.unscaledTime - _gateBoundsAt < 0.25f && text == _gateBoundsLinks) { return; } _gateBoundsAt = Time.unscaledTime; _gateBoundsLinks = text; _gateBoundsComplete = Ready; bool flag = false; Bounds gateBounds = default(Bounds); List list = new List(); if (Object.op_Implicit((Object)(object)_view)) { list.Add(_view); } if (!CollectTurntableAttachments(list, out string _)) { _gateBoundsComplete = false; } foreach (ZNetView item in list) { if (!Object.op_Implicit((Object)(object)item) || !item.IsValid() || !TryPackedVehicleBounds(((Component)item).gameObject, out var bounds)) { _gateBoundsComplete = false; continue; } Vector3[] array = PackedVehicleBoxCorners(bounds); foreach (Vector3 val in array) { Vector3 val2 = ((Component)this).transform.InverseTransformPoint(((Component)item).transform.TransformPoint(val)); if (!FiniteGateVector(val2)) { _gateBoundsComplete = false; } else if (!flag) { gateBounds = new Bounds(val2, Vector3.zero); flag = true; } else { ((Bounds)(ref gateBounds)).Encapsulate(val2); } } } RailMountCart mountCart = MountCart; if (Object.op_Implicit((Object)(object)mountCart)) { foreach (RailMountedObject attachment in mountCart.Attachments) { if (!Object.op_Implicit((Object)(object)attachment) || !attachment.IsDummy) { continue; } if (!attachment.TryBounds(out var bounds2)) { _gateBoundsComplete = false; continue; } Vector2 val3 = new Vector2(((Bounds)(ref bounds2)).center.x, ((Bounds)(ref bounds2)).center.z); float magnitude = ((Vector2)(ref val3)).magnitude; val3 = new Vector2(((Bounds)(ref bounds2)).extents.x, ((Bounds)(ref bounds2)).extents.z); float num = magnitude + ((Vector2)(ref val3)).magnitude; Vector3[] array = PackedVehicleBoxCorners(new Bounds(((Component)attachment).transform.position + Vector3.up * ((Bounds)(ref bounds2)).center.y, new Vector3(num * 2f, ((Bounds)(ref bounds2)).size.y, num * 2f))); foreach (Vector3 val4 in array) { Vector3 val5 = ((Component)this).transform.InverseTransformPoint(val4); if (!FiniteGateVector(val5)) { _gateBoundsComplete = false; } else if (!flag) { gateBounds = new Bounds(val5, Vector3.zero); flag = true; } else { ((Bounds)(ref gateBounds)).Encapsulate(val5); } } } } if (!flag || ((Bounds)(ref gateBounds)).size.x <= 0f || ((Bounds)(ref gateBounds)).size.y <= 0f || ((Bounds)(ref gateBounds)).size.z <= 0f) { _gateBoundsComplete = false; } if (!_gateBoundsComplete) { Vector3[] array = PackedVehicleBoxCorners(GateFallbackBounds); foreach (Vector3 val6 in array) { if (!flag) { ((Bounds)(ref gateBounds))..ctor(val6, Vector3.zero); flag = true; } else { ((Bounds)(ref gateBounds)).Encapsulate(val6); } } } ((Bounds)(ref gateBounds)).Expand(0.12f); _gateBounds = gateBounds; } internal RailGateBody GateBody(Transform gate, Vector3 position, Quaternion rotation, string trainIdentity, Vector3 velocity) { //IL_000a: 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_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) //IL_002e: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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_008a: 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_0091: 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_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_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_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_00b1: 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_009a: 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_0074: 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_0064: 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_00e9: 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_00ff: 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) RefreshGateBounds(); bool flag = true; Bounds val = default(Bounds); Vector3[] array = PackedVehicleBoxCorners(_gateBounds); foreach (Vector3 val2 in array) { Vector3 val3 = gate.InverseTransformPoint(position + rotation * val2); if (!FiniteGateVector(val3)) { _gateBoundsComplete = false; val = GateFallbackBounds; flag = false; break; } if (flag) { ((Bounds)(ref val))..ctor(val3, Vector3.zero); flag = false; } else { ((Bounds)(ref val)).Encapsulate(val3); } } Vector3 val4 = gate.InverseTransformDirection(velocity); if (!FiniteGateVector(val4)) { val4 = Vector3.zero; } Vector3 val5 = gate.InverseTransformDirection(rotation * Vector3.forward); if (!FiniteGateVector(val5) || ((Vector3)(ref val5)).sqrMagnitude < 1E-06f) { val5 = Vector3.forward; } return new RailGateBody(GateIdentity, string.IsNullOrEmpty(trainIdentity) ? GateIdentity : trainIdentity, RailSegment.ToRail(((Bounds)(ref val)).center), RailSegment.ToRail(((Bounds)(ref val)).extents), RailSegment.ToRail(val4), RailSegment.ToRail(val5)); } internal static bool GateRequestValid(long sender, string rootId, RailGate gate) { //IL_00d3: 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_00ec: Unknown result type (might be due to invalid IL or missing references) if (sender == 0L || string.IsNullOrEmpty(rootId) || rootId.Length > 128 || !Object.op_Implicit((Object)(object)gate)) { return false; } RailVehicle railVehicle = Find(rootId); if (!Object.op_Implicit((Object)(object)railVehicle) || !railVehicle.Ready || railVehicle.ParentId.Length != 0 || railVehicle._view.GetZDO().GetOwner() != sender || !ReadCouplingChain(railVehicle, out List chain) || !railVehicle.TryFormation(chain, out Dictionary _, out Dictionary _)) { return false; } float num = (railVehicle._view.IsOwner() ? Mathf.Abs(railVehicle.Speed) : railVehicle.PumpVisualSpeed); if (float.IsNaN(num) || float.IsInfinity(num)) { return false; } foreach (RailVehicle item in chain) { item.RefreshGateBounds(); float num2 = 16f + num * 3f; Vector3 extents = ((Bounds)(ref item._gateBounds)).extents; float distance = num2 + ((Vector3)(ref extents)).magnitude; if (gate.Near(((Component)item).transform.position, distance)) { return true; } } return false; } internal bool GateApproach(RailGate gate, List train, bool forward, float speed) { if (!Object.op_Implicit((Object)(object)gate) || !Ready || float.IsNaN(speed) || float.IsInfinity(speed)) { return false; } float unscaledTime = Time.unscaledTime; if (_gateApproaches.TryGetValue(gate, out var value) && unscaledTime < value.Until && value.Forward == forward) { return value.Approaching; } bool flag = ScanGateApproach(gate, train, forward, speed); if (_gateApproaches.Count > 128) { _gateApproaches.Clear(); } _gateApproaches[gate] = new GateApproachScan(forward, flag, unscaledTime + 0.2f); return flag; } private bool ScanGateApproach(RailGate gate, List train, bool forward, float speed) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) if (!TryFormation(train, out Dictionary slots, out Dictionary reversed)) { return false; } RailVehicle railVehicle = train[LeadingIndex(train, slots, forward)]; if (!railVehicle.TryCursor()) { return false; } railVehicle.RefreshGateBounds(); double num = 8.0 + (double)Math.Abs(speed) * 3.0; Vector3 position = ((Component)railVehicle).transform.position; float num2 = (float)num; Vector3 extents = ((Bounds)(ref railVehicle._gateBounds)).extents; if (!gate.Near(position, num2 + ((Vector3)(ref extents)).magnitude + 4f)) { return false; } bool flag = forward == reversed[railVehicle]; RailCursor cursor = (flag ? railVehicle._cursor.Value.Reversed() : railVehicle._cursor.Value); int num3 = Math.Max(1, (int)Math.Ceiling(num)); for (int i = 0; i <= num3; i++) { RailAdvanceResult railAdvanceResult = RailSegment.Network.Advance(cursor, num * (double)i / (double)num3); RailCursor cursor2 = (flag ? railAdvanceResult.Cursor.Reversed() : railAdvanceResult.Cursor); RailPose railPose = RailVehiclePose.Sample(RailSegment.Network, cursor2); Quaternion rotation = Quaternion.LookRotation(RailSegment.ToUnity(railPose.Tangent), Vector3.up); if (RailGatePolicy.OverlapsDoor(railVehicle.GateBody(((Component)gate).transform, RailSegment.ToUnity(railPose.Position), rotation, GateIdentity, Vector3.zero), 2.5, 0.75, 0.0, 4.0)) { return true; } if (railAdvanceResult.Stopped) { break; } } return false; } internal void WaitAtGate() { if (Ready && _view.IsOwner()) { ClearPlowIntent(); Speed = 0f; PublishMotion(moving: false); StopSmoke(); StopMovementAudio(); StopFollowerMotion(); Status = "Waiting for the railway gate to open. The train will continue when it is clear."; } } private static bool FiniteGateVector(Vector3 value) { //IL_0000: 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_001a: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!float.IsNaN(value.x) && !float.IsInfinity(value.x) && !float.IsNaN(value.y) && !float.IsInfinity(value.y) && !float.IsNaN(value.z)) { return !float.IsInfinity(value.z); } return false; } internal bool BeginHandPush(Player player) { //IL_00e1: 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_0103: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)player) && (Object)(object)player == (Object)(object)Player.m_localPlayer && (Object)(object)_driver == (Object)(object)player && (Object)(object)LocalDriven == (Object)(object)this) { StopLocalDriver(); return true; } if (!Ready || !CanHandPush || _pendingMount || _packing || _packPending || !Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return false; } if (!RailSettings.Ready) { Tell(player, "Waiting for server railroad settings."); return false; } if (((Character)player).IsDead() || ((Character)player).IsTeleporting() || ((Character)player).IsAttached() || player.GetDoodadController() != null || ((Character)player).InPlaceMode()) { return false; } if (!TryCursor()) { Tell(player, "Place the cart on connected railway track before pushing it."); return false; } SetHandPushAnchor(_cursor.Value); if (Vector3.Distance(((Component)player).transform.position, _seat.position) > 2.4f || !PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false) || !PrivateArea.CheckAccess(_seat.position, 0f, true, false)) { return false; } if (DriverId != 0L) { Tell(player, "Someone is already pushing this cart."); return false; } if (!HandPushAvailable(out string reason)) { Tell(player, reason); return false; } if (!PushOperatorSpaceClear(player)) { Tell(player, "You need clear standing space and support behind the cart to push it."); return false; } if (!_view.HasOwner()) { Tell(player, "Waiting for the cart's network owner. Try again shortly."); return false; } _pendingMount = true; _mountGranted = false; _requestTime = Time.time; _requestOwner = _view.GetZDO().GetOwner(); _view.InvokeRPC("VR_RequestDrive", new object[1] { player.GetPlayerID() }); return true; } private bool HandPushAvailable(out string reason) { reason = RailHandPush.EvaluateEligibility(IsEngine, ParentId.Length != 0, NextId.Length != 0, HasPassengers, CargoBusy); if (reason.Length == 0 && (_packing || _packPending || IsPacked)) { reason = "Wait for packing to finish."; } if (reason.Length == 0 && (CargoServiceBusy || CouplingServiceBusy || MountServiceBusy)) { reason = "Wait for storage or coupling to finish."; } if (reason.Length == 0 && HasPlowAt(front: false)) { reason = "Detach the rear plow before using the push handle."; } if (reason.Length == 0 && AttachedPlowId.Length != 0 && !Object.op_Implicit((Object)(object)MountedPlow)) { reason = "Wait for the attached plow to load."; } if (CanHandPush) { return reason.Length == 0; } return false; } private bool CanGrantHandPush(Player player) { //IL_0050: 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_0072: 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) if (!_cursor.HasValue || !CanHandPush) { return false; } SetHandPushAnchor(_cursor.Value); if (RailSettings.Ready && !((Character)player).IsTeleporting() && !((Character)player).IsAttached() && player.GetDoodadController() == null && Vector3.Distance(((Component)player).transform.position, _seat.position) <= 2.4f && RailWardAccess.Allows(((Component)this).transform.position, player.GetPlayerID()) && RailWardAccess.Allows(_seat.position, player.GetPlayerID()) && HandPushAvailable(out string _)) { return PushOperatorSpaceClear(player); } return false; } private bool PushOperatorSpaceClear(Player player) { if (!_cursor.HasValue) { return false; } SetHandPushAnchor(_cursor.Value); bool trackUnderfoot; RailPose anchor = HandPushAnchor(_cursor.Value, out trackUnderfoot); if (!trackUnderfoot && !HasPushFooting(anchor.Position)) { return false; } List list = new List(); AddPushOperatorVolume(list, anchor); foreach (Collider item in list) { if (PushOperatorObstacle(item, player)) { return false; } } return true; } private void AddPushOperatorVolume(List colliders, RailPose anchor) { //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_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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) AddVolumeHits(colliders, _seat.position + Vector3.up, RailSegment.ToUnity(anchor.Position) + Vector3.up, new Vector3(0.32f, 0.85f, 0.32f), PushRotation(anchor)); } private bool PushOperatorObstacle(Collider collider, Player player) { if (!Object.op_Implicit((Object)(object)collider) || (Object)(object)((Component)collider).GetComponentInParent() == (Object)(object)this || (Object)(object)((Component)collider).GetComponentInParent() == (Object)(object)player) { return false; } RailMountedTorch componentInParent = ((Component)collider).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent) && (Object)(object)componentInParent.Vehicle == (Object)(object)this) { return false; } Character componentInParent2 = ((Component)collider).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent2)) { if (!(componentInParent2 is Player)) { return !componentInParent2.IsDead(); } return true; } if (Object.op_Implicit((Object)(object)((Component)collider).GetComponentInParent()) || Object.op_Implicit((Object)(object)((Component)collider).GetComponentInParent())) { return false; } if (RailNaturalResource.IgnoreRailObstacle(collider)) { return false; } if (Object.op_Implicit((Object)(object)_body)) { return !Physics.GetIgnoreLayerCollision(((Component)this).gameObject.layer, ((Component)collider).gameObject.layer); } return true; } private bool PushOperatorPathBlocked(RailCursor cursor, Player player) { //IL_0030: 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) bool trackUnderfoot; RailPose anchor = HandPushAnchor(cursor, out trackUnderfoot); if (!trackUnderfoot && !HasPushFooting(anchor.Position)) { return true; } if (!RailWardAccess.Allows(RailSegment.ToUnity(RailVehiclePose.Sample(RailSegment.Network, cursor).Position), player.GetPlayerID()) || !RailWardAccess.Allows(RailSegment.ToUnity(anchor.Position), player.GetPlayerID())) { return true; } List list = new List(); AddPushOperatorVolume(list, anchor); foreach (Collider item in list) { if (PushOperatorObstacle(item, player)) { return true; } } return false; } private void RefreshHandPushAnchor() { if (CanHandPush && (DriverId != 0L || _pendingMount) && TryCursor()) { SetHandPushAnchor(_cursor.Value); } } private void SetHandPushAnchor(RailCursor cursor) { //IL_0047: 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_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_005b: 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_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_008b: 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_0092: 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_0029: Unknown result type (might be due to invalid IL or missing references) bool trackUnderfoot; RailPose anchor = HandPushAnchor(cursor, out trackUnderfoot); if (_view.IsOwner()) { _seat.SetPositionAndRotation(RailSegment.ToUnity(anchor.Position), PushRotation(anchor)); return; } RailPose railPose = RailVehiclePose.Sample(RailSegment.Network, cursor); Quaternion val = Quaternion.Inverse(Quaternion.LookRotation(RailSegment.ToUnity(railPose.Tangent), Vector3.up)); _seat.localPosition = val * RailSegment.ToUnity(anchor.Position - railPose.Position); _seat.localRotation = val * PushRotation(anchor); } private static Quaternion PushRotation(RailPose anchor) { //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_0019: 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) Vector3 val = RailSegment.ToUnity(anchor.Tangent); val.y = 0f; return Quaternion.LookRotation(val, Vector3.up); } private static RailPose HandPushAnchor(RailCursor cursor, out bool trackUnderfoot) { return RailHandPush.Anchor(RailSegment.Network, cursor, out trackUnderfoot); } private bool HasPushFooting(RailVector anchor) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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_001a: 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_003a: 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) RaycastHit[] array = Physics.RaycastAll(RailSegment.ToUnity(anchor) + Vector3.up * 0.3f, Vector3.down, 0.8f, -1, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { RaycastHit val = array[i]; Collider collider = ((RaycastHit)(ref val)).collider; if (Object.op_Implicit((Object)(object)collider) && !(((RaycastHit)(ref val)).normal.y < 0.5f) && !Object.op_Implicit((Object)(object)((Component)collider).GetComponentInParent()) && !Object.op_Implicit((Object)(object)((Component)collider).GetComponentInParent()) && !Object.op_Implicit((Object)(object)((Component)collider).GetComponentInParent()) && (!Object.op_Implicit((Object)(object)_body) || !Physics.GetIgnoreLayerCollision(((Component)this).gameObject.layer, ((Component)collider).gameObject.layer))) { return true; } } return false; } private void InitializeLights() { //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Expected O, but got Unknown //IL_011c: 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_012a: Unknown result type (might be due to invalid IL or missing references) List list = new List(); Light[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); foreach (Light val in componentsInChildren) { if (((Object)val).name.StartsWith("vr_lamp_", StringComparison.Ordinal)) { list.Add(val); } } _railLights = list.ToArray(); _railLightIntensities = new float[_railLights.Length]; for (int j = 0; j < _railLights.Length; j++) { _railLightIntensities[j] = _railLights[j].intensity; } List list2 = new List(); Renderer[] componentsInChildren2 = ((Component)this).GetComponentsInChildren(true); foreach (Renderer val2 in componentsInChildren2) { if (((Object)val2).name == "vr_lamp_lens") { list2.Add(val2); } } _railLenses = list2.ToArray(); _railLensEmission = (Color[])(object)new Color[_railLenses.Length]; for (int k = 0; k < _railLenses.Length; k++) { Material sharedMaterial = _railLenses[k].sharedMaterial; _railLensEmission[k] = ((Object.op_Implicit((Object)(object)sharedMaterial) && sharedMaterial.HasProperty("_EmissionColor")) ? sharedMaterial.GetColor("_EmissionColor") : Color.black); } _lampProperties = new MaterialPropertyBlock(); InitializeBeamSmoothing(); _view.Register("VR_Lights", (Action)RequestLights); } private void LateUpdate() { UpdateLights(); UpdateBeamSmoothing(); } private void UpdateLights() { //IL_0020: 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_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) Vector3 position; float num = ((Ready && LightsOn && RailLightingView.TryGetPosition(out position)) ? ((float)RailLightingMath.DistanceFade(Vector3.Distance(position, ((Component)this).transform.position))) : 0f); bool flag = num > 0f; for (int i = 0; i < _railLights.Length; i++) { Light val = _railLights[i]; if (Object.op_Implicit((Object)(object)val)) { val.intensity = _railLightIntensities[i] * num; if (((Behaviour)val).enabled != flag) { ((Behaviour)val).enabled = flag; } } } if (_lampBrightness == num || _lampProperties == null) { return; } _lampBrightness = num; for (int j = 0; j < _railLenses.Length; j++) { Renderer val2 = _railLenses[j]; if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val2.sharedMaterial) && val2.sharedMaterial.HasProperty("_EmissionColor")) { val2.GetPropertyBlock(_lampProperties); _lampProperties.SetColor("_EmissionColor", _railLensEmission[j] * num); val2.SetPropertyBlock(_lampProperties); _lampProperties.Clear(); } } } internal bool ToggleLights(Player player) { //IL_004f: 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_0071: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || Time.unscaledTime < _nextLightRequest || !_view.HasOwner()) { return false; } if (Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position) > 4f || !PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return false; } _nextLightRequest = Time.unscaledTime + 0.3f; _view.InvokeRPC("VR_Lights", new object[2] { player.GetPlayerID(), !LightsOn }); return true; } private void RequestLights(long sender, long playerId, bool enabled) { //IL_0044: 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_0066: 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) if (!Ready || !_view.IsOwner()) { return; } Player player = Player.GetPlayer(playerId); if (Object.op_Implicit((Object)(object)player) && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && ((Character)player).GetOwner() == sender && !(Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position) > 4f) && RailWardAccess.Allows(((Component)this).transform.position, playerId)) { _view.GetZDO().Set("vikingrail_lights_on", enabled); UpdateLights(); if (ZDOMan.instance != null) { ZDOMan.instance.ForceSendZDO(sender, _view.GetZDO().m_uid); } } } private void InitializeLinkCleanup() { ZDOMan instance = ZDOMan.instance; if (instance != _linkCleanupManager) { if (_linkCleanupManager != null) { ZDOMan? linkCleanupManager = _linkCleanupManager; linkCleanupManager.m_onZDODestroyed = (Action)Delegate.Remove(linkCleanupManager.m_onZDODestroyed, new Action(OnLinkedVehicleDestroyed)); } _linkCleanupManager = instance; if (instance != null) { instance.m_onZDODestroyed = (Action)Delegate.Combine(instance.m_onZDODestroyed, new Action(OnLinkedVehicleDestroyed)); } } } private void CleanupLinkCleanup() { if (Vehicles.Count == 0 && _linkCleanupManager != null) { ZDOMan? linkCleanupManager = _linkCleanupManager; linkCleanupManager.m_onZDODestroyed = (Action)Delegate.Remove(linkCleanupManager.m_onZDODestroyed, new Action(OnLinkedVehicleDestroyed)); _linkCleanupManager = null; } } private void UnlinkDestroyedVehicle() { if (Object.op_Implicit((Object)(object)_view) && _view.IsValid() && _view.IsOwner()) { ZDO zDO = _view.GetZDO(); if (zDO.GetFloat(ZDOVars.s_health, 1f) <= 0f) { ClearDestroyedLinks(zDO, notifyCargo: false); } } } private static void OnLinkedVehicleDestroyed(ZDO destroyed) { ClearDestroyedLinks(destroyed, notifyCargo: true); } private static void ClearDestroyedLinks(ZDO destroyed, bool notifyCargo) { string text; string text2; string text3; string text4; try { if (destroyed == null) { return; } text = destroyed.GetString("vikingrail_identity", ""); if (text.Length == 0) { return; } text2 = destroyed.GetString("vikingrail_parent", ""); text3 = destroyed.GetString("vikingrail_next", ""); text4 = destroyed.GetString("vikingrail_front", ""); } catch (Exception error) { RailPlugin.Error(error); return; } RailVehicle[] array = Vehicles.ToArray(); foreach (RailVehicle railVehicle in array) { try { if (Object.op_Implicit((Object)(object)railVehicle) && railVehicle.Ready && railVehicle._view.IsOwner()) { if (railVehicle._identity == text2 && railVehicle.NextId == text) { railVehicle._view.GetZDO().Set("vikingrail_next", ""); } if (railVehicle._identity == text2 && railVehicle.FrontId == text) { railVehicle._view.GetZDO().Set("vikingrail_front", ""); } if ((railVehicle._identity == text3 || railVehicle._identity == text4) && railVehicle.ParentId == text) { railVehicle.DetachCouplingParent(); } if (notifyCargo) { railVehicle.CargoTargetDestroyed(text); } } } catch (Exception error2) { RailPlugin.Error(error2); } } } private void FollowMountedObjects() { RailMountCart mountCart = MountCart; if (Object.op_Implicit((Object)(object)mountCart)) { mountCart.FollowMounts(); } } internal bool TryMusicTrain(out List train) { train = new List(); if (!Ready || !FindRoot(out RailVehicle root) || !ReadCouplingChain(root, out List chain) || !chain.Contains(this) || !root.TryFormation(chain, out Dictionary _, out Dictionary _)) { return false; } foreach (RailVehicle item in chain) { if (!item.Ready || item._packing || item._packPending || item._couplingOperation != null || item.HasCouplingLease || item._contactCouplingClient != null || (!((ZDOID)(ref item._couplingClientWagon)).IsNone() && Time.unscaledTime < item._couplingClientUntil)) { return false; } } train = chain; return true; } private void InitializePassengerCart() { _passengerSeats = ((Component)this).GetComponentsInChildren(true); } private void PublishMotion(bool moving) { if (!Ready || !_view.IsOwner()) { return; } ZDO zDO = _view.GetZDO(); if (!moving) { if (zDO.GetLong("vikingrail_moving_until", 0L) != 0L) { zDO.Set("vikingrail_moving_until", 0L); } _nextMotionUpdate = 0f; } else if (Object.op_Implicit((Object)(object)ZNet.instance) && !(Time.time < _nextMotionUpdate)) { _nextMotionUpdate = Time.time + 0.25f; zDO.Set("vikingrail_moving_until", (long)(ZNet.instance.GetTimeSeconds() * 1000.0) + 1000); } } private void StopPassengers() { RailPassengerSeat[] passengerSeats = _passengerSeats; foreach (RailPassengerSeat railPassengerSeat in passengerSeats) { if (Object.op_Implicit((Object)(object)railPassengerSeat)) { railPassengerSeat.StopLocalPassenger(); } } if (Object.op_Implicit((Object)(object)_pumpPartner)) { _pumpPartner.StopLocalPartner(); } } internal static bool TryPlacePackedVehicle(Humanoid user, Inventory? inventory, ItemData item) { //IL_052e: Unknown result type (might be due to invalid IL or missing references) //IL_0533: Unknown result type (might be due to invalid IL or missing references) //IL_0538: Unknown result type (might be due to invalid IL or missing references) //IL_053d: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) if (item == null || !Object.op_Implicit((Object)(object)item.m_dropPrefab)) { return false; } string text = PackedVehicle.PieceName(((Object)item.m_dropPrefab).name); if (text.Length == 0) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val != (Object)(object)Player.m_localPlayer) { return true; } if (inventory == null) { inventory = ((Humanoid)val).GetInventory(); } if (inventory != ((Humanoid)val).GetInventory() || !inventory.ContainsItem(item)) { return true; } if (((Character)val).IsDead() || ((Character)val).IsTeleporting() || ((Character)val).IsAttached() || val.GetDoodadController() != null || ((Character)val).InPlaceMode()) { Tell(val, "Stand on foot before placing a packed vehicle."); return true; } if (!RailSettings.Ready) { Tell(val, "Waiting for server railroad settings."); return true; } if (item.m_stack != 1) { Tell(val, "This vehicle bundle has an invalid stack. It has been kept."); return true; } ZNetScene instance = ZNetScene.instance; GameObject val2 = (Object.op_Implicit((Object)(object)instance) ? instance.GetPrefab(text) : null); RailVehicle railVehicle = (Object.op_Implicit((Object)(object)val2) ? val2.GetComponent() : null); Piece val3 = (Object.op_Implicit((Object)(object)val2) ? val2.GetComponent() : null); WearNTear val4 = (Object.op_Implicit((Object)(object)val2) ? val2.GetComponent() : null); if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)railVehicle) || !Object.op_Implicit((Object)(object)val3) || !Object.op_Implicit((Object)(object)val4) || !Object.op_Implicit((Object)(object)ZNet.instance)) { Tell(val, "The vehicle prefab is unavailable. The bundle has been kept."); return true; } if (!val3.m_allowedInDungeons && ((Character)val).InInterior() && !EnvMan.instance.CheckInteriorBuildingOverride() && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)34)) { Tell(val, "Rail vehicles cannot be placed in this dungeon."); return true; } ItemData val5 = item.Clone(); val5.m_stack = 1; float num; double num2; bool flag; PassengerFireState state; RailMusicMetadata state2; try { num = PackedVehicle.ReadHealth(val5.m_customData, val4.m_health); num2 = PackedVehicle.ReadFuel(val5.m_customData); flag = PackedVehicle.ReadBoolean(val5.m_customData, "vikingrail_vehicle_lamps"); state = RailPassengerFire.ReadPacked(val2, val5.m_customData); state2 = RailMusicCart.ReadPacked(val2, val5.m_customData); if (!railVehicle.FuelPowered && num2 != 0.0) { throw new FormatException("This vehicle cannot hold burned fuel credit."); } } catch (Exception ex) { Tell(val, "This vehicle's saved condition is invalid. Its bundle has been kept: " + ex.GetBaseException().Message); return true; } if (!RailPackedInventory.Validate(val5, val2.GetComponent(), out Inventory staged, out string error)) { Tell(val, error); return true; } if (!TryPackedVehiclePosition(val, railVehicle, out var cursor, out var position, out var rotation)) { return true; } ZNetView playerView = ((Component)val).GetComponent(); if (!Object.op_Implicit((Object)(object)playerView) || !playerView.IsValid()) { return true; } List playerList = ZNet.instance.GetPlayerList(); int num3 = playerList.FindIndex((PlayerInfo info) => info.m_characterID == playerView.GetZDO().m_uid); if (num3 < 0) { Tell(val, "Waiting for your player identity. Try again shortly."); return true; } if (PackedPlacementPlatformUser == null || PackedPlacementSetCreator == null) { Tell(val, "This game build's piece creator API is unavailable."); return true; } object value = PackedPlacementPlatformUser.GetValue(playerList[num3].m_userInfo); if (!inventory.RemoveItem(item, 1)) { return true; } GameObject val6 = null; bool flag2 = false; try { val6 = Object.Instantiate(val2, position, rotation); ZNetView component = val6.GetComponent(); RailVehicle component2 = val6.GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || !component.IsOwner() || !Object.op_Implicit((Object)(object)component2)) { throw new InvalidOperationException("The placed vehicle has no owned network identity."); } ZDO zDO = component.GetZDO(); zDO.Set("vikingrail_identity", Guid.NewGuid().ToString("N")); zDO.Set(ZDOVars.s_health, num); zDO.Set("vikingrail_fuel_seconds_bits", BitConverter.DoubleToInt64Bits(num2)); zDO.Set("vikingrail_lights_on", flag); zDO.Set("vikingrail_track", cursor.SegmentId); zDO.Set("vikingrail_direction", cursor.Direction); zDO.Set("vikingrail_distance", (float)cursor.Distance); zDO.Set("vikingrail_parent", ""); zDO.Set("vikingrail_next", ""); zDO.Set("vikingrail_front", ""); zDO.Set("vikingrail_parent_front", true); zDO.Set("vikingrail_driver", 0L); zDO.Set("vikingrail_plow", ""); zDO.Set("vikingrail_plow_front", true); zDO.Set("vikingrail_moving_until", 0L); zDO.Set("vikingrail_vehicle_packed", false); component2.EnsureIdentity(); component2._cursor = cursor; PackedPlacementSetCreator.Invoke(val6.GetComponent(), new object[2] { val.GetPlayerID(), value }); RailPackedInventory.Restore(val6.GetComponent(), staged); RailPassengerFire.Restore(val6, state); RailMusicCart.Restore(val6, state2); flag2 = true; Tell(val, "Vehicle placed. Its previous train connections have been released."); } catch (Exception error2) { RailPlugin.Error(error2); } finally { if (!flag2) { if (!Object.op_Implicit((Object)(object)val6) || RetireFailedPackedPlacement(instance, val6)) { if (!inventory.AddItem(val5)) { ItemDrop.DropItem(val5, 1, ((Component)val).transform.position + Vector3.up, Quaternion.identity); } Tell(val, "The vehicle could not be placed. Its bundle has been returned."); } else { Tell(val, "Placement could not finish because network ownership changed. The vehicle remains at the selected rail; check the mod log."); } } } return true; } private static bool RetireFailedPackedPlacement(ZNetScene scene, GameObject placed) { bool result = false; try { ZNetView component = placed.GetComponent(); if (Object.op_Implicit((Object)(object)component) && component.IsValid()) { if (!component.IsOwner()) { component.ClaimOwnership(); } if (!component.IsOwner()) { return false; } component.GetZDO().Set("vikingrail_vehicle_packed", true); result = true; } else { result = true; } scene.Destroy(placed); return true; } catch (Exception error) { RailPlugin.Error(error); return result; } } private static bool TryPackedVehiclePosition(Player player, RailVehicle shape, out RailCursor cursor, out Vector3 position, out Quaternion rotation) { //IL_0008: 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_017a: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0201: 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) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_0282: 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_029c: Unknown result type (might be due to invalid IL or missing references) //IL_0411: Unknown result type (might be due to invalid IL or missing references) //IL_0418: Unknown result type (might be due to invalid IL or missing references) //IL_041d: Unknown result type (might be due to invalid IL or missing references) //IL_0430: Unknown result type (might be due to invalid IL or missing references) //IL_0437: Unknown result type (might be due to invalid IL or missing references) //IL_043e: Unknown result type (might be due to invalid IL or missing references) //IL_0443: Unknown result type (might be due to invalid IL or missing references) //IL_0448: Unknown result type (might be due to invalid IL or missing references) //IL_044f: Unknown result type (might be due to invalid IL or missing references) //IL_0454: Unknown result type (might be due to invalid IL or missing references) //IL_045e: Unknown result type (might be due to invalid IL or missing references) //IL_0463: Unknown result type (might be due to invalid IL or missing references) //IL_046a: Unknown result type (might be due to invalid IL or missing references) cursor = default(RailCursor); position = default(Vector3); rotation = Quaternion.identity; Camera mainCamera = Utils.GetMainCamera(); if (!Object.op_Implicit((Object)(object)mainCamera) || !TryPackedVehicleAim(player, mainCamera, out var hit) || !IsOrdinaryRailBed(((RaycastHit)(ref hit)).collider)) { Tell(player, "Aim directly at a clear rail or sleeper within 5 metres, then use the vehicle bundle."); return false; } RailSegment componentInParent = ((Component)((RaycastHit)(ref hit)).collider).GetComponentInParent(); RailSwitch componentInParent2 = ((Component)((RaycastHit)(ref hit)).collider).GetComponentInParent(); ZNetView val = (Object.op_Implicit((Object)(object)componentInParent) ? ((Component)componentInParent).GetComponent() : (Object.op_Implicit((Object)(object)componentInParent2) ? ((Component)componentInParent2).GetComponent() : null)); if (!Object.op_Implicit((Object)(object)val) || !val.IsValid() || (Object.op_Implicit((Object)(object)componentInParent2) && !componentInParent2.Ready)) { Tell(player, "Wait for this rail to finish loading."); return false; } string text = val.GetZDO().GetString("vikingrail_identity", ""); if (text.Length == 0) { Tell(player, "Wait for this rail to finish loading."); return false; } RailTurntable railTurntable = (Object.op_Implicit((Object)(object)componentInParent) ? ((Component)componentInParent).GetComponent() : null); if (Object.op_Implicit((Object)(object)railTurntable) && (railTurntable.Busy || !railTurntable.Aligned)) { Tell(player, "Align the turntable before placing a vehicle."); return false; } object obj = (Object.op_Implicit((Object)(object)componentInParent2) ? ((object)new List(componentInParent2.StablePathIds(text)).ToArray()) : ((object)new string[1] { text })); double num = 1.15; bool flag = false; string[] array = (string[])obj; foreach (string text2 in array) { if (RailSegment.Network.TryGetPath(text2, out RailPath path)) { RailProjection railProjection = path.Project(RailSegment.ToRail(((RaycastHit)(ref hit)).point)); if (!(railProjection.Separation > num)) { num = railProjection.Separation; cursor = new RailCursor(text2, railProjection.Distance); flag = true; } } } if (!flag) { Tell(player, "Aim closer to the centre of the loaded rail."); return false; } Vector3 val2 = Vector3.ProjectOnPlane(((Character)player).GetLookDir(), Vector3.up); if (((Vector3)(ref val2)).sqrMagnitude < 0.001f) { val2 = ((Component)player).transform.forward; } RailPose railPose = RailVehiclePose.Sample(RailSegment.Network, cursor); if (Vector3.Dot(RailSegment.ToUnity(railPose.Tangent), val2) < 0f) { cursor = cursor.Reversed(); railPose = RailVehiclePose.Sample(RailSegment.Network, cursor); } position = RailSegment.ToUnity(railPose.Position); rotation = Quaternion.LookRotation(RailSegment.ToUnity(railPose.Tangent), Vector3.up); if (Vector3.Distance(((Component)player).transform.position, position) > 5f || !PackedVehicleLineOfSight(player, ((RaycastHit)(ref hit)).point, ((Component)val).transform)) { Tell(player, "Stand beside the rail with a clear view of the placement point, within 5 metres."); return false; } RailAdvanceResult railAdvanceResult = RailSegment.Network.Advance(cursor, 1.4); RailAdvanceResult railAdvanceResult2 = RailSegment.Network.Advance(cursor.Reversed(), 1.4); if (railAdvanceResult.DistanceTravelled < 1.398 || railAdvanceResult2.DistanceTravelled < 1.398) { Tell(player, "The whole vehicle needs connected track. Move the aim point away from rail ends or incomplete junctions."); return false; } if (shape.RequiresMetalTrack && !RailTrackCapacity.IsSupported(RailSegment.Network, cursor, 1.4, RailSegment.LightTrackIds)) { Tell(player, "Coal and Eitr engines require metal track. Wooden track supports handcarts, bronze engines and wagons."); return false; } foreach (RailStopMarker stopMarker in RailSegment.StopMarkers) { if (stopMarker.IsBumper && stopMarker.Cursor.SegmentId == cursor.SegmentId && (cursor.Distance - stopMarker.Cursor.Distance) * (double)stopMarker.Cursor.Direction > 0.002) { Tell(player, "Move the aim point away from the bumper or closed switch route."); return false; } } if (!TryPackedVehicleBounds(((Component)shape).gameObject, out var bounds)) { Tell(player, "The vehicle's placement shape is unavailable."); return false; } if (!PackedVehicleAreaAllowed(player, position, rotation, bounds)) { return false; } int num2 = PackedVehicleCollisionMask(); Collider[] array2 = Physics.OverlapBox(position + rotation * ((Bounds)(ref bounds)).center, ((Bounds)(ref bounds)).extents + Vector3.one * 0.005f, rotation, num2, (QueryTriggerInteraction)1); for (int i = 0; i < array2.Length; i++) { if (!IsOrdinaryRailBed(array2[i])) { Tell(player, "Clear room for the entire vehicle and stand to the side of the track before placing it."); return false; } } return true; } private static int PackedVehicleCollisionMask() { return LayerMask.GetMask(new string[10] { "terrain", "piece", "Default", "Default_small", "static_solid", "character", "character_net", "character_ghost", "character_noenv", "vehicle" }); } private static bool TryPackedVehicleAim(Player player, Camera camera, out RaycastHit hit) { //IL_0006: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0079: 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) RaycastHit[] array = Physics.RaycastAll(((Component)camera).transform.position, ((Component)camera).transform.forward, 50f, PackedVehicleCollisionMask(), (QueryTriggerInteraction)1); Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance)); RaycastHit[] array2 = array; for (int num = 0; num < array2.Length; num++) { RaycastHit val = array2[num]; if (!((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent() == (Object)(object)player)) { hit = val; return Vector3.Distance(((Component)player).transform.position, ((RaycastHit)(ref hit)).point) <= 5f; } } hit = default(RaycastHit); return false; } private static bool PackedVehicleLineOfSight(Player player, Vector3 point, Transform targetRail) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_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_001f: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) Vector3 eyePoint = ((Character)player).GetEyePoint(); Vector3 val = point - eyePoint; if (((Vector3)(ref val)).sqrMagnitude < 0.001f) { return true; } RaycastHit[] array = Physics.RaycastAll(eyePoint, ((Vector3)(ref val)).normalized, Mathf.Max(0f, ((Vector3)(ref val)).magnitude - 0.02f), PackedVehicleCollisionMask(), (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { RaycastHit val2 = array[i]; if (!((Object)(object)((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent() == (Object)(object)player) && (!((Component)((RaycastHit)(ref val2)).collider).transform.IsChildOf(targetRail) || !IsOrdinaryRailBed(((RaycastHit)(ref val2)).collider))) { return false; } } return true; } private static bool IsOrdinaryRailBed(Collider collider) { if (!Object.op_Implicit((Object)(object)((Component)collider).GetComponentInParent()) && !Object.op_Implicit((Object)(object)((Component)collider).GetComponentInParent())) { return false; } switch (((Object)((Component)collider).gameObject).name) { case "rail": case "sleeper": case "switch_rail": case "switch_sleeper": case "brake_strip": case "brake_link": return true; default: return false; } } private static bool TryPackedVehicleBounds(GameObject prefab, out Bounds bounds) { //IL_0001: 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_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_0057: 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_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_00c7: 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_007f: 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_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_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0151: 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_00e1: 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_00f2: 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_00fc: 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_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0102: 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_010e: Unknown result type (might be due to invalid IL or missing references) bounds = default(Bounds); bool flag = false; MeshFilter[] componentsInChildren = prefab.GetComponentsInChildren(true); foreach (MeshFilter val in componentsInChildren) { if (!Object.op_Implicit((Object)(object)val.sharedMesh)) { continue; } Vector3[] array = PackedVehicleBoxCorners(val.sharedMesh.bounds); foreach (Vector3 val2 in array) { Vector3 val3 = prefab.transform.InverseTransformPoint(((Component)val).transform.TransformPoint(val2)); if (!flag) { bounds = new Bounds(val3, Vector3.zero); flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val3); } } } SkinnedMeshRenderer[] componentsInChildren2 = prefab.GetComponentsInChildren(true); foreach (SkinnedMeshRenderer val4 in componentsInChildren2) { if (!Object.op_Implicit((Object)(object)val4.sharedMesh)) { continue; } Vector3[] array = PackedVehicleBoxCorners(((Renderer)val4).localBounds); foreach (Vector3 val5 in array) { Vector3 val6 = prefab.transform.InverseTransformPoint(((Component)val4).transform.TransformPoint(val5)); if (!flag) { bounds = new Bounds(val6, Vector3.zero); flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val6); } } } if (flag && ((Bounds)(ref bounds)).size.x > 0f && ((Bounds)(ref bounds)).size.y > 0f) { return ((Bounds)(ref bounds)).size.z > 0f; } return false; } private static Vector3[] PackedVehicleBoxCorners(Bounds box) { //IL_0022: 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_0041: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) Vector3[] array = (Vector3[])(object)new Vector3[8]; for (int i = 0; i < array.Length; i++) { array[i] = new Vector3(((i & 1) == 0) ? ((Bounds)(ref box)).min.x : ((Bounds)(ref box)).max.x, ((i & 2) == 0) ? ((Bounds)(ref box)).min.y : ((Bounds)(ref box)).max.y, ((i & 4) == 0) ? ((Bounds)(ref box)).min.z : ((Bounds)(ref box)).max.z); } return array; } private static bool PackedVehicleAreaAllowed(Player player, Vector3 position, Quaternion rotation, Bounds bounds) { //IL_0006: 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_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_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_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_0050: Unknown result type (might be due to invalid IL or missing references) if (!PrivateArea.CheckAccess(((Component)player).transform.position, 0f, true, false)) { return false; } Vector3[] array = PackedVehicleBoxCorners(bounds); foreach (Vector3 val in array) { if (!PackedVehiclePointAllowed(player, position + rotation * val)) { return false; } } return PackedVehiclePointAllowed(player, position); } private static bool PackedVehiclePointAllowed(Player player, Vector3 position) { //IL_0000: 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) if (Location.IsInsideNoBuildLocation(position)) { Tell(player, "Building is not allowed here."); return false; } if (RailWardAccess.Allows(position, player.GetPlayerID())) { return true; } Tell(player, "You need permission to place a vehicle in this protected area."); return false; } internal bool HasPlowAt(bool front) { if (AttachedPlowId.Length != 0) { return MountedPlowFront == front; } return false; } internal void SetPlowId(string identity, bool front = true) { if (Ready && _view.IsOwner()) { ClearPlowIntent(); _view.GetZDO().Set("vikingrail_plow_front", front); _view.GetZDO().Set("vikingrail_plow", identity); } } internal bool CanChangePlow(out string reason) { reason = "Park the whole train, dismount its operators, and finish storage or coupling before changing a plow."; if (!Ready || !FindRoot(out RailVehicle root) || !CouplingRootStopped(root) || root.HasDriveAuthority || !ReadCouplingChain(root, out List chain)) { return false; } foreach (RailVehicle item in chain) { if (!item.Ready || item._packing || item._packPending || item._pendingMount || item.DriverId != 0L || Object.op_Implicit((Object)(object)item._driver) || item.AutomaticDriveRequested || item.CargoBusy || item.CargoServiceBusy || item.CouplingServiceBusy || item.MountServiceBusy || Mathf.Abs(item.Speed) >= 0.05f || (Object.op_Implicit((Object)(object)ZNet.instance) && item._view.GetZDO().GetLong("vikingrail_moving_until", 0L) > CargoNow)) { return false; } } reason = ""; return true; } internal bool TryPlowDriveAuthority(out RailVehicle root) { root = null; if (!Ready || !Object.op_Implicit((Object)(object)MountedPlow) || HasCouplingAt(MountedPlowFront) || !FindRoot(out root) || !root.HasDriveAuthority || root._view.GetZDO().GetOwner() != _view.GetZDO().GetOwner() || !ReadCouplingChain(root, out List chain) || !root.TryFormation(chain, out Dictionary slots, out Dictionary reversed) || (!root.IsEngine && (!root.CanHandPush || chain.Count != 1))) { return false; } bool flag = _view.GetZDO().GetBool("vikingrail_plow_intent_forward", true); if (root._view.GetZDO().GetBool("vikingrail_plow_drive_forward", true) == flag && (Object)(object)chain[LeadingIndex(chain, slots, flag)] == (Object)(object)this) { return MountedPlowFront == (flag != reversed[this]); } return false; } internal static bool PlowContact(Character creature, Vector3 position, Quaternion rotation, float sweepDistance = 0f) { //IL_001a: 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_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_0027: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_008d: 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_00b0: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)creature) || creature.IsPlayer() || creature.IsDead()) { return false; } Vector3 val = Quaternion.Inverse(rotation) * (creature.GetCenterPoint() - position); float radius = creature.GetRadius(); float num = creature.GetHeight() * 0.5f; if (float.IsNaN(sweepDistance) || float.IsInfinity(sweepDistance) || sweepDistance < 0f || (double)sweepDistance > 0.75) { return false; } if (val.z + radius >= 0.7f && val.z - radius <= 1.65f + sweepDistance && Mathf.Abs(val.x) <= 1.15f + radius && val.y + num >= 0.2f) { return val.y - num <= 1.1f; } return false; } private bool CanPlow(Character creature, float approachSpeed, float sweepDistance) { //IL_000f: 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_0023: 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_0039: Unknown result type (might be due to invalid IL or missing references) VikingRail.Core.RailPlowPush push; if (Object.op_Implicit((Object)(object)MountedPlow) && PlowContact(creature, PlowPosition, PlowRotation, sweepDistance)) { return RailPlowMath.TryPlan(RailSegment.ToRail(PlowPosition), RailSegment.ToRail(PlowForward), RailSegment.ToRail(creature.GetCenterPoint()), creature.GetRadius(), approachSpeed, attached: true, creature.IsPlayer(), !creature.IsDead(), out push, sweepDistance); } return false; } private void NudgeWithPlow(HashSet creatures, float approachSpeed, float sweepDistance, bool forward) { if (!Ready || !_view.IsOwner() || !Object.op_Implicit((Object)(object)MountedPlow) || !Object.op_Implicit((Object)(object)ZNet.instance)) { return; } _view.GetZDO().Set("vikingrail_plow_intent_forward", forward); if (!TryPlowDriveAuthority(out RailVehicle _)) { return; } long num = (long)(ZNet.instance.GetTimeSeconds() * 1000.0); _plowContactSpeed = Mathf.Max(_plowContactSpeed, Mathf.Clamp(approachSpeed, 0.1f, 15f)); _plowContactTravel = Mathf.Max(_plowContactTravel, Mathf.Clamp(sweepDistance, 0f, 0.75f)); _view.GetZDO().Set("vikingrail_plow_intent_until", num + 500); _view.GetZDO().Set("vikingrail_plow_intent_speed", _plowContactSpeed); _view.GetZDO().Set("vikingrail_plow_intent_travel", _plowContactTravel); foreach (Character creature in creatures) { RailPlowPush.Request(creature, this); } } private void ClearPlowIntent() { RailVehicle activePlowCarrier = _activePlowCarrier; _activePlowCarrier = null; if (Object.op_Implicit((Object)(object)activePlowCarrier) && (Object)(object)activePlowCarrier != (Object)(object)this) { activePlowCarrier.ClearOwnPlowIntent(); } ClearOwnPlowIntent(); } private void ClearOwnPlowIntent() { _plowContactSpeed = 0f; _plowContactTravel = 0f; if (Ready && _view.IsOwner()) { _view.GetZDO().Set("vikingrail_plow_intent_until", 0L); _view.GetZDO().Set("vikingrail_plow_intent_speed", 0f); _view.GetZDO().Set("vikingrail_plow_intent_travel", 0f); } } private void TransferPlowOwnership(long peer) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) RailPlow mountedPlow = MountedPlow; if (Object.op_Implicit((Object)(object)mountedPlow)) { ZNetView component = ((Component)mountedPlow).GetComponent(); if (Object.op_Implicit((Object)(object)component) && component.IsValid()) { component.ClaimOwnership(); component.GetZDO().SetOwner(peer); ZDOMan.instance.ForceSendZDO(peer, component.GetZDO().m_uid); } } } private static void AddVolumeHits(List hits, Vector3 start, Vector3 end, Vector3 half, Quaternion rotation) { //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_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_0018: 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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_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) hits.AddRange(Physics.OverlapBox(end, half, rotation, -1, (QueryTriggerInteraction)1)); Vector3 val = end - start; if (!(((Vector3)(ref val)).sqrMagnitude <= 1E-05f)) { RaycastHit[] array = Physics.BoxCastAll(start, half, ((Vector3)(ref val)).normalized, rotation, ((Vector3)(ref val)).magnitude, -1, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { RaycastHit val2 = array[i]; hits.Add(((RaycastHit)(ref val2)).collider); } } } private void InitializePacking() { _view.Register("VR_VehiclePack", (Action)RequestPack); _view.Register("VR_VehiclePackReply", (Action)PackReply); } private bool UpdatePacking() { if (IsPacked) { if (_view.IsOwner() && Object.op_Implicit((Object)(object)ZNetScene.instance)) { ZNetScene.instance.Destroy(((Component)this).gameObject); } return true; } if (_packPending && Time.unscaledTime - _packRequestTime > 6f) { _packPending = false; Tell(Player.m_localPlayer, "Packing request timed out. Check for the bundle beside the vehicle before trying again."); } return false; } internal bool BeginPack(Player player) { //IL_0076: 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_0098: Unknown result type (might be due to invalid IL or missing references) if (!Ready || _packing || _packPending || !Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return false; } if (!RailSettings.Ready) { Tell(player, "Waiting for server railroad settings."); return false; } if (((Character)player).IsDead() || ((Character)player).IsTeleporting() || ((Character)player).IsAttached() || player.GetDoodadController() != null) { Tell(player, "Stand beside the vehicle on foot before packing it."); return false; } if (Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position) > 4f || !PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return false; } if (!CanPack(out string reason)) { Tell(player, reason); return false; } if (!_view.HasOwner()) { Tell(player, "Waiting for the vehicle's network owner. Try again shortly."); return false; } _packPending = true; _packRequestTime = Time.unscaledTime; _packRequestOwner = _view.GetZDO().GetOwner(); _view.InvokeRPC("VR_VehiclePack", new object[1] { player.GetPlayerID() }); return true; } private bool CanPack(out string reason) { reason = ""; if (!Ready || _packing) { reason = "This vehicle is already being packed."; return false; } if (AutomaticDriveRequested || AttachedAutoDriveId.Length != 0) { reason = "Stop and detach the automatic controller before packing the engine."; return false; } if (HasMountedObjects || MountServiceBusy) { reason = "Detach both mounted objects before packing this cart."; return false; } if (CargoServiceBusy || CouplingServiceBusy) { reason = "Wait for storage or coupling to finish before packing the vehicle."; return false; } if (DriverId != 0L || Object.op_Implicit((Object)(object)_driver) || _pendingMount || HasPassengers || Mathf.Abs(Speed) >= 0.05f || (Object.op_Implicit((Object)(object)ZNet.instance) && _view.GetZDO().GetLong("vikingrail_moving_until", 0L) > (long)(ZNet.instance.GetTimeSeconds() * 1000.0))) { reason = "Stop the vehicle and have everyone dismount before packing it."; return false; } if (ParentId.Length != 0 || NextId.Length != 0 || FrontId.Length != 0) { reason = "Uncouple this vehicle from the train at both ends before packing it."; return false; } if (CargoBusy) { reason = "Close the storage or fuel hopper before packing the vehicle."; return false; } if (AttachedPlowId.Length != 0) { reason = "Detach the plow before packing the vehicle. The plow can be picked up separately."; return false; } for (int i = 0; i < 4; i++) { if (_view.GetZDO().GetString(RailTorchMounts.Key(i) + "_guid", "").Length != 0) { reason = "Remove the attached torches before packing the vehicle."; return false; } } return true; } private void RequestPack(long sender, long playerId) { //IL_0365: 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_006e: 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_0248: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0261: 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_02d7: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !_view.IsOwner() || _packing) { return; } Player player = Player.GetPlayer(playerId); if (!RailSettings.Ready || !Object.op_Implicit((Object)(object)player) || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || ((Character)player).IsAttached() || player.GetDoodadController() != null || ((Character)player).GetOwner() != sender || Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position) > 4f || !RailWardAccess.Allows(((Component)this).transform.position, playerId)) { ReplyPack(sender, success: false, "Stand beside the parked vehicle with permission to use it."); return; } if (!CanPack(out string reason)) { ReplyPack(sender, success: false, reason); return; } string text = PackedVehicle.ItemName(Utils.GetPrefabName(((Component)this).gameObject)); GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab(text) : null); ItemDrop val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent() : null); WearNTear component = ((Component)this).GetComponent(); if (!Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)ZNetScene.instance)) { ReplyPack(sender, success: false, "The packed vehicle item is unavailable."); return; } ItemDrop val3 = null; bool flag = false; try { ItemData val4 = val2.m_itemData.Clone(); val4.m_dropPrefab = val; val4.m_stack = 1; val4.m_customData["vikingrail_vehicle_version"] = "1"; val4.m_customData["vikingrail_vehicle_health"] = PackedVehicle.EncodeHealth(_view.GetZDO().GetFloat(ZDOVars.s_health, component.m_health), component.m_health); val4.m_customData["vikingrail_vehicle_fuel_seconds"] = PackedVehicle.EncodeFuel(FuelSeconds); val4.m_customData["vikingrail_vehicle_lamps"] = PackedVehicle.EncodeBoolean(LightsOn); RailPassengerFire component2 = ((Component)this).GetComponent(); if (Object.op_Implicit((Object)(object)component2)) { component2.Capture(val4.m_customData); } RailMusicCart component3 = ((Component)this).GetComponent(); if (Object.op_Implicit((Object)(object)component3)) { component3.Capture(val4.m_customData); } RailPackedInventory.Capture(_container, val4); _packing = true; _view.GetZDO().Set("vikingrail_vehicle_packed", true); val3 = ItemDrop.DropItem(val4, 1, ((Component)player).transform.position + Vector3.up * 0.5f, Quaternion.identity); ZNetView val5 = (Object.op_Implicit((Object)(object)val3) ? ((Component)val3).GetComponent() : null); if (!Object.op_Implicit((Object)(object)val5) || !val5.IsValid()) { throw new InvalidOperationException("Packed vehicle has no network identity."); } flag = true; _view.GetZDO().Set("vikingrail_vehicle_packed_item", val5.GetZDO().m_uid); if (ZDOMan.instance != null) { ZDOMan.instance.ForceSendZDO(sender, val5.GetZDO().m_uid); } ReplyPack(sender, success: true, "Vehicle packed. Pick up the bundle; use it while facing clear track to place it again."); ZNetScene.instance.Destroy(((Component)this).gameObject); } catch (Exception ex) { RailPlugin.Error(ex); if (!flag) { if (Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)ZNetScene.instance)) { ZNetScene.instance.Destroy(((Component)val3).gameObject); } if (Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { _view.GetZDO().Set("vikingrail_vehicle_packed_item", ZDOID.None); _view.GetZDO().Set("vikingrail_vehicle_packed", false); } _packing = false; ReplyPack(sender, success: false, "Vehicle left in place: " + ex.GetBaseException().Message); } } } private void ReplyPack(long sender, bool success, string message) { if (Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { _view.InvokeRPC(sender, "VR_VehiclePackReply", new object[2] { success, message }); } } private void PackReply(long sender, bool success, string message) { if (_packPending && sender == _packRequestOwner) { _packPending = false; Tell(Player.m_localPlayer, message); } } internal bool TryRemoteMembers(long peer, long playerId, out List members, out string reason) { //IL_01dc: Unknown result type (might be due to invalid IL or missing references) members = new List(); reason = "Park the entire train, dismount everyone, and close its storage before starting."; if (!SupportsAutoDrive || !Ready || !ValidRequester(peer, playerId, out Player player) || ((Character)player).IsTeleporting() || ((Character)player).IsAttached() || player.GetDoodadController() != null || AutomaticDriveRequested || DriverId != 0L || Object.op_Implicit((Object)(object)_driver) || _pendingMount || _packing || _packPending || !FindRoot(out RailVehicle root) || !CouplingRootStopped(root) || !TryCursor() || !HasCompatibleTrack() || !ReadCouplingChain(root, out List chain) || !chain.Contains(this) || chain.Count > 128 || chain.Count((RailVehicle cart) => cart.IsEngine) > 21 || chain.Any((RailVehicle cart) => cart.IsEngine && !MultiEngineCompatible(this, cart))) { return false; } RailAutoDrive mountedAutoDrive = MountedAutoDrive; if (!Object.op_Implicit((Object)(object)mountedAutoDrive) || !mountedAutoDrive.IsReady) { reason = "Wait for the automatic controller to load."; return false; } foreach (RailVehicle item in chain) { if (!CouplingWagonIdle(item) || item.DriverId != 0L || Object.op_Implicit((Object)(object)item._driver) || item._pendingMount || item.AutomaticDriveRequested || item.HasPassengers || RailTurntable.BlocksVehicle(item) || item._couplingOperation != null || item.HasCouplingLease || item._contactCouplingClient != null || !item.TryCursor() || !RailWardAccess.Allows(((Component)item).transform.position, playerId)) { return false; } members.Add(item.View); if (item.AttachedPlowId.Length != 0) { if (!Object.op_Implicit((Object)(object)item.MountedPlow)) { reason = "Wait for every attached plow to load."; return false; } members.Add(item.MountedPlow.View); } if (item.AttachedAutoDriveId.Length != 0) { RailAutoDrive mountedAutoDrive2 = item.MountedAutoDrive; if (!Object.op_Implicit((Object)(object)mountedAutoDrive2) || !mountedAutoDrive2.IsReady) { reason = "Wait for every attached automatic controller to load."; return false; } members.Add(mountedAutoDrive2.View); } RailTorchMounts component = ((Component)item).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { for (int num = 0; num < component.Count; num++) { string text = component.IdentityAt(num); if (text.Length != 0) { RailMountedTorch railMountedTorch = RailMountedTorch.Find(text); if (!Object.op_Implicit((Object)(object)railMountedTorch) || !railMountedTorch.Ready || (Object)(object)railMountedTorch.Vehicle != (Object)(object)item || railMountedTorch.Slot != num) { reason = "Wait for every attached torch to load."; return false; } members.Add(railMountedTorch.View); } } } RailMountCart mountCart = item.MountCart; if (!Object.op_Implicit((Object)(object)mountCart)) { continue; } for (int num2 = 0; num2 < 2; num2++) { if (mountCart.Phase(num2) != 0 || mountCart.ChildIdentity(num2).Length != 0) { RailMountedObject railMountedObject = mountCart.Attachment(num2); if (mountCart.Phase(num2) != 2 || !Object.op_Implicit((Object)(object)railMountedObject) || !railMountedObject.Alive || !railMountedObject.IsAttached || (Object)(object)railMountedObject.Vehicle != (Object)(object)item || !railMountedObject.MotionCompatible) { reason = "Wait for every mounted object to finish synchronizing."; return false; } members.Add(railMountedObject.View); } } } if (members.Count > 320 || members.Any((ZNetView v) => !Object.op_Implicit((Object)(object)v) || !v.IsValid() || !RailWardAccess.Allows(((Component)v).transform.position, playerId) || RemoteContainerBusy(v))) { return false; } members = members.Distinct().ToList(); reason = ""; return true; } private static bool RemoteContainerBusy(ZNetView view) { Container component = ((Component)view).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { string error; if (!component.IsInUse() && view.GetZDO().GetInt("InUse", 0) == 0) { return !RailCargoInventory.TryRefresh(component, out error, requireOwner: false); } return true; } return false; } internal void SaveRemoteHandoffPose() { if (Ready && _view.IsOwner()) { Halt("Preparing automatic train for server operation."); if (TryCursor()) { SaveCursor(_cursor.Value, RailVehiclePose.Sample(RailSegment.Network, _cursor.Value)); } } } internal bool StartRemoteDrive(long peer, long player, string token, IReadOnlyCollection expected, out string reason) { if (!Ready || !_view.IsOwner() || !TryRemoteMembers(peer, player, out List members, out reason)) { reason = "The stopped train or its operator changed during preparation."; return false; } if (members.Count != expected.Count || members.Any((ZNetView v) => !v.IsOwner() || !expected.Contains(v.GetZDO().m_uid))) { reason = "Wait for the whole train's network ownership to settle."; return false; } foreach (ZNetView item in members) { Container component = ((Component)item).GetComponent(); if (Object.op_Implicit((Object)(object)component) && !RailCargoInventory.TryRefreshForOwnership(component, out reason)) { return false; } } if (!FindRoot(out RailVehicle root) || !ReadCouplingChain(root, out List train) || !train.Contains(this)) { reason = "Wait for the complete train's links to synchronize."; return false; } if (!TryRerootTrain(this, train, out reason)) { return false; } if (!BuildTrain(out train, out reason) || !ConsistHasFuel(0.05)) { reason = "Load at least one matching engine with " + FuelName + " and keep the train on connected track."; return false; } _view.GetZDO().Set("vikingrail_remote_session", token); ActivateAutomaticDrive(train, "Automatic drive active. The server keeps the route around this train loaded."); reason = "Automatic train running with its own loaded area."; return true; } internal bool RemoteLoadingPositions(out List positions) { //IL_0057: 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_00b9: 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_00de: 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_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) positions = new List(); if (!Ready || !FindRoot(out RailVehicle root) || !ReadCouplingChain(root, out List chain) || !chain.Contains(this) || !root.TryFormation(chain, out Dictionary slots, out Dictionary reversed)) { return false; } foreach (RailVehicle item in chain) { positions.Add(((Component)item).transform.position); } bool flag = !reversed[this]; RailVehicle railVehicle = chain[LeadingIndex(chain, slots, flag)]; Vector3 val = ((Component)railVehicle).transform.forward * (reversed[railVehicle] ? (-1f) : 1f) * (flag ? 1f : (-1f)); positions.Add(((Component)railVehicle).transform.position + val * 24f); return true; } private bool RemoteRouteReady() { //IL_0023: 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 (!RemoteManaged) { return true; } if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer() || !RailRemoteDrive.IsActive(Id)) { StopAutomaticDrive("Automatic train session ended. Use the controller to start again."); return false; } if (RailRemoteWorld.IsReady(Id)) { return true; } Halt("Loading the railway ahead. Automatic train is waiting.", keepPlowIntent: false, keepAutomaticDrive: true); return false; } private void InitializeSmoke() { if (CombustionPowered && Ready) { _smokeKnownOwner = _view.GetZDO().GetOwner(); if (_view.IsOwner()) { PublishSmoke(active: false); } } } private void BeginSmokeStep() { _smokeStepPowered = false; _smokeStepTime = Time.time; } private void NotifySmokePowered() { if (CombustionPowered && Ready && _view.IsOwner()) { _smokeStepPowered = true; _smokeStepTime = Time.time; } } private void UpdateSmoke() { //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) if (!CombustionPowered || !Ready || !Object.op_Implicit((Object)(object)ZNet.instance)) { SetSmokeEmission(active: false, clear: true); return; } ZDO zDO = _view.GetZDO(); long owner = zDO.GetOwner(); if (owner != _smokeKnownOwner) { _smokeKnownOwner = owner; _smokeStepPowered = false; _smokePublished = false; _nextSmokePublish = 0f; SetSmokeEmission(active: false, clear: true); if (_view.IsOwner()) { PublishSmoke(active: false); } } bool flag; if (_view.IsOwner()) { flag = _smokeStepPowered && IsLocallySimulatedMotion && HasMotionAuthority && (AutoDriveActive || !_brake) && Time.time - _smokeStepTime <= Mathf.Max(0.1f, Time.fixedDeltaTime * 2.5f); if (flag != _smokePublished || (flag && Time.time >= _nextSmokePublish)) { PublishSmoke(flag); } } else { long num = zDO.GetLong("vikingrail_smoke_until", 0L) - ZNet.instance.GetTime().Ticks; flag = HasMotionAuthority && zDO.GetLong("vikingrail_smoke_owner", 0L) == owner && owner != 0L && num > 0 && (float)num <= 30000000f; } Player localPlayer = Player.m_localPlayer; int num2; if (Object.op_Implicit((Object)(object)localPlayer)) { Vector3 val = ((Component)localPlayer).transform.position - ((Component)this).transform.position; num2 = ((((Vector3)(ref val)).sqrMagnitude <= 4096f) ? 1 : 0); } else { num2 = 0; } bool flag2 = (byte)num2 != 0; SetSmokeEmission(flag && flag2, !flag2); } private void PublishSmoke(bool active) { if (CombustionPowered && Ready && _view.IsOwner()) { ZDO zDO = _view.GetZDO(); zDO.Set("vikingrail_smoke_owner", zDO.GetOwner()); zDO.Set("vikingrail_smoke_until", (active && Object.op_Implicit((Object)(object)ZNet.instance)) ? (ZNet.instance.GetTime().Ticks + 20000000) : 0); _smokePublished = active; _nextSmokePublish = Time.time + 0.5f; } } private void StopSmoke() { _smokeStepPowered = false; PublishSmoke(active: false); SetSmokeEmission(active: false, clear: false); } private void SetSmokeEmission(bool active, bool clear) { if (active && !Object.op_Implicit((Object)(object)_chimneySmoke) && !_smokeFailed) { try { CreateChimneySmoke(); } catch (Exception ex) { _smokeFailed = true; CleanupSmokeParticles(); RailPlugin.Warn("Could not create locomotive exhaust; the engine can still operate. " + ex.Message); } } if (!Object.op_Implicit((Object)(object)_chimneySmoke)) { return; } if (active) { if (!_chimneySmoke.isPlaying) { _chimneySmoke.Play(false); } } else if (_chimneySmoke.isPlaying || (clear && _chimneySmoke.particleCount != 0)) { _chimneySmoke.Stop(false, (ParticleSystemStopBehavior)(!clear)); } } private void CreateChimneySmoke() { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //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_00b8: 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_0107: 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_013e: 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_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: 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_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0246: 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_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0284: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Expected O, but got Unknown //IL_02a9: 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_02c8: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Expected O, but got Unknown //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_034e: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_037a: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_0398: Unknown result type (might be due to invalid IL or missing references) //IL_039d: Unknown result type (might be due to invalid IL or missing references) //IL_03ad: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) ParticleSystem val = (ParticleSystem)((Object.op_Implicit((Object)(object)SmokeRenderer.Instance) && SmokeTemplateField != null) ? /*isinst with value type is only supported in some contexts*/: null); ParticleSystemRenderer val2 = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent() : null); Material val3 = (Object.op_Implicit((Object)(object)val2) ? ((Renderer)val2).sharedMaterial : null); if (!Object.op_Implicit((Object)(object)val3)) { val3 = CreateFallbackSmokeMaterial(); } GameObject val4 = new GameObject("vr_chimney_smoke"); val4.SetActive(false); val4.transform.SetParent(((Component)this).transform, false); Transform val5 = ((Component)this).transform.Find("vr_smoke_origin"); val4.transform.localPosition = (Vector3)(Object.op_Implicit((Object)(object)val5) ? ((Component)this).transform.InverseTransformPoint(val5.position) : new Vector3(0f, 2.62f, 0.81f)); val4.transform.localRotation = Quaternion.Euler(-90f, 0f, 0f); _chimneySmoke = val4.AddComponent(); MainModule main = _chimneySmoke.main; ((MainModule)(ref main)).playOnAwake = false; ((MainModule)(ref main)).loop = true; ((MainModule)(ref main)).duration = 4f; ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; ((MainModule)(ref main)).startLifetime = new MinMaxCurve(2.8f, 3.6f); ((MainModule)(ref main)).startSpeed = new MinMaxCurve(0.7f, 1.1f); ((MainModule)(ref main)).startSize = (BronzePowered ? new MinMaxCurve(0.22f, 0.36f) : new MinMaxCurve(0.35f, 0.55f)); ((MainModule)(ref main)).startRotation = new MinMaxCurve(0f, (float)Math.PI * 2f); ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(Color.white); ((MainModule)(ref main)).gravityModifier = MinMaxCurve.op_Implicit(-0.015f); ((MainModule)(ref main)).maxParticles = 64; ((MainModule)(ref main)).cullingMode = (ParticleSystemCullingMode)1; EmissionModule emission = _chimneySmoke.emission; ((EmissionModule)(ref emission)).enabled = true; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(BronzePowered ? 5f : 9f); ShapeModule shape = _chimneySmoke.shape; ((ShapeModule)(ref shape)).enabled = true; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)4; ((ShapeModule)(ref shape)).angle = 10f; ((ShapeModule)(ref shape)).radius = 0.1f; SizeOverLifetimeModule sizeOverLifetime = _chimneySmoke.sizeOverLifetime; ((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled = true; ((SizeOverLifetimeModule)(ref sizeOverLifetime)).size = new MinMaxCurve(1f, new AnimationCurve((Keyframe[])(object)new Keyframe[3] { new Keyframe(0f, 0.55f), new Keyframe(0.45f, 1.8f), new Keyframe(1f, 3.2f) })); ColorOverLifetimeModule colorOverLifetime = _chimneySmoke.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true; Gradient val6 = new Gradient(); val6.SetKeys((GradientColorKey[])(object)new GradientColorKey[2] { new GradientColorKey(new Color(0.22f, 0.22f, 0.22f), 0f), new GradientColorKey(new Color(0.48f, 0.48f, 0.48f), 1f) }, (GradientAlphaKey[])(object)new GradientAlphaKey[4] { new GradientAlphaKey(0f, 0f), new GradientAlphaKey(0.6f, 0.08f), new GradientAlphaKey(0.35f, 0.55f), new GradientAlphaKey(0f, 1f) }); ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(val6); CollisionModule collision = _chimneySmoke.collision; ((CollisionModule)(ref collision)).enabled = false; TriggerModule trigger = _chimneySmoke.trigger; ((TriggerModule)(ref trigger)).enabled = false; ParticleSystemRenderer component = val4.GetComponent(); ((Renderer)component).sharedMaterial = val3; component.renderMode = (ParticleSystemRenderMode)0; component.alignment = (ParticleSystemRenderSpace)0; ((Renderer)component).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)component).receiveShadows = false; val4.SetActive(true); _chimneySmoke.Stop(false, (ParticleSystemStopBehavior)0); } private Material CreateFallbackSmokeMaterial() { //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) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //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_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown //IL_0136: 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_00c6: 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) Shader val = Shader.Find("Legacy Shaders/Particles/Alpha Blended") ?? Shader.Find("Particles/Standard Unlit"); if (!Object.op_Implicit((Object)(object)val)) { throw new InvalidOperationException("Neither the native smoke material nor a particle shader is available."); } _ownedSmokeTexture = new Texture2D(32, 32, (TextureFormat)4, false) { name = "VikingRail smoke puff", wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)1 }; Color[] array = (Color[])(object)new Color[1024]; for (int i = 0; i < 32; i++) { for (int j = 0; j < 32; j++) { float num = ((float)j - 15.5f) / 15.5f; float num2 = ((float)i - 15.5f) / 15.5f; float num3 = Mathf.Clamp01(1f - Mathf.Sqrt(num * num + num2 * num2)); array[i * 32 + j] = new Color(1f, 1f, 1f, num3 * num3); } } _ownedSmokeTexture.SetPixels(array); _ownedSmokeTexture.Apply(false, true); _ownedSmokeMaterial = new Material(val) { name = "VikingRail smoke", mainTexture = (Texture)(object)_ownedSmokeTexture }; if (_ownedSmokeMaterial.HasProperty("_TintColor")) { _ownedSmokeMaterial.SetColor("_TintColor", Color.white); } if (_ownedSmokeMaterial.HasProperty("_Color")) { _ownedSmokeMaterial.SetColor("_Color", Color.white); } if (_ownedSmokeMaterial.HasProperty("_Mode")) { _ownedSmokeMaterial.SetFloat("_Mode", 2f); _ownedSmokeMaterial.SetInt("_SrcBlend", 5); _ownedSmokeMaterial.SetInt("_DstBlend", 10); _ownedSmokeMaterial.SetInt("_ZWrite", 0); _ownedSmokeMaterial.EnableKeyword("_ALPHABLEND_ON"); _ownedSmokeMaterial.renderQueue = 3000; } return _ownedSmokeMaterial; } private void CleanupSmokeParticles() { if (Object.op_Implicit((Object)(object)_chimneySmoke)) { Object.Destroy((Object)(object)((Component)_chimneySmoke).gameObject); } if (Object.op_Implicit((Object)(object)_ownedSmokeMaterial)) { Object.Destroy((Object)(object)_ownedSmokeMaterial); } if (Object.op_Implicit((Object)(object)_ownedSmokeTexture)) { Object.Destroy((Object)(object)_ownedSmokeTexture); } _chimneySmoke = null; _ownedSmokeMaterial = null; _ownedSmokeTexture = null; } private void CleanupSmoke() { StopSmoke(); CleanupSmokeParticles(); } private void InitializeSteamMachinery() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 if (CoalPowered && (int)SystemInfo.graphicsDeviceType != 4) { _steamLeftFront = ((Component)this).transform.Find("visual/vr_steam_wheel_left_front"); _steamLeftRear = ((Component)this).transform.Find("visual/vr_steam_wheel_left_rear"); _steamRightFront = ((Component)this).transform.Find("visual/vr_steam_wheel_right_front"); _steamRightRear = ((Component)this).transform.Find("visual/vr_steam_wheel_right_rear"); _steamLeftRod = ((Component)this).transform.Find("visual/vr_steam_rod_left"); _steamRightRod = ((Component)this).transform.Find("visual/vr_steam_rod_right"); _steamLeftPiston = ((Component)this).transform.Find("visual/vr_steam_piston_left"); _steamRightPiston = ((Component)this).transform.Find("visual/vr_steam_piston_right"); _steamFlywheel = ((Component)this).transform.Find("visual/vr_steam_flywheel"); } } private static bool SteamFinite(Vector3 value) { //IL_0000: 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_001a: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!float.IsNaN(value.x) && !float.IsInfinity(value.x) && !float.IsNaN(value.y) && !float.IsInfinity(value.y) && !float.IsNaN(value.z)) { return !float.IsInfinity(value.z); } return false; } private static RailVector SteamVector(Vector3 value) { //IL_0000: 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_000e: Unknown result type (might be due to invalid IL or missing references) return new RailVector(value.x, value.y, value.z); } private void UpdateSteamMachinery() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Invalid comparison between Unknown and I4 //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_007c: 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_00ad: 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_00b9: 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_0120: 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_0127: 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_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: 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) if (!CoalPowered || !IsEngine || !Ready || !Object.op_Implicit((Object)(object)ZNet.instance) || ZNet.instance.IsDedicated() || (int)SystemInfo.graphicsDeviceType == 4) { _steamMotionBaseline = false; return; } if (!HasMotionAuthority) { _steamMotionBaseline = false; if (!_steamPoseApplied) { ApplySteamMachinery(); } return; } double unscaledTimeAsDouble = Time.unscaledTimeAsDouble; Vector3 position = ((Component)this).transform.position; Vector3 forward = ((Component)this).transform.forward; if (!SteamFinite(position) || !SteamFinite(forward)) { _steamMotionBaseline = false; return; } ZDO zDO = _view.GetZDO(); long owner = zDO.GetOwner(); int ownerRevision = zDO.OwnerRevision; Vector3 value = position - _steamLastPosition; if (_steamMotionBaseline && SteamFinite(value) && owner != 0L && owner == _steamMotionOwner && ownerRevision == _steamMotionOwnerRevision && RailSteamMotion.TryRoll(SteamVector(value), SteamVector(_steamLastForward), SteamVector(forward), unscaledTimeAsDouble - _steamLastTime, out var radians)) { _steamPhase = RailSteamMotion.Advance(_steamPhase, radians); } _steamLastPosition = position; _steamLastForward = forward; _steamLastTime = unscaledTimeAsDouble; _steamMotionOwner = owner; _steamMotionOwnerRevision = ownerRevision; _steamMotionBaseline = true; ApplySteamMachinery(); } private void ApplySteamMachinery() { //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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_008f: 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_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_00a8: 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_00f1: 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_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_0124: 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_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018a: 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) _steamPoseApplied = true; double num = _steamPhase + Math.PI / 2.0; Quaternion localRotation = Quaternion.AngleAxis((float)(_steamPhase * 57.295780181884766), Vector3.right); Quaternion localRotation2 = Quaternion.AngleAxis((float)(num * 57.295780181884766), Vector3.right); if (Object.op_Implicit((Object)(object)_steamLeftFront)) { _steamLeftFront.localRotation = localRotation; } if (Object.op_Implicit((Object)(object)_steamLeftRear)) { _steamLeftRear.localRotation = localRotation; } if (Object.op_Implicit((Object)(object)_steamRightFront)) { _steamRightFront.localRotation = localRotation2; } if (Object.op_Implicit((Object)(object)_steamRightRear)) { _steamRightRear.localRotation = localRotation2; } Vector3 val = RailSegment.ToUnity(RailSteamMotion.Crank(_steamPhase)); Vector3 val2 = RailSegment.ToUnity(RailSteamMotion.Crank(num)); if (Object.op_Implicit((Object)(object)_steamLeftRod)) { _steamLeftRod.localPosition = new Vector3(-0.805f, 0.44f, 0f) + val; } if (Object.op_Implicit((Object)(object)_steamRightRod)) { _steamRightRod.localPosition = new Vector3(0.805f, 0.44f, 0f) + val2; } if (Object.op_Implicit((Object)(object)_steamLeftPiston)) { _steamLeftPiston.localPosition = new Vector3(-0.64f, 0.925f, 0.63f + val.z); } if (Object.op_Implicit((Object)(object)_steamRightPiston)) { _steamRightPiston.localPosition = new Vector3(0.64f, 0.925f, 0.63f + val2.z); } if (Object.op_Implicit((Object)(object)_steamFlywheel)) { _steamFlywheel.localRotation = localRotation; } } private void ResetTrackStops() { _brakeStop = null; _neutralAfterStop = false; _brakeBypass.Clear(); } private bool HoldAtBrakeTrack(List train, float input, bool controlsAvailable) { _brakeBypass.RemoveWhere((string id) => !RailSegment.HasStopMarker(id) || !train.Any((RailVehicle v) => v._cursor.HasValue && v._cursor.Value.SegmentId == id)); if (_brakeStop == null) { return false; } if (!RailSegment.HasStopMarker(_brakeStop)) { _brakeStop = null; return false; } if (controlsAvailable && Math.Abs(input) <= 0.05f) { _neutralAfterStop = true; } if (controlsAvailable && Math.Abs(input) > 0.05f && _neutralAfterStop) { _brakeBypass.Add(_brakeStop); _brakeStop = null; _neutralAfterStop = false; return false; } Halt("Brake track: release movement, then press forward or backward to depart."); return true; } private RailSafetyResult LimitAtTrackStops(List train, bool movingForward, double distance) { if (!TryFormation(train, out Dictionary slots, out Dictionary reversed)) { Halt("Wait for the whole train's couplings to synchronize."); return new RailSafetyResult(0.0, null, isBumper: false); } RailCursor[] trainCursors = (from v in train orderby slots[v] descending select (!reversed[v]) ? v._cursor.Value : v._cursor.Value.Reversed()).ToArray(); return RailSafety.FindFirstStop(RailSegment.Network, trainCursors, movingForward, distance, RailSegment.StopMarkers, _brakeBypass); } private bool CheckRelocations(List train, List destination, bool movingForward, double travel) { if (destination.Count != train.Count || !TryFormation(train, out Dictionary slots, out Dictionary _)) { Halt("Wait for the whole train's couplings to synchronize."); return false; } int num = LeadingIndex(train, slots, movingForward); for (int i = 0; i < train.Count; i++) { if (!RailSafety.CanRelocate(RailSegment.Network, train[i]._cursor.Value, destination[i], travel + 0.8, i == num, RailSegment.StopMarkers, _brakeBypass, out var obstruction)) { if (obstruction.HasStop) { ArriveAtTrackStop(obstruction); } else { Halt("A wagon cannot align on this route. Uncouple and reconnect it."); } return false; } } return true; } private void ArriveAtTrackStop(RailSafetyResult stop) { if (stop.IsBumper) { Halt(RailSwitch.IsClosedSwitchMarker(stop.MarkerId) ? "The railway switch is set to the other route. Reverse clear of the junction before changing it." : "End bumper. Reverse away from the buffer stop."); return; } _brakeStop = stop.MarkerId; _neutralAfterStop = false; Halt("Brake track: release movement, then press forward or backward to depart."); } internal bool BelongsToTrain(RailVehicle engine) { if (!((Object)(object)this == (Object)(object)engine)) { if (FindRoot(out RailVehicle root)) { return (Object)(object)root == (Object)(object)engine; } return false; } return true; } internal static bool OccupiesSwitch(IReadOnlyList paths, float clearance, RailVehicle? exemptEngine = null) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) foreach (RailVehicle vehicle in Vehicles) { if (Object.op_Implicit((Object)(object)vehicle) && vehicle.Ready && (!Object.op_Implicit((Object)(object)exemptEngine) || !vehicle.BelongsToTrain(exemptEngine)) && RailSwitchClearance.Contains(paths, RailSegment.ToRail(((Component)vehicle).transform.position), clearance)) { return true; } } return false; } private void ValidateManualThrottle() { if (IsEngine && (!ManualThrottleAvailable || Time.time - _inputTime >= 0.3f)) { CancelManualThrottle(); } } private void ApplyManualThrottle() { _manualThrottle.Step(_throttle > 0.05f || ZInput.GetButton("Forward"), _throttle < -0.05f || ZInput.GetButton("Backward"), _brake || !ManualThrottleAvailable || Time.time - _inputTime >= 0.3f); } private void OnApplicationFocus(bool focused) { if (!focused) { CancelManualThrottle(); } } private void OnApplicationPause(bool paused) { if (paused) { CancelManualThrottle(); } } private void OnDisable() { CancelManualThrottle(); } private void CancelManualThrottle() { _manualThrottle.Clear(); if (Object.op_Implicit((Object)(object)_driver)) { ClearPlowIntent(); } } private bool HasCompatibleTrack() { if (RequiresMetalTrack) { if (_cursor.HasValue) { return RailTrackCapacity.IsSupported(RailSegment.Network, _cursor.Value, 1.4, RailSegment.LightTrackIds); } return false; } return true; } private double LimitAtWoodenTrack(bool forward, double proposedDistance, out bool restricted) { restricted = false; if (!RequiresMetalTrack) { return proposedDistance; } return RailTrackCapacity.LimitTravel(RailSegment.Network, _cursor.Value, forward, proposedDistance, 1.4, RailSegment.LightTrackIds, out restricted); } internal static bool CollectTurntable(RailTurntable table, long playerId, out List members, out long owner, out string reason) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_03d3: Unknown result type (might be due to invalid IL or missing references) //IL_03d5: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: 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_03f7: Unknown result type (might be due to invalid IL or missing references) //IL_03fc: Unknown result type (might be due to invalid IL or missing references) //IL_040b: Unknown result type (might be due to invalid IL or missing references) //IL_040d: Unknown result type (might be due to invalid IL or missing references) //IL_0412: Unknown result type (might be due to invalid IL or missing references) //IL_0417: Unknown result type (might be due to invalid IL or missing references) //IL_0458: Unknown result type (might be due to invalid IL or missing references) //IL_0464: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Unknown result type (might be due to invalid IL or missing references) //IL_041f: Unknown result type (might be due to invalid IL or missing references) //IL_0421: Unknown result type (might be due to invalid IL or missing references) //IL_0352: Unknown result type (might be due to invalid IL or missing references) //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Unknown result type (might be due to invalid IL or missing references) //IL_0379: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_0380: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_03a0: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Unknown result type (might be due to invalid IL or missing references) //IL_038d: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Unknown result type (might be due to invalid IL or missing references) //IL_0397: Unknown result type (might be due to invalid IL or missing references) members = new List(); owner = 0L; reason = "Wait for the whole train to load."; HashSet hashSet = new HashSet(); foreach (RailVehicle vehicle in Vehicles) { if (Object.op_Implicit((Object)(object)vehicle) && table.NearDeck(((Component)vehicle).transform.position, 1.5f)) { if (!vehicle.Ready || !vehicle.FindRoot(out RailVehicle root) || !ReadCouplingChain(root, out List chain)) { return false; } hashSet.UnionWith(chain); } } List list = new List(); foreach (RailVehicle item in hashSet) { if (!item.Ready || !item.TryCursor()) { return false; } reason = "Stop the whole train, switch off automatic drive, and have everyone dismount."; if (Object.op_Implicit((Object)(object)item._driver) || item.DriverId != 0L || item.HasPassengers || item.AutomaticDriveRequested || Mathf.Abs(item.Speed) >= 0.01f || item._view.GetZDO().GetLong("vikingrail_moving_until", 0L) > CargoNow) { return false; } reason = "Close storage and finish mounting, packing or coupling first."; if (item._packing || item._packPending || item._pendingMount || item.CargoBusy || item.CargoServiceBusy || item.MountServiceBusy || item._couplingOperation != null || item.HasCouplingLease || item._contactCouplingClient != null || RailRemoteDrive.IsPreparing(item)) { return false; } reason = "You do not have access to the entire train."; if (!RailWardAccess.Allows(((Component)item).transform.position, playerId)) { return false; } long owner2 = item._view.GetZDO().GetOwner(); reason = "Wait for the train's ownership to settle. Take the engine controls once, then park and dismount."; if (owner2 == 0L || (owner != 0L && owner != owner2)) { return false; } owner = owner2; TurntableMember turntableMember = new TurntableMember { Cart = item, Cursor = item._cursor.Value, Links = item.TurntableLinks() }; turntableMember.Objects.Add(item._view); if (!item.CollectTurntableAttachments(turntableMember.Objects, out reason)) { return false; } bool flag = false; Bounds val = default(Bounds); Vector3[] array; foreach (ZNetView @object in turntableMember.Objects) { if (!Object.op_Implicit((Object)(object)@object) || !@object.IsValid() || !RailWardAccess.Allows(((Component)@object).transform.position, playerId)) { reason = "Wait for the complete train and its attachments to synchronize."; return false; } if (@object.GetZDO().GetOwner() != owner) { reason = "Wait for the train and all attachments to share their existing owner's authority."; return false; } turntableMember.Revisions.Add(@object, @object.GetZDO().OwnerRevision); Container component = ((Component)@object).GetComponent(); if (Object.op_Implicit((Object)(object)component) && (component.IsInUse() || @object.GetZDO().GetInt("InUse", 0) != 0)) { reason = "Close every attached container before turning."; return false; } if (!TryPackedVehicleBounds(((Component)@object).gameObject, out var bounds)) { reason = "The vehicle or an attachment's physical size could not be checked."; return false; } array = PackedVehicleBoxCorners(bounds); foreach (Vector3 val2 in array) { Vector3 val3 = ((Component)item).transform.InverseTransformPoint(((Component)@object).transform.TransformPoint(val2)); if (!flag) { val = new Bounds(val3, Vector3.zero); flag = true; } else { ((Bounds)(ref val)).Encapsulate(val3); } } } turntableMember.Bounds = val; Bounds val4 = default(Bounds); bool flag2 = true; array = PackedVehicleBoxCorners(val); foreach (Vector3 val5 in array) { Vector3 val6 = table.Deck.InverseTransformPoint(((Component)item).transform.TransformPoint(val5)); if (flag2) { ((Bounds)(ref val4))..ctor(val6, Vector3.zero); flag2 = false; } else { ((Bounds)(ref val4)).Encapsulate(val6); } } list.Add(new RailTurntableLoad(item._identity, turntableMember.Cursor, RailSegment.ToRail(((Bounds)(ref val4)).min), RailSegment.ToRail(((Bounds)(ref val4)).max))); members.Add(turntableMember); } return VikingRail.Core.RailTurntable.TryFit(table.Length, table.PathId, list, (IReadOnlyCollection)(object)hashSet.Select((RailVehicle c) => c._identity).ToArray(), out reason); } private bool CollectTurntableAttachments(List objects, out string reason) { reason = "Wait for every attached plow, torch, controller and mounted object to load."; if (AttachedPlowId.Length != 0) { if (!Object.op_Implicit((Object)(object)MountedPlow) || !MountedPlow.IsReady) { return false; } objects.Add(MountedPlow.View); } if (AttachedAutoDriveId.Length != 0) { if (!Object.op_Implicit((Object)(object)MountedAutoDrive) || !MountedAutoDrive.IsReady) { return false; } objects.Add(MountedAutoDrive.View); } RailTorchMounts component = ((Component)this).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { for (int i = 0; i < component.Count; i++) { string text = component.IdentityAt(i); if (text.Length != 0) { RailMountedTorch railMountedTorch = RailMountedTorch.Find(text); if (!Object.op_Implicit((Object)(object)railMountedTorch) || !railMountedTorch.Ready || (Object)(object)railMountedTorch.Vehicle != (Object)(object)this || railMountedTorch.Slot != i) { return false; } objects.Add(railMountedTorch.View); } } } RailMountCart mountCart = MountCart; if (Object.op_Implicit((Object)(object)mountCart)) { for (int j = 0; j < 2; j++) { if (mountCart.Phase(j) != 0 || mountCart.ChildIdentity(j).Length != 0) { RailMountedObject railMountedObject = mountCart.Attachment(j); if (mountCart.Phase(j) != 2 || !Object.op_Implicit((Object)(object)railMountedObject) || !railMountedObject.Alive || !railMountedObject.IsAttached || (Object)(object)railMountedObject.Vehicle != (Object)(object)this || !railMountedObject.MotionCompatible) { return false; } objects.Add(railMountedObject.View); } } } reason = ""; return true; } private string TurntableLinks() { return ParentId + "/" + NextId + "/" + FrontId + "/" + ParentFront + "/" + AttachedPlowId + "/" + MountedPlowFront + "/" + AttachedAutoDriveId; } internal static bool SameTurntableMembers(IReadOnlyList before, IReadOnlyList after) { if (before.Count != after.Count) { return false; } foreach (TurntableMember saved in before) { TurntableMember current = after.FirstOrDefault((TurntableMember m) => (Object)(object)m.Cart == (Object)(object)saved.Cart); if (current == null || current.Links != saved.Links || current.Cursor.SegmentId != saved.Cursor.SegmentId || current.Cursor.Direction != saved.Cursor.Direction || Math.Abs(current.Cursor.Distance - saved.Cursor.Distance) > 0.01 || current.Objects.Count != saved.Objects.Count || current.Objects.Any((ZNetView v) => !saved.Objects.Contains(v) || current.Revisions[v] != saved.Revisions[v])) { return false; } } return true; } internal void TurntableMove(TurntableMember member) { //IL_009b: 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) if (!Ready || !_view.IsOwner()) { throw new InvalidOperationException("Turntable vehicle authority changed."); } Speed = 0f; _manualThrottle.Clear(); ClearPlowIntent(); MoveTo(member.Cursor); if (Object.op_Implicit((Object)(object)MountedPlow)) { MountedPlow.FollowTurntable(this); } foreach (ZNetView @object in member.Objects) { if (Object.op_Implicit((Object)(object)@object) && @object.IsValid() && @object.IsOwner()) { @object.GetZDO().SetPosition(((Component)@object).transform.position); @object.GetZDO().SetRotation(((Component)@object).transform.rotation); } } PublishMotion(moving: false); Status = "Turntable: wait until the deck is aligned before taking the controls."; } internal bool TryWorkshopTrain(out List train) { train = new List(); if (FindRoot(out RailVehicle root) && ReadCouplingChain(root, out train)) { return train.Contains(this); } return false; } } public sealed class RailPassengerSeat : MonoBehaviour, Hoverable, Interactable, IDoodadController { public int SeatIndex; public Transform AttachPoint; public string AttachAnimation = "attach_chair"; public Vector3 DetachOffset = new Vector3(0f, 0.02f, 0.85f); private const long LeaseMilliseconds = 6000L; private const float BoardingRange = 3f; private RailVehicle _cart; private ZNetView _view; private bool _registered; private Player? _passenger; private string _localToken = ""; private long _requestPeer; private long _requestOwner; private long _requestPlayer; private bool _pending; private bool _granted; private float _requestAt; private float _nextRenew; private static readonly FieldInfo? WardList = AccessTools.Field(typeof(PrivateArea), "m_allAreas"); private static readonly MethodInfo? WardEnabled = AccessTools.Method(typeof(PrivateArea), "IsEnabled", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo? WardInside = AccessTools.Method(typeof(PrivateArea), "IsInside", new Type[2] { typeof(Vector3), typeof(float) }, (Type[])null); private static readonly MethodInfo? WardPermitted = AccessTools.Method(typeof(PrivateArea), "IsPermitted", new Type[1] { typeof(long) }, (Type[])null); private readonly Collider[] _exitOverlaps = (Collider[])(object)new Collider[64]; public static RailPassengerSeat? LocalSeat { get; private set; } private string Prefix => "vikingrail_seat_" + SeatIndex + "_"; private string RequestRpc => "VR_SeatRequest_" + SeatIndex; private string ReplyRpc => "VR_SeatReply_" + SeatIndex; private string RenewRpc => "VR_SeatRenew_" + SeatIndex; private string ReleaseRpc => "VR_SeatRelease_" + SeatIndex; private bool Ready { get { if (_registered && Object.op_Implicit((Object)(object)_cart) && _cart.IsReady && Object.op_Implicit((Object)(object)_view)) { return _view.IsValid(); } return false; } } private static long Now { get { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return 0L; } return (long)(ZNet.instance.GetTimeSeconds() * 1000.0); } } private PassengerSeatReservation Reservation { get { if (Ready) { return new PassengerSeatReservation(_view.GetZDO().GetLong(Prefix + "player", 0L), _view.GetZDO().GetLong(Prefix + "peer", 0L), _view.GetZDO().GetString(Prefix + "token", ""), _view.GetZDO().GetLong(Prefix + "until", 0L)); } return default(PassengerSeatReservation); } } public bool IsOccupied { get { if (Ready) { return Reservation.IsActive(Now); } return false; } } public long OccupantId { get { if (!IsOccupied) { return 0L; } return Reservation.Player; } } internal bool HasLocalRider(Player player) { if (Object.op_Implicit((Object)(object)player) && (Object)(object)player == (Object)(object)Player.m_localPlayer && (Object)(object)LocalSeat == (Object)(object)this && Ready && (Object)(object)_passenger == (Object)(object)player && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && Reservation.Matches(_requestPlayer, _requestPeer, _localToken) && Reservation.IsActive(Now)) { return HasSeatAttachment(player); } return false; } private void Awake() { _cart = ((Component)this).GetComponentInParent(); _view = ((Component)this).GetComponentInParent(); if (!Object.op_Implicit((Object)(object)AttachPoint)) { AttachPoint = ((Component)this).transform.Find("vr_attach") ?? ((Component)this).transform; } } private void Start() { if (Object.op_Implicit((Object)(object)_cart) && Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { _registered = true; _view.Register(RequestRpc, (Action)RequestSeat); _view.Register(ReplyRpc, (Action)SeatReply); _view.Register(RenewRpc, (Action)RenewSeat); _view.Register(ReleaseRpc, (Action)ReleaseSeat); ClearInvalidReservation(); } } private void Update() { //IL_00c4: 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_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) if (!Ready) { StopLocalPassenger(); return; } ClearInvalidReservation(); if (_pending) { Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting() || Time.unscaledTime - _requestAt > 6f) { CancelPending(); Tell("Could not reserve that passenger seat. Try again beside the stopped cart."); } else if (_granted && Reservation.Matches(_requestPlayer, _requestPeer, _localToken) && Reservation.IsActive(Now)) { if (((Character)localPlayer).IsAttached() || localPlayer.GetDoodadController() != null || Vector3.Distance(((Component)localPlayer).transform.position, AttachPoint.position) > 3f || !_cart.PassengerBoardingAllowed || !PrivateArea.CheckAccess(AttachPoint.position, 0f, true, false)) { CancelPending(); return; } _pending = false; _passenger = localPlayer; localPlayer.StartDoodadControl((IDoodadController)(object)this); ((Character)localPlayer).AttachStart(AttachPoint, ((Component)_cart).gameObject, true, false, true, AttachAnimation, DetachOffset, (Transform)null); _nextRenew = 0f; Tell("Passenger seat. Jump to dismount."); } } if (!Object.op_Implicit((Object)(object)_passenger)) { if (!_pending && (Object)(object)LocalSeat == (Object)(object)this && _localToken.Length != 0) { ReleaseReservation(); } } else if (((Character)_passenger).IsDead() || ((Character)_passenger).IsTeleporting() || !((Character)_passenger).IsAttached() || (Object)(object)_passenger.GetAttachPoint() != (Object)(object)AttachPoint || (object)_passenger.GetDoodadController() != this || !Reservation.Matches(_requestPlayer, _requestPeer, _localToken) || !Reservation.IsActive(Now)) { StopLocalPassenger(); } else if (Time.unscaledTime >= _nextRenew) { _nextRenew = Time.unscaledTime + 1f; _view.InvokeRPC(RenewRpc, new object[2] { _requestPlayer, _localToken }); } } private void ClearInvalidReservation() { if (!Ready || !_view.IsOwner()) { return; } PassengerSeatReservation reservation = Reservation; if (reservation.Player != 0L) { Player player = Player.GetPlayer(reservation.Player); if (!reservation.IsActive(Now) || (Object.op_Implicit((Object)(object)player) && (((Character)player).IsDead() || ((Character)player).GetOwner() != reservation.Peer))) { WriteReservation(default(PassengerSeatReservation)); } } } public float GetHoverOffset() { return 0f; } public string GetHoverName() { return "Passenger seat " + (SeatIndex + 1); } public string GetHoverText() { return Localization.instance.Localize(GetHoverName() + (IsOccupied ? "\nOccupied" : "\n[$KEY_Use] Sit (while stopped)") + "\n[$KEY_AltPlace + $KEY_Use] Couple / uncouple cart\nComfort 3 while seated; rest when dry, warm and safe."); } public bool UseItem(Humanoid user, ItemData item) { return false; } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_007f: 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_00a1: Unknown result type (might be due to invalid IL or missing references) if (hold || !Ready) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val != (Object)(object)Player.m_localPlayer) { return false; } if (alt) { return _cart.ToggleCoupling(val); } if (Object.op_Implicit((Object)(object)LocalSeat) || _pending || ((Character)val).IsDead() || ((Character)val).IsTeleporting() || ((Character)val).IsAttached() || val.GetDoodadController() != null || ((Character)val).InPlaceMode()) { return false; } if (Vector3.Distance(((Component)val).transform.position, AttachPoint.position) > 3f || !PrivateArea.CheckAccess(AttachPoint.position, 0f, true, false)) { return false; } if (!_cart.PassengerBoardingAllowed) { Tell("Wait for the train to stop before boarding."); return false; } if (IsOccupied) { Tell("That passenger seat is occupied."); return false; } if (!_view.HasOwner()) { Tell("Waiting for the cart's network owner. Try again shortly."); return false; } _pending = true; _granted = false; _localToken = Guid.NewGuid().ToString("N"); _requestPlayer = val.GetPlayerID(); _requestPeer = ((Character)val).GetOwner(); _requestOwner = _view.GetZDO().GetOwner(); _requestAt = Time.unscaledTime; LocalSeat = this; _view.InvokeRPC(RequestRpc, new object[2] { _requestPlayer, _localToken }); return true; } private bool ValidPlayer(long sender, long playerId, out Player player) { //IL_0034: 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) player = Player.GetPlayer(playerId); if (Object.op_Implicit((Object)(object)player) && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && ((Character)player).GetOwner() == sender) { return Vector3.Distance(((Component)player).transform.position, AttachPoint.position) <= 3f; } return false; } private void RequestSeat(long sender, long playerId, string token) { //IL_00dd: 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) if (!Ready || !_view.IsOwner()) { return; } ClearInvalidReservation(); Player player; bool flag = token != null && token.Length == 32 && ValidPlayer(sender, playerId, out player) && _cart.PassengerBoardingAllowed && CanAccessWard(AttachPoint.position, playerId) && Reservation.CanReserve(playerId, sender, token, Now); if (flag) { RailPassengerSeat[] passengerSeats = _cart.PassengerSeats; foreach (RailPassengerSeat railPassengerSeat in passengerSeats) { if ((Object)(object)railPassengerSeat != (Object)(object)this && railPassengerSeat.OccupantId == playerId) { flag = false; break; } } } if (flag) { WriteReservation(new PassengerSeatReservation(playerId, sender, token, Now + 6000)); ZDOMan.instance.ForceSendZDO(sender, _view.GetZDO().m_uid); } _view.InvokeRPC(sender, ReplyRpc, new object[2] { token ?? "", flag }); } private void SeatReply(long sender, string token, bool allowed) { if (_pending && sender == _requestOwner && !(token != _localToken)) { _granted = allowed; if (!allowed) { CancelPending(); Tell("That seat is occupied or the cart cannot be boarded here."); } } } private void RenewSeat(long sender, long playerId, string token) { if (Ready && _view.IsOwner()) { PassengerSeatReservation reservation = Reservation; if (reservation.IsActive(Now) && reservation.Matches(playerId, sender, token) && ValidPlayer(sender, playerId, out Player player) && HasSeatAttachment(player)) { WriteReservation(new PassengerSeatReservation(playerId, sender, token, Now + 6000), mounted: true); } } } private void ReleaseSeat(long sender, long playerId, string token) { if (Ready && _view.IsOwner() && Reservation.Matches(playerId, sender, token)) { WriteReservation(default(PassengerSeatReservation)); } } private void WriteReservation(PassengerSeatReservation reservation, bool mounted = false) { if (Object.op_Implicit((Object)(object)_view) && _view.IsValid() && _view.IsOwner()) { ZDO zDO = _view.GetZDO(); zDO.Set(Prefix + "player", reservation.Player); zDO.Set(Prefix + "peer", reservation.Peer); zDO.Set(Prefix + "token", reservation.Token ?? ""); zDO.Set(Prefix + "until", reservation.ExpiresAt); zDO.Set(Prefix + "mounted", mounted); } } private void ReleaseReservation() { if (Ready && _localToken.Length != 0) { _view.InvokeRPC(ReleaseRpc, new object[2] { _requestPlayer, _localToken }); } _localToken = ""; _pending = false; _granted = false; if ((Object)(object)LocalSeat == (Object)(object)this) { LocalSeat = null; } } private void CancelPending() { ReleaseReservation(); } public void ApplyControlls(Vector3 moveDir, Vector3 lookDir, bool run, bool autoRun, bool block) { } public Component GetControlledComponent() { return (Component)(object)this; } public Vector3 GetPosition() { //IL_001f: 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) if (!Object.op_Implicit((Object)(object)AttachPoint)) { return ((Component)this).transform.position; } return AttachPoint.position; } public bool IsValid() { if (Object.op_Implicit((Object)(object)this)) { return Ready; } return false; } public void OnUseStop(Player player) { //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) _passenger = null; if (Object.op_Implicit((Object)(object)player) && (Object)(object)player.GetAttachPoint() == (Object)(object)AttachPoint) { Vector3 exit; Quaternion rotation; bool num = TryDeckExit(player, out exit, out rotation); ((Character)player).AttachStop(); if (num && !((Character)player).IsAttached()) { FinishDeckExit(player, exit, rotation); } } ReleaseReservation(); RailPassengerComfort.Stop(player); } public void StopLocalPassenger() { Player passenger = _passenger; if (Object.op_Implicit((Object)(object)passenger)) { OnUseStop(passenger); if ((object)passenger.GetDoodadController() == this) { passenger.StopDoodadControl(); } } else if (_pending || _localToken.Length != 0) { CancelPending(); } } private void OnDestroy() { StopLocalPassenger(); if (_registered && Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { _view.Unregister(RequestRpc); _view.Unregister(ReplyRpc); _view.Unregister(RenewRpc); _view.Unregister(ReleaseRpc); } _registered = false; } public static bool IsPassenger(Player player, IEnumerable train) { if (!Object.op_Implicit((Object)(object)player)) { return false; } foreach (RailVehicle item in train) { RailPassengerSeat[] passengerSeats = item.PassengerSeats; foreach (RailPassengerSeat railPassengerSeat in passengerSeats) { if (railPassengerSeat.OccupantId == player.GetPlayerID() && railPassengerSeat.Reservation.Peer == ((Character)player).GetOwner() && railPassengerSeat._view.GetZDO().GetBool(railPassengerSeat.Prefix + "mounted", false) && railPassengerSeat.HasSeatAttachment(player)) { return true; } } } return false; } private bool HasSeatAttachment(Player player) { //IL_0056: 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_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_00a2: 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) if ((Object)(object)player == (Object)(object)Player.m_localPlayer) { if (((Character)player).IsAttached() && (Object)(object)player.GetAttachPoint() == (Object)(object)AttachPoint) { return (object)player.GetDoodadController() == this; } return false; } ZNetView component = ((Component)player).GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid()) { return false; } ZDO zDO = component.GetZDO(); if (zDO.GetConnectionZDOID((ConnectionType)2) == _view.GetZDO().m_uid) { return Vector3.Distance(zDO.GetVec3(ZDOVars.s_relPosHash, new Vector3(9999f, 9999f, 9999f)), ((Component)_cart).transform.InverseTransformPoint(AttachPoint.position)) <= 0.3f; } return false; } private static bool CanAccessWard(Vector3 point, long playerId) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) if (WardList == null || WardEnabled == null || WardInside == null || WardPermitted == null) { return false; } if (!(WardList.GetValue(null) is IEnumerable enumerable)) { return false; } bool flag = false; foreach (PrivateArea item in enumerable) { if (Object.op_Implicit((Object)(object)item) && true.Equals(WardEnabled.Invoke(item, null)) && true.Equals(WardInside.Invoke(item, new object[2] { point, 0f }))) { Piece component = ((Component)item).GetComponent(); if ((Object.op_Implicit((Object)(object)component) && component.GetCreator() == playerId) || true.Equals(WardPermitted.Invoke(item, new object[1] { playerId }))) { return true; } flag = true; } } return !flag; } private static void Tell(string text) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); } } private bool TryDeckExit(Player player, out Vector3 exit, out Quaternion rotation) { //IL_0001: 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_000d: 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_00a4: 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_00b6: 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_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0126: 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_014a: 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_0156: 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_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: 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_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0176: 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_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: 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_01b9: 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_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_022e: 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_0256: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02a4: 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_02ad: 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_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Unknown result type (might be due to invalid IL or missing references) //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_03a3: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03ac: Unknown result type (might be due to invalid IL or missing references) //IL_03b1: Unknown result type (might be due to invalid IL or missing references) //IL_03b6: Unknown result type (might be due to invalid IL or missing references) //IL_03b8: Unknown result type (might be due to invalid IL or missing references) //IL_03ba: Unknown result type (might be due to invalid IL or missing references) //IL_03bc: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_03c3: Unknown result type (might be due to invalid IL or missing references) //IL_03c5: Unknown result type (might be due to invalid IL or missing references) //IL_0466: Unknown result type (might be due to invalid IL or missing references) //IL_0468: Unknown result type (might be due to invalid IL or missing references) exit = default(Vector3); rotation = Quaternion.identity; if (!Object.op_Implicit((Object)(object)_cart) || !_cart.IsPassengerCart || _cart.IsPumpkinCart || !Object.op_Implicit((Object)(object)AttachPoint) || !Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer || ((Character)player).IsDead() || ((Character)player).IsTeleporting()) { return false; } CapsuleCollider collider = ((Character)player).GetCollider(); if (!Object.op_Implicit((Object)(object)collider) || !((Collider)collider).enabled || collider.direction != 1 || !TryExitDeck(out var deck)) { return false; } Vector3 lossyScale = ((Component)collider).transform.lossyScale; float num = collider.radius * Mathf.Max(Mathf.Abs(lossyScale.x), Mathf.Abs(lossyScale.z)); float num2 = Mathf.Max(collider.height * Mathf.Abs(lossyScale.y), num * 2f); if (!ExitFinite(num) || !ExitFinite(num2) || num <= 0f || num2 <= 0f) { return false; } Vector3 val = Vector3.ProjectOnPlane(((Component)_cart).transform.forward, Vector3.up); if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { return false; } rotation = Quaternion.LookRotation(((Vector3)(ref val)).normalized, Vector3.up); Vector3 val2 = rotation * Vector3.Scale(collider.center, lossyScale); Vector3 val3 = val2 + Vector3.up * (num - num2 * 0.5f); Vector3 val4 = val2 + Vector3.up * (num2 * 0.5f - num); Vector3 val5 = ((Component)_cart).transform.up; Vector3 normalized = ((Vector3)(ref val5)).normalized; float num3 = num - Mathf.Min(Vector3.Dot(normalized, val3), Vector3.Dot(normalized, val4)) + 0.025f; if (!ExitFinite(num3) || num3 < -0.1f || num3 > num2) { return false; } Vector3 val6 = ((Component)_cart).transform.InverseTransformPoint(AttachPoint.TransformPoint(DetachOffset)); float num4 = ((SeatIndex == 0) ? (-1f) : 1f); float num5 = ((Bounds)(ref deck)).min.z + 0.65f; float num6 = ((Bounds)(ref deck)).max.z - 0.65f; float num7 = Mathf.Min(Mathf.Abs(((Bounds)(ref deck)).min.x), Mathf.Abs(((Bounds)(ref deck)).max.x)) - 0.12f; if (num5 > num6 || num7 < 0.5f) { return false; } val5 = ((Component)_cart).transform.forward; float num8 = Vector3.Dot(((Vector3)(ref val5)).normalized, Vector3.up); float num9 = Mathf.Clamp(val6.z - num8 * num2 * 0.5f, num5, num6); Physics.SyncTransforms(); float[] array = new float[6] { Mathf.Min(Mathf.Abs(val6.x), num7), Mathf.Min(0.64f, num7), Mathf.Min(0.72f, num7), Mathf.Min(0.8f, num7), Mathf.Min(0.88f, num7), 0.5f }; foreach (float num10 in array) { float[] array2 = new float[13] { 0f, 0.08f, -0.08f, 0.16f, -0.16f, 0.24f, -0.24f, 0.32f, -0.32f, 0.4f, -0.4f, 0.48f, -0.48f }; foreach (float num11 in array2) { float num12 = Mathf.Clamp(num9 + num11, num5, num6); Vector3 val7 = ((Component)_cart).transform.TransformPoint(new Vector3(num4 * num10, ((Bounds)(ref deck)).max.y, num12)) + normalized * num3; int num13 = Physics.OverlapCapsuleNonAlloc(val7 + val3, val7 + val4, num + 0.015f, _exitOverlaps, -1, (QueryTriggerInteraction)1); bool flag = num13 < _exitOverlaps.Length; for (int k = 0; k < num13 && flag; k++) { Collider val8 = _exitOverlaps[k]; if (Object.op_Implicit((Object)(object)val8) && !((Component)val8).transform.IsChildOf(((Component)player).transform) && !Physics.GetIgnoreLayerCollision(((Component)collider).gameObject.layer, ((Component)val8).gameObject.layer)) { flag = false; } } Array.Clear(_exitOverlaps, 0, _exitOverlaps.Length); if (flag) { exit = val7; return true; } } } return false; } private bool TryExitDeck(out Bounds deck) { //IL_0001: 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_00be: 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_00d6: 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) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: 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_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_00fc: 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) deck = default(Bounds); Transform val = ((Component)_cart).transform.Find("visual"); if (!Object.op_Implicit((Object)(object)val)) { return false; } bool flag = false; BoxCollider[] componentsInChildren = ((Component)val).GetComponentsInChildren(true); foreach (BoxCollider val2 in componentsInChildren) { if (!Object.op_Implicit((Object)(object)val2) || !((Collider)val2).enabled || ((Collider)val2).isTrigger || (Object)(object)((Component)val2).transform.parent != (Object)(object)val || ((Object)val2).name != "deck_plank") { continue; } for (int j = -1; j <= 1; j += 2) { for (int k = -1; k <= 1; k += 2) { for (int l = -1; l <= 1; l += 2) { Vector3 val3 = ((Component)_cart).transform.InverseTransformPoint(((Component)val2).transform.TransformPoint(val2.center + Vector3.Scale(val2.size * 0.5f, new Vector3((float)j, (float)k, (float)l)))); if (!flag) { deck = new Bounds(val3, Vector3.zero); flag = true; } else { ((Bounds)(ref deck)).Encapsulate(val3); } } } } } return flag; } private static bool ExitFinite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } private static void FinishDeckExit(Player player, Vector3 position, Quaternion rotation) { //IL_0006: 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_001d: 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) ((Component)player).transform.SetPositionAndRotation(position, rotation); Rigidbody component = ((Component)player).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { component.position = position; component.rotation = rotation; } } } public sealed class RailPlow : MonoBehaviour, Hoverable, Interactable { public static readonly Vector3 SocketOffset = new Vector3(0f, 0f, 1.1f); private const string EngineKey = "vikingrail_engine"; private const string FrontKey = "vikingrail_plow_front"; private const string ToggleRpc = "VR_PlowToggleAtEnd_v2"; private const float SocketRange = 2.5f; private static readonly HashSet Plows = new HashSet(); private ZNetView _view; private Rigidbody? _body; private WearNTear? _wear; private string _identity = ""; private bool _started; private bool _pending; private float _requestTime; private long _requestOwner; private long _requestPlayer; private const string PackedItemKey = "vikingrail_packed_item"; private const string PackedKey = "vikingrail_packed"; private bool _packing; private static readonly FieldInfo? PlatformUser = AccessTools.Field(typeof(CrossNetworkUserInfo), "m_id"); private static readonly MethodInfo? SetCreator = FindCreatorMethod(); public bool IsReady { get { if (_started && Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { return _identity.Length != 0; } return false; } } public ZNetView View => _view; public string PersistentId => _identity; public string EngineIdentity { get { if (!IsReady) { return ""; } return _view.GetZDO().GetString("vikingrail_engine", ""); } } public bool Front { get { if (IsReady) { return _view.GetZDO().GetBool("vikingrail_plow_front", true); } return true; } } public bool IsAttached => EngineIdentity.Length != 0; public RailVehicle? Engine { get { RailVehicle railVehicle = FindEngine(EngineIdentity); if (!Object.op_Implicit((Object)(object)railVehicle) || !(railVehicle.AttachedPlowId == PersistentId) || railVehicle.MountedPlowFront != Front) { return null; } return railVehicle; } } internal bool IsPacked { get { if (IsReady) { return _view.GetZDO().GetBool("vikingrail_packed", false); } return false; } } public static Vector3 SocketOffsetAt(bool front) { //IL_000e: 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) if (!front) { return -SocketOffset; } return SocketOffset; } public static Quaternion SocketRotationAt(bool front) { //IL_0018: 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) if (!front) { return Quaternion.Euler(0f, 180f, 0f); } return Quaternion.identity; } public static RailPlow? Find(string persistentId) { if (string.IsNullOrEmpty(persistentId)) { return null; } foreach (RailPlow plow in Plows) { if (Object.op_Implicit((Object)(object)plow) && plow.IsReady && plow.PersistentId == persistentId) { return plow; } } return null; } private static RailVehicle? FindEngine(string identity) { if (identity.Length == 0) { return null; } foreach (RailVehicle loadedVehicle in RailVehicle.LoadedVehicles) { if (Object.op_Implicit((Object)(object)loadedVehicle) && loadedVehicle.IsReady && loadedVehicle.PersistentId == identity) { return loadedVehicle; } } return null; } private void Awake() { _view = ((Component)this).GetComponent(); _body = ((Component)this).GetComponent(); _wear = ((Component)this).GetComponent(); } private void Start() { InitializeNetwork(); } private void InitializeNetwork() { if (!_started && Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { _started = true; EnsureIdentity(); Plows.Add(this); _view.Register("VR_PlowToggleAtEnd_v2", (Action)RequestToggle); _view.Register("VR_PlowReply", (Action)ReceiveReply); _view.Register("VR_PlowPack", (Action)RequestPack); if (Object.op_Implicit((Object)(object)_wear)) { WearNTear? wear = _wear; wear.m_onDestroyed = (Action)Delegate.Combine(wear.m_onDestroyed, new Action(OnDestroyedPermanently)); } } } private void EnsureIdentity() { _identity = _view.GetZDO().GetString("vikingrail_identity", ""); if (_identity.Length == 0 && _view.IsOwner()) { _identity = Guid.NewGuid().ToString("N"); _view.GetZDO().Set("vikingrail_identity", _identity); } } private void Update() { if (_started && Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { if (_identity.Length == 0) { EnsureIdentity(); } if (IsPacked && _view.IsOwner()) { ZNetScene.instance.Destroy(((Component)this).gameObject); } else if (_pending && Time.time - _requestTime > 6f) { _pending = false; Tell("The plow request timed out. Check its position and try again."); } } } private void LateUpdate() { if (IsReady) { RailVehicle engine = Engine; if (Object.op_Implicit((Object)(object)engine)) { Follow(engine); } } } internal void FollowTurntable(RailVehicle engine) { Follow(engine); } private void Follow(RailVehicle engine) { //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) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_0052: Unknown result type (might be due to invalid IL or missing references) Vector3 val = ((Component)engine).transform.TransformPoint(SocketOffsetAt(Front)); Quaternion val2 = ((Component)engine).transform.rotation * SocketRotationAt(Front); if (Object.op_Implicit((Object)(object)_body)) { _body.position = val; _body.rotation = val2; } ((Component)this).transform.SetPositionAndRotation(val, val2); } public float GetHoverOffset() { return 0f; } public string GetHoverName() { Piece component = ((Component)this).GetComponent(); if (!Object.op_Implicit((Object)(object)component) || string.IsNullOrEmpty(component.m_name)) { return "Rail plow"; } return component.m_name; } public string GetHoverText() { return Localization.instance.Localize(GetHoverName() + (IsAttached ? ("\nAttached to vehicle " + (Front ? "front" : "rear")) : "\nBuild beside a free end of a parked rail vehicle") + "\n[$KEY_Use] " + (IsAttached ? "Detach plow" : "Attach plow") + (IsAttached ? "" : "\n[$KEY_AltPlace + $KEY_Use] Pack for pickup")); } public bool UseItem(Humanoid user, ItemData item) { return false; } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_005d: 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_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0188: 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_01b7: Unknown result type (might be due to invalid IL or missing references) if (hold || !IsReady || _pending || IsPacked) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val != (Object)(object)Player.m_localPlayer) { return false; } if (((Character)val).IsAttached() || val.GetDoodadController() != null) { Tell("Dismount before changing the plow attachment."); return false; } if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return false; } if (alt) { return BeginPack(val); } bool front = Front; RailVehicle railVehicle = (IsAttached ? FindEngine(EngineIdentity) : ClosestParkedEngine(out front)); if (!Object.op_Implicit((Object)(object)railVehicle)) { Tell(IsAttached ? "Approach the linked vehicle so it is loaded before detaching." : "Build the plow within 2.5 m of a free end of a parked rail vehicle. Each vehicle can carry one plow."); return false; } if (!railVehicle.CanChangePlow(out string reason)) { Tell(reason); return false; } if (!PrivateArea.CheckAccess(((Component)railVehicle).transform.position, 0f, true, false) || !PrivateArea.CheckAccess(((Component)railVehicle).transform.TransformPoint(SocketOffsetAt(front)), 0f, true, false)) { return false; } if (!NearSocket(railVehicle, front, val)) { Tell("Stand beside the vehicle's selected end to attach or detach its plow."); return false; } if (!_view.HasOwner()) { Tell("Waiting for the plow's network owner. Try again shortly."); return false; } _pending = true; _requestTime = Time.time; _requestOwner = _view.GetZDO().GetOwner(); _requestPlayer = val.GetPlayerID(); ZDOID val2 = (IsAttached ? ZDOID.None : railVehicle.View.GetZDO().m_uid); _view.InvokeRPC("VR_PlowToggleAtEnd_v2", new object[3] { _requestPlayer, val2, front }); return true; } private RailVehicle? ClosestParkedEngine(out bool front) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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) RailVehicle result = null; front = true; float num = 2.5f; foreach (RailVehicle loadedVehicle in RailVehicle.LoadedVehicles) { if (!Object.op_Implicit((Object)(object)loadedVehicle) || !loadedVehicle.IsReady || !Parked(loadedVehicle) || loadedVehicle.AttachedPlowId.Length != 0) { continue; } for (int i = 0; i < 2; i++) { bool flag = i == 0; if (!loadedVehicle.HasCouplingAt(flag)) { float num2 = Vector3.Distance(((Component)this).transform.position, ((Component)loadedVehicle).transform.TransformPoint(SocketOffsetAt(flag))); if (!(num2 > num)) { num = num2; result = loadedVehicle; front = flag; } } } } return result; } private static bool Parked(RailVehicle engine) { string reason; return engine.CanChangePlow(out reason); } private bool NearSocket(RailVehicle engine, bool front, Player player) { //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_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_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) Vector3 val = ((Component)engine).transform.TransformPoint(SocketOffsetAt(front)); if (Vector3.Distance(((Component)this).transform.position, val) <= 2.5f) { return Vector3.Distance(((Component)player).transform.position, val) <= 2.5f; } return false; } private void RequestToggle(long sender, long playerId, ZDOID targetEngine, bool front) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) if (IsReady && _view.IsOwner() && !IsPacked && !_packing) { string message; bool success = TryToggle(sender, playerId, targetEngine, front, out message); Reply(sender, success, message); } } private bool TryToggle(long sender, long playerId, ZDOID targetEngine, bool front, out string message) { //IL_006d: 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_0099: 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_018b: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: 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_0132: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_033a: Unknown result type (might be due to invalid IL or missing references) message = "The plow is unavailable. Try again shortly."; if (!IsReady || !_view.IsOwner() || IsPacked || _packing) { return false; } Player player = Player.GetPlayer(playerId); if (!Object.op_Implicit((Object)(object)player) || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || ((Character)player).IsAttached() || player.GetDoodadController() != null || ((Character)player).GetOwner() != sender || Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position) > 5f) { message = "Stand on foot near the plow before changing its attachment."; return false; } if (!CanAccessWard(((Component)this).transform.position, playerId)) { message = "A ward prevents changing this plow."; return false; } bool flag = targetEngine == ZDOID.None; if (flag && front != Front) { message = "The plow attachment changed. Try again."; return false; } RailVehicle railVehicle = (flag ? FindEngine(EngineIdentity) : null); if (!flag) { if (IsAttached) { message = "This plow is already attached. Detach it first."; return false; } foreach (RailVehicle loadedVehicle in RailVehicle.LoadedVehicles) { if (Object.op_Implicit((Object)(object)loadedVehicle) && loadedVehicle.IsReady && loadedVehicle.View.GetZDO().m_uid == targetEngine) { railVehicle = loadedVehicle; break; } } } if (!Object.op_Implicit((Object)(object)railVehicle) || !railVehicle.IsReady || !NearSocket(railVehicle, front, player)) { message = "The vehicle and plow must be loaded and close to the selected end."; return false; } if (!railVehicle.CanChangePlow(out message)) { return false; } if (!CanAccessWard(((Component)railVehicle).transform.position, playerId) || !CanAccessWard(((Component)railVehicle).transform.TransformPoint(SocketOffsetAt(front)), playerId)) { message = "A ward protects the vehicle's plow socket."; return false; } if (!flag && railVehicle.AttachedPlowId.Length != 0) { message = "That vehicle already has a plow attached."; return false; } if (!flag && railVehicle.HasCouplingAt(front)) { message = "Uncouple this end before attaching a plow."; return false; } if (!flag && !HasPlowClearance(((Component)this).gameObject, ((Component)railVehicle).transform.TransformPoint(SocketOffsetAt(front)), ((Component)railVehicle).transform.rotation * SocketRotationAt(front), railVehicle, this)) { message = "Move away from the blade and clear the selected end before attaching the plow."; return false; } if (!flag || railVehicle.AttachedPlowId == PersistentId) { railVehicle.View.ClaimOwnership(); if (!railVehicle.View.IsOwner()) { message = "The vehicle became unavailable. Try again once it is parked."; return false; } if (!railVehicle.CanChangePlow(out message)) { return false; } if (!flag && railVehicle.AttachedPlowId.Length != 0) { message = "Another plow took that vehicle's attachment slot."; return false; } if (!flag && railVehicle.HasCouplingAt(front)) { message = "This end was coupled before the plow could attach."; return false; } if (flag) { railVehicle.SetPlowId(""); } else { railVehicle.SetPlowId(PersistentId, front); } } _view.GetZDO().Set("vikingrail_plow_front", flag || front); _view.GetZDO().Set("vikingrail_engine", flag ? "" : railVehicle.PersistentId); if (!flag) { Follow(railVehicle); } ZDOMan.instance.ForceSendZDO(sender, railVehicle.View.GetZDO().m_uid); ZDOMan.instance.ForceSendZDO(sender, _view.GetZDO().m_uid); message = (flag ? "Plow detached." : ("Plow attached to the " + (front ? "front" : "rear") + ". It clears creatures when this blade leads the train.")); return true; } private void Reply(long peer, bool success, string message) { _view.InvokeRPC(peer, "VR_PlowReply", new object[2] { success, message }); } private void ReceiveReply(long sender, bool success, string message) { if (_pending && sender == _requestOwner) { _pending = false; if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerID() == _requestPlayer) { Tell(message); } } } public void DetachFromDestroyedEngine(RailVehicle engine) { if (!IsReady || !Object.op_Implicit((Object)(object)engine) || !engine.IsReady || !engine.View.IsOwner() || EngineIdentity != engine.PersistentId) { return; } _view.ClaimOwnership(); if (_view.IsOwner()) { Follow(engine); _view.GetZDO().Set("vikingrail_engine", ""); if (engine.AttachedPlowId == PersistentId) { engine.SetPlowId(""); } } } private void OnDestroyedPermanently() { if (!IsReady || !_view.IsOwner()) { return; } RailVehicle railVehicle = FindEngine(EngineIdentity); if (Object.op_Implicit((Object)(object)railVehicle) && railVehicle.AttachedPlowId == PersistentId) { railVehicle.View.ClaimOwnership(); if (railVehicle.View.IsOwner()) { railVehicle.SetPlowId(""); } } _view.GetZDO().Set("vikingrail_engine", ""); } private void OnDestroy() { if (Object.op_Implicit((Object)(object)_wear)) { WearNTear? wear = _wear; wear.m_onDestroyed = (Action)Delegate.Remove(wear.m_onDestroyed, new Action(OnDestroyedPermanently)); } Plows.Remove(this); _started = false; } private static void Tell(string message) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false); } } private static RailVector ToRail(Vector3 vector) { //IL_0000: 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_000e: Unknown result type (might be due to invalid IL or missing references) return new RailVector(vector.x, vector.y, vector.z); } private static Vector3 ToUnity(RailVector vector) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) return new Vector3((float)vector.X, (float)vector.Y, (float)vector.Z); } private static RailVehicle? TargetedEngine(Player player, Vector3 forward, out bool front) { //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) //IL_006d: 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_007f: 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_0099: 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) RailVehicle result = null; front = true; float num = 2.5f; foreach (RailVehicle loadedVehicle in RailVehicle.LoadedVehicles) { if (!Object.op_Implicit((Object)(object)loadedVehicle) || !loadedVehicle.IsReady || loadedVehicle.AttachedPlowId.Length != 0) { continue; } for (int i = 0; i < 2; i++) { bool flag = i == 0; if (loadedVehicle.HasCouplingAt(flag)) { continue; } Vector3 val = ((Component)loadedVehicle).transform.TransformPoint(SocketOffsetAt(flag)); if (PackedPlowPlacement.TargetsSocket(ToRail(((Component)player).transform.position), ToRail(forward), ToRail(val))) { float num2 = Vector3.Distance(((Component)player).transform.position, val); if (!(num2 > num)) { result = loadedVehicle; num = num2; front = flag; } } } } return result; } private static bool TryPackedPosition(Player player, Vector3 forward, GameObject shape, out Vector3 position, out Quaternion rotation, out RailVehicle? engine, out bool front) { //IL_0015: 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_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_0035: 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_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: 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_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: 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_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0124: 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_0147: Unknown result type (might be due to invalid IL or missing references) position = default(Vector3); rotation = Quaternion.LookRotation(forward, Vector3.up); engine = TargetedEngine(player, forward, out front); if (!PrivateArea.CheckAccess(((Component)player).transform.position, 0f, true, false)) { return false; } if (Object.op_Implicit((Object)(object)engine)) { if (!engine.CanChangePlow(out string reason)) { Tell(reason); return false; } if (engine.AttachedPlowId.Length != 0) { Tell("That vehicle already has a plow. Face away to place this one on the ground."); return false; } if (engine.HasCouplingAt(front)) { Tell("Uncouple this end before attaching a plow."); return false; } position = ((Component)engine).transform.TransformPoint(SocketOffsetAt(front)); rotation = ((Component)engine).transform.rotation * SocketRotationAt(front); if (Location.IsInsideNoBuildLocation(position)) { Tell("Building is not allowed here."); return false; } if (!PrivateArea.CheckAccess(((Component)engine).transform.position, 0f, true, false) || !PrivateArea.CheckAccess(position, 0f, true, false)) { return false; } if (!HasPlowClearance(shape, position, rotation, engine)) { Tell("Stand to the side of the selected vehicle end and clear space for the blade, then use the packed plow again."); return false; } return true; } Quaternion groundRotation = rotation; int groundMask = LayerMask.GetMask(new string[4] { "terrain", "piece", "Default", "static_solid" }); RaycastHit val = default(RaycastHit); if (!PackedPlowPlacement.TryGround(ToRail(((Component)player).transform.position), ToRail(forward), (RailVector candidate) => (!Physics.Raycast(ToUnity(candidate) + Vector3.up * 2f, Vector3.down, ref val, 4.5f, groundMask, (QueryTriggerInteraction)1) || Vector3.Dot(((RaycastHit)(ref val)).normal, Vector3.up) < 0.7f || Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent()) || Object.op_Implicit((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent()) || Location.IsInsideNoBuildLocation(((RaycastHit)(ref val)).point) || !CanAccessWard(((RaycastHit)(ref val)).point, player.GetPlayerID()) || !HasPlowClearance(shape, ((RaycastHit)(ref val)).point, groundRotation)) ? ((RailVector?)null) : new RailVector?(ToRail(((RaycastHit)(ref val)).point)), out var position2)) { Tell("No clear, level ground nearby. Face an open patch, or stand beside a free end of a parked rail vehicle and face its socket to attach directly."); return false; } position = ToUnity(position2); return true; } private static bool HasPlowClearance(GameObject shape, Vector3 position, Quaternion rotation, RailVehicle? engine = null, RailPlow? self = null) { //IL_0089: 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_009a: 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_00a4: 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_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_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_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_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_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: 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_0113: 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_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012b: 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_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: 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_0150: 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_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) int mask = LayerMask.GetMask(new string[9] { "terrain", "piece", "Default", "static_solid", "character", "character_net", "character_ghost", "character_noenv", "vehicle" }); BoxCollider[] componentsInChildren = shape.GetComponentsInChildren(true); if (componentsInChildren.Length == 0) { return false; } BoxCollider[] array = componentsInChildren; foreach (BoxCollider val in array) { if (!((Collider)val).enabled || ((Collider)val).isTrigger) { continue; } Vector3 val2 = position + rotation * shape.transform.InverseTransformPoint(((Component)val).transform.TransformPoint(val.center)); Quaternion val3 = rotation * Quaternion.Inverse(shape.transform.rotation) * ((Component)val).transform.rotation; Vector3 lossyScale = ((Component)val).transform.lossyScale; Vector3 val4 = Vector3.Scale(val.size * 0.5f, new Vector3(Mathf.Abs(lossyScale.x), Mathf.Abs(lossyScale.y), Mathf.Abs(lossyScale.z))); val4 = Vector3.Max(val4 - Vector3.one * 0.002f, Vector3.one * 0.001f); Collider[] array2 = Physics.OverlapBox(val2, val4, val3, mask, (QueryTriggerInteraction)1); foreach (Collider val5 in array2) { if ((!Object.op_Implicit((Object)(object)self) || !((Object)(object)((Component)val5).GetComponentInParent() == (Object)(object)self)) && (!Object.op_Implicit((Object)(object)engine) || !((Object)(object)((Component)val5).GetComponentInParent() == (Object)(object)engine))) { return false; } } } return true; } private static MethodInfo? FindCreatorMethod() { if (PlatformUser == null) { return null; } return AccessTools.Method(typeof(Piece), "SetCreator", new Type[2] { typeof(long), PlatformUser.FieldType }, (Type[])null); } private bool BeginPack(Player player) { //IL_001a: 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) if (IsAttached) { Tell("Detach the plow before picking it up."); return false; } if (Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position) > 3.5f) { return false; } if (!_view.HasOwner()) { Tell("Waiting for the plow's network owner. Try again shortly."); return false; } _pending = true; _requestTime = Time.time; _requestOwner = _view.GetZDO().GetOwner(); _requestPlayer = player.GetPlayerID(); _view.InvokeRPC("VR_PlowPack", new object[1] { _requestPlayer }); return true; } private void RequestPack(long sender, long playerId) { //IL_02a9: 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_005f: 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_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) //IL_01b1: 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_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) if (!IsReady || !_view.IsOwner() || _packing || IsPacked) { return; } Player player = Player.GetPlayer(playerId); if (!Object.op_Implicit((Object)(object)player) || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || ((Character)player).GetOwner() != sender || Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position) > 3.5f || !CanAccessWard(((Component)this).transform.position, playerId)) { Reply(sender, success: false, "Stand beside the detached plow with permission to use it."); return; } if (IsAttached) { Reply(sender, success: false, "Detach the plow before picking it up."); return; } string text = PackedPlow.ItemName(Utils.GetPrefabName(((Component)this).gameObject)); GameObject val = (Object.op_Implicit((Object)(object)ObjectDB.instance) ? ObjectDB.instance.GetItemPrefab(text) : null); ItemDrop val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent() : null); if (!Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)_wear) || !Object.op_Implicit((Object)(object)ZNetScene.instance)) { Reply(sender, success: false, "The packed plow item is unavailable."); return; } float num = _view.GetZDO().GetFloat(ZDOVars.s_health, _wear.m_health); if (num <= 0f) { return; } _packing = true; _view.GetZDO().Set("vikingrail_packed", true); ItemDrop val3 = null; try { ItemData obj = val2.m_itemData.Clone(); obj.m_dropPrefab = val; obj.m_stack = 1; obj.m_customData["vikingrail_plow_health"] = PackedPlow.EncodeHealth(num, _wear.m_health); val3 = ItemDrop.DropItem(obj, 1, ((Component)this).transform.position + Vector3.up * 0.5f, ((Component)this).transform.rotation); ZNetView val4 = (Object.op_Implicit((Object)(object)val3) ? ((Component)val3).GetComponent() : null); if (!Object.op_Implicit((Object)(object)val4) || !val4.IsValid()) { throw new InvalidOperationException("Packed plow item has no network identity."); } _view.GetZDO().Set("vikingrail_packed_item", val4.GetZDO().m_uid); ZDOMan.instance.ForceSendZDO(sender, val4.GetZDO().m_uid); Reply(sender, success: true, "Plow packed. Pick up the bundle; use it from your inventory or hotbar to place it again."); ZNetScene.instance.Destroy(((Component)this).gameObject); } catch (Exception error) { if (Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)ZNetScene.instance)) { ZNetScene.instance.Destroy(((Component)val3).gameObject); } if (Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { _view.GetZDO().Set("vikingrail_packed_item", ZDOID.None); _view.GetZDO().Set("vikingrail_packed", false); } _packing = false; RailPlugin.Error(error); Reply(sender, success: false, "The plow could not be packed. It has been left in place."); } } private static bool CanAccessWard(Vector3 point, long playerId) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return RailWardAccess.Allows(point, playerId); } internal static bool TryPlacePackedPlow(Humanoid user, Inventory? inventory, ItemData item) { //IL_045e: Unknown result type (might be due to invalid IL or missing references) //IL_0463: Unknown result type (might be due to invalid IL or missing references) //IL_0468: Unknown result type (might be due to invalid IL or missing references) //IL_046d: 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_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: 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_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0165: 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_016e: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) if (item == null || !Object.op_Implicit((Object)(object)item.m_dropPrefab)) { return false; } string text = PackedPlow.PieceName(((Object)item.m_dropPrefab).name); if (text.Length == 0) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val != (Object)(object)Player.m_localPlayer) { return true; } inventory = inventory ?? ((Humanoid)val).GetInventory(); if (inventory != ((Humanoid)val).GetInventory() || !inventory.ContainsItem(item)) { return true; } if (((Character)val).IsDead() || ((Character)val).IsTeleporting() || ((Character)val).IsAttached() || val.GetDoodadController() != null || ((Character)val).InPlaceMode()) { Tell("Stand on foot before placing the plow."); return true; } ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null) { Tell("The plow prefab is unavailable."); return true; } GameObject prefab = instance.GetPrefab(text); if (!Object.op_Implicit((Object)(object)prefab) || !Object.op_Implicit((Object)(object)ZNet.instance)) { Tell("The plow prefab is unavailable."); return true; } if (!prefab.GetComponent().m_allowedInDungeons && ((Character)val).InInterior() && !EnvMan.instance.CheckInteriorBuildingOverride() && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)34)) { Tell("Plows cannot be placed in this dungeon."); return true; } Vector3 val2 = Vector3.ProjectOnPlane(((Character)val).GetLookDir(), Vector3.up); Vector3 normalized = ((Vector3)(ref val2)).normalized; if (((Vector3)(ref normalized)).sqrMagnitude < 0.001f) { val2 = Vector3.ProjectOnPlane(((Component)val).transform.forward, Vector3.up); normalized = ((Vector3)(ref val2)).normalized; } if (!TryPackedPosition(val, normalized, prefab, out Vector3 position, out Quaternion rotation, out RailVehicle engine, out bool front)) { return true; } ZNetView playerView = ((Component)val).GetComponent(); if (!Object.op_Implicit((Object)(object)playerView) || !playerView.IsValid()) { return true; } List playerList = ZNet.instance.GetPlayerList(); int num = playerList.FindIndex((PlayerInfo info) => info.m_characterID == playerView.GetZDO().m_uid); if (num < 0) { Tell("Waiting for your player identity. Try again shortly."); return true; } if (PlatformUser == null || SetCreator == null) { Tell("This game build's piece creator API is unavailable."); return true; } object value = PlatformUser.GetValue(playerList[num].m_userInfo); ItemData val3 = item.Clone(); val3.m_stack = 1; if (!inventory.RemoveItem(item, 1)) { return true; } GameObject val4 = null; bool flag = false; string message = "The plow could not be placed; the packed plow has been returned."; try { val4 = Object.Instantiate(prefab, position, rotation); ZNetView component = val4.GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || !component.IsOwner()) { throw new InvalidOperationException("Placed plow has no owned network identity."); } WearNTear component2 = val4.GetComponent(); component.GetZDO().Set(ZDOVars.s_health, PackedPlow.ReadHealth(val3.m_customData, component2.m_health)); SetCreator.Invoke(val4.GetComponent(), new object[2] { val.GetPlayerID(), value }); if (Object.op_Implicit((Object)(object)engine)) { RailPlow component3 = val4.GetComponent(); component3.InitializeNetwork(); if (!component3.TryToggle(((Character)val).GetOwner(), val.GetPlayerID(), engine.View.GetZDO().m_uid, front, out message)) { return true; } } flag = true; Tell(Object.op_Implicit((Object)(object)engine) ? ("Plow attached directly to the vehicle's " + (front ? "front." : "rear.")) : "Plow placed. Use it beside a free end of a parked rail vehicle to attach it."); } catch (Exception error) { RailPlugin.Error(error); } finally { if (!flag) { if (Object.op_Implicit((Object)(object)val4)) { RailPlow component4 = val4.GetComponent(); if (Object.op_Implicit((Object)(object)component4) && Object.op_Implicit((Object)(object)engine) && engine.IsReady && engine.View.IsOwner() && component4.PersistentId.Length != 0 && engine.AttachedPlowId == component4.PersistentId) { engine.SetPlowId(""); } if (Object.op_Implicit((Object)(object)component4) && Object.op_Implicit((Object)(object)component4.View) && component4.View.IsValid() && component4.View.IsOwner()) { component4.View.GetZDO().Set("vikingrail_packed", true); component4.View.GetZDO().Set("vikingrail_engine", ""); } instance.Destroy(val4); } if (!inventory.AddItem(val3)) { ItemDrop.DropItem(val3, 1, ((Component)val).transform.position + Vector3.up, Quaternion.identity); } Tell(message); } } return true; } } [HarmonyPatch(typeof(Humanoid), "UseItem", new Type[] { typeof(Inventory), typeof(ItemData), typeof(bool) })] internal static class PackedRailPlowUsePatch { [HarmonyPrefix] private static bool Prefix(Humanoid __instance, Inventory __0, ItemData __1) { return !RailPlow.TryPlacePackedPlow(__instance, __0, __1); } } [HarmonyPatch(typeof(Piece), "CanBeRemoved")] internal static class PackedRailPlowRemovalPatch { [HarmonyPostfix] private static void Postfix(Piece __instance, ref bool __result) { RailPlow component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component) && component.IsPacked) { __result = false; } } } [HarmonyPatch(typeof(WearNTear), "RPC_Remove")] internal static class PackedRailPlowRemoveRequestPatch { [HarmonyPrefix] private static bool Prefix(WearNTear __instance) { RailPlow component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { return !component.IsPacked; } return true; } } internal sealed class RailPlowPush : MonoBehaviour { internal const string IntentUntilKey = "vikingrail_plow_intent_until"; internal const string IntentSpeedKey = "vikingrail_plow_intent_speed"; internal const string IntentTravelKey = "vikingrail_plow_intent_travel"; private const string HitEngineKey = "vikingrail_plow_hit_engine"; private const string HitTimeKey = "vikingrail_plow_hit_time"; private const string RpcName = "VR_PlowPush"; private const float RequestInterval = 0.12f; private const float ReceiveInterval = 0.1f; private static readonly MethodInfo? WakeMonster = AccessTools.Method(typeof(MonsterAI), "Wakeup", (Type[])null, (Type[])null); private Character _character; private ZNetView _view; private Rigidbody? _body; private bool _initialized; private bool _wakeFailureLogged; private float _nextRequestAt; private float _nextReceiveAt; private float _expiresAt; private long _sender; private ZDOID _carrierId = ZDOID.None; private ZDOID _rootId = ZDOID.None; private Vector3 _direction; private float _sideSpeed; private Vector3 _pulseOrigin; private string _plowIdentity = ""; private bool _plowFront; private ushort _carrierOwnerRevision; private ushort _rootOwnerRevision; private ushort _creatureOwnerRevision; internal static RailPlowPush? Ensure(Character character) { if (!Object.op_Implicit((Object)(object)character) || character.IsPlayer()) { return null; } ZNetView val = (Object.op_Implicit((Object)(object)character.m_nViewOverride) ? character.m_nViewOverride : ((Component)character).GetComponent()); if (!Object.op_Implicit((Object)(object)val) || !val.IsValid()) { return null; } RailPlowPush obj = ((Component)character).GetComponent() ?? ((Component)character).gameObject.AddComponent(); obj.Initialize(character, val); return obj; } private void Initialize(Character character, ZNetView view) { if (!_initialized) { _character = character; _view = view; _body = ((Component)character).GetComponent(); _view.Register("VR_PlowPush", (Action)Receive); _initialized = true; } } internal static void Request(Character character, RailVehicle carrier) { //IL_00fd: 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_00d5: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)character) || character.IsPlayer() || character.IsDead() || !Object.op_Implicit((Object)(object)carrier) || !carrier.IsReady || !Object.op_Implicit((Object)(object)carrier.View) || !carrier.View.IsValid() || !carrier.View.IsOwner() || !carrier.TryPlowDriveAuthority(out RailVehicle root)) { return; } RailPlowPush railPlowPush = Ensure(character); if (!Object.op_Implicit((Object)(object)railPlowPush) || Time.time < railPlowPush._nextRequestAt) { return; } railPlowPush._nextRequestAt = Time.time + 0.12f; if (ZDOMan.instance != null) { long owner = railPlowPush._view.GetZDO().GetOwner(); ZDOMan.instance.ForceSendZDO(owner, carrier.View.GetZDO().m_uid); if ((Object)(object)root != (Object)(object)carrier) { ZDOMan.instance.ForceSendZDO(owner, root.View.GetZDO().m_uid); } } railPlowPush._view.InvokeRPC("VR_PlowPush", new object[1] { carrier.View.GetZDO().m_uid }); } private void Receive(long sender, ZDOID carrierId) { //IL_0021: 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_0046: 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_005c: 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_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_00ee: Unknown result type (might be due to invalid IL or missing references) if (!(Time.time < _nextReceiveAt)) { _nextReceiveAt = Time.time + 0.1f; if (TryContactPlan(sender, carrierId, out RailVehicle carrier, out RailVehicle root, out Vector3 direction, out float speed, out float forwardSpeed) && WakeIfSleeping()) { _sender = sender; _carrierId = carrierId; _rootId = root.View.GetZDO().m_uid; _direction = direction; _sideSpeed = speed; _pulseOrigin = carrier.PlowPosition; _plowIdentity = carrier.MountedPlow.PersistentId; _plowFront = carrier.MountedPlowFront; _carrierOwnerRevision = carrier.View.GetZDO().OwnerRevision; _rootOwnerRevision = root.View.GetZDO().OwnerRevision; _creatureOwnerRevision = _view.GetZDO().OwnerRevision; _expiresAt = Time.time + 1.25f; DamageContact(carrier, root, direction, forwardSpeed); } } } private bool TryAuthority(long sender, ZDOID carrierId, out RailVehicle carrier, out RailVehicle root) { //IL_005f: 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_008b: 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_01a5: Unknown result type (might be due to invalid IL or missing references) carrier = (root = null); if (!_initialized || !Object.op_Implicit((Object)(object)_character) || _character.IsPlayer() || _character.IsDead() || !Object.op_Implicit((Object)(object)_view) || !_view.IsValid() || !_view.IsOwner() || carrierId == ZDOID.None || !Object.op_Implicit((Object)(object)ZNetScene.instance) || !Object.op_Implicit((Object)(object)ZNet.instance)) { return false; } GameObject val = ZNetScene.instance.FindInstance(carrierId); carrier = (Object.op_Implicit((Object)(object)val) ? val.GetComponent() : null); if (!Object.op_Implicit((Object)(object)carrier) || !carrier.IsReady || !Object.op_Implicit((Object)(object)carrier.View) || !carrier.View.IsValid() || carrier.PersistentId.Length == 0 || !Object.op_Implicit((Object)(object)carrier.MountedPlow) || carrier.View.GetZDO().GetOwner() != sender) { return false; } if (!carrier.TryPlowDriveAuthority(out root) || !Object.op_Implicit((Object)(object)root) || !Object.op_Implicit((Object)(object)root.View) || !root.View.IsValid() || root.View.GetZDO().GetOwner() != sender) { return false; } if (!root.AutoDriveActive) { Player player = Player.GetPlayer(root.ReservedDriver); if (root.ReservedDriver == 0L || !Object.op_Implicit((Object)(object)player) || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || ((Character)player).GetOwner() != sender || Vector3.Distance(((Component)player).transform.position, ((Component)root).transform.position) > 5f) { return false; } } return true; } private bool TryContactPlan(long sender, ZDOID carrierId, out RailVehicle carrier, out RailVehicle root, out Vector3 direction, out float speed, out float forwardSpeed) { //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_001e: 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_0112: 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_012f: 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_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) direction = Vector3.zero; speed = (forwardSpeed = 0f); if (!TryAuthority(sender, carrierId, out carrier, out root)) { return false; } ZDO zDO = carrier.View.GetZDO(); double num = ZNet.instance.GetTimeSeconds() * 1000.0; long num2 = zDO.GetLong("vikingrail_plow_intent_until", 0L); forwardSpeed = zDO.GetFloat("vikingrail_plow_intent_speed", 0f); float num3 = zDO.GetFloat("vikingrail_plow_intent_travel", 0f); if (double.IsNaN(num) || double.IsInfinity(num) || (double)num2 <= num || (double)num2 - num > 1000.0 || float.IsNaN(forwardSpeed) || float.IsInfinity(forwardSpeed) || (double)forwardSpeed <= 0.05 || (double)forwardSpeed > 15.0 || float.IsNaN(num3) || float.IsInfinity(num3) || num3 < 0f || (double)num3 > 0.75 || !RailVehicle.PlowContact(_character, carrier.PlowPosition, carrier.PlowRotation, num3)) { return false; } if (!RailPlowMath.TryPlan(RailSegment.ToRail(carrier.PlowPosition), RailSegment.ToRail(carrier.PlowForward), RailSegment.ToRail(_character.GetCenterPoint()), _character.GetRadius(), forwardSpeed, attached: true, isPlayer: false, alive: true, out var push, num3)) { return false; } direction = RailSegment.ToUnity(push.Direction); speed = (float)push.Speed; return true; } private void DamageContact(RailVehicle carrier, RailVehicle root, Vector3 direction, float forwardSpeed) { //IL_0092: 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_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: 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_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: 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_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: 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_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Expected O, but got Unknown ZDO zDO = _view.GetZDO(); long num = (long)(ZNet.instance.GetTimeSeconds() * 1000.0); string text = zDO.GetString("vikingrail_plow_hit_engine", ""); string text2 = "vikingrail_plow_impact_" + carrier.PersistentId; bool num2 = zDO.GetBool(text2, false); long num3 = zDO.GetLong(text2 + "_hit", num); long num4 = zDO.GetLong(text2 + "_contact", num3); int stableHashCode = StringExtensionMethods.GetStableHashCode(text2 + "_position"); bool num5 = RailPlowImpact.CanDamageContact(engineTravel: num2 ? Vector3.Distance(carrier.PlowPosition, zDO.GetVec3(stableHashCode, carrier.PlowPosition)) : 0f, previousHit: num2, sameEngine: true, elapsedSinceHit: ((double)num - (double)num3) / 1000.0, gapSinceContact: ((double)num - (double)num4) / 1000.0) && RailPlowImpact.CanDamageContact(text.Length != 0, sameEngine: false, ((double)num - (double)zDO.GetLong("vikingrail_plow_hit_time", num)) / 1000.0, 0.0, 0.0); zDO.Set(text2 + "_contact", num); if (!num5) { return; } RailPlow mountedPlow = carrier.MountedPlow; bool wooden = Object.op_Implicit((Object)(object)mountedPlow) && Utils.GetPrefabName(((Component)mountedPlow).gameObject) == "vr_plow_wood"; float num6 = (float)RailPlowImpact.BluntDamage(forwardSpeed, wooden); if (num6 > 0f) { zDO.Set("vikingrail_plow_hit_engine", carrier.PersistentId); zDO.Set("vikingrail_plow_hit_time", num); zDO.Set(text2, true); zDO.Set(text2 + "_hit", num); zDO.Set(stableHashCode, carrier.PlowPosition); HitData val = new HitData { m_point = _character.GetCenterPoint(), m_dir = direction, m_hitType = (HitType)12, m_pushForce = 0f, m_backstabBonus = 1f, m_staggerMultiplier = 0.5f, m_dodgeable = false, m_blockable = false, m_skillRaiseAmount = 0f }; val.m_damage.m_blunt = num6; Player player = Player.GetPlayer(root.ReservedDriver); if (Object.op_Implicit((Object)(object)player) && ((Character)player).GetOwner() == root.View.GetZDO().GetOwner()) { val.SetAttacker((Character)(object)player); } _character.Damage(val); } } private bool WakeIfSleeping() { BaseAI baseAI = _character.GetBaseAI(); if (!Object.op_Implicit((Object)(object)baseAI) || !baseAI.IsSleeping()) { return true; } MonsterAI val = (MonsterAI)(object)((baseAI is MonsterAI) ? baseAI : null); if (val == null) { return false; } try { if (WakeMonster == null) { throw new MissingMethodException(typeof(MonsterAI).FullName, "Wakeup"); } WakeMonster.Invoke(val, null); return !((BaseAI)val).IsSleeping(); } catch (Exception error) { if (!_wakeFailureLogged) { _wakeFailureLogged = true; RailPlugin.Error(error); } return false; } } internal void Apply(ref Vector3 velocity) { //IL_000a: 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_0026: 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_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) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (PulseActive()) { float num = Vector3.Dot(velocity, _direction); if (num < _sideSpeed) { velocity += _direction * (_sideSpeed - num); } } } private bool PulseActive() { //IL_001f: 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_0043: 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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) if (!_initialized || Time.time >= _expiresAt) { return false; } if (!TryAuthority(_sender, _carrierId, out RailVehicle carrier, out RailVehicle root) || root.View.GetZDO().m_uid != _rootId || root.View.GetZDO().OwnerRevision != _rootOwnerRevision || carrier.View.GetZDO().OwnerRevision != _carrierOwnerRevision || _view.GetZDO().OwnerRevision != _creatureOwnerRevision || !Object.op_Implicit((Object)(object)carrier.MountedPlow) || carrier.MountedPlow.PersistentId != _plowIdentity || carrier.MountedPlowFront != _plowFront || (double)Vector3.Dot(_character.GetCenterPoint() - _pulseOrigin, _direction) >= 1.8 + (double)_character.GetRadius()) { _expiresAt = 0f; return false; } return true; } internal void FinishMotion() { //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_0088: 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) if (PulseActive() && Object.op_Implicit((Object)(object)_body) && !_body.isKinematic && !_character.IsOnGround() && !_character.IsSwimming() && !_character.IsFlying()) { float num = Vector3.Dot(_body.linearVelocity, _direction); float num2 = Mathf.Clamp(_sideSpeed - num, 0f, 10f); if (num2 > 0f) { _body.AddForce(_direction * num2, (ForceMode)2); } } } private void OnDestroy() { if (_initialized && Object.op_Implicit((Object)(object)_view)) { _view.Unregister("VR_PlowPush"); } _initialized = false; } } [HarmonyPatch(typeof(Character), "UpdateMotion")] internal static class PlowCreatureAirVelocityPatch { [HarmonyPostfix] private static void Postfix(Character __instance) { RailPlowPush component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { component.FinishMotion(); } } } [HarmonyPatch(typeof(Character), "Awake")] internal static class PlowCreatureRegistrationPatch { [HarmonyPostfix] private static void Postfix(Character __instance) { RailPlowPush.Ensure(__instance); } } [HarmonyPatch(typeof(Character), "AddPushbackForce")] internal static class PlowCreatureVelocityPatch { [HarmonyPostfix] private static void Postfix(Character __instance, ref Vector3 velocity) { RailPlowPush component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { component.Apply(ref velocity); } } } [BepInPlugin("local.valheim.vikingrail", "Viking Rail", "0.46.1")] public sealed class RailPlugin : BaseUnityPlugin { public const string Id = "local.valheim.vikingrail"; public const string Version = "0.46.1"; private Harmony? _harmony; internal static RailPlugin Instance; private void Awake() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown Instance = this; _harmony = new Harmony("local.valheim.vikingrail"); try { RailSettings.Initialize(((BaseUnityPlugin)this).Config); CargoProtocol.Initialize(); _harmony.PatchAll(); } catch (Exception ex) { _harmony.UnpatchSelf(); ((Behaviour)this).enabled = false; ((BaseUnityPlugin)this).Logger.LogError((object)"Viking Rail 0.46.1 could not initialize on this Valheim build. No railroad patches remain active. Include the following error when reporting the game version."); ((BaseUnityPlugin)this).Logger.LogError((object)ex); return; } ((BaseUnityPlugin)this).Logger.LogInfo((object)("Cargo RPC compatibility: " + CargoProtocol.Open.RpcName + ", " + CargoProtocol.Stack.RpcName + ", " + CargoProtocol.TakeAll.RpcName)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Viking Rail 0.46.1 loaded. Prototype: in-game validation required."); } private void Update() { RailSettings.Update(); RailRemoteDrive.Update(); RailMusicNetwork.Update(); RailSpawnProtection.UpdateWorld(); RailTerrainMaintenance.UpdateWorld(); } private void OnGUI() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) RailVehicle localDriven = RailVehicle.LocalDriven; if (Object.op_Implicit((Object)(object)localDriven) && !Menu.IsVisible()) { int num = Mathf.Min(680, Screen.width - 24); GUI.Box(new Rect((float)((Screen.width - num) / 2), (float)(Screen.height - 158), (float)num, 130f), "Viking Rail | " + Mathf.Abs(localDriven.Speed).ToString("0.0") + " m/s | " + localDriven.WagonCount + " wagons" + (localDriven.HasPlow ? " | Plow fitted" : "") + "\n" + ((!localDriven.IsEngine) ? "Hold forward / backward: push" : "Tap forward / backward: throttle + / −") + " • Block: brake • Jump: " + ((!localDriven.IsEngine) ? "release handle" : "dismount") + "\n" + (localDriven.IsEngine ? (localDriven.ThrottleStatus + "\n") : "") + ((!localDriven.IsEngine) ? "Hand positioning: 0.8 m/s maximum\n" : (localDriven.FuelPowered ? ("Fuel: " + localDriven.FuelStatus + "\n") : ("Stamina: " + localDriven.PumpingStaminaRate.ToString("0.##") + "/s base" + ((localDriven.PumpingStaminaRate == 0.0) ? " (disabled)" : " before load") + "\n"))) + localDriven.Status); } } private void OnDestroy() { RailRemoteDrive.Reset(); RailMusicNetwork.Reset(); if (Object.op_Implicit((Object)(object)RailVehicle.LocalDriven)) { RailVehicle.LocalDriven.StopLocalDriver(); } if (Object.op_Implicit((Object)(object)RailPassengerSeat.LocalSeat)) { RailPassengerSeat.LocalSeat.StopLocalPassenger(); } if (Object.op_Implicit((Object)(object)RailPumpPartner.LocalPartner)) { RailPumpPartner.LocalPartner.StopLocalPartner(); } RailVehicle.ShutdownMovementAudio(); Harmony? harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } RailSettings.ResetSession(); RailPrefabs.Cleanup(); } internal static void Warn(string message) { ((BaseUnityPlugin)Instance).Logger.LogWarning((object)message); } internal static void LogInfo(string message) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)message); } internal static void Error(Exception error) { ((BaseUnityPlugin)Instance).Logger.LogError((object)error); } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class ScenePatch { [HarmonyPostfix] private static void Postfix(ZNetScene __instance) { try { RailPrefabs.Register(__instance); if (Object.op_Implicit((Object)(object)ObjectDB.instance)) { RailPrefabs.AddToHammer(ObjectDB.instance); } } catch (Exception error) { RailPlugin.Error(error); } } } [HarmonyPatch(typeof(ObjectDB), "Awake")] internal static class DatabasePatch { [HarmonyPostfix] private static void Postfix(ObjectDB __instance) { RailPrefabs.AddToHammer(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] internal static class CopyDatabasePatch { [HarmonyPostfix] private static void Postfix(ObjectDB __instance) { RailPrefabs.AddToHammer(__instance); } } [HarmonyPatch(typeof(Container), "Interact")] internal static class CargoInteractionPatch { [HarmonyPrefix] private static bool Prefix(Container __instance, Humanoid character, bool hold, bool alt, ref bool __result) { RailVehicle component = ((Component)__instance).GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return true; } if (!component.IsReady) { __result = false; return false; } if (component.FuelPowered && !alt) { __result = component.Interact(character, hold, alt: false); return false; } if (alt && !component.FuelPowered) { __result = !hold && component.ToggleCoupling((Player?)(object)((character is Player) ? character : null)); return false; } Player val = (Player)(object)((character is Player) ? character : null); if (val != null && !component.CanRequestCargo(val, out string reason)) { if (!hold) { ((Character)character).Message((MessageType)2, reason, 0, (Sprite)null, false); } __result = false; return false; } if (hold) { return true; } if (RailCargoInventory.BeginRequest(__instance, CargoProtocol.Open)) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(Container), "GetHoverText")] internal static class CargoHoverPatch { [HarmonyPrefix] private static bool Prefix(Container __instance, ref string __result) { if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent())) { return true; } if (RailCargoInventory.TryRefresh(__instance, out string error, requireOwner: false)) { return true; } __result = __instance.m_name + "\n" + error; return false; } [HarmonyPostfix] private static void Postfix(Container __instance, ref string __result) { RailVehicle component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component) && component.FuelPowered) { __result = component.GetHoverText(); } else if (Object.op_Implicit((Object)(object)component)) { __result += Localization.instance.Localize("\n[$KEY_AltPlace + $KEY_Use] " + (component.IsCoupled ? "Uncouple wagon" : "Couple to train ahead")); } } } [HarmonyPatch(typeof(Container), "CanBeRemoved")] internal static class CargoRemovalPatch { [HarmonyPostfix] private static void Postfix(Container __instance, ref bool __result) { RailVehicle component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component) && (!component.IsReady || component.TrainOccupied || component.CargoServiceBusy || component.CouplingServiceBusy || !RailCargoInventory.TryRefresh(__instance, out string _, requireOwner: false) || __instance.GetInventory().NrOfItems() > 0)) { __result = false; } } } internal static class CargoRequests { internal static bool Allow(Container container, long peer, long playerId, ContainerRpcResponse response) { return RailCargoInventory.AllowOwnerRequest(container, peer, playerId, response); } } internal static class CargoProtocol { internal static ContainerRpcResponse Open; internal static ContainerRpcResponse Stack; internal static ContainerRpcResponse TakeAll; internal static void Initialize() { Open = ContainerRpcCompatibility.Open(typeof(Container)); Stack = ContainerRpcCompatibility.Stack(typeof(Container)); TakeAll = ContainerRpcCompatibility.TakeAll(typeof(Container)); } } [HarmonyPatch(typeof(Container), "RPC_RequestOpen")] internal static class CargoOpenRequestPatch { [HarmonyPrefix] private static bool Prefix(Container __instance, long __0, long __1) { return CargoRequests.Allow(__instance, __0, __1, CargoProtocol.Open); } } [HarmonyPatch(typeof(Container), "RPC_RequestStack")] internal static class CargoStackRequestPatch { [HarmonyPrefix] private static bool Prefix(Container __instance, long __0, long __1) { return CargoRequests.Allow(__instance, __0, __1, CargoProtocol.Stack); } } [HarmonyPatch(typeof(Container), "RPC_RequestTakeAll")] internal static class CargoTakeAllRequestPatch { [HarmonyPrefix] private static bool Prefix(Container __instance, long __0, long __1) { return CargoRequests.Allow(__instance, __0, __1, CargoProtocol.TakeAll); } } internal static class CargoResponses { internal static bool Allow(Container container, long peer, bool granted, ContainerRpcResponse response) { return RailCargoInventory.Response(container, peer, granted, response); } } [HarmonyPatch] internal static class CargoOpenResponsePatch { [HarmonyTargetMethod] private static MethodBase TargetMethod() { return CargoProtocol.Open.Method; } [HarmonyPrefix] private static bool Prefix(Container __instance, long __0, bool __1) { return CargoResponses.Allow(__instance, __0, __1, CargoProtocol.Open); } } [HarmonyPatch] internal static class CargoStackResponsePatch { [HarmonyTargetMethod] private static MethodBase TargetMethod() { return CargoProtocol.Stack.Method; } [HarmonyPrefix] private static bool Prefix(Container __instance, long __0, bool __1) { return CargoResponses.Allow(__instance, __0, __1, CargoProtocol.Stack); } } [HarmonyPatch] internal static class CargoTakeAllResponsePatch { [HarmonyTargetMethod] private static MethodBase TargetMethod() { return CargoProtocol.TakeAll.Method; } [HarmonyPrefix] private static bool Prefix(Container __instance, long __0, bool __1) { return CargoResponses.Allow(__instance, __0, __1, CargoProtocol.TakeAll); } } [HarmonyPatch(typeof(Container), "StackAll")] internal static class CargoStackInteractionPatch { [HarmonyPrefix] private static bool Prefix(Container __instance) { return RailCargoInventory.BeginRequest(__instance, CargoProtocol.Stack); } } [HarmonyPatch(typeof(Container), "TakeAll")] internal static class CargoTakeAllInteractionPatch { [HarmonyPrefix] private static bool Prefix(Container __instance, ref bool __result) { if (RailCargoInventory.BeginRequest(__instance, CargoProtocol.TakeAll)) { return true; } __result = false; return false; } } internal static class RailPrefabs { private enum RailSignKind { Station, Direction, DirectionLeft, Warning, Crossing } private static readonly FieldInfo NamedPrefabs = typeof(ZNetScene).GetField("m_namedPrefabs", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly List Prefabs = new List(); private static readonly List Materials = new List(); private static readonly HashSet Scenes = new HashSet(); private static readonly HashSet Tables = new HashSet(); private static GameObject root; private static Material wood; private static Material metal; private static Material brass; private static Material red; private static readonly List SurfaceTextures = new List(); private const float PassengerDeckTop = 0.86f; private const float PassengerChairZ = -0.8f; private const float PassengerExitX = 0.56f; private const float PassengerExitZ = 0.18f; private const float PassengerHearthZ = 0.97f; private static bool warnedPassengerChairFallback; private static readonly List PortablePlowItems = new List(); private static readonly HashSet PortablePlowDatabases = new HashSet(); private static readonly FieldInfo ItemByHash = AccessTools.Field(typeof(ObjectDB), "m_itemByHash"); private static readonly FieldInfo ItemByData = AccessTools.Field(typeof(ObjectDB), "m_itemByData"); private static readonly List PortableVehicleItems = new List(); private static readonly HashSet PortableVehicleDatabases = new HashSet(); private static readonly List PumpkinMeshes = new List(); private static Mesh nativeSignWoodMesh; private static Material nativeSignWoodMaterial; private static Quaternion nativeSignWoodUpright; private const float WorkshopDeckTop = 0.86f; private static readonly HashSet DeferredWorkshopRecipes = new HashSet(StringComparer.Ordinal); internal static bool HasDeferredWorkshopRecipes => DeferredWorkshopRecipes.Count != 0; private static void CreateAutoDriveController(GameObject cart, GameObject floor) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_010b: 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_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_0244: 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_026c: 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_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_0372: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_03c6: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_03e3: Unknown result type (might be due to invalid IL or missing references) //IL_03ed: Unknown result type (might be due to invalid IL or missing references) //IL_03f7: Unknown result type (might be due to invalid IL or missing references) //IL_0462: Unknown result type (might be due to invalid IL or missing references) GameObject val = CloneBase(cart, "vr_autocontroller", keepContainer: false, floor); ConfigurePiece(val.GetComponent(), "Rail automatic controller", "Attach beside the left controls of a parked steam or Eitr engine. Use the attached lever to start or stop automatic forward travel. Alternate-use detaches it while parked. Remove the detached controller with the Hammer to recover its materials."); RailBuildMenu.ConfigureTransportPiece(val.GetComponent()); GameObject val2 = Child(val.transform, "visual", Vector3.zero); Material material = CopyMaterial(metal, "VikingRail_AutoControllerIron", (Color?)new Color(0.17f, 0.19f, 0.2f)); Cube(val2.transform, "controller_foot", new Vector3(0f, 0.02f, 0f), new Vector3(0.26f, 0.04f, 0.3f), Quaternion.identity, wood, collider: false); Cube(val2.transform, "controller_body", new Vector3(0f, 0.2f, 0f), new Vector3(0.24f, 0.3f, 0.26f), Quaternion.identity, material, collider: false); Cube(val2.transform, "controller_top_rim", new Vector3(0f, 0.355f, 0f), new Vector3(0.26f, 0.03f, 0.28f), Quaternion.identity, brass, collider: false); for (int i = -1; i <= 1; i += 2) { Cube(val2.transform, "controller_corner", new Vector3(0f, 0.195f, (float)i * 0.132f), new Vector3(0.25f, 0.29f, 0.012f), Quaternion.identity, brass, collider: false); Cube(val2.transform, "controller_foot_bolt", new Vector3((float)i * 0.09f, 0.045f, -0.11f), new Vector3(0.04f, 0.012f, 0.035f), Quaternion.identity, brass, collider: false); } Primitive(val2.transform, "controller_gauge", (PrimitiveType)2, new Vector3(-0.123f, 0.22f, 0.035f), new Vector3(0.13f, 0.004f, 0.13f), Quaternion.Euler(0f, 0f, 90f), brass, collider: false); Primitive(val2.transform, "controller_gauge_face", (PrimitiveType)2, new Vector3(-0.128f, 0.22f, 0.035f), new Vector3(0.105f, 0.001f, 0.105f), Quaternion.Euler(0f, 0f, 90f), wood, collider: false); Cube(val2.transform, "controller_gauge_needle", new Vector3(-0.129f, 0.235f, 0.021f), new Vector3(0.002f, 0.045f, 0.009f), Quaternion.Euler(42f, 0f, 0f), red, collider: false); GameObject obj = Child(val2.transform, "vr_auto_lever", new Vector3(0f, 0.35f, 0f)); obj.transform.localRotation = Quaternion.Euler(28f, 0f, 0f); Primitive(obj.transform, "controller_lever_hinge", (PrimitiveType)2, Vector3.zero, new Vector3(0.08f, 0.065f, 0.08f), Quaternion.Euler(0f, 0f, 90f), brass, collider: false); Cube(obj.transform, "controller_lever_stem", new Vector3(0f, 0.12f, 0f), new Vector3(0.035f, 0.22f, 0.035f), Quaternion.identity, material, collider: false); Primitive(obj.transform, "controller_lever_grip", (PrimitiveType)0, new Vector3(0f, 0.22f, 0f), new Vector3(0.1f, 0.07f, 0.08f), Quaternion.identity, brass, collider: false); BoxCollider obj2 = val.AddComponent(); obj2.center = RailAutoDrive.LocalBoundsCenter; obj2.size = RailAutoDrive.LocalBoundsHalfSize * 2f; Rigidbody obj3 = val.GetComponent() ?? val.AddComponent(); obj3.isKinematic = true; obj3.useGravity = false; obj3.mass = 20f; ZSyncTransform obj4 = val.GetComponent() ?? val.AddComponent(); obj4.m_syncPosition = true; obj4.m_syncRotation = true; obj4.m_syncScale = false; obj4.m_syncBodyVelocity = false; obj4.m_characterParentSync = false; val.GetComponent().m_type = (ObjectType)0; ConfigureWear(val, val2, track: false); val.GetComponent().m_health = 250f; val.AddComponent(); SetLayer(val, LayerMask.NameToLayer("piece")); Prefabs.Add(val); } private static void CreateRailBridge(GameObject floor, bool wooden = false) { //IL_007a: 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_00fc: 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) int count = Prefabs.Count; CreateTrack(floor, wooden ? "vr_track_wood_bridge24" : "vr_track_bridge24", wooden ? "Wooden rail bridge — 24 m" : "Rail bridge — 24 m", (wooden ? "A 24 m wooden railway bridge with timber side trusses and bronze joints. " : "A 24 m metal railway bridge with a wooden walkway and iron side trusses. ") + "Support both ends on solid banks or strong stone/iron piers; no middle pier needed. Snap the rail ends to ordinary track. " + (wooden ? "For handcarts, bronze engines and wagons. Upgrade in place with 20 Iron Nails for coal and Eitr engines." : "Suitable for every engine and wagon."), Array.ConvertAll(RailBridgeTracks.Points(), RailSegment.ToUnity), RailSectionKind.Normal, wooden, null, Vector3.zero, bridge: true); GameObject obj = Prefabs[count]; Transform obj2 = obj.transform.Find("visual"); if (!Object.op_Implicit((Object)(object)obj2)) { throw new InvalidOperationException("The rail bridge has no track model."); } Material frame = (wooden ? wood : metal); AddRailBridgeDeck(obj2, frame); AddRailBridgeTrusses(obj2, frame, wooden ? brass : metal); WearNTear component = obj.GetComponent(); component.m_materialType = (MaterialType)2; component.m_health = 1200f; component.m_comOffset = Vector3.zero; RailTerrainPlacement.Configure(obj); RailTrackSupport.ConfigureBridge(obj); } private static void AddRailBridgeDeck(Transform visual, Material frame) { //IL_0022: 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_003b: 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_0095: 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) for (int i = 0; i < 48; i++) { Cube(visual, "bridge_deck_plank", new Vector3(0f, -0.13f, -11.75f + (float)i * 0.5f), new Vector3(3.6f, 0.18f, 0.495f), Quaternion.identity, wood); } float[] array = new float[9] { -11.75f, -9f, -6f, -3f, 0f, 3f, 6f, 9f, 11.75f }; foreach (float num in array) { Cube(visual, "bridge_crossbearer", new Vector3(0f, -0.31f, num), new Vector3(3.8f, 0.18f, 0.18f), Quaternion.identity, frame); } } private static void AddRailBridgeTrusses(Transform visual, Material frame, Material joints) { //IL_0034: 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_006b: 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_0084: 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_00fc: 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_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: 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_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) float[] array = new float[9] { -11.75f, -9f, -6f, -3f, 0f, 3f, 6f, 9f, 11.75f }; for (int i = -1; i <= 1; i += 2) { float num = (float)i * 1.9f; Cube(visual, "bridge_side_beam", new Vector3(num, -0.38f, 0f), new Vector3(0.22f, 0.32f, 24f), Quaternion.identity, frame); Cube(visual, "bridge_top_chord", new Vector3(num, 1.35f, 0f), new Vector3(0.18f, 0.16f, 24f), Quaternion.identity, frame); float[] array2 = array; foreach (float num2 in array2) { bool flag = Mathf.Abs(num2) > 11f; float num3 = (flag ? (-0.54f) : (-0.22f)); Cube(visual, flag ? "bridge_end_post" : "bridge_truss_post", new Vector3(num, (num3 + 1.35f) * 0.5f, num2), new Vector3(0.16f, 1.35f - num3, 0.16f), Quaternion.identity, frame); Cube(visual, "bridge_joint_plate", new Vector3((float)i * 2.007f, 1.35f, num2), new Vector3(0.024f, 0.22f, 0.26f), Quaternion.identity, joints, collider: false); } for (int k = 0; k < array.Length - 1; k++) { bool flag2 = (k & 1) == 0; Beam(visual, "bridge_diagonal", new Vector3(num, flag2 ? (-0.22f) : 1.35f, array[k]), new Vector3(num, flag2 ? 1.35f : (-0.22f), array[k + 1]), 0.13f, 0.13f, frame); } for (int l = -1; l <= 1; l += 2) { Cube(visual, "bridge_bearing", new Vector3(num, -0.68f, (float)l * 11.65f), new Vector3(0.56f, 0.28f, 0.7f), Quaternion.identity, frame); } } } private static void CreateBronzeEngine(GameObject cart, GameObject floor) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Expected O, but got Unknown //IL_00ed: 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) //IL_017e: Unknown result type (might be due to invalid IL or missing references) GameObject val = CloneBase(cart, "vr_bronze_engine", keepContainer: true, floor); ConfigurePiece(val.GetComponent(), "Bronze rail engine", "A compact wood-burning bronze engine for wooden or metal rails. Use to drive; alternate-use opens its two-slot wood hopper."); GameObject val2 = Child(val.transform, "visual", Vector3.zero); AddWorkshopChassis(val2.transform); Material bronze = CopyMaterial(brass, "VikingRail_BronzeEngine", (Color?)new Color(0.73f, 0.47f, 0.2f)); AddBronzeEngineVisual(val2.transform, bronze); Container component = val.GetComponent(); component.m_name = "Bronze engine wood hopper"; component.m_width = 2; component.m_height = 1; component.m_privacy = (PrivacySetting)2; component.m_checkGuardStone = true; component.m_autoDestroyEmpty = false; component.m_rootObjectOverride = null; component.m_wagon = null; component.m_open = null; component.m_closed = null; component.m_defaultItems = new DropTable(); Child(val.transform, "vr_driver", new Vector3(0f, 1f, -0.65f)); Child(val.transform, "vr_smoke_origin", new Vector3(0f, 2.36f, 0.48f)); Rigidbody obj = val.GetComponent() ?? val.AddComponent(); obj.isKinematic = true; obj.useGravity = false; obj.mass = 170f; ZSyncTransform obj2 = val.GetComponent() ?? val.AddComponent(); obj2.m_syncPosition = true; obj2.m_syncRotation = true; obj2.m_syncScale = false; obj2.m_syncBodyVelocity = false; obj2.m_characterParentSync = false; val.GetComponent().m_type = (ObjectType)0; ConfigureWear(val, val2, track: false); RailVehicle railVehicle = val.AddComponent(); railVehicle.IsEngine = true; railVehicle.BronzePowered = true; railVehicle.CoalPowered = false; AddVehicleLights(val, val2.transform, engine: true); AddPackingHandle(val2.transform); Prefabs.Add(val); } private static void AddBronzeEngineVisual(Transform visual, Material bronze) { //IL_0015: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_006a: 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_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_00f2: 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_010b: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_016e: 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_01aa: 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_01c3: 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_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: 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_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_038d: Unknown result type (might be due to invalid IL or missing references) //IL_03c0: Unknown result type (might be due to invalid IL or missing references) //IL_03d4: Unknown result type (might be due to invalid IL or missing references) //IL_03e8: Unknown result type (might be due to invalid IL or missing references) //IL_040e: Unknown result type (might be due to invalid IL or missing references) //IL_0422: Unknown result type (might be due to invalid IL or missing references) //IL_0427: Unknown result type (might be due to invalid IL or missing references) //IL_044d: Unknown result type (might be due to invalid IL or missing references) //IL_0461: Unknown result type (might be due to invalid IL or missing references) //IL_0466: Unknown result type (might be due to invalid IL or missing references) //IL_0498: Unknown result type (might be due to invalid IL or missing references) //IL_04ac: Unknown result type (might be due to invalid IL or missing references) //IL_04c0: Unknown result type (might be due to invalid IL or missing references) //IL_04f1: Unknown result type (might be due to invalid IL or missing references) //IL_0505: Unknown result type (might be due to invalid IL or missing references) //IL_0519: Unknown result type (might be due to invalid IL or missing references) //IL_053c: Unknown result type (might be due to invalid IL or missing references) //IL_0550: Unknown result type (might be due to invalid IL or missing references) //IL_0555: Unknown result type (might be due to invalid IL or missing references) Cube(visual, "bronze_firebox", new Vector3(0f, 1.035f, 0.36f), new Vector3(0.7f, 0.34f, 0.75f), Quaternion.identity, bronze); Primitive(visual, "bronze_boiler", (PrimitiveType)2, new Vector3(0f, 1.41f, 0.36f), new Vector3(0.64f, 0.46f, 0.64f), Quaternion.identity, bronze, collider: true); float[] array = new float[2] { 1.27f, 1.81f }; foreach (float num in array) { Primitive(visual, "boiler_band", (PrimitiveType)2, new Vector3(0f, num, 0.36f), new Vector3(0.68f, 0.027f, 0.68f), Quaternion.identity, metal, collider: false); } Primitive(visual, "boiler_cap", (PrimitiveType)0, new Vector3(0f, 1.88f, 0.36f), new Vector3(0.64f, 0.17f, 0.64f), Quaternion.identity, bronze, collider: false); Primitive(visual, "chimney", (PrimitiveType)2, new Vector3(0f, 2.08f, 0.48f), new Vector3(0.18f, 0.23f, 0.18f), Quaternion.identity, metal, collider: true); Primitive(visual, "chimney_rim", (PrimitiveType)2, new Vector3(0f, 2.3f, 0.48f), new Vector3(0.28f, 0.03f, 0.28f), Quaternion.identity, bronze, collider: false); Primitive(visual, "pressure_valve", (PrimitiveType)2, new Vector3(-0.25f, 1.98f, 0.28f), new Vector3(0.09f, 0.07f, 0.09f), Quaternion.identity, brass, collider: false); Cube(visual, "firebox_door", new Vector3(0f, 1.045f, -0.023f), new Vector3(0.39f, 0.23f, 0.032f), Quaternion.identity, metal, collider: false); Cube(visual, "firebox_latch", new Vector3(0.12f, 1.05f, -0.051f), new Vector3(0.17f, 0.035f, 0.03f), Quaternion.identity, brass, collider: false); Cube(visual, "flywheel_bracket", new Vector3(0.45f, 1.06f, 0.21f), new Vector3(0.12f, 0.4f, 0.18f), Quaternion.identity, bronze); GameObject val = Child(visual, "vr_bronze_flywheel", new Vector3(0.52f, 1.3f, 0.21f)); Primitive(val.transform, "flywheel_rim", (PrimitiveType)2, Vector3.zero, new Vector3(0.6f, 0.05f, 0.6f), Quaternion.Euler(0f, 0f, 90f), bronze, collider: false); Primitive(val.transform, "flywheel_face", (PrimitiveType)2, new Vector3(0.057f, 0f, 0f), new Vector3(0.42f, 0.007f, 0.42f), Quaternion.Euler(0f, 0f, 90f), metal, collider: false); for (int j = 0; j < 4; j++) { Cube(val.transform, "flywheel_spoke", new Vector3(0.074f, 0f, 0f), new Vector3(0.023f, 0.045f, 0.48f), Quaternion.Euler((float)j * 45f, 0f, 0f), bronze, collider: false); } Primitive(val.transform, "flywheel_hub", (PrimitiveType)2, new Vector3(0.1f, 0f, 0f), new Vector3(0.14f, 0.027f, 0.14f), Quaternion.Euler(0f, 0f, 90f), brass, collider: false); Cube(visual, "wood_hopper", new Vector3(0.62f, 1.08f, -0.57f), new Vector3(0.34f, 0.44f, 0.62f), Quaternion.identity, wood); Cube(visual, "wood_hopper_rim", new Vector3(0.62f, 1.305f, -0.57f), new Vector3(0.38f, 0.055f, 0.66f), Quaternion.identity, bronze, collider: false); for (int k = -1; k <= 1; k++) { Primitive(visual, "hopper_log", (PrimitiveType)2, new Vector3(0.62f + (float)k * 0.09f, 1.35f, -0.57f), new Vector3(0.085f, 0.24f, 0.085f), Quaternion.Euler(90f, 0f, 0f), wood, collider: false); } Cube(visual, "throttle_stem", new Vector3(-0.41f, 1.25f, -0.25f), new Vector3(0.07f, 0.65f, 0.07f), Quaternion.Euler(-16f, 0f, 0f), bronze, collider: false); Primitive(visual, "throttle_grip", (PrimitiveType)0, new Vector3(-0.41f, 1.56f, -0.34f), new Vector3(0.17f, 0.17f, 0.17f), Quaternion.identity, wood, collider: false); } private static void CreateBypassTracks(GameObject floor) { //IL_013e: 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_022f: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) foreach (RailBypassTrackDefinition item in RailBypassTracks.All) { string text = (item.LightDuty ? "Wooden track" : "Rail track"); string text2 = (item.TurnsLeft ? "left" : "right"); string text3 = (item.LightDuty ? " Handcarts, bronze engines and wagons only; coal and Eitr engines require iron rails." : ""); if (!item.IsSwitch) { RailVector[] array = item.Points(); RailPath railPath = new RailPath(array); CreateTrack(floor, item.PrefabName, text + " — bypass curve " + text2, "An S-shaped connector that shifts the track 4 m " + text2 + " over 12 m, with parallel ends. Connects a single route; use bypass switches to join a passing siding to the main line." + text3, Array.ConvertAll(array, RailSegment.ToUnity), RailSectionKind.Normal, item.LightDuty, null, RailSegment.ToUnity(railPath.Sample(railPath.Length * 0.5).Position)); continue; } GameObject val = CloneBase(floor, item.PrefabName, keepContainer: false, floor); ConfigurePiece(val.GetComponent(), text + " — bypass switch " + text2, "A straight main line with a parallel siding 4 m to the " + text2 + ". Use the lever to select Main line or Bypass. Join a mirrored switch at the far end with straight rails; leave enough siding for the whole train." + text3); GameObject val2 = Child(val.transform, "visual", Vector3.zero); Vector3[] array2 = Array.ConvertAll(item.TrunkPoints(), RailSegment.ToUnity); Vector3[] array3 = Array.ConvertAll(item.ThroughPoints(), RailSegment.ToUnity); Vector3[] array4 = Array.ConvertAll(item.BranchPoints(), RailSegment.ToUnity); Material railMaterial = (item.LightDuty ? wood : metal); AddSwitchRails(val2.transform, array2, railMaterial); AddSwitchRails(val2.transform, array3, railMaterial); AddSwitchRails(val2.transform, array4, railMaterial); AddBypassSleepers(val2.transform, array2, array3, array4, item.LightDuty); AddSnap(val.transform, "snap_start", array2[0]); AddSnap(val.transform, "snap_left", array3[^1]); AddSnap(val.transform, "snap_right", array4[^1]); RailSwitch railSwitch = val.AddComponent(); railSwitch.TrunkPoints = array2; railSwitch.LeftPoints = array3; railSwitch.RightPoints = array4; railSwitch.LightDuty = item.LightDuty; railSwitch.IsBypassConnection = true; AddSwitchLever(Child(val2.transform, "bypass_control", array2[^1]).transform, railSwitch); ConfigureWear(val, val2, track: true); RailTerrainPlacement.Configure(val); RailTrackSupport.Configure(val); Prefabs.Add(val); } } private static void AddBypassSleepers(Transform parent, Vector3[] trunk, Vector3[] through, Vector3[] branch, bool lightDuty) { //IL_002f: 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_00b9: 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_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00db: 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_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: 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_01c0: 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_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_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_0130: 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_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0184: 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_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0292: 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_0205: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_024e: 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) float x = through[0].x; for (float num = trunk[0].z + 0.25f; num < trunk[^1].z; num += 0.5f) { Cube(parent, "sleeper", new Vector3(x, 0.02f, num), new Vector3(1.9f, 0.12f, 0.2f), Quaternion.identity, wood); if (lightDuty) { AddSwitchNails(parent, trunk, num); } } for (float num2 = through[0].z + 0.25f; num2 < through[^1].z; num2 += 0.5f) { int i; for (i = 1; i < branch.Length - 1 && branch[i].z < num2; i++) { } Vector3 val = branch[i] - branch[i - 1]; Vector3 normalized = ((Vector3)(ref val)).normalized; Vector3 val2 = Vector3.Lerp(branch[i - 1], branch[i], (num2 - branch[i - 1].z) / (branch[i].z - branch[i - 1].z)); if (Mathf.Abs(val2.x - x) < 1.85f) { float num3 = Mathf.Min(x, val2.x) - 0.95f; float num4 = Mathf.Max(x, val2.x) + 0.95f; Cube(parent, "switch_sleeper", new Vector3((num3 + num4) * 0.5f, 0.02f, num2), new Vector3(num4 - num3, 0.12f, 0.2f), Quaternion.identity, wood); if (lightDuty) { AddSwitchNails(parent, branch, num2); } } else { Cube(parent, "switch_sleeper", val2 + Vector3.up * 0.02f, new Vector3(1.9f, 0.12f, 0.2f), Quaternion.LookRotation(normalized, Vector3.up), wood); if (lightDuty) { for (int j = -1; j <= 1; j += 2) { Cube(parent, "bronze_nail", val2 + Vector3.Cross(Vector3.up, normalized) * ((float)j * 0.7f) + Vector3.up * 0.169f, new Vector3(0.065f, 0.025f, 0.065f), Quaternion.LookRotation(normalized, Vector3.up), brass, collider: false); } } Cube(parent, "switch_sleeper", new Vector3(x, 0.02f, num2), new Vector3(1.9f, 0.12f, 0.2f), Quaternion.identity, wood); } if (lightDuty) { AddSwitchNails(parent, through, num2); } } } private static void AddStorageCartBed(Transform visual) { //IL_0015: 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_002e: 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_0072: 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_00a0: 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_00b9: 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_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) Cube(visual, "cargo_bed_floor", new Vector3(0f, 0.97f, 0f), new Vector3(1.35f, 0.22f, 1.5f), Quaternion.identity, wood); for (int i = -1; i <= 1; i += 2) { Cube(visual, "cargo_bed_side", new Vector3((float)i * 0.65f, 1.1f, 0f), new Vector3(0.1f, 0.16f, 1.58f), Quaternion.identity, wood); Cube(visual, "cargo_bed_end", new Vector3(0f, 1.1f, (float)i * 0.735f), new Vector3(1.2f, 0.16f, 0.11f), Quaternion.identity, wood); for (int j = -1; j <= 1; j += 2) { Cube(visual, "cargo_bed_band", new Vector3((float)i * 0.655f, 1.08f, (float)j * 0.56f), new Vector3(0.11f, 0.21f, 0.06f), Quaternion.identity, metal, collider: false); } } } private static void AddCouplingLever(Transform visual) { //IL_0019: 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_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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_00ce: 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_011b: 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_0143: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: 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_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0277: 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_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: 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) if (!Object.op_Implicit((Object)(object)visual.Find("vr_coupling_lever"))) { GameObject val = Child(visual, "vr_coupling_lever", RailCouplingLever.SocketOffset); Cube(val.transform, "release_mount", new Vector3(0.025f, 0f, 0f), new Vector3(0.11f, 0.17f, 0.22f), Quaternion.identity, metal, collider: false); Cube(val.transform, "release_backplate", new Vector3(-0.04f, 0f, 0f), new Vector3(0.025f, 0.18f, 0.23f), Quaternion.identity, brass, collider: false); for (int i = -1; i <= 1; i += 2) { Primitive(val.transform, "release_rivet", (PrimitiveType)0, new Vector3(-0.057f, 0f, (float)i * 0.085f), new Vector3(0.025f, 0.04f, 0.04f), Quaternion.identity, metal, collider: false); } Primitive(val.transform, "release_pivot", (PrimitiveType)2, new Vector3(-0.062f, 0f, 0f), new Vector3(0.1f, 0.028f, 0.1f), Quaternion.Euler(0f, 0f, 90f), brass, collider: false); GameObject obj = Child(val.transform, "vr_release_arm", new Vector3(-0.075f, 0f, 0f)); obj.transform.localRotation = Quaternion.Euler(-35f, 0f, 0f); Cube(obj.transform, "release_stem", new Vector3(0f, 0.155f, 0f), new Vector3(0.055f, 0.31f, 0.065f), Quaternion.identity, red, collider: false); Cube(obj.transform, "release_grip", new Vector3(0f, 0.31f, 0f), new Vector3(0.12f, 0.08f, 0.1f), Quaternion.identity, red, collider: false); Cube(obj.transform, "release_grip_band", new Vector3(-0.002f, 0.31f, 0f), new Vector3(0.13f, 0.025f, 0.105f), Quaternion.identity, brass, collider: false); Cube(visual, "release_linkage", new Vector3(-0.49f, 0.6f, 1.015f), new Vector3(1.035f, 0.04f, 0.04f), Quaternion.Euler(0f, -18.6f, 0f), metal, collider: false); BoxCollider obj2 = val.AddComponent(); obj2.center = RailCouplingLever.TargetCenter; obj2.size = RailCouplingLever.HalfExtents * 2f; val.AddComponent(); SetLayer(val, LayerMask.NameToLayer("piece")); } } internal static void AddCouplingLevers(GameObject root) { //IL_0099: 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_00f9: 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) if (!Object.op_Implicit((Object)(object)root) || !Object.op_Implicit((Object)(object)root.GetComponent())) { return; } Transform val = root.transform.Find("visual"); if (!Object.op_Implicit((Object)(object)val)) { return; } AddCouplingLever(val); Transform val2 = val.Find("vr_coupling_lever"); if (Object.op_Implicit((Object)(object)val2)) { (((Component)val2).GetComponent() ?? ((Component)val2).gameObject.AddComponent()).Front = true; Transform val3 = val.Find("vr_coupling_lever_rear"); if (!Object.op_Implicit((Object)(object)val3)) { GameObject obj = Object.Instantiate(((Component)val2).gameObject, val, false); ((Object)obj).name = "vr_coupling_lever_rear"; val3 = obj.transform; } val3.localPosition = RailCouplingLever.RearSocketOffset; (((Component)val3).GetComponent() ?? ((Component)val3).gameObject.AddComponent()).Front = false; if (!Object.op_Implicit((Object)(object)val.Find("release_linkage_rear"))) { Cube(val, "release_linkage_rear", new Vector3(-0.49f, 0.6f, -1.015f), new Vector3(1.035f, 0.04f, 0.04f), Quaternion.Euler(0f, 18.6f, 0f), metal, collider: false); } } } internal static bool IsRegisteredBuildPiece(GameObject prefab) { if (Object.op_Implicit((Object)(object)prefab)) { return Prefabs.Contains(prefab); } return false; } public static void Register(ZNetScene scene) { if ((Object)(object)scene == (Object)null) { return; } RailSettings.Update(); RailTorchMounts.EnsureDestructionTracking(); RailAutoDrive.EnsureDestructionTracking(); if (NamedPrefabs == null) { throw new MissingFieldException(typeof(ZNetScene).FullName, "m_namedPrefabs"); } if ((Object)(object)root == (Object)null) { Build(scene); } Dictionary dictionary = (Dictionary)NamedPrefabs.GetValue(scene); foreach (GameObject prefab in Prefabs) { int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name); if (dictionary.TryGetValue(stableHashCode, out var value) && (Object)(object)value != (Object)(object)prefab) { throw new InvalidOperationException("A different prefab already uses the VikingRail name: " + ((Object)prefab).name); } } foreach (GameObject prefab2 in Prefabs) { int stableHashCode2 = StringExtensionMethods.GetStableHashCode(((Object)prefab2).name); dictionary[stableHashCode2] = prefab2; if (!scene.m_prefabs.Contains(prefab2)) { scene.m_prefabs.Add(prefab2); } } Scenes.Add(scene); AddToHammer(ObjectDB.instance); } public static void AddToHammer(ObjectDB db) { if ((Object)(object)db == (Object)null || Prefabs.Count == 0) { return; } RailTerrainPaintTool.Register(db); RegisterPortablePlowItems(db); RegisterPortableVehicleItems(db); GameObject itemPrefab = db.GetItemPrefab("Hammer"); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent() : null); PieceTable val2 = (((Object)(object)val != (Object)null) ? val.m_itemData.m_shared.m_buildPieces : null); if ((Object)(object)val2 == (Object)null || val2.m_pieces == null) { return; } ItemDrop val3 = FindItem(db, "Wood"); ItemDrop val4 = FindItem(db, "FineWood"); ItemDrop val5 = FindItem(db, "BronzeNails"); ItemDrop val6 = FindItem(db, "IronNails"); ItemDrop val7 = FindItem(db, "Iron"); ItemDrop val8 = FindItem(db, "Bronze"); ItemDrop val9 = FindItem(db, "Resin"); if ((Object)(object)val3 == (Object)null || (Object)(object)val5 == (Object)null || (Object)(object)val6 == (Object)null || (Object)(object)val7 == (Object)null || (Object)(object)val9 == (Object)null) { return; } Tables.Add(val2); foreach (GameObject prefab in Prefabs) { if (!Object.op_Implicit((Object)(object)prefab.GetComponent()) || RegisterWorkshopRecipe(prefab, db, val2)) { continue; } bool flag = (Object)(object)prefab.GetComponent() != (Object)null || (Object)(object)prefab.GetComponent() != (Object)null; Requirement[] resources; RailThreeWayTrackDefinition definition2; RailParallelYardTrackDefinition definition3; RailBypassTrackDefinition definition4; RailSteepTrackDefinition definition5; if (TryCurveRecipe(((Object)prefab).name, out RailCurveTrackDefinition definition)) { resources = (Requirement[])(object)new Requirement[2] { Cost(val3, definition.WoodCost), Cost(definition.LightDuty ? val5 : val6, definition.NailsCost) }; } else if (RailThreeWayTracks.TryGet(((Object)prefab).name, out definition2)) { resources = (Requirement[])(object)new Requirement[2] { Cost(val3, definition2.WoodCost), Cost(definition2.LightDuty ? val5 : val6, definition2.NailsCost) }; } else if (RailParallelYardTracks.TryGet(((Object)prefab).name, out definition3)) { resources = (Requirement[])(object)new Requirement[2] { Cost(val3, definition3.WoodCost), Cost(definition3.LightDuty ? val5 : val6, definition3.NailsCost) }; } else if (RailBypassTracks.TryGet(((Object)prefab).name, out definition4)) { resources = (Requirement[])(object)new Requirement[2] { Cost(val3, definition4.WoodCost), Cost(definition4.LightDuty ? val5 : val6, definition4.NailsCost) }; } else if (RailSteepTracks.TryGet(((Object)prefab).name, out definition5)) { if (definition5.Long && (Object)(object)val4 == (Object)null) { continue; } resources = (Requirement[])(object)new Requirement[2] { Cost(definition5.Long ? val4 : val3, definition5.WoodCost), Cost(definition5.LightDuty ? val5 : val6, definition5.NailsCost) }; } else { switch (((Object)prefab).name) { case "vr_rail_gate": resources = (Requirement[])(object)new Requirement[3] { Cost(val3, 20), Cost(val6, 10), Cost(val7, 4) }; break; case "vr_turntable12": case "vr_turntable24": { if ((Object)(object)val4 == (Object)null) { continue; } int num = ((!(((Object)prefab).name == "vr_turntable24")) ? 1 : 2); resources = (Requirement[])(object)new Requirement[3] { Cost(val4, 40 * num), Cost(val7, 20 * num), Cost(val6, 40 * num) }; break; } case "vr_track_wood_bridge24": if ((Object)(object)val4 == (Object)null) { continue; } resources = (Requirement[])(object)new Requirement[3] { Cost(val4, 36), Cost(val3, 40), Cost(val5, 20) }; break; case "vr_track_bridge24": if ((Object)(object)val4 == (Object)null) { continue; } resources = (Requirement[])(object)new Requirement[4] { Cost(val4, 48), Cost(val3, 20), Cost(val7, 12), Cost(val6, 20) }; break; case "vr_track_straight_long": case "vr_track_slope_long": if ((Object)(object)val4 == (Object)null) { continue; } resources = (Requirement[])(object)new Requirement[2] { Cost(val4, 24), Cost(val6, 6) }; break; case "vr_track_wood_straight_long": case "vr_track_wood_slope_long": if ((Object)(object)val4 == (Object)null) { continue; } resources = (Requirement[])(object)new Requirement[2] { Cost(val4, 18), Cost(val5, 3) }; break; case "vr_locomotive": resources = (Requirement[])(object)new Requirement[3] { Cost(val3, 20), Cost(val7, 20), Cost(val5, 10) }; break; case "vr_bronze_engine": if ((Object)(object)val8 == (Object)null) { continue; } resources = (Requirement[])(object)new Requirement[3] { Cost(val3, 20), Cost(val8, 10), Cost(val5, 10) }; break; case "vr_eitr_engine": { ItemDrop val13 = FindItem(db, "Eitr"); ItemDrop val14 = FindItem(db, "YggdrasilWood"); ItemDrop val15 = FindItem(db, "BlackMetal"); ItemDrop val16 = FindItem(db, "SurtlingCore"); if ((Object)(object)val13 == (Object)null || (Object)(object)val14 == (Object)null || (Object)(object)val15 == (Object)null || (Object)(object)val16 == (Object)null) { continue; } resources = (Requirement[])(object)new Requirement[5] { Cost(val14, 20), Cost(val15, 20), Cost(val7, 10), Cost(val13, 10), Cost(val16, 5) }; break; } case "vr_passengercart": resources = (Requirement[])(object)new Requirement[2] { Cost(val3, 30), Cost(val5, 10) }; break; case "vr_mount_cart": resources = (Requirement[])(object)new Requirement[3] { Cost(val3, 30), Cost(val7, 6), Cost(val6, 10) }; break; case "vr_music_cart": { ItemDrop val10 = FindItem(db, "SurtlingCore"); ItemDrop val11 = FindItem(db, "DeerHide"); if ((Object)(object)val4 == (Object)null || (Object)(object)val8 == (Object)null || (Object)(object)val10 == (Object)null || (Object)(object)val11 == (Object)null) { continue; } resources = (Requirement[])(object)new Requirement[5] { Cost(val4, 20), Cost(val8, 8), Cost(val5, 20), Cost(val10, 2), Cost(val11, 4) }; break; } case "vr_pumpkin_cart": { ItemDrop val18 = FindItem(db, "SurtlingCore"); if ((Object)(object)val4 == (Object)null || (Object)(object)val18 == (Object)null) { continue; } resources = (Requirement[])(object)new Requirement[5] { Cost(val3, 30), Cost(val4, 10), Cost(val5, 20), Cost(val9, 10), Cost(val18, 2) }; break; } case "vr_autocontroller": { ItemDrop val17 = FindItem(db, "SurtlingCore"); if ((Object)(object)val4 == (Object)null || (Object)(object)val17 == (Object)null) { continue; } resources = (Requirement[])(object)new Requirement[3] { Cost(val4, 5), Cost(val7, 5), Cost(val17, 1) }; break; } case "vr_handcart_tandem": resources = (Requirement[])(object)new Requirement[2] { Cost(val3, 30), Cost(val5, 20) }; break; case "vr_torch": { ItemDrop val12 = FindItem(db, "GreydwarfEye"); if ((Object)(object)val12 == (Object)null) { continue; } resources = (Requirement[])(object)new Requirement[2] { Cost(val3, 2), Cost(val12, 1) }; break; } case "vr_track_brake": resources = (Requirement[])(object)new Requirement[2] { Cost(val3, 8), Cost(val6, 4) }; break; case "vr_track_switch": resources = (Requirement[])(object)new Requirement[2] { Cost(val3, 20), Cost(val6, 8) }; break; case "vr_track_wood_switch": resources = (Requirement[])(object)new Requirement[2] { Cost(val3, 15), Cost(val5, 4) }; break; case "vr_track_bumper": resources = (Requirement[])(object)new Requirement[2] { Cost(val3, 10), Cost(val7, 2) }; break; case "vr_plow": resources = (Requirement[])(object)new Requirement[3] { Cost(val3, 10), Cost(val7, 10), Cost(val5, 4) }; break; case "vr_track_wood_straight": case "vr_track_wood_curve": case "vr_track_wood_slope": resources = (Requirement[])(object)new Requirement[2] { Cost(val3, 6), Cost(val5, 1) }; break; case "vr_track_wood_brake": resources = (Requirement[])(object)new Requirement[2] { Cost(val3, 6), Cost(val5, 2) }; break; case "vr_track_wood_bumper": resources = (Requirement[])(object)new Requirement[2] { Cost(val3, 8), Cost(val5, 2) }; break; case "vr_plow_wood": resources = (Requirement[])(object)new Requirement[2] { Cost(val3, 10), Cost(val5, 8) }; break; case "vr_sign_crossing": case "vr_sign_station": resources = (Requirement[])(object)new Requirement[2] { Cost(val3, 6), Cost(val5, 2) }; break; case "vr_sign_direction_left": case "vr_sign_direction": case "vr_sign_warning": resources = (Requirement[])(object)new Requirement[2] { Cost(val3, 4), Cost(val5, 2) }; break; default: resources = (Requirement[])(object)new Requirement[2] { Cost(val3, flag ? 8 : 20), Cost(flag ? val6 : val5, flag ? 2 : 10) }; break; } } prefab.GetComponent().m_resources = resources; if (!val2.m_pieces.Contains(prefab)) { val2.m_pieces.Add(prefab); } } } public static void Cleanup() { RailSpawnProtection.Reset(); RailTerrainMaintenance.Reset(); RailTerrainPaintTool.Cleanup(); RailTorchMounts.Cleanup(); RailMountedObject.Cleanup(); RailAutoDrive.Cleanup(); CleanupPortablePlowItems(); CleanupPortableVehicleItems(); foreach (PieceTable table in Tables) { if ((Object)(object)table != (Object)null) { table.m_pieces.RemoveAll((GameObject piece) => Prefabs.Contains(piece)); } } foreach (ZNetScene scene in Scenes) { if ((Object)(object)scene == (Object)null) { continue; } Dictionary dictionary = (Dictionary)NamedPrefabs.GetValue(scene); foreach (GameObject prefab in Prefabs) { if (!((Object)(object)prefab == (Object)null)) { int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name); if (dictionary.TryGetValue(stableHashCode, out var value) && (Object)(object)value == (Object)(object)prefab) { dictionary.Remove(stableHashCode); } scene.m_prefabs.Remove(prefab); } } } Tables.Clear(); DeferredWorkshopRecipes.Clear(); Scenes.Clear(); Prefabs.Clear(); if ((Object)(object)root != (Object)null) { Object.Destroy((Object)(object)root); } root = null; CleanupPumpkinMeshes(); CleanupNativeSignWood(); foreach (Material material in Materials) { if ((Object)(object)material != (Object)null) { Object.Destroy((Object)(object)material); } } Materials.Clear(); CleanupSurfaceTextures(); wood = null; metal = null; brass = null; red = null; RailIcons.Cleanup(); } private static void Build(ZNetScene scene) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //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) //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_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_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: 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) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_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_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = scene.GetPrefab("wood_floor"); GameObject prefab2 = scene.GetPrefab("Cart"); if ((Object)(object)prefab == (Object)null || (Object)(object)prefab2 == (Object)null) { throw new InvalidOperationException("VikingRail requires the vanilla wood_floor and Cart prefabs."); } root = new GameObject("VikingRail_Prefabs"); root.SetActive(false); Object.DontDestroyOnLoad((Object)(object)root); bool forceDisableInit = ZNetView.m_forceDisableInit; ZNetView.m_forceDisableInit = true; try { RailTerrainPaintTool.Initialize(root.transform); CreateSolidMaterials(prefab); CreateTrack(prefab, "vr_track_straight", "Rail track — straight", "4 m rail section. Snap the ends together; support elevated rails with a bridge.", (Vector3[])(object)new Vector3[2] { new Vector3(0f, 0f, -2f), new Vector3(0f, 0f, 2f) }); Vector3[] array = (Vector3[])(object)new Vector3[9]; for (int i = 0; i < array.Length; i++) { float num = (float)Math.PI / 8f * (float)i / (float)(array.Length - 1); array[i] = new Vector3(8f * (1f - Mathf.Cos(num)), 0f, 8f * Mathf.Sin(num)); } CreateTrack(prefab, "vr_track_curve", "Rail track — 22.5° curve", "22.5 degree curve, 8 m radius. Rotate or reverse placement to turn left or right.", array); CreateTrack(prefab, "vr_track_slope", "Rail track — incline", "Rises 1 m over 4 m. Support it with beams, stairs, or a bridge.", (Vector3[])(object)new Vector3[2] { Vector3.zero, new Vector3(0f, 1f, 4f) }); CreateTrack(prefab, "vr_track_brake", "Rail track — stop", "4 m stopping section. Trains stop automatically; release the controls before setting off again.", (Vector3[])(object)new Vector3[2] { new Vector3(0f, 0f, -2f), new Vector3(0f, 0f, 2f) }, RailSectionKind.Brake); CreateTrack(prefab, "vr_track_bumper", "Rail track — end bumper", "4 m terminal section. Approach from the open end; the train stops before the barrier and can reverse away.", (Vector3[])(object)new Vector3[2] { new Vector3(0f, 0f, -2f), new Vector3(0f, 0f, 2f) }, RailSectionKind.Bumper); CreateWoodenTracks(prefab, array); CreateLongTracks(prefab); CreateSteepTracks(prefab); CreateRailBridge(prefab); CreateRailBridge(prefab, wooden: true); CreateCurveTracks(prefab); CreateRailSwitch(prefab); CreateRailSwitch(prefab, lightDuty: true); CreateBypassTracks(prefab); CreateThreeWaySwitches(prefab); CreateParallelYardSwitches(prefab); CreateTurntables(prefab); CreateRailGate(prefab); CreateVehicle(prefab2, prefab, engine: true); CreateTandemHandcart(prefab2, prefab); CreateBronzeEngine(prefab2, prefab); CreateEitrEngine(prefab2, prefab); CreateVehicle(prefab2, prefab, engine: false); CreatePassengerCart(prefab2, prefab); CreateMountCart(prefab2, prefab); CreateMusicCart(scene, prefab2, prefab); CreatePumpkinCart(prefab2, prefab); CreateWorkshopCarts(scene, prefab2, prefab); CreateRepairCart(scene, prefab2, prefab); CreateVehicle(prefab2, prefab, engine: true, coalPowered: true); CreatePlow(prefab2, prefab); CreatePlow(prefab2, prefab, wooden: true); CreateAutoDriveController(prefab2, prefab); foreach (GameObject prefab3 in Prefabs) { if (Object.op_Implicit((Object)(object)prefab3.GetComponent())) { AddCouplingLevers(prefab3); } } CreatePortablePlowItems(scene); CreatePortableVehicleItems(scene); CreateRailSigns(scene); CreateRailTorch(scene); ConfigureTrackUpgrades(); } catch { Cleanup(); throw; } finally { ZNetView.m_forceDisableInit = forceDisableInit; } } private static void CreateTrack(GameObject floor, string name, string title, string description, Vector3[] points, RailSectionKind kind = RailSectionKind.Normal, bool lightDuty = false, Material timberMaterial = null, Vector3? supportCenter = null, bool bridge = false) { //IL_002e: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_0065: 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_006c: 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_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_0081: 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_0091: 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_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: 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_00bd: 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_00cf: 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_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_018f: 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_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: 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_01d4: 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_01dd: 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_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) Material val = timberMaterial ?? wood; GameObject val2 = CloneBase(floor, name, keepContainer: false, floor); ConfigurePiece(val2.GetComponent(), title, description); GameObject val3 = Child(val2.transform, "visual", Vector3.zero); Vector3 val4; for (int i = 0; i < points.Length - 1; i++) { val4 = points[i + 1] - points[i]; Vector3 normalized = ((Vector3)(ref val4)).normalized; val4 = Vector3.Cross(Vector3.up, normalized); Vector3 normalized2 = ((Vector3)(ref val4)).normalized; for (int j = -1; j <= 1; j += 2) { Vector3 val5 = normalized2 * ((float)j * 0.7f) + Vector3.up * 0.115f; Beam(val3.transform, "rail", points[i] + val5, points[i + 1] + val5, 0.095f, 0.09f, lightDuty ? val : metal); } } float num = 0f; for (int k = 1; k < points.Length; k++) { num += Vector3.Distance(points[k - 1], points[k]); } int num2 = Mathf.Max(2, Mathf.CeilToInt(num / 0.5f)); for (int l = 0; l < num2; l++) { Vector3 tangent; Vector3 val6 = Sample(points, num * ((float)l + 0.5f) / (float)num2, out tangent); Cube(val3.transform, "sleeper", val6 + Vector3.up * 0.02f, new Vector3(1.9f, 0.12f, 0.2f), Quaternion.LookRotation(tangent, Vector3.up), val); if (lightDuty) { val4 = Vector3.Cross(Vector3.up, tangent); Vector3 normalized3 = ((Vector3)(ref val4)).normalized; for (int m = -1; m <= 1; m += 2) { Cube(val3.transform, "bronze_nail", val6 + normalized3 * ((float)m * 0.7f) + Vector3.up * 0.169f, new Vector3(0.065f, 0.025f, 0.065f), Quaternion.LookRotation(tangent, Vector3.up), brass, collider: false); } } } AddSnap(val2.transform, "snap_start", points[0]); if (kind != RailSectionKind.Bumper) { AddSnap(val2.transform, "snap_end", points[^1]); } if (kind == RailSectionKind.Brake) { AddBrakeVisual(val3.transform); } if (kind == RailSectionKind.Bumper) { AddBumperVisual(val3.transform, lightDuty); } RailSegment railSegment = val2.AddComponent(); railSegment.Points = points; railSegment.Kind = kind; railSegment.LightDuty = lightDuty; railSegment.IsBridge = bridge; ConfigureWear(val2, val3, track: true); if (supportCenter.HasValue) { val2.GetComponent().m_comOffset = supportCenter.Value; } if (!bridge) { RailTerrainPlacement.Configure(val2); RailTrackSupport.Configure(val2); } Prefabs.Add(val2); } private static void CreateVehicle(GameObject cart, GameObject floor, bool engine, bool coalPowered = false) { //IL_0073: 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_00b7: 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_00fe: 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) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_015a: 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_018e: 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) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: 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_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_02f2: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Unknown result type (might be due to invalid IL or missing references) //IL_0335: 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_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_03f9: Unknown result type (might be due to invalid IL or missing references) //IL_0421: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Expected O, but got Unknown //IL_04a1: Unknown result type (might be due to invalid IL or missing references) string name = (coalPowered ? "vr_locomotive" : (engine ? "vr_handcart" : "vr_storagecart")); string title = (coalPowered ? "Coal locomotive" : (engine ? "Rail handcart" : "Rail storage cart")); GameObject val = CloneBase(cart, name, !engine || coalPowered, floor); ConfigurePiece(val.GetComponent(), title, coalPowered ? "Coal powered locomotive. Use to drive; alternate-use opens its two-slot fuel hopper. Fill with coal before departing." : (engine ? "Human powered handcart. Place on rails and use to drive; movement consumes stamina." : "16 slot storage wagon. Place on rails; use to open and alternate-use to couple or uncouple.")); GameObject val2 = Child(val.transform, "visual", Vector3.zero); for (int i = 0; i < 5; i++) { Cube(val2.transform, "deck_plank", new Vector3((float)(i - 2) * 0.33f, 0.74f, 0f), new Vector3(0.32f, 0.24f, 2.1f), Quaternion.identity, wood); } for (int j = -1; j <= 1; j += 2) { Cube(val2.transform, "chassis", new Vector3((float)j * 0.51f, 0.54f, 0f), new Vector3(0.15f, 0.22f, 2.25f), Quaternion.identity, wood); Cube(val2.transform, "coupler", new Vector3(0f, 0.53f, (float)j * 1.18f), new Vector3(0.16f, 0.14f, 0.35f), Quaternion.identity, metal); Cube(val2.transform, "axle", new Vector3(0f, 0.44f, (float)j * 0.68f), new Vector3(1.65f, 0.09f, 0.09f), Quaternion.identity, metal); for (int k = -1; k <= 1; k += 2) { if (!coalPowered) { ((Object)Primitive(val2.transform, "wheel", (PrimitiveType)2, new Vector3((float)k * 0.7f, 0.44f, (float)j * 0.68f), new Vector3(0.56f, 0.075f, 0.56f), Quaternion.Euler(0f, 0f, 90f), metal, collider: false)).name = "vr_wheel"; } } } if (coalPowered) { AddLocomotiveVisual(val2.transform); } else if (engine) { Cube(val2.transform, "pump_post", new Vector3(0f, 1.215f, 0.66f), new Vector3(0.14f, 0.71f, 0.14f), Quaternion.identity, wood); GameObject obj = Child(val.transform, "vr_pump", new Vector3(0f, 1.57f, 0.66f)); Cube(obj.transform, "pump_lever", new Vector3(0f, 0f, -0.275f), new Vector3(0.12f, 0.1f, 0.55f), Quaternion.identity, wood, collider: false); Cube(obj.transform, "pump_handle", new Vector3(0f, 0f, -0.55f), new Vector3(1.25f, 0.1f, 0.12f), Quaternion.identity, wood, collider: false); } else { AddStorageCartBed(val2.transform); } if (!engine || coalPowered) { Container component = val.GetComponent(); component.m_name = (coalPowered ? "Locomotive fuel hopper" : "Rail storage cart"); component.m_width = (coalPowered ? 2 : 4); component.m_height = (coalPowered ? 1 : 4); component.m_privacy = (PrivacySetting)2; component.m_checkGuardStone = true; component.m_autoDestroyEmpty = false; component.m_rootObjectOverride = null; component.m_wagon = null; component.m_open = null; component.m_closed = null; component.m_defaultItems = new DropTable(); } Child(val.transform, "vr_driver", new Vector3(0f, 1f, coalPowered ? (-0.6f) : (engine ? (-0.25f) : 0f))); if (coalPowered) { Child(val.transform, "vr_smoke_origin", new Vector3(0f, 2.63f, 0.78f)); } Rigidbody obj2 = val.GetComponent() ?? val.AddComponent(); obj2.isKinematic = true; obj2.useGravity = false; obj2.mass = (coalPowered ? 250f : (engine ? 100f : 80f)); ZSyncTransform obj3 = val.GetComponent() ?? val.AddComponent(); obj3.m_syncPosition = true; obj3.m_syncRotation = true; obj3.m_syncScale = false; obj3.m_syncBodyVelocity = false; obj3.m_characterParentSync = false; val.GetComponent().m_type = (ObjectType)0; ConfigureWear(val, val2, track: false); RailVehicle railVehicle = val.AddComponent(); railVehicle.IsEngine = engine; railVehicle.CoalPowered = coalPowered; if (!engine) { val.AddComponent(); } AddVehicleLights(val, val2.transform, engine); AddPackingHandle(val2.transform); if (!engine) { AddPushHandle(val2.transform); } Prefabs.Add(val); } private static void CreatePlow(GameObject cart, GameObject floor, bool wooden = false) { //IL_0042: 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_0086: 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_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0176: 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_01a6: 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_01bf: 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_00a5: 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_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_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_0109: Unknown result type (might be due to invalid IL or missing references) //IL_011d: 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_023b: Unknown result type (might be due to invalid IL or missing references) GameObject val = CloneBase(cart, wooden ? "vr_plow_wood" : "vr_plow", keepContainer: false, floor); ConfigurePiece(val.GetComponent(), wooden ? "Wooden rail plow" : "Rail plow", "Build beside a free end of a parked engine or cart. Use to attach or detach. Shoves and damages creatures when this blade leads the train."); GameObject val2 = Child(val.transform, "visual", Vector3.zero); Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(0f, 0.625f, 0.27f); Vector3 val4 = default(Vector3); for (int i = -1; i <= 1; i += 2) { ((Vector3)(ref val4))..ctor((float)i * 1.035f, 0.625f, -0.27f); Vector3 val5 = val4 - val3; Cube(val2.transform, wooden ? "wooden_blade" : "iron_blade", (val3 + val4) * 0.5f, new Vector3(0.06f, 0.75f, ((Vector3)(ref val5)).magnitude), Quaternion.LookRotation(val5, Vector3.up), wooden ? wood : metal); Cube(val2.transform, "plow_back_upright", new Vector3((float)i * 0.63f, 0.63f, -0.24f), new Vector3(0.1f, 0.6f, 0.1f), Quaternion.identity, wooden ? brass : wood); } Cube(val2.transform, "plow_back_beam", new Vector3(0f, 0.74f, -0.25f), new Vector3(1.68f, 0.12f, 0.1f), Quaternion.identity, wood); Cube(val2.transform, "plow_mount", new Vector3(0f, 0.48f, -0.24f), new Vector3(0.24f, 0.18f, 0.12f), Quaternion.identity, wooden ? brass : metal); Rigidbody obj = val.GetComponent() ?? val.AddComponent(); obj.isKinematic = true; obj.useGravity = false; obj.mass = 60f; ZSyncTransform obj2 = val.GetComponent() ?? val.AddComponent(); obj2.m_syncPosition = true; obj2.m_syncRotation = true; obj2.m_syncScale = false; obj2.m_syncBodyVelocity = false; obj2.m_characterParentSync = false; val.GetComponent().m_type = (ObjectType)0; ConfigureWear(val, val2, track: false); val.AddComponent(); Prefabs.Add(val); } private static void AddBrakeVisual(Transform parent) { //IL_001f: 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_0061: 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_007a: 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_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_00ea: 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_0112: 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_0153: 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) for (int i = -1; i <= 1; i += 2) { Cube(parent, "brake_strip", new Vector3((float)i * 0.49f, 0.14f, 0f), new Vector3(0.12f, 0.09f, 2.25f), Quaternion.identity, red); Cube(parent, "brake_link", new Vector3(0f, 0.1f, (float)i * 0.65f), new Vector3(1.15f, 0.05f, 0.14f), Quaternion.identity, brass); } Cube(parent, "stop_sign_post", new Vector3(-1.14f, 0.64f, 0f), new Vector3(0.09f, 1.25f, 0.09f), Quaternion.identity, wood, collider: false); Cube(parent, "stop_sign", new Vector3(-1.14f, 1.34f, 0f), new Vector3(0.43f, 0.43f, 0.08f), Quaternion.Euler(0f, 0f, 45f), red, collider: false); for (int j = -1; j <= 1; j += 2) { Cube(parent, "stop_sign_bar", new Vector3(-1.14f, 1.34f, (float)j * 0.046f), new Vector3(0.35f, 0.07f, 0.012f), Quaternion.identity, brass, collider: false); } } private static void AddBumperVisual(Transform parent, bool wooden = false) { //IL_001f: 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_0061: 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_007a: 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_00c9: 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_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0110: 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) for (int i = -1; i <= 1; i += 2) { Cube(parent, "buffer_upright", new Vector3((float)i * 0.74f, 0.61f, 2f), new Vector3(0.18f, 1.22f, 0.2f), Quaternion.identity, wood); Cube(parent, "buffer_foot", new Vector3((float)i * 0.74f, 0.11f, 2.15f), new Vector3(0.28f, 0.18f, 0.5f), Quaternion.identity, wooden ? brass : metal); } Cube(parent, "buffer_beam", new Vector3(0f, 0.93f, 2f), new Vector3(1.88f, 0.3f, 0.2f), Quaternion.identity, red); for (int j = -2; j <= 2; j++) { Cube(parent, "buffer_warning_band", new Vector3((float)j * 0.35f, 0.93f, 1.892f), new Vector3(0.1f, 0.31f, 0.012f), Quaternion.identity, brass, collider: false); } } private static Requirement Cost(ItemDrop item, int amount) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_0013: 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_0022: Expected O, but got Unknown return new Requirement { m_resItem = item, m_amount = amount, m_amountPerLevel = 0, m_recover = true }; } private static GameObject CloneBase(GameObject source, string name, bool keepContainer, GameObject floor) { //IL_001f: 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_003f: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate(source, root.transform, false); ((Object)val).name = name; val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; val.transform.localScale = Vector3.one; Container val2 = val.GetComponent(); if (keepContainer && (Object)(object)val2 == (Object)null) { Container componentInChildren = val.GetComponentInChildren(true); val2 = val.AddComponent(); if ((Object)(object)componentInChildren != (Object)null) { CopyFields((Component)(object)componentInChildren, (Component)(object)val2); } } Component[] components = val.GetComponents(); foreach (Component val3 in components) { if (!(val3 is Transform) && !(val3 is Piece) && !(val3 is ZNetView) && !(val3 is WearNTear) && !(val3 is Rigidbody) && !(val3 is ZSyncTransform) && (!keepContainer || !((Object)(object)val3 == (Object)(object)val2))) { Object.DestroyImmediate((Object)(object)val3); } } while (val.transform.childCount > 0) { Object.DestroyImmediate((Object)(object)((Component)val.transform.GetChild(0)).gameObject); } if ((Object)(object)val.GetComponent() == (Object)null) { CopyFields((Component)(object)floor.GetComponent(), (Component)(object)val.AddComponent()); } if ((Object)(object)val.GetComponent() == (Object)null) { CopyFields((Component)(object)floor.GetComponent(), (Component)(object)val.AddComponent()); } ZNetView obj = val.GetComponent() ?? val.AddComponent(); obj.m_persistent = true; obj.m_distant = false; SetLayer(val, LayerMask.NameToLayer("piece")); val.SetActive(true); return val; } private static void ConfigurePiece(Piece piece, string title, string description) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) Sprite val = RailIcons.Get(((Object)((Component)piece).gameObject).name); if ((Object)(object)val != (Object)null) { piece.m_icon = val; } piece.m_name = title; piece.m_description = description; piece.m_enabled = true; piece.m_category = (PieceCategory)0; piece.m_craftingStation = null; piece.m_groundOnly = false; piece.m_groundPiece = false; piece.m_cultivatedGroundOnly = false; piece.m_waterPiece = false; piece.m_noInWater = false; piece.m_notOnWood = false; piece.m_notOnFloor = false; piece.m_notOnTiltingSurface = false; piece.m_inCeilingOnly = false; piece.m_noClipping = false; piece.m_clipGround = true; piece.m_clipEverything = false; piece.m_spaceRequirement = 0f; piece.m_canRotate = true; piece.m_canBeRemoved = true; piece.m_comfort = 0; piece.m_comfortObject = null; piece.m_mustConnectTo = null; piece.m_resources = Array.Empty(); } private static void ConfigureWear(GameObject prefab, GameObject visual, bool track) { //IL_0041: 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) WearNTear component = prefab.GetComponent(); component.m_new = visual; component.m_worn = visual; component.m_broken = visual; component.m_wet = null; component.m_staticPosition = track; component.m_noSupportWear = track; component.m_noRoofWear = false; component.m_supports = track; component.m_materialType = (MaterialType)0; component.m_health = (track ? 200f : 500f); component.m_nonSolidRenderers = new List(); component.m_fragmentRoots = (GameObject[])(object)new GameObject[1] { visual }; component.m_comOffset = Vector3.zero; component.m_forceCorrectCOMCalculation = true; } private static Vector3 Sample(Vector3[] points, float distance, out Vector3 tangent) { //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_0019: 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_007a: 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_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_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_005d: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < points.Length - 1; i++) { Vector3 val = points[i + 1] - points[i]; float magnitude = ((Vector3)(ref val)).magnitude; if (distance <= magnitude || i == points.Length - 2) { tangent = ((Vector3)(ref val)).normalized; return Vector3.Lerp(points[i], points[i + 1], (magnitude > 0f) ? (distance / magnitude) : 0f); } distance -= magnitude; } tangent = Vector3.forward; return points[0]; } private static void AddSnap(Transform parent, string name, Vector3 point) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) Child(parent, name, point).tag = "snappoint"; } private static GameObject Child(Transform parent, string name, Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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_0019: 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_0031: Expected O, but got Unknown GameObject val = new GameObject(name); val.transform.SetParent(parent, false); val.transform.localPosition = position; val.layer = ((Component)parent).gameObject.layer; return val; } private static void Beam(Transform parent, string name, Vector3 from, Vector3 to, float width, float height, Material material) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_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_0016: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) Vector3 val = to - from; Cube(parent, name, (from + to) * 0.5f, new Vector3(width, height, ((Vector3)(ref val)).magnitude + 0.015f), Quaternion.LookRotation(val, Vector3.up), material); } private static GameObject Cube(Transform parent, string name, Vector3 position, Vector3 scale, Quaternion rotation, Material material, bool collider = true) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) return Primitive(parent, name, (PrimitiveType)3, position, scale, rotation, material, collider); } private static GameObject Primitive(Transform parent, string name, PrimitiveType type, Vector3 position, Vector3 scale, Quaternion rotation, Material material, bool collider) { //IL_0000: 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_002d: 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) GameObject val = GameObject.CreatePrimitive(type); ((Object)val).name = name; val.transform.SetParent(parent, false); val.transform.localPosition = position; val.transform.localRotation = rotation; val.transform.localScale = scale; val.layer = ((Component)parent).gameObject.layer; val.GetComponent().sharedMaterial = material; if (!collider) { Object.DestroyImmediate((Object)(object)val.GetComponent()); } return val; } private static Material FindMaterial(GameObject source, params string[] preferredNames) { Material val = null; Renderer[] componentsInChildren = source.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { Material[] sharedMaterials = componentsInChildren[i].sharedMaterials; foreach (Material val2 in sharedMaterials) { if ((Object)(object)val2 == (Object)null || (Object)(object)val2.shader == (Object)null) { continue; } if ((Object)(object)val == (Object)null) { val = val2; } foreach (string value in preferredNames) { if (((Object)val2).name.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { return val2; } } } } return val; } private static Material CopyMaterial(Material source, string name, Color? tint) { //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_0028: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)source == (Object)null) { throw new InvalidOperationException("Could not find a vanilla material for " + name); } Material val = new Material(source) { name = name }; if (tint.HasValue) { SetSolidTint(val, tint.Value); } SetOpaqueSurface(val); Materials.Add(val); return val; } private static void CopyFields(Component source, Component target) { if ((Object)(object)source == (Object)null) { return; } FieldInfo[] fields = ((object)source).GetType().GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { if (!fieldInfo.IsInitOnly) { fieldInfo.SetValue(target, fieldInfo.GetValue(source)); } } } private static ItemDrop FindItem(ObjectDB db, string name) { GameObject itemPrefab = db.GetItemPrefab(name); if (!((Object)(object)itemPrefab != (Object)null)) { return null; } return itemPrefab.GetComponent(); } private static void SetLayer(GameObject obj, int layer) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) if (layer >= 0) { obj.layer = layer; } foreach (Transform item in obj.transform) { SetLayer(((Component)item).gameObject, layer); } } private static void CreateCurveTracks(GameObject floor) { //IL_01b0: Unknown result type (might be due to invalid IL or missing references) foreach (RailCurveTrackDefinition addition in RailCurveTracks.Additions) { RailVector[] array = addition.Points(); RailPath railPath = new RailPath(array); string text = addition.AngleDegrees.ToString("0.##", CultureInfo.InvariantCulture); string text2 = (addition.LightDuty ? "Wooden track" : "Rail track"); string text3 = (addition.TurnsLeft ? "left" : "right"); string title = text2 + " — " + text + "° " + (addition.Incline ? ("rising " + text3) : "curve"); string text4 = text + " degree curve, 8 m radius. "; if (addition.Incline) { double num = array[^1].Y - array[0].Y; text4 = text4 + "Turns " + text3 + " while rising " + num.ToString("0.##", CultureInfo.InvariantCulture) + " m at the standard 1:4 grade. Connect its upper end to build downhill. "; } else { text4 += "Rotate or reverse placement to turn left or right. "; } text4 += "Snap the ends to compatible rails; support elevated sections with beams or a bridge."; if (addition.LightDuty) { text4 += " For handcarts, bronze engines and wagons; coal and Eitr engines require metal rails."; } CreateTrack(floor, addition.PrefabName, title, text4, Array.ConvertAll(array, RailSegment.ToUnity), RailSectionKind.Normal, addition.LightDuty, null, RailSegment.ToUnity(railPath.Sample(railPath.Length * 0.5).Position)); } } private static bool TryCurveRecipe(string prefabName, out RailCurveTrackDefinition definition) { foreach (RailCurveTrackDefinition addition in RailCurveTracks.Additions) { if (addition.PrefabName == prefabName) { definition = addition; return true; } } definition = null; return false; } private static void CreateEitrEngine(GameObject cart, GameObject floor) { //IL_0039: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Expected O, but got Unknown //IL_0141: 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_017a: Expected O, but got Unknown //IL_0194: 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_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) GameObject val = CloneBase(cart, "vr_eitr_engine", keepContainer: true, floor); ConfigurePiece(val.GetComponent(), "Eitr rail engine", "An arcane engine powered by refined Eitr. Runs on metal rails only. Use to drive; alternate-use opens its two-slot refined Eitr hopper."); RailBuildMenu.ConfigureTransportPiece(val.GetComponent()); GameObject val2 = Child(val.transform, "visual", Vector3.zero); AddWorkshopChassis(val2.transform); Material val3 = CopyMaterial(metal, "VikingRail_EitrFrame", (Color?)new Color(0.12f, 0.17f, 0.18f)); foreach (Transform item in val2.transform) { Transform val4 = item; if (!(((Object)val4).name == "deck_plank")) { if (((Object)val4).name == "axle") { Vector3 localScale = val4.localScale; localScale.x = 1.64f; val4.localScale = localScale; } Renderer component = ((Component)val4).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { component.sharedMaterial = val3; } } } AddEitrEngineVisual(val2.transform, val3, EitrCoreMaterial()); Container component2 = val.GetComponent(); component2.m_name = "Eitr engine fuel hopper"; component2.m_width = 2; component2.m_height = 1; component2.m_privacy = (PrivacySetting)2; component2.m_checkGuardStone = true; component2.m_autoDestroyEmpty = false; component2.m_rootObjectOverride = null; component2.m_wagon = null; component2.m_open = null; component2.m_closed = null; component2.m_defaultItems = new DropTable(); Child(val.transform, "vr_driver", new Vector3(0f, 1f, -0.65f)); Rigidbody obj = val.GetComponent() ?? val.AddComponent(); obj.isKinematic = true; obj.useGravity = false; obj.mass = 210f; ZSyncTransform obj2 = val.GetComponent() ?? val.AddComponent(); obj2.m_syncPosition = true; obj2.m_syncRotation = true; obj2.m_syncScale = false; obj2.m_syncBodyVelocity = false; obj2.m_characterParentSync = false; val.GetComponent().m_type = (ObjectType)0; ConfigureWear(val, val2, track: false); RailVehicle railVehicle = val.AddComponent(); railVehicle.IsEngine = true; railVehicle.EitrPowered = true; railVehicle.CoalPowered = false; railVehicle.BronzePowered = false; AddVehicleLights(val, val2.transform, engine: true); AddPackingHandle(val2.transform); Prefabs.Add(val); } private static Material EitrCoreMaterial() { //IL_0025: 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_00ad: Unknown result type (might be due to invalid IL or missing references) Color val = default(Color); ((Color)(ref val))..ctor(0.08f, 0.82f, 0.7f, 1f); Material val2 = CopyMaterial(metal, "VikingRail_EitrCore", val); SetSurfaceTexture(val2, (Texture)(object)Texture2D.whiteTexture); SetMaterialFloat(val2, "_Metallic", 0f); SetMaterialFloat(val2, "_Glossiness", 0.35f); SetMaterialFloat(val2, "_Smoothness", 0.35f); if (val2.HasProperty("_EmissionMap")) { val2.SetTexture("_EmissionMap", (Texture)(object)Texture2D.whiteTexture); } if (val2.HasProperty("_EmissionColor")) { val2.EnableKeyword("_EMISSION"); val2.SetColor("_EmissionColor", val * 0.8f); } SetOpaqueSurface(val2); return val2; } private static void AddEitrEngineVisual(Transform visual, Material frame, Material core) { //IL_001f: 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_00ca: 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_00e3: 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) //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_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015e: 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_007d: 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_01ac: 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_01c5: 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_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0350: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) //IL_0382: Unknown result type (might be due to invalid IL or missing references) //IL_0393: Unknown result type (might be due to invalid IL or missing references) //IL_03b4: Unknown result type (might be due to invalid IL or missing references) //IL_03c5: Unknown result type (might be due to invalid IL or missing references) //IL_03f1: Unknown result type (might be due to invalid IL or missing references) //IL_0402: Unknown result type (might be due to invalid IL or missing references) //IL_0423: Unknown result type (might be due to invalid IL or missing references) //IL_0434: Unknown result type (might be due to invalid IL or missing references) //IL_0455: Unknown result type (might be due to invalid IL or missing references) //IL_0466: Unknown result type (might be due to invalid IL or missing references) //IL_049d: Unknown result type (might be due to invalid IL or missing references) //IL_04b1: Unknown result type (might be due to invalid IL or missing references) //IL_04b6: Unknown result type (might be due to invalid IL or missing references) //IL_04d8: Unknown result type (might be due to invalid IL or missing references) //IL_04ec: Unknown result type (might be due to invalid IL or missing references) //IL_04f1: Unknown result type (might be due to invalid IL or missing references) //IL_0517: Unknown result type (might be due to invalid IL or missing references) //IL_052b: Unknown result type (might be due to invalid IL or missing references) //IL_0530: Unknown result type (might be due to invalid IL or missing references) //IL_0552: Unknown result type (might be due to invalid IL or missing references) //IL_0566: Unknown result type (might be due to invalid IL or missing references) //IL_057a: Unknown result type (might be due to invalid IL or missing references) //IL_059d: Unknown result type (might be due to invalid IL or missing references) //IL_05b1: Unknown result type (might be due to invalid IL or missing references) //IL_05b6: Unknown result type (might be due to invalid IL or missing references) for (int i = -1; i <= 1; i += 2) { Cube(visual, "eitr_deck_edge", new Vector3((float)i * 0.755f, 0.88f, 0f), new Vector3(0.055f, 0.055f, 2.05f), Quaternion.identity, brass, collider: false); for (int j = -1; j <= 1; j += 2) { Primitive(visual, "eitr_wheel_hub", (PrimitiveType)2, new Vector3((float)i * 0.785f, 0.44f, (float)j * 0.68f), new Vector3(0.16f, 0.018f, 0.16f), Quaternion.Euler(0f, 0f, 90f), brass, collider: false); } } Cube(visual, "eitr_reactor_plinth", new Vector3(0f, 1.01f, 0.34f), new Vector3(1.03f, 0.3f, 1.1f), Quaternion.identity, frame); Cube(visual, "eitr_reactor_base_band", new Vector3(0f, 1.175f, 0.34f), new Vector3(0.9f, 0.055f, 0.9f), Quaternion.identity, brass, collider: false); Primitive(visual, "vr_eitr_core", (PrimitiveType)0, new Vector3(0f, 1.61f, 0.34f), new Vector3(0.58f, 0.8f, 0.58f), Quaternion.identity, core, collider: false); float[] array = new float[2] { 1.22f, 2.03f }; foreach (float num in array) { for (int l = -1; l <= 1; l += 2) { Cube(visual, "eitr_cage_band", new Vector3((float)l * 0.36f, num, 0.34f), new Vector3(0.075f, 0.075f, 0.795f), Quaternion.identity, brass, collider: false); Cube(visual, "eitr_cage_band", new Vector3(0f, num, 0.34f + (float)l * 0.36f), new Vector3(0.645f, 0.075f, 0.075f), Quaternion.identity, brass, collider: false); } } for (int m = -1; m <= 1; m += 2) { for (int n = -1; n <= 1; n += 2) { Cube(visual, "eitr_cage_post", new Vector3((float)m * 0.36f, 1.625f, 0.34f + (float)n * 0.36f), new Vector3(0.075f, 0.81f, 0.075f), Quaternion.identity, frame); } } Cube(visual, "eitr_crown", new Vector3(0f, 2.1f, 0.34f), new Vector3(0.6f, 0.085f, 0.6f), Quaternion.Euler(0f, 45f, 0f), frame, collider: false); Primitive(visual, "eitr_crown_stud", (PrimitiveType)0, new Vector3(0f, 2.17f, 0.34f), new Vector3(0.17f, 0.13f, 0.17f), Quaternion.identity, brass, collider: false); for (int num2 = -1; num2 <= 1; num2 += 2) { float num3 = 0.34f + (float)num2 * 0.378f; EitrTrace(visual, new Vector3(0f, 1.29f, num3), new Vector3(0f, 1.94f, num3), 0.045f, brass); EitrTrace(visual, new Vector3(0f, 1.7f, num3), new Vector3(-0.18f, 1.87f, num3), 0.045f, brass); EitrTrace(visual, new Vector3(0f, 1.51f, num3), new Vector3(0.18f, 1.68f, num3), 0.045f, brass); float num4 = (float)num2 * 0.378f; EitrTrace(visual, new Vector3(num4, 1.29f, 0.34f), new Vector3(num4, 1.94f, 0.34f), 0.045f, brass); EitrTrace(visual, new Vector3(num4, 1.7f, 0.34f), new Vector3(num4, 1.87f, 0.16f), 0.045f, brass); EitrTrace(visual, new Vector3(num4, 1.51f, 0.34f), new Vector3(num4, 1.68f, 0.52f), 0.045f, brass); } Cube(visual, "eitr_fuel_box", new Vector3(0.635f, 1.045f, -0.54f), new Vector3(0.33f, 0.37f, 0.6f), Quaternion.identity, frame); Cube(visual, "eitr_fuel_box_lid", new Vector3(0.635f, 1.255f, -0.54f), new Vector3(0.355f, 0.055f, 0.625f), Quaternion.identity, brass, collider: false); Cube(visual, "eitr_fuel_box_inlay", new Vector3(0.635f, 1.292f, -0.54f), new Vector3(0.17f, 0.018f, 0.29f), Quaternion.identity, core, collider: false); Cube(visual, "eitr_control_stem", new Vector3(-0.44f, 1.22f, -0.23f), new Vector3(0.07f, 0.62f, 0.07f), Quaternion.Euler(-14f, 0f, 0f), frame, collider: false); Primitive(visual, "eitr_control_grip", (PrimitiveType)0, new Vector3(-0.44f, 1.515f, -0.304f), new Vector3(0.17f, 0.17f, 0.17f), Quaternion.identity, brass, collider: false); } private static void EitrTrace(Transform visual, Vector3 from, Vector3 to, float width, Material material) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_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_001a: 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_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) Vector3 val = to - from; Cube(visual, "eitr_rune", (from + to) * 0.5f, new Vector3(width, width, ((Vector3)(ref val)).magnitude), Quaternion.FromToRotation(Vector3.forward, ((Vector3)(ref val)).normalized), material, collider: false); } private static void CreateRailGate(GameObject floor) { //IL_002e: 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_007e: 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_00ab: 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_00ec: 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_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_029a: 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_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_0149: 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_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) GameObject val = CloneBase(floor, "vr_rail_gate", keepContainer: false, floor); ConfigurePiece(val.GetComponent(), "Automatic railway gate", "A wide double gate that opens for an approaching train and closes after the last car clears. Build over existing track with both posts supported. Keep the leaves' swing area clear; no overhead beam blocks tall carts."); GameObject val2 = Child(val.transform, "visual", Vector3.zero); val2.AddComponent(); for (int i = -1; i <= 1; i += 2) { float num = (float)i * 2.65f; Cube(val2.transform, "rail_gate_post", new Vector3(num, 1.96f, 0f), new Vector3(0.3f, 4.38f, 0.42f), Quaternion.identity, wood); Cube(val2.transform, "rail_gate_foot", new Vector3(num, -0.23f, 0f), new Vector3(0.6f, 0.24f, 0.7f), Quaternion.identity, metal); Cube(val2.transform, "rail_gate_post_cap", new Vector3(num, 4.2f, 0f), new Vector3(0.42f, 0.18f, 0.54f), Quaternion.identity, metal, collider: false); float[] array = new float[3] { 0.35f, 1.9f, 3.7f }; foreach (float num2 in array) { Cube(val2.transform, "rail_gate_post_band", new Vector3(num, num2, 0f), new Vector3(0.33f, 0.12f, 0.45f), Quaternion.identity, metal, collider: false); } array = new float[2] { 0.58f, 3.42f }; foreach (float num3 in array) { Primitive(val2.transform, "rail_gate_hinge", (PrimitiveType)2, new Vector3(num, num3, 0f), new Vector3(0.24f, 0.18f, 0.24f), Quaternion.identity, metal, collider: false); } } Transform leftLeaf = AddRailGateLeaf(val2.transform, -1); Transform rightLeaf = AddRailGateLeaf(val2.transform, 1); RailGate railGate = val.AddComponent(); railGate.LeftLeaf = leftLeaf; railGate.RightLeaf = rightLeaf; railGate.OpenDegrees = 100f; AddSnap(val.transform, "snap_start", new Vector3(0f, 0f, -2f)); AddSnap(val.transform, "snap_end", new Vector3(0f, 0f, 2f)); AddSnap(val.transform, "snap_left_foot", new Vector3(-2.65f, -0.35f, 0f)); AddSnap(val.transform, "snap_right_foot", new Vector3(2.65f, -0.35f, 0f)); ConfigureWear(val, val2, track: true); WearNTear component = val.GetComponent(); component.m_materialType = (MaterialType)2; component.m_health = 800f; Prefabs.Add(val); } private static Transform AddRailGateLeaf(Transform parent, int side) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_009f: 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_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0174: 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_0176: 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_0188: 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_018a: 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_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: 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_0279: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) GameObject val = Child(parent, (side < 0) ? "vr_rail_gate_left" : "vr_rail_gate_right", new Vector3((float)side * 2.65f, 0f, 0f)); float num = -side; val.AddComponent(); BoxCollider obj = val.AddComponent(); obj.center = new Vector3(num * 1.295f, 2.1f, 0f); obj.size = new Vector3(2.59f, 3.6f, 0.22f); for (int i = 0; i < 8; i++) { Cube(val.transform, "rail_gate_board", new Vector3(num * (0.19f + (float)i * 0.32f), 2.1f, 0f), new Vector3(0.3f, 3.36f, 0.16f), Quaternion.identity, wood, collider: false); } float[] array = new float[3] { 0.42f, 2.09f, 3.76f }; foreach (float num2 in array) { Cube(val.transform, "rail_gate_crossbar", new Vector3(num * 1.295f, num2, 0f), new Vector3(2.59f, 0.24f, 0.22f), Quaternion.identity, metal, collider: false); } Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(num * 0.16f, 0.57f, -0.12f); Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(num * 2.43f, 3.6f, -0.12f); Vector3 val4 = val3 - val2; Cube(val.transform, "rail_gate_diagonal", (val2 + val3) * 0.5f, new Vector3(0.11f, 0.05f, ((Vector3)(ref val4)).magnitude), Quaternion.LookRotation(val4, Vector3.forward), metal, collider: false); for (int k = 0; k < 3; k++) { array = new float[2] { 0.21f, 2.37f }; foreach (float num3 in array) { Primitive(val.transform, "rail_gate_rivet", (PrimitiveType)0, new Vector3(num * num3, 0.42f + (float)k * 1.67f, -0.133f), new Vector3(0.075f, 0.075f, 0.045f), Quaternion.identity, brass, collider: false); } } Cube(val.transform, "rail_gate_latch_plate", new Vector3(num * 2.34f, 2f, -0.139f), new Vector3(0.22f, 0.36f, 0.055f), Quaternion.identity, brass, collider: false); return val.transform; } private static void AddVehicleLights(GameObject prefab, Transform visual, bool engine) { //IL_01d4: 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_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: 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_0027: 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_006b: 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_0084: 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_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_00dc: 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_0111: 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_0155: 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_01ab: Unknown result type (might be due to invalid IL or missing references) if (engine) { GameObject obj = Child(visual, "vr_headlamp", prefab.GetComponent().HeadlampLocalPosition); Cube(obj.transform, "lamp_case", Vector3.zero, new Vector3(0.31f, 0.31f, 0.18f), Quaternion.identity, metal, collider: false); Cube(obj.transform, "lamp_rim", new Vector3(0f, 0f, 0.1f), new Vector3(0.34f, 0.34f, 0.035f), Quaternion.identity, brass, collider: false); Cube(obj.transform, "vr_lamp_lens", new Vector3(0f, 0f, 0.123f), new Vector3(0.26f, 0.26f, 0.025f), Quaternion.identity, LampGlass(new Color(1f, 0.73f, 0.3f)), collider: false); AddLampSwitch(obj, new Vector3(0f, 0f, 0.04f), new Vector3(0.34f, 0.34f, 0.26f)); Light obj2 = Child(obj.transform, "vr_lamp_beam", new Vector3(0f, 0f, 0.15f)).AddComponent(); ConfigureLamp(obj2, (LightType)0, new Color(1f, 0.81f, 0.48f), 20f, 2.6f); obj2.spotAngle = 70f; ConfigureLamp(Child(obj.transform, "vr_lamp_glow", new Vector3(0f, 0f, 0.2f)).AddComponent(), (LightType)2, new Color(1f, 0.73f, 0.35f), 5f, 0.65f); } GameObject obj3 = Child(visual, "vr_tail_lamp", new Vector3(0f, 0.67f, -1.22f)); Cube(obj3.transform, "tail_case", Vector3.zero, new Vector3(0.23f, 0.2f, 0.11f), Quaternion.identity, metal, collider: false); Cube(obj3.transform, "vr_lamp_lens", new Vector3(0f, 0f, -0.065f), new Vector3(0.16f, 0.13f, 0.025f), Quaternion.identity, LampGlass(new Color(1f, 0.12f, 0.035f)), collider: false); AddLampSwitch(obj3, new Vector3(0f, 0f, -0.015f), new Vector3(0.25f, 0.23f, 0.15f)); ConfigureLamp(Child(obj3.transform, "vr_lamp_marker", new Vector3(0f, 0f, -0.14f)).AddComponent(), (LightType)2, new Color(1f, 0.16f, 0.045f), 3f, 0.65f); } private static void AddLampSwitch(GameObject lamp, Vector3 center, Vector3 size) { //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) BoxCollider obj = lamp.AddComponent(); obj.center = center; obj.size = size; lamp.AddComponent(); } private static void ConfigureLamp(Light lamp, LightType type, Color color, float range, float intensity) { //IL_0001: 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) lamp.type = type; lamp.color = color; lamp.range = range; lamp.intensity = intensity; lamp.shadows = (LightShadows)0; lamp.renderMode = (LightRenderMode)1; ((Behaviour)lamp).enabled = false; } private static Material LampGlass(Color color) { //IL_000a: 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_0062: Unknown result type (might be due to invalid IL or missing references) Material val = CopyMaterial(metal, "VikingRail_LampGlass", color); SetSurfaceTexture(val, (Texture)(object)Texture2D.whiteTexture); if (val.HasProperty("_EmissionMap")) { val.SetTexture("_EmissionMap", (Texture)(object)Texture2D.whiteTexture); } if (val.HasProperty("_EmissionColor")) { val.EnableKeyword("_EMISSION"); val.SetColor("_EmissionColor", color * 1.8f); } return val; } private static void CreateLongTracks(GameObject floor) { //IL_0062: 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_0078: 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_00a5: 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_00b4: 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_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_00f0: 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_011d: 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_012c: Unknown result type (might be due to invalid IL or missing references) Vector3[] array = Array.ConvertAll(RailLongTracks.StraightPoints(), RailSegment.ToUnity); Vector3[] array2 = Array.ConvertAll(RailLongTracks.InclinePoints(), RailSegment.ToUnity); CreateTrack(floor, "vr_track_straight_long", "Rail track — long straight", "12 m metal rail section with Fine Wood sleepers, three times the standard length. Snap the ends to regular or long rails. Support elevated sections with beams or a bridge.", array, RailSectionKind.Normal, lightDuty: false, null, (array[0] + array[1]) * 0.5f); CreateTrack(floor, "vr_track_slope_long", "Rail track — long incline", "Rises 3 m over 12 m, three times the standard incline at the same grade. Uses Fine Wood sleepers. Snap the ends to regular or long rails. Support elevated sections with beams or a bridge.", array2, RailSectionKind.Normal, lightDuty: false, null, (array2[0] + array2[1]) * 0.5f); CreateTrack(floor, "vr_track_wood_straight_long", "Wooden track — long straight", "12 m Fine Wood rail section, three times the standard length. Snap the ends to regular or long rails. Support elevated sections with beams or a bridge. For handcarts, bronze engines and wagons; coal and Eitr engines require metal rails.", array, RailSectionKind.Normal, lightDuty: true, null, (array[0] + array[1]) * 0.5f); CreateTrack(floor, "vr_track_wood_slope_long", "Wooden track — long incline", "Rises 3 m over 12 m, three times the standard incline at the same grade. Built from Fine Wood. Snap the ends to regular or long rails. Support elevated sections with beams or a bridge. For handcarts, bronze engines and wagons; coal and Eitr engines require metal rails.", array2, RailSectionKind.Normal, lightDuty: true, null, (array2[0] + array2[1]) * 0.5f); } private static void CreateSolidMaterials(GameObject floor) { //IL_0068: 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_00d0: 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) Material val = FindMaterial(floor, "wood"); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.shader)) { throw new InvalidOperationException("The native building shader is unavailable for railway materials."); } Texture2D texture = CreateSurfaceTexture("VikingRail_WoodGrain", timber: true); Texture2D texture2 = CreateSurfaceTexture("VikingRail_MetalGrain", timber: false); wood = SolidMaterial(val.shader, "VikingRail_Wood", (Texture)(object)texture, new Color(0.55f, 0.36f, 0.2f), 0f, 0.16f); metal = SolidMaterial(val.shader, "VikingRail_Metal", (Texture)(object)texture2, new Color(0.38f, 0.39f, 0.4f), 0.6f, 0.28f); brass = SolidMaterial(val.shader, "VikingRail_Brass", (Texture)(object)texture2, new Color(0.85f, 0.62f, 0.22f), 0.55f, 0.34f); red = SolidMaterial(val.shader, "VikingRail_StopRed", (Texture)(object)texture, new Color(0.85f, 0.11f, 0.06f), 0f, 0.16f); } private static Material SolidMaterial(Shader shader, string name, Texture texture, Color tint, float metallic, float smoothness) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown //IL_0021: 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) Material val = new Material(shader) { name = name }; Materials.Add(val); SetSurfaceTexture(val, texture); SetSolidTint(val, tint); SetMaterialFloat(val, "_Metallic", metallic); SetMaterialFloat(val, "_Glossiness", smoothness); SetMaterialFloat(val, "_Smoothness", smoothness); SetMaterialFloat(val, "_MetallicAlphaGloss", smoothness); if (val.HasProperty("_MetallicTex")) { val.SetTexture("_MetallicTex", (Texture)(object)Texture2D.whiteTexture); } if (val.HasProperty("_MetalColor")) { val.SetColor("_MetalColor", tint); } SetMaterialFloat(val, "_ValueNoise", 0f); SetMaterialFloat(val, "_RippleDistance", 0f); SetMaterialFloat(val, "_TriplanarMap", 0f); if (val.HasProperty("_MoveableObject")) { val.SetFloat("_MoveableObject", 1f); val.EnableKeyword("_MOVEABLEOBJECT_ON"); } SetOpaqueSurface(val); return val; } private static Texture2D CreateSurfaceTexture(string name, bool timber) { //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_0013: 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_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(64, 64, (TextureFormat)4, true, false) { name = name, wrapMode = (TextureWrapMode)0, filterMode = (FilterMode)1, anisoLevel = 2 }; SurfaceTextures.Add(val); Color32[] array = (Color32[])(object)new Color32[4096]; for (int i = 0; i < 64; i++) { for (int j = 0; j < 64; j++) { float num = ((float)j + 0.5f) / 64f; float num2 = ((float)i + 0.5f) / 64f; uint num3 = (uint)((j + i * 64 + 1) * 747796405 + -1403630843); num3 = ((num3 >> 16) ^ num3) * 2246822519u; float num4 = (float)(num3 & 0xFF) / 255f - 0.5f; byte b = (byte)Mathf.RoundToInt(Mathf.Clamp01(timber ? (0.84f + 0.09f * Mathf.Sin((float)Math.PI * 2f * (5f * num + 0.05f * Mathf.Sin((float)Math.PI * 2f * num2))) + 0.035f * Mathf.Sin((float)Math.PI * 2f * (17f * num + 0.08f * Mathf.Sin((float)Math.PI * 4f * num2))) + num4 * 0.035f) : (0.93f + num4 * 0.08f)) * 255f); array[i * 64 + j] = new Color32(b, b, b, byte.MaxValue); } } val.SetPixels32(array); val.Apply(true, true); return val; } private static void SetSurfaceTexture(Material material, Texture texture) { //IL_0032: 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) string[] array = new string[2] { "_MainTex", "_BaseMap" }; foreach (string text in array) { if (material.HasProperty(text)) { material.SetTexture(text, texture); material.SetTextureScale(text, Vector2.one); material.SetTextureOffset(text, Vector2.zero); } } } private static void SetSolidTint(Material material, Color color) { //IL_001f: 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) color.a = 1f; if (material.HasProperty("_Color")) { material.SetColor("_Color", color); } if (material.HasProperty("_BaseColor")) { material.SetColor("_BaseColor", color); } } private static void SetOpaqueSurface(Material material) { material.DisableKeyword("_ALPHATEST_ON"); material.DisableKeyword("_ALPHABLEND_ON"); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); SetMaterialFloat(material, "_Mode", 0f); SetMaterialFloat(material, "_Surface", 0f); SetMaterialFloat(material, "_AlphaClip", 0f); SetMaterialFloat(material, "_Cutoff", 0f); SetMaterialFloat(material, "_AlphaToMask", 0f); SetMaterialFloat(material, "_SrcBlend", 1f); SetMaterialFloat(material, "_DstBlend", 0f); SetMaterialFloat(material, "_ZWrite", 1f); material.SetOverrideTag("RenderType", "Opaque"); material.renderQueue = 2000; } private static void SetMaterialFloat(Material material, string property, float value) { if (material.HasProperty(property)) { material.SetFloat(property, value); } } private static void CleanupSurfaceTextures() { foreach (Texture2D surfaceTexture in SurfaceTextures) { if (Object.op_Implicit((Object)(object)surfaceTexture)) { Object.Destroy((Object)(object)surfaceTexture); } } SurfaceTextures.Clear(); } private static void CreateMountCart(GameObject cart, GameObject floor) { //IL_002e: 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_005e: Expected O, but got Unknown //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_0085: 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_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_0118: 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_017d: 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) GameObject val = CloneBase(cart, "vr_mount_cart", keepContainer: false, floor); ConfigurePiece(val.GetComponent(), "Rail mounting cart", "An open rail cart with two mounting plates for compatible defenders and compact utilities. Park before mounting equipment. Alternate-use to couple or uncouple."); GameObject val2 = Child(val.transform, "visual", Vector3.zero); AddWorkshopChassis(val2.transform); foreach (Transform item in val2.transform) { Transform val3 = item; if (!(((Object)val3).name != "deck_plank")) { Vector3 localScale = val3.localScale; localScale.z = 2.4f; val3.localScale = localScale; } } for (int i = -1; i <= 1; i += 2) { Cube(val2.transform, "mount_deck_edge", new Vector3((float)i * 0.79f, 0.878f, 0f), new Vector3(0.045f, 0.035f, 2.36f), Quaternion.identity, metal, collider: false); Cube(val2.transform, "mount_end_band", new Vector3(0f, 0.878f, (float)i * 1.16f), new Vector3(1.59f, 0.035f, 0.055f), Quaternion.identity, brass, collider: false); } for (int j = 0; j < 2; j++) { AddMountingPlate(val.transform, val2.transform, j, new Vector3(0f, 0.92f, (j == 0) ? (-0.56f) : 0.56f)); } Rigidbody obj = val.GetComponent() ?? val.AddComponent(); obj.isKinematic = true; obj.useGravity = false; obj.mass = 160f; ZSyncTransform obj2 = val.GetComponent() ?? val.AddComponent(); obj2.m_syncPosition = true; obj2.m_syncRotation = true; obj2.m_syncScale = false; obj2.m_syncBodyVelocity = false; obj2.m_characterParentSync = false; val.GetComponent().m_type = (ObjectType)0; RailVehicle railVehicle = val.AddComponent(); railVehicle.IsEngine = false; railVehicle.CoalPowered = false; val.AddComponent(); RailBuildMenu.ConfigureTransportPiece(val.GetComponent()); ConfigureWear(val, val2, track: false); AddVehicleLights(val, val2.transform, engine: false); AddPackingHandle(val2.transform); AddPushHandle(val2.transform); if (Object.op_Implicit((Object)(object)val.GetComponentInChildren(true)) || Object.op_Implicit((Object)(object)val.GetComponentInChildren(true)) || Object.op_Implicit((Object)(object)val.GetComponentInChildren(true))) { throw new InvalidOperationException("The mounting cart retained an unrelated station or container."); } ZNetView[] componentsInChildren = val.GetComponentsInChildren(true); for (int k = 0; k < componentsInChildren.Length; k++) { if ((Object)(object)((Component)componentsInChildren[k]).gameObject != (Object)(object)val) { throw new InvalidOperationException("The mounting cart retained a nested network view."); } } Prefabs.Add(val); } private static void AddMountingPlate(Transform vehicle, Transform visual, int index, Vector3 position) { //IL_0012: 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_0047: 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_008f: 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_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0124: 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_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0173: 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_018c: 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_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) GameObject obj = Child(vehicle, "vr_mount_socket_" + index, position); BoxCollider obj2 = obj.AddComponent(); obj2.center = new Vector3(0f, -0.03f, 0f); obj2.size = new Vector3(1.22f, 0.06f, 0.94f); obj.AddComponent().Slot = index; GameObject val = Child(visual, "vr_mount_plate_" + index, position); Cube(val.transform, "mount_plate", new Vector3(0f, -0.03f, 0f), new Vector3(1.22f, 0.06f, 0.94f), Quaternion.identity, metal, collider: false); for (int i = -1; i <= 1; i += 2) { Cube(val.transform, "mount_plate_border", new Vector3((float)i * 0.58f, 0.006f, 0f), new Vector3(0.035f, 0.012f, 0.9f), Quaternion.identity, brass, collider: false); Cube(val.transform, "mount_plate_border", new Vector3(0f, 0.006f, (float)i * 0.43f), new Vector3(1.16f, 0.012f, 0.035f), Quaternion.identity, brass, collider: false); for (int j = -1; j <= 1; j += 2) { Primitive(val.transform, "mount_plate_bolt", (PrimitiveType)2, new Vector3((float)i * 0.51f, 0.012f, (float)j * 0.36f), new Vector3(0.075f, 0.012f, 0.075f), Quaternion.identity, brass, collider: false); } } for (int k = 0; k < 12; k++) { float num = (float)k * 30f; float num2 = num * ((float)Math.PI / 180f); Cube(val.transform, "mount_socket_ring", new Vector3(Mathf.Sin(num2) * 0.2f, 0.009f, Mathf.Cos(num2) * 0.2f), new Vector3(0.108f, 0.018f, 0.028f), Quaternion.Euler(0f, num, 0f), brass, collider: false); } for (int l = 0; l <= index; l++) { Cube(val.transform, "mount_socket_mark", new Vector3(((float)l - (float)index * 0.5f) * 0.07f, 0.009f, 0f), new Vector3(0.025f, 0.018f, 0.17f), Quaternion.identity, brass, collider: false); } } private static void CreateMusicCart(ZNetScene scene, GameObject cart, GameObject floor) { //IL_002e: 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: Expected O, but got Unknown //IL_0085: 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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: 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_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) GameObject val = CloneBase(cart, "vr_music_cart", keepContainer: false, floor); ConfigurePiece(val.GetComponent(), "Techno Viking sound cart", "A towable Viking sound system with bronze horns, rune turntables and a dancing wooden figure. Use the console to play or stop and the brass dial to change volume; edit the front banner while parked. Couple with a pumpkin carriage for Halloween techno. Alternate-use the console to couple or uncouple."); GameObject val2 = Child(val.transform, "visual", Vector3.zero); AddWorkshopChassis(val2.transform); foreach (Transform item in val2.transform) { Transform val3 = item; if (((Object)val3).name == "deck_plank") { val3.localScale = new Vector3(0.32f, 0.24f, 2.4f); } } Material dark = CopyMaterial(metal, "VikingRail_MusicDark", (Color?)new Color(0.12f, 0.15f, 0.16f)); Material hide = CopyMaterial(wood, "VikingRail_MusicCanopy", (Color?)new Color(0.63f, 0.49f, 0.3f)); Material skin = CopyMaterial(wood, "VikingRail_MusicCarving", (Color?)new Color(0.76f, 0.57f, 0.36f)); Material val4 = CopyMaterial(brass, "VikingRail_MusicRune", (Color?)new Color(0.12f, 0.84f, 0.72f)); if (val4.HasProperty("_EmissionMap")) { val4.SetTexture("_EmissionMap", (Texture)(object)Texture2D.whiteTexture); } if (val4.HasProperty("_EmissionColor")) { val4.EnableKeyword("_EMISSION"); val4.SetColor("_EmissionColor", new Color(0.12f, 0.48f, 0.65f) * 0.65f); } AddMusicCanopy(val2.transform, hide); for (int i = -1; i <= 1; i += 2) { AddMusicHorn(val2.transform, new Vector3((float)i * 0.49f, 1.55f, 0.63f), dark); } AddMusicConsole(val2.transform, dark, val4); AddMusicVolumeDial(val2.transform, new Vector3(0.38f, 1.11f, 0.4f)); AddMusicDancer(val2.transform, skin, dark); Rigidbody obj = val.GetComponent() ?? val.AddComponent(); obj.isKinematic = true; obj.useGravity = false; obj.mass = 100f; ZSyncTransform obj2 = val.GetComponent() ?? val.AddComponent(); obj2.m_syncPosition = true; obj2.m_syncRotation = true; obj2.m_syncScale = false; obj2.m_syncBodyVelocity = false; obj2.m_characterParentSync = false; val.GetComponent().m_type = (ObjectType)0; RailVehicle railVehicle = val.AddComponent(); railVehicle.IsEngine = false; railVehicle.CoalPowered = false; val.AddComponent(); AddMusicBanner(scene, val, val2.transform); RailBuildMenu.ConfigureTransportPiece(val.GetComponent()); ConfigureWear(val, val2, track: false); AddVehicleLights(val, val2.transform, engine: false); AddPackingHandle(val2.transform); AddPushHandle(val2.transform); if (Object.op_Implicit((Object)(object)val.GetComponentInChildren(true)) || Object.op_Implicit((Object)(object)val.GetComponentInChildren(true)) || Object.op_Implicit((Object)(object)val.GetComponentInChildren(true))) { throw new InvalidOperationException("The music cart retained an unrelated station or container."); } ZNetView[] componentsInChildren = val.GetComponentsInChildren(true); for (int j = 0; j < componentsInChildren.Length; j++) { if ((Object)(object)((Component)componentsInChildren[j]).gameObject != (Object)(object)val) { throw new InvalidOperationException("The music cart retained a nested network view."); } } Prefabs.Add(val); } private static void AddMusicCanopy(Transform visual, Material hide) { //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0161: 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_0026: 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_0070: 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_00b2: 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_00de: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) for (int i = -1; i <= 1; i += 2) { for (int j = -1; j <= 1; j += 2) { Cube(visual, "music_canopy_post", new Vector3((float)i * 0.73f, 1.65f, (float)j * 0.98f), new Vector3(0.07f, 1.58f, 0.07f), Quaternion.identity, wood); } Cube(visual, "music_canopy_rail", new Vector3((float)i * 0.76f, 2.41f, 0f), new Vector3(0.075f, 0.1f, 2.36f), Quaternion.identity, wood); Cube(visual, "music_canopy", new Vector3((float)i * 0.41f, 2.53f, 0f), new Vector3(0.85f, 0.055f, 2.4f), Quaternion.Euler(0f, 0f, (float)(-i) * 10f), hide); Cube(visual, "music_canopy_end", new Vector3(0f, 2.43f, (float)i * 1.13f), new Vector3(1.58f, 0.075f, 0.075f), Quaternion.identity, brass, collider: false); } Cube(visual, "music_canopy_ridge", new Vector3(0f, 2.61f, 0f), new Vector3(0.085f, 0.07f, 2.4f), Quaternion.identity, wood, collider: false); } private static void AddMusicHorn(Transform visual, Vector3 center, Material dark) { //IL_0006: 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_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_006b: 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_0084: 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_00d8: 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_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0148: 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_0184: 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) GameObject val = Child(visual, "music_horn", center); Cube(val.transform, "speaker_cabinet", new Vector3(0f, -0.22f, -0.08f), new Vector3(0.43f, 0.9f, 0.45f), Quaternion.identity, wood); Cube(val.transform, "speaker_band", new Vector3(0f, -0.62f, -0.08f), new Vector3(0.455f, 0.075f, 0.47f), Quaternion.identity, brass, collider: false); for (int i = 0; i < 5; i++) { float num = 0.25f + (float)i * 0.06f; Primitive(val.transform, "bronze_horn_flare", (PrimitiveType)2, new Vector3(0f, 0f, 0.03f + (float)i * 0.045f), new Vector3(num, 0.027f, num), Quaternion.Euler(90f, 0f, 0f), brass, collider: false); } Primitive(val.transform, "horn_dark_mouth", (PrimitiveType)2, new Vector3(0f, 0f, 0.243f), new Vector3(0.405f, 0.007f, 0.405f), Quaternion.Euler(90f, 0f, 0f), dark, collider: false); Primitive(val.transform, "horn_center", (PrimitiveType)0, new Vector3(0f, 0f, 0.259f), new Vector3(0.11f, 0.11f, 0.065f), Quaternion.identity, brass, collider: false); } private static void AddMusicConsole(Transform visual, Material dark, Material rune) { //IL_0015: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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) //IL_00aa: 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_022c: 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_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0283: 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_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: 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_0113: 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_0158: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Unknown result type (might be due to invalid IL or missing references) //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_0373: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Unknown result type (might be due to invalid IL or missing references) GameObject obj = Child(visual, "vr_music_console", new Vector3(0f, 1.12f, 0.03f)); Cube(obj.transform, "console_body", Vector3.zero, new Vector3(1.04f, 0.48f, 0.48f), Quaternion.identity, wood, collider: false); Cube(obj.transform, "console_face", new Vector3(0f, 0.255f, 0f), new Vector3(1.11f, 0.045f, 0.54f), Quaternion.identity, dark, collider: false); BoxCollider obj2 = obj.AddComponent(); obj2.center = new Vector3(0f, 0.02f, 0f); obj2.size = new Vector3(1.11f, 0.54f, 0.54f); obj.AddComponent(); for (int i = -1; i <= 1; i += 2) { GameObject obj3 = Child(visual, (i < 0) ? "vr_music_disc_left" : "vr_music_disc_right", new Vector3((float)i * 0.28f, 1.414f, 0.03f)); Primitive(obj3.transform, "rune_disc", (PrimitiveType)2, Vector3.zero, new Vector3(0.35f, 0.011f, 0.35f), Quaternion.identity, brass, collider: false); Primitive(obj3.transform, "disc_inset", (PrimitiveType)2, new Vector3(0f, 0.012f, 0f), new Vector3(0.285f, 0.006f, 0.285f), Quaternion.identity, dark, collider: false); Cube(obj3.transform, "disc_rune", new Vector3(0f, 0.02f, 0.055f), new Vector3(0.025f, 0.012f, 0.13f), Quaternion.identity, rune, collider: false); Cube(obj3.transform, "disc_rune", new Vector3(0.035f, 0.021f, 0.06f), new Vector3(0.07f, 0.012f, 0.025f), Quaternion.Euler(0f, 35f, 0f), rune, collider: false); } GameObject obj4 = Child(visual, "vr_music_lever", new Vector3(0.48f, 1.41f, -0.13f)); obj4.transform.localRotation = Quaternion.Euler(0f, 0f, -18f); Cube(obj4.transform, "music_switch_stem", new Vector3(0f, 0.07f, 0f), new Vector3(0.025f, 0.14f, 0.025f), Quaternion.identity, brass, collider: false); Primitive(obj4.transform, "music_switch_grip", (PrimitiveType)0, new Vector3(0f, 0.15f, 0f), Vector3.one * 0.075f, Quaternion.identity, red, collider: false); GameObject val = Child(visual, "vr_music_runes", new Vector3(0f, 1.13f, 0.278f)); for (int j = -1; j <= 1; j += 2) { Cube(val.transform, "console_rune", new Vector3((float)j * 0.15f, 0f, 0f), new Vector3(0.025f, 0.18f, 0.015f), Quaternion.identity, rune, collider: false); Cube(val.transform, "console_rune", new Vector3((float)j * 0.11f, 0.035f, 0f), new Vector3(0.11f, 0.025f, 0.015f), Quaternion.Euler(0f, 0f, (float)j * 40f), rune, collider: false); } } private static void AddMusicDancer(Transform visual, Material skin, Material dark) { //IL_0015: 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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_009b: 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_00e9: 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_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: 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_017d: 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_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: 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_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_031f: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_0382: Unknown result type (might be due to invalid IL or missing references) //IL_0396: Unknown result type (might be due to invalid IL or missing references) //IL_03aa: Unknown result type (might be due to invalid IL or missing references) GameObject val = Child(visual, "vr_music_dancer", new Vector3(0f, 0.87f, -0.6f)); for (int i = -1; i <= 1; i += 2) { Cube(val.transform, "dancer_boot", new Vector3((float)i * 0.135f, 0.08f, 0.025f), new Vector3(0.16f, 0.16f, 0.27f), Quaternion.identity, dark, collider: false); Cube(val.transform, "dancer_leg", new Vector3((float)i * 0.135f, 0.33f, 0f), new Vector3(0.13f, 0.43f, 0.15f), Quaternion.Euler(0f, 0f, (float)(-i) * 4f), wood, collider: false); } Cube(val.transform, "dancer_hips", new Vector3(0f, 0.57f, 0f), new Vector3(0.36f, 0.15f, 0.2f), Quaternion.identity, dark, collider: false); Cube(val.transform, "dancer_torso", new Vector3(0f, 0.85f, 0f), new Vector3(0.43f, 0.42f, 0.24f), Quaternion.identity, skin, collider: false); Cube(val.transform, "dancer_belt", new Vector3(0f, 0.64f, 0f), new Vector3(0.44f, 0.055f, 0.26f), Quaternion.identity, brass, collider: false); Primitive(val.transform, "dancer_head", (PrimitiveType)0, new Vector3(0f, 1.21f, 0f), new Vector3(0.28f, 0.31f, 0.26f), Quaternion.identity, skin, collider: false); Primitive(val.transform, "dancer_beard", (PrimitiveType)0, new Vector3(0f, 1.1f, 0.1f), new Vector3(0.22f, 0.27f, 0.13f), Quaternion.identity, wood, collider: false); Primitive(val.transform, "dancer_helmet", (PrimitiveType)0, new Vector3(0f, 1.35f, -0.01f), new Vector3(0.33f, 0.18f, 0.29f), Quaternion.identity, metal, collider: false); Cube(val.transform, "dancer_helmet_band", new Vector3(0f, 1.32f, 0.12f), new Vector3(0.29f, 0.055f, 0.025f), Quaternion.identity, brass, collider: false); GameObject obj = Child(val.transform, "vr_music_point_arm", new Vector3(0.25f, 0.98f, 0f)); Cube(obj.transform, "dancer_point_arm", new Vector3(0f, -0.025f, 0.22f), new Vector3(0.12f, 0.13f, 0.5f), Quaternion.identity, skin, collider: false); Cube(obj.transform, "dancer_point_hand", new Vector3(0f, -0.025f, 0.52f), new Vector3(0.095f, 0.095f, 0.16f), Quaternion.identity, skin, collider: false); Cube(Child(val.transform, "vr_music_left_arm", new Vector3(-0.25f, 0.98f, 0f)).transform, "dancer_left_arm", new Vector3(-0.03f, -0.2f, 0.04f), new Vector3(0.12f, 0.46f, 0.13f), Quaternion.Euler(-12f, 0f, -8f), skin, collider: false); } private static void AddMusicBanner(ZNetScene scene, GameObject prefab, Transform visual) { //IL_004d: 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_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_00a2: 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_00de: Expected O, but got Unknown //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: 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_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) GameObject prefab2 = scene.GetPrefab("sign"); Sign val = ((prefab2 != null) ? prefab2.GetComponent() : null); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.m_textWidget)) { throw new InvalidOperationException("The native sign text widget is required for the music-cart banner."); } GameObject val2 = Child(visual, "vr_music_banner", new Vector3(0f, 2.26f, 1.16f)); Cube(val2.transform, "music_banner_board", Vector3.zero, new Vector3(1.35f, 0.27f, 0.055f), Quaternion.identity, wood, collider: false); val2.AddComponent().size = new Vector3(1.35f, 0.27f, 0.065f); val2.AddComponent(); GameObject val3 = new GameObject("music_banner_canvas", new Type[2] { typeof(RectTransform), typeof(Canvas) }); val3.transform.SetParent(val2.transform, false); val3.layer = ((Component)val.m_textWidget).gameObject.layer; val3.GetComponent().renderMode = (RenderMode)2; val3.transform.localPosition = new Vector3(0f, 0f, 0.036f); val3.transform.localRotation = Quaternion.Euler(0f, 180f, 0f); val3.transform.localScale = Vector3.one * 0.002f; ((RectTransform)val3.transform).sizeDelta = new Vector2(640f, 112f); TextMeshProUGUI val4 = Object.Instantiate(val.m_textWidget, val3.transform, false); ((Object)val4).name = "music_banner_text"; RectTransform rectTransform = ((TMP_Text)val4).rectTransform; rectTransform.anchorMin = Vector2.zero; rectTransform.anchorMax = Vector2.one; rectTransform.offsetMin = Vector2.zero; rectTransform.offsetMax = Vector2.zero; ((Transform)rectTransform).localPosition = Vector3.zero; ((Transform)rectTransform).localRotation = Quaternion.identity; ((Transform)rectTransform).localScale = Vector3.one; ((TMP_Text)val4).alignment = (TextAlignmentOptions)514; ((TMP_Text)val4).enableAutoSizing = true; ((TMP_Text)val4).fontSizeMin = 12f; ((TMP_Text)val4).fontSizeMax = 42f; ((Graphic)val4).raycastTarget = false; ((TMP_Text)val4).text = "Techno Viking Express"; Sign val5 = prefab.AddComponent(); CopyFields((Component)(object)val, (Component)(object)val5); val5.m_name = "Sound cart banner"; val5.m_defaultText = "Techno Viking Express"; val5.m_characterLimit = 50; val5.m_textWidget = val4; } private static void AddMusicVolumeDial(Transform visual, Vector3 position) { //IL_0006: 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_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_005c: 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_0086: 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_00c4: 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_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_013d: 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_0183: 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) GameObject val = Child(visual, "vr_music_volume", position); Cube(val.transform, "volume_dial_plate", new Vector3(0f, 0f, -0.035f), new Vector3(0.23f, 0.24f, 0.045f), Quaternion.identity, metal, collider: false); GameObject obj = Child(val.transform, "knob", Vector3.zero); Primitive(obj.transform, "volume_knob", (PrimitiveType)2, Vector3.zero, new Vector3(0.16f, 0.035f, 0.16f), Quaternion.Euler(90f, 0f, 0f), brass, collider: false); Cube(obj.transform, "volume_pointer", new Vector3(0f, 0.045f, 0.038f), new Vector3(0.018f, 0.058f, 0.012f), Quaternion.identity, wood, collider: false); for (int i = 0; i < 5; i++) { float num = (float)(i * 60 - 120) * ((float)Math.PI / 180f); Cube(val.transform, "volume_scale", new Vector3(Mathf.Sin(num) * 0.094f, Mathf.Cos(num) * 0.094f, -0.005f), new Vector3(0.012f, 0.023f, 0.008f), Quaternion.Euler(0f, 0f, (0f - num) * 57.29578f), brass, collider: false); } BoxCollider obj2 = val.AddComponent(); obj2.center = new Vector3(0f, 0f, 0.018f); obj2.size = new Vector3(0.24f, 0.25f, 0.12f); val.AddComponent(); } private static void AddPackingHandle(Transform visual) { //IL_0015: 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_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_0085: 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_009e: 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_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: 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_012a: Unknown result type (might be due to invalid IL or missing references) GameObject val = Child(visual, "vr_packing_handle", new Vector3(-0.9f, 0.96f, -0.65f)); Cube(val.transform, "handle_back", new Vector3(0.04f, 0f, 0f), new Vector3(0.06f, 0.25f, 0.32f), Quaternion.identity, wood, collider: false); for (int i = -1; i <= 1; i += 2) { Cube(val.transform, "handle_bracket", new Vector3(-0.015f, 0f, (float)i * 0.12f), new Vector3(0.13f, 0.055f, 0.06f), Quaternion.identity, brass, collider: false); } Cube(val.transform, "handle_grip", new Vector3(-0.07f, 0f, 0f), new Vector3(0.06f, 0.065f, 0.28f), Quaternion.identity, brass, collider: false); BoxCollider obj = val.AddComponent(); obj.center = new Vector3(-0.01f, 0f, 0f); obj.size = new Vector3(0.19f, 0.27f, 0.35f); val.AddComponent(); SetLayer(val, LayerMask.NameToLayer("piece")); } private static void CreateParallelYardSwitches(GameObject floor) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: 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_01f2: 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_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) foreach (RailParallelYardTrackDefinition item in RailParallelYardTracks.All) { GameObject val = CloneBase(floor, item.PrefabName, keepContainer: false, floor); ConfigurePiece(val.GetComponent(), (item.LightDuty ? "Wooden track" : "Rail track") + " — " + item.ExitCount + "-way parallel yard splitter", "One entrance fans into " + item.ExitCount + " parallel exits spaced 4 m apart. Use the numbered lever to cycle lanes from left to right; clear the entire junction and its approaches first. Connect straight rails to make sorting sidings; detached wagons do not roll downhill by themselves." + (item.LightDuty ? " Handcarts, bronze engines and wagons only; coal and Eitr require iron rails." : "")); GameObject val2 = Child(val.transform, "visual", Vector3.zero); Vector3[] array = Array.ConvertAll(item.TrunkPoints(), RailSegment.ToUnity); Vector3[][] array2 = new Vector3[item.ExitCount][]; for (int i = 0; i < array2.Length; i++) { array2[i] = Array.ConvertAll(item.BranchPoints(i), RailSegment.ToUnity); } Material railMaterial = (item.LightDuty ? wood : metal); AddSwitchRails(val2.transform, array, railMaterial); Vector3[][] array3 = array2; foreach (Vector3[] points in array3) { AddSwitchRails(val2.transform, points, railMaterial); } AddParallelYardSleepers(val2.transform, array, array2, item.LightDuty); HideDuplicateYardRails(val2.transform); AddSnap(val.transform, "snap_start", array[0]); int num = array2.Length / 2; AddSnap(val.transform, "snap_left", array2[num - 1][array2[num - 1].Length - 1]); AddSnap(val.transform, "snap_straight", array2[num][array2[num].Length - 1]); AddSnap(val.transform, "snap_right", array2[num + 1][array2[num + 1].Length - 1]); if (item.ExitCount == 5) { AddSnap(val.transform, "snap_outer_left", array2[0][array2[0].Length - 1]); AddSnap(val.transform, "snap_outer_right", array2[4][array2[4].Length - 1]); } RailSwitch railSwitch = val.AddComponent(); railSwitch.ParallelExitCount = item.ExitCount; railSwitch.TrunkPoints = array; railSwitch.LeftPoints = array2[num - 1]; railSwitch.StraightPoints = array2[num]; railSwitch.RightPoints = array2[num + 1]; if (item.ExitCount == 5) { railSwitch.OuterLeftPoints = array2[0]; railSwitch.OuterRightPoints = array2[4]; } railSwitch.LightDuty = item.LightDuty; GameObject obj = Child(val2.transform, "yard_control", array[^1] + Vector3.left * 0.5f); AddSwitchLever(obj.transform, railSwitch); AddParallelYardIndex(obj.transform, item.ExitCount, item.LightDuty); ConfigureWear(val, val2, track: true); RailTerrainPlacement.Configure(val); RailTrackSupport.Configure(val); Prefabs.Add(val); } } private static void AddParallelYardSleepers(Transform parent, Vector3[] trunk, Vector3[][] branches, bool lightDuty) { //IL_0026: 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_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: 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_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_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_00f8: 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_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0159: 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_016d: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0243: 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_0261: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) for (float num = trunk[0].z + 0.25f; num < trunk[^1].z; num += 0.5f) { Cube(parent, "sleeper", new Vector3(0f, 0.02f, num), new Vector3(1.9f, 0.12f, 0.2f), Quaternion.identity, wood); if (lightDuty) { AddSwitchNails(parent, trunk, num); } } for (float num2 = branches[0][0].z + 0.25f; num2 < branches[0][branches[0].Length - 1].z; num2 += 0.5f) { List list = new List(); foreach (Vector3[] array in branches) { int j; for (j = 1; j < array.Length - 1 && array[j].z < num2; j++) { } Vector3 val = array[j] - array[j - 1]; Vector3 normalized = ((Vector3)(ref val)).normalized; Vector3 val2 = Vector3.Lerp(array[j - 1], array[j], (num2 - array[j - 1].z) / (array[j].z - array[j - 1].z)); float num3 = 0.95f / Mathf.Max(0.4f, normalized.z); list.Add(new Vector2(val2.x - num3, val2.x + num3)); if (lightDuty) { AddSwitchNails(parent, array, num2); } } list.Sort((Vector2 a, Vector2 b) => a.x.CompareTo(b.x)); float x = list[0].x; float num4 = list[0].y; for (int num5 = 1; num5 <= list.Count; num5++) { if (num5 < list.Count && list[num5].x <= num4 + 0.02f) { num4 = Mathf.Max(num4, list[num5].y); continue; } Cube(parent, "switch_sleeper", new Vector3((x + num4) * 0.5f, 0.02f, num2), new Vector3(num4 - x, 0.12f, 0.2f), Quaternion.identity, wood); if (num5 < list.Count) { x = list[num5].x; num4 = list[num5].y; } } } } private static void HideDuplicateYardRails(Transform visual) { List list = new List(); Renderer[] componentsInChildren = ((Component)visual).GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if (!(((Object)val).name != "switch_rail")) { Transform rail = ((Component)val).transform; if (list.Exists(delegate(Transform other) { //IL_0001: 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) //IL_0026: 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_0036: 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_004b: 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) Vector3 val2 = other.localPosition - rail.localPosition; if (((Vector3)(ref val2)).sqrMagnitude < 1E-08f) { val2 = other.localScale - rail.localScale; if (((Vector3)(ref val2)).sqrMagnitude < 1E-08f) { return Quaternion.Angle(other.localRotation, rail.localRotation) < 0.001f; } } return false; })) { val.enabled = false; } else { list.Add(rail); } } } } private static void AddParallelYardIndex(Transform parent, int routes, bool lightDuty) { //IL_0015: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_00b7: 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_00d0: 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) Cube(parent, "yard_index_plate", new Vector3(-1.6f, 1.32f, -1.115f), new Vector3(1.13f, 0.5f, 0.065f), Quaternion.identity, lightDuty ? wood : metal, collider: false); Vector3 val = default(Vector3); for (int i = 0; i < routes; i++) { float num = 35f - 70f * (float)i / (float)(routes - 1); float num2 = num * ((float)Math.PI / 180f); ((Vector3)(ref val))..ctor(-1.6f - Mathf.Sin(num2) * 0.79f, 0.72f + Mathf.Cos(num2) * 0.79f, -1.072f); AddYardDigit(parent, i + 1, val); Cube(parent, "yard_index_tick", val + Vector3.down * 0.09f, new Vector3(0.018f, 0.045f, 0.014f), Quaternion.Euler(0f, 0f, num), brass, collider: false); } } private static void AddYardDigit(Transform parent, int digit, Vector3 center) { //IL_00b8: 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_00f4: 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_00f9: Unknown result type (might be due to invalid IL or missing references) string text = digit switch { 4 => "fgbc", 3 => "abgcd", 2 => "abged", 1 => "bc", _ => "afgcd", }; foreach (char c in text) { bool flag = c == 'a' || c == 'g' || c == 'd'; float num = (flag ? 0f : ((c == 'b' || c == 'c') ? 0.027f : (-0.027f))); float num2; switch (c) { default: num2 = -0.024f; break; case 'b': case 'f': num2 = 0.024f; break; case 'g': num2 = 0f; break; case 'd': num2 = -0.048f; break; case 'a': num2 = 0.048f; break; } float num3 = num2; Cube(parent, "yard_index_digit", center + new Vector3(num, num3, 0f), flag ? new Vector3(0.06f, 0.012f, 0.014f) : new Vector3(0.012f, 0.046f, 0.014f), Quaternion.identity, brass, collider: false); } } private static void AddPassengerFire(GameObject prefab) { //IL_00d8: 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_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0141: 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_022a: Expected O, but got Unknown //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Expected O, but got Unknown //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_03e8: Unknown result type (might be due to invalid IL or missing references) //IL_03ed: Unknown result type (might be due to invalid IL or missing references) //IL_03f8: Unknown result type (might be due to invalid IL or missing references) //IL_03fd: Unknown result type (might be due to invalid IL or missing references) //IL_0407: Unknown result type (might be due to invalid IL or missing references) //IL_040c: Unknown result type (might be due to invalid IL or missing references) //IL_04ae: Unknown result type (might be due to invalid IL or missing references) //IL_04fa: Unknown result type (might be due to invalid IL or missing references) //IL_052f: Unknown result type (might be due to invalid IL or missing references) //IL_054a: Unknown result type (might be due to invalid IL or missing references) GameObject val = null; Fireplace val2 = null; RailPassengerFire railPassengerFire = null; RailPassengerHearthInteract railPassengerHearthInteract = null; BoxCollider val3 = null; try { if (!RailPassengerFire.Compatible) { throw new InvalidOperationException("The native fireplace fuel, water or weather APIs are unavailable."); } Transform val4 = prefab.transform.Find("vr_passenger_fire"); GameObject val5 = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab("fire_pit") : null); Fireplace val6 = (Object.op_Implicit((Object)(object)val5) ? val5.GetComponent() : null); if (!Object.op_Implicit((Object)(object)val4) || !Object.op_Implicit((Object)(object)val6) || !Object.op_Implicit((Object)(object)val6.m_fuelItem) || !Object.op_Implicit((Object)(object)val6.m_enabledObject) || !FiniteFireValue(val6.m_secPerFuel) || val6.m_secPerFuel <= 0f) { throw new InvalidOperationException("The native campfire or its fuel and flame configuration is unavailable."); } if (Object.op_Implicit((Object)(object)prefab.GetComponent())) { throw new InvalidOperationException("The passenger cart already has a fireplace."); } val = Child(val4, "vr_passenger_fire_lit", Vector3.zero); GameObject val7 = Object.Instantiate(val5, val.transform, false); ((Object)val7).name = "vr_passenger_native_flame"; val7.transform.localPosition = new Vector3(0f, 0.08f, 0.14f); val7.transform.localRotation = Quaternion.identity; val7.transform.localScale = Vector3.one * 0.35f; val7.SetActive(true); Fireplace component = val7.GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component.m_enabledObject) || !component.m_enabledObject.transform.IsChildOf(val7.transform)) { throw new InvalidOperationException("The native campfire flame does not belong to its prefab."); } val2 = prefab.AddComponent(); CopyFields((Component)(object)component, (Component)(object)val2); component.m_enabledObject.SetActive(true); val2.m_name = "Passenger chiminea"; val2.m_startFuel = 0f; val2.m_maxFuel = 10f; val2.m_infiniteFuel = false; val2.m_canTurnOff = false; val2.m_canRefill = true; val2.m_enabledObject = val; val2.m_fullObject = null; val2.m_halfObject = null; val2.m_emptyObject = null; val2.m_playerBaseObject = null; val2.m_smokeSpawner = null; val2.m_fireworkItemList = Array.Empty(); val2.m_fuelAddedEffects = new EffectList(); val2.m_toggleOnEffects = new EffectList(); val2.m_igniteInterval = 0f; val2.m_igniteChance = 0f; val2.m_igniteCapsuleRadius = 0f; val2.m_firePrefab = null; FieldInfo fieldInfo = AccessTools.Field(typeof(Fireplace), "m_snowMelter"); if (fieldInfo != null) { if (fieldInfo.FieldType != typeof(GameObject)) { throw new InvalidOperationException("The native campfire snow-melting configuration changed."); } fieldInfo.SetValue(val2, null); } float y = prefab.transform.InverseTransformPoint(val4.position).y; val2.m_disableCoverCheck = false; val2.m_checkTerrainOffset = y + 0.2f; val2.m_coverCheckOffset = y + 0.5f; Transform[] componentsInChildren = val7.GetComponentsInChildren(true); Component[] components; foreach (Transform obj in componentsInChildren) { ((Component)obj).gameObject.tag = "Untagged"; components = ((Component)obj).GetComponents(); foreach (Component val8 in components) { if (Object.op_Implicit((Object)(object)val8) && !PassengerFireVisualComponent(val8) && !(val8 is ZNetView)) { Object.DestroyImmediate((Object)(object)val8); } } } ZNetView[] componentsInChildren2 = val7.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } components = val7.GetComponentsInChildren(true); foreach (Component val9 in components) { if (Object.op_Implicit((Object)(object)val9) && !PassengerFireVisualComponent(val9)) { throw new InvalidOperationException("A campfire gameplay component could not be removed: " + ((object)val9).GetType().Name); } } ParticleSystem[] componentsInChildren3 = val7.GetComponentsInChildren(true); foreach (ParticleSystem obj2 in componentsInChildren3) { MainModule main = obj2.main; ((MainModule)(ref main)).scalingMode = (ParticleSystemScalingMode)0; CollisionModule collision = obj2.collision; ((CollisionModule)(ref collision)).enabled = false; TriggerModule trigger = obj2.trigger; ((TriggerModule)(ref trigger)).enabled = false; } AudioSource[] componentsInChildren4 = val7.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren4.Length; i++) { componentsInChildren4[i].dopplerLevel = 0f; } Light[] componentsInChildren5 = val7.GetComponentsInChildren(true); foreach (Light obj3 in componentsInChildren5) { obj3.type = (LightType)2; obj3.range = 3.5f; obj3.intensity = 1.2f; obj3.shadows = (LightShadows)0; obj3.renderMode = (LightRenderMode)1; ((Behaviour)obj3).enabled = true; } GameObject obj4 = Child(val.transform, "vr_passenger_hearth_heat", Vector3.zero); int num = LayerMask.NameToLayer("character_trigger"); if (num < 0) { throw new InvalidOperationException("The native warmth layer is unavailable."); } obj4.layer = num; SphereCollider obj5 = obj4.AddComponent(); obj5.radius = 2.5f; ((Collider)obj5).isTrigger = true; EffectArea obj6 = obj4.AddComponent(); obj6.m_type = (Type)3; obj6.m_statusEffect = ""; obj6.m_playerOnly = true; val3 = ((Component)val4).gameObject.AddComponent(); val3.center = new Vector3(0f, 0.29f, 0.24f); val3.size = new Vector3(0.42f, 0.44f, 0.16f); ((Component)val4).gameObject.layer = LayerMask.NameToLayer("piece"); railPassengerFire = prefab.AddComponent(); railPassengerHearthInteract = ((Component)val4).gameObject.AddComponent(); val.SetActive(false); } catch (Exception ex) { if (Object.op_Implicit((Object)(object)railPassengerHearthInteract)) { Object.DestroyImmediate((Object)(object)railPassengerHearthInteract); } if (Object.op_Implicit((Object)(object)railPassengerFire)) { Object.DestroyImmediate((Object)(object)railPassengerFire); } if (Object.op_Implicit((Object)(object)val3)) { Object.DestroyImmediate((Object)(object)val3); } if (Object.op_Implicit((Object)(object)val2)) { Object.DestroyImmediate((Object)(object)val2); } if (Object.op_Implicit((Object)(object)val)) { Object.DestroyImmediate((Object)(object)val); } RailPlugin.Warn("Passenger cart hearth is unavailable; the cart and its chairs remain usable: " + ex.GetBaseException().Message); } } private static bool FiniteFireValue(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } private static bool PassengerFireVisualComponent(Component component) { if (!(component is Transform) && !(component is ParticleSystem) && !(component is ParticleSystemRenderer) && !(component is Light) && !(component is AudioSource)) { return component is ZSFX; } return true; } private static void CreatePassengerCart(GameObject cart, GameObject floor) { //IL_002e: 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_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_00b2: 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_00cb: 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_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) //IL_0140: 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_0159: Unknown result type (might be due to invalid IL or missing references) //IL_022a: 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_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: 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_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) GameObject val = CloneBase(cart, "vr_passengercart", keepContainer: false, floor); ConfigurePiece(val.GetComponent(), "Rail passenger cart", "Two seats on a longer, wider open deck beneath a raised canvas awning, with a Wood-burning chiminea in front. Use either chair to sit; jump to stand in the open aisle. Alternate-use the cart or a chair to couple or uncouple while empty."); GameObject val2 = Child(val.transform, "visual", Vector3.zero); for (int i = 0; i < 5; i++) { Cube(val2.transform, "deck_plank", new Vector3((float)(i - 2) * 0.44f, 0.74f, 0f), new Vector3(0.435f, 0.24f, 2.7f), Quaternion.identity, wood); } for (int j = -1; j <= 1; j += 2) { Cube(val2.transform, "chassis", new Vector3((float)j * 0.51f, 0.54f, 0f), new Vector3(0.15f, 0.22f, 2.55f), Quaternion.identity, wood); Cube(val2.transform, "coupler", new Vector3(0f, 0.53f, (float)j * 1.18f), new Vector3(0.16f, 0.14f, 0.35f), Quaternion.identity, metal); Cube(val2.transform, "axle", new Vector3(0f, 0.44f, (float)j * 0.82f), new Vector3(1.65f, 0.09f, 0.09f), Quaternion.identity, metal); for (int k = -1; k <= 1; k += 2) { Primitive(val2.transform, "vr_wheel", (PrimitiveType)2, new Vector3((float)k * 0.7f, 0.44f, (float)j * 0.82f), new Vector3(0.56f, 0.075f, 0.56f), Quaternion.Euler(0f, 0f, 90f), metal, collider: false); } } AddPassengerChair(val2.transform, 0, -1); AddPassengerChair(val2.transform, 1, 1); AddPassengerAwning(val2.transform); AddPassengerHearth(val2.transform); Child(val.transform, "vr_passenger_fire", new Vector3(0f, 0.92f, 0.97f)); Rigidbody obj = val.GetComponent() ?? val.AddComponent(); obj.isKinematic = true; obj.useGravity = false; obj.mass = 100f; ZSyncTransform obj2 = val.GetComponent() ?? val.AddComponent(); obj2.m_syncPosition = true; obj2.m_syncRotation = true; obj2.m_syncScale = false; obj2.m_syncBodyVelocity = false; obj2.m_characterParentSync = false; val.GetComponent().m_type = (ObjectType)0; ConfigureWear(val, val2, track: false); RailVehicle railVehicle = val.AddComponent(); railVehicle.IsEngine = false; railVehicle.CoalPowered = false; railVehicle.IsPassengerCart = true; AddVehicleLights(val, val2.transform, engine: false); val2.transform.Find("vr_tail_lamp").localPosition = new Vector3(0.86f, 0.5f, -1.28f); AddPackingHandle(val2.transform); val2.transform.Find("vr_packing_handle").localPosition = new Vector3(-1.16f, 0.96f, -0.65f); AddPushHandle(val2.transform); AddPassengerFire(val); Prefabs.Add(val); } private static void AddPassengerChair(Transform visual, int index, int side) { //IL_002f: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_00bd: 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_00f8: 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_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0153: 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_0186: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_023d: 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_0271: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Unknown result type (might be due to invalid IL or missing references) if (TryAddNativePassengerChair(visual, index, side)) { return; } GameObject val = Child(visual, "vr_passenger_seat_" + index, new Vector3((float)side * 0.43f, 1.23f, -0.8f)); Cube(val.transform, "chair_seat", new Vector3(0f, -0.05f, 0f), new Vector3(0.68f, 0.1f, 0.64f), Quaternion.identity, wood, collider: false); for (int i = -1; i <= 1; i += 2) { for (int j = -1; j <= 1; j += 2) { Cube(val.transform, "chair_leg", new Vector3((float)i * 0.23f, -0.21f, (float)j * 0.21f), new Vector3(0.09f, 0.32f, 0.09f), Quaternion.identity, wood, collider: false); } Cube(val.transform, "chair_back_post", new Vector3((float)i * 0.26f, 0.3f, -0.26f), new Vector3(0.09f, 0.9f, 0.1f), Quaternion.identity, wood, collider: false); Cube(val.transform, "chair_arm", new Vector3((float)i * 0.3f, 0.2f, 0f), new Vector3(0.07f, 0.07f, 0.62f), Quaternion.identity, wood, collider: false); Cube(val.transform, "chair_arm_support", new Vector3((float)i * 0.3f, 0.075f, 0.22f), new Vector3(0.07f, 0.22f, 0.07f), Quaternion.identity, wood, collider: false); Cube(val.transform, "chair_bronze_nail", new Vector3((float)i * 0.26f, 0.55f, -0.197f), new Vector3(0.04f, 0.04f, 0.015f), Quaternion.identity, brass, collider: false); } for (int k = 0; k < 2; k++) { Cube(val.transform, "chair_back_slat", new Vector3(0f, 0.3f + (float)k * 0.25f, -0.26f), new Vector3(0.62f, 0.19f, 0.11f), Quaternion.identity, wood, collider: false); } BoxCollider obj = val.AddComponent(); obj.center = new Vector3(0f, -0.075f, 0f); obj.size = new Vector3(0.7f, 0.25f, 0.68f); RailPassengerSeat railPassengerSeat = val.AddComponent(); railPassengerSeat.SeatIndex = index; railPassengerSeat.AttachPoint = Child(val.transform, "vr_attach", new Vector3(0f, -0.37f, 0f)).transform; railPassengerSeat.DetachOffset = new Vector3((float)side * 0.13f, 0.04f, 0.98f); } private static bool TryAddNativePassengerChair(Transform visual, int index, int side) { //IL_0077: 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_00b1: 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_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_0109: 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_0113: 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_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0277: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02ee: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_040c: Unknown result type (might be due to invalid IL or missing references) //IL_043b: Unknown result type (might be due to invalid IL or missing references) //IL_0447: Unknown result type (might be due to invalid IL or missing references) //IL_045b: Unknown result type (might be due to invalid IL or missing references) //IL_046b: Unknown result type (might be due to invalid IL or missing references) //IL_04a5: Unknown result type (might be due to invalid IL or missing references) //IL_04aa: Unknown result type (might be due to invalid IL or missing references) //IL_04af: Unknown result type (might be due to invalid IL or missing references) //IL_04b3: Unknown result type (might be due to invalid IL or missing references) //IL_04b5: Unknown result type (might be due to invalid IL or missing references) //IL_04ba: Unknown result type (might be due to invalid IL or missing references) GameObject val = null; try { GameObject val2 = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab("piece_chair") : null); if (!Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)val2.GetComponent()) || !Object.op_Implicit((Object)(object)val2.GetComponent().m_attachPoint)) { throw new InvalidOperationException("The native wooden chair or its attachment point is unavailable."); } val = Child(visual, "vr_passenger_seat_" + index, new Vector3((float)side * 0.43f, 0.86f, -0.8f)); GameObject val3 = Object.Instantiate(val2, val.transform, false); ((Object)val3).name = "chair_model"; val3.transform.localPosition = Vector3.zero; val3.transform.localRotation = Quaternion.identity; val3.SetActive(true); Chair component = val3.GetComponent(); Transform attachPoint = component.m_attachPoint; string attachAnimation = (string.IsNullOrEmpty(component.m_attachAnimation) ? "attach_chair" : component.m_attachAnimation); Quaternion val4 = Quaternion.Inverse(val3.transform.rotation) * attachPoint.rotation; val3.transform.localRotation = Quaternion.Inverse(val4); WearNTear component2 = val3.GetComponent(); if (Object.op_Implicit((Object)(object)component2)) { if (Object.op_Implicit((Object)(object)component2.m_worn) && (Object)(object)component2.m_worn != (Object)(object)component2.m_new) { component2.m_worn.SetActive(false); } if (Object.op_Implicit((Object)(object)component2.m_broken) && (Object)(object)component2.m_broken != (Object)(object)component2.m_new) { component2.m_broken.SetActive(false); } if (Object.op_Implicit((Object)(object)component2.m_new)) { component2.m_new.SetActive(true); } if (Object.op_Implicit((Object)(object)component2.m_wet)) { component2.m_wet.SetActive(false); } } if (!TryPassengerChairBounds(val3.transform, val.transform, out var bounds) || ((Bounds)(ref bounds)).size.x < 0.2f || ((Bounds)(ref bounds)).size.x > 0.78f || ((Bounds)(ref bounds)).size.z > 0.7f || ((Bounds)(ref bounds)).size.y > 1.6f) { throw new InvalidOperationException("The native wooden chair does not fit the passenger deck without scaling."); } Transform transform = val3.transform; transform.localPosition += new Vector3(0f - ((Bounds)(ref bounds)).center.x, 0f - ((Bounds)(ref bounds)).min.y, 0f - ((Bounds)(ref bounds)).center.z); float num = Mathf.Clamp((((Bounds)(ref bounds)).size.x + 0.06f) * 0.5f, 0.43f, 0.47f); val.transform.localPosition = new Vector3((float)side * num, 0.86f, -0.8f); Transform transform2 = Child(val.transform, "vr_attach", val.transform.InverseTransformPoint(attachPoint.position)).transform; transform2.localRotation = Quaternion.Inverse(val.transform.rotation) * attachPoint.rotation; Transform[] componentsInChildren = val3.GetComponentsInChildren(true); Component[] components; foreach (Transform obj in componentsInChildren) { ((Component)obj).gameObject.tag = "Untagged"; components = ((Component)obj).GetComponents(); foreach (Component val5 in components) { if (Object.op_Implicit((Object)(object)val5) && !PassengerChairVisualComponent(val5) && !(val5 is ZNetView)) { Object.DestroyImmediate((Object)(object)val5); } } } ZNetView[] componentsInChildren2 = val3.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } components = val3.GetComponentsInChildren(true); foreach (Component val6 in components) { if (Object.op_Implicit((Object)(object)val6) && !PassengerChairVisualComponent(val6)) { throw new InvalidOperationException("A native chair component could not be removed: " + ((object)val6).GetType().Name); } } SetLayer(val, LayerMask.NameToLayer("piece")); BoxCollider obj2 = val.AddComponent(); float num2 = Mathf.Min(((Bounds)(ref bounds)).size.y + 0.02f, 0.55f); obj2.center = new Vector3(0f, num2 * 0.5f, 0f); obj2.size = new Vector3(((Bounds)(ref bounds)).size.x + 0.02f, num2, ((Bounds)(ref bounds)).size.z + 0.02f); RailPassengerSeat railPassengerSeat = val.AddComponent(); railPassengerSeat.SeatIndex = index; railPassengerSeat.AttachPoint = transform2; railPassengerSeat.AttachAnimation = attachAnimation; Vector3 val7 = visual.TransformPoint(new Vector3((float)side * 0.56f, 0.90000004f, 0.18f)); railPassengerSeat.DetachOffset = transform2.InverseTransformPoint(val7); return true; } catch (Exception ex) { if (Object.op_Implicit((Object)(object)val)) { Object.DestroyImmediate((Object)(object)val); } if (!warnedPassengerChairFallback) { warnedPassengerChairFallback = true; RailPlugin.Warn("Using the passenger chair fallback with its attachment at deck height: " + ex.Message); } return false; } } private static void AddPassengerAwning(Transform visual) { //IL_0019: 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_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_008a: 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_00a3: 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_00e0: 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_010e: 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_0150: 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_0178: 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_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: 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_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) Material material = CopyMaterial(wood, "vr_passenger_canvas", (Color?)new Color(0.72f, 0.63f, 0.43f)); for (int i = -1; i <= 1; i += 2) { Cube(visual, "passenger_awning_deck_bracket", new Vector3((float)i * 1.06f, 0.8f, -1.2f), new Vector3(0.24f, 0.12f, 0.2f), Quaternion.identity, metal); Cube(visual, "passenger_awning_post", new Vector3((float)i * 1.14f, 1.99f, -1.2f), new Vector3(0.09f, 2.26f, 0.09f), Quaternion.identity, wood); Cube(visual, "passenger_awning_foot", new Vector3((float)i * 1.14f, 0.93f, -1.2f), new Vector3(0.12f, 0.14f, 0.12f), Quaternion.identity, metal, collider: false); Cube(visual, "passenger_awning_side_beam", new Vector3((float)i * 1.14f, 3.14f, -0.4f), new Vector3(0.08f, 0.08f, 1.84f), Quaternion.identity, wood); Cube(visual, "passenger_awning_brace", new Vector3((float)i * 1.14f, 2.88f, -0.93f), new Vector3(0.065f, 0.065f, 0.71f), Quaternion.Euler(-45f, 0f, 0f), wood); Cube(visual, "passenger_awning_panel", new Vector3((float)i * 0.58f, 3.28f, -0.4f), new Vector3(1.2f, 0.035f, 1.84f), Quaternion.Euler(0f, 0f, (float)(-i) * 10f), material, collider: false); Cube(visual, "passenger_awning_valance", new Vector3((float)i * 1.17f, 3.11f, -0.4f), new Vector3(0.025f, 0.13f, 1.84f), Quaternion.identity, material, collider: false); Cube(visual, "passenger_awning_trim", new Vector3((float)i * 1.18f, 3.055f, -0.4f), new Vector3(0.025f, 0.025f, 1.84f), Quaternion.identity, brass, collider: false); } Cube(visual, "passenger_awning_ridge", new Vector3(0f, 3.38f, -0.4f), new Vector3(0.08f, 0.08f, 1.84f), Quaternion.identity, wood); } private static void AddPassengerHearth(Transform visual) { //IL_0015: 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_0097: 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_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) //IL_00f9: 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) //IL_0136: 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_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_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_01b3: 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_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0274: 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_02e6: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_0326: Unknown result type (might be due to invalid IL or missing references) //IL_033a: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Unknown result type (might be due to invalid IL or missing references) //IL_0362: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_039e: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_03b7: Unknown result type (might be due to invalid IL or missing references) //IL_03da: Unknown result type (might be due to invalid IL or missing references) //IL_03ee: Unknown result type (might be due to invalid IL or missing references) //IL_03f3: Unknown result type (might be due to invalid IL or missing references) //IL_041e: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Unknown result type (might be due to invalid IL or missing references) //IL_0437: Unknown result type (might be due to invalid IL or missing references) //IL_0465: Unknown result type (might be due to invalid IL or missing references) //IL_0479: Unknown result type (might be due to invalid IL or missing references) //IL_047e: Unknown result type (might be due to invalid IL or missing references) //IL_04a1: Unknown result type (might be due to invalid IL or missing references) //IL_04b5: Unknown result type (might be due to invalid IL or missing references) //IL_04ba: Unknown result type (might be due to invalid IL or missing references) //IL_04e8: Unknown result type (might be due to invalid IL or missing references) //IL_04fc: Unknown result type (might be due to invalid IL or missing references) //IL_0501: Unknown result type (might be due to invalid IL or missing references) //IL_058c: Unknown result type (might be due to invalid IL or missing references) //IL_05a0: Unknown result type (might be due to invalid IL or missing references) //IL_05a5: Unknown result type (might be due to invalid IL or missing references) //IL_0534: Unknown result type (might be due to invalid IL or missing references) //IL_0548: Unknown result type (might be due to invalid IL or missing references) //IL_054d: Unknown result type (might be due to invalid IL or missing references) Transform transform = Child(visual, "vr_passenger_hearth", new Vector3(0f, 0.92f, 0.97f)).transform; Material material = CopyMaterial(metal, "vr_passenger_chiminea_clay", (Color?)new Color(0.58f, 0.24f, 0.12f)); SetMaterialFloat(material, "_Metallic", 0f); SetMaterialFloat(material, "_Glossiness", 0.12f); SetMaterialFloat(material, "_Smoothness", 0.12f); Material material2 = CopyMaterial(metal, "vr_passenger_chiminea_iron", (Color?)new Color(0.16f, 0.17f, 0.18f)); Primitive(transform, "passenger_chiminea_base", (PrimitiveType)2, new Vector3(0f, -0.01f, 0f), new Vector3(0.55f, 0.04f, 0.55f), Quaternion.identity, material2, collider: true); Primitive(transform, "passenger_chiminea_floor", (PrimitiveType)2, new Vector3(0f, 0.045f, 0f), new Vector3(0.46f, 0.025f, 0.46f), Quaternion.identity, material2, collider: true); Vector3[] array = (Vector3[])(object)new Vector3[3] { new Vector3(0.2f, 0.145f, 0.19f), new Vector3(0.235f, 0.315f, 0.19f), new Vector3(0.215f, 0.475f, 0.15f) }; foreach (Vector3 val in array) { for (int j = 2; j <= 10; j++) { float num = (float)j * 30f; float num2 = num * ((float)Math.PI / 180f); Cube(transform, "passenger_chiminea_wall", new Vector3(Mathf.Sin(num2) * val.x, val.y, Mathf.Cos(num2) * val.x), new Vector3(2f * val.x * Mathf.Sin((float)Math.PI / 12f) + 0.012f, val.z, 0.052f), Quaternion.Euler(0f, num, 0f), material); } } for (int k = -1; k <= 1; k += 2) { Cube(transform, "passenger_chiminea_mouth_jamb", new Vector3((float)k * 0.18f, 0.23f, 0.21f), new Vector3(0.07f, 0.32f, 0.15f), Quaternion.identity, material2); } for (int l = -3; l <= 3; l++) { float num3 = (float)l * 25f; float num4 = num3 * ((float)Math.PI / 180f); Cube(transform, "passenger_chiminea_mouth_arch", new Vector3(Mathf.Sin(num4) * 0.19f, 0.35f + Mathf.Cos(num4) * 0.19f, 0.24f), new Vector3(0.105f, 0.07f, 0.085f), Quaternion.Euler(0f, 0f, 0f - num3), material2); } Primitive(transform, "passenger_chiminea_shoulder", (PrimitiveType)2, new Vector3(0f, 0.57f, 0f), new Vector3(0.49f, 0.025f, 0.49f), Quaternion.identity, material, collider: true); Primitive(transform, "passenger_chiminea_neck", (PrimitiveType)2, new Vector3(0f, 0.635f, 0f), new Vector3(0.36f, 0.04f, 0.36f), Quaternion.identity, material, collider: true); Primitive(transform, "passenger_chiminea_neck_top", (PrimitiveType)0, new Vector3(0f, 0.66f, 0f), new Vector3(0.36f, 0.17f, 0.36f), Quaternion.identity, material, collider: true); Primitive(transform, "passenger_chiminea_flue", (PrimitiveType)2, new Vector3(0f, 0.985f, 0f), new Vector3(0.18f, 0.27f, 0.18f), Quaternion.identity, material2, collider: true); for (int m = -1; m <= 1; m += 2) { Cube(transform, "passenger_chiminea_cap_support", new Vector3((float)m * 0.065f, 1.28f, 0f), new Vector3(0.025f, 0.14f, 0.025f), Quaternion.identity, material2, collider: false); } Primitive(transform, "passenger_chiminea_rain_cap", (PrimitiveType)2, new Vector3(0f, 1.33f, 0f), new Vector3(0.44f, 0.025f, 0.44f), Quaternion.identity, material2, collider: true); Primitive(transform, "passenger_chiminea_cap_top", (PrimitiveType)0, new Vector3(0f, 1.345f, 0f), new Vector3(0.42f, 0.09f, 0.42f), Quaternion.identity, material2, collider: false); for (int n = -1; n <= 1; n += 2) { Cube(transform, "passenger_hearth_guard", new Vector3((float)n * 0.34f, 0.215f, 0f), new Vector3(0.045f, 0.045f, 0.6f), Quaternion.identity, brass); for (int num5 = -1; num5 <= 1; num5 += 2) { Cube(transform, "passenger_hearth_guard_post", new Vector3((float)n * 0.34f, 0.1f, (float)num5 * 0.23f), new Vector3(0.045f, 0.25f, 0.045f), Quaternion.identity, metal); } } Cube(transform, "passenger_hearth_front_guard", new Vector3(0f, 0.215f, 0.335f), new Vector3(0.725f, 0.045f, 0.045f), Quaternion.identity, brass); } private static bool TryPassengerChairBounds(Transform model, Transform reference, out Bounds bounds) { //IL_0001: 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_0075: 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_008a: 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) //IL_0099: 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_00a3: 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_00a9: 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_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) bounds = default(Bounds); bool flag = false; MeshFilter[] componentsInChildren = ((Component)model).GetComponentsInChildren(true); foreach (MeshFilter val in componentsInChildren) { if (!Object.op_Implicit((Object)(object)val.sharedMesh) || !Object.op_Implicit((Object)(object)((Component)val).GetComponent()) || !PassengerChairPartVisible(((Component)val).transform, model)) { continue; } Bounds bounds2 = val.sharedMesh.bounds; for (int j = -1; j <= 1; j += 2) { for (int k = -1; k <= 1; k += 2) { for (int l = -1; l <= 1; l += 2) { Vector3 val2 = reference.InverseTransformPoint(((Component)val).transform.TransformPoint(((Bounds)(ref bounds2)).center + Vector3.Scale(((Bounds)(ref bounds2)).extents, new Vector3((float)j, (float)k, (float)l)))); if (!flag) { bounds = new Bounds(val2, Vector3.zero); flag = true; } else { ((Bounds)(ref bounds)).Encapsulate(val2); } } } } } return flag; } private static bool PassengerChairVisualComponent(Component component) { if (!(component is Transform) && !(component is MeshRenderer) && !(component is SkinnedMeshRenderer) && !(component is MeshFilter)) { return component is LODGroup; } return true; } private static bool PassengerChairPartVisible(Transform part, Transform model) { Transform val = part; while (Object.op_Implicit((Object)(object)val) && (Object)(object)val != (Object)(object)model) { if (!((Component)val).gameObject.activeSelf) { return false; } val = val.parent; } return true; } private static void CreatePortablePlowItems(ZNetScene scene) { //IL_009d: 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_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_017c: 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_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Expected O, but got Unknown //IL_02c7: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = scene.GetPrefab("Wood"); if (!Object.op_Implicit((Object)(object)prefab) || !Object.op_Implicit((Object)(object)prefab.GetComponent())) { throw new InvalidOperationException("The Wood item prefab is required for portable plows."); } string[] array = new string[2] { "vr_plow", "vr_plow_wood" }; foreach (string pieceName in array) { GameObject val = Prefabs.Find((GameObject p) => ((Object)p).name == pieceName); GameObject val2 = Object.Instantiate(prefab, root.transform, false); ((Object)val2).name = PackedPlow.ItemName(pieceName); val2.transform.localPosition = Vector3.zero; val2.transform.localRotation = Quaternion.identity; val2.transform.localScale = Vector3.one; Component[] components = val2.GetComponents(); foreach (Component val3 in components) { if (!(val3 is Transform) && !(val3 is Rigidbody) && !(val3 is ZNetView) && !(val3 is ZSyncTransform) && !(val3 is ItemDrop)) { Object.DestroyImmediate((Object)(object)val3); } } while (val2.transform.childCount > 0) { Object.DestroyImmediate((Object)(object)((Component)val2.transform.GetChild(0)).gameObject); } GameObject obj = Object.Instantiate(((Component)val.transform.Find("visual")).gameObject, val2.transform, false); ((Object)obj).name = "attach"; obj.transform.localScale = Vector3.one * 0.4f; Collider[] componentsInChildren = obj.GetComponentsInChildren(true); for (int num = 0; num < componentsInChildren.Length; num++) { Object.DestroyImmediate((Object)(object)componentsInChildren[num]); } BoxCollider obj2 = val2.AddComponent(); obj2.center = new Vector3(0f, 0.25f, 0f); obj2.size = new Vector3(0.85f, 0.35f, 0.3f); SetLayer(val2, LayerMask.NameToLayer("item")); ItemDrop component = val2.GetComponent(); component.m_autoPickup = true; component.m_itemData = prefab.GetComponent().m_itemData.Clone(); SharedData val4 = new SharedData(); FieldInfo[] fields = typeof(SharedData).GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { if (!fieldInfo.IsInitOnly) { fieldInfo.SetValue(val4, fieldInfo.GetValue(component.m_itemData.m_shared)); } } component.m_itemData.m_shared = val4; bool flag = pieceName == "vr_plow_wood"; val4.m_name = (flag ? "Packed wooden rail plow" : "Packed rail plow"); val4.m_description = "A detached plow ready to carry. Stand beside a free end of a parked engine or cart, face its socket and use this from the inventory or hotbar to attach directly. Away from a vehicle, it finds clear ground ahead. Retains its condition."; val4.m_itemType = (ItemType)1; val4.m_icons = (Sprite[])(object)new Sprite[1] { RailIcons.Get(pieceName) }; val4.m_maxStackSize = 1; val4.m_maxQuality = 1; val4.m_weight = (flag ? 12f : 20f); val4.m_teleportable = true; val4.m_questItem = false; val4.m_useDurability = false; val4.m_buildPieces = null; component.m_itemData.m_stack = 1; component.m_itemData.m_quality = 1; component.m_itemData.m_variant = 0; component.m_itemData.m_dropPrefab = val2; component.m_itemData.m_customData = new Dictionary(); val2.GetComponent().m_persistent = true; val2.SetActive(true); PortablePlowItems.Add(val2); Prefabs.Add(val2); } } private static void RegisterPortablePlowItems(ObjectDB db) { if (!Object.op_Implicit((Object)(object)db) || PortablePlowItems.Count == 0) { return; } if (ItemByHash == null || ItemByData == null) { throw new MissingFieldException("ObjectDB item registries are unavailable."); } Dictionary dictionary = (Dictionary)ItemByHash.GetValue(db); Dictionary dictionary2 = (Dictionary)ItemByData.GetValue(db); foreach (GameObject portablePlowItem in PortablePlowItems) { if (dictionary.TryGetValue(StringExtensionMethods.GetStableHashCode(((Object)portablePlowItem).name), out var value) && (Object)(object)value != (Object)(object)portablePlowItem) { throw new InvalidOperationException("A different item uses the VikingRail name: " + ((Object)portablePlowItem).name); } } foreach (GameObject portablePlowItem2 in PortablePlowItems) { if (!db.m_items.Contains(portablePlowItem2)) { db.m_items.Add(portablePlowItem2); } dictionary[StringExtensionMethods.GetStableHashCode(((Object)portablePlowItem2).name)] = portablePlowItem2; dictionary2[portablePlowItem2.GetComponent().m_itemData.m_shared] = portablePlowItem2; } PortablePlowDatabases.Add(db); } private static void CleanupPortablePlowItems() { foreach (ObjectDB portablePlowDatabase in PortablePlowDatabases) { if (!Object.op_Implicit((Object)(object)portablePlowDatabase)) { continue; } Dictionary dictionary = ItemByHash?.GetValue(portablePlowDatabase) as Dictionary; Dictionary dictionary2 = ItemByData?.GetValue(portablePlowDatabase) as Dictionary; foreach (GameObject portablePlowItem in PortablePlowItems) { if (Object.op_Implicit((Object)(object)portablePlowItem)) { portablePlowDatabase.m_items.Remove(portablePlowItem); if (dictionary != null && dictionary.TryGetValue(StringExtensionMethods.GetStableHashCode(((Object)portablePlowItem).name), out var value) && (Object)(object)value == (Object)(object)portablePlowItem) { dictionary.Remove(StringExtensionMethods.GetStableHashCode(((Object)portablePlowItem).name)); } dictionary2?.Remove(portablePlowItem.GetComponent().m_itemData.m_shared); } } } PortablePlowDatabases.Clear(); PortablePlowItems.Clear(); } private static void CreatePortableVehicleItems(ZNetScene scene) { //IL_014c: 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_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0337: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Unknown result type (might be due to invalid IL or missing references) //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_0355: Unknown result type (might be due to invalid IL or missing references) //IL_0360: Unknown result type (might be due to invalid IL or missing references) //IL_0365: Unknown result type (might be due to invalid IL or missing references) //IL_0379: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Unknown result type (might be due to invalid IL or missing references) //IL_0394: Unknown result type (might be due to invalid IL or missing references) //IL_0399: Unknown result type (might be due to invalid IL or missing references) //IL_03dc: Unknown result type (might be due to invalid IL or missing references) //IL_03e3: Expected O, but got Unknown //IL_0578: Unknown result type (might be due to invalid IL or missing references) GameObject prefab = scene.GetPrefab("Wood"); if (!Object.op_Implicit((Object)(object)prefab) || !Object.op_Implicit((Object)(object)prefab.GetComponent())) { throw new InvalidOperationException("The Wood item prefab is required for portable railway vehicles."); } string[] array = new string[16] { "vr_handcart", "vr_handcart_tandem", "vr_bronze_engine", "vr_eitr_engine", "vr_locomotive", "vr_storagecart", "vr_passengercart", "vr_mount_cart", "vr_music_cart", "vr_pumpkin_cart", "vr_workbench_cart", "vr_workbench_chopping_cart", "vr_workbench_tanning_cart", "vr_workbench_adze_cart", "vr_workbench_toolrack_cart", "vr_repair_cart" }; foreach (string pieceName in array) { GameObject val = Prefabs.Find((GameObject p) => ((Object)p).name == pieceName); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.transform.Find("visual"))) { throw new InvalidOperationException("The railway vehicle model is unavailable: " + pieceName); } GameObject val2 = Object.Instantiate(prefab, root.transform, false); ((Object)val2).name = PackedVehicle.ItemName(pieceName); val2.transform.localPosition = Vector3.zero; val2.transform.localRotation = Quaternion.identity; val2.transform.localScale = Vector3.one; Component[] components = val2.GetComponents(); foreach (Component val3 in components) { if (!(val3 is Transform) && !(val3 is Rigidbody) && !(val3 is ZNetView) && !(val3 is ZSyncTransform) && !(val3 is ItemDrop)) { Object.DestroyImmediate((Object)(object)val3); } } while (val2.transform.childCount > 0) { Object.DestroyImmediate((Object)(object)((Component)val2.transform.GetChild(0)).gameObject); } GameObject val4 = Child(val2.transform, "attach", Vector3.zero); Object.Instantiate(((Component)val.transform.Find("visual")).gameObject, val4.transform, false); Transform val5 = val.transform.Find("vr_pump"); if (Object.op_Implicit((Object)(object)val5)) { Object.Instantiate(((Component)val5).gameObject, val4.transform, false); } MonoBehaviour[] componentsInChildren = val4.GetComponentsInChildren(true); for (int num = 0; num < componentsInChildren.Length; num++) { Object.DestroyImmediate((Object)(object)componentsInChildren[num]); } components = val4.GetComponentsInChildren(true); foreach (Component val6 in components) { if (!(val6 is Transform) && !(val6 is MeshFilter) && !(val6 is MeshRenderer) && !(val6 is SkinnedMeshRenderer) && !(val6 is LODGroup)) { Object.DestroyImmediate((Object)(object)val6); } } val4.transform.localScale = Vector3.one * 0.35f; Bounds val7 = PortableVehicleModelBounds(val2.transform, val4); Transform transform = val4.transform; transform.localPosition += Vector3.up * (0.02f - ((Bounds)(ref val7)).min.y); ((Bounds)(ref val7)).center = ((Bounds)(ref val7)).center + Vector3.up * (0.02f - ((Bounds)(ref val7)).min.y); BoxCollider obj = val2.AddComponent(); obj.center = ((Bounds)(ref val7)).center; obj.size = ((Bounds)(ref val7)).size + Vector3.one * 0.02f; SetLayer(val2, LayerMask.NameToLayer("item")); ItemDrop component = val2.GetComponent(); component.m_autoPickup = true; component.m_itemData = prefab.GetComponent().m_itemData.Clone(); SharedData val8 = new SharedData(); FieldInfo[] fields = typeof(SharedData).GetFields(BindingFlags.Instance | BindingFlags.Public); foreach (FieldInfo fieldInfo in fields) { if (!fieldInfo.IsInitOnly) { fieldInfo.SetValue(val8, fieldInfo.GetValue(component.m_itemData.m_shared)); } } component.m_itemData.m_shared = val8; RailWorkshopCart component2 = val.GetComponent(); val8.m_name = (Object.op_Implicit((Object)(object)component2) ? ("Packed " + component2.DisplayName.ToLowerInvariant()) : ((pieceName == "vr_handcart") ? "Packed rail handcart" : ((pieceName == "vr_handcart_tandem") ? "Packed two-person rail handcart" : ((pieceName == "vr_bronze_engine") ? "Packed bronze rail engine" : ((pieceName == "vr_eitr_engine") ? "Packed Eitr rail engine" : ((pieceName == "vr_mount_cart") ? "Packed rail mounting cart" : ((pieceName == "vr_music_cart") ? "Packed Techno Viking sound cart" : ((pieceName == "vr_pumpkin_cart") ? "Packed Halloween pumpkin carriage" : ((pieceName == "vr_locomotive") ? "Packed coal locomotive" : ((pieceName == "vr_storagecart") ? "Packed rail storage cart" : "Packed rail passenger cart")))))))))); val8.m_description = "A portable railway vehicle. Use from your inventory or hotbar while facing a clear rail to place it. Keeps condition, stored items, fuel and lamp setting. Cargo weight and portal restrictions still apply."; val8.m_itemType = (ItemType)1; val8.m_icons = (Sprite[])(object)new Sprite[1] { RailIcons.Get(pieceName) }; val8.m_maxStackSize = 1; val8.m_maxQuality = 1; val8.m_weight = PackedVehicle.BaseWeight(pieceName); val8.m_teleportable = true; val8.m_questItem = false; val8.m_useDurability = false; val8.m_buildPieces = null; component.m_itemData.m_stack = 1; component.m_itemData.m_quality = 1; component.m_itemData.m_variant = 0; component.m_itemData.m_dropPrefab = val2; component.m_itemData.m_customData = new Dictionary(); val2.GetComponent().m_persistent = true; val2.SetActive(true); PortableVehicleItems.Add(val2); Prefabs.Add(val2); } } private static Bounds PortableVehicleModelBounds(Transform rootTransform, GameObject visual) { //IL_0002: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_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_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_007f: 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_0086: 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_00a4: 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_0094: Unknown result type (might be due to invalid IL or missing references) Bounds result = default(Bounds); bool flag = false; MeshFilter[] componentsInChildren = visual.GetComponentsInChildren(true); foreach (MeshFilter val in componentsInChildren) { if (!Object.op_Implicit((Object)(object)val.sharedMesh)) { continue; } Bounds bounds = val.sharedMesh.bounds; for (int j = -1; j <= 1; j += 2) { for (int k = -1; k <= 1; k += 2) { for (int l = -1; l <= 1; l += 2) { Vector3 val2 = ((Bounds)(ref bounds)).center + Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3((float)j, (float)k, (float)l)); Vector3 val3 = rootTransform.InverseTransformPoint(((Component)val).transform.TransformPoint(val2)); if (!flag) { ((Bounds)(ref result))..ctor(val3, Vector3.zero); flag = true; } else { ((Bounds)(ref result)).Encapsulate(val3); } } } } } if (!flag) { throw new InvalidOperationException("A portable railway vehicle has no visible model bounds."); } return result; } private static void RegisterPortableVehicleItems(ObjectDB db) { if (!Object.op_Implicit((Object)(object)db) || PortableVehicleItems.Count == 0) { return; } if (ItemByHash == null || ItemByData == null) { throw new MissingFieldException("ObjectDB item registries are unavailable."); } Dictionary dictionary = (Dictionary)ItemByHash.GetValue(db); Dictionary dictionary2 = (Dictionary)ItemByData.GetValue(db); foreach (GameObject portableVehicleItem in PortableVehicleItems) { if (dictionary.TryGetValue(StringExtensionMethods.GetStableHashCode(((Object)portableVehicleItem).name), out var value) && (Object)(object)value != (Object)(object)portableVehicleItem) { throw new InvalidOperationException("A different item uses the VikingRail name: " + ((Object)portableVehicleItem).name); } } foreach (GameObject portableVehicleItem2 in PortableVehicleItems) { if (!db.m_items.Contains(portableVehicleItem2)) { db.m_items.Add(portableVehicleItem2); } dictionary[StringExtensionMethods.GetStableHashCode(((Object)portableVehicleItem2).name)] = portableVehicleItem2; dictionary2[portableVehicleItem2.GetComponent().m_itemData.m_shared] = portableVehicleItem2; } PortableVehicleDatabases.Add(db); } private static void CleanupPortableVehicleItems() { foreach (ObjectDB portableVehicleDatabase in PortableVehicleDatabases) { if (!Object.op_Implicit((Object)(object)portableVehicleDatabase)) { continue; } Dictionary dictionary = ItemByHash?.GetValue(portableVehicleDatabase) as Dictionary; Dictionary dictionary2 = ItemByData?.GetValue(portableVehicleDatabase) as Dictionary; foreach (GameObject portableVehicleItem in PortableVehicleItems) { if (Object.op_Implicit((Object)(object)portableVehicleItem)) { portableVehicleDatabase.m_items.Remove(portableVehicleItem); if (dictionary != null && dictionary.TryGetValue(StringExtensionMethods.GetStableHashCode(((Object)portableVehicleItem).name), out var value) && (Object)(object)value == (Object)(object)portableVehicleItem) { dictionary.Remove(StringExtensionMethods.GetStableHashCode(((Object)portableVehicleItem).name)); } dictionary2?.Remove(portableVehicleItem.GetComponent().m_itemData.m_shared); } } } PortableVehicleDatabases.Clear(); PortableVehicleItems.Clear(); } private static void CreatePumpkinCart(GameObject cart, GameObject floor) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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_00af: 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_0103: 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_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Expected O, but got Unknown //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: 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_02de: Unknown result type (might be due to invalid IL or missing references) //IL_03d5: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_033c: Unknown result type (might be due to invalid IL or missing references) GameObject val = CloneBase(cart, "vr_pumpkin_cart", keepContainer: false, floor); ConfigurePiece(val.GetComponent(), "Halloween pumpkin carriage", "A giant hollow jack-o'-lantern with one passenger seat and comfort 3 while riding. Use the chair to sit; use the music lever for its spooky waltz and the brass dial to change volume. Couple with a Techno Viking cart for Halloween techno. Alternate-use the music lever to couple."); GameObject val2 = Child(val.transform, "visual", Vector3.zero); AddWorkshopChassis(val2.transform); Material val3 = CopyMaterial(wood, "VikingRail_PumpkinFrame", (Color?)new Color(0.16f, 0.12f, 0.12f)); Material rind = CopyMaterial(wood, "VikingRail_PumpkinRind", (Color?)new Color(0.93f, 0.3f, 0.055f)); Material inside = CopyMaterial(wood, "VikingRail_PumpkinInterior", (Color?)new Color(0.35f, 0.13f, 0.045f)); Material rim = CopyMaterial(wood, "VikingRail_PumpkinCutRim", (Color?)new Color(1f, 0.55f, 0.15f)); Material val4 = CopyMaterial(wood, "VikingRail_PumpkinVine", (Color?)new Color(0.2f, 0.3f, 0.085f)); Material dark = CopyMaterial(metal, "VikingRail_PumpkinEyeRecess", (Color?)new Color(0.055f, 0.038f, 0.045f)); Material amber = LampGlass(new Color(1f, 0.38f, 0.045f)); foreach (Transform item in val2.transform) { Transform val5 = item; if (((Object)val5).name == "deck_plank") { val5.localScale = new Vector3(0.32f, 0.24f, 2.4f); } if (!(((Object)val5).name != "deck_plank") || !(((Object)val5).name != "chassis") || !(((Object)val5).name != "vr_wheel")) { Renderer component = ((Component)val5).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { component.sharedMaterial = val3; } } } AddPumpkinShell(val2.transform, rind, inside, rim); AddPumpkinFace(val2.transform, dark, amber); AddPumpkinVines(val2.transform, val4); AddPumpkinChair(val2.transform); AddPumpkinMusicControl(val2.transform, val3, val4, amber); AddMusicVolumeDial(val2.transform, new Vector3(-0.53f, 1.075f, 1.1f)); for (int i = -1; i <= 1; i += 2) { for (int j = -1; j <= 1; j += 2) { Primitive(val2.transform, "pumpkin_wheel_inset", (PrimitiveType)2, new Vector3((float)i * 0.782f, 0.44f, (float)j * 0.68f), new Vector3(0.4f, 0.006f, 0.4f), Quaternion.Euler(0f, 0f, 90f), val4, collider: false); for (int k = 0; k < 3; k++) { Cube(val2.transform, "pumpkin_wheel_spoke", new Vector3((float)i * 0.794f, 0.44f, (float)j * 0.68f), new Vector3(0.012f, 0.035f, 0.39f), Quaternion.Euler((float)(k * 60), 0f, 0f), brass, collider: false); } } } Rigidbody obj = val.GetComponent() ?? val.AddComponent(); obj.isKinematic = true; obj.useGravity = false; obj.mass = 120f; ZSyncTransform obj2 = val.GetComponent() ?? val.AddComponent(); obj2.m_syncPosition = true; obj2.m_syncRotation = true; obj2.m_syncScale = false; obj2.m_syncBodyVelocity = false; obj2.m_characterParentSync = false; val.GetComponent().m_type = (ObjectType)0; RailVehicle railVehicle = val.AddComponent(); railVehicle.IsEngine = false; railVehicle.CoalPowered = false; railVehicle.IsPassengerCart = true; railVehicle.IsPumpkinCart = true; val.AddComponent(); RailBuildMenu.ConfigureTransportPiece(val.GetComponent()); ConfigureWear(val, val2, track: false); AddVehicleLights(val, val2.transform, engine: false); AddPackingHandle(val2.transform); AddPushHandle(val2.transform); if (val.GetComponentsInChildren(true).Length != 1 || Object.op_Implicit((Object)(object)val.GetComponentInChildren(true)) || Object.op_Implicit((Object)(object)val.GetComponentInChildren(true))) { throw new InvalidOperationException("The pumpkin carriage must contain exactly one chair, with no cargo or fireplace."); } ZNetView[] componentsInChildren = val.GetComponentsInChildren(true); for (int l = 0; l < componentsInChildren.Length; l++) { if ((Object)(object)((Component)componentsInChildren[l]).gameObject != (Object)(object)val) { throw new InvalidOperationException("The pumpkin carriage retained a nested network view."); } } Prefabs.Add(val); } private static void AddPumpkinShell(Transform visual, Material rind, Material inside, Material rim) { //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Expected O, but got Unknown //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_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_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_0087: 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_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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_0094: 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_009e: 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_00bb: 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_00c4: 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_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_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_00f9: 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_0108: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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) List list = new List(); List list2 = new List(); List[] array = new List[3] { new List(), new List(), new List() }; foreach (RailPumpkinShell.Face item in RailPumpkinShell.Build()) { RailVector[] points = item.Points; for (int i = 1; i + 1 < points.Length; i++) { Vector3 val = RailSegment.ToUnity(points[0]); Vector3 val2 = RailSegment.ToUnity(points[i]); Vector3 val3 = RailSegment.ToUnity(points[i + 1]); Vector3 val4 = Vector3.Cross(val2 - val, val3 - val); if (!(((Vector3)(ref val4)).sqrMagnitude < 1E-10f)) { Vector3[] array2 = (Vector3[])(object)new Vector3[3] { val, val2, val3 }; foreach (Vector3 val5 in array2) { array[item.Surface].Add(list.Count); list.Add(val5); list2.Add(new Vector2(Mathf.Atan2(val5.x, val5.z) / ((float)Math.PI * 2f), val5.y * 0.5f)); } } } } Mesh val6 = new Mesh { name = "VikingRail_HollowPumpkin", subMeshCount = 3 }; val6.vertices = list.ToArray(); val6.uv = list2.ToArray(); for (int k = 0; k < array.Length; k++) { val6.SetTriangles(array[k].ToArray(), k); } val6.RecalculateNormals(); val6.RecalculateBounds(); PumpkinMeshes.Add(val6); GameObject val7 = Child(visual, "pumpkin_hollow_shell", Vector3.zero); val7.AddComponent().sharedMesh = val6; ((Renderer)val7.AddComponent()).sharedMaterials = (Material[])(object)new Material[3] { rind, inside, rim }; MeshCollider obj = val7.AddComponent(); obj.convex = false; obj.sharedMesh = val6; } private static void AddPumpkinFace(Transform visual, Material dark, Material amber) { //IL_0027: 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_002d: 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_004b: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_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_0077: 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_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_00b1: 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_00dc: 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_0114: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) for (int i = -1; i <= 1; i += 2) { Vector3 val = RailSegment.ToUnity(RailPumpkinShell.Point(Math.Acos(50.0 / 99.0), (double)i * 0.9)); Vector3 val2 = new Vector3(val.x / 1.21f, (val.y - 1.78f) / 0.9801f, val.z / 1.2996f); Vector3 normalized = ((Vector3)(ref val2)).normalized; GameObject obj = Child(visual, "pumpkin_glowing_eye", val + normalized * 0.025f); obj.transform.localRotation = Quaternion.LookRotation(normalized, Vector3.up); PumpkinTriangle(obj.transform, "pumpkin_eye_socket", new Vector3(-0.2f, -0.085f, 0f), new Vector3(0.2f, -0.085f, 0f), new Vector3((float)i * 0.12f, 0.15f, 0f), dark); PumpkinTriangle(obj.transform, "pumpkin_eye_amber", new Vector3(-0.155f, -0.063f, 0.006f), new Vector3(0.155f, -0.063f, 0.006f), new Vector3((float)i * 0.09f, 0.113f, 0.006f), amber); } } private static void PumpkinTriangle(Transform parent, string name, Vector3 a, Vector3 b, Vector3 c, Material material) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: 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_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_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_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_0067: 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_0091: Unknown result type (might be due to invalid IL or missing references) Mesh val = new Mesh(); ((Object)val).name = name; val.vertices = (Vector3[])(object)new Vector3[3] { a, b, c }; val.triangles = new int[3] { 0, 1, 2 }; val.uv = (Vector2[])(object)new Vector2[3] { Vector2.zero, Vector2.right, Vector2.up }; Mesh val2 = val; val2.RecalculateNormals(); val2.RecalculateBounds(); PumpkinMeshes.Add(val2); GameObject obj = Child(parent, name, Vector3.zero); obj.AddComponent().sharedMesh = val2; ((Renderer)obj.AddComponent()).sharedMaterial = material; } private static void AddPumpkinVines(Transform visual, Material vine) { //IL_0017: 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_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_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0083: 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_00d4: 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_0111: 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_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) Vector3[] array = (Vector3[])(object)new Vector3[4] { new Vector3(0f, 2.73f, 0f), new Vector3(0.045f, 2.87f, -0.01f), new Vector3(0.15f, 2.98f, -0.05f), new Vector3(0.22f, 3.03f, -0.11f) }; for (int i = 1; i < array.Length; i++) { PumpkinVine(visual, array[i - 1], array[i], 0.19f - (float)i * 0.025f, vine); } Vector3 val = default(Vector3); Vector3 val2 = default(Vector3); for (int j = -1; j <= 1; j += 2) { PumpkinVine(visual, new Vector3(0f, 2.76f, 0f), new Vector3((float)j * 0.25f, 2.78f, -0.13f), 0.045f, vine); Primitive(visual, "pumpkin_leaf", (PrimitiveType)0, new Vector3((float)j * 0.3f, 2.78f, -0.16f), new Vector3(0.43f, 0.055f, 0.22f), Quaternion.Euler(0f, (float)(j * 25), (float)(j * -12)), vine, collider: false); ((Vector3)(ref val))..ctor((float)j * 0.25f, 2.59f, -0.54f); for (int k = 1; k <= 10; k++) { float num = (float)k * 0.36f; ((Vector3)(ref val2))..ctor((float)j * (0.25f + 0.12f * Mathf.Sin(num)), 2.59f - (float)k * 0.11f, (0f - Mathf.Sqrt(Mathf.Max(0.05f, 1f - Mathf.Pow((2.59f - (float)k * 0.11f - 1.78f) / 0.99f, 2f)))) * 1.11f); PumpkinVine(visual, val, val2, 0.032f, vine); val = val2; } } } private static void PumpkinVine(Transform visual, Vector3 from, Vector3 to, float width, Material vine) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_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_0011: 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_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_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) Vector3 val = to - from; Primitive(visual, "pumpkin_vine", (PrimitiveType)2, (from + to) * 0.5f, new Vector3(width, ((Vector3)(ref val)).magnitude * 0.5f, width), Quaternion.FromToRotation(Vector3.up, ((Vector3)(ref val)).normalized), vine, collider: false); } private static void AddPumpkinMusicControl(Transform visual, Material frame, Material vine, Material amber) { //IL_0015: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_0083: 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_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_00eb: 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_0126: 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_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: 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_0207: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) GameObject obj = Child(visual, "vr_music_console", new Vector3(-0.53f, 1.15f, 0.94f)); Cube(obj.transform, "pumpkin_music_box", Vector3.zero, new Vector3(0.24f, 0.36f, 0.22f), Quaternion.identity, frame, collider: false); Cube(obj.transform, "pumpkin_music_panel", new Vector3(0f, 0.1f, 0.118f), new Vector3(0.17f, 0.12f, 0.015f), Quaternion.identity, vine, collider: false); Cube(obj.transform, "pumpkin_music_note", new Vector3(0f, 0.11f, 0.131f), new Vector3(0.024f, 0.08f, 0.015f), Quaternion.identity, amber, collider: false); Primitive(obj.transform, "pumpkin_music_note_head", (PrimitiveType)0, new Vector3(-0.018f, 0.072f, 0.132f), new Vector3(0.06f, 0.036f, 0.018f), Quaternion.identity, amber, collider: false); obj.AddComponent().size = new Vector3(0.26f, 0.38f, 0.25f); obj.AddComponent(); GameObject obj2 = Child(visual, "vr_music_lever", new Vector3(-0.53f, 1.35f, 0.94f)); BoxCollider obj3 = obj2.AddComponent(); obj3.center = new Vector3(0f, 0.08f, 0f); obj3.size = new Vector3(0.1f, 0.2f, 0.1f); obj2.AddComponent(); Cube(obj2.transform, "pumpkin_music_lever", new Vector3(0f, 0.06f, 0f), new Vector3(0.035f, 0.12f, 0.035f), Quaternion.identity, brass, collider: false); Primitive(obj2.transform, "pumpkin_music_grip", (PrimitiveType)0, new Vector3(0f, 0.13f, 0f), new Vector3(0.08f, 0.065f, 0.08f), Quaternion.identity, amber, collider: false); } private static void CleanupPumpkinMeshes() { foreach (Mesh pumpkinMesh in PumpkinMeshes) { if (Object.op_Implicit((Object)(object)pumpkinMesh)) { Object.Destroy((Object)(object)pumpkinMesh); } } PumpkinMeshes.Clear(); } private static void AddPumpkinChair(Transform visual) { //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_0070: 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_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_00a6: 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_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) if (((Component)visual).GetComponentsInChildren(true).Length != 0) { throw new InvalidOperationException("The pumpkin carriage must have exactly one passenger chair."); } AddPassengerChair(visual, 0, 0); Transform val = visual.Find("vr_passenger_seat_0"); RailPassengerSeat railPassengerSeat = (Object.op_Implicit((Object)(object)val) ? ((Component)val).GetComponent() : null); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)railPassengerSeat) || !Object.op_Implicit((Object)(object)railPassengerSeat.AttachPoint)) { throw new InvalidOperationException("The pumpkin passenger chair has no valid attachment point."); } Vector3 localPosition = val.localPosition; val.localPosition = new Vector3(0f, localPosition.y, -0.1f); railPassengerSeat.SeatIndex = 0; Vector3 val2 = visual.TransformPoint(new Vector3(0f, 0.88f, 0.88f)); railPassengerSeat.DetachOffset = railPassengerSeat.AttachPoint.InverseTransformPoint(val2); } internal static void AddPushHandle(Transform visual) { //IL_0015: 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_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_0088: 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_00cf: 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_011a: 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_016e: Unknown result type (might be due to invalid IL or missing references) GameObject val = Child(visual, "vr_push_handle", new Vector3(0f, 1f, -1.1f)); Cube(val.transform, "push_crossbar", new Vector3(0f, 0f, -0.06f), new Vector3(0.9f, 0.1f, 0.1f), Quaternion.identity, wood, collider: false); for (int i = -1; i <= 1; i += 2) { Cube(val.transform, "push_bracket", new Vector3((float)i * 0.33f, -0.065f, 0.04f), new Vector3(0.07f, 0.15f, 0.26f), Quaternion.identity, brass, collider: false); Cube(val.transform, "push_grip_band", new Vector3((float)i * 0.28f, 0f, -0.06f), new Vector3(0.13f, 0.115f, 0.115f), Quaternion.identity, brass, collider: false); } BoxCollider obj = val.AddComponent(); obj.center = new Vector3(0f, -0.025f, -0.045f); obj.size = new Vector3(0.94f, 0.21f, 0.29f); val.AddComponent(); SetLayer(val, LayerMask.NameToLayer("piece")); Child(visual.parent, "vr_push_anchor", new Vector3(0f, 0.18f, -1.8f)); AddCouplingLever(visual); } private static void CreateRepairCart(ZNetScene scene, GameObject cart, GameObject floor) { //IL_0039: 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) GameObject val = CloneBase(cart, "vr_repair_cart", keepContainer: false, floor); ConfigurePiece(val.GetComponent(), "Rail repair station cart", "A covered repair bench and anvil on rails. Park the train and use the station to repair equipment. Alternate-use to couple or uncouple; this cart does not provide crafting recipes or station upgrades."); RailBuildMenu.ConfigureRepairPiece(val.GetComponent()); GameObject val2 = Child(val.transform, "visual", Vector3.zero); AddWorkshopChassis(val2.transform); AddWorkshopShelter(val2.transform); AddRepairBench(val2.transform); Rigidbody obj = val.GetComponent() ?? val.AddComponent(); obj.isKinematic = true; obj.useGravity = false; obj.mass = 170f; ZSyncTransform obj2 = val.GetComponent() ?? val.AddComponent(); obj2.m_syncPosition = true; obj2.m_syncRotation = true; obj2.m_syncScale = false; obj2.m_syncBodyVelocity = false; obj2.m_characterParentSync = false; val.GetComponent().m_type = (ObjectType)0; RailVehicle railVehicle = val.AddComponent(); railVehicle.IsEngine = false; railVehicle.CoalPowered = false; RailWorkshopCart railWorkshopCart = val.AddComponent(); railWorkshopCart.DisplayName = "Rail repair station cart"; railWorkshopCart.RepairStation = true; val.AddComponent(); ConfigureWear(val, val2, track: false); AddVehicleLights(val, val2.transform, engine: false); AddPackingHandle(val2.transform); AddPushHandle(val2.transform); if (Object.op_Implicit((Object)(object)val.GetComponentInChildren(true)) || Object.op_Implicit((Object)(object)val.GetComponentInChildren(true)) || Object.op_Implicit((Object)(object)val.GetComponentInChildren(true))) { throw new InvalidOperationException("The repair cart retained an unrelated station or container."); } ZNetView[] componentsInChildren = val.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)((Component)componentsInChildren[i]).gameObject != (Object)(object)val) { throw new InvalidOperationException("The repair cart retained a nested network view."); } } Prefabs.Add(val); } private static void AddRepairBench(Transform visual) { //IL_0015: 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_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0141: 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_015a: 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_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: 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_01fe: 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_0217: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_0291: 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_006b: 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_0084: 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_00c9: 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_00f7: 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_0110: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Unknown result type (might be due to invalid IL or missing references) //IL_039c: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_03e4: Unknown result type (might be due to invalid IL or missing references) //IL_040a: Unknown result type (might be due to invalid IL or missing references) //IL_041e: Unknown result type (might be due to invalid IL or missing references) //IL_0423: Unknown result type (might be due to invalid IL or missing references) //IL_0450: Unknown result type (might be due to invalid IL or missing references) //IL_0464: Unknown result type (might be due to invalid IL or missing references) //IL_0469: Unknown result type (might be due to invalid IL or missing references) //IL_0497: Unknown result type (might be due to invalid IL or missing references) //IL_04ab: Unknown result type (might be due to invalid IL or missing references) //IL_04bf: Unknown result type (might be due to invalid IL or missing references) //IL_04e5: Unknown result type (might be due to invalid IL or missing references) //IL_04f9: Unknown result type (might be due to invalid IL or missing references) //IL_050d: Unknown result type (might be due to invalid IL or missing references) Cube(visual, "repair_bench_top", new Vector3(0f, 1.51f, -0.08f), new Vector3(1.42f, 0.16f, 1.24f), Quaternion.identity, wood); for (int i = -1; i <= 1; i += 2) { for (int j = -1; j <= 1; j += 2) { Cube(visual, "repair_bench_leg", new Vector3((float)i * 0.55f, 1.145f, -0.08f + (float)j * 0.46f), new Vector3(0.14f, 0.57f, 0.14f), Quaternion.identity, wood); } Cube(visual, "repair_bench_brace", new Vector3((float)i * 0.55f, 1.03f, -0.08f), new Vector3(0.12f, 0.13f, 1.06f), Quaternion.identity, wood); Cube(visual, "repair_bench_edge", new Vector3((float)i * 0.62f, 1.598f, -0.08f), new Vector3(0.055f, 0.024f, 1.16f), Quaternion.identity, metal, collider: false); } Cube(visual, "repair_bench_lower_shelf", new Vector3(0f, 1.08f, 0.08f), new Vector3(1.15f, 0.1f, 0.73f), Quaternion.identity, wood); Cube(visual, "repair_anvil_foot", new Vector3(0.13f, 1.645f, 0.08f), new Vector3(0.66f, 0.11f, 0.43f), Quaternion.identity, metal); Cube(visual, "repair_anvil_waist", new Vector3(0.13f, 1.765f, 0.08f), new Vector3(0.28f, 0.18f, 0.26f), Quaternion.identity, metal); Cube(visual, "repair_anvil_shoulders", new Vector3(0.13f, 1.86f, 0.08f), new Vector3(0.48f, 0.1f, 0.31f), Quaternion.identity, metal); Cube(visual, "repair_anvil_face", new Vector3(0.13f, 1.945f, 0.08f), new Vector3(0.68f, 0.13f, 0.35f), Quaternion.identity, metal); Primitive(visual, "repair_anvil_horn", (PrimitiveType)0, new Vector3(-0.31f, 1.938f, 0.08f), new Vector3(0.42f, 0.14f, 0.23f), Quaternion.identity, metal, collider: false); for (int k = -1; k <= 1; k += 2) { Cube(visual, "repair_anvil_mount", new Vector3(0.13f + (float)k * 0.26f, 1.704f, 0.08f), new Vector3(0.06f, 0.025f, 0.3f), Quaternion.identity, brass, collider: false); } GameObject obj = Child(visual, "repair_hammer", new Vector3(-0.25f, 1.63f, -0.44f)); obj.transform.localRotation = Quaternion.Euler(0f, -24f, 0f); Cube(obj.transform, "repair_hammer_handle", Vector3.zero, new Vector3(0.065f, 0.065f, 0.47f), Quaternion.identity, wood, collider: false); Cube(obj.transform, "repair_hammer_head", new Vector3(0f, 0.018f, 0.2f), new Vector3(0.26f, 0.12f, 0.13f), Quaternion.identity, metal, collider: false); Cube(obj.transform, "repair_hammer_grip", new Vector3(0f, 0f, -0.16f), new Vector3(0.075f, 0.075f, 0.12f), Quaternion.identity, brass, collider: false); Cube(visual, "repair_badge", new Vector3(0f, 2.4f, -1.035f), new Vector3(0.52f, 0.44f, 0.075f), Quaternion.identity, wood, collider: false); for (int l = -1; l <= 1; l += 2) { Cube(visual, "repair_badge_strap", new Vector3((float)l * 0.16f, 2.775f, -1.035f), new Vector3(0.045f, 0.35f, 0.035f), Quaternion.identity, metal, collider: false); } Cube(visual, "repair_badge_handle", new Vector3(0f, 2.35f, -1.081f), new Vector3(0.055f, 0.26f, 0.025f), Quaternion.Euler(0f, 0f, -30f), brass, collider: false); Cube(visual, "repair_badge_head", new Vector3(0.065f, 2.463f, -1.083f), new Vector3(0.23f, 0.09f, 0.028f), Quaternion.Euler(0f, 0f, -30f), brass, collider: false); } private static void CreateRailSigns(ZNetScene scene) { int count = Prefabs.Count; int childCount = root.transform.childCount; try { GameObject prefab = scene.GetPrefab("sign"); if ((Object)(object)prefab == (Object)null || (Object)(object)prefab.GetComponent() == (Object)null) { throw new InvalidOperationException("The vanilla sign prefab is unavailable."); } InitializeNativeSignWood(scene); CreateRailSign(prefab, "vr_sign_station", "Rail station sign", "Station", "Editable station name. Use the sign to change its text. Place beside the railway, clear of passing trains.", RailSignKind.Station); CreateRailSign(prefab, "vr_sign_direction", "Rail direction sign — right", "Destination", "Editable destination sign with an arrow pointing right when facing its text. Use to edit its destination.", RailSignKind.Direction); CreateRailSign(prefab, "vr_sign_direction_left", "Rail direction sign — left", "Destination", "Editable destination sign with an arrow pointing left when facing its text. Use to edit its destination.", RailSignKind.DirectionLeft); CreateRailSign(prefab, "vr_sign_warning", "Rail warning sign", "Caution", "Editable railway warning. Use to change its text. This sign is a marker; stopping tracks control trains.", RailSignKind.Warning); CreateRailSign(prefab, "vr_sign_crossing", "Rail crossing sign", "Railway crossing", "Crossbuck railway crossing marker with editable text. Use to change its message. Place beside the crossing, clear of passing trains.", RailSignKind.Crossing); } catch (Exception ex) { Prefabs.RemoveRange(count, Prefabs.Count - count); while (root.transform.childCount > childCount) { Object.DestroyImmediate((Object)(object)((Component)root.transform.GetChild(root.transform.childCount - 1)).gameObject); } RailPlugin.Warn("Editable rail signs could not be built; other railway pieces remain available. " + ex.Message); } } private static void CreateRailSign(GameObject source, string name, string title, string defaultText, string description, RailSignKind kind) { //IL_001f: 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_003f: 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_012b: 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_013e: 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_0174: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: 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) //IL_01c4: 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_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_024e: 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_0257: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate(source, root.transform, false); ((Object)val).name = name; val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; val.transform.localScale = Vector3.one; Piece component = val.GetComponent(); Sign component2 = val.GetComponent(); ZNetView component3 = val.GetComponent(); WearNTear component4 = val.GetComponent(); if ((Object)(object)component == (Object)null || (Object)(object)component2 == (Object)null || (Object)(object)component3 == (Object)null || (Object)(object)component4 == (Object)null || (Object)(object)component2.m_textWidget == (Object)null) { throw new InvalidOperationException("The vanilla sign prefab has incomplete piece, networking, wear, or text components."); } if (!((TMP_Text)component2.m_textWidget).transform.IsChildOf(val.transform)) { throw new InvalidOperationException("The railway sign text widget must belong to its own cloned hierarchy."); } ConfigurePiece(component, title, description); component3.m_persistent = true; component3.m_distant = false; component2.m_name = title; component2.m_defaultText = defaultText; component2.m_characterLimit = 50; ((TMP_Text)component2.m_textWidget).text = defaultText; component4.m_noRoofWear = false; component4.m_noSupportWear = true; component4.m_staticPosition = true; Bounds bounds; Bounds rootBounds; GameObject val2 = CreateSignDecorationFrame(val, component2, out bounds, out rootBounds); Bounds board = MeasureSignBounds(val, val2.transform); RailSignLayout layout = new RailSignLayout(((Bounds)(ref rootBounds)).min.y, ((Bounds)(ref rootBounds)).max.y, ((Bounds)(ref board)).size.x); GameObject val3 = RaiseNativeSign(val, component4, (float)layout.Lift); GameObject item = AddSignLegs(val, val2.transform, board, layout); switch (kind) { case RailSignKind.Station: AddStationSignFrame(val2.transform, bounds); break; case RailSignKind.Direction: AddDirectionSignArrow(val2.transform, bounds, 1); break; case RailSignKind.DirectionLeft: AddDirectionSignArrow(val2.transform, bounds, -1); break; case RailSignKind.Warning: AddWarningSignMarker(val2.transform, bounds); break; case RailSignKind.Crossing: AddCrossingSignMarker(val2.transform, bounds); break; } if (component4.m_fragmentRoots != null && component4.m_fragmentRoots.Length != 0) { List list = new List(component4.m_fragmentRoots); if (!list.Contains(val)) { list.Add(val2); list.Add(item); if ((Object)(object)val3 != (Object)null) { list.Add(val3); } } component4.m_fragmentRoots = list.ToArray(); } Bounds val4 = MeasureSignBounds(val, val.transform); component4.m_comOffset = ((Bounds)(ref val4)).center; component4.m_forceCorrectCOMCalculation = true; LODGroup[] componentsInChildren = val.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].RecalculateBounds(); } val.SetActive(true); Prefabs.Add(val); } private static GameObject CreateSignDecorationFrame(GameObject prefab, Sign sign, out Bounds bounds, out Bounds rootBounds) { //IL_0017: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //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_0081: 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_00a5: 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_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) RectTransform rectTransform = ((TMP_Text)sign.m_textWidget).rectTransform; GameObject val = Child(prefab.transform, "vr_sign_frame", Vector3.zero); Transform transform = val.transform; Rect rect = rectTransform.rect; transform.position = ((Transform)rectTransform).TransformPoint(Vector2.op_Implicit(((Rect)(ref rect)).center)); val.transform.rotation = ((Transform)rectTransform).rotation; val.transform.localScale = Vector3.one; bounds = MeasureSignBounds(prefab, val.transform); rootBounds = MeasureSignBounds(prefab, prefab.transform); Vector3[] array = (Vector3[])(object)new Vector3[4]; rectTransform.GetWorldCorners(array); Vector3[] array2 = array; foreach (Vector3 val2 in array2) { ((Bounds)(ref bounds)).Encapsulate(val.transform.InverseTransformPoint(val2)); } return val; } private static Bounds MeasureSignBounds(GameObject prefab, Transform space) { //IL_0004: 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_01b0: 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_008b: 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_00b0: 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_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_0185: 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_00ee: 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_012b: 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_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) bool found = false; Bounds bounds = default(Bounds); MeshFilter[] componentsInChildren = prefab.GetComponentsInChildren(true); foreach (MeshFilter val in componentsInChildren) { if (!((Object)(object)val.sharedMesh == (Object)null)) { EncapsulateSignBounds(ref bounds, ref found, val.sharedMesh.bounds, ((Component)val).transform, space); } } Collider[] componentsInChildren2 = prefab.GetComponentsInChildren(true); Bounds bounds2 = default(Bounds); foreach (Collider val2 in componentsInChildren2) { if (val2.isTrigger) { continue; } BoxCollider val3 = (BoxCollider)(object)((val2 is BoxCollider) ? val2 : null); if (val3 != null) { ((Bounds)(ref bounds2))..ctor(val3.center, val3.size); } else { SphereCollider val4 = (SphereCollider)(object)((val2 is SphereCollider) ? val2 : null); if (val4 != null) { ((Bounds)(ref bounds2))..ctor(val4.center, Vector3.one * val4.radius * 2f); } else { CapsuleCollider val5 = (CapsuleCollider)(object)((val2 is CapsuleCollider) ? val2 : null); if (val5 != null) { Vector3 val6 = Vector3.one * val5.radius * 2f; ((Vector3)(ref val6))[val5.direction] = Mathf.Max(val5.height, ((Vector3)(ref val6))[val5.direction]); ((Bounds)(ref bounds2))..ctor(val5.center, val6); } else { MeshCollider val7 = (MeshCollider)(object)((val2 is MeshCollider) ? val2 : null); if (val7 == null || !((Object)(object)val7.sharedMesh != (Object)null)) { throw new InvalidOperationException("The native sign has an unsupported collider: " + ((object)val2).GetType().Name); } bounds2 = val7.sharedMesh.bounds; } } } EncapsulateSignBounds(ref bounds, ref found, bounds2, ((Component)val2).transform, space); } if (!found) { throw new InvalidOperationException("The native sign has no measurable board geometry."); } return bounds; } private static void EncapsulateSignBounds(ref Bounds bounds, ref bool found, Bounds local, Transform from, Transform to) { //IL_000e: 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_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_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_0033: 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_003e: 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_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_004a: 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) for (int i = -1; i <= 1; i += 2) { for (int j = -1; j <= 1; j += 2) { for (int k = -1; k <= 1; k += 2) { Vector3 val = ((Bounds)(ref local)).center + Vector3.Scale(((Bounds)(ref local)).extents, new Vector3((float)i, (float)j, (float)k)); val = to.InverseTransformPoint(from.TransformPoint(val)); if (!found) { bounds = new Bounds(val, Vector3.zero); found = true; } else { ((Bounds)(ref bounds)).Encapsulate(val); } } } } } private static GameObject RaiseNativeSign(GameObject prefab, WearNTear wear, float lift) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: 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) List list = new List(); foreach (Transform item2 in prefab.transform) { Transform item = item2; list.Add(item); } GameObject val = Child(prefab.transform, "vr_sign_raised", Vector3.zero); Collider[] components = prefab.GetComponents(); MeshFilter component = prefab.GetComponent(); MeshRenderer component2 = prefab.GetComponent(); GameObject val2 = null; if (components.Length != 0 || (Object)(object)component != (Object)null || (Object)(object)component2 != (Object)null) { val2 = Object.Instantiate(prefab, root.transform, false); ((Object)val2).name = "vr_sign_native_root_geometry"; while (val2.transform.childCount > 0) { Object.DestroyImmediate((Object)(object)((Component)val2.transform.GetChild(val2.transform.childCount - 1)).gameObject); } Component[] components2 = val2.GetComponents(); foreach (Component val3 in components2) { if (!(val3 is Transform) && !(val3 is Collider) && !(val3 is MeshFilter) && !(val3 is MeshRenderer)) { Object.DestroyImmediate((Object)(object)val3); } } val2.transform.SetParent(val.transform, false); if ((Object)(object)component2 != (Object)null) { MeshRenderer component3 = val2.GetComponent(); ((Renderer)component3).probeAnchor = ((Renderer)component2).probeAnchor; ((Renderer)component3).lightProbeProxyVolumeOverride = ((Renderer)component2).lightProbeProxyVolumeOverride; LODGroup[] componentsInChildren = prefab.GetComponentsInChildren(true); foreach (LODGroup val4 in componentsInChildren) { LOD[] lODs = val4.GetLODs(); LOD[] array = lODs; foreach (LOD val5 in array) { for (int k = 0; k < val5.renderers.Length; k++) { if ((Object)(object)val5.renderers[k] == (Object)(object)component2) { val5.renderers[k] = (Renderer)(object)component3; } } } val4.SetLODs(lODs); } if (wear.m_nonSolidRenderers != null) { for (int l = 0; l < wear.m_nonSolidRenderers.Count; l++) { if ((Object)(object)wear.m_nonSolidRenderers[l] == (Object)(object)component2) { wear.m_nonSolidRenderers[l] = (Renderer)(object)component3; } } } Object.DestroyImmediate((Object)(object)component2); } Collider[] array2 = components; for (int i = 0; i < array2.Length; i++) { Object.DestroyImmediate((Object)(object)array2[i]); } if ((Object)(object)component != (Object)null) { Object.DestroyImmediate((Object)(object)component); } } foreach (Transform item3 in list) { item3.SetParent(val.transform, false); } val.transform.localPosition = new Vector3(0f, lift, 0f); return val2; } private static GameObject AddSignLegs(GameObject prefab, Transform face, Bounds board, RailSignLayout layout) { //IL_000b: 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_004e: 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_0064: Unknown result type (might be due to invalid IL or missing references) //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_0095: 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_009f: 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_00b0: 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_00b5: 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_00e1: 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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0114: 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_012a: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) GameObject val = Child(prefab.transform, "vr_sign_legs", Vector3.zero); float num = ((((Bounds)(ref board)).center.z < 0f) ? (-1f) : 1f); float num2 = ((num < 0f) ? ((Bounds)(ref board)).min.z : ((Bounds)(ref board)).max.z); num2 += num * 0.07000001f; Vector3 val2 = Vector3.ProjectOnPlane(face.forward, prefab.transform.up); Quaternion rotation = ((((Vector3)(ref val2)).sqrMagnitude > 0.001f) ? (Quaternion.Inverse(prefab.transform.rotation) * Quaternion.LookRotation(val2, prefab.transform.up)) : Quaternion.identity); for (int i = -1; i <= 1; i += 2) { Vector3 position = prefab.transform.InverseTransformPoint(face.TransformPoint(new Vector3(((Bounds)(ref board)).center.x + (float)i * (float)layout.PostHalfSeparation, ((Bounds)(ref board)).min.y, num2))); position.y = 0.61f; SignWoodBlock(val.transform, "sign_wooden_leg", position, new Vector3(0.16f, 1.22f, 0.18f), rotation); position.y = 0.05f; SignWoodBlock(val.transform, "sign_wooden_foot", position, new Vector3(0.28f, 0.1f, 0.28f), rotation, horizontal: true); } return val; } private static void AddStationSignFrame(Transform frame, Bounds bounds) { //IL_0004: 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_001e: 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_006e: 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_00b4: 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_0101: 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_011d: 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) //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) RailStationSignFrame railStationSignFrame = new RailStationSignFrame(((Bounds)(ref bounds)).min.y, ((Bounds)(ref bounds)).max.y, Mathf.Max(Mathf.Abs(((Bounds)(ref bounds)).min.x), Mathf.Abs(((Bounds)(ref bounds)).max.x))); for (int i = -1; i <= 1; i += 2) { SignWoodBlock(frame, "station_upright", new Vector3((float)i * (float)railStationSignFrame.PostHalfSeparation, (float)railStationSignFrame.UprightCenterY, 0f), new Vector3(0.12f, (float)railStationSignFrame.UprightHeight, 0.14f), Quaternion.identity); Cube(frame, "station_post_cap", new Vector3((float)i * (float)railStationSignFrame.PostHalfSeparation, (float)railStationSignFrame.CapCenterY, 0f), new Vector3(0.18f, 0.06f, 0.18f), Quaternion.identity, brass); } Cube(frame, "station_header", new Vector3(0f, (float)railStationSignFrame.HeaderCenterY, 0f), new Vector3((float)railStationSignFrame.HeaderWidth, 0.14f, 0.14f), Quaternion.identity, metal); for (int j = -1; j <= 1; j += 2) { Cube(frame, "station_header_stripe", new Vector3(0f, (float)railStationSignFrame.HeaderCenterY, (float)j * 0.077f), new Vector3((float)railStationSignFrame.StripeWidth, 0.035f, 0.012f), Quaternion.identity, brass, collider: false); } } private static void AddDirectionSignArrow(Transform frame, Bounds bounds, int direction) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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_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_009d: 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_00cb: Unknown result type (might be due to invalid IL or missing references) float num = ((direction > 0) ? (((Bounds)(ref bounds)).max.x + 0.035f) : (((Bounds)(ref bounds)).min.x - 0.035f)); float num2 = num + (float)direction * 0.68f; Cube(frame, "direction_shaft", new Vector3((num + num2) * 0.5f, 0f, 0f), new Vector3(Mathf.Abs(num2 - num), 0.13f, 0.1f), Quaternion.identity, brass); for (int i = -1; i <= 1; i += 2) { Cube(frame, "direction_arrowhead", new Vector3(num2 - (float)direction * 0.115f, (float)i * 0.115f, 0f), new Vector3(0.38f, 0.13f, 0.1f), Quaternion.Euler(0f, 0f, (float)(-direction * i) * 45f), brass); } } private static void AddWarningSignMarker(Transform frame, Bounds bounds) { //IL_0002: 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_0035: 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_004e: 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_007f: 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_00c5: 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_0109: Unknown result type (might be due to invalid IL or missing references) //IL_011d: 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) float num = ((Bounds)(ref bounds)).max.y + 0.48f; SignWoodBlock(frame, "warning_stem", new Vector3(0f, ((Bounds)(ref bounds)).max.y + 0.16f, 0f), new Vector3(0.1f, 0.38f, 0.12f), Quaternion.identity); Cube(frame, "warning_diamond", new Vector3(0f, num, 0f), new Vector3(0.55f, 0.55f, 0.1f), Quaternion.Euler(0f, 0f, 45f), red); for (int i = -1; i <= 1; i += 2) { Cube(frame, "warning_exclamation_bar", new Vector3(0f, num + 0.075f, (float)i * 0.058f), new Vector3(0.075f, 0.23f, 0.012f), Quaternion.identity, brass, collider: false); Cube(frame, "warning_exclamation_dot", new Vector3(0f, num - 0.12f, (float)i * 0.058f), new Vector3(0.075f, 0.075f, 0.012f), Quaternion.identity, brass, collider: false); } } private static void AddCrossingSignMarker(Transform frame, Bounds bounds) { //IL_0002: 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_0035: 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_004e: 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_008f: 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_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: 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_0136: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) float num = ((Bounds)(ref bounds)).max.y + 0.68f; SignWoodBlock(frame, "crossing_stem", new Vector3(0f, ((Bounds)(ref bounds)).max.y + 0.3f, 0f), new Vector3(0.12f, 0.66f, 0.14f), Quaternion.identity); for (int i = -1; i <= 1; i += 2) { Quaternion rotation = Quaternion.Euler(0f, 0f, (float)i * 35f); float num2 = (float)i * 0.06f; SignWoodBlock(frame, "crossing_crossbuck", new Vector3(0f, num, num2), new Vector3(1.7f, 0.22f, 0.1f), rotation, horizontal: true); for (int j = -1; j <= 1; j += 2) { Cube(frame, "crossing_crossbuck_face", new Vector3(0f, num, num2 + (float)j * 0.057f), new Vector3(1.58f, 0.13f, 0.012f), rotation, brass, collider: false); } } for (int k = -1; k <= 1; k += 2) { Cube(frame, "crossing_center_bolt", new Vector3(0f, num, (float)k * 0.13f), new Vector3(0.1f, 0.1f, 0.035f), Quaternion.Euler(0f, 0f, 45f), metal, collider: false); } } private static void InitializeNativeSignWood(ZNetScene scene) { //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011c: 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_0138: 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_015e: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: 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_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) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) CleanupNativeSignWood(); try { GameObject prefab = scene.GetPrefab("wood_pole2"); WearNTear val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent() : null); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.m_new) || !val.m_new.transform.IsChildOf(prefab.transform)) { throw new InvalidOperationException("The native wood_pole2 new-state model is unavailable."); } MeshFilter[] componentsInChildren = val.m_new.GetComponentsInChildren(true); if (componentsInChildren.Length != 1 || !Object.op_Implicit((Object)(object)componentsInChildren[0].sharedMesh)) { throw new InvalidOperationException("The native wood pole no longer has one supported wood mesh."); } MeshFilter val2 = componentsInChildren[0]; MeshRenderer component = ((Component)val2).GetComponent(); Material[] array = (Object.op_Implicit((Object)(object)component) ? ((Renderer)component).sharedMaterials : Array.Empty()); if (val2.sharedMesh.subMeshCount != 1 || array.Length != 1 || !Object.op_Implicit((Object)(object)array[0]) || !Object.op_Implicit((Object)(object)array[0].shader) || !array[0].HasProperty("_MainTex") || !Object.op_Implicit((Object)(object)array[0].GetTexture("_MainTex"))) { throw new InvalidOperationException("The native wood pole material or texture is unavailable."); } Bounds bounds = val2.sharedMesh.bounds; if (!FiniteSignWoodVector(((Bounds)(ref bounds)).center) || !FiniteSignWoodVector(((Bounds)(ref bounds)).size) || ((Bounds)(ref bounds)).size.x <= 0.001f || ((Bounds)(ref bounds)).size.y <= 0.001f || ((Bounds)(ref bounds)).size.z <= 0.001f) { throw new InvalidOperationException("The native wood pole mesh bounds are invalid."); } nativeSignWoodMaterial = CopyMaterial(array[0], "VikingRail_SignNativeWood", null); SetMaterialFloat(nativeSignWoodMaterial, "_RippleDistance", 0f); nativeSignWoodUpright = Quaternion.Inverse(prefab.transform.rotation) * ((Component)val2).transform.rotation; nativeSignWoodMesh = val2.sharedMesh; } catch (Exception ex) { CleanupNativeSignWood(); RailPlugin.Warn("Native wood for railway sign framing is unavailable; retaining the generated wood grain. " + ex.GetBaseException().Message); } } private static bool FiniteSignWoodVector(Vector3 value) { //IL_0000: 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_001a: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!float.IsNaN(value.x) && !float.IsInfinity(value.x) && !float.IsNaN(value.y) && !float.IsInfinity(value.y) && !float.IsNaN(value.z)) { return !float.IsInfinity(value.z); } return false; } private static GameObject SignWoodBlock(Transform parent, string name, Vector3 position, Vector3 size, Quaternion rotation, bool horizontal = false) { //IL_001a: 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_002c: 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_0046: 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_005d: 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_0086: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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_009e: 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_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_0123: 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_014c: Unknown result type (might be due to invalid IL or missing references) //IL_015e: 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_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: 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_00c6: 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_00d0: 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_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_00ed: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)nativeSignWoodMesh) || !Object.op_Implicit((Object)(object)nativeSignWoodMaterial)) { return Cube(parent, name, position, size, rotation, wood); } GameObject val = Child(parent, name, position); val.transform.localRotation = rotation; val.transform.localScale = size; BoxCollider obj = val.AddComponent(); obj.center = Vector3.zero; obj.size = Vector3.one; Quaternion val2 = (horizontal ? (Quaternion.Euler(0f, 0f, -90f) * nativeSignWoodUpright) : nativeSignWoodUpright); Bounds bounds = nativeSignWoodMesh.bounds; Bounds val3 = default(Bounds); ((Bounds)(ref val3))..ctor(val2 * ((Bounds)(ref bounds)).center, Vector3.zero); for (int i = -1; i <= 1; i += 2) { for (int j = -1; j <= 1; j += 2) { for (int k = -1; k <= 1; k += 2) { ((Bounds)(ref val3)).Encapsulate(val2 * (((Bounds)(ref bounds)).center + Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3((float)i, (float)j, (float)k)))); } } } GameObject obj2 = Child(val.transform, "native_wood_fit", Vector3.zero); obj2.transform.localScale = new Vector3(1f / ((Bounds)(ref val3)).size.x, 1f / ((Bounds)(ref val3)).size.y, 1f / ((Bounds)(ref val3)).size.z); GameObject obj3 = Child(obj2.transform, "native_wood_surface", -((Bounds)(ref val3)).center); obj3.transform.localRotation = val2; obj3.AddComponent().sharedMesh = nativeSignWoodMesh; ((Renderer)obj3.AddComponent()).sharedMaterial = nativeSignWoodMaterial; return val; } private static void CleanupNativeSignWood() { //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) nativeSignWoodMesh = null; nativeSignWoodMaterial = null; nativeSignWoodUpright = Quaternion.identity; } private static void AddLocomotiveVisual(Transform visual) { //IL_0019: 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_006b: 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_009c: Expected O, but got Unknown //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: 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_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0241: 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) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_03a7: Unknown result type (might be due to invalid IL or missing references) //IL_03bb: Unknown result type (might be due to invalid IL or missing references) //IL_03cf: Unknown result type (might be due to invalid IL or missing references) //IL_03f1: Unknown result type (might be due to invalid IL or missing references) //IL_0405: Unknown result type (might be due to invalid IL or missing references) //IL_0419: Unknown result type (might be due to invalid IL or missing references) //IL_043f: Unknown result type (might be due to invalid IL or missing references) //IL_0453: Unknown result type (might be due to invalid IL or missing references) //IL_0458: Unknown result type (might be due to invalid IL or missing references) //IL_0483: Unknown result type (might be due to invalid IL or missing references) //IL_0497: Unknown result type (might be due to invalid IL or missing references) //IL_049c: Unknown result type (might be due to invalid IL or missing references) //IL_04ce: Unknown result type (might be due to invalid IL or missing references) //IL_04e2: Unknown result type (might be due to invalid IL or missing references) //IL_04e7: Unknown result type (might be due to invalid IL or missing references) //IL_050e: Unknown result type (might be due to invalid IL or missing references) //IL_0522: Unknown result type (might be due to invalid IL or missing references) //IL_0527: Unknown result type (might be due to invalid IL or missing references) //IL_054a: Unknown result type (might be due to invalid IL or missing references) //IL_055e: Unknown result type (might be due to invalid IL or missing references) //IL_0563: Unknown result type (might be due to invalid IL or missing references) //IL_0586: Unknown result type (might be due to invalid IL or missing references) //IL_059a: Unknown result type (might be due to invalid IL or missing references) //IL_059f: Unknown result type (might be due to invalid IL or missing references) //IL_05c6: Unknown result type (might be due to invalid IL or missing references) //IL_05da: Unknown result type (might be due to invalid IL or missing references) //IL_05df: Unknown result type (might be due to invalid IL or missing references) //IL_0602: Unknown result type (might be due to invalid IL or missing references) //IL_0616: Unknown result type (might be due to invalid IL or missing references) //IL_061b: Unknown result type (might be due to invalid IL or missing references) //IL_0642: Unknown result type (might be due to invalid IL or missing references) //IL_0656: Unknown result type (might be due to invalid IL or missing references) //IL_065b: Unknown result type (might be due to invalid IL or missing references) //IL_0682: Unknown result type (might be due to invalid IL or missing references) //IL_0696: Unknown result type (might be due to invalid IL or missing references) //IL_069b: Unknown result type (might be due to invalid IL or missing references) //IL_06bd: Unknown result type (might be due to invalid IL or missing references) //IL_06d1: Unknown result type (might be due to invalid IL or missing references) //IL_06d6: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_0360: Unknown result type (might be due to invalid IL or missing references) //IL_0703: Unknown result type (might be due to invalid IL or missing references) //IL_071b: Unknown result type (might be due to invalid IL or missing references) //IL_0743: Unknown result type (might be due to invalid IL or missing references) //IL_075b: Unknown result type (might be due to invalid IL or missing references) //IL_0789: Unknown result type (might be due to invalid IL or missing references) //IL_079d: Unknown result type (might be due to invalid IL or missing references) //IL_07b1: Unknown result type (might be due to invalid IL or missing references) //IL_07d8: Unknown result type (might be due to invalid IL or missing references) //IL_07ec: Unknown result type (might be due to invalid IL or missing references) //IL_0800: Unknown result type (might be due to invalid IL or missing references) //IL_082a: Unknown result type (might be due to invalid IL or missing references) //IL_083e: Unknown result type (might be due to invalid IL or missing references) //IL_0843: Unknown result type (might be due to invalid IL or missing references) //IL_0935: Unknown result type (might be due to invalid IL or missing references) //IL_0949: Unknown result type (might be due to invalid IL or missing references) //IL_094e: Unknown result type (might be due to invalid IL or missing references) //IL_0970: Unknown result type (might be due to invalid IL or missing references) //IL_09a6: Unknown result type (might be due to invalid IL or missing references) //IL_09ba: Unknown result type (might be due to invalid IL or missing references) //IL_09bf: Unknown result type (might be due to invalid IL or missing references) //IL_09e1: Unknown result type (might be due to invalid IL or missing references) //IL_09f5: Unknown result type (might be due to invalid IL or missing references) //IL_09fa: Unknown result type (might be due to invalid IL or missing references) //IL_0a20: Unknown result type (might be due to invalid IL or missing references) //IL_0a34: Unknown result type (might be due to invalid IL or missing references) //IL_0a39: Unknown result type (might be due to invalid IL or missing references) //IL_0a85: Unknown result type (might be due to invalid IL or missing references) //IL_0a99: Unknown result type (might be due to invalid IL or missing references) //IL_0aaf: Unknown result type (might be due to invalid IL or missing references) //IL_0881: Unknown result type (might be due to invalid IL or missing references) //IL_0896: Unknown result type (might be due to invalid IL or missing references) //IL_08aa: Unknown result type (might be due to invalid IL or missing references) //IL_08af: Unknown result type (might be due to invalid IL or missing references) //IL_08d9: Unknown result type (might be due to invalid IL or missing references) //IL_08ed: Unknown result type (might be due to invalid IL or missing references) //IL_0901: Unknown result type (might be due to invalid IL or missing references) //IL_0aeb: Unknown result type (might be due to invalid IL or missing references) //IL_0aff: Unknown result type (might be due to invalid IL or missing references) //IL_0b04: Unknown result type (might be due to invalid IL or missing references) //IL_0b30: Unknown result type (might be due to invalid IL or missing references) //IL_0b44: Unknown result type (might be due to invalid IL or missing references) //IL_0b6e: Unknown result type (might be due to invalid IL or missing references) //IL_0b82: Unknown result type (might be due to invalid IL or missing references) //IL_0b96: Unknown result type (might be due to invalid IL or missing references) //IL_0bbd: Unknown result type (might be due to invalid IL or missing references) //IL_0bd1: Unknown result type (might be due to invalid IL or missing references) //IL_0be5: Unknown result type (might be due to invalid IL or missing references) //IL_0c07: Unknown result type (might be due to invalid IL or missing references) //IL_0c1b: Unknown result type (might be due to invalid IL or missing references) //IL_0c2f: Unknown result type (might be due to invalid IL or missing references) //IL_0c51: Unknown result type (might be due to invalid IL or missing references) //IL_0c65: Unknown result type (might be due to invalid IL or missing references) //IL_0c79: Unknown result type (might be due to invalid IL or missing references) //IL_0c9c: Unknown result type (might be due to invalid IL or missing references) //IL_0cb0: Unknown result type (might be due to invalid IL or missing references) //IL_0cb5: Unknown result type (might be due to invalid IL or missing references) Material val = CopyMaterial(metal, "VikingRail_SteamIron", (Color?)new Color(0.25f, 0.3f, 0.32f)); Material val2 = CopyMaterial(metal, "VikingRail_SteamRecess", (Color?)new Color(0.1f, 0.13f, 0.14f)); Material material = CopyMaterial(wood, "VikingRail_SteamDial", (Color?)new Color(0.83f, 0.77f, 0.6f)); SetSurfaceTexture(material, (Texture)(object)Texture2D.whiteTexture); foreach (Transform item in visual) { Transform val3 = item; if (!(((Object)val3).name != "chassis")) { Renderer component = ((Component)val3).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { component.sharedMaterial = val; } } } AddSteamRunningGear(visual, val, val2); for (int i = -1; i <= 1; i += 2) { Cube(visual, "steam_deck_edge", new Vector3((float)i * 0.805f, 0.76f, 0f), new Vector3(0.04f, 0.1f, 2.12f), Quaternion.identity, val, collider: false); Cube(visual, "boiler_saddle", new Vector3(0f, 0.93f, 0.4f + (float)i * 0.35f), new Vector3(0.85f, 0.14f, 0.17f), Quaternion.identity, val); } Cube(visual, "steam_firebox", new Vector3(0f, 1.045f, 0.39f), new Vector3(0.78f, 0.3f, 1.15f), Quaternion.identity, val); Primitive(visual, "steam_boiler", (PrimitiveType)2, new Vector3(0f, 1.43f, 0.4f), new Vector3(0.86f, 0.58f, 0.86f), Quaternion.Euler(90f, 0f, 0f), val, collider: true); float[] array = new float[3] { -0.1f, 0.4f, 0.9f }; foreach (float num in array) { Primitive(visual, "steam_boiler_band", (PrimitiveType)2, new Vector3(0f, 1.43f, num), new Vector3(0.9f, 0.026f, 0.9f), Quaternion.Euler(90f, 0f, 0f), brass, collider: false); } array = new float[2] { -0.197f, 0.997f }; foreach (float num2 in array) { Primitive(visual, "steam_boiler_end", (PrimitiveType)2, new Vector3(0f, 1.43f, num2), new Vector3(0.81f, 0.016f, 0.81f), Quaternion.Euler(90f, 0f, 0f), val2, collider: false); for (int k = 0; k < 12; k++) { float num3 = (float)k * (float)Math.PI / 6f; Primitive(visual, "steam_boiler_rivet", (PrimitiveType)0, new Vector3(Mathf.Sin(num3) * 0.36f, 1.43f + Mathf.Cos(num3) * 0.36f, num2 + ((num2 > 0f) ? 0.022f : (-0.022f))), Vector3.one * 0.048f, Quaternion.identity, brass, collider: false); } } Primitive(visual, "steam_front_door", (PrimitiveType)2, new Vector3(0f, 1.43f, 1.022f), new Vector3(0.56f, 0.015f, 0.56f), Quaternion.Euler(90f, 0f, 0f), val, collider: false); Cube(visual, "steam_door_latch", new Vector3(0f, 1.4f, 1.045f), new Vector3(0.29f, 0.048f, 0.035f), Quaternion.Euler(0f, 0f, 18f), brass, collider: false); Cube(visual, "steam_firebox_door", new Vector3(0f, 1.09f, -0.194f), new Vector3(0.48f, 0.23f, 0.027f), Quaternion.identity, val2, collider: false); for (int l = -1; l <= 1; l++) { Cube(visual, "steam_firebox_vent", new Vector3((float)l * 0.11f, 1.09f, -0.212f), new Vector3(0.045f, 0.13f, 0.013f), Quaternion.identity, brass, collider: false); } Primitive(visual, "steam_stack_collar", (PrimitiveType)2, new Vector3(0f, 1.85f, 0.78f), new Vector3(0.35f, 0.045f, 0.35f), Quaternion.identity, brass, collider: false); Primitive(visual, "chimney", (PrimitiveType)2, new Vector3(0f, 2.18f, 0.78f), new Vector3(0.25f, 0.3f, 0.25f), Quaternion.identity, val, collider: true); Primitive(visual, "steam_stack_flare", (PrimitiveType)2, new Vector3(0f, 2.48f, 0.78f), new Vector3(0.32f, 0.065f, 0.32f), Quaternion.identity, val, collider: false); Primitive(visual, "chimney_rim", (PrimitiveType)2, new Vector3(0f, 2.57f, 0.78f), new Vector3(0.39f, 0.035f, 0.39f), Quaternion.identity, brass, collider: false); Primitive(visual, "steam_stack_mouth", (PrimitiveType)2, new Vector3(0f, 2.607f, 0.78f), new Vector3(0.29f, 0.004f, 0.29f), Quaternion.identity, val2, collider: false); Primitive(visual, "steam_dome_base", (PrimitiveType)2, new Vector3(0f, 1.88f, 0.13f), new Vector3(0.36f, 0.065f, 0.36f), Quaternion.identity, brass, collider: false); Primitive(visual, "steam_dome", (PrimitiveType)0, new Vector3(0f, 1.98f, 0.13f), new Vector3(0.35f, 0.29f, 0.35f), Quaternion.identity, brass, collider: false); Primitive(visual, "steam_safety_valve", (PrimitiveType)2, new Vector3(0f, 2.15f, 0.13f), new Vector3(0.09f, 0.07f, 0.09f), Quaternion.identity, val, collider: false); Cube(visual, "steam_valve_cap", new Vector3(0f, 2.22f, 0.13f), new Vector3(0.18f, 0.035f, 0.05f), Quaternion.identity, brass, collider: false); for (int m = -1; m <= 1; m += 2) { SteamPipe(visual, new Vector3((float)m * 0.445f, 1.63f, -0.05f), new Vector3((float)m * 0.445f, 1.63f, 0.79f), 0.035f, brass); SteamPipe(visual, new Vector3((float)m * 0.445f, 1.63f, 0.79f), new Vector3((float)m * 0.6f, 1.085f, 0.79f), 0.04f, brass); Primitive(visual, "steam_cylinder", (PrimitiveType)2, new Vector3((float)m * 0.62f, 1.035f, 0.86f), new Vector3(0.16f, 0.12f, 0.16f), Quaternion.Euler(90f, 0f, 0f), val, collider: true); Primitive(visual, "steam_cylinder_ring", (PrimitiveType)2, new Vector3((float)m * 0.62f, 1.035f, 0.97f), new Vector3(0.18f, 0.018f, 0.18f), Quaternion.Euler(90f, 0f, 0f), brass, collider: false); Cube(visual, "steam_slide_guide", new Vector3((float)m * 0.64f, 0.875f, 0.6f), new Vector3(0.13f, 0.055f, 0.4f), Quaternion.identity, val, collider: false); GameObject obj = Child(visual, (m < 0) ? "vr_steam_piston_left" : "vr_steam_piston_right", new Vector3((float)m * 0.64f, 0.925f, (m < 0) ? 0.63f : 0.75f)); Cube(obj.transform, "steam_crosshead", Vector3.zero, new Vector3(0.12f, 0.075f, 0.11f), Quaternion.identity, brass, collider: false); Cube(obj.transform, "steam_piston_shaft", new Vector3(0f, 0.055f, 0.12f), new Vector3(0.035f, 0.035f, 0.3f), Quaternion.Euler(-16f, 0f, 0f), metal, collider: false); } Cube(visual, "steam_flywheel_bracket", new Vector3(-0.48f, 1.09f, 0.28f), new Vector3(0.15f, 0.37f, 0.16f), Quaternion.identity, val, collider: false); SteamWheelFace(Child(visual, "vr_steam_flywheel", new Vector3(-0.565f, 1.33f, 0.28f)).transform, -1, 0.54f, 0.042f, val, val2); Cube(visual, "steam_coal_bunker", new Vector3(0.625f, 1.1f, -0.55f), new Vector3(0.35f, 0.48f, 0.63f), Quaternion.identity, val); Cube(visual, "steam_bunker_rim", new Vector3(0.625f, 1.35f, -0.55f), new Vector3(0.39f, 0.045f, 0.67f), Quaternion.identity, brass, collider: false); Cube(visual, "steam_bunker_inset", new Vector3(0.625f, 1.375f, -0.55f), new Vector3(0.3f, 0.012f, 0.57f), Quaternion.identity, val2, collider: false); for (int n = 0; n < 6; n++) { Primitive(visual, "steam_coal", (PrimitiveType)0, new Vector3(0.55f + (float)(n % 2) * 0.14f, 1.39f + (float)(n % 3) * 0.012f, -0.74f + (float)(n / 2) * 0.17f), new Vector3(0.14f, 0.09f, 0.15f), Quaternion.Euler(0f, (float)(n * 33), (float)(n * 17)), val2, collider: false); } for (int num4 = -1; num4 <= 1; num4 += 2) { Cube(visual, "steam_bunker_band", new Vector3(0.625f, 1.1f, -0.55f + (float)num4 * 0.22f), new Vector3(0.368f, 0.045f, 0.045f), Quaternion.identity, brass, collider: false); } SteamPipe(visual, new Vector3(-0.24f, 1.47f, -0.205f), new Vector3(-0.24f, 1.76f, -0.205f), 0.04f, brass); Primitive(visual, "steam_gauge_case", (PrimitiveType)2, new Vector3(-0.24f, 1.76f, -0.205f), new Vector3(0.23f, 0.019f, 0.23f), Quaternion.Euler(90f, 0f, 0f), brass, collider: false); Primitive(visual, "steam_gauge_face", (PrimitiveType)2, new Vector3(-0.24f, 1.76f, -0.226f), new Vector3(0.18f, 0.003f, 0.18f), Quaternion.Euler(90f, 0f, 0f), material, collider: false); Cube(visual, "steam_gauge_needle", new Vector3(-0.263f, 1.79f, -0.231f), new Vector3(0.012f, 0.085f, 0.008f), Quaternion.Euler(0f, 0f, 37f), val2, collider: false); Cube(visual, "throttle_stem", new Vector3(-0.44f, 1.27f, -0.18f), new Vector3(0.08f, 0.67f, 0.08f), Quaternion.Euler(-16f, 0f, 0f), val, collider: false); Primitive(visual, "throttle_grip", (PrimitiveType)0, new Vector3(-0.44f, 1.59f, -0.27f), new Vector3(0.17f, 0.17f, 0.17f), Quaternion.identity, brass, collider: false); } private static void AddSteamRunningGear(Transform visual, Material iron, Material dark) { //IL_0050: 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) //IL_00a8: 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_00e7: 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_0146: Unknown result type (might be due to invalid IL or missing references) //IL_015a: 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_0194: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: 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) for (int i = -1; i <= 1; i += 2) { string text = ((i < 0) ? "left" : "right"); for (int j = -1; j <= 1; j += 2) { GameObject val = Child(visual, "vr_steam_wheel_" + text + ((j > 0) ? "_front" : "_rear"), new Vector3((float)i * 0.7f, 0.44f, (float)j * 0.68f)); SteamWheelFace(val.transform, i, 0.56f, 0.075f, iron, dark); Primitive(val.transform, "steam_crank_pin", (PrimitiveType)2, new Vector3((float)i * 0.105f, 0.12f, 0f), new Vector3(0.075f, 0.025f, 0.075f), Quaternion.Euler(0f, 0f, 90f), brass, collider: false); if (i > 0) { val.transform.localRotation = Quaternion.Euler(90f, 0f, 0f); } } GameObject val2 = Child(visual, "vr_steam_rod_" + text, new Vector3((float)i * 0.805f, (i < 0) ? 0.56f : 0.44f, (i < 0) ? 0f : 0.12f)); Cube(val2.transform, "steam_coupling_rod", Vector3.zero, new Vector3(0.045f, 0.055f, 1.36f), Quaternion.identity, brass, collider: false); for (int k = -1; k <= 1; k += 2) { Primitive(val2.transform, "steam_rod_bearing", (PrimitiveType)2, new Vector3(0f, 0f, (float)k * 0.68f), new Vector3(0.105f, 0.03f, 0.105f), Quaternion.Euler(0f, 0f, 90f), iron, collider: false); } } } private static void SteamWheelFace(Transform pivot, int side, float diameter, float thickness, Material iron, Material dark) { //IL_0007: 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_0023: 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_0064: 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_00a4: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_0102: 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_012a: Unknown result type (might be due to invalid IL or missing references) Primitive(pivot, "steam_wheel_rim", (PrimitiveType)2, Vector3.zero, new Vector3(diameter, thickness, diameter), Quaternion.Euler(0f, 0f, 90f), iron, collider: false); Primitive(pivot, "steam_wheel_face", (PrimitiveType)2, new Vector3((float)side * (thickness + 0.004f), 0f, 0f), new Vector3(diameter * 0.79f, 0.006f, diameter * 0.79f), Quaternion.Euler(0f, 0f, 90f), dark, collider: false); for (int i = 0; i < 4; i++) { Cube(pivot, "steam_wheel_spoke", new Vector3((float)side * (thickness + 0.013f), 0f, 0f), new Vector3(0.023f, 0.038f, diameter * 0.82f), Quaternion.Euler((float)(i * 45), 0f, 0f), brass, collider: false); } Primitive(pivot, "steam_wheel_hub", (PrimitiveType)2, new Vector3((float)side * (thickness + 0.03f), 0f, 0f), new Vector3(0.13f, 0.021f, 0.13f), Quaternion.Euler(0f, 0f, 90f), brass, collider: false); } private static void SteamPipe(Transform visual, Vector3 from, Vector3 to, float width, Material material) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_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_0011: 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_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_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) Vector3 val = to - from; Primitive(visual, "steam_pipe", (PrimitiveType)2, (from + to) * 0.5f, new Vector3(width, ((Vector3)(ref val)).magnitude * 0.5f, width), Quaternion.FromToRotation(Vector3.up, ((Vector3)(ref val)).normalized), material, collider: false); } private static void CreateSteepTracks(GameObject floor) { //IL_00bb: 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_00d1: Unknown result type (might be due to invalid IL or missing references) foreach (RailSteepTrackDefinition item in RailSteepTracks.All) { Vector3[] array = Array.ConvertAll(item.Points(), RailSegment.ToUnity); string title = (item.LightDuty ? "Wooden track" : "Rail track") + (item.Long ? " — long steep incline" : " — steep incline"); string text = (item.Long ? "Rises 6 m over 12 m at a 1:2 grade, twice as steep as the regular incline. Uses Fine Wood." : "Rises 2 m over 4 m at a 1:2 grade, twice as steep as the regular incline."); text += " Connect to flat track through a regular incline. Support elevated rails with beams or a bridge."; if (item.LightDuty) { text += " For handcarts, bronze engines and wagons; coal and Eitr engines require metal rails."; } CreateTrack(floor, item.PrefabName, title, text, array, RailSectionKind.Normal, item.LightDuty, null, (array[0] + array[1]) * 0.5f); } } private static void CreateRailSwitch(GameObject floor, bool lightDuty = false) { //IL_004c: 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_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_0105: 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_01c7: 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_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) GameObject val = CloneBase(floor, lightDuty ? "vr_track_wood_switch" : "vr_track_switch", keepContainer: false, floor); ConfigurePiece(val.GetComponent(), lightDuty ? "Wooden track — Y switch" : "Rail track — Y switch", lightDuty ? "A wooden junction with two 45 degree exits for handcarts, bronze engines and wagons. Cannot support coal and Eitr engines. Use the lever to choose left or right; clear the entire train before switching." : "A metal junction with two 45 degree exits. Use the lever beside the entrance to choose left or right; clear the entire train before switching."); GameObject val2 = Child(val.transform, "visual", Vector3.zero); Vector3[] array = (Vector3[])(object)new Vector3[2] { new Vector3(0f, 0f, -2f), Vector3.zero }; Vector3[] array2 = SwitchBranch(-1f); Vector3[] array3 = SwitchBranch(1f); Material railMaterial = (lightDuty ? wood : metal); AddSwitchRails(val2.transform, array, railMaterial); AddSwitchRails(val2.transform, array2, railMaterial); AddSwitchRails(val2.transform, array3, railMaterial); for (int i = 0; i < 4; i++) { float num = -1.75f + (float)i * 0.5f; Cube(val2.transform, "sleeper", new Vector3(0f, 0.02f, num), new Vector3(1.9f, 0.12f, 0.2f), Quaternion.identity, wood); if (lightDuty) { AddSwitchNails(val2.transform, array, num); } } float z = array3[^1].z; int num2 = Mathf.CeilToInt(z / 0.5f); for (int j = 0; j < num2; j++) { float num3 = z * ((float)j + 0.5f) / (float)num2; float num4 = Mathf.Sqrt(1f - num3 * num3 / 64f); float num5 = 8f * (1f - num4); Cube(val2.transform, "switch_sleeper", new Vector3(0f, 0.02f, num3), new Vector3(2f * num5 + 1.9f * num4, 0.12f, 0.2f), Quaternion.identity, wood); if (lightDuty) { AddSwitchNails(val2.transform, array2, num3); AddSwitchNails(val2.transform, array3, num3); } } AddSnap(val.transform, "snap_start", array[0]); AddSnap(val.transform, "snap_left", array2[^1]); AddSnap(val.transform, "snap_right", array3[^1]); RailSwitch railSwitch = val.AddComponent(); railSwitch.TrunkPoints = array; railSwitch.LeftPoints = array2; railSwitch.RightPoints = array3; railSwitch.LightDuty = lightDuty; AddSwitchLever(val2.transform, railSwitch); ConfigureWear(val, val2, track: true); RailTerrainPlacement.Configure(val); RailTrackSupport.Configure(val); Prefabs.Add(val); } private static Vector3[] SwitchBranch(float side) { //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) Vector3[] array = (Vector3[])(object)new Vector3[17]; for (int i = 0; i < array.Length; i++) { float num = (float)Math.PI / 4f * (float)i / (float)(array.Length - 1); array[i] = new Vector3(side * 8f * (1f - Mathf.Cos(num)), 0f, 8f * Mathf.Sin(num)); } return array; } private static void AddSwitchRails(Transform parent, Vector3[] points, Material railMaterial) { //IL_000b: 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_0017: 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_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) //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_0030: 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_003e: 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_0057: 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_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_0072: 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_0082: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < points.Length - 1; i++) { Vector3 val = points[i + 1] - points[i]; Vector3 normalized = ((Vector3)(ref val)).normalized; val = Vector3.Cross(Vector3.up, normalized); Vector3 normalized2 = ((Vector3)(ref val)).normalized; for (int j = -1; j <= 1; j += 2) { Vector3 val2 = normalized2 * ((float)j * 0.7f) + Vector3.up * 0.115f; Beam(parent, "switch_rail", points[i] + val2, points[i + 1] + val2, 0.095f, 0.09f, railMaterial); } } } private static void AddSwitchNails(Transform parent, Vector3[] points, float sleeperZ) { //IL_0012: 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_0023: 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_002c: 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_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_003c: 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_004e: Unknown result type (might be due to invalid IL or missing references) //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_0057: 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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_006d: 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_007a: 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_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0090: 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_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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_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_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: 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_00dd: Unknown result type (might be due to invalid IL or missing references) for (int i = -1; i <= 1; i += 2) { for (int j = 0; j < points.Length - 1; j++) { Vector3 val = points[j + 1] - points[j]; Vector3 normalized = ((Vector3)(ref val)).normalized; val = Vector3.Cross(Vector3.up, normalized); Vector3 val2 = ((Vector3)(ref val)).normalized * ((float)i * 0.7f); Vector3 val3 = points[j] + val2; Vector3 val4 = points[j + 1] + val2; if (!(sleeperZ < val3.z) && !(sleeperZ > val4.z)) { Vector3 val5 = Vector3.Lerp(val3, val4, (sleeperZ - val3.z) / (val4.z - val3.z)); Cube(parent, "bronze_nail", val5 + Vector3.up * 0.169f, new Vector3(0.065f, 0.025f, 0.065f), Quaternion.LookRotation(normalized, Vector3.up), brass, collider: false); break; } } } } private static void AddSwitchLever(Transform parent, RailSwitch railSwitch) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_00a5: 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_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: 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_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_0168: Unknown result type (might be due to invalid IL or missing references) //IL_017c: 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_019d: 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_01d6: Unknown result type (might be due to invalid IL or missing references) Material material = (railSwitch.LightDuty ? wood : metal); Cube(parent, "switch_lever_foot", new Vector3(-1.6f, 0.1f, -1f), new Vector3(0.55f, 0.2f, 0.55f), Quaternion.identity, material); Cube(parent, "switch_lever_post", new Vector3(-1.6f, 0.45f, -1f), new Vector3(0.14f, 0.6f, 0.14f), Quaternion.identity, wood, collider: false); Primitive(parent, "switch_lever_axle", (PrimitiveType)2, new Vector3(-1.6f, 0.72f, -1f), new Vector3(0.2f, 0.13f, 0.2f), Quaternion.Euler(90f, 0f, 0f), railSwitch.LightDuty ? brass : metal, collider: false); GameObject val = Child(parent, "vr_switch_lever", new Vector3(-1.6f, 0.72f, -1f)); Cube(val.transform, "switch_lever_rod", new Vector3(0f, 0.32f, 0f), new Vector3(0.08f, 0.64f, 0.08f), Quaternion.identity, material, collider: false); Primitive(val.transform, "switch_lever_grip", (PrimitiveType)0, new Vector3(0f, 0.68f, 0f), new Vector3(0.23f, 0.23f, 0.23f), Quaternion.identity, red, collider: false); GameObject obj = Child(val.transform, "vr_switch_handle", Vector3.zero); BoxCollider obj2 = obj.AddComponent(); obj2.center = new Vector3(0f, 0.35f, 0f); obj2.size = new Vector3(0.24f, 0.85f, 0.4f); obj.AddComponent().Switch = railSwitch; railSwitch.Lever = val.transform; } private static void CreateTandemHandcart(GameObject cart, GameObject floor) { //IL_002e: 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_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_00ae: 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_00d6: 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_0117: Unknown result type (might be due to invalid IL or missing references) //IL_012b: 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_0167: 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_0216: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_034e: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) GameObject val = CloneBase(cart, "vr_handcart_tandem", keepContainer: false, floor); ConfigurePiece(val.GetComponent(), "Two-person rail handcart", "A handcart with two opposed pumping positions. Use the rear handle to drive; a second player can use the front handle to help pump. Jump to dismount."); GameObject val2 = Child(val.transform, "visual", Vector3.zero); AddWorkshopChassis(val2.transform); ExtendTandemDeck(val2.transform); Cube(val2.transform, "pump_post", new Vector3(0f, 1.215f, 0f), new Vector3(0.14f, 0.71f, 0.14f), Quaternion.identity, wood); Primitive(val2.transform, "pump_pivot", (PrimitiveType)2, new Vector3(0f, 1.57f, 0f), new Vector3(0.22f, 0.11f, 0.22f), Quaternion.Euler(0f, 0f, 90f), brass, collider: false); GameObject val3 = Child(val.transform, "vr_pump", new Vector3(0f, 1.57f, 0f)); Cube(val3.transform, "pump_lever", Vector3.zero, new Vector3(0.12f, 0.1f, 0.8f), Quaternion.identity, wood, collider: false); for (int i = -1; i <= 1; i += 2) { Cube(val3.transform, "pump_handle", new Vector3(0f, 0f, (float)i * 0.4f), new Vector3(1.25f, 0.1f, 0.12f), Quaternion.identity, wood, collider: false); if (i > 0) { for (int j = -1; j <= 1; j += 2) { Cube(val3.transform, "helper_grip", new Vector3((float)j * 0.47f, 0f, 0.4f), new Vector3(0.16f, 0.115f, 0.13f), Quaternion.identity, brass, collider: false); } } } Child(val.transform, "vr_driver", new Vector3(0f, 1f, -0.95f)); GameObject val4 = Child(val.transform, "vr_pump_partner_attach", new Vector3(0f, 1f, 0.95f)); val4.transform.localRotation = Quaternion.Euler(0f, 180f, 0f); Rigidbody obj = val.GetComponent() ?? val.AddComponent(); obj.isKinematic = true; obj.useGravity = false; obj.mass = 120f; ZSyncTransform obj2 = val.GetComponent() ?? val.AddComponent(); obj2.m_syncPosition = true; obj2.m_syncRotation = true; obj2.m_syncScale = false; obj2.m_syncBodyVelocity = false; obj2.m_characterParentSync = false; val.GetComponent().m_type = (ObjectType)0; ConfigureWear(val, val2, track: false); RailVehicle railVehicle = val.AddComponent(); railVehicle.IsEngine = true; railVehicle.CoalPowered = false; railVehicle.IsTandemHandcart = true; AddTandemPumpTarget(val3.transform, "vr_tandem_driver", -0.4f).AddComponent().Vehicle = railVehicle; RailPumpPartner railPumpPartner = AddTandemPumpTarget(val3.transform, "vr_tandem_partner", 0.4f).AddComponent(); railPumpPartner.AttachPoint = val4.transform; railPumpPartner.DetachOffset = new Vector3(1.4f, 0.2f, 0f); AddVehicleLights(val, val2.transform, engine: true); AddPackingHandle(val2.transform); Prefabs.Add(val); } private static GameObject AddTandemPumpTarget(Transform pump, string name, float z) { //IL_000d: 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) GameObject obj = Child(pump, name, new Vector3(0f, 0f, z)); obj.AddComponent().size = new Vector3(1.25f, 0.2f, 0.2f); return obj; } private static void ExtendTandemDeck(Transform visual) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown //IL_002b: 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_0098: 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_00a4: 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) foreach (Transform item in visual) { Transform val = item; float num2; if (((Object)val).name == "deck_plank") { float num = Mathf.Abs(val.localPosition.x); num2 = ((num > 0.5f) ? 0.89f : ((num > 0.1f) ? 1.075f : 1.25f)); } else { if (!(((Object)val).name == "chassis")) { continue; } num2 = 1.02f; } Vector3 localPosition = val.localPosition; localPosition.z = (-1.35f + num2) * 0.5f; val.localPosition = localPosition; Vector3 localScale = val.localScale; localScale.z = num2 - -1.35f; val.localScale = localScale; } } private static void CreateThreeWaySwitches(GameObject floor) { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_0326: Unknown result type (might be due to invalid IL or missing references) //IL_0343: Unknown result type (might be due to invalid IL or missing references) //IL_0360: Unknown result type (might be due to invalid IL or missing references) foreach (RailThreeWayTrackDefinition item in RailThreeWayTracks.All) { GameObject val = CloneBase(floor, item.PrefabName, keepContainer: false, floor); ConfigurePiece(val.GetComponent(), (item.LightDuty ? "Wooden track" : "Rail track") + " — three-way yard switch", "One entrance with left, straight and right exits. Use the lever to cycle routes; clear the entire junction and its approaches first." + (item.LightDuty ? " Handcarts, bronze engines and wagons only; coal and Eitr engines require iron rails." : "")); GameObject val2 = Child(val.transform, "visual", Vector3.zero); Vector3[] array = Array.ConvertAll(item.TrunkPoints(), RailSegment.ToUnity); Vector3[] array2 = Array.ConvertAll(item.LeftPoints(), RailSegment.ToUnity); Vector3[] array3 = Array.ConvertAll(item.StraightPoints(), RailSegment.ToUnity); Vector3[] array4 = Array.ConvertAll(item.RightPoints(), RailSegment.ToUnity); Material railMaterial = (item.LightDuty ? wood : metal); Vector3[][] array5 = new Vector3[4][] { array, array2, array3, array4 }; foreach (Vector3[] points in array5) { AddSwitchRails(val2.transform, points, railMaterial); } for (int j = 0; j < 4; j++) { float num = -1.75f + (float)j * 0.5f; Cube(val2.transform, "sleeper", new Vector3(0f, 0.02f, num), new Vector3(1.9f, 0.12f, 0.2f), Quaternion.identity, wood); if (item.LightDuty) { AddSwitchNails(val2.transform, array, num); } } float z = array3[1].z; int num2 = Mathf.CeilToInt(z / 0.5f); for (int k = 0; k < num2; k++) { float num3 = z * ((float)k + 0.5f) / (float)num2; float num4 = Mathf.Sqrt(1f - num3 * num3 / 64f); float num5 = 8f * (1f - num4); Cube(val2.transform, "switch_sleeper", new Vector3(0f, 0.02f, num3), new Vector3(2f * num5 + 1.9f * num4, 0.12f, 0.2f), Quaternion.identity, wood); if (item.LightDuty) { array5 = new Vector3[3][] { array2, array3, array4 }; foreach (Vector3[] points2 in array5) { AddSwitchNails(val2.transform, points2, num3); } } } AddSnap(val.transform, "snap_start", array[0]); AddSnap(val.transform, "snap_left", array2[^1]); AddSnap(val.transform, "snap_straight", array3[^1]); AddSnap(val.transform, "snap_right", array4[^1]); RailSwitch railSwitch = val.AddComponent(); railSwitch.TrunkPoints = array; railSwitch.LeftPoints = array2; railSwitch.StraightPoints = array3; railSwitch.RightPoints = array4; railSwitch.LightDuty = item.LightDuty; AddSwitchLever(val2.transform, railSwitch); ConfigureWear(val, val2, track: true); RailTerrainPlacement.Configure(val); RailTrackSupport.Configure(val); Prefabs.Add(val); } } private static void CreateRailTorch(ZNetScene scene) { //IL_0061: 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_0154: 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_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: 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_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) if (!RailTorchPlacementPatch.Compatible) { RailPlugin.Warn("Rail torch placement is unavailable on this game API; other railway pieces remain available."); return; } GameObject prefab = scene.GetPrefab("piece_groundtorch_wood"); if (!Object.op_Implicit((Object)(object)prefab) || !Object.op_Implicit((Object)(object)prefab.GetComponent())) { RailPlugin.Warn("The native wood torch is unavailable; rail torch was not registered."); return; } GameObject val = Object.Instantiate(prefab, root.transform, false); ((Object)val).name = "vr_torch"; val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; ConfigurePiece(val.GetComponent(), "Rail torch", "Ever-burning Greydwarf Eye torch for a rail vehicle or track. Aim at a parked vehicle's deck corner or either side of a track. Needs no fuel; remove with the hammer."); val.GetComponent().m_clipEverything = true; Transform[] componentsInChildren = val.GetComponentsInChildren(true); foreach (Transform val2 in componentsInChildren) { if (Object.op_Implicit((Object)(object)val2) && (Object)(object)val2 != (Object)(object)val.transform && ((Component)val2).CompareTag("snappoint")) { Object.DestroyImmediate((Object)(object)((Component)val2).gameObject); } } Fireplace component = val.GetComponent(); component.m_name = "Rail torch"; component.m_infiniteFuel = true; component.m_canTurnOff = false; component.m_startFuel = 0f; WearNTear component2 = val.GetComponent(); bool noSupportWear = component2.m_noSupportWear; component2.m_noSupportWear = false; component2.m_noRoofWear = false; component2.m_supports = false; component2.m_staticPosition = false; ZNetView component3 = val.GetComponent(); component3.m_persistent = true; component3.m_distant = false; component3.m_type = (ObjectType)0; val.AddComponent().UnmountedSupportWear = noSupportWear; RailTorchLighting.Configure(val); val.SetActive(true); Prefabs.Add(val); foreach (GameObject prefab2 in Prefabs) { if (!Object.op_Implicit((Object)(object)prefab2.GetComponent())) { AddTrackTorchSockets(prefab2); continue; } prefab2.AddComponent(); for (int j = 0; j < 4; j++) { Cube(prefab2.transform, "vr_torch_bracket_" + j, RailTorchMounts.LocalSocket(j) - Vector3.up * 0.03f, new Vector3(0.17f, 0.06f, 0.17f), Quaternion.identity, metal, collider: false); } } } private static void AddTrackTorchSockets(GameObject prefab) { //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: 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) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: 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_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0246: 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_0260: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0286: 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_028d: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_0299: 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_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02c5: 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_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)prefab.GetComponent())) { return; } RailSegment component = prefab.GetComponent(); RailSwitch component2 = prefab.GetComponent(); if (!Object.op_Implicit((Object)(object)component) && !Object.op_Implicit((Object)(object)component2)) { return; } Material material = ((Object.op_Implicit((Object)(object)component) ? component.LightDuty : component2.LightDuty) ? wood : metal); RailPath[] array; RailVector[] array2; if (Object.op_Implicit((Object)(object)component)) { array = new RailPath[1] { TorchPath(component.Points) }; array2 = RailTorchSockets.Beside(array[0]); } else { array = ((component2.ParallelExitCount != 5) ? new RailPath[2] { TorchPath(component2.LeftPoints), TorchPath(component2.RightPoints) } : new RailPath[2] { TorchPath(component2.OuterLeftPoints), TorchPath(component2.OuterRightPoints) }); if (array[0].Sample(array[0].Length * 0.5).Position.X > array[1].Sample(array[1].Length * 0.5).Position.X) { array = new RailPath[2] { array[1], array[0] }; } array2 = RailTorchSockets.OutsideJunction(array[0], array[1]); } RailTorchMounts railTorchMounts = prefab.AddComponent(); railTorchMounts.TrackSockets = (Vector3[])(object)new Vector3[array2.Length]; Transform parent = prefab.transform.Find("visual") ?? prefab.transform; for (int i = 0; i < array2.Length; i++) { Vector3 val = RailSegment.ToUnity(array2[i]); railTorchMounts.TrackSockets[i] = val; Vector3 val2 = RailSegment.ToUnity(array[(array.Length != 1) ? i : 0].Sample(array[(array.Length != 1) ? i : 0].Length * 0.5).Position); Vector3 val3 = Vector3.ProjectOnPlane(val - val2, Vector3.up); Vector3 normalized = ((Vector3)(ref val3)).normalized; Vector3 val4 = val2 + normalized * 0.85f + Vector3.up * 0.04f; Vector3 val5 = val - Vector3.up * 0.08f; Cube(parent, "vr_track_torch_arm_" + i, (val4 + val5) * 0.5f, new Vector3(0.12f, 0.07f, Vector3.Distance(val4, val5)), Quaternion.LookRotation(val5 - val4, Vector3.up), material, collider: false); Cube(parent, "vr_track_torch_socket_" + i, val - Vector3.up * 0.035f, new Vector3(0.23f, 0.07f, 0.23f), Quaternion.identity, material); } } private static RailPath TorchPath(Vector3[] points) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) RailVector[] array = new RailVector[points.Length]; for (int i = 0; i < points.Length; i++) { array[i] = RailSegment.ToRail(points[i]); } return new RailPath(array); } private static void CreateTurntables(GameObject floor) { CreateTurntable(floor, 12f); CreateTurntable(floor, 24f); } private static void CreateTurntable(GameObject floor, float length) { //IL_0054: 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_00c8: 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_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0156: 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_0194: Unknown result type (might be due to invalid IL or missing references) string text = ((length < 18f) ? "12" : "24"); GameObject val = CloneBase(floor, "vr_turntable" + text, keepContainer: false, floor); ConfigurePiece(val.GetComponent(), "Rail turntable — " + text + " m", "An iron railway turntable with built-in rails and a rotating timber deck. Park the entire train on the deck, stop and dismount, then use the rim crank to turn it. Keep the full turning circle clear and support the circular base on level ground or a solid foundation."); GameObject val2 = Child(val.transform, "visual", Vector3.zero); GameObject val3 = Child(val2.transform, "vr_turntable_deck", Vector3.zero); float num = Mathf.Sqrt(length * length * 0.25f + 3.2399998f) + 0.55f; AddTurntableBase(val2.transform, num, length); AddTurntableDeck(val3.transform, length); AddSnap(val3.transform, "snap_start", new Vector3(0f, 0f, (0f - length) * 0.5f)); AddSnap(val3.transform, "snap_end", new Vector3(0f, 0f, length * 0.5f)); RailTurntable railTurntable = val.AddComponent(); railTurntable.Deck = val3.transform; railTurntable.Length = length; RailSegment railSegment = val.AddComponent(); railSegment.Points = (Vector3[])(object)new Vector3[2] { new Vector3(0f, 0f, (0f - length) * 0.5f), new Vector3(0f, 0f, length * 0.5f) }; railSegment.Kind = RailSectionKind.Normal; railSegment.LightDuty = false; AddTurntableCrank(val2.transform, railTurntable, num); ConfigureWear(val, val2, track: true); WearNTear component = val.GetComponent(); component.m_materialType = (MaterialType)2; component.m_health = 1600f; ConfigureTurntableFootprint(val, num); Prefabs.Add(val); } private static void ConfigureTurntableFootprint(GameObject prefab, float rimRadius) { //IL_0103: 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_0157: 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_00b0: 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_00d9: Unknown result type (might be due to invalid IL or missing references) float num = rimRadius + 0.28f; int num2 = Mathf.CeilToInt(num * 2f); float num3 = num * 2f / (float)num2; List list = new List((num2 + 1) * 4); for (int i = 0; i < num2; i++) { float num4 = 0f - num + (float)i * num3; float num5 = 0f - num + (float)(i + 1) * num3; float num6 = ((num4 <= 0f && num5 >= 0f) ? 0f : Mathf.Min(Mathf.Abs(num4), Mathf.Abs(num5))); float num7 = Mathf.Sqrt(Mathf.Max(0f, num * num - num6 * num6)); list.Add(new Vector3(0f - num7, -0.045f, num4)); list.Add(new Vector3(num7, -0.045f, num4)); list.Add(new Vector3(num7, -0.045f, num5)); list.Add(new Vector3(0f - num7, -0.045f, num5)); } list.Add(new Vector3(rimRadius - 0.045f, -0.025f, -0.6f)); list.Add(new Vector3(rimRadius + 1.405f, -0.025f, -0.6f)); list.Add(new Vector3(rimRadius + 1.405f, -0.025f, 0.6f)); list.Add(new Vector3(rimRadius - 0.045f, -0.025f, 0.6f)); RailTerrainPlacement railTerrainPlacement = prefab.AddComponent(); railTerrainPlacement.PreserveTerrain = true; railTerrainPlacement.BedCorners = list.ToArray(); RailSpawnProtection.Configure(prefab); } private static void AddTurntableBase(Transform parent, float radius, float length) { //IL_007a: 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_0114: 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_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: 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_00cc: 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) int num = ((length < 18f) ? 48 : 96); Vector3 val = default(Vector3); Vector3 to = default(Vector3); Vector3 position = default(Vector3); for (int i = 0; i < num; i++) { float num2 = (float)i * (float)Math.PI * 2f / (float)num; float num3 = (float)(i + 1) * (float)Math.PI * 2f / (float)num; ((Vector3)(ref val))..ctor(Mathf.Sin(num2) * radius, -0.39f, Mathf.Cos(num2) * radius); ((Vector3)(ref to))..ctor(Mathf.Sin(num3) * radius, -0.39f, Mathf.Cos(num3) * radius); Beam(parent, "turntable_rim", val, to, 0.56f, 0.42f, metal); if (i % (num / 8) == 0) { ((Vector3)(ref position))..ctor(Mathf.Sin(num2) * radius, -0.169f, Mathf.Cos(num2) * radius); Cube(parent, "turntable_alignment_mark", position, new Vector3(0.13f, 0.022f, 0.6f), Quaternion.Euler(0f, num2 * 57.29578f, 0f), brass, collider: false); } } Primitive(parent, "turntable_pivot_base", (PrimitiveType)2, new Vector3(0f, -0.48f, 0f), new Vector3(2.45f, 0.24f, 2.45f), Quaternion.identity, metal, collider: true); Primitive(parent, "turntable_pivot_bearing", (PrimitiveType)2, new Vector3(0f, -0.225f, 0f), new Vector3(1.32f, 0.08f, 1.32f), Quaternion.identity, brass, collider: false); } private static void AddTurntableDeck(Transform parent, float length) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //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_0078: 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_0091: 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_00dc: 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_010a: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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_0164: 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_0189: 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_01a3: 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_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.RoundToInt(length * 2f); for (int i = 0; i < num; i++) { float num2 = (0f - length) * 0.5f + 0.25f + (float)i * 0.5f; Cube(parent, "turntable_deck_plank", new Vector3(0f, -0.13f, num2), new Vector3(3.6f, 0.18f, 0.49f), Quaternion.identity, wood); Cube(parent, "sleeper", new Vector3(0f, 0.02f, num2), new Vector3(1.9f, 0.12f, 0.2f), Quaternion.identity, wood); } Vector3 val = default(Vector3); for (int j = -1; j <= 1; j += 2) { Cube(parent, "turntable_girder", new Vector3((float)j * 1.57f, -0.28f, 0f), new Vector3(0.18f, 0.3f, length), Quaternion.identity, metal); Cube(parent, "rail", new Vector3((float)j * 0.7f, 0.115f, 0f), new Vector3(0.095f, 0.09f, length), Quaternion.identity, metal); for (int k = -1; k <= 1; k += 2) { ((Vector3)(ref val))..ctor((float)j * 1.57f, -0.28f, (float)k * (length * 0.5f - 0.4f)); Primitive(parent, "turntable_runner_wheel", (PrimitiveType)2, val, new Vector3(0.35f, 0.085f, 0.35f), Quaternion.Euler(0f, 0f, 90f), metal, collider: false); Primitive(parent, "turntable_runner_hub", (PrimitiveType)2, val + Vector3.right * ((float)j * 0.09f), new Vector3(0.13f, 0.015f, 0.13f), Quaternion.Euler(0f, 0f, 90f), brass, collider: false); } } for (int l = -1; l <= 1; l += 2) { Cube(parent, "turntable_end_beam", new Vector3(0f, -0.24f, (float)l * (length * 0.5f - 0.09f)), new Vector3(3.6f, 0.22f, 0.18f), Quaternion.identity, metal); } } private static void AddTurntableCrank(Transform parent, RailTurntable table, float radius) { //IL_0017: 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_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_007f: 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_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: 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_0108: Unknown result type (might be due to invalid IL or missing references) //IL_011c: 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_015b: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: 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_0212: Unknown result type (might be due to invalid IL or missing references) GameObject obj = Child(parent, "vr_turntable_crank", new Vector3(radius + 0.82f, 0f, 0f)); Cube(obj.transform, "turntable_operator_step", new Vector3(-0.14f, -0.14f, 0f), new Vector3(1.45f, 0.24f, 1.2f), Quaternion.identity, wood); Cube(obj.transform, "turntable_crank_foot", new Vector3(0.08f, 0.1f, 0f), new Vector3(0.5f, 0.2f, 0.5f), Quaternion.identity, metal); Cube(obj.transform, "turntable_crank_post", new Vector3(0.08f, 0.56f, 0f), new Vector3(0.14f, 0.8f, 0.14f), Quaternion.identity, metal); Primitive(obj.transform, "turntable_crank_axle", (PrimitiveType)2, new Vector3(0.08f, 0.96f, 0f), new Vector3(0.22f, 0.12f, 0.22f), Quaternion.Euler(0f, 0f, 90f), brass, collider: false); Cube(obj.transform, "turntable_crank_arm", new Vector3(-0.06f, 0.96f, 0.25f), new Vector3(0.07f, 0.07f, 0.5f), Quaternion.identity, metal, collider: false); Primitive(obj.transform, "turntable_crank_grip", (PrimitiveType)2, new Vector3(-0.15f, 0.96f, 0.48f), new Vector3(0.12f, 0.12f, 0.12f), Quaternion.Euler(0f, 0f, 90f), red, collider: false); GameObject val = Child(obj.transform, "vr_turntable_handle", new Vector3(-0.06f, 0.96f, 0.24f)); val.AddComponent().size = new Vector3(0.42f, 0.4f, 0.72f); val.AddComponent().Table = table; table.Lever = val.transform; } private static void ConfigureTrackUpgrades() { foreach (RailTrackUpgradeDefinition definition in RailTrackUpgrade.Definitions) { GameObject? obj = Prefabs.Find((GameObject prefab) => ((Object)prefab).name == definition.WoodenPrefab); GameObject val = Prefabs.Find((GameObject prefab) => ((Object)prefab).name == definition.MetalPrefab); if (!Object.op_Implicit((Object)(object)obj) || !Object.op_Implicit((Object)(object)val)) { throw new InvalidOperationException("Missing rail upgrade counterpart: " + definition.WoodenPrefab); } RailTrackUpgradeInteraction railTrackUpgradeInteraction = obj.AddComponent(); railTrackUpgradeInteraction.WoodenPrefab = definition.WoodenPrefab; railTrackUpgradeInteraction.MetalPrefab = val; } } private static void CreateWoodenTracks(GameObject floor, Vector3[] curve) { //IL_0017: 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_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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_00bb: Unknown result type (might be due to invalid IL or missing references) Vector3[] points = (Vector3[])(object)new Vector3[2] { new Vector3(0f, 0f, -2f), new Vector3(0f, 0f, 2f) }; CreateTrack(floor, "vr_track_wood_straight", "Wooden track — straight", "4 m wooden rail section. Snaps to either track type; support elevated rails with a bridge. For handcarts, bronze engines and wagons; coal and Eitr engines cannot use wooden tracks.", points, RailSectionKind.Normal, lightDuty: true); CreateTrack(floor, "vr_track_wood_curve", "Wooden track — 22.5° curve", "22.5 degree wooden curve, 8 m radius. Rotate or reverse placement to turn left or right. For handcarts, bronze engines and wagons; coal and Eitr engines cannot use wooden tracks.", curve, RailSectionKind.Normal, lightDuty: true); CreateTrack(floor, "vr_track_wood_slope", "Wooden track — incline", "Rises 1 m over 4 m. Support it with beams, stairs, or a bridge. For handcarts, bronze engines and wagons; coal and Eitr engines cannot use wooden tracks.", (Vector3[])(object)new Vector3[2] { Vector3.zero, new Vector3(0f, 1f, 4f) }, RailSectionKind.Normal, lightDuty: true); CreateTrack(floor, "vr_track_wood_brake", "Wooden track — stop", "4 m stopping section. Trains stop automatically; release the controls before setting off again. For handcarts, bronze engines and wagons; coal and Eitr engines cannot use wooden tracks.", points, RailSectionKind.Brake, lightDuty: true); CreateTrack(floor, "vr_track_wood_bumper", "Wooden track — end bumper", "4 m terminal section. Approach from the open end; the train stops before the barrier and can reverse away. For handcarts, bronze engines and wagons; coal and Eitr engines cannot use wooden tracks.", points, RailSectionKind.Bumper, lightDuty: true); } private static void CreateWorkshopCarts(ZNetScene scene, GameObject cart, GameObject floor) { CreateWorkshopCart(scene, cart, floor, "vr_workbench_cart", "Rail workbench cart", "piece_workbench", workbench: true); CreateWorkshopCart(scene, cart, floor, "vr_workbench_chopping_cart", "Rail chopping block cart", "piece_workbench_ext1", workbench: false); CreateWorkshopCart(scene, cart, floor, "vr_workbench_tanning_cart", "Rail tanning rack cart", "piece_workbench_ext2", workbench: false); CreateWorkshopCart(scene, cart, floor, "vr_workbench_adze_cart", "Rail adze cart", "piece_workbench_ext3", workbench: false); CreateWorkshopCart(scene, cart, floor, "vr_workbench_toolrack_cart", "Rail tool shelf cart", "piece_workbench_ext4", workbench: false); } private static void CreateWorkshopCart(ZNetScene scene, GameObject cart, GameObject floor, string prefabName, string title, string sourceName, bool workbench) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0299: 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) GameObject prefab = scene.GetPrefab(sourceName); if (!Object.op_Implicit((Object)(object)prefab) || !Object.op_Implicit((Object)(object)prefab.GetComponent()) || (workbench ? (!Object.op_Implicit((Object)(object)prefab.GetComponent())) : (!Object.op_Implicit((Object)(object)prefab.GetComponent())))) { throw new InvalidOperationException("The native workshop piece is unavailable: " + sourceName); } GameObject val = CloneBase(cart, prefabName, keepContainer: false, floor); ConfigurePiece(val.GetComponent(), title, workbench ? "A sheltered working workbench on rails. Park and dismount to craft or repair. Couple upgrade carts to improve the workbench; use alternate-use to couple or uncouple." : "A workbench upgrade on its own rail cart. Park beside a workbench or couple it into the workbench's train. One of each upgrade counts. Alternate-use to couple or uncouple."); GameObject val2 = Child(val.transform, "visual", Vector3.zero); AddWorkshopChassis(val2.transform); Rigidbody obj = val.GetComponent() ?? val.AddComponent(); obj.isKinematic = true; obj.useGravity = false; obj.mass = (workbench ? 160f : 110f); ZSyncTransform obj2 = val.GetComponent() ?? val.AddComponent(); obj2.m_syncPosition = true; obj2.m_syncRotation = true; obj2.m_syncScale = false; obj2.m_syncBodyVelocity = false; obj2.m_characterParentSync = false; val.GetComponent().m_type = (ObjectType)0; RailVehicle railVehicle = val.AddComponent(); railVehicle.IsEngine = false; railVehicle.CoalPowered = false; RailWorkshopCart railWorkshopCart = val.AddComponent(); railWorkshopCart.UpgradePrefab = (workbench ? "" : sourceName); railWorkshopCart.DisplayName = title; GameObject val3 = Object.Instantiate(prefab, val2.transform, false); ((Object)val3).name = "vr_workshop_model"; val3.transform.localPosition = Vector3.zero; val3.transform.localRotation = Quaternion.identity; val3.transform.localScale = Vector3.one; val3.SetActive(true); SelectNewWorkshopModel(val3); List list = DetachWorkshopUtilities(val3, val.transform); CraftingStation component = val3.GetComponent(); StationExtension component2 = val3.GetComponent(); if (workbench) { CraftingStation val4 = val.AddComponent(); CopyFields((Component)(object)component, (Component)(object)val4); val4.m_useDistance = Mathf.Max(val4.m_useDistance, 2.5f); val4.m_roofCheckPoint = Child(val.transform, "vr_workshop_roof_check", new Vector3(0f, 1.7f, 0f)).transform; val4.m_craftRequireRoof = true; AddWorkshopShelter(val2.transform); } else { StationExtension target = val.AddComponent(); CopyFields((Component)(object)component2, (Component)(object)target); } StripWorkshopComponents(val3); foreach (GameObject item in list) { StripWorkshopComponents(item); } FitWorkshopModel(val3, val2.transform, sourceName, workbench); if (!workbench) { StationExtension component3 = prefab.GetComponent(); val.GetComponent().m_connectionOffset = val.transform.InverseTransformPoint(val3.transform.TransformPoint(component3.m_connectionOffset)); } if (sourceName == "piece_workbench_ext4") { AddWorkshopToolBacking(val2.transform); } ConfigureWear(val, val2, track: false); AddVehicleLights(val, val2.transform, engine: false); AddPackingHandle(val2.transform); AddPushHandle(val2.transform); ZNetView[] componentsInChildren = val.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)((Component)componentsInChildren[i]).gameObject != (Object)(object)val) { throw new InvalidOperationException("A workshop cart retained a nested network view."); } } Prefabs.Add(val); } private static void AddWorkshopChassis(Transform visual) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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) //IL_00b1: 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_00f3: 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_010c: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < 5; i++) { Cube(visual, "deck_plank", new Vector3((float)(i - 2) * 0.33f, 0.74f, 0f), new Vector3(0.32f, 0.24f, 2.1f), Quaternion.identity, wood); } for (int j = -1; j <= 1; j += 2) { Cube(visual, "chassis", new Vector3((float)j * 0.51f, 0.54f, 0f), new Vector3(0.15f, 0.22f, 2.25f), Quaternion.identity, wood); Cube(visual, "coupler", new Vector3(0f, 0.53f, (float)j * 1.18f), new Vector3(0.16f, 0.14f, 0.35f), Quaternion.identity, metal); Cube(visual, "axle", new Vector3(0f, 0.44f, (float)j * 0.68f), new Vector3(1.65f, 0.09f, 0.09f), Quaternion.identity, metal); for (int k = -1; k <= 1; k += 2) { Primitive(visual, "vr_wheel", (PrimitiveType)2, new Vector3((float)k * 0.7f, 0.44f, (float)j * 0.68f), new Vector3(0.56f, 0.075f, 0.56f), Quaternion.Euler(0f, 0f, 90f), metal, collider: false); } } } private static void AddWorkshopShelter(Transform visual) { //IL_001f: 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_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0165: 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_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: 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_007c: 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_00b2: 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_00de: 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_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) for (int i = -1; i <= 1; i += 2) { Cube(visual, "workshop_side_wall", new Vector3((float)i * 0.9f, 1.72f, 0f), new Vector3(0.12f, 1.72f, 2.04f), Quaternion.identity, wood); for (int j = -1; j <= 1; j += 2) { Cube(visual, "workshop_roof_post", new Vector3((float)i * 0.9f, 1.76f, (float)j * 0.96f), new Vector3(0.18f, 1.8f, 0.18f), Quaternion.identity, wood); } Cube(visual, "workshop_roof_panel", new Vector3((float)i * 0.5f, 2.82f, 0f), new Vector3(1.12f, 0.12f, 2.3f), Quaternion.Euler(0f, 0f, (float)(-i) * 18f), wood); Cube(visual, "workshop_wall_brace", new Vector3((float)i * 0.977f, 1.73f, 0f), new Vector3(0.055f, 0.13f, 1.88f), Quaternion.identity, metal, collider: false); } Cube(visual, "workshop_back_wall", new Vector3(0f, 1.72f, 0.96f), new Vector3(1.8f, 1.72f, 0.12f), Quaternion.identity, wood); Cube(visual, "workshop_roof_ridge", new Vector3(0f, 3f, 0f), new Vector3(0.15f, 0.15f, 2.35f), Quaternion.identity, wood); } private static void AddWorkshopToolBacking(Transform visual) { //IL_001c: 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_0063: 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_00a2: 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_00bb: Unknown result type (might be due to invalid IL or missing references) for (int i = -1; i <= 1; i += 2) { Cube(visual, "workshop_tool_post", new Vector3((float)i * 0.65f, 1.76f, 0.78f), new Vector3(0.12f, 1.8f, 0.12f), Quaternion.identity, wood); } Cube(visual, "workshop_tool_backing", new Vector3(0f, 1.75f, 0.76f), new Vector3(1.5f, 1.6f, 0.12f), Quaternion.identity, wood); Cube(visual, "workshop_tool_foot", new Vector3(0f, 0.92f, 0.6f), new Vector3(1.55f, 0.12f, 0.65f), Quaternion.identity, wood); } private static void SelectNewWorkshopModel(GameObject model) { WearNTear component = model.GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return; } GameObject val = component.m_new; HashSet hashSet = new HashSet(); if (Object.op_Implicit((Object)(object)component.m_worn) && (Object)(object)component.m_worn != (Object)(object)val) { hashSet.Add(component.m_worn); } if (Object.op_Implicit((Object)(object)component.m_broken) && (Object)(object)component.m_broken != (Object)(object)val) { hashSet.Add(component.m_broken); } if (Object.op_Implicit((Object)(object)component.m_wet) && (Object)(object)component.m_wet != (Object)(object)val) { hashSet.Add(component.m_wet); } foreach (GameObject item in hashSet) { if (Object.op_Implicit((Object)(object)item) && (Object)(object)item != (Object)(object)model && (!Object.op_Implicit((Object)(object)val) || !val.transform.IsChildOf(item.transform))) { Object.DestroyImmediate((Object)(object)item); } } if (Object.op_Implicit((Object)(object)val)) { val.SetActive(true); } } private static List DetachWorkshopUtilities(GameObject model, Transform cart) { HashSet hashSet = new HashSet(); CraftingStation component = model.GetComponent(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.m_areaMarker)) { hashSet.Add(component.m_areaMarker.transform); } if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.m_effectAreaCollider)) { hashSet.Add(((Component)component.m_effectAreaCollider).transform); } EffectArea[] componentsInChildren = model.GetComponentsInChildren(true); foreach (EffectArea val in componentsInChildren) { hashSet.Add(((Component)val).transform); } Transform[] componentsInChildren2 = model.GetComponentsInChildren(true); foreach (Transform val2 in componentsInChildren2) { if (((Component)val2).gameObject.CompareTag("StationUseArea")) { hashSet.Add(val2); } } List list = new List(); foreach (Transform item in hashSet) { if ((Object)(object)item == (Object)(object)model.transform) { continue; } bool flag = false; foreach (Transform item2 in hashSet) { if ((Object)(object)item2 != (Object)(object)item && item.IsChildOf(item2)) { flag = true; break; } } if (!flag) { list.Add(((Component)item).gameObject); } } foreach (GameObject item3 in list) { item3.transform.SetParent(cart, true); } return list; } private static void StripWorkshopComponents(GameObject model) { Transform[] componentsInChildren = model.GetComponentsInChildren(true); Component[] components; foreach (Transform val in componentsInChildren) { if (((Component)val).gameObject.CompareTag("snappoint")) { ((Component)val).gameObject.tag = "Untagged"; } components = ((Component)val).GetComponents(); foreach (Component val2 in components) { if (Object.op_Implicit((Object)(object)val2) && !WorkshopModelComponent(val2) && !(val2 is ZNetView)) { Object.DestroyImmediate((Object)(object)val2); } } } ZNetView[] componentsInChildren2 = model.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren2.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren2[i]); } components = model.GetComponentsInChildren(true); foreach (Component val3 in components) { if (Object.op_Implicit((Object)(object)val3) && !WorkshopModelComponent(val3)) { throw new InvalidOperationException("A native workshop component could not be removed: " + ((object)val3).GetType().Name); } } } private static bool WorkshopModelComponent(Component component) { if (!(component is Transform) && !(component is MeshFilter) && !(component is MeshRenderer) && !(component is SkinnedMeshRenderer) && !(component is LODGroup) && !(component is Collider) && !(component is ParticleSystem) && !(component is ParticleSystemRenderer) && !(component is Light) && !(component is Animator) && !(component is EffectArea)) { return component is CircleProjector; } return true; } private static void FitWorkshopModel(GameObject model, Transform visual, string sourceName, bool workbench) { //IL_0012: 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_0038: 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_0077: 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_00f3: 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_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0138: 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_01a1: 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) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_016e: 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_018d: 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_01d5: Unknown result type (might be due to invalid IL or missing references) if (!TryPassengerChairBounds(model.transform, visual, out var bounds) || ((Bounds)(ref bounds)).size.x < 0.05f || ((Bounds)(ref bounds)).size.y < 0.05f || ((Bounds)(ref bounds)).size.z < 0.05f) { throw new InvalidOperationException("The native workshop model has no usable visible geometry: " + sourceName); } bool flag = sourceName == "piece_workbench_ext4"; if (workbench && ((Bounds)(ref bounds)).size.x > ((Bounds)(ref bounds)).size.z) { model.transform.localRotation = Quaternion.Euler(0f, 90f, 0f); if (!TryPassengerChairBounds(model.transform, visual, out bounds)) { throw new InvalidOperationException("The native workbench cannot be measured."); } } float num = (workbench ? 1.55f : (flag ? 1.6f : 1.75f)); float num2 = (flag ? 0.45f : 1.65f); float num3 = Mathf.Min(1f, Mathf.Min(1.45f / ((Bounds)(ref bounds)).size.x, Mathf.Min(num / ((Bounds)(ref bounds)).size.y, num2 / ((Bounds)(ref bounds)).size.z))); model.transform.localScale = Vector3.one * num3; if (!TryPassengerChairBounds(model.transform, visual, out bounds)) { throw new InvalidOperationException("The fitted workshop model cannot be measured."); } Transform transform = model.transform; transform.localPosition += (flag ? new Vector3(0f - ((Bounds)(ref bounds)).center.x, 1.75f - ((Bounds)(ref bounds)).center.y, 0.45f - ((Bounds)(ref bounds)).center.z) : new Vector3(0f - ((Bounds)(ref bounds)).center.x, 0.86f - ((Bounds)(ref bounds)).min.y, 0f - ((Bounds)(ref bounds)).center.z)); } private static bool RegisterWorkshopRecipe(GameObject prefab, ObjectDB db, PieceTable table) { if (!Object.op_Implicit((Object)(object)prefab.GetComponent())) { return false; } if (!TryWorkshopRecipe(prefab, db, table, out var requirements)) { DeferredWorkshopRecipes.Add(((Object)prefab).name); table.m_pieces.RemoveAll((GameObject candidate) => (Object)(object)candidate == (Object)(object)prefab); return true; } prefab.GetComponent().m_resources = requirements; if (!table.m_pieces.Contains(prefab)) { table.m_pieces.Add(prefab); } DeferredWorkshopRecipes.Remove(((Object)prefab).name); return true; } private static bool TryWorkshopRecipe(GameObject prefab, ObjectDB db, PieceTable table, out Requirement[] requirements) { requirements = Array.Empty(); RailWorkshopCart component = prefab.GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return false; } Dictionary dictionary; if (component.RepairStation) { dictionary = new Dictionary(StringComparer.Ordinal) { ["Wood"] = 20, ["FineWood"] = 10, ["Copper"] = 6, ["Coal"] = 4, ["IronNails"] = 10 }; } else { string sourceName = (string.IsNullOrEmpty(component.UpgradePrefab) ? "piece_workbench" : component.UpgradePrefab); Piece val = FindWorkshopRecipe(table, sourceName); if (!Object.op_Implicit((Object)(object)val) || val.m_resources == null) { return false; } dictionary = new Dictionary(StringComparer.Ordinal) { ["Wood"] = 20, ["BronzeNails"] = 10 }; Requirement[] resources = val.m_resources; foreach (Requirement val2 in resources) { if (val2 == null) { return false; } if (val2.m_amount > 0) { if (!Object.op_Implicit((Object)(object)val2.m_resItem)) { return false; } string prefabName = Utils.GetPrefabName(((Object)val2.m_resItem).name); if (string.IsNullOrEmpty(prefabName)) { return false; } dictionary.TryGetValue(prefabName, out var value); if (val2.m_amount > int.MaxValue - value) { return false; } dictionary[prefabName] = value + val2.m_amount; } } } List list = new List(); foreach (KeyValuePair item in dictionary) { ItemDrop val3 = FindItem(db, item.Key); if (!Object.op_Implicit((Object)(object)val3)) { return false; } list.Add(Cost(val3, item.Value)); } requirements = list.ToArray(); return true; } private static Piece FindWorkshopRecipe(PieceTable table, string sourceName) { foreach (GameObject piece in table.m_pieces) { if (Object.op_Implicit((Object)(object)piece) && !(((Object)piece).name != sourceName)) { Piece component = piece.GetComponent(); if (Object.op_Implicit((Object)(object)component)) { return component; } } } GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.GetPrefab(sourceName) : null); if (!Object.op_Implicit((Object)(object)val)) { return null; } return val.GetComponent(); } } public sealed class RailTandemDriverTarget : MonoBehaviour, Hoverable, Interactable { public RailVehicle Vehicle; public float GetHoverOffset() { return 0f; } public string GetHoverName() { if (!Object.op_Implicit((Object)(object)Vehicle)) { return "Two-person rail handcart"; } return Vehicle.GetHoverName(); } public string GetHoverText() { if (!Object.op_Implicit((Object)(object)Vehicle)) { return ""; } return Vehicle.GetHoverText(); } public bool Interact(Humanoid user, bool hold, bool alt) { if (Object.op_Implicit((Object)(object)Vehicle)) { return Vehicle.Interact(user, hold, alt); } return false; } public bool UseItem(Humanoid user, ItemData item) { if (Object.op_Implicit((Object)(object)Vehicle)) { return Vehicle.UseItem(user, item); } return false; } } public sealed class RailPumpPartner : MonoBehaviour, Hoverable, Interactable, IDoodadController { public Transform AttachPoint; public Vector3 DetachOffset = new Vector3(1.4f, 0.2f, 0f); private const long LeaseMilliseconds = 6000L; private const float BoardingRange = 3f; private const string Prefix = "vikingrail_pump_partner_"; private const string RequestRpc = "VR_PumpPartnerRequest"; private const string ReplyRpc = "VR_PumpPartnerReply"; private const string RenewRpc = "VR_PumpPartnerRenew"; private const string ReleaseRpc = "VR_PumpPartnerRelease"; private const string CheckpointRpc = "VR_PumpPartnerCheckpoint"; private const string CheckpointReplyRpc = "VR_PumpPartnerCheckpointReply"; private const float CheckpointInterval = 0.25f; private const float CheckpointTimeout = 2f; private const string DriverKey = "vikingrail_driver"; private RailVehicle _cart; private ZNetView _view; private bool _registered; private Player? _partner; private string _localToken = ""; private long _requestPeer; private long _requestOwner; private long _requestPlayer; private bool _pending; private bool _granted; private float _requestAt; private float _nextRenew; private readonly RailPumpStaminaLedger _stamina = new RailPumpStaminaLedger(); private string _staminaToken = ""; private long _staminaDriver; private long _staminaPlayer; private long _staminaPeer; private long _staminaOwner; private ushort _staminaOwnerRevision; private string _staminaSession = ""; private float _nextCheckpoint; private float _checkpointAt; private float _confirmedAt = -1f; private static readonly FieldInfo? WardList = AccessTools.Field(typeof(PrivateArea), "m_allAreas"); private static readonly MethodInfo? WardEnabled = AccessTools.Method(typeof(PrivateArea), "IsEnabled", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo? WardInside = AccessTools.Method(typeof(PrivateArea), "IsInside", new Type[2] { typeof(Vector3), typeof(float) }, (Type[])null); private static readonly MethodInfo? WardPermitted = AccessTools.Method(typeof(PrivateArea), "IsPermitted", new Type[1] { typeof(long) }, (Type[])null); public static RailPumpPartner? LocalPartner { get; private set; } internal RailVehicle Cart => _cart; private bool Ready { get { if (_registered && Object.op_Implicit((Object)(object)_cart) && _cart.IsReady && _cart.IsEngine && _cart.IsTandemHandcart && !_cart.FuelPowered && Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { return Object.op_Implicit((Object)(object)AttachPoint); } return false; } } private static long Now { get { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return 0L; } return (long)(ZNet.instance.GetTimeSeconds() * 1000.0); } } private PassengerSeatReservation Reservation { get { if (Ready) { return new PassengerSeatReservation(_view.GetZDO().GetLong("vikingrail_pump_partner_player", 0L), _view.GetZDO().GetLong("vikingrail_pump_partner_peer", 0L), _view.GetZDO().GetString("vikingrail_pump_partner_token", ""), _view.GetZDO().GetLong("vikingrail_pump_partner_until", 0L)); } return default(PassengerSeatReservation); } } public bool IsOccupied { get { if (Ready) { return Reservation.IsActive(Now); } return false; } } public long OccupantId { get { if (!IsOccupied) { return 0L; } return Reservation.Player; } } private void Awake() { _cart = ((Component)this).GetComponentInParent(); _view = ((Component)this).GetComponentInParent(); if (!Object.op_Implicit((Object)(object)AttachPoint)) { AttachPoint = ((Component)this).transform.Find("vr_attach") ?? ((Component)this).transform; } } private void Start() { if (Object.op_Implicit((Object)(object)_cart) && Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { _registered = true; _view.Register("VR_PumpPartnerRequest", (Action)RequestPartner); _view.Register("VR_PumpPartnerReply", (Action)PartnerReply); _view.Register("VR_PumpPartnerRenew", (Action)RenewPartner); _view.Register("VR_PumpPartnerRelease", (Action)ReleasePartner); _view.Register("VR_PumpPartnerCheckpoint", (Action)RequestCheckpoint); _view.Register("VR_PumpPartnerCheckpointReply", (Method)CheckpointReply); ClearInvalidReservation(); } } private void Update() { //IL_00e1: 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_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) if (!Ready) { StopLocalPartner(); return; } ClearInvalidReservation(); if (_view.IsOwner() && !HasCurrentDriver(out var _)) { ResetStaminaContext(); } if (_pending) { Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting() || Time.unscaledTime - _requestAt > 6f) { ReleaseReservation(); Tell("Could not reserve the front pump. Try again beside the stopped handcart."); } else if (_granted && Reservation.Matches(_requestPlayer, _requestPeer, _localToken) && Reservation.IsActive(Now)) { if (((Character)localPlayer).IsAttached() || localPlayer.GetDoodadController() != null || Vector3.Distance(((Component)localPlayer).transform.position, AttachPoint.position) > 3f || !_cart.PassengerBoardingAllowed || !PrivateArea.CheckAccess(AttachPoint.position, 0f, true, false)) { ReleaseReservation(); return; } _pending = false; _partner = localPlayer; localPlayer.StartDoodadControl((IDoodadController)(object)this); RailRiderAttachment.ClearWalkingInput(localPlayer); ((Character)localPlayer).AttachStart(AttachPoint, ((Component)_cart).gameObject, true, false, true, "standing", DetachOffset, (Transform)null); _nextRenew = 0f; Tell("You help pump automatically with the driver. Jump to dismount."); } } if (!Object.op_Implicit((Object)(object)_partner)) { if (!_pending && (Object)(object)LocalPartner == (Object)(object)this && _localToken.Length != 0) { ReleaseReservation(); } } else if (((Character)_partner).IsDead() || ((Character)_partner).IsTeleporting() || !HasAttachment(_partner) || !Reservation.Matches(_requestPlayer, _requestPeer, _localToken) || !Reservation.IsActive(Now)) { StopLocalPartner(); } else if (Time.unscaledTime >= _nextRenew) { _nextRenew = Time.unscaledTime + 1f; _view.InvokeRPC("VR_PumpPartnerRenew", new object[2] { _requestPlayer, _localToken }); } } private void ClearInvalidReservation() { if (!Ready || !_view.IsOwner()) { return; } PassengerSeatReservation reservation = Reservation; if (reservation.Player != 0L) { Player player = Player.GetPlayer(reservation.Player); if (!reservation.IsActive(Now) || (Object.op_Implicit((Object)(object)player) && (((Character)player).IsDead() || ((Character)player).IsTeleporting() || ((Character)player).GetOwner() != reservation.Peer))) { WriteReservation(default(PassengerSeatReservation)); } } } internal bool TryRider(Player player, out Transform anchor) { anchor = AttachPoint; if (!Ready || !Object.op_Implicit((Object)(object)player) || ((Character)player).IsDead() || ((Character)player).IsTeleporting()) { return false; } PassengerSeatReservation reservation = Reservation; if (!reservation.IsActive(Now) || reservation.Player != player.GetPlayerID() || reservation.Peer != ((Character)player).GetOwner()) { return false; } if ((Object)(object)player == (Object)(object)Player.m_localPlayer) { if ((Object)(object)LocalPartner == (Object)(object)this && (Object)(object)_partner == (Object)(object)player && reservation.Matches(_requestPlayer, _requestPeer, _localToken)) { return HasAttachment(player); } return false; } if (_view.GetZDO().GetBool("vikingrail_pump_partner_mounted", false)) { return HasAttachment(player); } return false; } internal bool TryGetPoweredPartner(float requiredStamina, out Player player) { player = null; if (!Ready || !_view.IsOwner() || !NativeCost(requiredStamina, out var cost) || !HasCurrentDriver(out var driver)) { ResetStaminaContext(); return false; } PassengerSeatReservation reservation = Reservation; Player player2 = Player.GetPlayer(reservation.Player); if (driver == reservation.Player || !TryRider(player2, out Transform _)) { ResetStaminaContext(); return false; } EnsureStaminaContext(reservation, driver); RefreshStaminaCheckpoint(reservation); if (!RailTandemPolicy.HasTwoOperators(driver, reservation.Player, driverAttached: true, helperAttached: true, Time.unscaledTime, _confirmedAt) || !_stamina.CanSpend(cost)) { return false; } player = player2; return true; } private bool HasCurrentDriver(out long driver) { driver = 0L; Player localPlayer = Player.m_localPlayer; if (!Ready || !_view.IsOwner() || !Object.op_Implicit((Object)(object)localPlayer) || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting() || (Object)(object)RailVehicle.LocalDriven != (Object)(object)_cart || !((Character)localPlayer).IsAttached() || (object)localPlayer.GetDoodadController() != _cart || (Object)(object)localPlayer.GetAttachPoint() != (Object)(object)((Component)_cart).transform.Find("vr_driver")) { return false; } driver = localPlayer.GetPlayerID(); if (driver != 0L && driver == _view.GetZDO().GetLong("vikingrail_driver", 0L)) { return ((Character)localPlayer).GetOwner() == _view.GetZDO().GetOwner(); } return false; } internal void UsePartnerStamina(Player player, float acceptedStamina) { if (NativeCost(acceptedStamina, out var cost) && !(cost <= 0f) && TryGetPoweredPartner(acceptedStamina, out Player player2) && !((Object)(object)player2 != (Object)(object)player)) { ((Character)player).UseStamina(acceptedStamina); _stamina.RecordSpend(cost); } } internal static bool NativeCost(float amount, out float cost) { cost = 0f; float staminaRate = Game.m_staminaRate; if (float.IsNaN(amount) || float.IsInfinity(amount) || amount < 0f || float.IsNaN(staminaRate) || float.IsInfinity(staminaRate) || staminaRate < 0f) { return false; } cost = amount * staminaRate; if (!float.IsNaN(cost)) { return !float.IsInfinity(cost); } return false; } private void EnsureStaminaContext(PassengerSeatReservation reservation, long driver) { long owner = _view.GetZDO().GetOwner(); ushort ownerRevision = _view.GetZDO().OwnerRevision; if (_staminaDriver != driver || !(_staminaToken == reservation.Token) || _staminaPlayer != reservation.Player || _staminaPeer != reservation.Peer || _staminaOwner != owner || _staminaOwnerRevision != ownerRevision) { _stamina.Reset(); _staminaDriver = driver; _staminaToken = reservation.Token; _staminaPlayer = reservation.Player; _staminaPeer = reservation.Peer; _staminaOwner = owner; _staminaOwnerRevision = ownerRevision; _staminaSession = Guid.NewGuid().ToString("N"); _nextCheckpoint = 0f; _checkpointAt = 0f; _confirmedAt = -1f; } } private void ResetStaminaContext() { _stamina.Reset(); _staminaDriver = (_staminaPlayer = (_staminaPeer = (_staminaOwner = 0L))); _staminaOwnerRevision = 0; _staminaToken = (_staminaSession = ""); _nextCheckpoint = (_checkpointAt = 0f); _confirmedAt = -1f; } private void RefreshStaminaCheckpoint(PassengerSeatReservation reservation) { float unscaledTime = Time.unscaledTime; if (!(unscaledTime < _nextCheckpoint) && (!_stamina.CheckpointPending || !(unscaledTime - _checkpointAt < 2f))) { long num = _stamina.BeginCheckpoint(); _checkpointAt = unscaledTime; _nextCheckpoint = unscaledTime + 0.25f; _view.InvokeRPC(reservation.Peer, "VR_PumpPartnerCheckpoint", new object[3] { reservation.Token, _staminaSession, num }); } } private void RequestCheckpoint(long sender, string token, string session, long checkpoint) { Player localPlayer = Player.m_localPlayer; if (Ready && Object.op_Implicit((Object)(object)localPlayer) && sender == _view.GetZDO().GetOwner() && checkpoint > 0 && session != null && session.Length == 32 && !(token != _localToken) && !((Object)(object)LocalPartner != (Object)(object)this) && Reservation.Matches(localPlayer.GetPlayerID(), ((Character)localPlayer).GetOwner(), token) && TryRider(localPlayer, out Transform _)) { long num = _view.GetZDO().GetLong("vikingrail_driver", 0L); if (num != 0L && num != localPlayer.GetPlayerID()) { _view.InvokeRPC(sender, "VR_PumpPartnerCheckpointReply", new object[4] { token, session, checkpoint, localPlayer.GetStamina() }); } } } private void CheckpointReply(long sender, string token, string session, long checkpoint, float stamina) { if (Ready && _view.IsOwner() && sender == _staminaPeer && !(session != _staminaSession) && !(token != _staminaToken) && _staminaOwner == _view.GetZDO().GetOwner() && _staminaOwnerRevision == _view.GetZDO().OwnerRevision && !(Time.unscaledTime - _checkpointAt >= 2f) && HasCurrentDriver(out var driver) && driver == _staminaDriver) { PassengerSeatReservation reservation = Reservation; if (reservation.Matches(_staminaPlayer, sender, token) && reservation.IsActive(Now) && TryRider(Player.GetPlayer(reservation.Player), out Transform _) && _stamina.Acknowledge(checkpoint, stamina)) { _confirmedAt = _checkpointAt; } } } public float GetHoverOffset() { return 0f; } public string GetHoverName() { return "Front pump position"; } public string GetHoverText() { return Localization.instance.Localize(GetHoverName() + (IsOccupied ? "\nOccupied" : "\n[$KEY_Use] Help pump (while stopped)") + "\nPumps automatically with the driver; jump to dismount.\nTwo rested operators travel faster and use less stamina each."); } public bool UseItem(Humanoid user, ItemData item) { return false; } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_0082: 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_00a4: Unknown result type (might be due to invalid IL or missing references) if (hold || alt || !Ready) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val != (Object)(object)Player.m_localPlayer || Object.op_Implicit((Object)(object)LocalPartner) || _pending || ((Character)val).IsDead() || ((Character)val).IsTeleporting() || ((Character)val).IsAttached() || val.GetDoodadController() != null || ((Character)val).InPlaceMode()) { return false; } if (!RailSettings.Ready) { Tell("Waiting for server railroad settings."); return false; } if (Vector3.Distance(((Component)val).transform.position, AttachPoint.position) > 3f || !PrivateArea.CheckAccess(AttachPoint.position, 0f, true, false)) { return false; } if (!_cart.PassengerBoardingAllowed) { Tell("Wait for the handcart to stop before boarding."); return false; } if (IsOccupied) { Tell("The front pump position is occupied."); return false; } if (!_view.HasOwner()) { Tell("Waiting for the handcart's network owner. Try again shortly."); return false; } _pending = true; _granted = false; _localToken = Guid.NewGuid().ToString("N"); _requestPlayer = val.GetPlayerID(); _requestPeer = ((Character)val).GetOwner(); _requestOwner = _view.GetZDO().GetOwner(); _requestAt = Time.unscaledTime; LocalPartner = this; _view.InvokeRPC("VR_PumpPartnerRequest", new object[2] { _requestPlayer, _localToken }); return true; } private bool ValidPlayer(long sender, long playerId, out Player player) { //IL_0034: 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) player = Player.GetPlayer(playerId); if (Object.op_Implicit((Object)(object)player) && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && ((Character)player).GetOwner() == sender) { return Vector3.Distance(((Component)player).transform.position, AttachPoint.position) <= 3f; } return false; } private void RequestPartner(long sender, long playerId, string token) { //IL_00bf: 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) if (Ready && _view.IsOwner()) { ClearInvalidReservation(); Player player; bool flag = RailSettings.Ready && token != null && token.Length == 32 && _view.GetZDO().GetLong("vikingrail_driver", 0L) != playerId && ValidPlayer(sender, playerId, out player) && _cart.PassengerBoardingAllowed && CanAccessWard(AttachPoint.position, playerId) && Reservation.CanReserve(playerId, sender, token, Now); if (flag) { WriteReservation(new PassengerSeatReservation(playerId, sender, token, Now + 6000)); ZDOMan.instance.ForceSendZDO(sender, _view.GetZDO().m_uid); } _view.InvokeRPC(sender, "VR_PumpPartnerReply", new object[2] { token ?? "", flag }); } } private void PartnerReply(long sender, string token, bool allowed) { if (_pending && sender == _requestOwner && !(token != _localToken)) { _granted = allowed; if (!allowed) { ReleaseReservation(); Tell("The front pump is occupied or cannot be boarded here."); } } } private void RenewPartner(long sender, long playerId, string token) { if (Ready && _view.IsOwner()) { PassengerSeatReservation reservation = Reservation; if (reservation.IsActive(Now) && reservation.Matches(playerId, sender, token) && ValidPlayer(sender, playerId, out Player player) && HasAttachment(player)) { WriteReservation(new PassengerSeatReservation(playerId, sender, token, Now + 6000), mounted: true); } } } private void ReleasePartner(long sender, long playerId, string token) { if (Ready && _view.IsOwner() && Reservation.Matches(playerId, sender, token)) { WriteReservation(default(PassengerSeatReservation)); } } private void WriteReservation(PassengerSeatReservation reservation, bool mounted = false) { if (Object.op_Implicit((Object)(object)_view) && _view.IsValid() && _view.IsOwner()) { ZDO zDO = _view.GetZDO(); zDO.Set("vikingrail_pump_partner_player", reservation.Player); zDO.Set("vikingrail_pump_partner_peer", reservation.Peer); zDO.Set("vikingrail_pump_partner_token", reservation.Token ?? ""); zDO.Set("vikingrail_pump_partner_until", reservation.ExpiresAt); zDO.Set("vikingrail_pump_partner_mounted", mounted); if (reservation.Player == 0L) { ResetStaminaContext(); } } } private void ReleaseReservation() { if (Ready && _localToken.Length != 0) { _view.InvokeRPC("VR_PumpPartnerRelease", new object[2] { _requestPlayer, _localToken }); } _localToken = ""; _pending = false; _granted = false; if ((Object)(object)LocalPartner == (Object)(object)this) { LocalPartner = null; } } private bool HasAttachment(Player player) { //IL_0056: 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_0078: 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_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) if ((Object)(object)player == (Object)(object)Player.m_localPlayer) { if (((Character)player).IsAttached() && (Object)(object)player.GetAttachPoint() == (Object)(object)AttachPoint) { return (object)player.GetDoodadController() == this; } return false; } ZNetView component = ((Component)player).GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid()) { return false; } ZDO zDO = component.GetZDO(); if (zDO.GetConnectionZDOID((ConnectionType)2) == _view.GetZDO().m_uid) { return Vector3.Distance(zDO.GetVec3(ZDOVars.s_relPosHash, Vector3.positiveInfinity), ((Component)_cart).transform.InverseTransformPoint(AttachPoint.position)) <= 0.3f; } return false; } public void ApplyControlls(Vector3 moveDir, Vector3 lookDir, bool run, bool autoRun, bool block) { } public Component GetControlledComponent() { return (Component)(object)this; } public Vector3 GetPosition() { //IL_001f: 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) if (!Object.op_Implicit((Object)(object)AttachPoint)) { return ((Component)this).transform.position; } return AttachPoint.position; } public bool IsValid() { if (Object.op_Implicit((Object)(object)this)) { return Ready; } return false; } public void OnUseStop(Player player) { _partner = null; if (Object.op_Implicit((Object)(object)player) && (Object)(object)player.GetAttachPoint() == (Object)(object)AttachPoint) { ((Character)player).AttachStop(); } ReleaseReservation(); } public void StopLocalPartner() { Player partner = _partner; if (Object.op_Implicit((Object)(object)partner)) { OnUseStop(partner); if ((object)partner.GetDoodadController() == this) { partner.StopDoodadControl(); } } else if (_pending || _localToken.Length != 0) { ReleaseReservation(); } } private void OnDestroy() { StopLocalPartner(); if (_registered && Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { _view.Unregister("VR_PumpPartnerRequest"); _view.Unregister("VR_PumpPartnerReply"); _view.Unregister("VR_PumpPartnerRenew"); _view.Unregister("VR_PumpPartnerRelease"); _view.Unregister("VR_PumpPartnerCheckpoint"); _view.Unregister("VR_PumpPartnerCheckpointReply"); } _registered = false; } private static bool CanAccessWard(Vector3 point, long playerId) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) if (WardList == null || WardEnabled == null || WardInside == null || WardPermitted == null) { return false; } if (!(WardList.GetValue(null) is IEnumerable enumerable)) { return false; } bool flag = false; foreach (PrivateArea item in enumerable) { if (Object.op_Implicit((Object)(object)item) && true.Equals(WardEnabled.Invoke(item, null)) && true.Equals(WardInside.Invoke(item, new object[2] { point, 0f }))) { Piece component = ((Component)item).GetComponent(); if ((Object.op_Implicit((Object)(object)component) && component.GetCreator() == playerId) || true.Equals(WardPermitted.Invoke(item, new object[1] { playerId }))) { return true; } flag = true; } } return !flag; } private static void Tell(string text) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); } } } public sealed class RailPushHandle : MonoBehaviour, Hoverable, Interactable { private RailVehicle? _cart; private void Awake() { _cart = ((Component)this).GetComponentInParent(); } public float GetHoverOffset() { return 0f; } public string GetHoverName() { return "Cart push handle"; } public string GetHoverText() { return Localization.instance.Localize(GetHoverName() + "\n[$KEY_Use] " + ((Object.op_Implicit((Object)(object)_cart) && (Object)(object)RailVehicle.LocalDriven == (Object)(object)_cart) ? "Release push handle" : "Push cart slowly") + "\n[$KEY_AltPlace + $KEY_Use] " + ((Object.op_Implicit((Object)(object)_cart) && _cart.IsCoupled) ? "Uncouple" : "Couple")); } public bool Interact(Humanoid user, bool hold, bool alt) { if (!hold && Object.op_Implicit((Object)(object)_cart) && !_cart.IsEngine) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer)) { if (!alt) { return _cart.BeginHandPush(val); } return _cart.ToggleCoupling(val); } } return false; } public bool UseItem(Humanoid user, ItemData item) { return false; } } internal static class RailRemoteDrive { private sealed class Member { internal ZDOID Id; internal long Owner; internal long Stamp = -1L; internal string Digest = ""; } private sealed class Session { internal ZDOID Engine; internal string Token = ""; internal long Peer; internal long Player; internal float Until; internal float NextYield; internal bool Active; internal long Order; internal string Waiting = "Waiting for the train and its owners to load."; internal readonly List Members = new List(); } private sealed class YieldCache { internal float Until; internal byte[] Reply = Array.Empty(); } internal const int MaximumMembers = 320; private const string RequestRpc = "VR_RemoteRequest_v1"; private const string ReplyRpc = "VR_RemoteReply_v1"; private const string YieldRpc = "VR_RemoteYield_v1"; private const string YieldReplyRpc = "VR_RemoteYieldReply_v1"; private const float Timeout = 45f; private static ZNet? _network; private static readonly HashSet Registered = new HashSet(); private static readonly Dictionary Sessions = new Dictionary(); private static readonly Dictionary Yielded = new Dictionary(); private static string _requestToken = ""; private static float _requestUntil; private static long _nextSessionOrder; private static long Server { get { if (Object.op_Implicit((Object)(object)ZNet.instance)) { if (!ZNet.instance.IsServer()) { return ZNet.instance.GetServerPeer()?.m_uid ?? 0; } return ZNet.GetUID(); } return 0L; } } private static long Now { get { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return 0L; } return (long)(ZNet.instance.GetTimeSeconds() * 1000.0); } } internal static bool IsActive(ZDOID id) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (Sessions.TryGetValue(id, out Session value)) { return value.Active; } return false; } internal static bool IsPreparing(RailVehicle cart) { if (!Object.op_Implicit((Object)(object)cart) || !cart.IsReady) { return false; } long num = cart.View.GetZDO().GetLong("vikingrail_remote_prepare_until", 0L); if (num <= Now || num > Now + 60000) { return Sessions.Values.Any((Session s) => !s.Active && SameConsist(s, cart)); } return true; } private static bool SameConsist(Session session, RailVehicle cart) { //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_0027: 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_0055: Unknown result type (might be due to invalid IL or missing references) if (!cart.IsReady) { return false; } ZDOID identity = cart.View.GetZDO().m_uid; if (session.Engine == identity || session.Members.Any((Member member) => member.Id == identity)) { return true; } RailVehicle railVehicle = Engine(session.Engine); if (Object.op_Implicit((Object)(object)railVehicle) && railVehicle.IsReady && cart.TryCargoRoot(out RailVehicle root) && railVehicle.TryCargoRoot(out RailVehicle root2)) { return (Object)(object)root == (Object)(object)root2; } return false; } internal static void Update() { if (_network != ZNet.instance) { Reset(); _network = ZNet.instance; } if (!Object.op_Implicit((Object)(object)_network) || !Object.op_Implicit((Object)(object)ZNetScene.instance) || ZDOMan.instance == null) { return; } ZRpc[] array = Registered.Where((ZRpc rpc) => !_network.GetPeers().Any((ZNetPeer p) => p.m_rpc == rpc && p.IsReady() && rpc.IsConnected())).ToArray(); foreach (ZRpc val in array) { val.Unregister("VR_RemoteRequest_v1"); val.Unregister("VR_RemoteReply_v1"); val.Unregister("VR_RemoteYield_v1"); val.Unregister("VR_RemoteYieldReply_v1"); Registered.Remove(val); } foreach (ZNetPeer peer in _network.GetPeers()) { if (!peer.IsReady() || !peer.m_rpc.IsConnected() || !Registered.Add(peer.m_rpc)) { continue; } if (_network.IsServer()) { peer.m_rpc.Register("VR_RemoteRequest_v1", (Action)delegate(ZRpc rpc, ZPackage p) { WithClient(rpc, delegate(long uid) { ReceiveRequest(uid, p); }); }); peer.m_rpc.Register("VR_RemoteYieldReply_v1", (Action)delegate(ZRpc rpc, ZPackage p) { WithClient(rpc, delegate(long uid) { ReceiveYieldReply(uid, p); }); }); } else { if (peer != _network.GetServerPeer()) { continue; } peer.m_rpc.Register("VR_RemoteYield_v1", (Action)delegate(ZRpc rpc, ZPackage p) { if (IsServerConnection(rpc)) { ReceiveYield(p); } }); peer.m_rpc.Register("VR_RemoteReply_v1", (Action)delegate(ZRpc rpc, ZPackage p) { if (IsServerConnection(rpc)) { ReceiveReply(p); } }); } } if (_requestToken.Length != 0 && Time.unscaledTime >= _requestUntil) { _requestToken = ""; Tell("Automatic train request timed out. Check its controller and try again."); } string[] array2 = (from p in Yielded where Time.unscaledTime >= p.Value.Until select p.Key).ToArray(); foreach (string key in array2) { Yielded.Remove(key); } if (!_network.IsServer()) { return; } RailRemoteWorld.Update(); Session[] array3 = Sessions.Values.ToArray(); foreach (Session s in array3) { try { UpdateSession(s); } catch (Exception error) { RailPlugin.Error(error); End(s, "Automatic train stopped after a loading error."); } } } private static bool IsServerConnection(ZRpc rpc) { if (Object.op_Implicit((Object)(object)_network) && _network == ZNet.instance && !_network.IsServer() && _network.GetServerPeer()?.m_rpc == rpc) { return rpc.IsConnected(); } return false; } private static void WithClient(ZRpc rpc, Action receive) { if (Object.op_Implicit((Object)(object)_network) && _network == ZNet.instance && _network.IsServer()) { ZNetPeer val = ((IEnumerable)_network.GetPeers()).FirstOrDefault((Func)((ZNetPeer p) => p.IsReady() && p.m_rpc == rpc && rpc.IsConnected())); if (val != null) { receive(val.m_uid); } } } internal static bool Request(RailVehicle engine, Player player, bool start) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_0068: 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_00b1: Expected O, but got Unknown if (_requestToken.Length != 0 || !RailSettings.Ready || Server == 0L) { return false; } _requestToken = Guid.NewGuid().ToString("N"); _requestUntil = Time.unscaledTime + 45f + 10f; if (start) { Tell("Preparing the automatic train on the server. Stay beside the parked engine until it is ready."); } ZPackage val = new ZPackage(); val.Write(engine.View.GetZDO().m_uid); val.Write(player.GetPlayerID()); val.Write(start); val.Write(_requestToken); if (ZNet.instance.IsServer()) { ReceiveRequest(ZNet.GetUID(), new ZPackage(val.GetArray())); } else { ZNet.instance.GetServerPeer().m_rpc.Invoke("VR_RemoteRequest_v1", new object[1] { val }); } return true; } private static bool Readable(ZPackage p) { if (p != null && p.Size() > 0) { return p.Size() <= 32768; } return false; } private static bool ValidToken(string token) { Guid result; if (token.Length == 32) { return Guid.TryParseExact(token, "N", out result); } return false; } private static RailVehicle? Engine(ZDOID id) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) GameObject val = (Object.op_Implicit((Object)(object)ZNetScene.instance) ? ZNetScene.instance.FindInstance(id) : null); if (!Object.op_Implicit((Object)(object)val)) { return null; } return val.GetComponent(); } private static bool Requester(long peer, long playerId, ZDOID id) { //IL_0064: 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_00f8: 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) ZDO val2; if (peer == ZNet.GetUID()) { Player localPlayer = Player.m_localPlayer; ZNetView val = (Object.op_Implicit((Object)(object)localPlayer) ? ((Component)localPlayer).GetComponent() : null); val2 = ((Object.op_Implicit((Object)(object)val) && val.IsValid()) ? val.GetZDO() : null); } else { ZNetPeer peer2 = ZNet.instance.GetPeer(peer); val2 = ((peer2 != null && peer2.IsReady()) ? ZDOMan.instance.GetZDO(peer2.m_characterID) : null); } ZDO zDO = ZDOMan.instance.GetZDO(id); if (val2 == null || zDO == null || val2.GetOwner() != peer || val2.GetPrefab() != StringExtensionMethods.GetStableHashCode("Player") || val2.GetLong(ZDOVars.s_playerID, 0L) != playerId || val2.GetBool(ZDOVars.s_dead, false) || val2.GetFloat(ZDOVars.s_health, 0f) <= 0f || (zDO.GetPrefab() != StringExtensionMethods.GetStableHashCode("vr_locomotive") && zDO.GetPrefab() != StringExtensionMethods.GetStableHashCode("vr_eitr_engine"))) { return false; } float num = Vector3.Distance(val2.GetPosition(), zDO.GetPosition()); if (!float.IsNaN(num) && !float.IsInfinity(num)) { return num <= 5f; } return false; } private static void ReceiveRequest(long peer, ZPackage p) { //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_0063: 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_014e: 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_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: 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_01cf: 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_01d7: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)ZNet.instance) || !ZNet.instance.IsServer() || !Readable(p)) { return; } try { ZDOID val = p.ReadZDOID(); long num = p.ReadLong(); bool flag = p.ReadBool(); string token = p.ReadString(); if (p.GetPos() != p.Size() || !ValidToken(token)) { return; } if (!Requester(peer, num, val)) { Reply(peer, token, "Stand beside the engine with your living character before using its controller."); return; } RailVehicle engine = Engine(val); string reason; if (!flag) { if (!Object.op_Implicit((Object)(object)engine) || !engine.IsReady || !RailWardAccess.Allows(((Component)engine).transform.position, num)) { Reply(peer, token, "Stand beside the loaded engine with ward access to stop it."); return; } if (Sessions.TryGetValue(val, out Session value)) { End(value, "Automatic train stopped by its controller."); } else if (engine.View.IsOwner()) { engine.StopAutomaticDrive("Automatic drive stopped by its controller."); } Reply(peer, token, "Automatic train stopped."); } else if (!RailSettings.RemoteSimulationEnabled || !RailRemoteWorld.Available) { Reply(peer, token, "Remote train simulation is disabled or unavailable on this game build."); } else if (Sessions.ContainsKey(val)) { Reply(peer, token, "This train is already running or preparing to depart."); } else if (Object.op_Implicit((Object)(object)engine) && Sessions.Values.Any((Session session) => SameConsist(session, engine))) { Reply(peer, token, "Another engine in this train is already running or preparing automatic travel."); } else if (!RailRemoteWorld.TryReserve(val, ZDOMan.instance.GetZDO(val).GetPosition(), out reason)) { Reply(peer, token, reason); } else { Sessions.Add(val, new Session { Engine = val, Peer = peer, Player = num, Token = token, Order = ++_nextSessionOrder, Until = Time.unscaledTime + 45f }); } } catch (Exception ex) { RailPlugin.Warn("Ignored invalid automatic train request: " + ex.Message); } } private unsafe static void UpdateSession(Session s) { //IL_007b: 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_019c: 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_01df: 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_0234: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0639: Unknown result type (might be due to invalid IL or missing references) //IL_037d: Unknown result type (might be due to invalid IL or missing references) //IL_0382: Unknown result type (might be due to invalid IL or missing references) //IL_03bd: Unknown result type (might be due to invalid IL or missing references) //IL_066a: Unknown result type (might be due to invalid IL or missing references) //IL_052b: Unknown result type (might be due to invalid IL or missing references) //IL_0532: Expected O, but got Unknown //IL_053a: Unknown result type (might be due to invalid IL or missing references) //IL_06d4: Unknown result type (might be due to invalid IL or missing references) //IL_05b2: Unknown result type (might be due to invalid IL or missing references) //IL_05e5: Unknown result type (might be due to invalid IL or missing references) //IL_05ef: Expected O, but got Unknown if (!RailSettings.RemoteSimulationEnabled || !RailRemoteWorld.Available || ZNet.instance.GetNrOfPlayers() == 0) { End(s, "Automatic train stopped: remote simulation disabled or nobody is connected. Activate it again when ready."); return; } if (Sessions.Keys.OrderBy((ZDOID id) => ((object)(*(ZDOID*)(&id))/*cast due to .constrained prefix*/).ToString(), StringComparer.Ordinal).Skip(RailSettings.RemoteTrainLimit).Contains(s.Engine)) { End(s, "Automatic train stopped: the server's remote-train limit was reduced."); return; } RailVehicle engine = Engine(s.Engine); string reason; if (s.Active) { List positions; if (!Object.op_Implicit((Object)(object)engine) || !engine.IsReady || !engine.AutoDriveActive || !engine.View.IsOwner() || s.Members.Any(delegate(Member m) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) ZDO zDO2 = ZDOMan.instance.GetZDO(m.Id); return ((zDO2 != null) ? new long?(zDO2.GetOwner()) : ((long?)null)) != Server; })) { End(s, "Automatic train stopped: a train member or its authority changed."); } else if (!engine.RemoteLoadingPositions(out positions) || !RailRemoteWorld.Refresh(s.Engine, positions)) { End(s, "Automatic train stopped: its loaded area exceeded the server limit."); } } else if (Time.unscaledTime >= s.Until || !Requester(s.Peer, s.Player, s.Engine)) { End(s, "Automatic train preparation stopped. Stay beside the parked engine. " + s.Waiting); } else if (!RailRemoteWorld.TryReserve(s.Engine, ZDOMan.instance.GetZDO(s.Engine).GetPosition(), out reason)) { End(s, reason); } else { if (!Object.op_Implicit((Object)(object)engine) || !engine.IsReady) { return; } if (engine.RemoteLoadingPositions(out List positions2) && !RailRemoteWorld.Refresh(s.Engine, positions2)) { End(s, "This train needs too large a loading area."); } else { if (s.Members.Count == 0 && !RailRemoteWorld.IsReady(s.Engine)) { return; } if (Sessions.Values.Any((Session other) => other != s && (other.Active || other.Members.Count != 0 || other.Order < s.Order) && SameConsist(other, engine))) { End(s, "Another engine in this train is already preparing or running automatic travel."); return; } if (!engine.TryRemoteMembers(s.Peer, s.Player, out List views, out string reason2)) { s.Waiting = reason2; return; } if (Sessions.Values.Any((Session other) => other != s && (other.Active || other.Members.Count != 0 || other.Order < s.Order) && (views.Any((ZNetView view) => view.GetZDO().m_uid == other.Engine) || other.Members.Any((Member member) => views.Any((ZNetView view) => view.GetZDO().m_uid == member.Id))))) { End(s, "Another engine in this train is already preparing or running automatic travel."); return; } if (s.Members.Count == 0) { if (views.Any((ZNetView v) => !v.HasOwner())) { return; } foreach (ZNetView item in views) { s.Members.Add(new Member { Id = item.GetZDO().m_uid, Owner = item.GetZDO().GetOwner() }); } if (!RailRemoteWorld.Pin(s.Engine, s.Members.Select((Member m) => m.Id))) { End(s, "Could not reserve the train's network objects."); return; } } if (views.Count != s.Members.Count || views.Any((ZNetView v) => !s.Members.Any((Member m) => m.Id == v.GetZDO().m_uid))) { End(s, "The train's couplings or attachments changed. Try again."); return; } if (s.Members.Any(delegate(Member m) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (m.Stamp < 0) { ZDO zDO2 = ZDOMan.instance.GetZDO(m.Id); if (zDO2 != null && zDO2.GetOwner() != m.Owner) { return zDO2.GetOwner() != Server; } } return false; })) { End(s, "A train member changed owners while preparing. Let ownership settle, then activate the controller again."); return; } if (Time.unscaledTime >= s.NextYield) { s.NextYield = Time.unscaledTime + 0.75f; long[] array = (from m in s.Members where m.Stamp < 0 select m.Owner).Distinct().ToArray(); foreach (long num2 in array) { ZPackage val = new ZPackage(); val.Write(s.Engine); val.Write(s.Token); val.Write(s.Peer); val.Write(s.Player); val.Write(s.Members.Count); foreach (Member member in s.Members) { val.Write(member.Id); } if (num2 == Server) { ReceiveYield(new ZPackage(val.GetArray())); continue; } ZNetPeer peer = ZNet.instance.GetPeer(num2); if (peer != null) { peer.m_rpc.Invoke("VR_RemoteYield_v1", new object[1] { val }); } } } if (!Sessions.ContainsKey(s.Engine)) { return; } foreach (Member member2 in s.Members) { ZDO zDO = ZDOMan.instance.GetZDO(member2.Id); if (zDO == null || !RailRemoteTransfer.IsAcknowledged(Server, zDO.GetOwner(), zDO.OwnerRevision, zDO.DataRevision, member2.Stamp, member2.Digest, RailCargoInventory.InventoryDigest(zDO))) { return; } } if (RailRemoteWorld.IsReady(s.Engine)) { if (!engine.StartRemoteDrive(s.Peer, s.Player, s.Token, (IReadOnlyCollection)(object)s.Members.Select((Member m) => m.Id).ToArray(), out reason2)) { End(s, reason2); return; } s.Active = true; ClearLeases(s); Reply(s.Peer, s.Token, reason2); } } } } private static void ReceiveYield(ZPackage p) { //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_0067: 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_00ca: 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_00c5: Expected O, but got Unknown //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Expected O, but got Unknown //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) if (!Readable(p)) { return; } try { ZDOID val = p.ReadZDOID(); string text = p.ReadString(); long peer = p.ReadLong(); long playerId = p.ReadLong(); int num = p.ReadInt(); if (!ValidToken(text) || num < 2 || num > 320) { return; } HashSet expected = new HashSet(); for (int i = 0; i < num; i++) { if (!expected.Add(p.ReadZDOID())) { return; } } if (p.GetPos() != p.Size() || !expected.Contains(val)) { return; } if (Yielded.TryGetValue(text, out YieldCache value)) { SendYieldReply(new ZPackage(value.Reply)); return; } RailVehicle railVehicle = Engine(val); if (!Object.op_Implicit((Object)(object)railVehicle) || !railVehicle.TryRemoteMembers(peer, playerId, out List members, out string error) || members.Count != expected.Count || members.Any((ZNetView v) => !expected.Contains(v.GetZDO().m_uid))) { return; } ZNetView[] array = members.Where((ZNetView v) => v.IsOwner()).ToArray(); if (array.Length == 0) { return; } ZNetView[] array2 = array; for (int num2 = 0; num2 < array2.Length; num2++) { Container component = ((Component)array2[num2]).GetComponent(); if (Object.op_Implicit((Object)(object)component) && !RailCargoInventory.TryRefresh(component, out error)) { return; } } ZPackage val2 = new ZPackage(); val2.Write(val); val2.Write(text); val2.Write(array.Length); array2 = array; foreach (ZNetView obj in array2) { RailVehicle component2 = ((Component)obj).GetComponent(); if (Object.op_Implicit((Object)(object)component2)) { component2.SaveRemoteHandoffPose(); } ZDO zDO = obj.GetZDO(); zDO.Set("vikingrail_remote_prepare_until", Now + 45000); string text2 = RailCargoInventory.InventoryDigest(zDO); zDO.SetOwner(Server); val2.Write(zDO.m_uid); val2.Write((long)(((ulong)zDO.OwnerRevision << 32) | zDO.DataRevision)); val2.Write(text2); ZDOMan.instance.ForceSendZDO(Server, zDO.m_uid); } Yielded[text] = new YieldCache { Until = Time.unscaledTime + 45f + 5f, Reply = val2.GetArray() }; SendYieldReply(val2); } catch (Exception ex) { RailPlugin.Warn("Automatic train ownership handoff failed: " + ex.Message); } } private static void SendYieldReply(ZPackage p) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown if (ZNet.instance.IsServer()) { ReceiveYieldReply(Server, new ZPackage(p.GetArray())); return; } ZNetPeer serverPeer = ZNet.instance.GetServerPeer(); if (serverPeer != null) { serverPeer.m_rpc.Invoke("VR_RemoteYieldReply_v1", new object[1] { p }); } } private static void ReceiveYieldReply(long peer, ZPackage p) { //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_0031: 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_0091: 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 (!Readable(p)) { return; } try { ZDOID key = p.ReadZDOID(); string text = p.ReadString(); int num = p.ReadInt(); if (!Sessions.TryGetValue(key, out Session value) || value.Active || value.Token != text || num < 1 || num > 320) { return; } List> list = new List>(); HashSet hashSet = new HashSet(); for (int i = 0; i < num; i++) { ZDOID memberId = p.ReadZDOID(); long num2 = p.ReadLong(); string text2 = p.ReadString(); Member member = value.Members.FirstOrDefault((Member m) => m.Id == memberId && m.Owner == peer); if (member == null || !hashSet.Add(memberId) || num2 < 0 || num2 >> 48 != 0L || text2.Length != 64 || text2.Any((char c) => !Uri.IsHexDigit(c))) { return; } list.Add(Tuple.Create(member, num2, text2)); } if (p.GetPos() != p.Size()) { return; } foreach (Tuple item in list) { if (item.Item1.Stamp < 0) { item.Item1.Stamp = item.Item2; item.Item1.Digest = item.Item3; } } } catch (Exception ex) { RailPlugin.Warn("Ignored invalid train ownership reply: " + ex.Message); } } private static void ClearLeases(Session s) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) foreach (Member member in s.Members) { ZDOMan instance = ZDOMan.instance; ZDO val = ((instance != null) ? instance.GetZDO(member.Id) : null); if (val != null && val.IsOwner()) { val.Set("vikingrail_remote_prepare_until", 0L); } } } private static void End(Session s, string reason) { //IL_0006: 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_0062: Unknown result type (might be due to invalid IL or missing references) Sessions.Remove(s.Engine); RailVehicle railVehicle = Engine(s.Engine); if (Object.op_Implicit((Object)(object)railVehicle) && railVehicle.IsReady && railVehicle.View.IsOwner()) { railVehicle.StopAutomaticDrive(reason); railVehicle.View.GetZDO().Set("vikingrail_remote_session", ""); } ClearLeases(s); RailRemoteWorld.Release(s.Engine); if (!s.Active) { Reply(s.Peer, s.Token, reason); } } private static void Reply(long peer, string token, string reason) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(token); val.Write(reason); if (peer == Server) { ReceiveReply(new ZPackage(val.GetArray())); return; } ZNetPeer peer2 = ZNet.instance.GetPeer(peer); if (peer2 != null) { peer2.m_rpc.Invoke("VR_RemoteReply_v1", new object[1] { val }); } } private static void ReceiveReply(ZPackage p) { if (!Readable(p)) { return; } try { string text = p.ReadString(); string message = p.ReadString(); if (p.GetPos() == p.Size() && !(text != _requestToken) && text.Length != 0) { _requestToken = ""; Tell(message); } } catch (Exception ex) { RailPlugin.Warn("Ignored invalid automatic train reply: " + ex.Message); } } private static void Tell(string message) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false); } } internal static void Reset() { if (Object.op_Implicit((Object)(object)_network) && _network == ZNet.instance && _network.IsServer()) { Session[] array = Sessions.Values.ToArray(); for (int i = 0; i < array.Length; i++) { End(array[i], "Automatic train stopped because the session ended."); } } foreach (ZRpc item in Registered) { item.Unregister("VR_RemoteRequest_v1"); item.Unregister("VR_RemoteReply_v1"); item.Unregister("VR_RemoteYield_v1"); item.Unregister("VR_RemoteYieldReply_v1"); } Registered.Clear(); Sessions.Clear(); Yielded.Clear(); _requestToken = ""; _nextSessionOrder = 0L; RailRemoteWorld.Reset(); _network = null; } } internal static class RailRemoteWorld { private sealed class Anchor { internal readonly HashSet Zones = new HashSet(); internal readonly HashSet Pins = new HashSet(); internal float Refreshed; } internal static class Native { private static readonly MethodInfo? GetZone = AccessTools.Method(typeof(ZoneSystem), "GetZone", new Type[1] { typeof(Vector3) }, (Type[])null); private static readonly Type? ZoneType = GetZone?.ReturnType; private static readonly MethodInfo? PokeZone = ((ZoneType == null) ? null : AccessTools.Method(typeof(ZoneSystem), "PokeLocalZone", new Type[1] { ZoneType }, (Type[])null)); private static readonly MethodInfo? Loaded = ((ZoneType == null) ? null : AccessTools.Method(typeof(ZoneSystem), "IsZoneLoaded", new Type[1] { ZoneType }, (Type[])null)); private static readonly MethodInfo? Ready = ((ZoneType == null) ? null : AccessTools.Method(typeof(ZoneSystem), "IsZoneReadyForType", new Type[2] { ZoneType, typeof(ObjectType) }, (Type[])null)); private static readonly FieldInfo? ZoneMap = AccessTools.Field(typeof(ZoneSystem), "m_zones"); private static readonly MethodInfo? CreateObject = AccessTools.Method(typeof(ZNetScene), "CreateObject", new Type[1] { typeof(ZDO) }, (Type[])null); internal static readonly MethodInfo? CreateObjects = AccessTools.Method(typeof(ZNetScene), "CreateObjects", new Type[2] { typeof(List), typeof(List) }, (Type[])null); internal static readonly MethodInfo? RemoveObjects = AccessTools.Method(typeof(ZNetScene), "RemoveObjects", new Type[2] { typeof(List), typeof(List) }, (Type[])null); internal static readonly MethodInfo? ReleaseNearby = AccessTools.Method(typeof(ZDOMan), "ReleaseNearbyZDOS", new Type[2] { typeof(Vector3), typeof(long) }, (Type[])null); internal static readonly MethodInfo? PeerArea = AccessTools.Method(typeof(ZDOMan), "IsInPeerActiveArea", new Type[2] { typeof(Vector3), typeof(long) }, (Type[])null); internal static readonly MethodInfo? SetOwner = AccessTools.Method(typeof(ZDO), "SetOwner", new Type[1] { typeof(long) }, (Type[])null); internal static readonly MethodInfo? Outside = AccessTools.Method(typeof(ZNetScene), "OutsideActiveArea", new Type[1] { typeof(Vector3) }, (Type[])null); private static readonly MethodInfo? Search = FindSearch(); private static object? _distance; internal static bool Compatible { get { if (GetZone != null && PokeZone?.ReturnType == typeof(bool) && Loaded?.ReturnType == typeof(bool) && Ready?.ReturnType == typeof(bool) && ZoneMap != null && typeof(IDictionary).IsAssignableFrom(ZoneMap.FieldType) && CreateObject?.ReturnType == typeof(GameObject) && CreateObjects != null && RemoveObjects != null && ReleaseNearby != null && PeerArea?.ReturnType == typeof(bool) && SetOwner != null && Outside?.ReturnType == typeof(bool)) { return Search != null; } return false; } } private static object Zone(RailZoneCoord zone) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) return GetZone.Invoke(null, new object[1] { (object)new Vector3((float)zone.X * 64f, 0f, (float)zone.Y * 64f) }); } internal static void Poke(ZoneSystem terrain, RailZoneCoord zone) { PokeZone.Invoke(terrain, new object[1] { Zone(zone) }); } internal static bool ZoneExists(ZoneSystem terrain, RailZoneCoord zone) { return ((IDictionary)ZoneMap.GetValue(terrain)).Contains(Zone(zone)); } internal static bool ZoneLoaded(ZoneSystem terrain, RailZoneCoord zone) { return (bool)Loaded.Invoke(terrain, new object[1] { Zone(zone) }); } internal static bool ZoneReady(ZoneSystem terrain, RailZoneCoord zone, ObjectType type) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) return (bool)Ready.Invoke(terrain, new object[2] { Zone(zone), type }); } internal static void Create(ZNetScene scene, ZDO zdo) { CreateObject.Invoke(scene, new object[1] { zdo }); } internal static bool PeerActive(ZDOMan manager, Vector3 position, long peer) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) return (bool)PeerArea.Invoke(manager, new object[2] { position, peer }); } private static MethodInfo? FindSearch() { MethodInfo[] methods = typeof(ZDOMan).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (!(methodInfo.Name != "FindSectorObjects")) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length == 4 && parameters[0].ParameterType == ZoneType && parameters[1].ParameterType.Name == "SimulationDistance" && parameters[2].ParameterType == typeof(List) && parameters[3].ParameterType == typeof(List) && (parameters[1].ParameterType.GetConstructor(new Type[3] { typeof(int), typeof(int), typeof(bool) }) != null || parameters[1].ParameterType.GetConstructor(new Type[2] { typeof(int), typeof(int) }) != null)) { return methodInfo; } } } return null; } internal static void Find(ZDOMan manager, RailZoneCoord zone, List output) { if (_distance == null) { Type parameterType = Search.GetParameters()[1].ParameterType; ConstructorInfo constructor = parameterType.GetConstructor(new Type[3] { typeof(int), typeof(int), typeof(bool) }); _distance = ((constructor != null) ? constructor.Invoke(new object[3] { 0, 0, false }) : parameterType.GetConstructor(new Type[2] { typeof(int), typeof(int) }).Invoke(new object[2] { 0, 0 })); } Search.Invoke(manager, new object[4] { Zone(zone), _distance, output, null }); } } private const float LeaseSeconds = 10f; private const int MaximumPins = 320; private const int ObjectBudget = 24; private static readonly Dictionary Anchors = new Dictionary(); private static readonly HashSet Zones = new HashSet(); private static readonly HashSet Pins = new HashSet(); private static readonly List Objects = new List(); private static readonly List SectorObjects = new List(); private static readonly HashSet Seen = new HashSet(); private static ZNet? _network; private static ZDOMan? _manager; private static ZNetScene? _scene; private static ZoneSystem? _terrain; private static string _failure = ""; private static float _nextUpdate; private static int _zoneTurn; internal static int NativeReleaseDepth; internal static bool Available { get { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 EnsureWorld(); if (Native.Compatible && _failure.Length == 0 && ServerWorld && (int)ZNet.GetConnectionStatus() == 2 && _terrain.LocationsGenerated && RailSettings.Ready && RailSettings.RemoteSimulationEnabled) { return _network.GetNrOfPlayers() > 0; } return false; } } internal static string UnavailableReason { get { if (Native.Compatible) { if (_failure.Length == 0) { if (RailSettings.RemoteSimulationEnabled) { if (ServerWorld) { if (_network.GetNrOfPlayers() != 0) { return "Remote train simulation is unavailable."; } return "Automatic trains stop when no players are online."; } return "Waiting for the server's world to load."; } return "Remote train simulation is disabled by the server."; } return _failure; } return "This Valheim build does not support the remote train loading hooks."; } } private static bool ServerWorld { get { if (Object.op_Implicit((Object)(object)_network) && _network.IsServer() && _manager != null && Object.op_Implicit((Object)(object)_scene)) { return Object.op_Implicit((Object)(object)_terrain); } return false; } } private static bool Holding { get { if (ServerWorld && Native.Compatible) { return Anchors.Count != 0; } return false; } } internal static bool TryReserve(ZDOID engineId, Vector3 position, out string reason) { //IL_001e: 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_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: 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_008a: Unknown result type (might be due to invalid IL or missing references) if (!Available) { reason = UnavailableReason; return false; } if (((ZDOID)(ref engineId)).IsNone() || _manager.GetZDO(engineId) == null) { reason = "The engine's saved network object is unavailable."; return false; } if (!Anchors.ContainsKey(engineId) && Anchors.Count >= RailSettings.RemoteTrainLimit) { reason = "The server's remote train limit has been reached."; return false; } if (!Collect((IReadOnlyList)(object)new Vector3[1] { position }, out IReadOnlyCollection footprint)) { reason = "The engine is outside the supported world-loading area."; return false; } if (!Anchors.TryGetValue(engineId, out Anchor value)) { Anchors.Add(engineId, value = new Anchor()); } if (value.Zones.Count == 0) { value.Zones.UnionWith(footprint); } value.Refreshed = Time.time; RebuildUnion(); reason = ""; return true; } internal static bool Refresh(ZDOID engineId, IReadOnlyList consistPositions) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (!Available || !Anchors.TryGetValue(engineId, out Anchor value) || !Collect(consistPositions, out IReadOnlyCollection footprint)) { return false; } value.Zones.Clear(); value.Zones.UnionWith(footprint); value.Refreshed = Time.time; RebuildUnion(); return true; } internal static bool Pin(ZDOID engineId, IEnumerable ownedIds) { //IL_000c: 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_0035: 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_0057: Unknown result type (might be due to invalid IL or missing references) if (!Available || !Anchors.TryGetValue(engineId, out Anchor value) || ownedIds == null) { return false; } HashSet hashSet = new HashSet { engineId }; int num = 0; foreach (ZDOID ownedId in ownedIds) { ZDOID current = ownedId; if (++num > 320 || ((ZDOID)(ref current)).IsNone()) { return false; } hashSet.Add(current); } if (hashSet.Count > 320 || hashSet.Any(delegate(ZDOID id) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) ZDO zDO = _manager.GetZDO(id); return zDO == null || IsPlayerObject(zDO); })) { return false; } value.Pins.Clear(); value.Pins.UnionWith(hashSet); value.Refreshed = Time.time; RebuildUnion(); return true; } internal static bool IsReady(ZDOID engineId) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0102: 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_010e: Unknown result type (might be due to invalid IL or missing references) if (!Available || !Anchors.TryGetValue(engineId, out Anchor value)) { return false; } try { foreach (RailZoneCoord zone in value.Zones) { if (!Native.ZoneLoaded(_terrain, zone)) { return false; } } List list = new List(); ReadObjects(value.Zones, list); foreach (ZDO item in list) { if (item.GetPrefab() != 0) { if (!Object.op_Implicit((Object)(object)_scene.GetPrefab(item.GetPrefab()))) { return false; } ZNetView val = _scene.FindInstance(item); if (!Object.op_Implicit((Object)(object)val) || !((Component)val).gameObject.activeInHierarchy) { return false; } } } foreach (ZDOID pin in value.Pins) { ZDO zDO = _manager.GetZDO(pin); if (zDO == null || zDO.GetOwner() != ZDOMan.GetSessionID() || !Object.op_Implicit((Object)(object)_scene.FindInstance(zDO))) { return false; } } return true; } catch (Exception error) { Fail(error); return false; } } internal static void Release(ZDOID engineId) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (Anchors.Remove(engineId)) { RebuildUnion(); } } internal static bool IsPinned(ZDOID id) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (Holding) { return Pins.Contains(id); } return false; } internal static bool ContainsPosition(Vector3 point) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) if (Holding && TryZone(point, out var zone)) { return Zones.Contains(zone); } return false; } internal static void Update() { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) EnsureWorld(); if (!ServerWorld || Anchors.Count == 0 || Time.timeScale <= 0f || Time.time < _nextUpdate) { return; } _nextUpdate = Time.time + 0.1f; ZDOID[] array = (from pair in Anchors where Time.time - pair.Value.Refreshed > 10f || _manager.GetZDO(pair.Key) == null select pair.Key).ToArray(); for (int num = 0; num < array.Length; num++) { Release(array[num]); } if (Anchors.Count == 0 || !Available) { return; } try { RailZoneCoord[] array2 = (from railZoneCoord in Zones orderby railZoneCoord.X, railZoneCoord.Y select railZoneCoord).ToArray(); RailZoneCoord[] array3 = array2; foreach (RailZoneCoord zone in array3) { if (Native.ZoneExists(_terrain, zone)) { Native.Poke(_terrain, zone); } } for (int num2 = 0; num2 < array2.Length; num2++) { int num3 = (_zoneTurn + num2) % array2.Length; if (!Native.ZoneExists(_terrain, array2[num3])) { Native.Poke(_terrain, array2[num3]); _zoneTurn = (num3 + 1) % array2.Length; break; } } ReadObjects(Zones, Objects); int num4 = 0; foreach (ZDO item in Objects.OrderByDescending((ZDO item) => (int)item.Type)) { if (item.Persistent && !IsPlayerObject(item) && item.GetOwner() != ZDOMan.GetSessionID() && (!item.HasOwner() || !IsTrainObject(item)) && (!item.HasOwner() || !Native.PeerActive(_manager, item.GetPosition(), item.GetOwner()))) { item.SetOwner(ZDOMan.GetSessionID()); } if (!Object.op_Implicit((Object)(object)_scene.FindInstance(item)) && item.GetPrefab() != 0 && Object.op_Implicit((Object)(object)_scene.GetPrefab(item.GetPrefab())) && num4 < 24 && TryZone(item.GetPosition(), out var zone2) && Native.ZoneExists(_terrain, zone2) && Native.ZoneReady(_terrain, zone2, item.Type)) { Native.Create(_scene, item); num4++; } } } catch (Exception error) { Fail(error); } } internal static void IncludeObjects(List near, bool creating) { //IL_0068: 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_00a9: 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_00ca: Unknown result type (might be due to invalid IL or missing references) EnsureWorld(); if (!Holding) { return; } try { List list = new List(); ReadObjects(Zones, list); HashSet hashSet = new HashSet(near.Select((ZDO item) => item.m_uid)); foreach (ZDO item in list) { if ((!creating || CanCreate(item)) && hashSet.Add(item.m_uid)) { near.Add(item); } } foreach (ZDOID pin in Pins) { ZDO zDO = _manager.GetZDO(pin); if (zDO != null && (!creating || CanCreate(zDO)) && hashSet.Add(pin)) { near.Add(zDO); } } } catch (Exception error) { Fail(error); } } internal static bool KeepOwner(ZDO zdo, long requestedOwner) { //IL_002d: 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) if (NativeReleaseDepth > 0 && Holding && !IsPlayerObject(zdo) && requestedOwner != ZDOMan.GetSessionID() && zdo.GetOwner() == ZDOMan.GetSessionID()) { if (!IsPinned(zdo.m_uid)) { return ContainsPosition(zdo.GetPosition()); } return true; } return false; } internal static void Reset() { Anchors.Clear(); Zones.Clear(); Pins.Clear(); Objects.Clear(); SectorObjects.Clear(); Seen.Clear(); _failure = ""; _nextUpdate = 0f; _zoneTurn = 0; _network = null; _manager = null; _scene = null; _terrain = null; } private static void EnsureWorld() { if (_network != ZNet.instance || _manager != ZDOMan.instance || _scene != ZNetScene.instance || _terrain != ZoneSystem.instance) { Reset(); _network = ZNet.instance; _manager = ZDOMan.instance; _scene = ZNetScene.instance; _terrain = ZoneSystem.instance; } } private static void RebuildUnion() { Zones.Clear(); Pins.Clear(); foreach (Anchor value in Anchors.Values) { Zones.UnionWith(value.Zones); Pins.UnionWith(value.Pins); } } private static bool Collect(IReadOnlyList centers, out IReadOnlyCollection footprint) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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_0057: 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_0071: 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_0090: 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_009e: Unknown result type (might be due to invalid IL or missing references) footprint = (IReadOnlyCollection)(object)Array.Empty(); if (centers == null || centers.Count == 0 || centers.Count > 129) { return false; } List list = new List(centers.Count); foreach (Vector3 center in centers) { if (float.IsNaN(center.x) || float.IsInfinity(center.x) || float.IsNaN(center.y) || float.IsInfinity(center.y) || float.IsNaN(center.z) || float.IsInfinity(center.z)) { return false; } list.Add(new RailVector(center.x, center.y, center.z)); } if (!RailLoadingFootprint.TryCollect(list, 25, out footprint)) { return false; } return footprint.All((RailZoneCoord zone) => zone.X >= -256 && zone.X < 256 && zone.Y >= -256 && zone.Y < 256); } private static bool TryZone(Vector3 point, out RailZoneCoord zone) { //IL_0007: 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_002e: 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_005e: Unknown result type (might be due to invalid IL or missing references) zone = default(RailZoneCoord); if (float.IsNaN(point.x) || float.IsInfinity(point.x) || float.IsNaN(point.z) || float.IsInfinity(point.z)) { return false; } double num = Math.Floor(((double)point.x + 32.0) / 64.0); double num2 = Math.Floor(((double)point.z + 32.0) / 64.0); if (num < -256.0 || num >= 256.0 || num2 < -256.0 || num2 >= 256.0) { return false; } zone = new RailZoneCoord((int)num, (int)num2); return true; } private static void ReadObjects(IEnumerable zones, List output) { //IL_0053: 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) output.Clear(); Seen.Clear(); foreach (RailZoneCoord zone2 in zones) { SectorObjects.Clear(); Native.Find(_manager, zone2, SectorObjects); foreach (ZDO sectorObject in SectorObjects) { if (TryZone(sectorObject.GetPosition(), out var zone) && zone.Equals(zone2) && Seen.Add(sectorObject.m_uid)) { output.Add(sectorObject); } } } } private static bool CanCreate(ZDO zdo) { //IL_0018: 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) if (Object.op_Implicit((Object)(object)_scene.GetPrefab(zdo.GetPrefab())) && TryZone(zdo.GetPosition(), out var zone) && Native.ZoneExists(_terrain, zone)) { return Native.ZoneReady(_terrain, zone, zdo.Type); } return false; } private static bool IsPlayerObject(ZDO zdo) { if (zdo.GetPrefab() == StringExtensionMethods.GetStableHashCode("Player")) { return true; } GameObject val = (Object.op_Implicit((Object)(object)_scene) ? _scene.GetPrefab(zdo.GetPrefab()) : null); if (Object.op_Implicit((Object)(object)val)) { return Object.op_Implicit((Object)(object)val.GetComponent()); } return false; } private static bool IsTrainObject(ZDO zdo) { //IL_0006: 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) if (!Pins.Contains(zdo.m_uid) && zdo.GetString("vikingrail_object_host_guid", "").Length == 0 && zdo.GetString("vikingrail_object_token", "").Length == 0) { ZDOID zDOID = zdo.GetZDOID("vikingrail_object_host"); if (((ZDOID)(ref zDOID)).IsNone() && !zdo.GetBool("vikingrail_object_detach_pending", false)) { GameObject val = (Object.op_Implicit((Object)(object)_scene) ? _scene.GetPrefab(zdo.GetPrefab()) : null); if (Object.op_Implicit((Object)(object)val)) { if (!Object.op_Implicit((Object)(object)val.GetComponent()) && !Object.op_Implicit((Object)(object)val.GetComponent()) && !Object.op_Implicit((Object)(object)val.GetComponent()) && !Object.op_Implicit((Object)(object)val.GetComponent())) { return Object.op_Implicit((Object)(object)val.GetComponent()); } return true; } return false; } } return true; } private static void Fail(Exception error) { if (_failure.Length == 0) { _failure = "Remote train world loading failed: " + error.GetBaseException().Message; RailPlugin.Warn(_failure); } } } [HarmonyPatch] internal static class RailRemoteWorldObjects { [HarmonyPrepare] private static bool Prepare() { return RailRemoteWorld.Native.Compatible; } [HarmonyTargetMethods] private static IEnumerable Targets() { yield return RailRemoteWorld.Native.CreateObjects; yield return RailRemoteWorld.Native.RemoveObjects; } [HarmonyPrefix] private static void Prefix(List __0, MethodBase __originalMethod) { RailRemoteWorld.IncludeObjects(__0, __originalMethod.Name == "CreateObjects"); } } [HarmonyPatch] internal static class RailRemoteWorldReleaseScope { [HarmonyPrepare] private static bool Prepare() { return RailRemoteWorld.Native.Compatible; } [HarmonyTargetMethod] private static MethodBase Target() { return RailRemoteWorld.Native.ReleaseNearby; } [HarmonyPrefix] private static void Prefix(out int __state) { __state = RailRemoteWorld.NativeReleaseDepth; RailRemoteWorld.NativeReleaseDepth++; } [HarmonyFinalizer] private static void Finalizer(int __state) { RailRemoteWorld.NativeReleaseDepth = __state; } } [HarmonyPatch] internal static class RailRemoteWorldKeepOwner { [HarmonyPrepare] private static bool Prepare() { return RailRemoteWorld.Native.Compatible; } [HarmonyTargetMethod] private static MethodBase Target() { return RailRemoteWorld.Native.SetOwner; } [HarmonyPrefix] private static bool Prefix(ZDO __instance, long __0) { return !RailRemoteWorld.KeepOwner(__instance, __0); } } [HarmonyPatch] internal static class RailRemoteWorldOwnerArea { [HarmonyPrepare] private static bool Prepare() { return RailRemoteWorld.Native.Compatible; } [HarmonyTargetMethod] private static MethodBase Target() { return RailRemoteWorld.Native.PeerArea; } [HarmonyPostfix] private static void Postfix(Vector3 __0, long __1, ref bool __result) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) if (!__result && Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer() && __1 == ZDOMan.GetSessionID() && RailRemoteWorld.ContainsPosition(__0)) { __result = true; } } } [HarmonyPatch] internal static class RailRemoteWorldLocalArea { [HarmonyPrepare] private static bool Prepare() { return RailRemoteWorld.Native.Compatible; } [HarmonyTargetMethod] private static MethodBase Target() { return RailRemoteWorld.Native.Outside; } [HarmonyPostfix] private static void Postfix(Vector3 __0, ref bool __result) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) if (__result && RailRemoteWorld.ContainsPosition(__0)) { __result = false; } } } public sealed class RailRepairCart : MonoBehaviour { private readonly List _worn = new List(); internal bool Interact(Player player) { //IL_0065: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer) { return false; } RailVehicle component = ((Component)this).GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !component.IsReady || !RailSettings.Ready) { return false; } if (((Character)player).IsDead() || ((Character)player).IsTeleporting() || ((Character)player).IsAttached() || player.GetDoodadController() != null || ((Character)player).InPlaceMode() || Vector3.Distance(((Component)player).transform.position, ((Component)this).transform.position) > 4f || !PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return false; } if (!component.RepairStationAvailable) { ((Character)player).Message((MessageType)2, "Park the train, leave the controls, and finish storage or coupling before repairing.", 0, (Sprite)null, false); return false; } ZNetScene instance = ZNetScene.instance; ObjectDB instance2 = ObjectDB.instance; GameObject val = (Object.op_Implicit((Object)(object)instance) ? instance.GetPrefab("piece_workbench") : null); GameObject val2 = (Object.op_Implicit((Object)(object)instance) ? instance.GetPrefab("forge") : null); CraftingStation val3 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent() : null); CraftingStation val4 = (Object.op_Implicit((Object)(object)val2) ? val2.GetComponent() : null); if (!Object.op_Implicit((Object)(object)instance2) || !Object.op_Implicit((Object)(object)val3) || !Object.op_Implicit((Object)(object)val4) || string.IsNullOrEmpty(val3.m_name) || string.IsNullOrEmpty(val4.m_name)) { ((Character)player).Message((MessageType)2, "Waiting for workbench and forge repair data.", 0, (Sprite)null, false); return false; } _worn.Clear(); ((Humanoid)player).GetInventory().GetWornItems(_worn); int num = 0; CraftingStation val5 = val3; foreach (ItemData item in _worn) { if (item == null || item.m_shared == null) { continue; } Recipe recipe = instance2.GetRecipe(item); if (!Object.op_Implicit((Object)(object)recipe)) { continue; } string text = (Object.op_Implicit((Object)(object)recipe.m_craftingStation) ? recipe.m_craftingStation.m_name : null); string text2 = (Object.op_Implicit((Object)(object)recipe.m_repairStation) ? recipe.m_repairStation.m_name : null); float maxDurability = item.GetMaxDurability(); if (RailRepairPolicy.CanRepair(item.m_shared.m_useDurability, item.m_shared.m_canBeReparied, item.m_durability, maxDurability, recipe.m_minStationLevel, text, text2, val3.m_name, val4.m_name)) { ((Character)player).RaiseSkill((SkillType)107, 1f - item.m_durability / maxDurability); item.m_durability = maxDurability; if (text == val4.m_name || text2 == val4.m_name) { val5 = val4; } num++; } } _worn.Clear(); if (num > 0) { EffectList repairItemDoneEffects = val5.m_repairItemDoneEffects; if (repairItemDoneEffects != null) { repairItemDoneEffects.Create(((Component)this).transform.position + Vector3.up * 1.7f, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } ((Character)player).Message((MessageType)2, "Repaired " + num + ((num == 1) ? " item." : " items."), 0, (Sprite)null, false); } else { ((Character)player).Message((MessageType)2, "No damaged workbench or forge equipment to repair.", 0, (Sprite)null, false); } return true; } } internal sealed class RailRiderAnimation : MonoBehaviour { internal static readonly MethodInfo? AnimationTick = AccessTools.Method(typeof(CharacterAnimEvent), "CustomFixedUpdate", new Type[1] { typeof(float) }, (Type[])null); internal static readonly MethodInfo? NetworkTick = AccessTools.Method(typeof(ZSyncAnimation), "SyncParameters", new Type[2] { typeof(float), typeof(bool) }, (Type[])null); private static readonly int Standing = Animator.StringToHash("standing"); private static readonly int Forward = Animator.StringToHash("forward_speed"); private static readonly int Sideways = Animator.StringToHash("sideway_speed"); private static readonly int Turning = Animator.StringToHash("turn_speed"); private static bool _warned; private readonly RailRiderPoseHold _settle = new RailRiderPoseHold(); private Player _player; private Animator _animator; private RuntimeAnimatorController? _controller; private bool _compatible; private bool _held; private bool _failed; private float _normalSpeed = 1f; internal static bool Prepare() { int num; if (IsVoid(AnimationTick)) { num = (IsVoid(NetworkTick) ? 1 : 0); if (num != 0) { goto IL_0026; } } else { num = 0; } Warn("The native animation update API has changed; retaining normal rider animations."); goto IL_0026; IL_0026: return (byte)num != 0; } private static bool IsVoid(MethodInfo? method) { if (method != null && !method.IsStatic) { return method.ReturnType == typeof(void); } return false; } internal static void Refresh(CharacterAnimEvent animation) { Player componentInParent = ((Component)animation).GetComponentInParent(); if (!Object.op_Implicit((Object)(object)componentInParent)) { return; } RailRiderAnimation railRiderAnimation = ((Component)componentInParent).GetComponent(); if (!Object.op_Implicit((Object)(object)railRiderAnimation)) { if (!RailRiderAttachment.TryStandingRider(componentInParent, out RailVehicle _, out Transform _)) { return; } Animator component = ((Component)animation).GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return; } railRiderAnimation = ((Component)componentInParent).gameObject.AddComponent(); railRiderAnimation._player = componentInParent; railRiderAnimation._animator = component; } railRiderAnimation.Refresh(); } private void Update() { Refresh(); } internal void Refresh() { //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) if (!((Behaviour)this).isActiveAndEnabled) { Release(); } else { if (_failed) { return; } try { if (!Object.op_Implicit((Object)(object)_player) || !Object.op_Implicit((Object)(object)_animator) || !RailRiderAttachment.TryStandingRider(_player, out RailVehicle _, out Transform _) || ((Character)_player).InAttack() || ((Character)_player).InDodge() || ((Character)_player).IsStaggering() || ((Character)_player).InMinorAction() || ((Character)_player).InEmote()) { Release(); return; } if ((Object)(object)_controller != (Object)(object)_animator.runtimeAnimatorController) { Release(); _controller = _animator.runtimeAnimatorController; _compatible = HasParameter(Standing, (AnimatorControllerParameterType)4) && HasParameter(Forward, (AnimatorControllerParameterType)1) && HasParameter(Sideways, (AnimatorControllerParameterType)1) && HasParameter(Turning, (AnimatorControllerParameterType)1); } if (!_compatible || !_animator.GetBool(Standing)) { Release(); return; } bool flag = false; int num = 17; AnimatorStateInfo currentAnimatorStateInfo; for (int i = 0; i < _animator.layerCount; i++) { flag |= _animator.IsInTransition(i); int num2 = num * 31; currentAnimatorStateInfo = _animator.GetCurrentAnimatorStateInfo(i); num = num2 + ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).fullPathHash; } bool neutral = Mathf.Abs(_animator.GetFloat(Forward)) <= 0.05f && Mathf.Abs(_animator.GetFloat(Sideways)) <= 0.05f && Mathf.Abs(_animator.GetFloat(Turning)) <= 0.05f; RailRiderPoseHold settle = _settle; bool transitioning = flag; int state = num; double now = Time.unscaledTime; currentAnimatorStateInfo = _animator.GetCurrentAnimatorStateInfo(0); if (!settle.Update(eligible: true, neutral, transitioning, state, now, ((AnimatorStateInfo)(ref currentAnimatorStateInfo)).normalizedTime)) { RestoreSpeed(); return; } float speed = _animator.speed; if (float.IsNaN(speed) || float.IsInfinity(speed) || (speed != 0f && speed <= 0.01f)) { Release(); return; } if (!_held || speed > 0.01f) { if (speed <= 0.01f) { return; } _normalSpeed = speed; _held = true; } _animator.speed = 0f; } catch (Exception ex) { Release(); _failed = true; Warn("Retaining normal rider animations after an animation API error: " + ex.GetBaseException().Message); } } } private bool HasParameter(int hash, AnimatorControllerParameterType type) { //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) AnimatorControllerParameter[] parameters = _animator.parameters; foreach (AnimatorControllerParameter val in parameters) { if (val.nameHash == hash && val.type == type) { return true; } } return false; } internal bool ExposeNormalSpeedForSync() { if (!_held || !Object.op_Implicit((Object)(object)_animator)) { return false; } if (_animator.speed == 0f) { _animator.speed = _normalSpeed; } return true; } private void RestoreSpeed() { if (_held && Object.op_Implicit((Object)(object)_animator) && _animator.speed == 0f) { _animator.speed = _normalSpeed; } _held = false; } private void Release() { RestoreSpeed(); _settle.Reset(); } private void OnDisable() { Release(); } private void OnDestroy() { Release(); } private static void Warn(string reason) { if (!_warned) { _warned = true; RailPlugin.Warn(reason); } } } [HarmonyPatch] internal static class RailRiderAnimationTickPatch { [HarmonyPrepare] private static bool Prepare() { return RailRiderAnimation.Prepare(); } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailRiderAnimation.AnimationTick; } [HarmonyPostfix] private static void Postfix(CharacterAnimEvent __instance) { RailRiderAnimation.Refresh(__instance); } } [HarmonyPatch] internal static class RailRiderAnimationNetworkPatch { [HarmonyPrepare] private static bool Prepare() { return RailRiderAnimation.Prepare(); } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailRiderAnimation.NetworkTick; } [HarmonyPrefix] private static void Prefix(ZSyncAnimation __instance, out RailRiderAnimation? __state) { Player componentInParent = ((Component)__instance).GetComponentInParent(); RailRiderAnimation railRiderAnimation = (Object.op_Implicit((Object)(object)componentInParent) ? ((Component)componentInParent).GetComponent() : null); __state = ((Object.op_Implicit((Object)(object)railRiderAnimation) && railRiderAnimation.ExposeNormalSpeedForSync()) ? railRiderAnimation : null); } [HarmonyFinalizer] private static Exception? Finalizer(Exception? __exception, RailRiderAnimation? __state) { if (Object.op_Implicit((Object)(object)__state)) { __state.Refresh(); } return __exception; } } internal static class RailRiderAttachment { private static readonly MethodInfo? AttachMethod = AccessTools.Method(typeof(Player), "UpdateAttach", Type.EmptyTypes, (Type[])null); private static readonly FieldInfo? Eye = AccessTools.Field(typeof(Character), "m_eye"); private static readonly Action? UpdateAttach = BindAttach(); internal static readonly MethodInfo? PlayerUpdate = AccessTools.Method(typeof(Player), "Update", Type.EmptyTypes, (Type[])null); internal static readonly MethodInfo? CameraUpdate = AccessTools.Method(typeof(GameCamera), "LateUpdate", Type.EmptyTypes, (Type[])null); internal static readonly MethodInfo? OwnerSync = AccessTools.Method(typeof(ZSyncTransform), "OwnerSync", Type.EmptyTypes, (Type[])null); private static bool _warned; private static bool _failed; internal static void ClearWalkingInput(Player player) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) player.m_autoRun = false; ((Character)player).SetMoveDir(Vector3.zero); ((Character)player).SetRun(false); } private static Action? BindAttach() { if (AttachMethod == null || AttachMethod.IsStatic || AttachMethod.ReturnType != typeof(void)) { return null; } try { return (Action)Delegate.CreateDelegate(typeof(Action), AttachMethod); } catch { return null; } } internal static bool Prepare() { int num; if (UpdateAttach != null && Eye != null && !Eye.IsStatic && Eye.FieldType == typeof(Transform) && IsVoidMethod(PlayerUpdate) && IsVoidMethod(CameraUpdate)) { num = (IsVoidMethod(OwnerSync) ? 1 : 0); if (num != 0) { goto IL_007a; } } else { num = 0; } if (!_warned) { _warned = true; RailPlugin.Warn("Rail driver attachment refresh is unavailable on this game API; retaining native attachment timing."); } goto IL_007a; IL_007a: return (byte)num != 0; } private static bool IsVoidMethod(MethodInfo? method) { if (method != null && !method.IsStatic) { return method.ReturnType == typeof(void); } return false; } internal static bool TryStandingRider(Player player, out RailVehicle cart, out Transform anchor) { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: 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) cart = null; anchor = null; if (!Object.op_Implicit((Object)(object)player) || ((Character)player).IsDead() || ((Character)player).IsTeleporting()) { return false; } if ((Object)(object)player == (Object)(object)Player.m_localPlayer) { if (player.GetDoodadController() is RailPumpPartner railPumpPartner && Object.op_Implicit((Object)(object)railPumpPartner) && (Object)(object)railPumpPartner == (Object)(object)RailPumpPartner.LocalPartner && railPumpPartner.TryRider(player, out anchor)) { cart = railPumpPartner.Cart; return true; } if (!(player.GetDoodadController() is RailVehicle railVehicle) || !Object.op_Implicit((Object)(object)railVehicle) || (Object)(object)railVehicle != (Object)(object)RailVehicle.LocalDriven || !railVehicle.TryDriverAnchor(player, out anchor)) { return false; } cart = railVehicle; return true; } ZNetView component = ((Component)player).GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || !Object.op_Implicit((Object)(object)ZNetScene.instance)) { return false; } ZDOID connectionZDOID = component.GetZDO().GetConnectionZDOID((ConnectionType)2); if (((ZDOID)(ref connectionZDOID)).IsNone()) { return false; } GameObject val = ZNetScene.instance.FindInstance(connectionZDOID); RailVehicle railVehicle2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent() : null); if (!Object.op_Implicit((Object)(object)railVehicle2)) { return false; } if (!railVehicle2.TryDriverAnchor(player, out anchor) && (!Object.op_Implicit((Object)(object)railVehicle2.PumpPartner) || !railVehicle2.PumpPartner.TryRider(player, out anchor))) { return false; } cart = railVehicle2; return true; } internal static void Synchronize(Player? player) { //IL_00ea: 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_009f: 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) if (_failed || UpdateAttach == null || Eye == null || !Object.op_Implicit((Object)(object)player) || (Object)(object)player != (Object)(object)Player.m_localPlayer || !TryStandingRider(player, out RailVehicle _, out Transform _)) { return; } ZNetView component = ((Component)player).GetComponent(); Rigidbody component2 = ((Component)player).GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || !component.IsOwner() || !Object.op_Implicit((Object)(object)component2)) { return; } object? value = Eye.GetValue(player); Transform val = (Transform)((value is Transform) ? value : null); if (!Object.op_Implicit((Object)(object)val)) { return; } Quaternion rotation = val.rotation; try { UpdateAttach(player); component2.position = ((Component)player).transform.position; component2.rotation = ((Component)player).transform.rotation; } catch (Exception ex) { _failed = true; RailPlugin.Warn("Rail driver attachment refresh failed; retaining native attachment timing. " + ex.GetBaseException().Message); } finally { if (Object.op_Implicit((Object)(object)val)) { val.rotation = rotation; } } } } [HarmonyPatch] internal static class RailRiderUpdatePatch { [HarmonyPrepare] private static bool Prepare() { return RailRiderAttachment.Prepare(); } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailRiderAttachment.PlayerUpdate; } [HarmonyPostfix] private static void Postfix(Player __instance) { RailRiderAttachment.Synchronize(__instance); } } [HarmonyPatch] internal static class RailRiderCameraPatch { [HarmonyPrepare] private static bool Prepare() { return RailRiderAttachment.Prepare(); } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailRiderAttachment.CameraUpdate; } [HarmonyPrefix] private static void Prefix() { RailRiderAttachment.Synchronize(Player.m_localPlayer); } } [HarmonyPatch] internal static class RailRiderNetworkPatch { [HarmonyPrepare] private static bool Prepare() { return RailRiderAttachment.Prepare(); } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailRiderAttachment.OwnerSync; } [HarmonyPrefix] private static void Prefix(ZSyncTransform __instance) { Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)localPlayer) && (Object)(object)((Component)__instance).gameObject == (Object)(object)((Component)localPlayer).gameObject) { RailRiderAttachment.Synchronize(localPlayer); } } } [HarmonyPatch] internal static class RailRiderFootIK { private static readonly MethodInfo? FootMethod = AccessTools.Method(typeof(CharacterAnimEvent), "UpdateFootIK", Type.EmptyTypes, (Type[])null); private static readonly Type? FootType = typeof(CharacterAnimEvent).GetNestedType("Foot", BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo? Character = FindField(typeof(CharacterAnimEvent), "m_character"); private static readonly FieldInfo? Animator = FindField(typeof(CharacterAnimEvent), "m_animator"); private static readonly FieldInfo? Feet = FindField(typeof(CharacterAnimEvent), "m_feets"); private static readonly FieldInfo? Handle = FindField(FootType, "m_ikHandle"); private static readonly FieldInfo? Weight = FindField(FootType, "m_ikWeight"); private static readonly FieldInfo? Planted = FindField(FootType, "m_isPlanted"); private static readonly FieldInfo? PlantPosition = FindField(FootType, "m_plantPosition"); private static readonly FieldInfo? PlantNormal = FindField(FootType, "m_plantNormal"); private static bool _disabled; private static bool _warned; [HarmonyPrepare] private static bool Prepare() { int num; if (FootMethod != null && !FootMethod.IsStatic && FootMethod.ReturnType == typeof(void) && FootType != null && !FootType.IsValueType && Matches(Character, typeof(Character)) && Matches(Animator, typeof(Animator)) && Matches(Feet, FootType.MakeArrayType()) && Matches(Handle, typeof(AvatarIKGoal)) && Matches(Weight, typeof(float), writable: true) && Matches(Planted, typeof(bool), writable: true) && Matches(PlantPosition, typeof(Vector3), writable: true)) { num = (Matches(PlantNormal, typeof(Vector3), writable: true) ? 1 : 0); if (num != 0) { goto IL_0128; } } else { num = 0; } Warn("The foot animation API changed on this Valheim build."); goto IL_0128; IL_0128: return (byte)num != 0; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return FootMethod; } [HarmonyPrefix] private static bool Prefix(CharacterAnimEvent __instance) { //IL_009d: 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_00a5: 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_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) if (_disabled) { return true; } try { object? value = Character.GetValue(__instance); Player val = (Player)((value is Player) ? value : null); if (!Object.op_Implicit((Object)(object)val) || !RailRiderAttachment.TryStandingRider(val, out RailVehicle _, out Transform _)) { return true; } object? value2 = Animator.GetValue(__instance); Animator val2 = (Animator)((value2 is Animator) ? value2 : null); if (!Object.op_Implicit((Object)(object)val2) || !val2.isHuman || !(Feet.GetValue(__instance) is Array array)) { return true; } foreach (object item in array) { if (item != null) { AvatarIKGoal val3 = (AvatarIKGoal)Handle.GetValue(item); val2.SetIKPositionWeight(val3, 0f); val2.SetIKRotationWeight(val3, 0f); Weight.SetValue(item, 0f); Planted.SetValue(item, false); PlantPosition.SetValue(item, Vector3.zero); PlantNormal.SetValue(item, Vector3.up); } } return false; } catch (Exception ex) { _disabled = true; Warn(ex.Message); return true; } } private static FieldInfo? FindField(Type? type, string name) { if (!(type == null)) { return AccessTools.Field(type, name); } return null; } private static bool Matches(FieldInfo? field, Type type, bool writable = false) { if (field != null && !field.IsStatic && field.FieldType == type) { if (writable) { return !field.IsInitOnly; } return true; } return false; } private static void Warn(string reason) { if (!_warned) { _warned = true; RailPlugin.Warn("Rail driver foot stabilization is unavailable; using native foot IK. " + reason); } } } public enum RailSectionKind { Normal, Brake, Bumper } public sealed class RailSegment : MonoBehaviour { public Vector3[] Points = Array.Empty(); public RailSectionKind Kind; public bool LightDuty; public bool IsBridge; internal const string IdentityKey = "vikingrail_identity"; internal static readonly RailNetwork Network = new RailNetwork(0.16, 18.0); internal static readonly ISet LightTrackIds = new HashSet(); private static readonly Dictionary Markers = new Dictionary(); private string? _id; private Vector3 _position; private Quaternion _rotation; internal static IEnumerable StopMarkers => Markers.Values; internal string PathId => _id ?? ""; internal static bool HasStopMarker(string id) { return Markers.ContainsKey(id); } internal static void SetStopMarker(RailStopMarker marker) { Markers[marker.Id] = marker; } internal static void RemoveStopMarker(string id) { Markers.Remove(id); } internal void RefreshGeometry() { Register(); } private void Start() { Register(); } internal void SetLightDuty(bool lightDuty) { LightDuty = lightDuty; if (_id != null) { if (lightDuty) { LightTrackIds.Add(_id); } else { LightTrackIds.Remove(_id); } } } private void Register() { //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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_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) ZNetView component = ((Component)this).GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || Points.Length < 2) { return; } string text = component.GetZDO().GetString("vikingrail_identity", ""); if (text.Length == 0 && component.IsOwner()) { text = Guid.NewGuid().ToString("N"); component.GetZDO().Set("vikingrail_identity", text); } if (text.Length != 0) { if (_id != null && _id != text) { Network.Remove(_id); Markers.Remove(_id); LightTrackIds.Remove(_id); } _id = text; _position = ((Component)this).transform.position; _rotation = ((Component)this).transform.rotation; RailVector[] array = new RailVector[Points.Length]; for (int i = 0; i < Points.Length; i++) { array[i] = ToRail(((Component)this).transform.TransformPoint(Points[i])); } RailPath railPath = new RailPath(array); Network.Upsert(_id, railPath); if (LightDuty) { LightTrackIds.Add(_id); } else { LightTrackIds.Remove(_id); } if (Kind == RailSectionKind.Normal) { Markers.Remove(_id); return; } double distance = ((Kind == RailSectionKind.Bumper) ? Math.Max(0.0, railPath.Length - 1.6) : (railPath.Length / 2.0)); Markers[_id] = new RailStopMarker(_id, new RailCursor(_id, distance), Kind == RailSectionKind.Bumper); } } private void Update() { //IL_0015: 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_0025: 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_0040: Unknown result type (might be due to invalid IL or missing references) if (_id == null) { Register(); return; } Vector3 val = ((Component)this).transform.position - _position; if (((Vector3)(ref val)).sqrMagnitude > 0.0001f || Quaternion.Angle(((Component)this).transform.rotation, _rotation) > 0.05f) { Register(); } } private void OnDestroy() { if (_id != null) { Network.Remove(_id); Markers.Remove(_id); LightTrackIds.Remove(_id); } } internal static RailVector ToRail(Vector3 p) { //IL_0000: 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_000e: Unknown result type (might be due to invalid IL or missing references) return new RailVector(p.x, p.y, p.z); } internal static Vector3 ToUnity(RailVector p) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) return new Vector3((float)p.X, (float)p.Y, (float)p.Z); } } internal static class RailSettings { private enum ProposalResult { Applied = 1, Denied, Invalid, SaveFailed, Stale, HostFileBusy } private sealed class SettingsPeer { internal readonly RailSettingsRequestLedger Requests = new RailSettingsRequestLedger(); internal ProposalResult LastResult; } private sealed class ConfigurationManagerAttributes { public bool Browsable; } private sealed class FiniteRange : AcceptableValueRange { private readonly string _setting; private readonly double _fallback; private readonly string _unit; internal FiniteRange(string setting, double min, double max, double fallback, string unit) : base(min, max) { _setting = setting; _fallback = fallback; _unit = unit; } public override object Clamp(object value) { if (value is double d && (double.IsNaN(d) || double.IsInfinity(d))) { string[] obj = new string[7] { "Invalid ", _setting, "; using the default ", null, null, null, null }; double fallback = _fallback; obj[3] = fallback.ToString(CultureInfo.InvariantCulture); obj[4] = " "; obj[5] = _unit; obj[6] = "."; RailPlugin.Warn(string.Concat(obj)); return _fallback; } object obj2 = base.Clamp(value); if (!object.Equals(value, obj2)) { RailPlugin.Warn("Out-of-range " + _setting + "; clamped to " + ((double)obj2).ToString(CultureInfo.InvariantCulture) + " " + _unit + "."); } return obj2; } public override bool IsValid(object value) { if (value is double d && !double.IsNaN(d) && !double.IsInfinity(d)) { return base.IsValid(value); } return false; } } private sealed class CartRange : AcceptableValueRange { private readonly string _setting; internal CartRange(string setting) : base(0, 20) { _setting = setting; } public override object Clamp(object value) { object obj = base.Clamp(value); if (!object.Equals(value, obj)) { RailPlugin.Warn("Out-of-range " + _setting + "; clamped to " + obj?.ToString() + " carts."); } return obj; } } private sealed class RemoteTrainRange : AcceptableValueRange { internal RemoteTrainRange() : base(1, 8) { } public override object Clamp(object value) { object obj = base.Clamp(value); if (!object.Equals(value, obj)) { RailPlugin.Warn("Out-of-range RemoteTrainLimit; clamped to " + obj?.ToString() + " trains."); } return obj; } } [CompilerGenerated] private static class <>O { public static Method <0>__ReceiveSettingsRequest; public static Action <1>__ReceiveAccessRequest; public static Action <2>__ReceiveProposal; public static Action <3>__ReceiveSettings; public static Action <4>__ReceiveAccess; public static Action <5>__ReceiveProposalResult; public static ConsoleEvent <6>__SettingsCommand; public static Action <7>__Warn; public static EventHandler <8>__OnSettingChanged; public static EventHandler <9>__OnConfigReloaded; } private const string AccessRequestRpc = "VikingRail_SettingsAccessRequest_v13"; private const string AccessRpc = "VikingRail_SettingsAccess_v13"; private const string ProposalRpc = "VikingRail_SettingsProposal_v13"; private const string ResultRpc = "VikingRail_SettingsResult_v13"; private static readonly Dictionary SettingsPeers = new Dictionary(); private static ZRpc? _clientRpc; private static bool? _adminAllowed; private static volatile bool _adminEditsEnabled; private static int _accessRequestId; private static int _proposalId; private static float _nextRequest; private static float _firstRequest; private static bool _syncWarned; private static ulong _queuedMask; private static RailSettingsValues? _queuedValues; private static RailSettingsProposal? _pendingProposal; private static float _pendingSince; private static int _pendingAttempts; private static RailSettingsValues _local = RailSettingsValues.Defaults; private static RailSettingsValues? _remote; private static RailMusicClientValues _music = RailMusicClientValues.Defaults; private static Func? _readMusicBindings; private static Action? _writeMusicBindings; private static int _musicBindingsDirty; private static ConfigFile? _config; private static Func? _readBindings; private static Action? _writeBindings; private static int _bindingsDirty; private static int _bindingsAdminDirty; private static bool _candidateCanPropose; private static float _nextConfigPoll; private static string? _observedText; private static string? _candidateText; private static bool _ioWarned; private static bool _broadcastPending; private static ZNet? _network; internal static bool Ready { get { if (Object.op_Implicit((Object)(object)ZNet.instance) && !ZNet.instance.IsServer()) { if (_network == ZNet.instance && _remote != null) { return ServerConnectionMatches(); } return false; } return true; } } private static RailSettingsValues Effective { get { if (!Object.op_Implicit((Object)(object)ZNet.instance) || ZNet.instance.IsServer() || !Ready) { return _local; } return _remote; } } internal static RailSettingsValues Current => Effective; internal static bool AttachedTorchesUseFuel => Effective.AttachedTorchesUseFuel; internal static double CoalSecondsPerItem => Effective.CoalSecondsPerItem; internal static int HandcartMaxCarts => Effective.HandcartMaxCarts; internal static int LocomotiveMaxCarts => Effective.LocomotiveMaxCarts; internal static bool ClearTerrainOnPlacement => false; internal static bool DirtTrackbedOnPlacement => Effective.DirtTrackbedOnPlacement; internal static double HandcartStaminaPerSecond => Effective.HandcartStaminaPerSecond; internal static bool FillTerrainOnPlacement => false; internal static double HandcartMaxSpeed => Effective.HandcartMaxSpeed; internal static double LocomotiveMaxSpeed => Effective.LocomotiveMaxSpeed; internal static bool TracksTakeDamage => Effective.TracksTakeDamage; internal static double TandemHandcartMaxSpeed => Effective.TandemHandcartMaxSpeed; internal static double TandemHandcartStaminaPerSecond => Effective.TandemHandcartStaminaPerSecond; internal static int TandemHandcartMaxCarts => Effective.TandemHandcartMaxCarts; internal static double BronzeFuelSecondsPerItem => Effective.BronzeFuelSecondsPerItem; internal static double BronzeEngineMaxSpeed => Effective.BronzeEngineMaxSpeed; internal static int BronzeEngineMaxCarts => Effective.BronzeEngineMaxCarts; internal static double HandcartLoadPenaltyMultiplier => Effective.HandcartLoadPenaltyMultiplier; internal static double HandcartHillPenaltyMultiplier => Effective.HandcartHillPenaltyMultiplier; internal static double TandemHandcartLoadPenaltyMultiplier => Effective.TandemHandcartLoadPenaltyMultiplier; internal static double TandemHandcartHillPenaltyMultiplier => Effective.TandemHandcartHillPenaltyMultiplier; internal static double BronzeEngineLoadPenaltyMultiplier => Effective.BronzeEngineLoadPenaltyMultiplier; internal static double BronzeEngineHillPenaltyMultiplier => Effective.BronzeEngineHillPenaltyMultiplier; internal static double LocomotiveLoadPenaltyMultiplier => Effective.LocomotiveLoadPenaltyMultiplier; internal static double LocomotiveHillPenaltyMultiplier => Effective.LocomotiveHillPenaltyMultiplier; internal static double EitrFuelSecondsPerItem => Effective.EitrFuelSecondsPerItem; internal static double EitrEngineMaxSpeed => Effective.EitrEngineMaxSpeed; internal static int EitrEngineMaxCarts => Effective.EitrEngineMaxCarts; internal static double EitrEngineLoadPenaltyMultiplier => Effective.EitrEngineLoadPenaltyMultiplier; internal static double EitrEngineHillPenaltyMultiplier => Effective.EitrEngineHillPenaltyMultiplier; internal static bool RemoteSimulationEnabled => Effective.RemoteSimulationEnabled; internal static int RemoteTrainLimit => Effective.RemoteTrainLimit; internal static bool MusicCartsEnabled => Effective.MusicCartsEnabled; internal static double MusicCartRange => Effective.MusicCartRange; internal static double MusicCartMaxVolume => Effective.MusicCartMaxVolume; internal static double MusicVolume => _music.Volume; internal static double MusicTechnoVolume => _music.TechnoVolume; internal static double MusicPumpkinVolume => _music.PumpkinVolume; internal static double MusicHalloweenTechnoVolume => _music.HalloweenTechnoVolume; internal static bool MusicMuted => _music.Muted; internal static bool MusicBeatLights => _music.BeatLights; internal static int MusicMaxAudibleCarts => _music.MaxAudibleCarts; private static void EnsureSettingsConnection() { //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Expected O, but got Unknown ZNet instance = ZNet.instance; if (_network != instance) { ResetSettingsConnections(); _network = instance; } if (!Object.op_Implicit((Object)(object)instance)) { return; } if (instance.IsServer()) { ZRpc[] ready = (from peer in instance.GetPeers() where peer.IsReady() && peer.m_rpc.IsConnected() select peer.m_rpc).ToArray(); ZRpc[] array = SettingsPeers.Keys.Where((ZRpc rpc) => !ready.Contains(rpc)).ToArray(); foreach (ZRpc val in array) { UnregisterSettings(val); SettingsPeers.Remove(val); } array = ready; foreach (ZRpc val2 in array) { if (!SettingsPeers.ContainsKey(val2)) { SettingsPeers.Add(val2, new SettingsPeer()); object obj = <>O.<0>__ReceiveSettingsRequest; if (obj == null) { Method val3 = ReceiveSettingsRequest; <>O.<0>__ReceiveSettingsRequest = val3; obj = (object)val3; } val2.Register("VikingRail_RequestSettings_v13", (Method)obj); val2.Register("VikingRail_SettingsAccessRequest_v13", (Action)ReceiveAccessRequest); val2.Register("VikingRail_SettingsProposal_v13", (Action)ReceiveProposal); SendSettings(val2); } } return; } ZNetPeer serverPeer = instance.GetServerPeer(); ZRpc val4 = ((serverPeer != null && serverPeer.IsReady() && serverPeer.m_rpc.IsConnected()) ? serverPeer.m_rpc : null); if (val4 != _clientRpc) { ResetSettingsConnections(); _clientRpc = val4; if (val4 != null) { val4.Register("VikingRail_Settings_v13", (Action)ReceiveSettings); val4.Register("VikingRail_SettingsAccess_v13", (Action)ReceiveAccess); val4.Register("VikingRail_SettingsResult_v13", (Action)ReceiveProposalResult); _firstRequest = Time.realtimeSinceStartup; } } } private static bool ServerConnectionMatches() { if (!Object.op_Implicit((Object)(object)_network) || _network != ZNet.instance || _network.IsServer() || _clientRpc == null) { return false; } ZNetPeer serverPeer = _network.GetServerPeer(); if (serverPeer != null && serverPeer.IsReady() && serverPeer.m_rpc == _clientRpc) { return _clientRpc.IsConnected(); } return false; } private static bool IsReadyClient(ZRpc rpc) { if (Object.op_Implicit((Object)(object)_network) && _network == ZNet.instance && _network.IsServer() && rpc.IsConnected()) { return _network.GetPeers().Any((ZNetPeer peer) => peer.IsReady() && peer.m_rpc == rpc); } return false; } private static bool IsAdminConnection(ZRpc rpc) { if (IsReadyClient(rpc)) { return _network.IsAdmin(rpc.GetSocket().GetHostName()); } return false; } private static void UpdateSettingsNetwork() { if (!Object.op_Implicit((Object)(object)_network)) { return; } if (_network.IsServer()) { if (!_broadcastPending) { return; } _broadcastPending = false; ZRpc[] array = SettingsPeers.Keys.ToArray(); foreach (ZRpc rpc in array) { if (IsReadyClient(rpc)) { SendSettings(rpc); } } } else { if (!ServerConnectionMatches()) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup >= _nextRequest) { _nextRequest = realtimeSinceStartup + ((_remote == null) ? 3f : 5f); _clientRpc.Invoke("VikingRail_RequestSettings_v13", Array.Empty()); if (_accessRequestId == int.MaxValue) { _accessRequestId = 0; } _clientRpc.Invoke("VikingRail_SettingsAccessRequest_v13", new object[1] { ++_accessRequestId }); } if (_remote != null && _adminAllowed.HasValue) { _adminEditsEnabled = true; } if (_remote == null && !_syncWarned && realtimeSinceStartup - _firstRequest > 15f) { _syncWarned = true; RailPlugin.Warn("The server has not supplied Viking Rail settings. Install the same mod version on the server and every client."); } if (_pendingProposal != null && realtimeSinceStartup - _pendingSince >= 8f) { if (_pendingAttempts >= 3) { ClearProposals(); SettingsFeedback("Rail settings confirmation timed out. Check vikingrail_config status before retrying push.", warning: true); } else { SendPendingProposal(); } } if (_pendingProposal == null && _queuedMask != 0L && _queuedValues != null && CanSubmit()) { if (_proposalId == int.MaxValue) { ClearProposals(); SettingsFeedback("Reconnect before submitting more rail settings.", warning: true); return; } _pendingProposal = new RailSettingsProposal(++_proposalId, _queuedMask, _queuedValues); _queuedMask = 0uL; _queuedValues = null; _pendingAttempts = 0; SendPendingProposal(); } } } private static void ReceiveSettingsRequest(ZRpc rpc) { if (IsReadyClient(rpc)) { SendSettings(rpc); } } private static void SendSettings(ZRpc rpc) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown rpc.Invoke("VikingRail_Settings_v13", new object[1] { (object)new ZPackage(RailSettingsCodec.Encode(_local)) }); } private static void ReceiveSettings(ZRpc rpc, ZPackage package) { if (rpc != _clientRpc || !ServerConnectionMatches()) { return; } try { if (package == null || package.Size() != 211) { throw new FormatException("Incorrect settings packet length."); } RailSettingsValues railSettingsValues = RailSettingsCodec.Decode(package.GetArray()); bool num = _remote == null || !_remote.Equals(railSettingsValues); _remote = railSettingsValues; if (num) { RailPlugin.LogInfo("Server railroad settings are active. " + Describe(railSettingsValues)); } } catch (Exception ex) { RailPlugin.Warn("Rejected server railroad settings: " + ex.Message); } } private static void ReceiveAccessRequest(ZRpc rpc, int requestId) { if (requestId > 0 && IsReadyClient(rpc)) { rpc.Invoke("VikingRail_SettingsAccess_v13", new object[2] { requestId, IsAdminConnection(rpc) }); } } private static void ReceiveAccess(ZRpc rpc, int requestId, bool allowed) { if (rpc != _clientRpc || !ServerConnectionMatches() || requestId != _accessRequestId) { return; } bool num = _adminAllowed != allowed; _adminAllowed = allowed; if (!allowed) { bool num2 = _pendingProposal != null || _queuedMask != 0; ClearProposals(); if (num2) { SettingsFeedback("Pending rail settings canceled: the server no longer grants administrator access.", warning: true); } } if (num) { RailPlugin.LogInfo(allowed ? "Server confirmed Viking Rail administrator access. Live local edits can now update changed settings; vikingrail_config push sends all local values." : "Server railroad settings are read-only for this player. Administration requires the server's native admin list."); } } private static bool CanSubmit() { if (ServerConnectionMatches() && _remote != null && _adminEditsEnabled) { return _adminAllowed == true; } return false; } private static void QueueAdminEdit(ulong mask, RailSettingsValues values) { if (!CanSubmit()) { SettingsFeedback((_adminAllowed == false) ? "Rail settings not sent: the server does not recognize you as an administrator." : "Rail settings not sent: wait for server settings and administrator confirmation, then use vikingrail_config push.", warning: true); return; } _queuedMask |= mask; _queuedValues = values; } private static void SendPendingProposal() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown if (_pendingProposal != null && CanSubmit()) { _pendingSince = Time.realtimeSinceStartup; _pendingAttempts++; _clientRpc.Invoke("VikingRail_SettingsProposal_v13", new object[1] { (object)new ZPackage(_pendingProposal.Encode()) }); } } private static void ReceiveProposal(ZRpc rpc, ZPackage package) { if (!IsReadyClient(rpc) || !SettingsPeers.TryGetValue(rpc, out SettingsPeer value)) { return; } RailSettingsProposal railSettingsProposal; try { if (package == null || package.Size() != 223) { throw new FormatException("Incorrect proposal length."); } railSettingsProposal = RailSettingsProposal.Decode(package.GetArray()); } catch (Exception ex) { RailPlugin.Warn("Rejected malformed railroad settings proposal: " + ex.Message); return; } if (!IsAdminConnection(rpc)) { rpc.Invoke("VikingRail_SettingsResult_v13", new object[2] { railSettingsProposal.RequestId, 2 }); return; } if (railSettingsProposal.RequestId <= value.Requests.LastRequestId) { rpc.Invoke("VikingRail_SettingsResult_v13", new object[2] { railSettingsProposal.RequestId, (int)((railSettingsProposal.RequestId == value.Requests.LastRequestId) ? value.LastResult : ProposalResult.Stale) }); return; } PollLocalSettings(); if (!ServerFileReady()) { rpc.Invoke("VikingRail_SettingsResult_v13", new object[2] { railSettingsProposal.RequestId, 6 }); } else if (value.Requests.TryStart(railSettingsProposal.RequestId)) { RailSettingsValues railSettingsValues = railSettingsProposal.ApplyTo(_local); if (!PersistServerSettings(railSettingsValues)) { value.LastResult = ProposalResult.SaveFailed; } else { _local = railSettingsValues; _broadcastPending = true; value.LastResult = ProposalResult.Applied; RailPlugin.LogInfo("Administrator railroad settings saved and activated (request " + railSettingsProposal.RequestId + ", changed-field mask " + railSettingsProposal.Mask + "). " + Describe(railSettingsValues)); SendSettings(rpc); } rpc.Invoke("VikingRail_SettingsResult_v13", new object[2] { railSettingsProposal.RequestId, (int)value.LastResult }); } } private static void ReceiveProposalResult(ZRpc rpc, int requestId, int result) { if (rpc != _clientRpc || !ServerConnectionMatches()) { return; } RailSettingsProposal? pendingProposal = _pendingProposal; if (pendingProposal == null || pendingProposal.RequestId != requestId) { return; } if (result == 6) { _pendingSince = Time.realtimeSinceStartup - 6f; return; } _pendingProposal = null; if (result == 1) { SettingsFeedback("Rail settings saved on the server and shared with all players.", warning: false); return; } ClearProposals(); if (result == 2) { _adminAllowed = false; } SettingsFeedback(result switch { 4 => "Rail settings were not applied: the server could not save its configuration. See the server log.", 2 => "Rail settings denied: you are not on the server's administrator list.", _ => "Rail settings proposal was rejected. Check version compatibility before retrying.", }, warning: true); } private static bool ServerFileReady() { if (_config == null || _candidateText != null) { return false; } try { string text = File.ReadAllText(_config.ConfigFilePath); return text == _observedText && RailSettingsText.Read(text, _local).Equals(_local); } catch (Exception ex) { RailPlugin.Warn("Administrator rail settings are waiting for a complete, readable server configuration: " + ex.Message); return false; } } private static bool PersistServerSettings(RailSettingsValues values) { //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_00d5: Expected O, but got Unknown if (_config == null || _readBindings == null || _writeBindings == null) { return false; } RailSettingsValues obj = _readBindings(); bool saveOnConfigSet = _config.SaveOnConfigSet; string text = _config.ConfigFilePath + ".vikingrail." + Guid.NewGuid().ToString("N") + ".tmp"; _config.SaveOnConfigSet = false; bool flag = false; try { string text2 = File.ReadAllText(_config.ConfigFilePath); if (text2 != _observedText || !RailSettingsText.Read(text2, _local).Equals(_local)) { throw new IOException("The server configuration changed while processing the request; retry after it reloads."); } _writeBindings(values); File.Copy(_config.ConfigFilePath, text); ConfigFile val = new ConfigFile(text, false) { SaveOnConfigSet = false }; foreach (KeyValuePair item in _config) { ConfigEntryBase value = item.Value; if (value.SettingType == typeof(bool)) { val.Bind(item.Key, (bool)value.DefaultValue, value.Description).Value = (bool)value.BoxedValue; continue; } if (value.SettingType == typeof(int)) { val.Bind(item.Key, (int)value.DefaultValue, value.Description).Value = (int)value.BoxedValue; continue; } if (value.SettingType == typeof(double)) { val.Bind(item.Key, (double)value.DefaultValue, value.Description).Value = (double)value.BoxedValue; continue; } throw new InvalidOperationException("Unsupported railroad setting type: " + value.SettingType); } val.Save(); string text3 = File.ReadAllText(text); if (!RailSettingsText.Read(text3, values).Equals(values)) { throw new IOException("Saved railroad settings did not verify."); } if (File.ReadAllText(_config.ConfigFilePath) != text2) { throw new IOException("The server configuration changed during the save; the host file was preserved. Retry after it reloads."); } File.Replace(text, _config.ConfigFilePath, null); flag = true; _observedText = text3; _candidateText = null; return true; } catch (Exception ex) { RailPlugin.Warn("Cannot persist administrator railroad settings; previous settings remain active. " + ex.Message); return false; } finally { if (!flag) { _writeBindings(obj); } _config.SaveOnConfigSet = saveOnConfigSet; Interlocked.Exchange(ref _bindingsDirty, 0); Interlocked.Exchange(ref _bindingsAdminDirty, 0); try { if (File.Exists(text)) { File.Delete(text); } } catch (Exception ex2) { RailPlugin.Warn("Cannot remove temporary railroad configuration: " + ex2.Message); } } } private static void InitializeSettingsCommand() { //IL_002f: 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_0025: Expected O, but got Unknown try { object obj = <>O.<6>__SettingsCommand; if (obj == null) { ConsoleEvent val = SettingsCommand; <>O.<6>__SettingsCommand = val; obj = (object)val; } new ConsoleCommand("vikingrail_config", "status | push: show railroad settings authority, or deliberately reload and push all local settings.", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } catch (Exception ex) { RailPlugin.Warn("Rail settings console command is unavailable; live configuration still works. " + ex.Message); } } private static void SettingsCommand(ConsoleEventArgs args) { string text = ((args.Length > 1) ? args[1].ToLowerInvariant() : "status"); if (text == "status") { bool flag = !Object.op_Implicit((Object)(object)ZNet.instance) || ZNet.instance.IsServer(); bool flag2 = !flag && _remote != null && ServerConnectionMatches(); Terminal context = args.Context; ConfigFile? config = _config; context.AddString("Active LOCAL configuration file: " + (((config != null) ? config.ConfigFilePath : null) ?? "not initialized")); args.Context.AddString(flag ? ("Viking Rail: local host/server settings are authoritative. " + Describe(_local)) : ("Viking Rail: server authoritative; settings " + (flag2 ? "received" : "pending") + "; administrator " + ((!_adminAllowed.HasValue) ? "pending" : (_adminAllowed.Value ? "confirmed" : "denied")) + "; edit " + ((_pendingProposal != null || _queuedMask != 0L) ? "awaiting confirmation" : "none pending") + ". " + (flag2 ? Describe(_remote) : ""))); if (flag2) { args.Context.AddString("HandcartStaminaPerSecond: loaded local " + _local.HandcartStaminaPerSecond.ToString(CultureInfo.InvariantCulture) + "/s; active server " + _remote.HandcartStaminaPerSecond.ToString(CultureInfo.InvariantCulture) + "/s."); bool flag3 = _local.TandemHandcartStaminaPerSecond != _remote.TandemHandcartStaminaPerSecond; if (flag3) { args.Context.AddString("TandemHandcartStaminaPerSecond: loaded local " + _local.TandemHandcartStaminaPerSecond.ToString(CultureInfo.InvariantCulture) + "/s; active server " + _remote.TandemHandcartStaminaPerSecond.ToString(CultureInfo.InvariantCulture) + "/s per rider."); } if (_local.HandcartStaminaPerSecond != _remote.HandcartStaminaPerSecond || flag3) { args.Context.AddString("Only the server values are active. Joining or re-saving an unchanged local value does not upload it. Edit the active server config, make a changed-value edit after administrator confirmation, or review all " + 35 + " shared local settings before deliberately running vikingrail_config push."); } } return; } if (text != "push") { args.Context.AddString("Usage: vikingrail_config [status|push]"); return; } bool flag4 = !Object.op_Implicit((Object)(object)ZNet.instance) || ZNet.instance.IsServer(); if (!flag4 && !CanSubmit()) { string text2 = ((_adminAllowed == false) ? "The server does not recognize you as an administrator." : "Wait for server settings and administrator confirmation first."); args.Context.AddString(text2); SettingsFeedback("Rail settings not sent. " + text2, warning: true); return; } try { if (_config == null || _writeBindings == null || _writeMusicBindings == null) { throw new InvalidOperationException("Configuration is not initialized."); } string text3 = File.ReadAllText(_config.ConfigFilePath); RailSettingsValues railSettingsValues = RailSettingsText.Read(text3, _local, RailPlugin.Warn); RailMusicClientValues railMusicClientValues = RailSettingsText.ReadClient(text3, _music, RailPlugin.Warn); bool saveOnConfigSet = _config.SaveOnConfigSet; _config.SaveOnConfigSet = false; try { _writeBindings(railSettingsValues); _writeMusicBindings(railMusicClientValues); } finally { _config.SaveOnConfigSet = saveOnConfigSet; } Interlocked.Exchange(ref _bindingsDirty, 0); Interlocked.Exchange(ref _bindingsAdminDirty, 0); Interlocked.Exchange(ref _musicBindingsDirty, 0); _music = railMusicClientValues; _observedText = text3; _candidateText = null; if (flag4) { PublishLocal(railSettingsValues, "Explicitly reloaded host railroad settings"); } else { _local = railSettingsValues; QueueAdminEdit(34359738367uL, railSettingsValues); } args.Context.AddString(flag4 ? "Local railroad file reloaded; host settings are active." : ("Deliberately proposing all " + 35 + " local file values. These replace all server railroad settings if approved and saved.")); } catch (Exception ex) { args.Context.AddString("Rail settings push failed: " + ex.Message); SettingsFeedback("Rail settings push failed: " + ex.Message, warning: true); } } private static void SettingsFeedback(string message, bool warning) { if (warning) { RailPlugin.Warn(message); } else { RailPlugin.LogInfo(message); } if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false); } } private static void ClearProposals() { _queuedMask = 0uL; _queuedValues = null; _pendingProposal = null; _pendingAttempts = 0; } private static void UnregisterSettings(ZRpc rpc) { rpc.Unregister("VikingRail_RequestSettings_v13"); rpc.Unregister("VikingRail_Settings_v13"); rpc.Unregister("VikingRail_SettingsAccessRequest_v13"); rpc.Unregister("VikingRail_SettingsAccess_v13"); rpc.Unregister("VikingRail_SettingsProposal_v13"); rpc.Unregister("VikingRail_SettingsResult_v13"); } private static void ResetSettingsConnections() { _adminEditsEnabled = false; foreach (ZRpc key in SettingsPeers.Keys) { UnregisterSettings(key); } SettingsPeers.Clear(); if (_clientRpc != null) { UnregisterSettings(_clientRpc); } _clientRpc = null; _remote = null; _adminAllowed = null; _accessRequestId = 0; _proposalId = 0; _nextRequest = 0f; _nextConfigPoll = 0f; _syncWarned = false; _candidateCanPropose = false; Interlocked.Exchange(ref _bindingsAdminDirty, 0); ClearProposals(); } internal static void Initialize(ConfigFile config) { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Expected O, but got Unknown //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Expected O, but got Unknown //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Expected O, but got Unknown //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Expected O, but got Unknown //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Expected O, but got Unknown //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Expected O, but got Unknown //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_030d: Expected O, but got Unknown //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_0366: Expected O, but got Unknown //IL_03b5: Unknown result type (might be due to invalid IL or missing references) //IL_03bf: Expected O, but got Unknown //IL_03e6: Unknown result type (might be due to invalid IL or missing references) //IL_03f0: Expected O, but got Unknown //IL_043f: Unknown result type (might be due to invalid IL or missing references) //IL_0449: Expected O, but got Unknown //IL_0470: Unknown result type (might be due to invalid IL or missing references) //IL_047a: Expected O, but got Unknown //IL_04c9: Unknown result type (might be due to invalid IL or missing references) //IL_04d3: Expected O, but got Unknown //IL_0522: Unknown result type (might be due to invalid IL or missing references) //IL_052c: Expected O, but got Unknown //IL_057b: Unknown result type (might be due to invalid IL or missing references) //IL_0585: Expected O, but got Unknown //IL_05d4: Unknown result type (might be due to invalid IL or missing references) //IL_05de: Expected O, but got Unknown //IL_062d: Unknown result type (might be due to invalid IL or missing references) //IL_0637: Expected O, but got Unknown //IL_0686: Unknown result type (might be due to invalid IL or missing references) //IL_0690: Expected O, but got Unknown //IL_06df: Unknown result type (might be due to invalid IL or missing references) //IL_06e9: Expected O, but got Unknown //IL_0738: Unknown result type (might be due to invalid IL or missing references) //IL_0742: Expected O, but got Unknown //IL_0791: Unknown result type (might be due to invalid IL or missing references) //IL_079b: Expected O, but got Unknown //IL_07ea: Unknown result type (might be due to invalid IL or missing references) //IL_07f4: Expected O, but got Unknown //IL_081b: Unknown result type (might be due to invalid IL or missing references) //IL_0825: Expected O, but got Unknown //IL_0874: Unknown result type (might be due to invalid IL or missing references) //IL_087e: Expected O, but got Unknown //IL_08cd: Unknown result type (might be due to invalid IL or missing references) //IL_08d7: Expected O, but got Unknown //IL_0916: Unknown result type (might be due to invalid IL or missing references) //IL_0920: Expected O, but got Unknown //IL_098c: Unknown result type (might be due to invalid IL or missing references) //IL_0996: Expected O, but got Unknown //IL_09e5: Unknown result type (might be due to invalid IL or missing references) //IL_09ef: Expected O, but got Unknown //IL_0a3e: Unknown result type (might be due to invalid IL or missing references) //IL_0a48: Expected O, but got Unknown //IL_0a97: Unknown result type (might be due to invalid IL or missing references) //IL_0aa1: Expected O, but got Unknown //IL_0af0: Unknown result type (might be due to invalid IL or missing references) //IL_0afa: Expected O, but got Unknown //IL_0b49: Unknown result type (might be due to invalid IL or missing references) //IL_0b53: Expected O, but got Unknown //IL_0bb1: Unknown result type (might be due to invalid IL or missing references) //IL_0bbb: Expected O, but got Unknown if (_config != null) { _config.SettingChanged -= OnSettingChanged; _config.ConfigReloaded -= OnConfigReloaded; } _config = config; string text = null; try { if (File.Exists(config.ConfigFilePath)) { text = File.ReadAllText(config.ConfigFilePath); } } catch (Exception ex) { RailPlugin.Warn("Could not read railroad configuration: " + ex.Message); } bool saveOnConfigSet = config.SaveOnConfigSet; config.SaveOnConfigSet = false; bool flag = true; try { ConfigEntry val = config.Bind("Internal", "SpeedDefaultsRevision", 0, new ConfigDescription("Internal one-time speed-default upgrade marker. Leave this value unchanged. Custom speeds are preserved; later edits to any speed are not upgraded again.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { Browsable = false } })); ConfigEntry torches = config.Bind("Fuel", "AttachedTorchesUseFuel", true, "Controls ordinary standing torches attached to mounting-cart pads. True: consume fuel normally. False: unlimited fuel and stay switched on, including previously extinguished torches; native weather, water and obstruction checks still apply. The custom Greydwarf Eye Rail torch always stays lit without fuel, regardless of this setting. Ordinary unmounted torches and the passenger chiminea are unaffected. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically."); ConfigEntry coal = config.Bind("Fuel", "CoalSecondsPerItem", 90.0, new ConfigDescription("Seconds of powered movement supplied by each newly consumed Coal. Already-burning fuel keeps its saved seconds. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("CoalSecondsPerItem", 1.0, 86400.0, 90.0, "seconds"), Array.Empty())); ConfigEntry bronzeFuel = config.Bind("Fuel", "BronzeFuelSecondsPerItem", 60.0, new ConfigDescription("Seconds of powered movement supplied by each newly consumed Wood in the bronze engine. Already-burning fuel keeps its saved seconds. Idling, braking and blocked movement consume no fuel. Coal locomotive fuel duration is controlled separately by CoalSecondsPerItem. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("BronzeFuelSecondsPerItem", 1.0, 86400.0, 60.0, "seconds per Wood"), Array.Empty())); ConfigEntry handcart = config.Bind("Trains", "HandcartMaxCarts", 4, new ConfigDescription("Maximum attached carts in total across both ends of a regular human-powered handcart. Tandem handcarts use TandemHandcartMaxCarts. Engine and plow do not count. Zero prevents new cart attachments. Lowering this value leaves existing trains intact. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new CartRange("HandcartMaxCarts"), Array.Empty())); ConfigEntry locomotive = config.Bind("Trains", "LocomotiveMaxCarts", 4, new ConfigDescription("Maximum attached unpowered carts in total across both ends of a coal locomotive. Matching engines and plows do not count. Zero prevents new cart attachments. Lowering this value leaves existing trains intact. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new CartRange("LocomotiveMaxCarts"), Array.Empty())); ConfigEntry stamina = config.Bind("Trains", "HandcartStaminaPerSecond", 5.0, new ConfigDescription("Base stamina consumed per second of powered movement by an empty regular handcart, or a tandem handcart with only one eligible rider. Attached carts, cargo and passengers increase this rate. Zero disables handcart stamina consumption. Coasting, braking and blocked movement consume none; coal locomotives are unaffected. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("HandcartStaminaPerSecond", 0.0, 100.0, 5.0, "stamina per second"), Array.Empty())); ConfigEntry handcartSpeed = config.Bind("Trains", "HandcartMaxSpeed", 4.5, new ConfigDescription("Base powered target speed of a regular handcart, or a tandem handcart with only one eligible rider, in metres per second before load and uphill grades reduce it. Acceleration, braking, coasting and stamina costs retain their normal behavior. Attached carts follow the engine. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("HandcartMaxSpeed", 0.5, 15.0, 4.5, "m/s"), Array.Empty())); ConfigEntry locomotiveSpeed = config.Bind("Trains", "LocomotiveMaxSpeed", 7.5, new ConfigDescription("Base powered target speed of a coal locomotive in metres per second, before load and uphill grades reduce it. Acceleration, braking, coasting and fuel use retain their normal behavior. Attached carts follow the engine. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("LocomotiveMaxSpeed", 0.5, 15.0, 7.5, "m/s"), Array.Empty())); ConfigEntry tandemSpeed = config.Bind("Trains", "TandemHandcartMaxSpeed", 6.75, new ConfigDescription("Base powered target speed of a tandem handcart when the driver and an eligible helper are riding, in metres per second before load and uphill grades reduce it. With only one eligible rider, HandcartMaxSpeed applies. Attached carts follow the engine. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("TandemHandcartMaxSpeed", 0.5, 15.0, 6.75, "m/s"), Array.Empty())); ConfigEntry tandemStamina = config.Bind("Trains", "TandemHandcartStaminaPerSecond", 2.5, new ConfigDescription("Base stamina consumed per second PER RIDER during powered movement of an empty tandem handcart with a driver and eligible helper. Attached carts, cargo and passengers increase each rider's rate. Zero disables stamina consumption while both riders are eligible. With only one eligible rider, HandcartStaminaPerSecond applies. Coasting, braking and blocked movement consume none. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("TandemHandcartStaminaPerSecond", 0.0, 100.0, 2.5, "stamina per second per rider"), Array.Empty())); ConfigEntry tandemCarts = config.Bind("Trains", "TandemHandcartMaxCarts", 4, new ConfigDescription("Maximum attached carts in total across both ends of a tandem handcart, whether operated by one or two riders. Engine and plow do not count. Zero prevents new cart attachments. Lowering this value leaves existing trains intact. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new CartRange("TandemHandcartMaxCarts"), Array.Empty())); ConfigEntry bronzeSpeed = config.Bind("Trains", "BronzeEngineMaxSpeed", 6.0, new ConfigDescription("Base powered target speed of the bronze engine in metres per second, before load and uphill grades reduce it. Acceleration, braking, coasting and fuel duration retain their normal behavior. Attached carts follow the engine. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("BronzeEngineMaxSpeed", 0.5, 15.0, 6.0, "m/s"), Array.Empty())); ConfigEntry bronzeCarts = config.Bind("Trains", "BronzeEngineMaxCarts", 3, new ConfigDescription("Maximum attached unpowered carts in total across both ends of a bronze engine. Matching engines and plows do not count. Zero prevents new cart attachments. Lowering this value leaves existing trains intact. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new CartRange("BronzeEngineMaxCarts"), Array.Empty())); ConfigEntry handcartLoadPenaltyMultiplier = config.Bind("Trains", "HandcartLoadPenaltyMultiplier", 1.0, new ConfigDescription("Scales the wagon-count and cargo/passenger-weight penalty on powered speed and acceleration for regular handcarts and solo tandems. Zero disables the penalty; one restores its original strength. Range 0 to 5. Fuel and stamina costs are unchanged. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("HandcartLoadPenaltyMultiplier", 0.0, 5.0, 1.0, "penalty multiplier"), Array.Empty())); ConfigEntry handcartHillPenaltyMultiplier = config.Bind("Trains", "HandcartHillPenaltyMultiplier", 1.0, new ConfigDescription("Scales the uphill penalty on powered target speed for regular handcarts and solo tandems. Zero disables the penalty; one restores its original strength. Range 0 to 5. Fuel and stamina costs are unchanged. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("HandcartHillPenaltyMultiplier", 0.0, 5.0, 1.0, "penalty multiplier"), Array.Empty())); ConfigEntry tandemHandcartLoadPenaltyMultiplier = config.Bind("Trains", "TandemHandcartLoadPenaltyMultiplier", 1.0, new ConfigDescription("Scales the wagon-count and cargo/passenger-weight penalty on powered speed and acceleration for tandems with two confirmed eligible operators; solo uses regular handcart values. Zero disables the penalty; one restores its original strength. Range 0 to 5. Fuel and stamina costs are unchanged. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("TandemHandcartLoadPenaltyMultiplier", 0.0, 5.0, 1.0, "penalty multiplier"), Array.Empty())); ConfigEntry tandemHandcartHillPenaltyMultiplier = config.Bind("Trains", "TandemHandcartHillPenaltyMultiplier", 1.0, new ConfigDescription("Scales the uphill penalty on powered target speed for tandems with two confirmed eligible operators; solo uses regular handcart values. Zero disables the penalty; one restores its original strength. Range 0 to 5. Fuel and stamina costs are unchanged. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("TandemHandcartHillPenaltyMultiplier", 0.0, 5.0, 1.0, "penalty multiplier"), Array.Empty())); ConfigEntry bronzeEngineLoadPenaltyMultiplier = config.Bind("Trains", "BronzeEngineLoadPenaltyMultiplier", 0.5, new ConfigDescription("Scales the wagon-count and cargo/passenger-weight penalty on powered speed and acceleration for the Wood-powered bronze engine. Zero disables the penalty; one restores its original strength. Range 0 to 5. Fuel and stamina costs are unchanged. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("BronzeEngineLoadPenaltyMultiplier", 0.0, 5.0, 0.5, "penalty multiplier"), Array.Empty())); ConfigEntry bronzeEngineHillPenaltyMultiplier = config.Bind("Trains", "BronzeEngineHillPenaltyMultiplier", 0.5, new ConfigDescription("Scales the uphill penalty on powered target speed for the Wood-powered bronze engine. Zero disables the penalty; one restores its original strength. Range 0 to 5. Fuel and stamina costs are unchanged. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("BronzeEngineHillPenaltyMultiplier", 0.0, 5.0, 0.5, "penalty multiplier"), Array.Empty())); ConfigEntry locomotiveLoadPenaltyMultiplier = config.Bind("Trains", "LocomotiveLoadPenaltyMultiplier", 0.5, new ConfigDescription("Scales the wagon-count and cargo/passenger-weight penalty on powered speed and acceleration for the coal locomotive. Zero disables the penalty; one restores its original strength. Range 0 to 5. Fuel and stamina costs are unchanged. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("LocomotiveLoadPenaltyMultiplier", 0.0, 5.0, 0.5, "penalty multiplier"), Array.Empty())); ConfigEntry locomotiveHillPenaltyMultiplier = config.Bind("Trains", "LocomotiveHillPenaltyMultiplier", 0.5, new ConfigDescription("Scales the uphill penalty on powered target speed for the coal locomotive. Zero disables the penalty; one restores its original strength. Range 0 to 5. Fuel and stamina costs are unchanged. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("LocomotiveHillPenaltyMultiplier", 0.0, 5.0, 0.5, "penalty multiplier"), Array.Empty())); ConfigEntry eitrFuel = config.Bind("Fuel", "EitrFuelSecondsPerItem", 300.0, new ConfigDescription("Seconds of powered movement supplied by each newly consumed Refined Eitr in the Eitr engine. Already-burning fuel keeps its saved seconds. Idling, coasting, braking and blocked movement consume no fuel. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("EitrFuelSecondsPerItem", 1.0, 86400.0, 300.0, "seconds per Refined Eitr"), Array.Empty())); ConfigEntry eitrSpeed = config.Bind("Trains", "EitrEngineMaxSpeed", 10.5, new ConfigDescription("Base powered target speed and maximum downhill speed of the Eitr engine in metres per second. Load and uphill grades reduce powered speed; acceleration, braking and fuel duration remain independent. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("EitrEngineMaxSpeed", 0.5, 15.0, 10.5, "m/s"), Array.Empty())); ConfigEntry eitrCarts = config.Bind("Trains", "EitrEngineMaxCarts", 8, new ConfigDescription("Maximum attached unpowered carts in total across both ends of an Eitr engine. Matching engines and plows do not count. Zero prevents new cart attachments. Lowering this value leaves existing trains intact. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new CartRange("EitrEngineMaxCarts"), Array.Empty())); ConfigEntry eitrLoadPenaltyMultiplier = config.Bind("Trains", "EitrEngineLoadPenaltyMultiplier", 0.25, new ConfigDescription("Scales the wagon-count and cargo/passenger-weight penalty on powered speed and acceleration for the Eitr engine. Zero disables the penalty; one uses the full underlying coefficients. Fuel duration is unchanged. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("EitrEngineLoadPenaltyMultiplier", 0.0, 5.0, 0.25, "penalty multiplier"), Array.Empty())); ConfigEntry eitrHillPenaltyMultiplier = config.Bind("Trains", "EitrEngineHillPenaltyMultiplier", 0.25, new ConfigDescription("Scales the uphill penalty on powered target speed for the Eitr engine. Zero disables the penalty; one uses the full underlying coefficient. Downhill momentum and fuel duration are unchanged. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("EitrEngineHillPenaltyMultiplier", 0.0, 5.0, 0.25, "penalty multiplier"), Array.Empty())); ConfigEntry remoteSimulation = config.Bind("Automation", "RemoteSimulationEnabled", true, "True: allow automatic trains to keep operating away from nearby players. False: automatic trains require the normal nearby-player simulation area. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically."); ConfigEntry remoteTrainLimit = config.Bind("Automation", "RemoteTrainLimit", 4, new ConfigDescription("Maximum automatic trains simulated away from players at once. Range 1 to 8; default 4. Lower this to reduce background simulation load. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new RemoteTrainRange(), Array.Empty())); ConfigEntry musicEnabled = config.Bind("Music", "MusicCartsEnabled", true, "Enable playback from Techno Viking and Halloween pumpkin music carts. This is the server-wide permission; personal mute and volume are separate. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically."); ConfigEntry musicRange = config.Bind("Music", "MusicCartRange", 40.0, new ConfigDescription("Maximum music-cart hearing distance in metres, from 10 to 80. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("MusicCartRange", 10.0, 80.0, 40.0, "metres"), Array.Empty())); ConfigEntry musicMaxVolume = config.Bind("Music", "MusicCartMaxVolume", 0.6, new ConfigDescription("Server-wide music-cart volume cap, from 0 to 1. Personal volume can reduce it further. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically.", (AcceptableValueBase)(object)new FiniteRange("MusicCartMaxVolume", 0.0, 1.0, 0.6, "volume"), Array.Empty())); ConfigEntry musicVolume = config.Bind("MusicClient", "Volume", 0.5, new ConfigDescription("Personal master music-cart volume, from 0 to 1. Multiplies the selected soundtrack volume and the cart's shared volume. Personal preference only; never sent to or overwritten by the server. Saved edits apply live.", (AcceptableValueBase)(object)new FiniteRange("MusicClient.Volume", 0.0, 1.0, 0.5, "volume"), Array.Empty())); ConfigEntry technoVolume = config.Bind("MusicClient", "TechnoVolume", 1.0, new ConfigDescription("Personal Techno Viking soundtrack multiplier, from 0 to 1. Multiplies master Volume when playing on its own. Personal preference only; never sent to or overwritten by the server. Saved edits apply live.", (AcceptableValueBase)(object)new FiniteRange("MusicClient.TechnoVolume", 0.0, 1.0, 1.0, "volume"), Array.Empty())); ConfigEntry pumpkinVolume = config.Bind("MusicClient", "PumpkinVolume", 1.0, new ConfigDescription("Personal pumpkin-carriage soundtrack multiplier, from 0 to 1. Multiplies master Volume when playing on its own. Personal preference only; never sent to or overwritten by the server. Saved edits apply live.", (AcceptableValueBase)(object)new FiniteRange("MusicClient.PumpkinVolume", 0.0, 1.0, 1.0, "volume"), Array.Empty())); ConfigEntry halloweenTechnoVolume = config.Bind("MusicClient", "HalloweenTechnoVolume", 1.0, new ConfigDescription("Personal combined Halloween techno soundtrack multiplier, from 0 to 1. Used instead of the two solo multipliers when both cart types play together. Personal preference only; never sent to or overwritten by the server. Saved edits apply live.", (AcceptableValueBase)(object)new FiniteRange("MusicClient.HalloweenTechnoVolume", 0.0, 1.0, 1.0, "volume"), Array.Empty())); ConfigEntry musicMuted = config.Bind("MusicClient", "Muted", false, "Mute music-cart audio for this client. Personal preference only; never sent to or overwritten by the server. Saved edits apply live."); ConfigEntry musicBeatLights = config.Bind("MusicClient", "BeatLights", false, "Enable optional music-cart beat lights for this client. Personal preference only; never sent to or overwritten by the server. Saved edits apply live."); ConfigEntry musicMaxAudible = config.Bind("MusicClient", "MaxAudibleCarts", 1, new ConfigDescription("Maximum simultaneously audible independent music groups for this client, from 1 to 4. A linked Techno/Pumpkin train counts once. Personal preference only; never sent to or overwritten by the server. Saved edits apply live.", (AcceptableValueBase)(object)new AcceptableValueRange(1, 4), Array.Empty())); _readMusicBindings = () => new RailMusicClientValues(musicVolume.Value, musicMuted.Value, musicBeatLights.Value, musicMaxAudible.Value, technoVolume.Value, pumpkinVolume.Value, halloweenTechnoVolume.Value); _writeMusicBindings = delegate(RailMusicClientValues values) { musicVolume.Value = values.Volume; musicMuted.Value = values.Muted; musicBeatLights.Value = values.BeatLights; musicMaxAudible.Value = values.MaxAudibleCarts; technoVolume.Value = values.TechnoVolume; pumpkinVolume.Value = values.PumpkinVolume; halloweenTechnoVolume.Value = values.HalloweenTechnoVolume; }; ConfigEntry clearTerrain = config.Bind("Construction", "ClearTerrainOnPlacement", false, "Retired compatibility setting. Ignored even when true: railway tracks never automatically lower or clear earth. Existing values remain readable and synchronized for compatibility with older configuration files."); ConfigEntry fillTerrain = config.Bind("Construction", "FillTerrainOnPlacement", false, "Retired compatibility setting. Ignored even when true: railway tracks never automatically raise or fill earth. Existing values remain readable and synchronized for compatibility with older configuration files."); ConfigEntry dirtTrackbed = config.Bind("Construction", "DirtTrackbedOnPlacement", true, "True: paint stone gravel beneath ground-level tracks, including between the rails and 2 m beyond each side of the sleepers. Skips elevated track and ground covered by bridge decks. False: preserve the existing ground surface. Applies on placement and gradually to loaded existing tracks, respects protected areas, and remains after removing the rail. Never raises, lowers, levels or smooths terrain. This setting keeps its legacy DirtTrackbedOnPlacement name. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically."); ConfigEntry damage = config.Bind("Construction", "TracksTakeDamage", true, "True: railway tracks take damage normally. False: protect wooden, iron and upgraded tracks, including switches, stops and bumpers, from damage and support decay. Hammer removal is still allowed; vehicles, signs and other structures are unaffected. Saved file edits apply automatically within about two seconds. Host/server settings apply to all clients. After joining and receiving admin access, a server administrator's live edits update only the changed fields on the server. Use vikingrail_config push to deliberately push all local values; joining never pushes them automatically."); _readBindings = () => new RailSettingsValues(torches.Value, coal.Value, handcart.Value, locomotive.Value, clearTerrain.Value, dirtTrackbed.Value, stamina.Value, fillTerrain.Value, handcartSpeed.Value, locomotiveSpeed.Value, damage.Value, tandemSpeed.Value, tandemStamina.Value, tandemCarts.Value, bronzeFuel.Value, bronzeSpeed.Value, bronzeCarts.Value, handcartLoadPenaltyMultiplier.Value, handcartHillPenaltyMultiplier.Value, tandemHandcartLoadPenaltyMultiplier.Value, tandemHandcartHillPenaltyMultiplier.Value, bronzeEngineLoadPenaltyMultiplier.Value, bronzeEngineHillPenaltyMultiplier.Value, locomotiveLoadPenaltyMultiplier.Value, locomotiveHillPenaltyMultiplier.Value, eitrFuel.Value, eitrSpeed.Value, eitrCarts.Value, eitrLoadPenaltyMultiplier.Value, eitrHillPenaltyMultiplier.Value, remoteSimulation.Value, remoteTrainLimit.Value, musicEnabled.Value, musicRange.Value, musicMaxVolume.Value); _writeBindings = delegate(RailSettingsValues values) { torches.Value = values.AttachedTorchesUseFuel; coal.Value = values.CoalSecondsPerItem; handcart.Value = values.HandcartMaxCarts; locomotive.Value = values.LocomotiveMaxCarts; clearTerrain.Value = values.ClearTerrainOnPlacement; dirtTrackbed.Value = values.DirtTrackbedOnPlacement; stamina.Value = values.HandcartStaminaPerSecond; fillTerrain.Value = values.FillTerrainOnPlacement; handcartSpeed.Value = values.HandcartMaxSpeed; locomotiveSpeed.Value = values.LocomotiveMaxSpeed; damage.Value = values.TracksTakeDamage; tandemSpeed.Value = values.TandemHandcartMaxSpeed; tandemStamina.Value = values.TandemHandcartStaminaPerSecond; tandemCarts.Value = values.TandemHandcartMaxCarts; bronzeFuel.Value = values.BronzeFuelSecondsPerItem; bronzeSpeed.Value = values.BronzeEngineMaxSpeed; bronzeCarts.Value = values.BronzeEngineMaxCarts; handcartLoadPenaltyMultiplier.Value = values.HandcartLoadPenaltyMultiplier; handcartHillPenaltyMultiplier.Value = values.HandcartHillPenaltyMultiplier; tandemHandcartLoadPenaltyMultiplier.Value = values.TandemHandcartLoadPenaltyMultiplier; tandemHandcartHillPenaltyMultiplier.Value = values.TandemHandcartHillPenaltyMultiplier; bronzeEngineLoadPenaltyMultiplier.Value = values.BronzeEngineLoadPenaltyMultiplier; bronzeEngineHillPenaltyMultiplier.Value = values.BronzeEngineHillPenaltyMultiplier; locomotiveLoadPenaltyMultiplier.Value = values.LocomotiveLoadPenaltyMultiplier; locomotiveHillPenaltyMultiplier.Value = values.LocomotiveHillPenaltyMultiplier; eitrFuel.Value = values.EitrFuelSecondsPerItem; eitrSpeed.Value = values.EitrEngineMaxSpeed; eitrCarts.Value = values.EitrEngineMaxCarts; eitrLoadPenaltyMultiplier.Value = values.EitrEngineLoadPenaltyMultiplier; eitrHillPenaltyMultiplier.Value = values.EitrEngineHillPenaltyMultiplier; remoteSimulation.Value = values.RemoteSimulationEnabled; remoteTrainLimit.Value = values.RemoteTrainLimit; musicEnabled.Value = values.MusicCartsEnabled; musicRange.Value = values.MusicCartRange; musicMaxVolume.Value = values.MusicCartMaxVolume; }; _local = _readBindings(); _music = _readMusicBindings(); if (!string.IsNullOrWhiteSpace(text)) { try { RailSettingsValues local = RailSettingsText.Read(text, _local, RailPlugin.Warn); RailMusicClientValues music = RailSettingsText.ReadClient(text, _music, RailPlugin.Warn); _local = local; _music = music; } catch (FormatException ex2) { flag = false; RailPlugin.Warn("Railroad configuration could not be fully read; keeping valid bound values. " + ex2.Message); } } if (flag && val.Value < 1) { RailSettingsValues railSettingsValues = RailSpeedDefaultsUpgrade.Apply(_local, val.Value); if (!railSettingsValues.Equals(_local)) { RailPlugin.LogInfo("Updated previous default train speeds: handcart 4.5, tandem 6.75, bronze 6, coal 7.5, Eitr 10.5 m/s. Custom speeds were preserved."); } _local = railSettingsValues; val.Value = 1; } _writeBindings(_local); _writeMusicBindings(_music); if (flag) { try { config.Save(); } catch (Exception ex3) { RailPlugin.Warn("Could not save railroad configuration: " + ex3.Message); } } } finally { config.SaveOnConfigSet = saveOnConfigSet; } _config.SettingChanged += OnSettingChanged; _config.ConfigReloaded += OnConfigReloaded; Interlocked.Exchange(ref _bindingsDirty, 0); Interlocked.Exchange(ref _bindingsAdminDirty, 0); Interlocked.Exchange(ref _musicBindingsDirty, 0); _candidateText = null; _nextConfigPoll = 0f; _broadcastPending = true; try { _observedText = File.ReadAllText(config.ConfigFilePath); } catch { _observedText = text; } RailPlugin.LogInfo("Rail settings loaded from " + config.ConfigFilePath + ". File edits reload automatically. " + Describe(_local)); InitializeSettingsCommand(); } private static void OnSettingChanged(object sender, SettingChangedEventArgs args) { if (args.ChangedSetting.Definition.Section == "MusicClient") { Interlocked.Exchange(ref _musicBindingsDirty, 1); } else { MarkBindingsChanged(); } } private static void OnConfigReloaded(object sender, EventArgs args) { Interlocked.Exchange(ref _musicBindingsDirty, 1); MarkBindingsChanged(); } private static void MarkBindingsChanged() { if (_adminEditsEnabled) { Interlocked.Exchange(ref _bindingsAdminDirty, 1); } Interlocked.Exchange(ref _bindingsDirty, 1); } private static void PollLocalSettings() { if (_config == null || _readBindings == null || _writeBindings == null || _readMusicBindings == null || _writeMusicBindings == null) { return; } if (Interlocked.Exchange(ref _musicBindingsDirty, 0) != 0) { try { _music = _readMusicBindings(); } catch (Exception ex) { RailPlugin.Warn("Invalid personal music preferences; keeping previous values. " + ex.Message); } } if (Interlocked.Exchange(ref _bindingsDirty, 0) != 0) { bool mayPropose = Interlocked.Exchange(ref _bindingsAdminDirty, 0) != 0; try { PublishLocal(_readBindings(), "Configuration entries changed", mayPropose); } catch (Exception ex2) { RailPlugin.Warn("Invalid railroad configuration entries; keeping previous settings. " + ex2.Message); } } if (Time.realtimeSinceStartup < _nextConfigPoll) { return; } _nextConfigPoll = Time.realtimeSinceStartup + 1f; string text; try { text = File.ReadAllText(_config.ConfigFilePath); _ioWarned = false; } catch (Exception ex3) { if (!_ioWarned) { RailPlugin.Warn("Cannot reload railroad configuration; keeping previous settings. " + ex3.Message); } _ioWarned = true; _candidateText = null; return; } if (text == _observedText) { _candidateText = null; return; } if (text != _candidateText) { _candidateText = text; _candidateCanPropose = _adminEditsEnabled; return; } bool candidateCanPropose = _candidateCanPropose; _candidateText = null; _observedText = text; try { RailSettingsValues railSettingsValues = RailSettingsText.Read(text, _local, RailPlugin.Warn); RailMusicClientValues railMusicClientValues = RailSettingsText.ReadClient(text, _music, RailPlugin.Warn); bool saveOnConfigSet = _config.SaveOnConfigSet; _config.SaveOnConfigSet = false; try { _writeBindings(railSettingsValues); _writeMusicBindings(railMusicClientValues); } finally { _config.SaveOnConfigSet = saveOnConfigSet; } Interlocked.Exchange(ref _bindingsDirty, 0); Interlocked.Exchange(ref _bindingsAdminDirty, 0); Interlocked.Exchange(ref _musicBindingsDirty, 0); _music = railMusicClientValues; PublishLocal(railSettingsValues, "Reloaded " + _config.ConfigFilePath, candidateCanPropose); } catch (Exception ex4) { RailPlugin.Warn("Cannot apply railroad configuration; keeping previous settings. " + ex4.Message); } } private static void PublishLocal(RailSettingsValues values, string reason, bool mayPropose = false) { if (!_local.Equals(values)) { ulong mask = RailSettingsProposal.ChangedFields(_local, values); _local = values; _broadcastPending = true; bool flag = Object.op_Implicit((Object)(object)ZNet.instance) && !ZNet.instance.IsServer(); RailPlugin.LogInfo(reason + ". " + (flag ? "Local values updated; active multiplayer values change only after server approval. " : "Railroad settings are now active. ") + Describe(values)); if (flag && mayPropose) { QueueAdminEdit(mask, values); } else if (flag) { RailPlugin.LogInfo("This edit was observed before settings/admin synchronization; it stays local. After synchronization, edit a value again or deliberately use vikingrail_config push."); } } } internal static void Update() { EnsureSettingsConnection(); PollLocalSettings(); UpdateSettingsNetwork(); } private static string Describe(RailSettingsValues values) { return "Mounting-pad standing torch fuel: " + values.AttachedTorchesUseFuel + "; Rail torches: always lit; coal: " + values.CoalSecondsPerItem.ToString(CultureInfo.InvariantCulture) + " s; handcart carts: " + values.HandcartMaxCarts + "; locomotive carts: " + values.LocomotiveMaxCarts + "; earth clearing/filling: disabled (retired settings); stone gravel trackbed (+2 m each side): " + values.DirtTrackbedOnPlacement + "; handcart stamina: " + values.HandcartStaminaPerSecond.ToString(CultureInfo.InvariantCulture) + " per second; handcart powered speed: " + values.HandcartMaxSpeed.ToString(CultureInfo.InvariantCulture) + " m/s; locomotive powered speed: " + values.LocomotiveMaxSpeed.ToString(CultureInfo.InvariantCulture) + " m/s; tracks take damage: " + values.TracksTakeDamage + "; tandem two-rider powered speed: " + values.TandemHandcartMaxSpeed.ToString(CultureInfo.InvariantCulture) + " m/s; tandem two-rider stamina: " + values.TandemHandcartStaminaPerSecond.ToString(CultureInfo.InvariantCulture) + " per second per rider; tandem carts: " + values.TandemHandcartMaxCarts + "; bronze fuel: " + values.BronzeFuelSecondsPerItem.ToString(CultureInfo.InvariantCulture) + " s per Wood; bronze engine powered speed: " + values.BronzeEngineMaxSpeed.ToString(CultureInfo.InvariantCulture) + " m/s; bronze engine carts: " + values.BronzeEngineMaxCarts + "; HandcartLoadPenaltyMultiplier: " + values.HandcartLoadPenaltyMultiplier.ToString(CultureInfo.InvariantCulture) + "; HandcartHillPenaltyMultiplier: " + values.HandcartHillPenaltyMultiplier.ToString(CultureInfo.InvariantCulture) + "; TandemHandcartLoadPenaltyMultiplier: " + values.TandemHandcartLoadPenaltyMultiplier.ToString(CultureInfo.InvariantCulture) + "; TandemHandcartHillPenaltyMultiplier: " + values.TandemHandcartHillPenaltyMultiplier.ToString(CultureInfo.InvariantCulture) + "; BronzeEngineLoadPenaltyMultiplier: " + values.BronzeEngineLoadPenaltyMultiplier.ToString(CultureInfo.InvariantCulture) + "; BronzeEngineHillPenaltyMultiplier: " + values.BronzeEngineHillPenaltyMultiplier.ToString(CultureInfo.InvariantCulture) + "; LocomotiveLoadPenaltyMultiplier: " + values.LocomotiveLoadPenaltyMultiplier.ToString(CultureInfo.InvariantCulture) + "; LocomotiveHillPenaltyMultiplier: " + values.LocomotiveHillPenaltyMultiplier.ToString(CultureInfo.InvariantCulture) + "; Eitr fuel: " + values.EitrFuelSecondsPerItem.ToString(CultureInfo.InvariantCulture) + " s per Refined Eitr; Eitr engine powered speed: " + values.EitrEngineMaxSpeed.ToString(CultureInfo.InvariantCulture) + " m/s; Eitr engine carts: " + values.EitrEngineMaxCarts + "; EitrEngineLoadPenaltyMultiplier: " + values.EitrEngineLoadPenaltyMultiplier.ToString(CultureInfo.InvariantCulture) + "; EitrEngineHillPenaltyMultiplier: " + values.EitrEngineHillPenaltyMultiplier.ToString(CultureInfo.InvariantCulture) + "; remote train simulation: " + values.RemoteSimulationEnabled + "; remote train limit: " + values.RemoteTrainLimit + "; music carts: " + values.MusicCartsEnabled + "; music range: " + values.MusicCartRange.ToString(CultureInfo.InvariantCulture) + " m; music volume cap: " + values.MusicCartMaxVolume.ToString(CultureInfo.InvariantCulture) + "."; } internal static void ResetSession() { ResetSettingsConnections(); _network = null; } } internal static class RailSpawnHooks { [ThreadStatic] internal static int VegetationDepth; private static readonly HashSet Warnings = new HashSet(); internal static bool Blocks(Vector3 point) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) try { return RailSpawnProtection.Blocks(point); } catch (Exception ex) { Warn("Rail clearance lookup", ex.Message); return false; } } internal static bool Blocks(Bounds bounds, bool onlyNearBed) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) try { return RailSpawnProtection.Blocks(bounds, onlyNearBed); } catch (Exception ex) { Warn("Rail clearance bounds lookup", ex.Message); return false; } } internal static void Warn(string feature, string detail) { if (Warnings.Add(feature)) { RailPlugin.Warn(feature + " protection is unavailable: " + detail); } } internal static MethodInfo? Find(Type type, string name, Type returns, params Type[] arguments) { MethodInfo methodInfo = AccessTools.DeclaredMethod(type, name, arguments, (Type[])null); if (methodInfo != null && !methodInfo.IsStatic && methodInfo.ReturnType == returns) { return methodInfo; } Warn(type.Name + "." + name, "the native method signature changed on this Valheim build."); return null; } internal static MethodInfo[] Resources(string name, Type returns, params Type[] arguments) { List list = new List(); Type[] array = new Type[3] { typeof(Pickable), typeof(PickableItem), typeof(Plant) }; for (int i = 0; i < array.Length; i++) { MethodInfo methodInfo = Find(array[i], name, returns, arguments); if (methodInfo != null) { list.Add(methodInfo); } } return list.ToArray(); } } [HarmonyPatch] internal static class RailClutterGroundPatch { private static readonly MethodInfo? Method = RailSpawnHooks.Find(typeof(ClutterSystem), "GetGroundInfo", typeof(bool), typeof(Vector3), typeof(Vector3).MakeByRefType(), typeof(Vector3).MakeByRefType(), typeof(Heightmap).MakeByRefType(), typeof(Biome).MakeByRefType()); [HarmonyPrepare] private static bool Prepare() { return Method != null; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return Method; } [HarmonyPostfix] private static void Postfix(Vector3 __1, ref bool __result) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) if (__result && RailSpawnHooks.Blocks(__1)) { __result = false; } } } [HarmonyPatch] internal static class RailVegetationScopePatch { private static readonly MethodInfo? Method = FindPlacement(); private static MethodInfo? FindPlacement() { MethodInfo[] methods = typeof(ZoneSystem).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (!(methodInfo.Name != "PlaceVegetation") && !(methodInfo.ReturnType != typeof(void))) { ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length == 7 && parameters[1].ParameterType == typeof(Vector3) && parameters[2].ParameterType == typeof(Transform) && parameters[3].ParameterType == typeof(Heightmap) && parameters[4].ParameterType == typeof(List) && parameters[5].ParameterType == typeof(SpawnMode) && parameters[6].ParameterType == typeof(List)) { return methodInfo; } } } RailSpawnHooks.Warn("Zone vegetation", "the native placement signature changed on this Valheim build."); return null; } [HarmonyPrepare] private static bool Prepare() { return Method != null; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return Method; } [HarmonyPrefix] private static void Prefix(out int __state) { __state = RailSpawnHooks.VegetationDepth; RailSpawnHooks.VegetationDepth++; } [HarmonyFinalizer] private static void Finalizer(int __state) { RailSpawnHooks.VegetationDepth = __state; } } [HarmonyPatch] internal static class RailVegetationClearAreaPatch { private static readonly MethodInfo? Method = RailSpawnHooks.Find(typeof(ZoneSystem), "InsideClearArea", typeof(bool), typeof(List), typeof(Vector3)); [HarmonyPrepare] private static bool Prepare() { return Method != null; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return Method; } [HarmonyPostfix] private static void Postfix(Vector3 __1, ref bool __result) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (!__result && RailSpawnHooks.VegetationDepth > 0 && RailSpawnHooks.Blocks(__1)) { __result = true; } } } [HarmonyPatch] internal static class RailPickableRegrowthPatch { private static readonly MethodInfo? Method = RailSpawnHooks.Find(typeof(Pickable), "ShouldRespawn", typeof(bool)); [HarmonyPrepare] private static bool Prepare() { return Method != null; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return Method; } [HarmonyPostfix] private static void Postfix(Pickable __instance, ref bool __result) { if (__result && __instance.GetPicked() && RailNaturalResource.Covered((Component)(object)__instance)) { __result = false; } } } [HarmonyPatch] internal static class RailPlantGrowthPatch { private static readonly MethodInfo? Method = RailSpawnHooks.Find(typeof(Plant), "Grow", typeof(GameObject)); [HarmonyPrepare] private static bool Prepare() { return Method != null; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return Method; } [HarmonyPrefix] private static bool Prefix(Plant __instance, ref GameObject __result) { if (!RailNaturalResource.Covered((Component)(object)__instance)) { return true; } __result = null; return false; } } [HarmonyPatch] internal static class RailNaturalResourceAwakePatch { private static readonly MethodInfo[] Methods = RailSpawnHooks.Resources("Awake", typeof(void)); [HarmonyPrepare] private static bool Prepare() { return Methods.Length != 0; } [HarmonyTargetMethods] private static IEnumerable TargetMethods() { return Methods; } [HarmonyPostfix] private static void Postfix(Component __instance) { RailNaturalResource.Register(__instance); } } [HarmonyPatch] internal static class RailNaturalResourceStreamingPatch { private static readonly MethodInfo? Method = RailSpawnHooks.Find(typeof(ZNetScene), "CreateObject", typeof(GameObject), typeof(ZDO)); [HarmonyPrepare] private static bool Prepare() { return Method != null; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return Method; } [HarmonyPostfix] private static void Postfix(GameObject __result) { RailNaturalResource.RegisterHierarchy(__result); } } [HarmonyPatch] internal static class RailNaturalRockInitializationPatch { private static readonly MethodInfo[] Methods = FindMethods(); private static MethodInfo[] FindMethods() { List result = new List(); Add(typeof(Destructible), "Awake"); Add(typeof(Destructible), "Start"); Add(typeof(MineRock), "Start"); Add(typeof(MineRock5), "Awake"); return result.ToArray(); void Add(Type type, string name) { MethodInfo methodInfo = RailSpawnHooks.Find(type, name, typeof(void)); if (methodInfo != null) { result.Add(methodInfo); } } } [HarmonyPrepare] private static bool Prepare() { return Methods.Length != 0; } [HarmonyTargetMethods] private static IEnumerable TargetMethods() { return Methods; } [HarmonyPostfix] private static void Postfix(Component __instance) { RailNaturalResource.Register(__instance); } } [HarmonyPatch] internal static class RailNaturalRockDamagePatch { private static readonly MethodInfo[] Methods = FindMethods(); private static MethodInfo[] FindMethods() { List result = new List(); Type[] array = new Type[3] { typeof(Destructible), typeof(MineRock), typeof(MineRock5) }; for (int i = 0; i < array.Length; i++) { Add(array[i], "Damage", new Type[1] { typeof(HitData) }); } Add(typeof(Destructible), "RPC_Damage", new Type[2] { typeof(long), typeof(HitData) }); Add(typeof(MineRock), "RPC_Hit", new Type[3] { typeof(long), typeof(HitData), typeof(int) }); Add(typeof(MineRock5), "RPC_Damage", new Type[3] { typeof(long), typeof(HitData), typeof(int) }); Add(typeof(MineRock5), "CheckSupport", Array.Empty()); return result.ToArray(); void Add(Type type, string name, Type[] arguments) { MethodInfo methodInfo = RailSpawnHooks.Find(type, name, typeof(void), arguments); if (methodInfo != null) { result.Add(methodInfo); } } } [HarmonyPrepare] private static bool Prepare() { return Methods.Length != 0; } [HarmonyTargetMethods] private static IEnumerable TargetMethods() { return Methods; } [HarmonyPrefix] private static bool Prefix(Component __instance) { return !RailNaturalResource.Covered(__instance); } } [HarmonyPatch] internal static class RailNaturalResourceHoverPatch { private static readonly MethodInfo[] Methods = RailSpawnHooks.Resources("GetHoverText", typeof(string)); [HarmonyPrepare] private static bool Prepare() { return Methods.Length != 0; } [HarmonyTargetMethods] private static IEnumerable TargetMethods() { return Methods; } [HarmonyPrefix] private static bool Prefix(Component __instance, ref string __result) { if (!RailNaturalResource.Covered(__instance)) { return true; } __result = ""; return false; } } [HarmonyPatch] internal static class RailNaturalResourceInteractPatch { private static readonly MethodInfo[] Methods = FindMethods(); private static MethodInfo[] FindMethods() { List list = new List(); Type[] array = new Type[2] { typeof(Pickable), typeof(PickableItem) }; for (int i = 0; i < array.Length; i++) { MethodInfo methodInfo = RailSpawnHooks.Find(array[i], "Interact", typeof(bool), typeof(Humanoid), typeof(bool), typeof(bool)); if (methodInfo != null) { list.Add(methodInfo); } } return list.ToArray(); } [HarmonyPrepare] private static bool Prepare() { return Methods.Length != 0; } [HarmonyTargetMethods] private static IEnumerable TargetMethods() { return Methods; } [HarmonyPrefix] private static bool Prefix(Component __instance, ref bool __result) { if (!RailNaturalResource.Covered(__instance)) { return true; } __result = false; return false; } } [HarmonyPatch] internal static class RailNaturalResourcePickRpcPatch { private static readonly MethodInfo[] Methods = FindMethods(); private static MethodInfo[] FindMethods() { List list = new List(); MethodInfo methodInfo = RailSpawnHooks.Find(typeof(Pickable), "RPC_Pick", typeof(void), typeof(long), typeof(int)); MethodInfo methodInfo2 = RailSpawnHooks.Find(typeof(PickableItem), "RPC_Pick", typeof(void), typeof(long)); if (methodInfo != null) { list.Add(methodInfo); } if (methodInfo2 != null) { list.Add(methodInfo2); } return list.ToArray(); } [HarmonyPrepare] private static bool Prepare() { return Methods.Length != 0; } [HarmonyTargetMethods] private static IEnumerable TargetMethods() { return Methods; } [HarmonyPrefix] private static bool Prefix(Component __instance) { return !RailNaturalResource.Covered(__instance); } } [HarmonyPatch] internal static class RailNaturalResourceNativeVisualPatch { private static readonly MethodInfo[] Methods = FindMethods(); private static MethodInfo[] FindMethods() { List result = new List(); string[] array = new string[2] { "SetPicked", "SetEnabled" }; foreach (string name in array) { MethodInfo methodInfo = RailSpawnHooks.Find(typeof(Pickable), name, typeof(void), typeof(bool)); if (methodInfo != null) { result.Add(methodInfo); } } MethodInfo methodInfo2 = RailSpawnHooks.Find(typeof(Pickable), "SetEnabled", typeof(void), typeof(int)); MethodInfo methodInfo3 = RailSpawnHooks.Find(typeof(PickableItem), "SetupItem", typeof(void), typeof(bool)); if (methodInfo2 != null) { result.Add(methodInfo2); } if (methodInfo3 != null) { result.Add(methodInfo3); } AddRock(typeof(MineRock), "UpdateVisability", Array.Empty()); AddRock(typeof(MineRock), "RPC_Hide", new Type[2] { typeof(long), typeof(int) }); AddRock(typeof(MineRock5), "UpdateMesh", Array.Empty()); AddRock(typeof(MineRock5), "RPC_SetAreaHealth", new Type[3] { typeof(long), typeof(int), typeof(float) }); return result.ToArray(); void AddRock(Type type, string name2, Type[] arguments) { MethodInfo methodInfo4 = RailSpawnHooks.Find(type, name2, typeof(void), arguments); if (methodInfo4 != null) { result.Add(methodInfo4); } } } [HarmonyPrepare] private static bool Prepare() { return Methods.Length != 0; } [HarmonyTargetMethods] private static IEnumerable TargetMethods() { return Methods; } [HarmonyPrefix] private static void Prefix(Component __instance, out RailNaturalResource? __state) { __state = __instance.GetComponent(); if (Object.op_Implicit((Object)(object)__state)) { __state.BeginNativeVisualUpdate(); } } [HarmonyFinalizer] private static void Finalizer(Component __instance, RailNaturalResource? __state) { if (Object.op_Implicit((Object)(object)__state)) { __state.EndNativeVisualUpdate(); } else if (Object.op_Implicit((Object)(object)__instance)) { RailNaturalResource.Register(__instance); } } } internal static class RailPlantPlacement { private static readonly FieldInfo? Ghost = AccessTools.Field(typeof(Player), "m_placementGhost"); private static readonly FieldInfo? Status = AccessTools.Field(typeof(Player), "m_placementStatus"); internal static readonly MethodInfo? UpdateGhost = RailSpawnHooks.Find(typeof(Player), "UpdatePlacementGhost", typeof(void), typeof(bool)); internal static readonly MethodInfo? Place = RailSpawnHooks.Find(typeof(Player), "TryPlacePiece", typeof(bool), typeof(Piece)); internal static bool Compatible { get { if (Ghost?.FieldType == typeof(GameObject) && Status?.FieldType == typeof(PlacementStatus)) { return UpdateGhost != null; } return false; } } internal static bool Reject(Player player) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)player != (Object)(object)Player.m_localPlayer) && Compatible) { object? value = Ghost.GetValue(player); GameObject val = (GameObject)((value is GameObject) ? value : null); if (val != null && Object.op_Implicit((Object)(object)val) && val.activeSelf) { Plant componentInChildren = val.GetComponentInChildren(true); if (!Object.op_Implicit((Object)(object)componentInChildren) || !RailSpawnHooks.Blocks(((Component)componentInChildren).transform.position)) { return false; } Status.SetValue(player, (object)(PlacementStatus)5); Piece component = val.GetComponent(); if (Object.op_Implicit((Object)(object)component)) { component.SetInvalidPlacementHeightlight(true); } return true; } } return false; } } [HarmonyPatch] internal static class RailPlantPlacementGhostPatch { [HarmonyPrepare] private static bool Prepare() { return RailPlantPlacement.Compatible; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailPlantPlacement.UpdateGhost; } [HarmonyPostfix] private static void Postfix(Player __instance) { RailPlantPlacement.Reject(__instance); } } [HarmonyPatch] internal static class RailPlantPlacementCommitPatch { [HarmonyPrepare] private static bool Prepare() { if (RailPlantPlacement.Compatible) { return RailPlantPlacement.Place != null; } return false; } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailPlantPlacement.Place; } [HarmonyPrefix] private static bool Prefix(Player __instance, Piece __0, ref bool __result) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Object.op_Implicit((Object)(object)__0) || !Object.op_Implicit((Object)(object)((Component)__0).GetComponentInChildren(true))) { return true; } RailPlantPlacement.UpdateGhost.Invoke(__instance, new object[1] { true }); if (!RailPlantPlacement.Reject(__instance)) { return true; } ((Character)__instance).Message((MessageType)2, "Plants cannot be placed on or beneath railroad tracks.", 0, (Sprite)null, false); __result = false; return false; } } public sealed class RailSpawnProtection : MonoBehaviour { private sealed class SectorCache { internal readonly Vector2Int Sector; internal readonly RailSpawnIndex Index = new RailSpawnIndex(); internal readonly Dictionary Rails = new Dictionary(); internal readonly List Objects = new List(); internal readonly HashSet Seen = new HashSet(); internal readonly List Removed = new List(); internal float NextRefresh; internal float LastUsed; internal SectorCache(Vector2Int sector) { //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) Sector = sector; } } private sealed class SavedRail { internal readonly GameObject Prefab; internal readonly Vector3 Position; internal readonly Vector3 Scale; internal readonly Quaternion Rotation; internal readonly RailSpawnFootprint Footprint; internal SavedRail(GameObject prefab, Vector3 position, Quaternion rotation, Vector3 scale, RailSpawnFootprint footprint) { //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_0015: 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_001c: 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) Prefab = prefab; Position = position; Rotation = rotation; Scale = scale; Footprint = footprint; } } public Vector3[] LocalCorners = Array.Empty(); private const float CacheSeconds = 1f; private const float IdleSeconds = 5f; private const int MaximumSectorCaches = 128; private const float DirtyCellSize = 16f; private static readonly RailSpawnIndex Loaded = new RailSpawnIndex(); private static readonly HashSet Instances = new HashSet(); private static readonly Dictionary Sectors = new Dictionary(); private static readonly HashSet DirtyCells = new HashSet(); private static readonly HashSet Deleting = new HashSet(); private static readonly List ExpiredSectors = new List(); private static readonly List RemovedIds = new List(); private static readonly List DeadInstances = new List(); private static readonly MethodInfo? NativeZone = AccessTools.Method(typeof(ZoneSystem), "GetZone", new Type[1] { typeof(Vector3) }, (Type[])null); private static readonly MethodInfo? NativeSectorSearch = FindSectorSearch(); private static ZDOMan? _manager; private static ZNetScene? _scene; private static int _revision; private static int _generation; private static bool _warned; private static object? _nativeDistance; private ZNetView? _view; private ZDOID _id; private string _key = ""; private RailSpawnFootprint? _footprint; private Matrix4x4 _matrix; private int _registeredGeneration = -1; internal static int Revision { get { EnsureWorld(); return _revision; } } internal static void Configure(GameObject prefab) { RailTerrainPlacement component = prefab.GetComponent(); if (!Object.op_Implicit((Object)(object)component) || component.BedCorners.Length == 0) { throw new InvalidOperationException("Rail spawn protection requires measured sleeper corners: " + ((Object)prefab).name); } (prefab.GetComponent() ?? prefab.AddComponent()).LocalCorners = (Vector3[])component.BedCorners.Clone(); } private void Awake() { _view = ((Component)this).GetComponent(); Instances.Add(this); TryRegister(); } private void OnEnable() { Instances.Add(this); TryRegister(); } private void Start() { TryRegister(); } private void OnDisable() { Unregister(); Instances.Remove(this); } private void OnDestroy() { Unregister(); Instances.Remove(this); } private void TryRegister() { //IL_0096: 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_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_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: 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_00e3: 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_0125: 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_014e: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) EnsureWorld(); if (_registeredGeneration != _generation) { _footprint = null; _key = ""; _registeredGeneration = _generation; } if (!Object.op_Implicit((Object)(object)_view)) { _view = ((Component)this).GetComponent(); } if (!((Behaviour)this).isActiveAndEnabled || !Object.op_Implicit((Object)(object)_view) || !_view.IsValid() || _manager == null || LocalCorners.Length == 0) { Unregister(); return; } ZDO zDO = _view.GetZDO(); if (zDO == null || Deleting.Contains(zDO.m_uid) || _manager.GetZDO(zDO.m_uid) != zDO) { Unregister(); return; } Matrix4x4 localToWorldMatrix = ((Component)this).transform.localToWorldMatrix; if (_footprint != null && _id == zDO.m_uid && localToWorldMatrix == _matrix) { return; } try { RailSpawnFootprint footprint = MakeFootprint(LocalCorners, localToWorldMatrix); if (_footprint != null) { InvalidateSaved(((Matrix4x4)(ref _matrix)).MultiplyPoint3x4(Vector3.zero)); } Unregister(); _id = zDO.m_uid; _key = "loaded:" + ((Object)this).GetInstanceID(); _matrix = localToWorldMatrix; _footprint = footprint; Loaded.Upsert(_key, footprint); Changed(footprint); InvalidateSaved(zDO.GetPosition()); } catch (Exception error) { WarnOnce(error); } } private void Unregister() { if (_footprint != null) { Loaded.Remove(_key); Changed(_footprint); _footprint = null; _key = ""; } } internal static bool Blocks(Vector3 point) { //IL_0018: 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_008e: Unknown result type (might be due to invalid IL or missing references) //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_00ba: Unknown result type (might be due to invalid IL or missing references) EnsureWorld(); if (_manager == null || !Object.op_Implicit((Object)(object)_scene) || !Finite(point)) { return false; } RailVector point2 = RailSegment.ToRail(point); if (Loaded.Blocks(point2)) { return true; } if (NativeZone == null || NativeSectorSearch == null) { WarnOnce(new MissingMethodException("The native saved-object sector query is unavailable.")); return false; } if (!Object.op_Implicit((Object)(object)ZoneSystem.instance)) { return false; } float zoneSize = ZoneSystem.instance.m_zoneSize; if (!(zoneSize > 0f) || float.IsInfinity(zoneSize)) { return false; } Vector2Int val = SectorAt(point, zoneSize); float realtimeSinceStartup = Time.realtimeSinceStartup; for (int i = ((Vector2Int)(ref val)).y - 1; i <= ((Vector2Int)(ref val)).y + 1; i++) { for (int j = ((Vector2Int)(ref val)).x - 1; j <= ((Vector2Int)(ref val)).x + 1; j++) { SectorCache sector = GetSector(new Vector2Int(j, i), realtimeSinceStartup); sector.LastUsed = realtimeSinceStartup; Refresh(sector, realtimeSinceStartup, zoneSize); if (sector.Index.Blocks(point2)) { return true; } } } return false; } internal static bool Blocks(Bounds bounds, bool onlyNearBed) { //IL_001a: 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_0036: 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_005c: 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_007e: 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_00e7: 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_00ef: 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_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) EnsureWorld(); if (_manager == null || !Object.op_Implicit((Object)(object)_scene) || !Finite(((Bounds)(ref bounds)).min) || !Finite(((Bounds)(ref bounds)).max) || ((Bounds)(ref bounds)).size.x > 64f || ((Bounds)(ref bounds)).size.y > 64f || ((Bounds)(ref bounds)).size.z > 64f) { return false; } RailVector minimum = RailSegment.ToRail(((Bounds)(ref bounds)).min); RailVector maximum = RailSegment.ToRail(((Bounds)(ref bounds)).max); if (Loaded.BlocksBounds(minimum, maximum, onlyNearBed)) { return true; } if (!Object.op_Implicit((Object)(object)ZoneSystem.instance) || NativeZone == null || NativeSectorSearch == null) { return false; } float zoneSize = ZoneSystem.instance.m_zoneSize; if (!(zoneSize > 0f) || float.IsInfinity(zoneSize)) { return false; } Vector2Int val = SectorAt(((Bounds)(ref bounds)).min, zoneSize); Vector2Int val2 = SectorAt(((Bounds)(ref bounds)).max, zoneSize); float realtimeSinceStartup = Time.realtimeSinceStartup; for (int i = ((Vector2Int)(ref val)).y - 1; i <= ((Vector2Int)(ref val2)).y + 1; i++) { for (int j = ((Vector2Int)(ref val)).x - 1; j <= ((Vector2Int)(ref val2)).x + 1; j++) { SectorCache sector = GetSector(new Vector2Int(j, i), realtimeSinceStartup); sector.LastUsed = realtimeSinceStartup; Refresh(sector, realtimeSinceStartup, zoneSize); if (sector.Index.BlocksBounds(minimum, maximum, onlyNearBed)) { return true; } } } return false; } internal static void UpdateWorld() { //IL_0102: 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_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0161: 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) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: 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_01e6: 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_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) EnsureWorld(); DeadInstances.Clear(); foreach (RailSpawnProtection instance2 in Instances) { if (!Object.op_Implicit((Object)(object)instance2)) { DeadInstances.Add(instance2); } else { instance2.TryRegister(); } } foreach (RailSpawnProtection deadInstance in DeadInstances) { Instances.Remove(deadInstance); } if (_manager == null) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; float num = (Object.op_Implicit((Object)(object)ZoneSystem.instance) ? ZoneSystem.instance.m_zoneSize : 0f); ExpiredSectors.Clear(); foreach (KeyValuePair sector in Sectors) { if (realtimeSinceStartup - sector.Value.LastUsed > 5f) { ExpiredSectors.Add(sector.Key); } else if (num > 0f && !float.IsInfinity(num)) { Refresh(sector.Value, realtimeSinceStartup, num); } } foreach (Vector2Int expiredSector in ExpiredSectors) { Sectors.Remove(expiredSector); } RemovedIds.Clear(); foreach (ZDOID item in Deleting) { if (_manager.GetZDO(item) == null) { RemovedIds.Add(item); } } foreach (ZDOID removedId in RemovedIds) { Deleting.Remove(removedId); } ClutterSystem instance = ClutterSystem.instance; if (!Object.op_Implicit((Object)(object)instance)) { return; } foreach (Vector2Int dirtyCell in DirtyCells) { Vector2Int current7 = dirtyCell; instance.ResetGrass(new Vector3(((float)((Vector2Int)(ref current7)).x + 0.5f) * 16f, 0f, ((float)((Vector2Int)(ref current7)).y + 0.5f) * 16f), 8f); } DirtyCells.Clear(); } internal static void Reset() { if (_manager != null) { ZDOMan? manager = _manager; manager.m_onZDODestroyed = (Action)Delegate.Remove(manager.m_onZDODestroyed, new Action(OnSavedDestroyed)); } _manager = null; _scene = null; Loaded.Clear(); Sectors.Clear(); Deleting.Clear(); DirtyCells.Clear(); _warned = false; _generation++; _revision++; } private static void EnsureWorld() { ZDOMan instance = ZDOMan.instance; ZNetScene instance2 = ZNetScene.instance; if (instance != _manager || instance2 != _scene) { Reset(); _manager = instance; _scene = instance2; if (_manager != null) { ZDOMan? manager = _manager; manager.m_onZDODestroyed = (Action)Delegate.Combine(manager.m_onZDODestroyed, new Action(OnSavedDestroyed)); } } } private static SectorCache GetSector(Vector2Int key, float now) { //IL_0005: 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_009c: 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_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_0082: Unknown result type (might be due to invalid IL or missing references) if (Sectors.TryGetValue(key, out SectorCache value)) { return value; } if (Sectors.Count >= 128) { Vector2Int key2 = key; float num = float.PositiveInfinity; foreach (KeyValuePair sector in Sectors) { if (sector.Value.LastUsed < num) { key2 = sector.Key; num = sector.Value.LastUsed; } } Sectors.Remove(key2); } value = new SectorCache(key) { LastUsed = now }; Sectors.Add(key, value); return value; } private unsafe static void Refresh(SectorCache cache, float now, float size) { //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_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_0084: 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_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0271: 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_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015a: 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_0167: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: 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_01bc: 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_01e0: 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_01e5: 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_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: 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) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) if (now < cache.NextRefresh || _manager == null || !Object.op_Implicit((Object)(object)_scene) || NativeZone == null || NativeSectorSearch == null) { return; } cache.NextRefresh = now + 1f; try { cache.Objects.Clear(); MethodInfo? nativeZone = NativeZone; object[] array = new object[1]; Vector2Int sector = cache.Sector; float num = (float)((Vector2Int)(ref sector)).x * size; sector = cache.Sector; array[0] = (object)new Vector3(num, 0f, (float)((Vector2Int)(ref sector)).y * size); ReadSectorObjects(nativeZone.Invoke(null, array), cache.Objects); cache.Seen.Clear(); foreach (ZDO @object in cache.Objects) { if (@object == null || Deleting.Contains(@object.m_uid) || _manager.GetZDO(@object.m_uid) != @object) { continue; } GameObject prefab = _scene.GetPrefab(@object.GetPrefab()); if ((Object)(object)prefab == (Object)null) { continue; } RailSpawnProtection component = prefab.GetComponent(); if (!Object.op_Implicit((Object)(object)component) || component.LocalCorners.Length == 0) { continue; } ZDOID uid = @object.m_uid; cache.Seen.Add(uid); Vector3 position = @object.GetPosition(); Quaternion rotation = @object.GetRotation(); Vector3 val = SavedScale(@object, prefab); if (!cache.Rails.TryGetValue(uid, out SavedRail value) || !((Object)(object)value.Prefab == (Object)(object)prefab) || !(value.Position == position) || !(value.Rotation == rotation) || !(value.Scale == val)) { RailSpawnFootprint footprint = MakeFootprint(component.LocalCorners, Matrix4x4.TRS(position, rotation, val)); if (value != null) { Changed(value.Footprint); } cache.Rails[uid] = new SavedRail(prefab, position, rotation, val, footprint); cache.Index.Upsert(((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString(), footprint); Changed(footprint); } } cache.Removed.Clear(); foreach (KeyValuePair rail in cache.Rails) { if (!cache.Seen.Contains(rail.Key)) { cache.Removed.Add(rail.Key); } } foreach (ZDOID item in cache.Removed) { RemoveSaved(cache, item); } } catch (Exception error) { WarnOnce(error); } } private static Vector3 SavedScale(ZDO zdo, GameObject prefab) { //IL_0006: 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_0023: 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_0036: 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_004b: 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_0043: Unknown result type (might be due to invalid IL or missing references) Vector3 localScale = prefab.transform.localScale; ZNetView component = prefab.GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !component.m_syncInitialScale) { return localScale; } Vector3 vec = zdo.GetVec3(ZDOVars.s_scaleHash, Vector3.zero); if (vec != Vector3.zero) { return vec; } float num = zdo.GetFloat(ZDOVars.s_scaleScalarHash, localScale.x); return new Vector3(num, num, num); } private static void OnSavedDestroyed(ZDO zdo) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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_0032: 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_0083: 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_00fb: Unknown result type (might be due to invalid IL or missing references) ZDOID uid = zdo.m_uid; bool flag = false; foreach (SectorCache value in Sectors.Values) { if (value.Rails.ContainsKey(uid)) { RemoveSaved(value, uid); flag = true; } } foreach (RailSpawnProtection instance in Instances) { if (Object.op_Implicit((Object)(object)instance) && instance._footprint != null && instance._id == uid) { instance.Unregister(); flag = true; } } if (!flag) { GameObject val = (Object.op_Implicit((Object)(object)_scene) ? _scene.GetPrefab(zdo.GetPrefab()) : null); flag = Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.GetComponent()); } if (flag) { Deleting.Add(uid); InvalidateSaved(zdo.GetPosition()); _revision++; } } private unsafe static void RemoveSaved(SectorCache cache, ZDOID id) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (cache.Rails.TryGetValue(id, out SavedRail value)) { cache.Rails.Remove(id); cache.Index.Remove(((object)(*(ZDOID*)(&id))/*cast due to .constrained prefix*/).ToString()); Changed(value.Footprint); } } private static void InvalidateSaved(Vector3 position) { //IL_001e: 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_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) if (Object.op_Implicit((Object)(object)ZoneSystem.instance) && ZoneSystem.instance.m_zoneSize > 0f) { Vector2Int key = SectorAt(position, ZoneSystem.instance.m_zoneSize); if (Sectors.TryGetValue(key, out SectorCache value)) { value.NextRefresh = 0f; } } } private static void Changed(RailSpawnFootprint footprint) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) _revision++; int num = Mathf.FloorToInt((float)footprint.MinX / 16f); int num2 = Mathf.FloorToInt((float)footprint.MaxX / 16f); int num3 = Mathf.FloorToInt((float)footprint.MinZ / 16f); int num4 = Mathf.FloorToInt((float)footprint.MaxZ / 16f); for (int i = num3; i <= num4; i++) { for (int j = num; j <= num2; j++) { DirtyCells.Add(new Vector2Int(j, i)); } } } private static RailSpawnFootprint MakeFootprint(Vector3[] corners, Matrix4x4 matrix) { //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) if (corners.Length == 0 || corners.Length % 4 != 0) { throw new ArgumentException("Rail sleeper corners must contain complete quads.", "corners"); } RailVector[][] array = new RailVector[corners.Length / 4][]; for (int i = 0; i < array.Length; i++) { array[i] = new RailVector[4]; for (int j = 0; j < 4; j++) { array[i][j] = RailSegment.ToRail(((Matrix4x4)(ref matrix)).MultiplyPoint3x4(corners[i * 4 + j])); } } return new RailSpawnFootprint(array); } private static Vector2Int SectorAt(Vector3 point, float size) { //IL_0000: 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_002a: Unknown result type (might be due to invalid IL or missing references) return new Vector2Int(Mathf.FloorToInt((point.x + size * 0.5f) / size), Mathf.FloorToInt((point.z + size * 0.5f) / size)); } private static bool Finite(Vector3 point) { //IL_0000: 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_001a: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (!float.IsNaN(point.x) && !float.IsInfinity(point.x) && !float.IsNaN(point.y) && !float.IsInfinity(point.y) && !float.IsNaN(point.z)) { return !float.IsInfinity(point.z); } return false; } private static MethodInfo? FindSectorSearch() { if (NativeZone == null) { return null; } MethodInfo[] methods = typeof(ZDOMan).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (methodInfo.Name != "FindSectorObjects") { continue; } ParameterInfo[] parameters = methodInfo.GetParameters(); if (parameters.Length >= 3 && !(parameters[0].ParameterType != NativeZone.ReturnType)) { if (parameters.Length == 5 && parameters[1].ParameterType == typeof(int) && parameters[2].ParameterType == typeof(int) && parameters[3].ParameterType == typeof(List) && parameters[4].ParameterType == typeof(List)) { return methodInfo; } if ((parameters.Length == 3 || parameters.Length == 4) && parameters[1].ParameterType.Name == "SimulationDistance" && parameters[2].ParameterType == typeof(List) && (parameters.Length == 3 || parameters[3].ParameterType == typeof(List)) && (parameters[1].ParameterType.GetConstructor(new Type[3] { typeof(int), typeof(int), typeof(bool) }) != null || parameters[1].ParameterType.GetConstructor(new Type[2] { typeof(int), typeof(int) }) != null)) { return methodInfo; } } } return null; } private static void ReadSectorObjects(object zone, List output) { ParameterInfo[] parameters = NativeSectorSearch.GetParameters(); if (parameters.Length == 5) { NativeSectorSearch.Invoke(_manager, new object[5] { zone, 0, 0, output, null }); return; } if (_nativeDistance == null) { Type parameterType = parameters[1].ParameterType; ConstructorInfo constructor = parameterType.GetConstructor(new Type[3] { typeof(int), typeof(int), typeof(bool) }); _nativeDistance = ((constructor != null) ? constructor.Invoke(new object[3] { 0, 0, false }) : parameterType.GetConstructor(new Type[2] { typeof(int), typeof(int) }).Invoke(new object[2] { 0, 0 })); } object[] parameters2 = ((parameters.Length != 4) ? new object[3] { zone, _nativeDistance, output } : new object[4] { zone, _nativeDistance, output, null }); NativeSectorSearch.Invoke(_manager, parameters2); } private static void WarnOnce(Exception error) { if (!_warned) { _warned = true; RailPlugin.Warn("Rail spawn protection could not refresh some saved track geometry; it will retry. " + error.GetBaseException().Message); } } } public sealed class RailSwitch : MonoBehaviour { public Vector3[] TrunkPoints = Array.Empty(); public Vector3[] LeftPoints = Array.Empty(); public Vector3[] RightPoints = Array.Empty(); public Vector3[] StraightPoints = Array.Empty(); public Vector3[] OuterLeftPoints = Array.Empty(); public Vector3[] OuterRightPoints = Array.Empty(); public int ParallelExitCount; public bool LightDuty; public bool IsBypassConnection; public Transform? Lever; private const string SelectedKey = "vikingrail_switch_right"; private const string ThreeWaySelectedKey = "vikingrail_switch_route3"; private const string YardSelectedKey = "vikingrail_switch_yard_route"; private const float InteractionRange = 4f; internal const float OccupancyClearance = 3f; private static readonly HashSet Switches = new HashSet(); private static readonly HashSet ClosedMarkers = new HashSet(StringComparer.Ordinal); private readonly List _paths = new List(6); private ZNetView _view; private string _identity = ""; private string _stemId = ""; private string _leftId = ""; private string _rightId = ""; private string _straightId = ""; private string _outerLeftId = ""; private string _outerRightId = ""; private string _markerId = ""; private bool _started; private bool _registered; private int _selectedRoute; private Vector3 _position; private Quaternion _rotation; private Quaternion _leverRest = Quaternion.identity; private bool _pending; private float _requestAt; private long _requestOwner; private long _requestPlayer; private static readonly FieldInfo? WardList = AccessTools.Field(typeof(PrivateArea), "m_allAreas"); private static readonly MethodInfo? WardEnabled = AccessTools.Method(typeof(PrivateArea), "IsEnabled", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo? WardInside = AccessTools.Method(typeof(PrivateArea), "IsInside", new Type[2] { typeof(Vector3), typeof(float) }, (Type[])null); private static readonly MethodInfo? WardPermitted = AccessTools.Method(typeof(PrivateArea), "IsPermitted", new Type[1] { typeof(long) }, (Type[])null); private const string LeaseEngineKey = "vikingrail_switch_engine"; private const string LeasePeerKey = "vikingrail_switch_peer"; private const string LeaseTokenKey = "vikingrail_switch_token"; private const string LeaseRightKey = "vikingrail_switch_lease_right"; private const string LeaseRouteKey = "vikingrail_switch_lease_route3"; private const string LeaseYardRouteKey = "vikingrail_switch_lease_yard_route"; private const string LeaseUntilKey = "vikingrail_switch_until"; private readonly Dictionary _releasedTokens = new Dictionary(StringComparer.Ordinal); private string _localEngine = ""; private string _localToken = ""; private long _localPeer; private float _nextLeaseRequest; public bool IsParallelYard { get { if (ParallelExitCount != 3) { return ParallelExitCount == 5; } return true; } } public bool IsThreeWay => StraightPoints.Length >= 2; internal int RouteCount { get { if (!IsParallelYard) { if (!IsThreeWay) { return 2; } return 3; } return ParallelExitCount; } } internal bool Ready { get { if (_started && Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { return _registered; } return false; } } internal bool IsOccupied { get { if (Ready) { if (!Reservation.IsActive(Now)) { return RailVehicle.OccupiesSwitch(_paths, 3f); } return true; } return false; } } internal static IEnumerable LoadedSwitches => Switches; private int NextRoute => (_selectedRoute + 1) % RouteCount; private Vector3 LeverPosition { get { //IL_001f: 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) if (!Object.op_Implicit((Object)(object)Lever)) { return ((Component)this).transform.position; } return Lever.position; } } private static long Now { get { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return 0L; } return (long)(ZNet.instance.GetTimeSeconds() * 1000.0); } } private SwitchRouteReservation Reservation { get { if (Ready) { return new SwitchRouteReservation(_view.GetZDO().GetString("vikingrail_switch_engine", ""), _view.GetZDO().GetLong("vikingrail_switch_peer", 0L), _view.GetZDO().GetString("vikingrail_switch_token", ""), IsParallelYard ? _view.GetZDO().GetInt("vikingrail_switch_lease_yard_route", -1) : (IsThreeWay ? _view.GetZDO().GetInt("vikingrail_switch_lease_route3", -1) : (_view.GetZDO().GetBool("vikingrail_switch_lease_right", false) ? 1 : 0)), _view.GetZDO().GetLong("vikingrail_switch_until", 0L)); } return default(SwitchRouteReservation); } } internal static bool IsClosedSwitchMarker(string? id) { if (id != null) { return ClosedMarkers.Contains(id); } return false; } internal void SetLightDuty(bool lightDuty) { LightDuty = lightDuty; if (!_registered) { return; } foreach (string item in PathIds()) { if (lightDuty) { RailSegment.LightTrackIds.Add(item); } else { RailSegment.LightTrackIds.Remove(item); } } } private void Awake() { //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) _view = ((Component)this).GetComponent(); if (Object.op_Implicit((Object)(object)Lever)) { _leverRest = Lever.localRotation; } } private void Start() { if (Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { _started = true; Switches.Add(this); _view.Register("VR_SwitchToggle", (Action)RequestToggle); _view.Register("VR_SwitchSelect3_v1", (Action)RequestThreeWaySelection); _view.Register("VR_SwitchSelectYard_v1", (Action)RequestYardSelection); _view.Register("VR_SwitchReply", (Action)ReceiveReply); RegisterReservations(); Register(); } } private void Update() { //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) //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_005e: 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) if (!_started || !Object.op_Implicit((Object)(object)_view) || !_view.IsValid()) { return; } if (!_registered) { Register(); } else { Vector3 val = ((Component)this).transform.position - _position; if (((Vector3)(ref val)).sqrMagnitude > 0.0001f || Quaternion.Angle(((Component)this).transform.rotation, _rotation) > 0.05f) { Register(); } } if (Ready && _selectedRoute != ReadSelection()) { ApplySelection(); } if (_pending && Time.unscaledTime - _requestAt > 6f) { _pending = false; Tell("The switch request timed out. Stand beside the lever and try again."); } } private void Register() { //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_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)_view) || !_view.IsValid() || TrunkPoints.Length < 2 || LeftPoints.Length < 2 || RightPoints.Length < 2 || (ParallelExitCount != 0 && !IsParallelYard) || (IsParallelYard && StraightPoints.Length < 2) || (ParallelExitCount == 5 && (OuterLeftPoints.Length < 2 || OuterRightPoints.Length < 2))) { return; } string text = _view.GetZDO().GetString("vikingrail_identity", ""); if (text.Length == 0 && _view.IsOwner()) { text = Guid.NewGuid().ToString("N"); _view.GetZDO().Set("vikingrail_identity", text); } if (text.Length == 0) { return; } if (_registered && text != _identity) { Unregister(); } _identity = text; _stemId = text + ":stem"; _leftId = text + ":left"; _rightId = text + ":right"; _straightId = text + ":straight"; _outerLeftId = text + ":outerleft"; _outerRightId = text + ":outerright"; _markerId = text + ":closed"; _position = ((Component)this).transform.position; _rotation = ((Component)this).transform.rotation; _paths.Clear(); _paths.Add(WorldPath(TrunkPoints)); _paths.Add(WorldPath(LeftPoints)); _paths.Add(WorldPath(RightPoints)); if (IsThreeWay) { _paths.Add(WorldPath(StraightPoints)); } if (ParallelExitCount == 5) { _paths.Add(WorldPath(OuterLeftPoints)); _paths.Add(WorldPath(OuterRightPoints)); } RailSegment.Network.Upsert(_stemId, _paths[0]); RailSegment.Network.Upsert(_leftId, _paths[1]); RailSegment.Network.Upsert(_rightId, _paths[2]); if (IsThreeWay) { RailSegment.Network.Upsert(_straightId, _paths[3]); } if (ParallelExitCount == 5) { RailSegment.Network.Upsert(_outerLeftId, _paths[4]); RailSegment.Network.Upsert(_outerRightId, _paths[5]); } foreach (string item in PathIds()) { if (LightDuty) { RailSegment.LightTrackIds.Add(item); } else { RailSegment.LightTrackIds.Remove(item); } } _registered = true; ApplySelection(); } private RailPath WorldPath(Vector3[] points) { //IL_0017: 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) RailVector[] array = new RailVector[points.Length]; for (int i = 0; i < points.Length; i++) { array[i] = RailSegment.ToRail(((Component)this).transform.TransformPoint(points[i])); } return new RailPath(array); } private void ApplySelection() { //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) _selectedRoute = ReadSelection(); ClearClosedMarkers(); if (IsParallelYard) { string[] array = ((ParallelExitCount != 5) ? new string[3] { _leftId, _straightId, _rightId } : new string[5] { _outerLeftId, _leftId, _straightId, _rightId, _outerRightId }); int[] array2 = ((ParallelExitCount != 5) ? new int[3] { 1, 3, 2 } : new int[5] { 4, 1, 3, 2, 5 }); RailSegment.Network.SetParallelYardSwitch(_stemId, array, _selectedRoute); for (int i = 0; i < array.Length; i++) { if (i != _selectedRoute) { MarkClosed(_markerId + ":route" + i, array[i], _paths[array2[i]]); } } } else if (IsThreeWay) { RailSegment.Network.SetThreeWaySwitch(_stemId, _leftId, _straightId, _rightId, _selectedRoute); if (_selectedRoute != 0) { MarkClosed(_markerId + ":left", _leftId, _paths[1]); } if (_selectedRoute != 1) { MarkClosed(_markerId + ":straight", _straightId, _paths[3]); } if (_selectedRoute != 2) { MarkClosed(_markerId + ":right", _rightId, _paths[2]); } } else { bool flag = _selectedRoute == 1; RailSegment.Network.SetSwitch(_stemId, _leftId, _rightId, flag); MarkClosed(_markerId, flag ? _leftId : _rightId, _paths[flag ? 1 : 2]); } if (Object.op_Implicit((Object)(object)Lever)) { bool flag2 = IsBypassConnection && RightPoints[RightPoints.Length - 1].x < LeftPoints[LeftPoints.Length - 1].x; float num = (IsParallelYard ? ((1f - 2f * (float)_selectedRoute / (float)(RouteCount - 1)) * 35f) : (IsThreeWay ? ((float)(1 - _selectedRoute) * 35f) : (((_selectedRoute == 1) ? (-35f) : 35f) * (flag2 ? (-1f) : 1f)))); Lever.localRotation = _leverRest * Quaternion.Euler(0f, 0f, num); } } private int ReadSelection() { if (!IsParallelYard) { if (!IsThreeWay) { return _view.GetZDO().GetBool("vikingrail_switch_right", false) ? 1 : 0; } return Mathf.Clamp(_view.GetZDO().GetInt("vikingrail_switch_route3", 1), 0, 2); } return Mathf.Clamp(_view.GetZDO().GetInt("vikingrail_switch_yard_route", RouteCount / 2), 0, RouteCount - 1); } private IEnumerable PathIds() { yield return _stemId; yield return _leftId; yield return _rightId; if (IsThreeWay) { yield return _straightId; } if (ParallelExitCount == 5) { yield return _outerLeftId; yield return _outerRightId; } } internal IEnumerable LocalPaths() { yield return TrunkPoints; yield return LeftPoints; yield return RightPoints; if (IsThreeWay) { yield return StraightPoints; } if (ParallelExitCount == 5) { yield return OuterLeftPoints; yield return OuterRightPoints; } } internal IEnumerable StablePathIds(string identity) { yield return identity + ":stem"; yield return identity + ":left"; yield return identity + ":right"; if (IsThreeWay) { yield return identity + ":straight"; } if (ParallelExitCount == 5) { yield return identity + ":outerleft"; yield return identity + ":outerright"; } } internal Vector3[]? SnapPath(string name) { switch (name) { case "snap_start": return TrunkPoints; case "snap_left": return LeftPoints; case "snap_right": return RightPoints; case "snap_straight": if (IsThreeWay) { return StraightPoints; } break; } if (name == "snap_outer_left" && ParallelExitCount == 5) { return OuterLeftPoints; } if (name == "snap_outer_right" && ParallelExitCount == 5) { return OuterRightPoints; } return null; } private void MarkClosed(string marker, string pathId, RailPath path) { RailSegment.SetStopMarker(new RailStopMarker(marker, new RailCursor(pathId, Math.Min(1.6, path.Length), -1), isBumper: true)); ClosedMarkers.Add(marker); } private void ClearClosedMarkers() { string[] array = new string[4] { _markerId, _markerId + ":left", _markerId + ":straight", _markerId + ":right" }; foreach (string text in array) { RailSegment.RemoveStopMarker(text); ClosedMarkers.Remove(text); } for (int j = 0; j < 5; j++) { string text2 = _markerId + ":route" + j; RailSegment.RemoveStopMarker(text2); ClosedMarkers.Remove(text2); } } private void Unregister() { if (!_registered) { return; } foreach (string item in PathIds()) { RailSegment.Network.Remove(item); RailSegment.LightTrackIds.Remove(item); } ClearClosedMarkers(); _paths.Clear(); _registered = false; } private void OnDestroy() { ReleaseLocalRoute(); Unregister(); Switches.Remove(this); _started = false; } public float GetHoverOffset() { return 0f; } private string RouteName(int route) { if (!IsParallelYard) { if (!IsThreeWay) { if (!IsBypassConnection) { if (route != 1) { return "left"; } return "right"; } if (route != 1) { return "main line"; } return "bypass"; } return route switch { 1 => "straight", 0 => "left", _ => "right", }; } return "yard line " + (route + 1) + ((route == RouteCount / 2) ? " (straight)" : ""); } public string GetHoverName() { if (!IsParallelYard) { if (!IsThreeWay) { if (!IsBypassConnection) { if (!LightDuty) { return "Railway switch"; } return "Wooden railway switch"; } if (!LightDuty) { return "Rail bypass switch"; } return "Wooden bypass switch"; } if (!LightDuty) { return "Three-way yard switch"; } return "Wooden three-way yard switch"; } return (LightDuty ? "Wooden " : "") + RouteCount + "-way parallel yard splitter"; } public string GetHoverText() { return Localization.instance.Localize(GetHoverName() + "\nRoute: " + RouteName(_selectedRoute) + "\n[$KEY_Use] Select " + RouteName(NextRoute) + (IsOccupied ? "\nClear the junction and its approaches before switching." : "")); } public bool UseItem(Humanoid user, ItemData item) { return ((Component)this).GetComponent()?.UseItem(user, item) ?? false; } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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_0098: Unknown result type (might be due to invalid IL or missing references) if (hold || alt || !Ready || _pending) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val != (Object)(object)Player.m_localPlayer || ((Character)val).IsDead() || ((Character)val).IsTeleporting()) { return false; } if (((Character)val).IsAttached() || val.GetDoodadController() != null) { Tell("Dismount before operating the railway switch."); return false; } if (!(Vector3.Distance(((Component)val).transform.position, LeverPosition) <= 4f) || !PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false) || !PrivateArea.CheckAccess(LeverPosition, 0f, true, false)) { return false; } if (IsOccupied) { Tell("Clear every cart from the junction and its approaches before switching."); return false; } if (!_view.HasOwner()) { Tell("Waiting for the switch's network owner. Try again shortly."); return false; } _pending = true; _requestAt = Time.unscaledTime; _requestOwner = _view.GetZDO().GetOwner(); _requestPlayer = val.GetPlayerID(); if (IsParallelYard) { _view.InvokeRPC("VR_SwitchSelectYard_v1", new object[2] { _requestPlayer, NextRoute }); } else if (IsThreeWay) { _view.InvokeRPC("VR_SwitchSelect3_v1", new object[2] { _requestPlayer, NextRoute }); } else { _view.InvokeRPC("VR_SwitchToggle", new object[2] { _requestPlayer, NextRoute == 1 }); } return true; } private void RequestToggle(long sender, long playerId, bool selectRight) { if (!IsThreeWay && !IsParallelYard) { RequestSelection(sender, playerId, selectRight ? 1 : 0); } } private void RequestThreeWaySelection(long sender, long playerId, int route) { if (IsThreeWay && !IsParallelYard && route >= 0 && route <= 2) { RequestSelection(sender, playerId, route); } } private void RequestYardSelection(long sender, long playerId, int route) { if (IsParallelYard && route >= 0 && route < RouteCount) { RequestSelection(sender, playerId, route); } } private void RequestSelection(long sender, long playerId, int route) { //IL_0051: 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_008b: 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_013f: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !_view.IsOwner() || route < 0 || route >= RouteCount) { return; } Player player = Player.GetPlayer(playerId); if (!Object.op_Implicit((Object)(object)player) || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || ((Character)player).GetOwner() != sender || !(Vector3.Distance(((Component)player).transform.position, LeverPosition) <= 4f) || ((Character)player).IsAttached() || player.GetDoodadController() != null) { Reply(sender, "Stand beside the lever and dismount before changing the railway switch."); return; } if (!CanAccessWard(((Component)this).transform.position, playerId) || !CanAccessWard(LeverPosition, playerId)) { Reply(sender, "You do not have access to this protected railway switch."); return; } if (IsOccupied) { Reply(sender, "Clear every cart from the junction and its approaches before switching."); return; } if (IsParallelYard) { _view.GetZDO().Set("vikingrail_switch_yard_route", route); } else if (IsThreeWay) { _view.GetZDO().Set("vikingrail_switch_route3", route); } else { _view.GetZDO().Set("vikingrail_switch_right", route == 1); } ApplySelection(); if (ZDOMan.instance != null) { ZDOMan.instance.ForceSendZDO(sender, _view.GetZDO().m_uid); } Reply(sender, "Railway switch set to " + RouteName(route) + "."); } private void Reply(long peer, string message) { _view.InvokeRPC(peer, "VR_SwitchReply", new object[1] { message }); } private void ReceiveReply(long sender, string message) { if (_pending && sender == _requestOwner) { _pending = false; if (Object.op_Implicit((Object)(object)Player.m_localPlayer) && Player.m_localPlayer.GetPlayerID() == _requestPlayer) { Tell(message); } } } private static bool CanAccessWard(Vector3 point, long playerId) { //IL_0097: Unknown result type (might be due to invalid IL or missing references) if (WardList == null || WardEnabled == null || WardInside == null || WardPermitted == null) { return false; } if (!(WardList.GetValue(null) is IEnumerable enumerable)) { return false; } bool flag = false; foreach (PrivateArea item in enumerable) { if (Object.op_Implicit((Object)(object)item) && true.Equals(WardEnabled.Invoke(item, null)) && true.Equals(WardInside.Invoke(item, new object[2] { point, 0f }))) { Piece component = ((Component)item).GetComponent(); if ((Object.op_Implicit((Object)(object)component) && component.GetCreator() == playerId) || true.Equals(WardPermitted.Invoke(item, new object[1] { playerId }))) { return true; } flag = true; } } return !flag; } private static void Tell(string message) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false); } } private void RegisterReservations() { _view.Register("VR_SwitchReserve", (Action)RequestRoute); _view.Register("VR_SwitchReserve3_v1", (Action)RequestThreeWayRoute); _view.Register("VR_SwitchReserveYard_v1", (Action)RequestYardRoute); _view.Register("VR_SwitchRelease", (Action)ReleaseRoute); } internal static bool TryReserveTrainRoute(RailVehicle engine, IReadOnlyList train, out string reason) { reason = ""; bool result = true; foreach (RailSwitch @switch in Switches) { if (!Object.op_Implicit((Object)(object)@switch) || !@switch.Ready) { continue; } if (!@switch.NearTrain(train, 3.25f)) { if (@switch._localEngine == engine.PersistentId) { @switch.ReleaseLocalRoute(); } } else if (!@switch.ReserveLocalRoute(engine)) { result = false; reason = "Waiting for the railway switch to reserve this route."; } } return result; } internal static void ReleaseTrainRoute(RailVehicle engine) { if (!Object.op_Implicit((Object)(object)engine)) { return; } foreach (RailSwitch @switch in Switches) { if (Object.op_Implicit((Object)(object)@switch) && @switch._localEngine == engine.PersistentId) { @switch.ReleaseLocalRoute(); } } } private bool NearTrain(IReadOnlyList train, float clearance) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) foreach (RailVehicle item in train) { if (Object.op_Implicit((Object)(object)item) && item.IsReady) { RailVector position = RailSegment.ToRail(((Component)item).transform.position); if (RailSwitchClearance.Contains(_paths, position, clearance)) { return true; } } } return false; } private bool ReserveLocalRoute(RailVehicle engine) { //IL_00fc: 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_014e: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)ZNet.instance) || !engine.IsReady || !engine.View.IsOwner() || !engine.HasDriveAuthority || !_view.HasOwner()) { return false; } long owner = engine.View.GetZDO().GetOwner(); if (_localEngine != engine.PersistentId || _localPeer != owner) { ReleaseLocalRoute(); _localEngine = engine.PersistentId; _localPeer = owner; _localToken = Guid.NewGuid().ToString("N"); _nextLeaseRequest = 0f; } if (_selectedRoute != ReadSelection()) { ApplySelection(); } if (Time.unscaledTime >= _nextLeaseRequest) { _nextLeaseRequest = Time.unscaledTime + 1f; if (IsParallelYard) { _view.InvokeRPC("VR_SwitchReserveYard_v1", new object[3] { engine.View.GetZDO().m_uid, _localToken, _selectedRoute }); } else if (IsThreeWay) { _view.InvokeRPC("VR_SwitchReserve3_v1", new object[3] { engine.View.GetZDO().m_uid, _localToken, _selectedRoute }); } else { _view.InvokeRPC("VR_SwitchReserve", new object[3] { engine.View.GetZDO().m_uid, _localToken, _selectedRoute == 1 }); } } return Reservation.CanDrive(_localEngine, _localPeer, _localToken, _selectedRoute, RouteCount, Now); } private void RequestRoute(long sender, ZDOID engineId, string token, bool selectRight) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (!IsThreeWay && !IsParallelYard) { RequestSelectedRoute(sender, engineId, token, selectRight ? 1 : 0); } } private void RequestThreeWayRoute(long sender, ZDOID engineId, string token, int selectedRoute) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (IsThreeWay && !IsParallelYard && selectedRoute >= 0 && selectedRoute <= 2) { RequestSelectedRoute(sender, engineId, token, selectedRoute); } } private void RequestYardRoute(long sender, ZDOID engineId, string token, int selectedRoute) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (IsParallelYard && selectedRoute >= 0 && selectedRoute < RouteCount) { RequestSelectedRoute(sender, engineId, token, selectedRoute); } } private void RequestSelectedRoute(long sender, ZDOID engineId, string token, int selectedRoute) { //IL_00a9: 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_0175: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !_view.IsOwner() || string.IsNullOrEmpty(token) || token.Length > 64 || !Object.op_Implicit((Object)(object)ZNet.instance) || selectedRoute < 0 || selectedRoute >= RouteCount) { return; } if (_releasedTokens.TryGetValue(token, out var value)) { if (value > Now) { return; } _releasedTokens.Remove(token); } RailVehicle railVehicle = null; foreach (RailVehicle loadedVehicle in RailVehicle.LoadedVehicles) { if (Object.op_Implicit((Object)(object)loadedVehicle) && loadedVehicle.IsReady && loadedVehicle.CanControlRoute && loadedVehicle.View.GetZDO().m_uid == engineId) { railVehicle = loadedVehicle; break; } } if (!Object.op_Implicit((Object)(object)railVehicle) || railVehicle.View.GetZDO().GetOwner() != sender || !railVehicle.HasDriveAuthority) { return; } if (!railVehicle.AutoDriveActive) { Player player = Player.GetPlayer(railVehicle.ReservedDriver); if (railVehicle.ReservedDriver == 0L || !Object.op_Implicit((Object)(object)player) || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || ((Character)player).GetOwner() != sender) { return; } } bool flag = false; foreach (RailVehicle loadedVehicle2 in RailVehicle.LoadedVehicles) { if (Object.op_Implicit((Object)(object)loadedVehicle2) && loadedVehicle2.IsReady && loadedVehicle2.BelongsToTrain(railVehicle)) { RailVector position = RailSegment.ToRail(((Component)loadedVehicle2).transform.position); if (RailSwitchClearance.Contains(_paths, position, 6.0)) { flag = true; } if (flag) { break; } } } if (flag) { int num = ReadSelection(); SwitchRouteReservation reservation = Reservation; if (num == selectedRoute && reservation.CanReserve(railVehicle.PersistentId, sender, token, selectedRoute, RouteCount, Now)) { WriteReservation(new SwitchRouteReservation(railVehicle.PersistentId, sender, token, selectedRoute, Now + 6000)); } if (ZDOMan.instance != null) { ZDOMan.instance.ForceSendZDO(sender, _view.GetZDO().m_uid); } } } private void ReleaseLocalRoute() { if (_localToken.Length != 0 && Object.op_Implicit((Object)(object)_view) && _view.IsValid() && _view.HasOwner()) { _view.InvokeRPC("VR_SwitchRelease", new object[2] { _localEngine, _localToken }); } _localEngine = ""; _localToken = ""; _localPeer = 0L; _nextLeaseRequest = 0f; } private void ReleaseRoute(long sender, string engineIdentity, string token) { if (!Ready || !_view.IsOwner() || string.IsNullOrEmpty(token) || token.Length > 64) { return; } bool flag = Reservation.Matches(engineIdentity, sender, token); if (!flag) { bool flag2 = false; foreach (RailVehicle loadedVehicle in RailVehicle.LoadedVehicles) { if (Object.op_Implicit((Object)(object)loadedVehicle) && loadedVehicle.IsReady && (loadedVehicle.IsEngine || loadedVehicle.CanHandPush) && loadedVehicle.PersistentId == engineIdentity && loadedVehicle.View.GetZDO().GetOwner() == sender) { flag2 = true; break; } } if (!flag2) { return; } } _releasedTokens[token] = Now + 12000; if (flag) { WriteReservation(default(SwitchRouteReservation)); } if (_releasedTokens.Count <= 32) { return; } List list = new List(); foreach (KeyValuePair releasedToken in _releasedTokens) { if (releasedToken.Value <= Now) { list.Add(releasedToken.Key); } } foreach (string item in list) { _releasedTokens.Remove(item); } } private void WriteReservation(SwitchRouteReservation reservation) { ZDO zDO = _view.GetZDO(); zDO.Set("vikingrail_switch_engine", reservation.Engine ?? ""); zDO.Set("vikingrail_switch_peer", reservation.Peer); zDO.Set("vikingrail_switch_token", reservation.Token ?? ""); if (IsParallelYard) { zDO.Set("vikingrail_switch_lease_yard_route", reservation.SelectedRoute); } else if (IsThreeWay) { zDO.Set("vikingrail_switch_lease_route3", reservation.SelectedRoute); } else { zDO.Set("vikingrail_switch_lease_right", reservation.SelectRight); } zDO.Set("vikingrail_switch_until", reservation.ExpiresAt); } } public sealed class RailSwitchLever : MonoBehaviour, Hoverable, Interactable { public RailSwitch Switch; public float GetHoverOffset() { return 0f; } public string GetHoverName() { if (!Object.op_Implicit((Object)(object)Switch)) { return "Railway switch"; } return Switch.GetHoverName(); } public string GetHoverText() { if (!Object.op_Implicit((Object)(object)Switch)) { return ""; } return Switch.GetHoverText(); } public bool Interact(Humanoid user, bool hold, bool alt) { if (Object.op_Implicit((Object)(object)Switch)) { return Switch.Interact(user, hold, alt); } return false; } public bool UseItem(Humanoid user, ItemData item) { if (Object.op_Implicit((Object)(object)Switch)) { return Switch.UseItem(user, item); } return false; } } public sealed class RailTerrainMaintenance : MonoBehaviour { private static readonly List Tracks = new List(); private static ZNetScene? _scene; private static ZDOMan? _manager; private static int _nextTrack; private static int _generation; private static float _nextTick; private static float _nextPlan; private static bool _enabled; private static bool _warned; private RailTerrainPlacement? _terrain; private ZNetView? _view; private Piece? _piece; private RailTerrainPlacement.GravelPlan? _plan; private RailTerrainBed? _bed; private Matrix4x4 _matrix; private Vector3[]? _corners; private int _preparedGeneration = -1; private int _index; private int _attempts; private ushort _ownerRevision; private bool _complete; private bool _wasOwner; private float _retryAfter; internal static void Configure(GameObject prefab) { if (!Object.op_Implicit((Object)(object)prefab.GetComponent())) { prefab.AddComponent(); } } private void Awake() { OnEnable(); } private void OnEnable() { _terrain = ((Component)this).GetComponent(); _view = ((Component)this).GetComponent(); _piece = ((Component)this).GetComponent(); if (!Tracks.Contains(this)) { Tracks.Add(this); } _preparedGeneration = -1; } private void OnDisable() { Tracks.Remove(this); _plan = null; _bed = null; } private void OnDestroy() { OnDisable(); } internal static void Reset() { Tracks.Clear(); _scene = null; _manager = null; _nextTrack = 0; _nextTick = (_nextPlan = 0f); _generation++; _enabled = (_warned = false); } internal static void UpdateWorld() { if (_scene != ZNetScene.instance || _manager != ZDOMan.instance) { _scene = ZNetScene.instance; _manager = ZDOMan.instance; _generation++; _nextTick = (_nextPlan = 0f); } bool flag = Object.op_Implicit((Object)(object)_scene) && _manager != null && RailSettings.Ready && RailSettings.DirtTrackbedOnPlacement; if (flag != _enabled) { _enabled = flag; _generation++; } if (!flag || Time.unscaledTime < _nextTick) { return; } _nextTick = Time.unscaledTime + 0.1f; int writes = 2; int samples = 32; int num = Math.Min(Tracks.Count, 16); while (num-- > 0 && writes > 0 && samples > 0 && Tracks.Count > 0) { if (_nextTrack >= Tracks.Count) { _nextTrack = 0; } RailTerrainMaintenance railTerrainMaintenance = Tracks[_nextTrack++]; if (!Object.op_Implicit((Object)(object)railTerrainMaintenance)) { continue; } try { railTerrainMaintenance.Advance(ref samples, ref writes); } catch (Exception ex) { railTerrainMaintenance._plan = null; railTerrainMaintenance._bed = null; railTerrainMaintenance._retryAfter = Time.unscaledTime + 30f; if (!_warned) { _warned = true; RailPlugin.Warn("Rail gravel painting skipped unavailable terrain: " + ex.GetBaseException().Message); } } } } private bool Authorized() { //IL_009a: Unknown result type (might be due to invalid IL or missing references) if (_scene != ZNetScene.instance || _manager != ZDOMan.instance || !((Behaviour)this).isActiveAndEnabled || !Object.op_Implicit((Object)(object)_terrain) || _terrain.PreserveTerrain || !Object.op_Implicit((Object)(object)_view) || !_view.IsValid() || !_view.IsOwner() || !Object.op_Implicit((Object)(object)_piece) || !RailSettings.Ready || !RailSettings.DirtTrackbedOnPlacement || _manager == null) { return false; } ZDO zDO = _view.GetZDO(); if (zDO != null && _manager.GetZDO(zDO.m_uid) == zDO) { return _piece.GetCreator() != 0; } return false; } private void Advance(ref int samples, ref int writes) { //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_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_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_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) if (!Authorized()) { _wasOwner = false; _plan = null; return; } Matrix4x4 localToWorldMatrix = ((Component)this).transform.localToWorldMatrix; ushort ownerRevision = _view.GetZDO().OwnerRevision; if (!_wasOwner || _ownerRevision != ownerRevision || _preparedGeneration != _generation || _matrix != localToWorldMatrix || _corners != _terrain.BedCorners) { _wasOwner = true; _ownerRevision = ownerRevision; _preparedGeneration = _generation; _matrix = localToWorldMatrix; _corners = _terrain.BedCorners; _plan = null; _bed = null; _complete = false; _attempts = 0; _retryAfter = 0f; } if (_complete || Time.unscaledTime < _retryAfter) { return; } if (_plan == null) { if (Time.unscaledTime < _nextPlan) { return; } _nextPlan = Time.unscaledTime + 1f; RailTerrainPlacement.GravelPlan gravelPlan = _terrain.BuildPlan(_piece.GetCreator()); if (gravelPlan.Skipped || gravelPlan.Error.Length != 0) { _retryAfter = Time.unscaledTime + 30f; return; } if (gravelPlan.Paints.Count == 0 || _attempts >= 3) { _complete = true; return; } _attempts++; _plan = gravelPlan; _bed = _terrain.BuildGravelBed(); _index = 0; } int num = Math.Min(samples, 8); while (_index < _plan.Paints.Count && num-- > 0 && writes > 0) { samples--; RailTerrainPlacement.GravelPaint gravelPaint = _plan.Paints[_index]; if (!Object.op_Implicit((Object)(object)gravelPaint.Map)) { _plan = null; _attempts = Math.Max(0, _attempts - 1); _retryAfter = Time.unscaledTime + 5f; return; } if (gravelPaint.Map.HaveQueuedRebuild()) { _retryAfter = Time.unscaledTime + 0.25f; return; } if (RailTerrainPaintTool.IsPainted(gravelPaint.Map, gravelPaint.Target)) { _index++; continue; } if (!_terrain.TryPaintTarget(_bed, gravelPaint.Map, gravelPaint.Target, _piece.GetCreator(), out Vector3 target, out string error)) { if (error.Length != 0) { _retryAfter = Time.unscaledTime + 5f; return; } _index++; continue; } if (!Authorized()) { _plan = null; return; } if (!RailTerrainPaintTool.Apply(gravelPaint.Map, target)) { _retryAfter = Time.unscaledTime + 30f; return; } writes--; _index++; } if (_index == _plan.Paints.Count) { _plan = null; _bed = null; _retryAfter = Time.unscaledTime + 5f; } } } internal static class RailTerrainPaintTool { internal const string PrefabName = "vr_rail_dirt_trackbed"; private const float OperationRadius = 0.1f; private const BindingFlags Fields = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; private static readonly FieldInfo? TerrainOperations = typeof(ObjectDB).GetField("m_terrainOps", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly FieldInfo? TerrainOperationHashes = typeof(ObjectDB).GetField("m_terrainOpsByHash", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static readonly MethodInfo? PaintCleared = typeof(TerrainComp).GetMethod("PaintCleared", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[3] { typeof(Vector3), typeof(Vector3), typeof(Settings) }, null); private static readonly HashSet Databases = new HashSet(); private static readonly HashSet VerifiedDatabases = new HashSet(); private static readonly HashSet VerifiedScales = new HashSet(); private static readonly int PrefabHash = StringExtensionMethods.GetStableHashCode("vr_rail_dirt_trackbed"); private static TerrainOp? operation; private static bool compatible = true; private static bool reportedUnavailable; internal static bool Compatible => compatible; internal static bool Available { get { if (!compatible || !Object.op_Implicit((Object)(object)operation) || ((Component)operation).gameObject.activeInHierarchy || !Object.op_Implicit((Object)(object)ObjectDB.instance) || VerifiedScales.Count == 0 || !VerifiedDatabases.Contains(ObjectDB.instance)) { return false; } if (TerrainOperationHashes?.GetValue(ObjectDB.instance) is Dictionary dictionary && dictionary.TryGetValue(PrefabHash, out var value) && (Object)(object)value == (Object)(object)operation) { return StonePaintOnly(operation.m_settings); } return false; } } internal static void Initialize(Transform inactivePrefabRoot) { //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Expected O, but got Unknown //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016e: 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_0180: 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_0192: 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_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01af: 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_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: 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_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Expected O, but got Unknown if (!compatible || Object.op_Implicit((Object)(object)operation)) { return; } GameObject val = null; try { if (!Object.op_Implicit((Object)(object)inactivePrefabRoot) || ((Component)inactivePrefabRoot).gameObject.activeInHierarchy) { throw new InvalidOperationException("Rail paint operations require an inactive prefab root."); } if (TerrainOperations?.FieldType != typeof(List) || TerrainOperationHashes?.FieldType != typeof(Dictionary) || PaintCleared == null) { throw new MissingMemberException("The native Valheim terrain-paint API is unavailable."); } MethodInfo method = typeof(Settings).GetMethod("Serialize", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2] { typeof(ZPackage), typeof(GameObject) }, null); MethodInfo method2 = typeof(Settings).GetMethod("Deserialize", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(ZPackage) }, null); if (method == null || method2?.ReturnType != typeof(Settings)) { throw new MissingMethodException("The native Valheim 1.0 terrain-operation format is unavailable."); } val = new GameObject("vr_rail_dirt_trackbed"); val.SetActive(false); val.transform.SetParent(inactivePrefabRoot, false); operation = val.AddComponent(); operation.m_settings = new Settings { m_levelOffset = 0f, m_level = false, m_levelRadius = 0f, m_square = false, m_raise = false, m_raiseRadius = 0f, m_raisePower = 0f, m_raiseDelta = 0f, m_smooth = false, m_smoothRadius = 0f, m_smoothPower = 0f, m_paintCleared = true, m_paintHeightCheck = false, m_paintType = (PaintType)2, m_paintRadius = 0.1f, m_paintStrength = 1f, m_paintExp = 1f, m_paintCurve = AnimationCurve.Linear(0f, 0f, 1f, 1f), m_rotation = false, m_sides = false, m_addMedianMax = 0f, m_centerMultiplicationFactor = 0f, m_pointMultiplicationFactor = 0f, m_halfOffset = false }; operation.m_spawnOnPlaced = null; if (!Probe(1f, out string reason)) { operation.m_settings.m_paintCurve = AnimationCurve.Linear(0f, 1f, 1f, 0f); if (!Probe(1f, out string reason2)) { throw new InvalidOperationException("Native stone-paint compatibility check failed. Forward curve: " + reason + " Reverse curve: " + reason2); } } VerifiedScales.Add(1f); RailPlugin.LogInfo("Native rail stone brush verified: one changed blue paint pixel, bounded paint bookkeeping, unchanged terrain heights."); } catch (Exception error) { operation = null; if (Object.op_Implicit((Object)(object)val)) { Object.DestroyImmediate((Object)(object)val); } Disable(error); } } internal static void Register(ObjectDB db) { //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Expected O, but got Unknown if (!compatible || !Object.op_Implicit((Object)(object)operation) || !Object.op_Implicit((Object)(object)db)) { return; } try { List list = TerrainOperations?.GetValue(db) as List; Dictionary dictionary = TerrainOperationHashes?.GetValue(db) as Dictionary; if (list == null || dictionary == null) { return; } if (dictionary.TryGetValue(PrefabHash, out var value) && (Object)(object)value != (Object)(object)operation) { throw new InvalidOperationException("A different terrain operation uses the Viking Rail trackbed prefab name."); } foreach (TerrainOp item in list) { if (Object.op_Implicit((Object)(object)item) && (Object)(object)item != (Object)(object)operation && StringExtensionMethods.GetStableHashCode(Utils.GetPrefabName(((Object)((Component)item).gameObject).name)) == PrefabHash) { throw new InvalidOperationException("A different terrain operation uses the Viking Rail trackbed prefab name."); } } Databases.Add(db); if (!list.Contains(operation)) { list.Add(operation); } dictionary[PrefabHash] = operation; if ((Object)(object)db == (Object)(object)ObjectDB.instance && !VerifiedDatabases.Contains(db)) { ZPackage val = new ZPackage(); operation.m_settings.Serialize(val, ((Component)operation).gameObject); val.SetPos(0); Settings val2 = Settings.Deserialize(val); if (val2 != operation.m_settings || !StonePaintOnly(val2)) { throw new InvalidOperationException("The serialized rail operation did not resolve to its registered stone-only settings."); } if (!Probe(1f, out string reason, val2)) { throw new InvalidOperationException("The serialized native stone brush failed its isolated paint check: " + reason); } VerifiedDatabases.Add(db); } } catch (Exception error) { Disable(error); } } internal static int PixelCount(Heightmap map) { if (!Object.op_Implicit((Object)(object)map) || !compatible || !Object.op_Implicit((Object)(object)operation)) { return 0; } try { if (map.m_width <= 0 || map.m_width > 256) { ReportUnavailable("Unsupported terrain width: " + map.m_width + "."); return 0; } if (!VerifyScale(map.m_scale)) { return 0; } Texture2D paintMask = map.GetPaintMask(); if (!Object.op_Implicit((Object)(object)paintMask)) { ReportUnavailable("The terrain paint texture has not initialized yet; it can be retried after terrain loads."); return 0; } int num = map.m_width + 1; if (((Texture)paintMask).width != num || ((Texture)paintMask).height != num) { ReportUnavailable("Terrain paint grid mismatch: expected " + num + " x " + num + ", received " + ((Texture)paintMask).width + " x " + ((Texture)paintMask).height + "."); return 0; } return num; } catch (Exception error) { Disable(error); return 0; } } internal static Vector3 PixelCenter(Heightmap map, int x, int z) { //IL_0038: 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_006b: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)map) || x < 0 || z < 0 || x > map.m_width || z > map.m_width) { throw new ArgumentOutOfRangeException("x", "The paint pixel is outside its heightmap."); } return ((Component)map).transform.position + new Vector3((float)(x - map.m_width / 2) * map.m_scale, 0f, (float)(z - map.m_width / 2) * map.m_scale); } internal static float ProtectionRadius(Heightmap map) { return map.m_scale * 2.121321f; } internal static bool IsPainted(Heightmap map, Vector3 pixelCenter) { //IL_0008: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_00a9: 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_00c3: 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_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0104: 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) //IL_0125: 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) if (!Object.op_Implicit((Object)(object)map) || !Finite(pixelCenter) || map.m_width <= 0 || map.m_width > 256 || !Finite(map.m_scale) || map.m_scale <= 0f) { return false; } try { Texture2D paintMask = map.GetPaintMask(); int num = map.m_width + 1; if (!Object.op_Implicit((Object)(object)paintMask) || ((Texture)paintMask).width != num || ((Texture)paintMask).height != num) { return false; } int num2 = default(int); int num3 = default(int); map.WorldToVertexMask(pixelCenter, ref num2, ref num3); if (num2 < 0 || num3 < 0 || num2 >= num || num3 >= num) { return false; } Vector3 val = PixelCenter(map, num2, num3); if (Mathf.Abs(val.x - pixelCenter.x) > 0.001f || Mathf.Abs(val.z - pixelCenter.z) > 0.001f) { return false; } Color pixel = paintMask.GetPixel(num2, num3); return Finite(pixel.r) && Finite(pixel.g) && Finite(pixel.b) && Mathf.Abs(pixel.r) <= 0.01f && Mathf.Abs(pixel.g) <= 0.01f && Mathf.Abs(pixel.b - 1f) <= 0.01f; } catch { return false; } } internal static bool Apply(Heightmap map, Vector3 pixelCenter) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_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_0076: 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_008f: 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_00b7: 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) if (!Object.op_Implicit((Object)(object)map) || !Finite(pixelCenter) || PixelCount(map) == 0) { return false; } try { Register(ObjectDB.instance); if (!Available || !Object.op_Implicit((Object)(object)operation)) { return false; } int num = default(int); int num2 = default(int); map.WorldToVertexMask(pixelCenter, ref num, ref num2); if (num < 0 || num2 < 0 || num > map.m_width || num2 > map.m_width) { return false; } Vector3 val = PixelCenter(map, num, num2); if (Mathf.Abs(val.x - pixelCenter.x) > 0.001f || Mathf.Abs(val.z - pixelCenter.z) > 0.001f) { return false; } ((Component)operation).transform.position = pixelCenter; ((Component)operation).transform.rotation = Quaternion.identity; TerrainComp andCreateTerrainCompiler = map.GetAndCreateTerrainCompiler(); if (!Object.op_Implicit((Object)(object)andCreateTerrainCompiler)) { return false; } andCreateTerrainCompiler.ApplyOperation(operation); return true; } catch (Exception error) { Disable(error); return false; } } private static bool VerifyScale(float scale) { if (!compatible || !Object.op_Implicit((Object)(object)operation)) { return false; } if (!Finite(scale) || scale <= 0.2f || scale > 16f) { ReportUnavailable("Unsupported terrain paint scale: " + scale + "."); return false; } if (VerifiedScales.Contains(scale)) { return true; } try { if (!Probe(scale, out string reason)) { throw new InvalidOperationException("Native stone painting uses an unsupported terrain grid at scale " + scale + ": " + reason); } VerifiedScales.Add(scale); return true; } catch (Exception error) { Disable(error); return false; } } private static bool StonePaintOnly(Settings settings) { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Invalid comparison between Unknown and I4 if (settings != null && !settings.m_level && !settings.m_raise && !settings.m_smooth && settings.m_levelOffset == 0f && settings.m_levelRadius == 0f && settings.m_raiseRadius == 0f && settings.m_raisePower == 0f && settings.m_raiseDelta == 0f && settings.m_smoothRadius == 0f && settings.m_smoothPower == 0f && settings.m_paintCleared && !settings.m_paintHeightCheck && (int)settings.m_paintType == 2 && settings.m_paintRadius == 0.1f && settings.m_paintStrength == 1f && settings.m_paintExp == 1f && !settings.m_rotation && !settings.m_sides && settings.m_addMedianMax == 0f && settings.m_centerMultiplicationFactor == 0f && settings.m_pointMultiplicationFactor == 0f) { return !settings.m_halfOffset; } return false; } private static bool Probe(float scale, out string reason, Settings? settings = null) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Expected O, but got Unknown //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_020d: 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_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_030d: Unknown result type (might be due to invalid IL or missing references) reason = "Native paint operation or method is unavailable."; if (!Object.op_Implicit((Object)(object)operation) || PaintCleared == null) { return false; } if (settings == null) { settings = operation.m_settings; } if (!StonePaintOnly(settings)) { reason = "The rail operation is not the fixed stone-only brush."; return false; } GameObject val = null; Texture2D val2 = null; try { val = new GameObject("VikingRail isolated paint compatibility check"); val.SetActive(false); Heightmap val3 = val.AddComponent(); TerrainComp val4 = val.AddComponent(); SetField(val3, "m_width", 8); SetField(val3, "m_scale", scale); List field = GetField>(val3, "m_heights"); field.Clear(); for (int i = 0; i < 81; i++) { field.Add(7f); } float[] beforeHeights = field.ToArray(); val2 = new Texture2D(9, 9, (TextureFormat)4, false); ((Texture)val2).wrapMode = (TextureWrapMode)1; Color[] array = (Color[])(object)new Color[81]; for (int j = 0; j < 81; j++) { array[j] = new Color(0.6f, 0.3f, 0.1f, (float)(j % 3 + 1) * 0.25f); } val2.SetPixels(array); val2.Apply(); array = val2.GetPixels(); float[] beforeRgba = Flatten(array); SetField(val3, "m_paintMask", val2); SetField(val4, "m_hmap", val3); SetField(val4, "m_width", 8); SetField(val4, "m_pitch", 9); SetField(val4, "m_size", 8f * scale); SetField(val4, "m_initialized", true); bool[] array2 = new bool[81]; float[] array3 = new float[81]; float[] array4 = new float[81]; SetField(val4, "m_modifiedHeight", array2); SetField(val4, "m_levelDelta", array3); SetField(val4, "m_smoothDelta", array4); Vector2Int[] array5 = (Vector2Int[])(object)new Vector2Int[2] { new Vector2Int(3, 3), new Vector2Int(5, 4) }; int num = default(int); int num2 = default(int); for (int k = 0; k < array5.Length; k++) { Vector2Int val5 = array5[k]; Color[] array6 = (Color[])array.Clone(); bool[] array7 = new bool[81]; SetField(val4, "m_paintMask", array6); SetField(val4, "m_modifiedPaint", array7); Vector3 val6 = PixelCenter(val3, ((Vector2Int)(ref val5)).x, ((Vector2Int)(ref val5)).y); val3.WorldToVertexMask(val6, ref num, ref num2); if (num != ((Vector2Int)(ref val5)).x || num2 != ((Vector2Int)(ref val5)).y) { reason = "WorldToVertexMask mapped the probe point to " + num + "," + num2 + " instead of " + ((Vector2Int)(ref val5)).x + "," + ((Vector2Int)(ref val5)).y + "."; return false; } PaintCleared.Invoke(val4, new object[3] { val6, Vector3.zero, settings }); int targetIndex = ((Vector2Int)(ref val5)).y * 9 + ((Vector2Int)(ref val5)).x; if (!RailTerrainPaintProbe.Validate(beforeRgba, Flatten(array6), array7, 9, targetIndex, Mathf.CeilToInt(0.1f / scale), beforeHeights, field, array2, array3, array4, out reason)) { return false; } } reason = ""; return true; } catch (Exception ex) { Exception ex2 = ((ex is TargetInvocationException && ex.InnerException != null) ? ex.InnerException : ex); reason = ex2.GetType().Name + ": " + ex2.Message; return false; } finally { if (Object.op_Implicit((Object)(object)val)) { Object.DestroyImmediate((Object)(object)val); } if (Object.op_Implicit((Object)(object)val2)) { Object.DestroyImmediate((Object)(object)val2); } } } private static float[] Flatten(Color[] colors) { float[] array = new float[colors.Length * 4]; for (int i = 0; i < colors.Length; i++) { array[i * 4] = colors[i].r; array[i * 4 + 1] = colors[i].g; array[i * 4 + 2] = colors[i].b; array[i * 4 + 3] = colors[i].a; } return array; } private static void SetField(object instance, string name, object value) { FieldInfo? field = instance.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { throw new MissingFieldException(instance.GetType().Name, name); } field.SetValue(instance, value); } private static T GetField(object instance, string name) where T : class { return (instance.GetType().GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(instance) as T) ?? throw new MissingFieldException(instance.GetType().Name, name); } internal static void Cleanup() { foreach (ObjectDB database in Databases) { if (!Object.op_Implicit((Object)(object)database)) { continue; } try { List list = TerrainOperations?.GetValue(database) as List; Dictionary dictionary = TerrainOperationHashes?.GetValue(database) as Dictionary; if (Object.op_Implicit((Object)(object)operation)) { list?.RemoveAll((TerrainOp entry) => (Object)(object)entry == (Object)(object)operation); } if (dictionary != null && dictionary.TryGetValue(PrefabHash, out var value) && (Object)(object)value == (Object)(object)operation) { dictionary.Remove(PrefabHash); } } catch (Exception ex) { RailPlugin.Warn("Could not remove the rail stone operation from a closing ObjectDB: " + ex.Message); } } Databases.Clear(); VerifiedDatabases.Clear(); VerifiedScales.Clear(); if (Object.op_Implicit((Object)(object)operation)) { Object.DestroyImmediate((Object)(object)((Component)operation).gameObject); } operation = null; compatible = true; reportedUnavailable = false; } private static bool Finite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } private static bool Finite(Vector3 value) { //IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references) if (Finite(value.x) && Finite(value.y)) { return Finite(value.z); } return false; } private static void Disable(Exception error) { if (compatible) { compatible = false; ReportUnavailable(((error is TargetInvocationException && error.InnerException != null) ? error.InnerException : error).Message); } } private static void ReportUnavailable(string reason) { if (!reportedUnavailable) { reportedUnavailable = true; RailPlugin.Warn("Automatic rail stone painting is unavailable; rails can still be placed without painting. " + reason); } } } public sealed class RailTerrainPlacement : MonoBehaviour, IPlaced { internal sealed class GravelPlan { internal readonly List Paints = new List(); internal bool Skipped; internal string Error = ""; internal GravelPlan Fail(string error) { Paints.Clear(); Error = error; return this; } } internal readonly struct GravelPaint { internal readonly Heightmap Map; internal readonly Vector3 Target; internal GravelPaint(Heightmap map, Vector3 target) { //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) Map = map; Target = target; } } public Vector3[] BedCorners = Array.Empty(); public bool PreserveTerrain; private bool _placed; private GravelPlan? _preview; private Vector3 _previewPosition; private Quaternion _previewRotation; private float _previewUntil; private static bool _paintSkipNotified; internal static void Configure(GameObject prefab) { //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_00b4: 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_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_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_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_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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_0121: 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_012b: 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_0139: 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_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) List list = new List(); RailSegment component = prefab.GetComponent(); bool flag = Object.op_Implicit((Object)(object)component) && component.IsBridge; BoxCollider[] componentsInChildren = prefab.GetComponentsInChildren(true); foreach (BoxCollider val in componentsInChildren) { bool num; if (!flag) { if (!(((Object)val).name != "sleeper")) { goto IL_0077; } num = ((Object)val).name != "switch_sleeper"; } else { num = ((Object)val).name != "bridge_deck_plank"; } if (num) { continue; } goto IL_0077; IL_0077: float num2 = (flag ? 1f : (-1f)); Vector3[] array = (Vector3[])(object)new Vector3[4] { new Vector3(-1f, num2, -1f), new Vector3(1f, num2, -1f), new Vector3(1f, num2, 1f), new Vector3(-1f, num2, 1f) }; foreach (Vector3 val2 in array) { Vector3 val3 = ((Component)val).transform.TransformPoint(val.center + Vector3.Scale(val.size * 0.5f, val2)); list.Add(prefab.transform.InverseTransformPoint(val3) - Vector3.up * 0.005f); } } if (list.Count == 0) { throw new InvalidOperationException("Track has no measurable bed: " + ((Object)prefab).name); } RailTerrainPlacement railTerrainPlacement = prefab.AddComponent(); railTerrainPlacement.BedCorners = list.ToArray(); railTerrainPlacement.PreserveTerrain = flag; RailSpawnProtection.Configure(prefab); RailTerrainMaintenance.Configure(prefab); } public void OnPlaced() { //IL_00fb: 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) //IL_0161: Unknown result type (might be due to invalid IL or missing references) if (PreserveTerrain) { return; } ZNetView component = ((Component)this).GetComponent(); Player localPlayer = Player.m_localPlayer; if (_placed || !Object.op_Implicit((Object)(object)component) || !component.IsValid() || !component.IsOwner() || !Object.op_Implicit((Object)(object)localPlayer) || !RailSettings.Ready || !RailSettings.DirtTrackbedOnPlacement) { return; } _placed = true; try { GravelPlan gravelPlan = BuildPlan(0L); if (gravelPlan.Error.Length != 0) { Tell(localPlayer, gravelPlan.Error); return; } RailTerrainBed bed = ((gravelPlan.Paints.Count > 0) ? BuildGravelBed() : null); foreach (GravelPaint paint in gravelPlan.Paints) { if (!component.IsValid() || !component.IsOwner() || !RailSettings.Ready || !RailSettings.DirtTrackbedOnPlacement || !Object.op_Implicit((Object)(object)paint.Map) || paint.Map.HaveQueuedRebuild()) { return; } if (RailTerrainPaintTool.IsPainted(paint.Map, paint.Target)) { continue; } if (!TryPaintTarget(bed, paint.Map, paint.Target, 0L, out Vector3 target, out string error)) { if (error.Length != 0) { Tell(localPlayer, error); return; } continue; } if (!component.IsValid() || !component.IsOwner() || !RailSettings.Ready || !RailSettings.DirtTrackbedOnPlacement) { return; } if (!RailTerrainPaintTool.Apply(paint.Map, target)) { Tell(localPlayer, "Track placed. Its stone gravel could not finish; loaded-track painting will retry."); return; } } if (gravelPlan.Skipped && !_paintSkipNotified) { _paintSkipNotified = true; Tell(localPlayer, "Track placed. Automatic stone gravel is unavailable and was skipped; see LogOutput.log."); } } catch (Exception error2) { RailPlugin.Error(error2); Tell(localPlayer, "Track placed. Its stone gravel could not finish; check the log."); } } internal string PreviewError() { //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_009f: 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_003d: 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_0062: 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) if (!RailSettings.Ready) { return "Waiting for the host's railroad settings before placing track."; } if (!PreserveTerrain && !RailSettings.DirtTrackbedOnPlacement) { return ""; } if (_preview != null && !(Time.unscaledTime >= _previewUntil)) { Vector3 val = ((Component)this).transform.position - _previewPosition; if (!(((Vector3)(ref val)).sqrMagnitude > 1E-05f) && !(Quaternion.Angle(((Component)this).transform.rotation, _previewRotation) > 0.01f)) { goto IL_00ba; } } _preview = BuildPlan(0L); _previewPosition = ((Component)this).transform.position; _previewRotation = ((Component)this).transform.rotation; _previewUntil = Time.unscaledTime + 0.2f; goto IL_00ba; IL_00ba: return _preview.Error; } private string BridgePlacementError() { //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_002e: 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) for (int i = 0; i <= 24; i++) { for (int j = -1; j <= 1; j++) { Vector3 val = ((Component)this).transform.TransformPoint(new Vector3((float)j * 2.18f, 0f, (float)i - 12f)); if (Location.IsInsideNoBuildLocation(val)) { return "The bridge crosses a no-build area."; } if (!PrivateArea.CheckAccess(val, 1f, false, false)) { return "You do not have permission to build across the whole bridge span."; } } } return ""; } private string TurntablePlacementError() { //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_00d1: 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_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_0084: 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_0095: Unknown result type (might be due to invalid IL or missing references) RailTurntable component = ((Component)this).GetComponent(); if (Vector3.Dot(((Component)this).transform.up, Vector3.up) < 0.999f) { return "Place the turntable level."; } float num = (float)VikingRail.Core.RailTurntable.DeckRadius(component.Length) + 0.85f; int num2 = Mathf.CeilToInt(num); for (int i = -num2; i <= num2; i++) { for (int j = -num2; j <= num2; j++) { if (!((float)(j * j + i * i) > (num + 0.75f) * (num + 0.75f))) { Vector3 val = ((Component)this).transform.TransformPoint(new Vector3((float)j, 0f, (float)i)); if (Location.IsInsideNoBuildLocation(val)) { return "The turntable crosses a no-build area."; } if (!PrivateArea.CheckAccess(val, 1f, false, false)) { return "You need access to the whole turntable foundation."; } } } } if (Object.op_Implicit((Object)(object)component.Lever) && (Location.IsInsideNoBuildLocation(component.Lever.position) || !PrivateArea.CheckAccess(component.Lever.position, 1f, false, false))) { return "You need permission to build the turntable's operator platform."; } return ""; } internal RailTerrainBed BuildGravelBed() { //IL_005d: 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) if (BedCorners == null || BedCorners.Length == 0 || BedCorners.Length % 4 != 0 || BedCorners.Length > 1024) { throw new InvalidOperationException("The rail has no valid measured gravel footprint."); } List list = new List(); for (int i = 0; i < BedCorners.Length; i += 4) { RailVector[] array = new RailVector[4]; for (int j = 0; j < 4; j++) { array[j] = RailSegment.ToRail(((Component)this).transform.TransformPoint(BedCorners[i + j])); } list.Add(array); } return new RailTerrainBed(list, 2.0, 0.35); } internal GravelPlan BuildPlan(long creator = 0L) { //IL_00dc: 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_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_02cd: 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_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) GravelPlan gravelPlan = new GravelPlan(); if (PreserveTerrain) { string text = (Object.op_Implicit((Object)(object)((Component)this).GetComponent()) ? TurntablePlacementError() : BridgePlacementError()); if (text.Length != 0) { return gravelPlan.Fail(text); } return gravelPlan; } if (!RailSettings.Ready || !RailSettings.DirtTrackbedOnPlacement) { return gravelPlan; } RailTerrainPaintTool.Register(ObjectDB.instance); if (!RailTerrainPaintTool.Available) { gravelPlan.Skipped = true; return gravelPlan; } RailTerrainBed railTerrainBed = BuildGravelBed(); if (!GravelGroundLoaded()) { return gravelPlan.Fail("Wait for the ground around the entire rail gravel corridor to load."); } float num = (float)(railTerrainBed.MaxX - railTerrainBed.MinX); float num2 = (float)(railTerrainBed.MaxZ - railTerrainBed.MinZ); if (num > 100f || num2 > 100f) { return gravelPlan.Fail("The rail gravel footprint is too large."); } Vector3 val = new Vector3((float)((railTerrainBed.MinX + railTerrainBed.MaxX) * 0.5), ((Component)this).transform.position.y, (float)((railTerrainBed.MinZ + railTerrainBed.MaxZ) * 0.5)); List list = new List(); Heightmap.FindHeightmap(val, Mathf.Sqrt(num * num + num2 * num2) * 0.5f + 4f, list); if (list.Count == 0) { return gravelPlan.Fail("Wait for the ground around the rail gravel to load."); } HashSet hashSet = new HashSet(); int num3 = 0; foreach (Heightmap item in list) { if (!Object.op_Implicit((Object)(object)item) || item.IsDistantLod || !hashSet.Add(item)) { continue; } if (item.m_scale < 0.1f || item.m_scale > 8f || item.m_width <= 0 || item.m_width > 256) { return gravelPlan.Fail("The rail gravel terrain grid is unavailable."); } int num4 = RailTerrainPaintTool.PixelCount(item); if (num4 <= 0) { gravelPlan.Paints.Clear(); gravelPlan.Skipped = true; return gravelPlan; } Vector3 val2 = RailTerrainPaintTool.PixelCenter(item, 0, 0); int num5 = Mathf.Max(0, Mathf.FloorToInt(((float)railTerrainBed.MinX - val2.x) / item.m_scale) - 1); int num6 = Mathf.Max(0, Mathf.FloorToInt(((float)railTerrainBed.MinZ - val2.z) / item.m_scale) - 1); int num7 = Mathf.Min(num4 - 1, Mathf.CeilToInt(((float)railTerrainBed.MaxX - val2.x) / item.m_scale) + 1); int num8 = Mathf.Min(num4 - 1, Mathf.CeilToInt(((float)railTerrainBed.MaxZ - val2.z) / item.m_scale) + 1); for (int i = num6; i <= num8; i++) { for (int j = num5; j <= num7; j++) { if (++num3 > 8192) { return gravelPlan.Fail("The rail gravel footprint exceeds the terrain sampling limit."); } Vector3 point = RailTerrainPaintTool.PixelCenter(item, j, i); if (TryPaintTarget(railTerrainBed, item, point, creator, out Vector3 target, out string error)) { if (!RailTerrainPaintTool.IsPainted(item, target)) { gravelPlan.Paints.Add(new GravelPaint(item, target)); } } else if (error.Length != 0) { return gravelPlan.Fail(error); } } } } if (hashSet.Count != 0) { return gravelPlan; } return gravelPlan.Fail("Wait for the ground around the rail gravel to load."); } private bool GravelGroundLoaded() { //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) //IL_001e: 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_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_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_0052: 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_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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_006d: 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_0077: 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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: 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_00b4: 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_00b0: 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_00c9: 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_00ce: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < BedCorners.Length; i += 4) { Vector3 val = ((Component)this).transform.TransformPoint(BedCorners[i]); Vector3 val2 = ((Component)this).transform.TransformPoint(BedCorners[i + 1]); Vector3 val3 = ((Component)this).transform.TransformPoint(BedCorners[i + 3]); Vector3 val4 = val2 - val; Vector3 val5 = ((Vector3)(ref val4)).normalized * 2f; val4 = val3 - val; Vector3 val6 = ((Vector3)(ref val4)).normalized * 0.35f; for (int j = 0; j < 4; j++) { Heightmap val7 = Heightmap.FindHeightmap(((Component)this).transform.TransformPoint(BedCorners[i + j]) + ((j == 0 || j == 3) ? (-val5) : val5) + ((j < 2) ? (-val6) : val6)); if (!Object.op_Implicit((Object)(object)val7) || val7.IsDistantLod) { return false; } } } return true; } internal bool TryPaintTarget(RailTerrainBed bed, Heightmap map, Vector3 point, long creator, out Vector3 target, out string error) { //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_0033: 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_0052: 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_00a6: 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_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_016d: 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_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) target = point; error = ""; if (!Object.op_Implicit((Object)(object)map) || map.IsDistantLod || map.HaveQueuedRebuild()) { error = "Wait for the ground around the rail gravel to load."; return false; } double? num = bed.SurfaceHeight(point.x, point.z); if (!num.HasValue) { return false; } if (!TryGround(point, out var height)) { error = "Wait for the ground around the rail gravel to load."; return false; } if (!RailTerrainBed.IsGravelGroundLevel(num.Value, height)) { return false; } float num2 = RailTerrainPaintTool.ProtectionRadius(map); float num3 = num2 * 0.707107f; float num4 = height; float num5 = (float)num.Value; for (int i = -2; i <= 2; i++) { for (int j = -2; j <= 2; j++) { Vector3 val = point + new Vector3((float)j * num3 * 0.5f, 0f, (float)i * num3 * 0.5f); if (!TryGround(val, out var height2)) { error = "Wait for the ground around the rail gravel to load."; return false; } double? num6 = bed.SurfaceHeight(val.x, val.z); if (num6.HasValue) { if (!RailTerrainBed.IsGravelGroundLevel(num6.Value, height2)) { return false; } num4 = Mathf.Min(num4, height2); num5 = Mathf.Max(num5, (float)num6.Value); } } } if (HasBuiltSurface(point, num4, num5, num3)) { return false; } target.y = height; if (!((creator == 0L) ? PrivateArea.CheckAccess(target, num2, false, true) : RailWardAccess.Allows(target, creator, num2))) { error = "A ward protects this gravel trackbed. Move the track or get permission."; return false; } if (!RailTerrainProtection.Allows(target, num2)) { error = (RailTerrainProtection.Available ? "This gravel trackbed is inside a protected no-build area." : RailTerrainProtection.Error); return false; } return true; } private static bool TryGround(Vector3 point, out float height) { //IL_0007: 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_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_0159: Unknown result type (might be due to invalid IL or missing references) height = 0f; Heightmap val = Heightmap.FindHeightmap(point); if (!Object.op_Implicit((Object)(object)val) || val.IsDistantLod || val.HaveQueuedRebuild() || val.m_scale <= 0f || val.m_width <= 0) { return false; } float num = (point.x - ((Component)val).transform.position.x) / val.m_scale + (float)(val.m_width / 2); float num2 = (point.z - ((Component)val).transform.position.z) / val.m_scale + (float)(val.m_width / 2); if (num < -0.001f || num2 < -0.001f || num > (float)val.m_width + 0.001f || num2 > (float)val.m_width + 0.001f) { return false; } num = Mathf.Clamp(num, 0f, (float)val.m_width); num2 = Mathf.Clamp(num2, 0f, (float)val.m_width); int num3 = Mathf.Min(Mathf.FloorToInt(num), val.m_width - 1); int num4 = Mathf.Min(Mathf.FloorToInt(num2), val.m_width - 1); height = (float)RailTerrainBed.InterpolateGround(val.GetHeight(num3, num4), val.GetHeight(num3 + 1, num4), val.GetHeight(num3, num4 + 1), val.GetHeight(num3 + 1, num4 + 1), num - (float)num3, num2 - (float)num4) + ((Component)val).transform.position.y; return true; } private bool HasBuiltSurface(Vector3 point, float ground, float bed, float halfFootprint) { //IL_0018: 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_0073: 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_0075: Unknown result type (might be due to invalid IL or missing references) float num = ground - 0.025f; float num2 = Mathf.Max(ground, bed) + 0.08f; Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(point.x, (num + num2) * 0.5f, point.z); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(halfFootprint, (num2 - num) * 0.5f, halfFootprint); int mask = LayerMask.GetMask(new string[4] { "piece", "Default", "static_solid", "vehicle" }); Collider[] array = Physics.OverlapBox(val, val2, Quaternion.identity, mask, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { Piece componentInParent = ((Component)array[i]).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent) && !((Object)(object)((Component)componentInParent).gameObject == (Object)(object)((Component)this).gameObject)) { RailTerrainPlacement component = ((Component)componentInParent).GetComponent(); if (!Object.op_Implicit((Object)(object)component) || component.PreserveTerrain || (!Object.op_Implicit((Object)(object)((Component)componentInParent).GetComponent()) && !Object.op_Implicit((Object)(object)((Component)componentInParent).GetComponent()))) { return true; } } } return false; } private static void Tell(Player player, string message) { ((Character)player).Message((MessageType)2, message, 0, (Sprite)null, false); } } [HarmonyPatch(typeof(Player), "UpdatePlacementGhost", new Type[] { typeof(bool) })] internal static class RailTerrainPreviewPatch { private static readonly MethodInfo? SetValid = AccessTools.Method(typeof(Player), "SetPlacementGhostValid", new Type[1] { typeof(bool) }, (Type[])null); internal static string LastError = ""; [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix(Player __instance, bool flashGuardStone, GameObject ___m_placementGhost, ref PlacementStatus ___m_placementStatus) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } LastError = ""; if (!Object.op_Implicit((Object)(object)___m_placementGhost) || !___m_placementGhost.activeInHierarchy || ___m_placementStatus) { return; } RailTerrainPlacement component = ___m_placementGhost.GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return; } string text; try { text = component.PreviewError(); } catch (Exception error) { RailPlugin.Error(error); text = "The rail gravel could not be checked. Check the log or disable DirtTrackbedOnPlacement."; } if (text.Length != 0) { LastError = text; ___m_placementStatus = (PlacementStatus)1; SetValid?.Invoke(__instance, new object[1] { false }); if (flashGuardStone) { ((Character)__instance).Message((MessageType)2, text, 0, (Sprite)null, false); } } } } [HarmonyPatch(typeof(Player), "TryPlacePiece", new Type[] { typeof(Piece) })] internal static class RailTerrainPlacementMessagePatch { [HarmonyPostfix] private static void Postfix(Player __instance, bool __result) { if (!__result && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && RailTerrainPreviewPatch.LastError.Length != 0) { ((Character)__instance).Message((MessageType)2, RailTerrainPreviewPatch.LastError, 0, (Sprite)null, false); } } } internal static class RailTerrainProtection { private delegate bool LocationContains(Location location, Vector3 point, float radius, bool buildCheck); private static readonly FieldInfo? Locations = AccessTools.Field(typeof(Location), "s_allLocations"); private static readonly FieldInfo? NoBuild = AccessTools.Field(typeof(Location), "m_noBuild"); private static readonly LocationContains? Contains = FindContains(); private static bool _disabled; private static string _error = "This game build's protected-location API is unavailable. Disable DirtTrackbedOnPlacement to build without gravel painting."; internal static string Error => _error; internal static bool Available { get { if (_disabled || Contains == null || Locations?.FieldType != typeof(List) || NoBuild?.FieldType != typeof(bool)) { return false; } try { return Locations.GetValue(null) is IEnumerable; } catch (Exception exception) { Disable(exception); return false; } } } internal static bool Allows(Vector3 point, float affectedRadius) { //IL_0021: 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_003b: 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) if (!Available) { return false; } if (float.IsNaN(affectedRadius) || float.IsInfinity(affectedRadius) || affectedRadius < 0f || !Finite(point.x) || !Finite(point.y) || !Finite(point.z)) { Disable(new ArgumentOutOfRangeException("affectedRadius", "The gravel footprint is not finite.")); return false; } try { if (!(Locations.GetValue(null) is IEnumerable enumerable)) { return false; } foreach (Location item in enumerable) { if (Object.op_Implicit((Object)(object)item) && true.Equals(NoBuild.GetValue(item)) && Contains(item, point, affectedRadius, buildCheck: true)) { return false; } } return true; } catch (Exception exception) { Disable(exception); return false; } } private static LocationContains? FindContains() { try { MethodInfo methodInfo = AccessTools.Method(typeof(Location), "IsInside", new Type[3] { typeof(Vector3), typeof(float), typeof(bool) }, (Type[])null); return (methodInfo?.ReturnType == typeof(bool)) ? ((LocationContains)Delegate.CreateDelegate(typeof(LocationContains), methodInfo)) : null; } catch { return null; } } private static bool Finite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } private static void Disable(Exception exception) { if (!_disabled) { _disabled = true; _error = "Terrain protection could not be checked. Check the log or disable DirtTrackbedOnPlacement to build without gravel painting."; RailPlugin.Warn("Rail terrain protection is unavailable: " + exception.Message); } } } public sealed class RailTorchFuel : MonoBehaviour { private const string FreeFuelKey = "vikingrail_torch_free_fuel"; private RailMountedTorch _torch; private RailMountedObject _mounted; private Fireplace _fire; private bool _originalInfiniteFuel; private bool _originalCanTurnOff; internal bool FreeFuel { get; private set; } internal bool AlwaysLit => Object.op_Implicit((Object)(object)_torch); internal static RailTorchFuel Ensure(RailMountedTorch torch) { return Ensure(((Component)torch).gameObject); } internal static RailTorchFuel Ensure(RailMountedObject mounted) { return Ensure(((Component)mounted).gameObject); } private static RailTorchFuel Ensure(GameObject target) { RailTorchFuel railTorchFuel = target.GetComponent(); if (!Object.op_Implicit((Object)(object)railTorchFuel)) { railTorchFuel = target.AddComponent(); } railTorchFuel.Refresh(); return railTorchFuel; } private void Awake() { _torch = ((Component)this).GetComponent(); _mounted = ((Component)this).GetComponent(); _fire = ((Component)this).GetComponent(); if (Object.op_Implicit((Object)(object)_fire)) { _originalInfiniteFuel = _fire.m_infiniteFuel; _originalCanTurnOff = _fire.m_canTurnOff; } } private void Update() { Refresh(); } internal void Refresh() { if (!Object.op_Implicit((Object)(object)_fire)) { return; } ZNetView val = ((Object.op_Implicit((Object)(object)_torch) && _torch.Ready) ? _torch.View : ((Object.op_Implicit((Object)(object)_mounted) && _mounted.Ready) ? _mounted.View : null)); if (Object.op_Implicit((Object)(object)val) && !val.IsValid()) { val = null; } if (!AlwaysLit && !Object.op_Implicit((Object)(object)val)) { RestoreFlags(); return; } bool flag = Object.op_Implicit((Object)(object)_mounted) && _mounted.HasCommittedMount; FreeFuel = AlwaysLit || (flag && (!RailSettings.Ready || !RailSettings.AttachedTorchesUseFuel)); bool flag2 = AlwaysLit || (flag && RailSettings.Ready && !RailSettings.AttachedTorchesUseFuel); _fire.m_infiniteFuel = _originalInfiniteFuel || FreeFuel; _fire.m_canTurnOff = _originalCanTurnOff && !flag2; if (!Object.op_Implicit((Object)(object)val) || !val.IsOwner()) { return; } ZDO zDO = val.GetZDO(); if (flag2 && zDO.GetInt(ZDOVars.s_state, 1) != 1) { zDO.Set(ZDOVars.s_state, 1, false); } bool flag3 = zDO.GetBool("vikingrail_torch_free_fuel", false); if (flag3 != FreeFuel) { if (flag3 && Object.op_Implicit((Object)(object)ZNet.instance)) { zDO.Set(ZDOVars.s_lastTime, ZNet.instance.GetTime().Ticks); } zDO.Set("vikingrail_torch_free_fuel", FreeFuel); } } private void RestoreFlags() { FreeFuel = false; if (Object.op_Implicit((Object)(object)_fire)) { _fire.m_infiniteFuel = _originalInfiniteFuel; _fire.m_canTurnOff = _originalCanTurnOff; } } private void OnDestroy() { RestoreFlags(); } } internal static class RailTorchFuelHooks { internal static readonly MethodInfo? UpdateMethod = AccessTools.DeclaredMethod(typeof(Fireplace), "UpdateFireplace", Type.EmptyTypes, (Type[])null); internal static readonly MethodInfo? StateMethod = AccessTools.DeclaredMethod(typeof(Fireplace), "UpdateState", Type.EmptyTypes, (Type[])null); internal static readonly MethodInfo? HoverMethod = AccessTools.DeclaredMethod(typeof(Fireplace), "GetHoverText", Type.EmptyTypes, (Type[])null); internal static readonly MethodInfo? BurningMethod = AccessTools.DeclaredMethod(typeof(Fireplace), "IsBurning", Type.EmptyTypes, (Type[])null); private static bool _warned; internal static bool Prepare() { int num; if (UpdateMethod?.ReturnType == typeof(void) && StateMethod?.ReturnType == typeof(void) && HoverMethod?.ReturnType == typeof(string)) { num = ((BurningMethod?.ReturnType == typeof(bool)) ? 1 : 0); if (num != 0) { goto IL_00a3; } } else { num = 0; } if (!_warned) { _warned = true; RailPlugin.Warn("Rail torch fuel hooks are unavailable on this Valheim build: the native fireplace API changed."); } goto IL_00a3; IL_00a3: return (byte)num != 0; } internal static RailTorchFuel? Refresh(Fireplace fire) { RailMountedTorch component = ((Component)fire).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { return RailTorchFuel.Ensure(component); } RailMountedObject component2 = ((Component)fire).GetComponent(); if (!Object.op_Implicit((Object)(object)component2)) { return null; } return RailTorchFuel.Ensure(component2); } } [HarmonyPatch] internal static class RailTorchAlwaysBurningPatch { [HarmonyPrepare] private static bool Prepare() { return RailTorchFuelHooks.Prepare(); } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailTorchFuelHooks.BurningMethod; } [HarmonyPrefix] private static bool Prefix(Fireplace __instance, ref bool __result) { RailMountedTorch component = ((Component)__instance).GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return true; } RailTorchFuel.Ensure(component); __result = true; return false; } } [HarmonyPatch] internal static class RailTorchFuelUpdatePatch { [HarmonyPrepare] private static bool Prepare() { return RailTorchFuelHooks.Prepare(); } [HarmonyTargetMethods] private static IEnumerable TargetMethods() { yield return RailTorchFuelHooks.UpdateMethod; yield return RailTorchFuelHooks.StateMethod; } [HarmonyPrefix] private static void Prefix(Fireplace __instance) { RailTorchFuelHooks.Refresh(__instance); } } [HarmonyPatch] internal static class RailTorchFuelHoverPatch { [HarmonyPrepare] private static bool Prepare() { return RailTorchFuelHooks.Prepare(); } [HarmonyTargetMethod] private static MethodBase TargetMethod() { return RailTorchFuelHooks.HoverMethod; } [HarmonyPrefix] private static void Prefix(Fireplace __instance) { RailTorchFuelHooks.Refresh(__instance); } [HarmonyPostfix] private static void Postfix(Fireplace __instance, ref string __result) { RailTorchFuel component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component) && component.FreeFuel) { __result = Localization.instance.Localize(__instance.m_name) + (component.AlwaysLit ? "\nGreydwarf eye: always lit; no fuel needed" : "\nAttached torch: unlimited fuel"); } } } [DefaultExecutionOrder(100)] public sealed class RailTorchLighting : MonoBehaviour { [Serializable] public sealed class NativeLamp { public Light Lamp; public LightLod? Lod; public LightFlicker? Flicker; public float BaseRange; public LightRenderMode RenderMode; public LightShadows Shadows; } private struct SavedState { internal bool Captured; internal bool LightEnabled; internal bool LodEnabled; internal float FlickerIntensity; internal float Movement; } public NativeLamp[] Lamps = Array.Empty(); private RailMountedTorch _torch; private SavedState[] _states = Array.Empty(); private bool _vehicleMounted; internal static void Configure(GameObject prefab) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: 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) RailTorchLighting railTorchLighting = prefab.GetComponent() ?? prefab.AddComponent(); Light[] componentsInChildren = prefab.GetComponentsInChildren(true); railTorchLighting.Lamps = new NativeLamp[componentsInChildren.Length]; for (int i = 0; i < componentsInChildren.Length; i++) { Light val = componentsInChildren[i]; railTorchLighting.Lamps[i] = new NativeLamp { Lamp = val, Lod = ((Component)val).GetComponent(), Flicker = ((Component)val).GetComponent(), BaseRange = val.range, RenderMode = val.renderMode, Shadows = val.shadows }; } } private void Awake() { _torch = ((Component)this).GetComponent(); } private void BeginVehicleLighting() { _states = new SavedState[Lamps.Length]; for (int i = 0; i < Lamps.Length; i++) { NativeLamp nativeLamp = Lamps[i]; if (nativeLamp != null && Object.op_Implicit((Object)(object)nativeLamp.Lamp)) { _states[i] = new SavedState { Captured = true, LightEnabled = ((Behaviour)nativeLamp.Lamp).enabled, LodEnabled = (Object.op_Implicit((Object)(object)nativeLamp.Lod) && ((Behaviour)nativeLamp.Lod).enabled), FlickerIntensity = (Object.op_Implicit((Object)(object)nativeLamp.Flicker) ? nativeLamp.Flicker.m_flickerIntensity : 0f), Movement = (Object.op_Implicit((Object)(object)nativeLamp.Flicker) ? nativeLamp.Flicker.m_movement : 0f) }; } } _vehicleMounted = true; } private void LateUpdate() { //IL_00ea: 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 (!Object.op_Implicit((Object)(object)_torch) || !Object.op_Implicit((Object)(object)_torch.Vehicle)) { Restore(); return; } if (!_vehicleMounted) { BeginVehicleLighting(); } Vector3 position; bool flag = RailLightingView.TryGetPosition(out position); for (int i = 0; i < Lamps.Length; i++) { NativeLamp nativeLamp = Lamps[i]; if (nativeLamp != null && Object.op_Implicit((Object)(object)nativeLamp.Lamp)) { if (Object.op_Implicit((Object)(object)nativeLamp.Lod) && ((Behaviour)nativeLamp.Lod).enabled) { ((Behaviour)nativeLamp.Lod).enabled = false; } if (Object.op_Implicit((Object)(object)nativeLamp.Flicker)) { nativeLamp.Flicker.m_flickerIntensity = Mathf.Min(_states[i].FlickerIntensity, 0.04f); nativeLamp.Flicker.m_movement = 0f; } if (((Component)nativeLamp.Lamp).gameObject.activeInHierarchy) { float num = (flag ? ((float)RailLightingMath.DistanceFade(Vector3.Distance(position, ((Component)nativeLamp.Lamp).transform.position))) : 0f); nativeLamp.Lamp.range = nativeLamp.BaseRange * num; nativeLamp.Lamp.shadows = (LightShadows)0; nativeLamp.Lamp.renderMode = (LightRenderMode)1; ((Behaviour)nativeLamp.Lamp).enabled = num > 0f; } } } } private void Restore() { //IL_0061: 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) if (!_vehicleMounted) { return; } _vehicleMounted = false; for (int i = 0; i < Lamps.Length && i < _states.Length; i++) { NativeLamp nativeLamp = Lamps[i]; if (nativeLamp != null && _states[i].Captured) { if (Object.op_Implicit((Object)(object)nativeLamp.Lamp)) { nativeLamp.Lamp.range = nativeLamp.BaseRange; nativeLamp.Lamp.renderMode = nativeLamp.RenderMode; nativeLamp.Lamp.shadows = nativeLamp.Shadows; ((Behaviour)nativeLamp.Lamp).enabled = _states[i].LightEnabled; } if (Object.op_Implicit((Object)(object)nativeLamp.Flicker)) { nativeLamp.Flicker.m_flickerIntensity = _states[i].FlickerIntensity; nativeLamp.Flicker.m_movement = _states[i].Movement; } if (Object.op_Implicit((Object)(object)nativeLamp.Lod)) { ((Behaviour)nativeLamp.Lod).enabled = _states[i].LodEnabled; } } } _states = Array.Empty(); } private void OnDisable() { Restore(); } private void OnDestroy() { Restore(); } } internal static class RailTrackDamage { internal static bool Protected(WearNTear piece) { if (!RailSettings.Ready || !RailSettings.TracksTakeDamage) { if (!Object.op_Implicit((Object)(object)((Component)piece).GetComponent())) { return Object.op_Implicit((Object)(object)((Component)piece).GetComponent()); } return true; } return false; } } [HarmonyPatch(typeof(WearNTear), "RPC_Damage")] internal static class RailTrackHitPatch { [HarmonyPrefix] private static bool Prefix(WearNTear __instance) { return !RailTrackDamage.Protected(__instance); } } [HarmonyPatch(typeof(WearNTear), "ApplyDamage", new Type[] { typeof(float), typeof(HitData) })] internal static class RailTrackWearPatch { [HarmonyPrefix] private static bool Prefix(WearNTear __instance, float __0, ref bool __result) { if (__0 <= 0f || !RailTrackDamage.Protected(__instance)) { return true; } __result = false; return false; } } internal static class RailTrackPlacement { private readonly struct Port { internal readonly Transform Snap; internal readonly Piece Piece; internal readonly RailSnapPort Geometry; internal Port(Transform snap, Piece piece, RailSnapPort geometry) { Snap = snap; Piece = piece; Geometry = geometry; } } private static readonly MethodInfo? Overlap = AccessTools.Method(typeof(Player), "IsOverlappingOtherPiece", new Type[5] { typeof(Vector3), typeof(Quaternion), typeof(string), typeof(List), typeof(bool) }, (Type[])null); internal static readonly bool Compatible = Overlap?.ReturnType == typeof(bool) && AccessTools.Method(typeof(Player), "UpdatePlacementGhost", new Type[1] { typeof(bool) }, (Type[])null) != null && AccessTools.Method(typeof(Player), "PieceRayTest", new Type[6] { typeof(Vector3).MakeByRefType(), typeof(Vector3).MakeByRefType(), typeof(Piece).MakeByRefType(), typeof(Heightmap).MakeByRefType(), typeof(Collider).MakeByRefType(), typeof(bool) }, (Type[])null) != null && AccessTools.Method(typeof(Player), "FindClosestSnapPoints", new Type[5] { typeof(Transform), typeof(float), typeof(Transform).MakeByRefType(), typeof(Transform).MakeByRefType(), typeof(List) }, (Type[])null) != null && AccessTools.Field(typeof(Player), "m_placementGhost")?.FieldType == typeof(GameObject) && AccessTools.Field(typeof(Player), "m_manualSnapPoint")?.FieldType == typeof(int) && AccessTools.Field(typeof(Player), "m_maxPlaceDistance")?.FieldType == typeof(float) && AccessTools.Field(typeof(Player), "m_eye")?.FieldType == typeof(Transform); private static Player? _player; private static GameObject? _ghost; private static Vector3 _aim; private static bool _hasAim; private static readonly List LocalSnaps = new List(); private static readonly List NearbySnaps = new List(); private static readonly List LocalPorts = new List(); private static readonly List NearbyPorts = new List(); internal static void Begin(Player player, GameObject ghost) { End(); if (!((Object)(object)player != (Object)(object)Player.m_localPlayer) && Object.op_Implicit((Object)(object)ghost) && (Object.op_Implicit((Object)(object)ghost.GetComponent()) || Object.op_Implicit((Object)(object)ghost.GetComponent()))) { _player = player; _ghost = ghost; } } internal static void End() { _player = null; _ghost = null; _hasAim = false; } internal static void RayHit(Player player, Vector3 point, bool hit) { //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) if (!((Object)(object)player != (Object)(object)_player)) { _aim = point; _hasAim = hit; } } internal static bool TrySnap(Player player, Transform ghost, int manualSnap, Transform eye, float reach, List pieces, out Transform a, out Transform b) { //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: 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_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_03b1: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Unknown result type (might be due to invalid IL or missing references) a = null; b = null; if ((Object)(object)player != (Object)(object)_player || !Object.op_Implicit((Object)(object)_ghost) || (Object)(object)ghost != (Object)(object)_ghost.transform || !_hasAim || !Object.op_Implicit((Object)(object)eye)) { return false; } Piece component = ((Component)ghost).GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return false; } LocalSnaps.Clear(); LocalPorts.Clear(); NearbySnaps.Clear(); NearbyPorts.Clear(); component.GetSnapPoints(LocalSnaps); for (int i = 0; i < LocalSnaps.Count; i++) { if ((manualSnap < 0 || i == manualSnap) && TryPort(LocalSnaps[i], component, world: false, out var port)) { LocalPorts.Add(port); } } if (LocalPorts.Count == 0) { return false; } pieces.Clear(); Piece.GetSnapPoints(_aim, 20f, NearbySnaps, pieces); foreach (Transform nearbySnap in NearbySnaps) { if (!Object.op_Implicit((Object)(object)nearbySnap)) { continue; } Piece componentInParent = ((Component)nearbySnap).GetComponentInParent(); if (Object.op_Implicit((Object)(object)componentInParent) && !((Object)(object)componentInParent == (Object)(object)component)) { ZNetView component2 = ((Component)componentInParent).GetComponent(); if (Object.op_Implicit((Object)(object)component2) && component2.IsValid() && TryPort(nearbySnap, componentInParent, world: true, out var port2)) { NearbyPorts.Add(port2); } } } int num = -1; int index = -1; double num2 = double.PositiveInfinity; double num3 = double.PositiveInfinity; RailSnapPlacement railSnapPlacement = default(RailSnapPlacement); RailVector railVector = RailSegment.ToRail(_aim); RailVector eye2 = RailSegment.ToRail(eye.position); double requestedYaw = ghost.eulerAngles.y; for (int j = 0; j < NearbyPorts.Count; j++) { Port port3 = NearbyPorts[j]; if (!RailTrackSnapping.IsReachable(port3.Geometry, railVector, eye2, reach + (float)component.m_extraPlacementDistance)) { continue; } bool flag = false; foreach (Port nearbyPort in NearbyPorts) { if (!((Object)(object)nearbyPort.Piece == (Object)(object)port3.Piece) && RailTrackSnapping.IsConnected(port3.Geometry, nearbyPort.Geometry)) { flag = true; break; } } if (flag) { continue; } double num4 = RailVector.Distance(port3.Geometry.Position, railVector); if (num4 > num2 + 0.001) { continue; } for (int k = 0; k < LocalPorts.Count; k++) { if (RailTrackSnapping.TryAlign(LocalPorts[k].Geometry, port3.Geometry, requestedYaw, out var placement) && (!(Math.Abs(num4 - num2) <= 0.001) || !(placement.RotationChange >= num3))) { Vector3 val = RailSegment.ToUnity(placement.Position); Quaternion val2 = Quaternion.Euler(0f, (float)placement.YawDegrees, 0f); if (!true.Equals(Overlap.Invoke(player, new object[5] { val, val2, ((Object)ghost).name, pieces, component.m_allowRotatedOverlap }))) { num = k; index = j; num2 = num4; num3 = placement.RotationChange; railSnapPlacement = placement; } } } } if (num < 0) { return false; } ghost.rotation = Quaternion.Euler(0f, (float)railSnapPlacement.YawDegrees, 0f); a = LocalPorts[num].Snap; b = NearbyPorts[index].Snap; return true; } private static bool TryPort(Transform snap, Piece piece, bool world, out Port port) { //IL_00af: 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_00eb: 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_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) port = default(Port); Vector3[] array = null; bool flag = ((Object)snap).name == "snap_start"; RailSegment component = ((Component)piece).GetComponent(); RailSwitch component2 = ((Component)piece).GetComponent(); RailTurntable component3 = ((Component)piece).GetComponent(); if (world && Object.op_Implicit((Object)(object)component3) && (component3.Busy || !component3.Aligned)) { return false; } if (Object.op_Implicit((Object)(object)component) && (flag || (((Object)snap).name == "snap_end" && component.Kind != RailSectionKind.Bumper))) { array = component.Points; } else if (Object.op_Implicit((Object)(object)component2)) { array = component2.SnapPath(((Object)snap).name); } if (array == null || array.Length < 2) { return false; } int num = ((!flag) ? (array.Length - 1) : 0); RailSnapPort geometry = RailTrackSnapping.Endpoint(RailSegment.ToRail(array[num]), RailSegment.ToRail(array[flag ? 1 : (num - 1)]), (array.Length > 2) ? new RailVector?(RailSegment.ToRail(array[flag ? 2 : (num - 2)])) : ((RailVector?)null)); if (world) { geometry = new RailSnapPort(RailSegment.ToRail(snap.position), RailSegment.ToRail(((Component)piece).transform.TransformDirection(RailSegment.ToUnity(geometry.Outward)))); } port = new Port(snap, piece, geometry); return true; } } [HarmonyPatch(typeof(Player), "UpdatePlacementGhost")] internal static class RailTrackPlacementScopePatch { [HarmonyPrepare] private static bool Prepare() { return RailTrackPlacement.Compatible; } [HarmonyPrefix] private static void Prefix(Player __instance, GameObject ___m_placementGhost) { RailTrackPlacement.Begin(__instance, ___m_placementGhost); } [HarmonyFinalizer] private static void Finalizer() { RailTrackPlacement.End(); } } [HarmonyPatch(typeof(Player), "PieceRayTest")] internal static class RailTrackPlacementRayPatch { [HarmonyPrepare] private static bool Prepare() { return RailTrackPlacement.Compatible; } [HarmonyPostfix] private static void Postfix(Player __instance, Vector3 point, bool __result) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) RailTrackPlacement.RayHit(__instance, point, __result); } } [HarmonyPatch(typeof(Player), "FindClosestSnapPoints")] internal static class RailTrackPlacementSnapPatch { [HarmonyPrepare] private static bool Prepare() { return RailTrackPlacement.Compatible; } [HarmonyPrefix] private static bool Prefix(Player __instance, Transform ghost, List pieces, ref Transform a, ref Transform b, ref bool __result, int ___m_manualSnapPoint, Transform ___m_eye, float ___m_maxPlaceDistance) { if (!RailTrackPlacement.TrySnap(__instance, ghost, ___m_manualSnapPoint, ___m_eye, ___m_maxPlaceDistance, pieces, out a, out b)) { return true; } __result = true; return false; } } public sealed class RailTrackSupport : MonoBehaviour { [Serializable] public sealed class Channel { public BoxCollider[] Rails = Array.Empty(); public Vector3 Center; } public Channel[] Channels = Array.Empty(); public bool RequireBothEnds; private bool _evaluating; private bool _failed; private IList[]? _channelBounds; private Vector3 _boundsPosition; private Quaternion _boundsRotation; private Vector3 _boundsScale; internal const string SocketPrefix = "vr_support_"; private const float NativePadding = 0.15f; private static bool _compatibilityWarning; private static readonly Collider[] TerrainHits = (Collider[])(object)new Collider[1]; private static readonly FieldInfo? Bounds = AccessTools.Field(typeof(WearNTear), "m_bounds"); private static readonly FieldInfo? Colliders = AccessTools.Field(typeof(WearNTear), "m_colliders"); private static readonly FieldInfo? Support = AccessTools.Field(typeof(WearNTear), "m_support"); private static readonly FieldInfo? ClearPending = AccessTools.Field(typeof(WearNTear), "m_clearCachedSupport"); private static readonly Type? BoundType; private static readonly FieldInfo? BoundPosition; private static readonly FieldInfo? BoundRotation; private static readonly FieldInfo? BoundSize; private static readonly Action? Setup; private static readonly Action? UpdateNative; private static readonly Action? ClearCache; internal static bool Compatible { get { if (Bounds != null && typeof(IList).IsAssignableFrom(Bounds.FieldType) && Colliders?.FieldType == typeof(Collider[]) && Support?.FieldType == typeof(float) && ClearPending?.FieldType == typeof(bool) && BoundPosition?.FieldType == typeof(Vector3) && BoundRotation?.FieldType == typeof(Quaternion) && BoundSize?.FieldType == typeof(Vector3) && Setup != null && UpdateNative != null) { return ClearCache != null; } return false; } } internal static void Configure(GameObject prefab) { //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0151: 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_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_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_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: 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_018f: 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) //IL_01b1: 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_0296: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_032b: Unknown result type (might be due to invalid IL or missing references) if (!Compatible) { if (!_compatibilityWarning) { _compatibilityWarning = true; RailPlugin.Warn("Rail side support is unavailable on this game build; retaining the game's original support checks."); } return; } RailSegment component = prefab.GetComponent(); RailSwitch component2 = prefab.GetComponent(); List list = new List(); if (Object.op_Implicit((Object)(object)component)) { list.Add(component.Points); } else { if (!Object.op_Implicit((Object)(object)component2)) { throw new ArgumentException("Rail support requires a track or junction.", "prefab"); } list.AddRange(component2.LocalPaths()); } List list2 = new List(); BoxCollider[] componentsInChildren = prefab.GetComponentsInChildren(true); foreach (BoxCollider val in componentsInChildren) { if (((Object)val).name == "rail" || ((Object)val).name == "switch_rail") { list2.Add(val); } } HashSet hashSet = new HashSet(); List list3 = new List(); for (int j = 0; j < list.Count; j++) { Vector3[] array = list[j]; RailVector[] array2 = new RailVector[array.Length]; for (int k = 0; k < array.Length; k++) { array2[k] = RailSegment.ToRail(array[k]); } for (int l = -1; l <= 1; l += 2) { BoxCollider[] array3 = (BoxCollider[])(object)new BoxCollider[array.Length - 1]; for (int m = 0; m < array3.Length; m++) { Vector3 val2 = array[m + 1] - array[m]; Vector3 normalized = ((Vector3)(ref val2)).normalized; Vector3 val3 = (array[m] + array[m + 1]) * 0.5f; val2 = Vector3.Cross(Vector3.up, normalized); Vector3 val4 = val3 + ((Vector3)(ref val2)).normalized * ((float)l * 0.7f) + Vector3.up * 0.115f; BoxCollider val5 = null; float num = 0.0001f; foreach (BoxCollider item in list2) { if (!hashSet.Contains(item)) { val2 = prefab.transform.InverseTransformPoint(((Component)item).transform.TransformPoint(item.center)) - val4; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (!(sqrMagnitude >= num)) { num = sqrMagnitude; val5 = item; } } } if (!Object.op_Implicit((Object)(object)val5)) { throw new InvalidOperationException("Could not locate a side-rail support collider on " + ((Object)prefab).name); } array3[m] = val5; hashSet.Add(val5); } list3.Add(new Channel { Rails = array3, Center = RailSegment.ToUnity(RailSupportLayout.Center(array2, l)) }); RailVector[] array4 = RailSupportLayout.Sockets(array2, l); for (int n = 0; n < array4.Length; n++) { GameObject val6 = new GameObject("vr_support_" + ((l < 0) ? "left_" : "right_") + j + "_" + n); val6.transform.SetParent(prefab.transform, false); val6.transform.localPosition = RailSegment.ToUnity(array4[n]); val6.layer = prefab.layer; val6.tag = "snappoint"; } } } if (hashSet.Count != list2.Count || list3.Count > 12) { throw new InvalidOperationException("Unexpected side-rail support layout on " + ((Object)prefab).name); } prefab.AddComponent().Channels = list3.ToArray(); } internal static void ConfigureBridge(GameObject prefab) { //IL_0099: 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_00a3: 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_0155: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) RailSegment component = prefab.GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !component.IsBridge) { throw new ArgumentException("Bridge support requires a rail bridge.", "prefab"); } List[] array = new List[2] { new List(), new List() }; int[] array2 = new int[2]; int[] array3 = new int[2]; BoxCollider[] componentsInChildren = prefab.GetComponentsInChildren(true); foreach (BoxCollider val in componentsInChildren) { if (!(((Object)val).name != "bridge_bearing") || !(((Object)val).name != "bridge_end_post")) { int num = ((!(prefab.transform.InverseTransformPoint(((Component)val).transform.TransformPoint(val.center)).z < 0f)) ? 1 : 0); array[num].Add(val); if (((Object)val).name == "bridge_bearing") { array2[num]++; } else { array3[num]++; } } } if (array2[0] != 2 || array2[1] != 2 || array3[0] != 2 || array3[1] != 2) { throw new InvalidOperationException("A rail bridge requires four end bearings and their joined end posts."); } RailTrackSupport railTrackSupport = prefab.AddComponent(); railTrackSupport.RequireBothEnds = true; railTrackSupport.Channels = new Channel[2] { new Channel { Rails = array[0].ToArray(), Center = Vector3.zero }, new Channel { Rails = array[1].ToArray(), Center = Vector3.zero } }; RailVector[] array4 = RailBridgeTracks.SupportSockets(); for (int j = 0; j < array4.Length; j++) { GameObject val2 = new GameObject("vr_support_bridge_" + j); val2.transform.SetParent(prefab.transform, false); val2.transform.localPosition = RailSegment.ToUnity(array4[j]); val2.layer = prefab.layer; val2.tag = "snappoint"; } if (!Compatible) { prefab.GetComponent().m_enabled = false; RailPlugin.Warn("The 24 m bridge build piece is unavailable because native bearing-support checks could not be initialized."); } } internal bool Evaluate(WearNTear wear) { //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) if (_evaluating || _failed || !Compatible || Channels.Length == 0 || Channels.Length > 12) { return false; } ZNetView component = ((Component)wear).GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !component.IsValid() || !component.IsOwner()) { return false; } object obj = null; Vector3 comOffset = wear.m_comOffset; float num = (float)Support.GetValue(wear); bool flag = (bool)ClearPending.GetValue(wear); bool flag2 = false; float num2 = (RequireBothEnds ? float.PositiveInfinity : 0f); _evaluating = true; try { if (Colliders.GetValue(wear) == null) { Setup(wear); } obj = Bounds.GetValue(wear); if (!(obj is IList bounds)) { throw new InvalidOperationException("Native support bounds are not initialized."); } ClearCache(wear); if (!RequireBothEnds && TouchesTerrain(bounds)) { UpdateNative(wear); flag2 = true; num2 = (float)Support.GetValue(wear); } else { EnsureChannelBounds(); for (int i = 0; i < Channels.Length; i++) { ClearCache(wear); Bounds.SetValue(wear, _channelBounds[i]); wear.m_comOffset = Channels[i].Center; ClearPending.SetValue(wear, flag); UpdateNative(wear); float num3 = (float)Support.GetValue(wear); num2 = (RequireBothEnds ? Mathf.Min(num2, num3) : Mathf.Max(num2, num3)); } flag2 = true; } } catch (Exception ex) { _failed = true; RailPlugin.Warn("Rail side-support evaluation failed; retaining native support for this piece: " + ex.GetBaseException().Message); } finally { try { if (obj != null) { Bounds.SetValue(wear, obj); } wear.m_comOffset = comOffset; ClearPending.SetValue(wear, !flag2 && flag); ClearCache(wear); float num4 = (flag2 ? num2 : num); Support.SetValue(wear, num4); if (Object.op_Implicit((Object)(object)component) && component.IsValid() && component.IsOwner()) { component.GetZDO().Set(ZDOVars.s_support, num4); } } finally { wear.m_comOffset = comOffset; _evaluating = false; } } return flag2; } private static bool TouchesTerrain(IList bounds) { //IL_002f: 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_0054: Unknown result type (might be due to invalid IL or missing references) int mask = LayerMask.GetMask(new string[1] { "terrain" }); foreach (object bound in bounds) { if (Physics.OverlapBoxNonAlloc((Vector3)BoundPosition.GetValue(bound), (Vector3)BoundSize.GetValue(bound), TerrainHits, (Quaternion)BoundRotation.GetValue(bound), mask, (QueryTriggerInteraction)1) > 0) { return true; } } return false; } private void EnsureChannelBounds() { //IL_000e: 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_0026: 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_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: 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_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: 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_0044: 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_00c6: 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_00cf: 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_00e7: 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_0102: 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_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_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0153: 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) if (_channelBounds != null && ((Component)this).transform.position == _boundsPosition && ((Component)this).transform.rotation == _boundsRotation && ((Component)this).transform.lossyScale == _boundsScale) { return; } _channelBounds = new IList[Channels.Length]; for (int i = 0; i < Channels.Length; i++) { IList list = (IList)Activator.CreateInstance(Bounds.FieldType); BoxCollider[] rails = Channels[i].Rails; foreach (BoxCollider val in rails) { if (!Object.op_Implicit((Object)(object)val)) { throw new InvalidOperationException("A rail support collider is missing."); } object obj = Activator.CreateInstance(BoundType); Vector3 lossyScale = ((Component)val).transform.lossyScale; Vector3 val2 = Vector3.Scale(val.size, new Vector3(Mathf.Abs(lossyScale.x), Mathf.Abs(lossyScale.y), Mathf.Abs(lossyScale.z))) * 0.5f; BoundPosition.SetValue(obj, ((Component)val).transform.TransformPoint(val.center)); BoundRotation.SetValue(obj, ((Component)val).transform.rotation); BoundSize.SetValue(obj, val2 + Vector3.one * 0.15f); list.Add(obj); } _channelBounds[i] = list; } _boundsPosition = ((Component)this).transform.position; _boundsRotation = ((Component)this).transform.rotation; _boundsScale = ((Component)this).transform.lossyScale; } private static Action? NativeAction(string name) { try { MethodInfo methodInfo = AccessTools.Method(typeof(WearNTear), name, Type.EmptyTypes, (Type[])null); return (methodInfo?.ReturnType == typeof(void)) ? ((Action)Delegate.CreateDelegate(typeof(Action), methodInfo)) : null; } catch { return null; } } static RailTrackSupport() { FieldInfo? bounds = Bounds; BoundType = (((object)bounds != null && bounds.FieldType.IsGenericType) ? Bounds.FieldType.GetGenericArguments()[0] : null); BoundPosition = ((BoundType == null) ? null : AccessTools.Field(BoundType, "m_pos")); BoundRotation = ((BoundType == null) ? null : AccessTools.Field(BoundType, "m_rot")); BoundSize = ((BoundType == null) ? null : AccessTools.Field(BoundType, "m_size")); Setup = NativeAction("SetupColliders"); UpdateNative = NativeAction("UpdateSupport"); ClearCache = NativeAction("ClearCachedSupport"); } } [HarmonyPatch(typeof(WearNTear), "UpdateSupport")] internal static class RailTrackSupportPatch { [HarmonyPrepare] private static bool Prepare() { return RailTrackSupport.Compatible; } [HarmonyPrefix] private static bool Prefix(WearNTear __instance) { RailTrackSupport component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { return !component.Evaluate(__instance); } return true; } } [HarmonyPatch(typeof(Player), "UpdatePlacementGhost", new Type[] { typeof(bool) })] internal static class RailSupportSnapScopePatch { internal static bool BuildingRail; [HarmonyPrepare] private static bool Prepare() { return RailTrackPlacement.Compatible; } [HarmonyPrefix] private static void Prefix(GameObject ___m_placementGhost, out bool __state) { __state = BuildingRail; BuildingRail = Object.op_Implicit((Object)(object)___m_placementGhost) && Object.op_Implicit((Object)(object)___m_placementGhost.GetComponent()); } [HarmonyFinalizer] private static void Finalizer(bool __state) { BuildingRail = __state; } } [HarmonyPatch(typeof(Piece), "GetSnapPoints", new Type[] { typeof(List) })] internal static class RailSupportSnapFilterPatch { [HarmonyPrepare] private static bool Prepare() { return RailTrackPlacement.Compatible; } [HarmonyPrefix] private static void Prefix(List points, out int __state) { __state = points.Count; } [HarmonyPostfix] private static void Postfix(List points, int __state) { if (!RailSupportSnapScopePatch.BuildingRail) { return; } for (int num = points.Count - 1; num >= __state; num--) { if (Object.op_Implicit((Object)(object)points[num]) && ((Object)points[num]).name.StartsWith("vr_support_", StringComparison.Ordinal)) { points.RemoveAt(num); } } } } public sealed class RailTrackUpgradeInteraction : MonoBehaviour, Hoverable, Interactable { public string WoodenPrefab = ""; public GameObject MetalPrefab; internal const string UpgradedKey = "vikingrail_track_iron"; private const string PaidNailsKey = "vikingrail_upgrade_nails"; private const string ClaimPeer = "vikingrail_upgrade_peer"; private const string ClaimPlayer = "vikingrail_upgrade_player"; private const string ClaimToken = "vikingrail_upgrade_token"; private const string ClaimUntil = "vikingrail_upgrade_until"; private const float UseRange = 4f; private ZNetView _view; private Piece _piece; private RailTrackUpgradeDefinition _definition; private RailTrackUpgradeVisual? _visual; private Requirement[]? _refund; private bool _applied; private bool _warned; private string _pending = ""; private long _requestOwner; private long _requestPlayer; private float _requestedAt; private bool _granted; private bool Ready { get { if (Object.op_Implicit((Object)(object)_view) && _view.IsValid()) { return _definition != null; } return false; } } private bool Upgraded { get { if (Ready) { return _view.GetZDO().GetBool("vikingrail_track_iron", false); } return false; } } private static long Now { get { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return -1L; } return (long)(ZNet.instance.GetTimeSeconds() * 1000.0); } } private RailUpgradeClaim Claim => new RailUpgradeClaim(_view.GetZDO().GetLong("vikingrail_upgrade_peer", 0L), _view.GetZDO().GetLong("vikingrail_upgrade_player", 0L), _view.GetZDO().GetString("vikingrail_upgrade_token", ""), _view.GetZDO().GetLong("vikingrail_upgrade_until", 0L)); private void Awake() { _view = ((Component)this).GetComponent(); _piece = ((Component)this).GetComponent(); RailTrackUpgrade.TryGet(WoodenPrefab, out _definition); } private void Start() { if (Ready) { _view.Register("VR_RailUpgrade", (Action)RequestUpgrade); _view.Register("VR_RailUpgradeReply", (Action)ReceiveReply); ApplySavedUpgrade(); } } private void Update() { if (!Ready) { return; } ApplySavedUpgrade(); if (_pending.Length == 0) { return; } if (Upgraded) { EndRequest(); return; } if (Time.unscaledTime - _requestedAt > 20f) { EndRequest(); Tell("The upgrade request timed out. Your nails were not used; try again."); return; } Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer) || localPlayer.GetPlayerID() != _requestPlayer) { EndRequest(); } else { if (!_granted || !_view.IsOwner()) { return; } RailUpgradeClaim claim = Claim; if (claim.Matches(((Character)localPlayer).GetOwner(), _requestPlayer, _pending)) { if (!claim.IsActive(Now)) { EndRequest(); Tell("The upgrade permission expired. Your nails were not used; try again."); } else { CompleteUpgrade(localPlayer); } } } } public float GetHoverOffset() { return 0f; } public string GetHoverName() { if (!Object.op_Implicit((Object)(object)_piece)) { return "Railway track"; } return _piece.m_name; } public string GetHoverText() { return Localization.instance.Localize(GetHoverName() + (Upgraded ? "\nIron rail upgrade installed." : ((_definition == null) ? "" : ("\nUse Iron Nails from your hotbar to upgrade in place (" + _definition.IronNailsCost + " Iron Nails).")))); } public bool Interact(Humanoid user, bool hold, bool alt) { return false; } public bool UseItem(Humanoid user, ItemData item) { if (item == null || !Object.op_Implicit((Object)(object)item.m_dropPrefab) || ((Object)item.m_dropPrefab).name != "IronNails") { return false; } Player val = (Player)(object)((user is Player) ? user : null); if (!Object.op_Implicit((Object)(object)val) || (Object)(object)val != (Object)(object)Player.m_localPlayer) { return true; } if (!Ready) { Tell("Wait for this rail to finish loading."); return true; } if (Upgraded) { Tell("This rail is already upgraded."); return true; } if (_pending.Length != 0) { Tell("Waiting for the rail upgrade."); return true; } if (!((Humanoid)val).GetInventory().ContainsItem(item)) { return true; } if (!ValidatePlayer(val, out string error) || !Prepare(out error)) { Tell(error); return true; } if (((Humanoid)val).GetInventory().CountItems(item.m_shared.m_name, -1, true) < _definition.IronNailsCost) { Tell("This upgrade needs " + _definition.IronNailsCost + " Iron Nails."); return true; } if (!_view.HasOwner()) { Tell("Waiting for the rail's network owner. Try again shortly."); return true; } _pending = Guid.NewGuid().ToString("N"); _requestOwner = _view.GetZDO().GetOwner(); _requestPlayer = val.GetPlayerID(); _requestedAt = Time.unscaledTime; _granted = false; _view.InvokeRPC("VR_RailUpgrade", new object[2] { _requestPlayer, _pending }); return true; } private void RequestUpgrade(long sender, long playerId, string token) { //IL_00ee: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !_view.IsOwner() || string.IsNullOrWhiteSpace(token) || token.Length > 64) { return; } if (!Claim.CanGrant(sender, playerId, token, Now)) { Reply(sender, token, granted: false, "Another player is upgrading this rail. Try again shortly."); return; } Player player = Player.GetPlayer(playerId); if (Object.op_Implicit((Object)(object)player) && ((Character)player).GetOwner() == sender) { if (Upgraded) { Reply(sender, token, granted: false, "This rail is already upgraded."); return; } if (!ValidatePlayer(player, out string error) || !Prepare(out error)) { Reply(sender, token, granted: false, error); return; } ZDO zDO = _view.GetZDO(); zDO.Set("vikingrail_upgrade_peer", sender); zDO.Set("vikingrail_upgrade_player", playerId); zDO.Set("vikingrail_upgrade_token", token); zDO.Set("vikingrail_upgrade_until", Now + 15000); ZDOMan.instance.ForceSendZDO(sender, zDO.m_uid); zDO.SetOwner(sender); Reply(sender, token, granted: true, ""); } } private void Reply(long peer, string token, bool granted, string message) { _view.InvokeRPC(peer, "VR_RailUpgradeReply", new object[3] { token, granted, message }); } private void ReceiveReply(long sender, string token, bool granted, string message) { if (_pending.Length != 0 && !(token != _pending) && sender == _requestOwner) { if (!granted) { EndRequest(); Tell(message); } else { _granted = true; } } } private bool ValidatePlayer(Player player, out string error) { //IL_0063: 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_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) error = ""; if (!RailSettings.Ready || !Object.op_Implicit((Object)(object)ZNet.instance)) { error = "Waiting for server railroad settings."; return false; } if (((Character)player).IsDead() || ((Character)player).IsTeleporting() || ((Character)player).IsAttached() || player.GetDoodadController() != null) { error = "Stand on foot before upgrading rails."; return false; } RailPath[] array = WorldPaths(); double num = double.MaxValue; RailVector point = RailSegment.ToRail(((Component)player).transform.position); RailPath[] array2 = array; foreach (RailPath railPath in array2) { num = Math.Min(num, railPath.Project(point).Separation); } if (num > 4.0) { error = "Stand within 4 metres of the rail you want to upgrade."; return false; } RailSegment component = ((Component)this).GetComponent(); array2 = array; foreach (RailPath railPath2 in array2) { int num2 = Math.Max(1, (int)Math.Ceiling(railPath2.Length)); for (int j = 0; j <= num2; j++) { if (!RailWardAccess.Allows(RailSegment.ToUnity(railPath2.Sample(railPath2.Length * (double)j / (double)num2).Position), player.GetPlayerID())) { error = "You do not have access to this protected railway."; return false; } if (!Object.op_Implicit((Object)(object)component) || !component.IsBridge) { continue; } for (int k = -1; k <= 1; k += 2) { if (!RailWardAccess.Allows(RailSegment.ToUnity(railPath2.Sample(railPath2.Length * (double)j / (double)num2).Position) + ((Component)this).transform.right * ((float)k * 2.18f), player.GetPlayerID())) { error = "You do not have access to the whole bridge span."; return false; } } } } RailSwitch component2 = ((Component)this).GetComponent(); if ((Object.op_Implicit((Object)(object)component2) && (!component2.Ready || component2.IsOccupied)) || RailVehicle.OccupiesSwitch(array, 3f)) { error = "Clear the carts from this rail and its approaches before upgrading."; return false; } return true; } private RailPath[] WorldPaths() { RailSegment component = ((Component)this).GetComponent(); RailSwitch component2 = ((Component)this).GetComponent(); Vector3[][] array = ((!Object.op_Implicit((Object)(object)component)) ? new List(component2.LocalPaths()).ToArray() : new Vector3[1][] { component.Points }); RailPath[] array2 = new RailPath[array.Length]; for (int i = 0; i < array2.Length; i++) { array2[i] = new RailPath(Array.ConvertAll(array[i], (Vector3 p) => RailSegment.ToRail(((Component)this).transform.TransformPoint(p)))); } return array2; } private bool Prepare(out string error) { //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_00d8: 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_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown //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_012e: 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_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Expected O, but got Unknown error = "The track upgrade materials are not loaded yet."; if (!Object.op_Implicit((Object)(object)MetalPrefab) || !Object.op_Implicit((Object)(object)ObjectDB.instance) || !Object.op_Implicit((Object)(object)ZNetScene.instance)) { return false; } GameObject prefab = ZNetScene.instance.GetPrefab(WoodenPrefab); Piece val = (Object.op_Implicit((Object)(object)prefab) ? prefab.GetComponent() : null); GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("IronNails"); ItemDrop val2 = (Object.op_Implicit((Object)(object)itemPrefab) ? itemPrefab.GetComponent() : null); if (!Object.op_Implicit((Object)(object)val) || val.m_resources.Length == 0 || !Object.op_Implicit((Object)(object)val2)) { return false; } if (_refund == null) { _refund = (Requirement[]?)(object)new Requirement[val.m_resources.Length + 1]; for (int i = 0; i < val.m_resources.Length; i++) { Requirement val3 = val.m_resources[i]; _refund[i] = new Requirement { m_resItem = val3.m_resItem, m_amount = val3.m_amount, m_amountPerLevel = val3.m_amountPerLevel, m_recover = val3.m_recover }; } _refund[_refund.Length - 1] = new Requirement { m_resItem = val2, m_amount = _definition.IronNailsCost, m_amountPerLevel = 0, m_recover = true }; } if (Upgraded) { _refund[_refund.Length - 1].m_amount = Math.Max(0, _view.GetZDO().GetInt("vikingrail_upgrade_nails", _definition.IronNailsCost)); } if (_visual == null) { _visual = new RailTrackUpgradeVisual(((Component)this).gameObject, MetalPrefab); } return _visual.Prepare(out error); } private void CompleteUpgrade(Player player) { //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) if (!ValidatePlayer(player, out string error) || !Prepare(out error)) { EndRequest(); Tell(error); return; } Inventory inventory = ((Humanoid)player).GetInventory(); string name = _refund[_refund.Length - 1].m_resItem.m_itemData.m_shared.m_name; int num = _definition.IronNailsCost; if (inventory.CountItems(name, -1, true) < num) { EndRequest(); Tell("This upgrade needs " + num + " Iron Nails."); return; } List list = new List(); try { foreach (ItemData item in new List(inventory.GetAllItems())) { if (num == 0) { break; } if (item.m_shared.m_name != name || item.m_worldLevel < Game.m_worldLevel) { continue; } int num2 = Math.Min(num, item.m_stack); int stack = item.m_stack; ItemData val = item.Clone(); try { if (!inventory.RemoveItem(item, num2)) { throw new InvalidOperationException("The nail inventory changed."); } } finally { int num3 = stack - (inventory.ContainsItem(item) ? item.m_stack : 0); if (num3 > 0) { val.m_stack = num3; list.Add(val); num -= num3; } } } if (num != 0 || !_view.IsOwner() || !Claim.IsActive(Now) || !Claim.Matches(((Character)player).GetOwner(), _requestPlayer, _pending)) { throw new InvalidOperationException("The rail upgrade permission changed before completion."); } _view.GetZDO().Set("vikingrail_upgrade_nails", _definition.IronNailsCost); _view.GetZDO().Set("vikingrail_track_iron", true); Tell(ApplySavedUpgrade() ? ("Rail upgraded in place using " + _definition.IronNailsCost + " Iron Nails.") : "The upgrade was saved, but its appearance could not refresh. Check the mod log."); } catch (Exception error2) { RailPlugin.Error(error2); if (!Upgraded) { foreach (ItemData item2 in list) { if (!inventory.AddItem(item2)) { ItemDrop.DropItem(item2, item2.m_stack, ((Component)player).transform.position + Vector3.up, Quaternion.identity); } } Tell("The rail could not be upgraded. Your nails were returned."); } else { Tell("The upgrade was saved, but its appearance could not refresh. Reload the area and check the mod log."); } } finally { EndRequest(); } } internal bool ApplySavedUpgrade() { if (_applied) { return true; } if (!Upgraded) { return false; } string error; bool num = Prepare(out error); if (_refund != null) { _piece.m_resources = _refund; } if (!num) { if (!_warned) { _warned = true; RailPlugin.Warn("Could not apply a saved rail upgrade: " + error); } return false; } _visual.Apply(); Piece component = MetalPrefab.GetComponent(); _piece.m_name = component.m_name; _piece.m_description = component.m_description; _piece.m_icon = component.m_icon; _piece.m_resources = _refund; RailSegment component2 = ((Component)this).GetComponent(); if (Object.op_Implicit((Object)(object)component2)) { component2.SetLightDuty(lightDuty: false); } RailSwitch component3 = ((Component)this).GetComponent(); if (Object.op_Implicit((Object)(object)component3)) { component3.SetLightDuty(lightDuty: false); } _applied = true; return true; } private void EndRequest() { if (Ready && _view.IsOwner() && _pending.Length != 0 && Claim.Matches(_view.GetZDO().GetOwner(), _requestPlayer, _pending)) { ZDO zDO = _view.GetZDO(); zDO.Set("vikingrail_upgrade_peer", 0L); zDO.Set("vikingrail_upgrade_player", 0L); zDO.Set("vikingrail_upgrade_token", ""); zDO.Set("vikingrail_upgrade_until", 0L); } _pending = ""; _granted = false; } private static void Tell(string message) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false); } } } [HarmonyPatch(typeof(Piece), "DropResources")] internal static class RailTrackUpgradeRefundPatch { [HarmonyPrefix] private static void Prefix(Piece __instance) { ((Component)__instance).GetComponent()?.ApplySavedUpgrade(); } } internal sealed class RailTrackUpgradeVisual { private sealed class Replacement { internal readonly Renderer Renderer; internal readonly Material[] Materials; internal Replacement(Renderer renderer, Material[] materials) { Renderer = renderer; Materials = materials; } } private readonly GameObject _track; private readonly GameObject _metalPrefab; private readonly List _replacements = new List(); private readonly List _nails = new List(); private bool _prepared; internal RailTrackUpgradeVisual(GameObject track, GameObject metalPrefab) { _track = track; _metalPrefab = metalPrefab; } internal bool Prepare(out string error) { _prepared = false; _replacements.Clear(); _nails.Clear(); error = ""; if (!Object.op_Implicit((Object)(object)_track) || !Object.op_Implicit((Object)(object)_metalPrefab)) { return Fail("The matching iron track model is unavailable.", out error); } Transform val = _track.transform.Find("visual"); Transform val2 = _metalPrefab.transform.Find("visual"); if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val2)) { return Fail("The track model has no visual root.", out error); } Dictionary dictionary = new Dictionary(StringComparer.Ordinal); Dictionary dictionary2 = new Dictionary(StringComparer.Ordinal); Collect(val, "visual", dictionary); Collect(val2, "visual", dictionary2); foreach (KeyValuePair item in dictionary) { Renderer value = item.Value; if (((Object)value).name == "bronze_nail") { if (Object.op_Implicit((Object)(object)((Component)value).GetComponent())) { return Fail("A wooden nail unexpectedly has a collider.", out error); } _nails.Add(value); continue; } if (!dictionary2.TryGetValue(item.Key, out var value2) || ((object)value).GetType() != ((object)value2).GetType() || !SameLayout(((Component)value).transform, ((Component)value2).transform, val, val2) || !SameMesh(value, value2)) { return Fail("The wooden and iron track models do not match at " + item.Key + ".", out error); } Material[] sharedMaterials = value2.sharedMaterials; if (sharedMaterials.Length == 0 || sharedMaterials.Length != value.sharedMaterials.Length) { return Fail("The iron track material slots do not match at " + item.Key + ".", out error); } Material[] array = sharedMaterials; foreach (Material val3 in array) { if (!Object.op_Implicit((Object)(object)val3) || !Object.op_Implicit((Object)(object)val3.shader)) { return Fail("An iron track material is unavailable at " + item.Key + ".", out error); } } _replacements.Add(new Replacement(value, sharedMaterials)); dictionary2.Remove(item.Key); } if (_replacements.Count == 0 || dictionary2.Count != 0) { return Fail("The iron track has an unmatched model part.", out error); } _prepared = true; return true; } internal void Apply() { if (!_prepared) { throw new InvalidOperationException("Prepare the rail upgrade model before applying it."); } foreach (Replacement replacement in _replacements) { if (!Object.op_Implicit((Object)(object)replacement.Renderer)) { throw new InvalidOperationException("The rail model changed after the upgrade was prepared."); } } foreach (Renderer nail in _nails) { if (!Object.op_Implicit((Object)(object)nail)) { throw new InvalidOperationException("The wooden rail model changed after the upgrade was prepared."); } } foreach (Replacement replacement2 in _replacements) { replacement2.Renderer.sharedMaterials = replacement2.Materials; } foreach (Renderer nail2 in _nails) { nail2.enabled = false; } if (Object.op_Implicit((Object)(object)MaterialMan.instance)) { MaterialMan.instance.ResetValue(_track, ShaderProps._Color); MaterialMan.instance.ResetValue(_track, ShaderProps._EmissionColor); } } private static bool Fail(string message, out string error) { error = message; return false; } private static void Collect(Transform node, string path, Dictionary renderers) { Renderer[] components = ((Component)node).GetComponents(); for (int i = 0; i < components.Length; i++) { renderers.Add(path + ":renderer[" + i + "]", components[i]); } Dictionary dictionary = new Dictionary(StringComparer.Ordinal); for (int j = 0; j < node.childCount; j++) { Transform child = node.GetChild(j); dictionary.TryGetValue(((Object)child).name, out var value); dictionary[((Object)child).name] = value + 1; Collect(child, path + "/" + ((Object)child).name + "[" + value + "]", renderers); } } private static bool SameLayout(Transform original, Transform target, Transform originalRoot, Transform targetRoot) { //IL_0006: 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) //IL_0026: 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_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_005a: 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) while (Object.op_Implicit((Object)(object)original) && Object.op_Implicit((Object)(object)target)) { Vector3 val = original.localPosition - target.localPosition; if (!(((Vector3)(ref val)).sqrMagnitude > 1E-06f)) { val = original.localScale - target.localScale; if (!(((Vector3)(ref val)).sqrMagnitude > 1E-06f)) { if (((Object)original).name != "vr_switch_lever" && Quaternion.Angle(original.localRotation, target.localRotation) > 0.01f) { return false; } if ((Object)(object)original == (Object)(object)originalRoot || (Object)(object)target == (Object)(object)targetRoot) { if ((Object)(object)original == (Object)(object)originalRoot) { return (Object)(object)target == (Object)(object)targetRoot; } return false; } original = original.parent; target = target.parent; continue; } } return false; } return false; } private static bool SameMesh(Renderer original, Renderer target) { //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_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_009d: 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_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_00c2: 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_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) if (!(original is MeshRenderer) || !(target is MeshRenderer)) { return false; } MeshFilter component = ((Component)original).GetComponent(); MeshFilter component2 = ((Component)target).GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component2)) { return false; } Mesh sharedMesh = component.sharedMesh; Mesh sharedMesh2 = component2.sharedMesh; if (!Object.op_Implicit((Object)(object)sharedMesh) || !Object.op_Implicit((Object)(object)sharedMesh2)) { return false; } if (!((Object)(object)sharedMesh == (Object)(object)sharedMesh2)) { if (sharedMesh.vertexCount == sharedMesh2.vertexCount && sharedMesh.subMeshCount == sharedMesh2.subMeshCount) { Bounds bounds = sharedMesh.bounds; Vector3 center = ((Bounds)(ref bounds)).center; bounds = sharedMesh2.bounds; Vector3 val = center - ((Bounds)(ref bounds)).center; if (((Vector3)(ref val)).sqrMagnitude <= 1E-06f) { bounds = sharedMesh.bounds; Vector3 size = ((Bounds)(ref bounds)).size; bounds = sharedMesh2.bounds; val = size - ((Bounds)(ref bounds)).size; return ((Vector3)(ref val)).sqrMagnitude <= 1E-06f; } } return false; } return true; } } public sealed class RailTurntable : MonoBehaviour { public Transform Deck; public Transform Lever; public float Length = 12f; private const string AngleKey = "vr_table_angle"; private const string UntilKey = "vr_table_until"; private const string PeerKey = "vr_table_peer"; private const string PlayerKey = "vr_table_player"; private const string DirectionKey = "vr_table_direction"; private const string PendingKey = "vr_table_pending"; private const string TokenKey = "vr_table_token"; private static readonly HashSet Tables = new HashSet(); private ZNetView _view; private RailSegment _segment; private List? _turn; private float _angle; private float _target; private string _token = ""; private long _player; private long _peer; private bool _started; private float _nextRequest; private float _nextOwnerRequest; internal string PathId { get { if (!Object.op_Implicit((Object)(object)_segment)) { return ""; } return _segment.PathId; } } private bool Ready { get { if (_started && Object.op_Implicit((Object)(object)_view) && _view.IsValid() && Object.op_Implicit((Object)(object)Deck) && Object.op_Implicit((Object)(object)_segment)) { return PathId.Length != 0; } return false; } } private static long Now { get { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return 0L; } return (long)(ZNet.instance.GetTimeSeconds() * 1000.0); } } internal bool Busy { get { if (Ready && _view.GetZDO().GetLong("vr_table_until", 0L) > Now) { return _view.GetZDO().GetLong("vr_table_until", 0L) <= Now + 12000; } return false; } } internal bool Aligned => Mathf.Abs(Mathf.DeltaAngle(_angle, Mathf.Round(_angle / 45f) * 45f)) < 0.01f; internal bool CanRemove { get { if (Ready && !Busy) { return !RailVehicle.LoadedVehicles.Any((RailVehicle v) => Object.op_Implicit((Object)(object)v) && NearDeck(((Component)v).transform.position, 1.5f)); } return false; } } private void Awake() { _view = ((Component)this).GetComponent(); _segment = ((Component)this).GetComponent(); if (Object.op_Implicit((Object)(object)_view) && _view.IsValid() && Object.op_Implicit((Object)(object)Deck) && Object.op_Implicit((Object)(object)_segment)) { SetGeometry(ReadAngle(), refresh: false); } } private void Start() { if (Object.op_Implicit((Object)(object)_view) && _view.IsValid() && Object.op_Implicit((Object)(object)Deck) && Object.op_Implicit((Object)(object)_segment) && VikingRail.Core.RailTurntable.IsLength(Length)) { _started = true; Tables.Add(this); _view.Register("VR_TableTurn_v1", (Action)RequestTurn); _view.Register("VR_TableReply_v1", (Action)ReceiveReply); SetGeometry(ReadAngle(), refresh: true); } } private float ReadAngle() { float num = _view.GetZDO().GetFloat("vr_table_angle", 0f); if (!float.IsNaN(num) && !float.IsInfinity(num)) { return Mathf.Repeat(num, 360f); } return 0f; } private void SetGeometry(float angle, bool refresh) { //IL_0027: 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_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_006b: 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_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_009d: Unknown result type (might be due to invalid IL or missing references) _angle = Mathf.Repeat(angle, 360f); Deck.localRotation = Quaternion.Euler(0f, _angle, 0f); _segment.Points = (Vector3[])(object)new Vector3[2] { Deck.localRotation * new Vector3(0f, 0f, (0f - Length) * 0.5f), Deck.localRotation * new Vector3(0f, 0f, Length * 0.5f) }; if (refresh) { _segment.RefreshGeometry(); } if (PathId.Length != 0) { RailSegment.Network.SetIsolated(PathId, Busy || !Aligned); } } private void Update() { if (!Ready) { return; } if (_turn != null && !_view.IsOwner()) { _turn = null; } if (_turn == null) { float num = ReadAngle(); if (Mathf.Abs(Mathf.DeltaAngle(num, _angle)) > 0.001f) { SetGeometry(num, refresh: true); } RailSegment.Network.SetIsolated(PathId, Busy || !Aligned); if (_view.IsOwner() && _view.GetZDO().GetBool("vr_table_pending", false)) { BeginPending(); } } } internal bool NearDeck(Vector3 point, float extra) { //IL_0015: 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_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_0030: 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) if (!Object.op_Implicit((Object)(object)Deck)) { return false; } Vector3 val = Deck.InverseTransformPoint(point); if (Mathf.Abs(val.x) <= 1.8f + extra && Mathf.Abs(val.z) <= Length * 0.5f + extra) { return Mathf.Abs(val.y) <= 4f; } return false; } internal static bool BlocksVehicle(RailVehicle cart) { return Tables.Any((RailTurntable t) => Object.op_Implicit((Object)(object)t) && t.Ready && (t.Busy || !t.Aligned) && t.NearDeck(((Component)cart).transform.position, 1.5f)); } private bool Operator(long peer, long playerId, out Player player) { //IL_006d: 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_0085: 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_00db: 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) player = Player.GetPlayer(playerId); if (Ready && RailSettings.Ready && Object.op_Implicit((Object)(object)player) && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && ((Character)player).GetOwner() == peer && !((Character)player).IsAttached() && player.GetDoodadController() == null && Vector3.Distance(((Component)player).transform.position, Object.op_Implicit((Object)(object)Lever) ? Lever.position : ((Component)this).transform.position) <= 4f && RailWardAccess.Allows(((Component)this).transform.position, playerId)) { return RailWardAccess.Allows(Object.op_Implicit((Object)(object)Lever) ? Lever.position : ((Component)this).transform.position, playerId); } return false; } public string GetHoverName() { return "Rail turntable — " + Length.ToString("0") + " m"; } public string GetHoverText() { return Localization.instance.Localize(GetHoverName() + "\n[$KEY_Use] Turn clockwise 45°\n[$KEY_AltPlace + $KEY_Use] Turn counterclockwise 45°" + (Busy ? "\nTurning / preparing — keep clear" : ((!Aligned) ? "\nPaused between exits: clear the area and use the crank to finish." : "\nPark the entire train on the deck, close storage and dismount."))); } public bool Interact(Humanoid user, bool hold, bool alt) { if (!hold) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && Ready) { if (Time.unscaledTime < _nextRequest) { return false; } _nextRequest = Time.unscaledTime + 0.75f; if (Busy) { Tell("Wait for the turntable to finish."); return false; } if (!Operator(((Character)val).GetOwner(), val.GetPlayerID(), out Player _)) { Tell("Stand beside the crank, dismount, and check ward access."); return false; } if (!_view.HasOwner()) { Tell("Waiting for the turntable's owner."); return false; } _view.InvokeRPC("VR_TableTurn_v1", new object[2] { val.GetPlayerID(), (!alt) ? 1 : (-1) }); return true; } } return false; } private void RequestTurn(long sender, long playerId, int direction) { //IL_012a: Unknown result type (might be due to invalid IL or missing references) if (!Ready || !_view.IsOwner() || (direction != -1 && direction != 1) || Time.unscaledTime < _nextOwnerRequest) { return; } _nextOwnerRequest = Time.unscaledTime + 0.3f; if (Busy || !Operator(sender, playerId, out Player _)) { Reply(sender, "Stand beside the crank and wait for the current turn to finish."); return; } if (!RailVehicle.CollectTurntable(this, playerId, out List _, out long owner, out string reason)) { Reply(sender, reason); return; } if (owner == 0L) { owner = _view.GetZDO().GetOwner(); } ZDO zDO = _view.GetZDO(); zDO.Set("vr_table_peer", sender); zDO.Set("vr_table_player", playerId); zDO.Set("vr_table_direction", direction); zDO.Set("vr_table_token", Guid.NewGuid().ToString("N")); zDO.Set("vr_table_until", Now + 6000); zDO.Set("vr_table_pending", true); RailSegment.Network.SetIsolated(PathId, isolated: true); if (owner != zDO.GetOwner()) { zDO.SetOwner(owner); if (ZDOMan.instance != null) { ZDOMan.instance.ForceSendZDO(owner, zDO.m_uid); } } else { BeginPending(); } } private void BeginPending() { if (!_view.IsOwner() || _turn != null) { return; } ZDO zDO = _view.GetZDO(); _peer = zDO.GetLong("vr_table_peer", 0L); _player = zDO.GetLong("vr_table_player", 0L); int num = zDO.GetInt("vr_table_direction", 0); _token = zDO.GetString("vr_table_token", ""); string reason = "The turntable request expired or its operator moved away. Try the crank again."; if (!Busy || _token.Length != 32 || (num != 1 && num != -1) || !Operator(_peer, _player, out Player _) || !RailVehicle.CollectTurntable(this, _player, out List members, out long owner, out reason)) { Stop(reason); return; } if (owner != 0L && owner != zDO.GetOwner()) { Stop("The train's ownership changed. Wait for it to settle and try again."); return; } _target = ((num > 0) ? ((Mathf.Floor((_angle + 0.01f) / 45f) + 1f) * 45f) : ((Mathf.Ceil((_angle - 0.01f) / 45f) - 1f) * 45f)); if (!ClearSweep(members, _angle, _target)) { Stop("Clear the turntable's turning area of people, animals, loose items and structures."); return; } _turn = members; zDO.Set("vr_table_pending", false); zDO.Set("vr_table_until", Now + 6000); Reply(_peer, "Turning the " + Length.ToString("0") + " m deck. Keep the turning area clear."); } private void FixedUpdate() { //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02b8: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) if (_turn == null || !Ready || !_view.IsOwner()) { return; } if (!RailSettings.Ready || _view.GetZDO().GetString("vr_table_token", "") != _token || !Operator(_peer, _player, out Player _) || !RailVehicle.CollectTurntable(this, _player, out List members, out long owner, out string _) || (owner != 0L && owner != _view.GetZDO().GetOwner()) || !RailVehicle.SameTurntableMembers(_turn, members)) { Stop("Turntable paused: its operator, train or ownership changed. Clear the area and use the crank again."); return; } _turn = members; float num = _angle; if (_target < 0f && num > 180f) { num -= 360f; } if (_target >= 360f && num < 180f) { num += 360f; } float num2 = Mathf.MoveTowards(num, _target, 15f * Time.fixedDeltaTime); if (!ClearSweep(_turn, num, num2)) { Stop("Turntable paused: something entered its turning area. Clear it and use the crank again."); return; } (ZNetView, Vector3, Quaternion)[] array = (from v in _turn.SelectMany((RailVehicle.TurntableMember m) => m.Objects).Distinct() select (View: v, Position: ((Component)v).transform.position, Rotation: ((Component)v).transform.rotation)).ToArray(); try { SetGeometry(num2, refresh: true); foreach (RailVehicle.TurntableMember item in _turn) { item.Cart.TurntableMove(item); } _view.GetZDO().Set("vr_table_angle", _angle); _view.GetZDO().Set("vr_table_until", Now + 6000); } catch (Exception error) { SetGeometry(num, refresh: true); (ZNetView, Vector3, Quaternion)[] array2 = array; for (int num3 = 0; num3 < array2.Length; num3++) { (ZNetView, Vector3, Quaternion) tuple = array2[num3]; if (Object.op_Implicit((Object)(object)tuple.Item1) && tuple.Item1.IsValid() && tuple.Item1.IsOwner()) { Rigidbody component = ((Component)tuple.Item1).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { component.position = tuple.Item2; component.rotation = tuple.Item3; } ((Component)tuple.Item1).transform.SetPositionAndRotation(tuple.Item2, tuple.Item3); tuple.Item1.GetZDO().SetPosition(tuple.Item2); tuple.Item1.GetZDO().SetRotation(tuple.Item3); } } _view.GetZDO().Set("vr_table_angle", _angle); RailPlugin.Error(error); Stop("Turntable paused because its train could not be moved. Check the mod log."); return; } if (Mathf.Abs(num2 - _target) < 0.001f) { Stop("Turntable aligned. The train can leave through either connected end."); } } private bool ClearSweep(IReadOnlyList members, float from, float to) { //IL_00ca: 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_00ee: 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_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_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: 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_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_01ab: 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_01c0: 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_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: 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_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0208: 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_021e: Unknown result type (might be due to invalid IL or missing references) HashSet hashSet = new HashSet { ((Component)this).transform }; foreach (RailVehicle.TurntableMember member in members) { foreach (ZNetView @object in member.Objects) { hashSet.Add(((Component)@object).transform); } } int num = Mathf.Max(1, Mathf.CeilToInt(Mathf.Abs(to - from) / 2f)); float num2 = Mathf.Abs(to - from) / (float)num; float num3 = (float)VikingRail.Core.RailTurntable.SweepPadding(VikingRail.Core.RailTurntable.DeckRadius(Length), num2) + 0.01f; Quaternion val = Quaternion.Euler(0f, _angle, 0f); for (int i = 0; i <= num; i++) { float num4 = Mathf.Lerp(from, to, (float)i / (float)num); Quaternion val2 = ((Component)this).transform.rotation * Quaternion.Euler(0f, num4, 0f); Quaternion val3 = val2 * Quaternion.Inverse(((Component)this).transform.rotation * val); if (!ClearBox(((Component)this).transform.position + ((Component)this).transform.up * 0.2f, new Vector3(1.8f + num3, 0.19f, Length * 0.5f + num3), val2, hashSet)) { return false; } foreach (RailVehicle.TurntableMember member2 in members) { Vector3 val4 = ((Component)this).transform.position + val3 * (((Component)member2.Cart).transform.position - ((Component)this).transform.position); Quaternion val5 = val3 * ((Component)member2.Cart).transform.rotation; if (!ClearBox(val4 + val5 * ((Bounds)(ref member2.Bounds)).center, ((Bounds)(ref member2.Bounds)).extents + new Vector3(num3, 0.005f, num3), val5, hashSet)) { return false; } } } return true; } private bool ClearBox(Vector3 center, Vector3 half, Quaternion rotation, HashSet ignored) { //IL_0000: 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_0028: 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_003c: 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_0050: 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_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: 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_017b: 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_005d: 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_005f: 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) if (!RailWardAccess.Allows(center, _player)) { return false; } Vector3 val = default(Vector3); for (int i = 0; i < 8; i++) { ((Vector3)(ref val))..ctor(((i & 1) == 0) ? (0f - half.x) : half.x, ((i & 2) == 0) ? (0f - half.y) : half.y, ((i & 4) == 0) ? (0f - half.z) : half.z); if (!RailWardAccess.Allows(center + rotation * val, _player)) { return false; } } int mask = LayerMask.GetMask(new string[10] { "terrain", "piece", "Default", "Default_small", "static_solid", "character", "character_net", "character_ghost", "character_noenv", "vehicle" }); Collider[] array = Physics.OverlapBox(center, half, rotation, mask, (QueryTriggerInteraction)1); foreach (Collider hit in array) { if (!Object.op_Implicit((Object)(object)hit) || ignored.Any((Transform root) => ((Component)hit).transform.IsChildOf(root))) { continue; } if (Object.op_Implicit((Object)(object)((Component)hit).GetComponentInParent()) || Object.op_Implicit((Object)(object)((Component)hit).GetComponentInParent())) { Bounds bounds = hit.bounds; if (((Bounds)(ref bounds)).max.y <= ((Component)this).transform.position.y + 0.18f && (((Object)hit).name == "rail" || ((Object)hit).name == "sleeper" || ((Object)hit).name == "switch_rail" || ((Object)hit).name == "switch_sleeper")) { continue; } } return false; } return true; } private void Stop(string reason) { _turn = null; if (Object.op_Implicit((Object)(object)_view) && _view.IsValid() && _view.IsOwner()) { _view.GetZDO().Set("vr_table_pending", false); _view.GetZDO().Set("vr_table_until", 0L); _view.GetZDO().Set("vr_table_token", ""); if (PathId.Length != 0) { RailSegment.Network.SetIsolated(PathId, !Aligned); } if (_peer != 0L) { Reply(_peer, reason); } } } private void Reply(long peer, string message) { _view.InvokeRPC(peer, "VR_TableReply_v1", new object[1] { message }); } private void ReceiveReply(long sender, string message) { //IL_0031: 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_0049: Unknown result type (might be due to invalid IL or missing references) if (Ready && sender == _view.GetZDO().GetOwner() && Object.op_Implicit((Object)(object)Player.m_localPlayer) && !(Vector3.Distance(((Component)Player.m_localPlayer).transform.position, Object.op_Implicit((Object)(object)Lever) ? Lever.position : ((Component)this).transform.position) > 5f)) { Tell(message); } } private static void Tell(string text) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); } } private void OnDestroy() { Tables.Remove(this); _turn = null; } } public sealed class RailTurntableLever : MonoBehaviour, Hoverable, Interactable { public RailTurntable Table; public float GetHoverOffset() { return 0f; } public string GetHoverName() { if (!Object.op_Implicit((Object)(object)Table)) { return "Rail turntable"; } return Table.GetHoverName(); } public string GetHoverText() { if (!Object.op_Implicit((Object)(object)Table)) { return ""; } return Table.GetHoverText(); } public bool Interact(Humanoid user, bool hold, bool alt) { if (Object.op_Implicit((Object)(object)Table)) { return Table.Interact(user, hold, alt); } return false; } public bool UseItem(Humanoid user, ItemData item) { return false; } } [HarmonyPatch(typeof(Piece), "CanBeRemoved")] internal static class TurntableRemovalPatch { [HarmonyPostfix] private static void Postfix(Piece __instance, ref bool __result) { RailTurntable component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component) && !component.CanRemove) { __result = false; } } } [HarmonyPatch(typeof(WearNTear), "RPC_Remove")] internal static class TurntableRemoveOwnerPatch { [HarmonyPrefix] private static bool Prefix(WearNTear __instance) { RailTurntable component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { return component.CanRemove; } return true; } } public sealed class RailLampSwitch : MonoBehaviour, Hoverable, Interactable { private RailVehicle? _cart; private void Awake() { _cart = ((Component)this).GetComponentInParent(); } public float GetHoverOffset() { return 0f; } public string GetHoverName() { return "Rail lamps"; } public string GetHoverText() { return Localization.instance.Localize(GetHoverName() + "\n[$KEY_Use] Turn " + ((Object.op_Implicit((Object)(object)_cart) && _cart.LightsOn) ? "off" : "on")); } public bool Interact(Humanoid user, bool hold, bool alt) { if (!hold && !alt && Object.op_Implicit((Object)(object)_cart)) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null) { return _cart.ToggleLights(val); } } return false; } public bool UseItem(Humanoid user, ItemData item) { return false; } } internal static class RailWardAccess { private static readonly FieldInfo? Areas = AccessTools.Field(typeof(PrivateArea), "m_allAreas"); private static readonly MethodInfo? Enabled = AccessTools.Method(typeof(PrivateArea), "IsEnabled", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo? Inside = AccessTools.Method(typeof(PrivateArea), "IsInside", new Type[2] { typeof(Vector3), typeof(float) }, (Type[])null); private static readonly MethodInfo? Permitted = AccessTools.Method(typeof(PrivateArea), "IsPermitted", new Type[1] { typeof(long) }, (Type[])null); internal static bool Allows(Vector3 point, long playerId, float radius = 0f) { //IL_00af: Unknown result type (might be due to invalid IL or missing references) if (float.IsNaN(radius) || float.IsInfinity(radius) || radius < 0f) { return false; } if (Areas == null || Enabled == null || Inside == null || Permitted == null || !(Areas.GetValue(null) is IEnumerable enumerable)) { return false; } bool flag = false; foreach (PrivateArea item in enumerable) { if (Object.op_Implicit((Object)(object)item) && true.Equals(Enabled.Invoke(item, null)) && true.Equals(Inside.Invoke(item, new object[2] { point, radius }))) { Piece component = ((Component)item).GetComponent(); if ((Object.op_Implicit((Object)(object)component) && component.GetCreator() == playerId) || true.Equals(Permitted.Invoke(item, new object[1] { playerId }))) { return true; } flag = true; } } return !flag; } } [HarmonyPatch(typeof(Piece), "CanBeRemoved")] internal static class OccupiedRailPieceRemovalPatch { [HarmonyPostfix] private static void Postfix(Piece __instance, ref bool __result) { RailVehicle component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component) && (!component.IsReady || component.TrainOccupied || component.TrainHasPassengers || component.CargoServiceBusy || component.CouplingServiceBusy)) { __result = false; } RailSwitch component2 = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component2) && component2.IsOccupied) { __result = false; } } } [HarmonyPatch(typeof(WearNTear), "RPC_Remove")] internal static class OccupiedRailRemovalRequestPatch { [HarmonyPrefix] private static bool Prefix(WearNTear __instance) { RailVehicle component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component) && (!component.IsReady || component.TrainOccupied || component.TrainHasPassengers || component.CargoServiceBusy || component.CouplingServiceBusy)) { return false; } RailSwitch component2 = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component2)) { return !component2.IsOccupied; } return true; } } [HarmonyPatch(typeof(Humanoid), "UseItem", new Type[] { typeof(Inventory), typeof(ItemData), typeof(bool) })] internal static class PackedRailVehicleUsePatch { [HarmonyPrefix] private static bool Prefix(Humanoid __instance, Inventory __0, ItemData __1) { return !RailVehicle.TryPlacePackedVehicle(__instance, __0, __1); } } public sealed class RailPackingHandle : MonoBehaviour, Hoverable, Interactable { private RailVehicle? _cart; private void Awake() { _cart = ((Component)this).GetComponentInParent(); } public float GetHoverOffset() { return 0f; } public string GetHoverName() { return "Vehicle packing handle"; } public string GetHoverText() { return Localization.instance.Localize(GetHoverName() + "\n[$KEY_Use] Pack vehicle for pickup"); } public bool Interact(Humanoid user, bool hold, bool alt) { if (!hold && !alt && Object.op_Implicit((Object)(object)_cart)) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null) { return _cart.BeginPack(val); } } return false; } public bool UseItem(Humanoid user, ItemData item) { return false; } } [HarmonyPatch(typeof(WearNTear), "RPC_Damage")] internal static class PackedVehicleDamagePatch { [HarmonyPrefix] private static bool Prefix(WearNTear __instance) { RailVehicle component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { return !component.IsPacked; } return true; } } [HarmonyPatch(typeof(WearNTear), "Destroy", new Type[] { typeof(HitData), typeof(bool) })] internal static class PackedVehicleDestructionPatch { [HarmonyPrefix] private static bool Prefix(WearNTear __instance) { RailVehicle component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { return !component.IsPacked; } return true; } } public sealed class RailWorkshopCart : MonoBehaviour { private static readonly HashSet Loaded = new HashSet(); public string UpgradePrefab = ""; public string DisplayName = "Rail workbench cart"; public bool RepairStation; private RailVehicle _cart; private CraftingStation? _station; private Bounds _collisionBounds; private bool _hasBounds; internal bool Ready { get { if (Object.op_Implicit((Object)(object)_cart)) { return _cart.IsReady; } return false; } } internal bool CanUse { get { if (Ready && RailSettings.Ready) { return _cart.WorkshopTrainParked; } return false; } } private void OnEnable() { Loaded.Add(this); } private void OnDisable() { Loaded.Remove(this); } private void Awake() { //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_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_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_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: 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_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_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014f: 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_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0192: 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_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //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_01b5: Unknown result type (might be due to invalid IL or missing references) _cart = ((Component)this).GetComponent(); _station = ((Component)this).GetComponent(); Collider[] componentsInChildren = ((Component)this).GetComponentsInChildren(true); Bounds bounds = default(Bounds); foreach (Collider val in componentsInChildren) { if (!val.enabled || val.isTrigger || !((Component)val).gameObject.activeInHierarchy) { continue; } BoxCollider val2 = (BoxCollider)(object)((val is BoxCollider) ? val : null); if (val2 != null) { ((Bounds)(ref bounds))..ctor(val2.center, val2.size); } else { MeshCollider val3 = (MeshCollider)(object)((val is MeshCollider) ? val : null); if (val3 != null && Object.op_Implicit((Object)(object)val3.sharedMesh)) { bounds = val3.sharedMesh.bounds; } else { SphereCollider val4 = (SphereCollider)(object)((val is SphereCollider) ? val : null); if (val4 != null) { ((Bounds)(ref bounds))..ctor(val4.center, Vector3.one * val4.radius * 2f); } else { CapsuleCollider val5 = (CapsuleCollider)(object)((val is CapsuleCollider) ? val : null); if (val5 == null) { continue; } Vector3 val6 = Vector3.one * val5.radius * 2f; ((Vector3)(ref val6))[val5.direction] = Mathf.Max(val5.height, ((Vector3)(ref val6))[val5.direction]); ((Bounds)(ref bounds))..ctor(val5.center, val6); } } } for (int j = 0; j < 8; j++) { Vector3 val7 = ((Bounds)(ref bounds)).center + Vector3.Scale(((Bounds)(ref bounds)).extents, new Vector3((float)(((j & 1) != 0) ? 1 : (-1)), (float)(((j & 2) != 0) ? 1 : (-1)), (float)(((j & 4) != 0) ? 1 : (-1)))); Vector3 val8 = ((Component)this).transform.InverseTransformPoint(((Component)val).transform.TransformPoint(val7)); if (!_hasBounds) { _collisionBounds = new Bounds(val8, Vector3.zero); _hasBounds = true; } else { ((Bounds)(ref _collisionBounds)).Encapsulate(val8); } } } } internal bool TryGetCollisionBounds(out Bounds bounds) { //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) bounds = _collisionBounds; return _hasBounds; } internal string HoverText() { return Localization.instance.Localize(DisplayName + (RepairStation ? "\n[$KEY_Use] Repair workbench / forge equipment (park train first)" : (Object.op_Implicit((Object)(object)_station) ? "\n[$KEY_Use] Use workbench (park train first)" : "\nWorkbench upgrade")) + "\n[$KEY_AltPlace + $KEY_Use] Couple / uncouple"); } internal bool Interact(Player player, bool alt) { if (!alt) { if (!RepairStation) { if (Object.op_Implicit((Object)(object)_station)) { return _station.Interact((Humanoid)(object)player, false, false); } return false; } return ((Component)this).GetComponent().Interact(player); } return _cart.ToggleCoupling(player); } private void Update() { Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)_station) && Object.op_Implicit((Object)(object)localPlayer) && !((Object)(object)localPlayer.GetCurrentCraftingStation() != (Object)(object)_station) && !CanUse) { CloseLocalWorkbench(localPlayer); } } private void OnDestroy() { Loaded.Remove(this); Player localPlayer = Player.m_localPlayer; if (Object.op_Implicit((Object)(object)_station) && Object.op_Implicit((Object)(object)localPlayer) && (Object)(object)localPlayer.GetCurrentCraftingStation() == (Object)(object)_station) { CloseLocalWorkbench(localPlayer); } } private static void CloseLocalWorkbench(Player player) { if (Object.op_Implicit((Object)(object)InventoryGui.instance)) { InventoryGui.instance.Hide(); } player.SetCraftingStation((CraftingStation)null); } internal static void Extend(CraftingStation station, List extensions) { //IL_00c4: 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) RailWorkshopCart component = ((Component)station).GetComponent(); bool flag = Object.op_Implicit((Object)(object)component); foreach (StationExtension extension in extensions) { if (Object.op_Implicit((Object)(object)extension) && Object.op_Implicit((Object)(object)((Component)extension).GetComponent())) { flag = true; break; } } foreach (RailWorkshopCart item in Loaded) { if (!Object.op_Implicit((Object)(object)item) || !item.Ready) { continue; } StationExtension component2 = ((Component)item).GetComponent(); if (Object.op_Implicit((Object)(object)component2) && Object.op_Implicit((Object)(object)component2.m_craftingStation) && !(component2.m_craftingStation.m_name != station.m_name) && !(Vector3.Distance(((Component)item).transform.position, ((Component)station).transform.position) >= component2.m_maxStationDistance) && item.CanUse) { flag = true; if (!extensions.Contains(component2)) { extensions.Add(component2); } } } if (!flag) { return; } if (Object.op_Implicit((Object)(object)component) && component.Ready && component._cart.TryWorkshopTrain(out List train)) { foreach (RailVehicle item2 in train) { StationExtension component3 = ((Component)item2).GetComponent(); if (Object.op_Implicit((Object)(object)component3) && Object.op_Implicit((Object)(object)component3.m_craftingStation) && component3.m_craftingStation.m_name == station.m_name && !extensions.Contains(component3)) { extensions.Add(component3); } } } HashSet hashSet = new HashSet(StringComparer.Ordinal); int num = 0; while (num < extensions.Count) { StationExtension val = extensions[num]; if (!Object.op_Implicit((Object)(object)val)) { extensions.RemoveAt(num); continue; } RailWorkshopCart component4 = ((Component)val).GetComponent(); if (Object.op_Implicit((Object)(object)component4) && !component4.CanUse) { extensions.RemoveAt(num); continue; } string text = (Object.op_Implicit((Object)(object)component4) ? component4.UpgradePrefab : Utils.GetPrefabName(((Component)val).gameObject)); if (RailWorkshopUpgrades.IsWorkbenchUpgrade(text) && !hashSet.Add(text)) { extensions.RemoveAt(num); } else { num++; } } } } [HarmonyPatch(typeof(CraftingStation), "Interact")] internal static class RailWorkbenchInteractionPatch { [HarmonyPrefix] private static bool Prefix(CraftingStation __instance, Humanoid user, bool repeat, bool alt, ref bool __result) { RailWorkshopCart component = ((Component)__instance).GetComponent(); if (!Object.op_Implicit((Object)(object)component) || !alt) { return true; } int num; if (!repeat && component.Ready) { Player val = (Player)(object)((user is Player) ? user : null); if (val != null) { num = (component.Interact(val, alt: true) ? 1 : 0); goto IL_0036; } } num = 0; goto IL_0036; IL_0036: __result = (byte)num != 0; return false; } } [HarmonyPatch(typeof(CraftingStation), "CheckUsable")] internal static class RailWorkbenchUsabilityPatch { [HarmonyPrefix] private static bool Prefix(CraftingStation __instance, Player player, bool showMessage, ref bool __result) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) RailWorkshopCart component = ((Component)__instance).GetComponent(); if (!Object.op_Implicit((Object)(object)component)) { return true; } if (component.CanUse && Object.op_Implicit((Object)(object)player) && !((Character)player).IsDead() && !((Character)player).IsTeleporting() && !((Character)player).IsAttached() && PrivateArea.CheckAccess(((Component)__instance).transform.position, 0f, true, false)) { return true; } if (showMessage && Object.op_Implicit((Object)(object)player)) { ((Character)player).Message((MessageType)2, "Park the train, leave the controls, and stand beside the workbench with permission to use it.", 0, (Sprite)null, false); } __result = false; return false; } } [HarmonyPatch(typeof(CraftingStation), "GetHoverText")] internal static class RailWorkbenchHoverPatch { [HarmonyPostfix] private static void Postfix(CraftingStation __instance, ref string __result) { RailWorkshopCart component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { __result = component.HoverText(); } } } [HarmonyPatch(typeof(StationExtension), "GetHoverText")] internal static class RailWorkshopUpgradeHoverPatch { [HarmonyPostfix] private static void Postfix(StationExtension __instance, ref string __result) { RailWorkshopCart component = ((Component)__instance).GetComponent(); if (Object.op_Implicit((Object)(object)component)) { __result = component.HoverText(); } } } [HarmonyPatch(typeof(StationExtension), "FindExtensions")] internal static class RailWorkshopExtensionsPatch { [HarmonyPostfix] private static void Postfix(CraftingStation __0, List __2) { RailWorkshopCart.Extend(__0, __2); } } } namespace VikingRail.Core { public readonly struct CoalFuelPlan { public bool CanPower { get; } public int CoalToConsume { get; } public double RemainingSeconds { get; } internal CoalFuelPlan(bool canPower, int coalToConsume, double remainingSeconds) { CanPower = canPower; CoalToConsume = coalToConsume; RemainingSeconds = remainingSeconds; } } public static class CoalFuelBudget { public const double SecondsPerCoal = 90.0; public const double MaximumSecondsPerCoal = 86400.0; public static CoalFuelPlan Plan(double remainingSeconds, int availableCoal, double poweredSeconds, double secondsPerCoal = 90.0) { try { FuelPlan fuelPlan = FuelBudget.Plan(remainingSeconds, availableCoal, poweredSeconds, secondsPerCoal); return new CoalFuelPlan(fuelPlan.CanPower, fuelPlan.ItemsToConsume, fuelPlan.RemainingSeconds); } catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "availableItems") { throw new ArgumentOutOfRangeException("availableCoal"); } catch (ArgumentOutOfRangeException ex2) when (ex2.ParamName == "secondsPerItem") { throw new ArgumentOutOfRangeException("secondsPerCoal", "Coal burn time must be between 1 and 86400 seconds."); } } } internal sealed class ContainerRpcResponse { internal MethodInfo Method { get; } internal string RpcName { get; } internal ContainerRpcResponse(MethodInfo method, string rpcName) { Method = method; RpcName = rpcName; } } internal static class ContainerRpcCompatibility { internal static ContainerRpcResponse Open(Type containerType) { return Resolve(containerType, "RPC_OpenResponse", "RPC_OpenRespons", "OpenRespons"); } internal static ContainerRpcResponse TakeAll(Type containerType) { return Resolve(containerType, "RPC_TakeAllResponse", "RPC_TakeAllRespons", "TakeAllRespons"); } internal static ContainerRpcResponse Stack(Type containerType) { return Resolve(containerType, "RPC_StackResponse", null, null); } private static ContainerRpcResponse Resolve(Type containerType, string currentName, string? legacyName, string? legacyRpcName) { MethodInfo methodInfo = FindResponse(containerType, currentName); if (methodInfo != null) { return new ContainerRpcResponse(methodInfo, currentName); } if (legacyName != null) { methodInfo = FindResponse(containerType, legacyName); if (methodInfo != null) { return new ContainerRpcResponse(methodInfo, legacyRpcName); } } throw new MissingMethodException(containerType.FullName, currentName + ((legacyName == null) ? "" : (" or " + legacyName)) + " (long, bool) -> void"); } private static MethodInfo? FindResponse(Type containerType, string name) { MethodInfo method = containerType.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[2] { typeof(long), typeof(bool) }, null); if (method == null || method.ReturnType != typeof(void) || method.ContainsGenericParameters) { return null; } ParameterInfo[] parameters = method.GetParameters(); if (parameters.Length != 2 || !(parameters[0].ParameterType == typeof(long)) || !(parameters[1].ParameterType == typeof(bool))) { return null; } return method; } } public readonly struct FuelPlan { public bool CanPower { get; } public int ItemsToConsume { get; } public double RemainingSeconds { get; } internal FuelPlan(bool canPower, int itemsToConsume, double remainingSeconds) { CanPower = canPower; ItemsToConsume = itemsToConsume; RemainingSeconds = remainingSeconds; } } public static class FuelBudget { public const double MaximumSecondsPerItem = 86400.0; private const double RoundingTolerance = 1E-09; public static FuelPlan Plan(double remainingSeconds, int availableItems, double poweredSeconds, double secondsPerItem) { Guard.Finite(remainingSeconds, "remainingSeconds"); Guard.Finite(poweredSeconds, "poweredSeconds"); Guard.Finite(secondsPerItem, "secondsPerItem"); if (secondsPerItem < 1.0 || secondsPerItem > 86400.0) { throw new ArgumentOutOfRangeException("secondsPerItem", "Fuel burn time must be between 1 and 86400 seconds."); } if (remainingSeconds < 0.0 || remainingSeconds > 86400.0) { throw new ArgumentOutOfRangeException("remainingSeconds", "Fuel credit must be between zero and 86400 seconds."); } if (availableItems < 0) { throw new ArgumentOutOfRangeException("availableItems"); } if (poweredSeconds < 0.0) { throw new ArgumentOutOfRangeException("poweredSeconds"); } double num = poweredSeconds - remainingSeconds; if (num <= 0.0 || (remainingSeconds > 0.0 && num <= 1E-09)) { return new FuelPlan(canPower: true, 0, Math.Max(0.0, 0.0 - num)); } double num2 = Math.Max(1.0, Math.Ceiling(num / secondsPerItem)); if (num2 > (double)availableItems) { return new FuelPlan(canPower: false, 0, remainingSeconds); } int num3 = (int)num2; double remainingSeconds2 = Math.Max(0.0, (double)num3 * secondsPerItem - num); return new FuelPlan(canPower: true, num3, remainingSeconds2); } } public static class PackedPlow { public const string MetalItem = "vr_plow_packed"; public const string WoodenItem = "vr_plow_wood_packed"; public const string HealthKey = "vikingrail_plow_health"; public static string PieceName(string itemName) { if (!(itemName == "vr_plow_packed")) { if (!(itemName == "vr_plow_wood_packed")) { return ""; } return "vr_plow_wood"; } return "vr_plow"; } public static string ItemName(string pieceName) { if (!(pieceName == "vr_plow")) { if (!(pieceName == "vr_plow_wood")) { return ""; } return "vr_plow_wood_packed"; } return "vr_plow_packed"; } public static string EncodeHealth(float health, float maximum) { return Normalize(health, maximum).ToString("R", CultureInfo.InvariantCulture); } public static float ReadHealth(IReadOnlyDictionary data, float maximum) { if (!data.TryGetValue("vikingrail_plow_health", out string value) || !float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return maximum; } return Normalize(result, maximum); } private static float Normalize(float health, float maximum) { if (maximum <= 0f || float.IsNaN(maximum) || float.IsInfinity(maximum)) { throw new ArgumentOutOfRangeException("maximum"); } if (float.IsNaN(health) || float.IsInfinity(health)) { return maximum; } return Math.Max(0.01f, Math.Min(maximum, health)); } } public static class PackedPlowPlacement { public const double SocketRange = 2.5; private static readonly RailVector[] GroundOffsets = new RailVector[12] { new RailVector(0.0, 0.0, 2.0), new RailVector(0.0, 0.0, 2.5), new RailVector(0.0, 0.0, 1.5), new RailVector(0.75, 0.0, 2.0), new RailVector(-0.75, 0.0, 2.0), new RailVector(1.25, 0.0, 2.0), new RailVector(-1.25, 0.0, 2.0), new RailVector(0.0, 0.0, 3.0), new RailVector(0.75, 0.0, 2.75), new RailVector(-0.75, 0.0, 2.75), new RailVector(1.25, 0.0, 2.75), new RailVector(-1.25, 0.0, 2.75) }; public static bool TargetsSocket(RailVector player, RailVector look, RailVector socket) { RailVector railVector = socket - player; if (railVector.Magnitude > 2.5) { return false; } RailVector railVector2 = new RailVector(railVector.X, 0.0, railVector.Z); RailVector railVector3 = new RailVector(look.X, 0.0, look.Z); if (railVector2.Magnitude < 0.2 || railVector3.Magnitude < 0.001) { return false; } return RailVector.Dot(railVector2.Normalized(), railVector3.Normalized()) >= 0.5; } public static bool TryGround(RailVector origin, RailVector look, Func validate, out RailVector position) { if (validate == null) { throw new ArgumentNullException("validate"); } position = default(RailVector); RailVector railVector = new RailVector(look.X, 0.0, look.Z); if (railVector.Magnitude < 0.001) { return false; } railVector = railVector.Normalized(); RailVector railVector2 = new RailVector(railVector.Z, 0.0, 0.0 - railVector.X); RailVector[] groundOffsets = GroundOffsets; for (int i = 0; i < groundOffsets.Length; i++) { RailVector railVector3 = groundOffsets[i]; RailVector? railVector4 = validate(origin + railVector * railVector3.Z + railVector2 * railVector3.X); if (railVector4.HasValue) { position = railVector4.Value; return true; } } return false; } } public static class PackedVehicle { public const string HandcartItem = "vr_handcart_packed"; public const string TandemHandcartItem = "vr_handcart_tandem_packed"; public const string BronzeEngineItem = "vr_bronze_engine_packed"; public const string EitrEngineItem = "vr_eitr_engine_packed"; public const string MountCartItem = "vr_mount_cart_packed"; public const string MusicCartItem = "vr_music_cart_packed"; public const string PumpkinCartItem = "vr_pumpkin_cart_packed"; public const string LocomotiveItem = "vr_locomotive_packed"; public const string StorageItem = "vr_storagecart_packed"; public const string PassengerItem = "vr_passengercart_packed"; public const string WorkbenchItem = "vr_workbench_cart_packed"; public const string ChoppingItem = "vr_workbench_chopping_cart_packed"; public const string TanningItem = "vr_workbench_tanning_cart_packed"; public const string AdzeItem = "vr_workbench_adze_cart_packed"; public const string ToolrackItem = "vr_workbench_toolrack_cart_packed"; public const string RepairItem = "vr_repair_cart_packed"; public const string VersionKey = "vikingrail_vehicle_version"; public const string CurrentVersion = "1"; public const string HealthKey = "vikingrail_vehicle_health"; public const string FuelKey = "vikingrail_vehicle_fuel_seconds"; public const string LampsKey = "vikingrail_vehicle_lamps"; public const string InventoryKey = "vikingrail_vehicle_inventory"; public const string CargoWeightKey = "vikingrail_vehicle_cargo_weight"; public const string TeleportableKey = "vikingrail_vehicle_teleportable"; public static string PieceName(string itemName) { return itemName switch { "vr_repair_cart_packed" => "vr_repair_cart", "vr_workbench_toolrack_cart_packed" => "vr_workbench_toolrack_cart", "vr_workbench_adze_cart_packed" => "vr_workbench_adze_cart", "vr_workbench_tanning_cart_packed" => "vr_workbench_tanning_cart", "vr_workbench_chopping_cart_packed" => "vr_workbench_chopping_cart", "vr_workbench_cart_packed" => "vr_workbench_cart", "vr_passengercart_packed" => "vr_passengercart", "vr_storagecart_packed" => "vr_storagecart", "vr_locomotive_packed" => "vr_locomotive", "vr_pumpkin_cart_packed" => "vr_pumpkin_cart", "vr_music_cart_packed" => "vr_music_cart", "vr_mount_cart_packed" => "vr_mount_cart", "vr_eitr_engine_packed" => "vr_eitr_engine", "vr_bronze_engine_packed" => "vr_bronze_engine", "vr_handcart_tandem_packed" => "vr_handcart_tandem", "vr_handcart_packed" => "vr_handcart", _ => "", }; } public static string ItemName(string pieceName) { return pieceName switch { "vr_repair_cart" => "vr_repair_cart_packed", "vr_workbench_toolrack_cart" => "vr_workbench_toolrack_cart_packed", "vr_workbench_adze_cart" => "vr_workbench_adze_cart_packed", "vr_workbench_tanning_cart" => "vr_workbench_tanning_cart_packed", "vr_workbench_chopping_cart" => "vr_workbench_chopping_cart_packed", "vr_workbench_cart" => "vr_workbench_cart_packed", "vr_passengercart" => "vr_passengercart_packed", "vr_storagecart" => "vr_storagecart_packed", "vr_locomotive" => "vr_locomotive_packed", "vr_pumpkin_cart" => "vr_pumpkin_cart_packed", "vr_music_cart" => "vr_music_cart_packed", "vr_mount_cart" => "vr_mount_cart_packed", "vr_eitr_engine" => "vr_eitr_engine_packed", "vr_bronze_engine" => "vr_bronze_engine_packed", "vr_handcart_tandem" => "vr_handcart_tandem_packed", "vr_handcart" => "vr_handcart_packed", _ => "", }; } public static float BaseWeight(string pieceName) { return pieceName switch { "vr_repair_cart" => 45f, "vr_workbench_toolrack_cart" => 35f, "vr_workbench_adze_cart" => 30f, "vr_workbench_tanning_cart" => 30f, "vr_workbench_chopping_cart" => 30f, "vr_workbench_cart" => 40f, "vr_passengercart" => 25f, "vr_storagecart" => 20f, "vr_locomotive" => 60f, "vr_pumpkin_cart" => 35f, "vr_music_cart" => 35f, "vr_mount_cart" => 35f, "vr_eitr_engine" => 60f, "vr_bronze_engine" => 45f, "vr_handcart_tandem" => 35f, "vr_handcart" => 25f, _ => throw new ArgumentException("Unknown packed vehicle type.", "pieceName"), }; } public static string EncodeHealth(float health, float maximum) { CheckMaximum(maximum); Guard.Finite(health, "health"); if (health <= 0f || health > maximum) { throw new ArgumentOutOfRangeException("health"); } return health.ToString("R", CultureInfo.InvariantCulture); } public static float ReadHealth(IReadOnlyDictionary data, float maximum) { CheckMaximum(maximum); float num = ReadFloat(data, "vikingrail_vehicle_health"); if (num <= 0f || num > maximum) { throw Invalid("vikingrail_vehicle_health"); } return num; } public static string EncodeFuel(double seconds) { Guard.Finite(seconds, "seconds"); if (seconds < 0.0 || seconds > 86400.0) { throw new ArgumentOutOfRangeException("seconds"); } return seconds.ToString("R", CultureInfo.InvariantCulture); } public static double ReadFuel(IReadOnlyDictionary data) { if (!double.TryParse(Read(data, "vikingrail_vehicle_fuel_seconds"), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || double.IsNaN(result) || double.IsInfinity(result) || result < 0.0 || result > 86400.0) { throw Invalid("vikingrail_vehicle_fuel_seconds"); } return result; } public static string EncodeCargoWeight(float weight) { Guard.Finite(weight, "weight"); if (weight < 0f) { throw new ArgumentOutOfRangeException("weight"); } return weight.ToString("R", CultureInfo.InvariantCulture); } public static float ReadCargoWeight(IReadOnlyDictionary data) { float num = ReadFloat(data, "vikingrail_vehicle_cargo_weight"); if (num < 0f) { throw Invalid("vikingrail_vehicle_cargo_weight"); } return num; } public static string EncodeBoolean(bool value) { if (!value) { return "0"; } return "1"; } public static bool ReadBoolean(IReadOnlyDictionary data, string key) { string text = Read(data, key); if (text == "1") { return true; } if (text == "0") { return false; } throw Invalid(key); } private static void CheckMaximum(float maximum) { Guard.Finite(maximum, "maximum"); if (maximum <= 0f) { throw new ArgumentOutOfRangeException("maximum"); } } private static float ReadFloat(IReadOnlyDictionary data, string key) { if (!float.TryParse(Read(data, key), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || float.IsNaN(result) || float.IsInfinity(result)) { throw Invalid(key); } return result; } private static string Read(IReadOnlyDictionary data, string key) { if (data == null) { throw new ArgumentNullException("data"); } if (!data.TryGetValue(key, out string value) || string.IsNullOrEmpty(value)) { throw Invalid(key); } return value; } private static FormatException Invalid(string key) { return new FormatException("Packed vehicle data is missing or invalid: " + key); } } public static class PackedVehicleCargo { public const string CountKey = "vikingrail_vehicle_inventory_count"; public const int MaximumPayloadBytes = 262144; public const int MaximumItemCount = 256; private const int MaximumEncodedLength = 349528; public static string EncodePayload(byte[] payload) { if (payload == null) { throw new ArgumentNullException("payload"); } if (payload.Length == 0 || payload.Length > 262144) { throw new ArgumentException("The cargo's saved data is empty or too large to pack safely.", "payload"); } return Convert.ToBase64String(payload); } public static byte[] DecodePayload(string? encoded) { CheckEncodedLength(encoded); byte[] array = Convert.FromBase64String(encoded); if (array.Length == 0 || array.Length > 262144) { throw new FormatException("The packed inventory is missing or too large."); } return array; } public static int ReadMetadata(IReadOnlyDictionary data, out float weight, out bool teleportable) { if (data == null || !data.TryGetValue("vikingrail_vehicle_version", out string value) || value != "1") { throw new FormatException("The packed vehicle version is missing or unsupported."); } PackedVehicle.ReadHealth(data, float.MaxValue); PackedVehicle.ReadFuel(data); PackedVehicle.ReadBoolean(data, "vikingrail_vehicle_lamps"); weight = PackedVehicle.ReadCargoWeight(data); teleportable = PackedVehicle.ReadBoolean(data, "vikingrail_vehicle_teleportable"); if (!data.TryGetValue("vikingrail_vehicle_inventory_count", out string value2) || !int.TryParse(value2, NumberStyles.None, CultureInfo.InvariantCulture, out var result) || result > 256 || !data.TryGetValue("vikingrail_vehicle_inventory", out string value3)) { throw new FormatException("The packed inventory metadata is missing or invalid."); } CheckEncodedLength(value3); if (result == 0 && (weight != 0f || !teleportable)) { throw new FormatException("An empty packed inventory has inconsistent cargo metadata."); } return result; } private static void CheckEncodedLength(string? encoded) { if (encoded == null || encoded.Length == 0 || encoded.Length > 349528) { throw new FormatException("The packed inventory is missing or too large."); } } } public readonly struct PassengerFireState { public float Fuel { get; } public bool IsOn { get; } internal PassengerFireState(float fuel, bool isOn) { Fuel = fuel; IsOn = isOn; } } public static class PassengerFireFuel { public const string FuelKey = "vikingrail_passenger_fire_fuel"; public const string OnKey = "vikingrail_passenger_fire_on"; public const float DefaultMaximumFuel = 10f; public static void Capture(IDictionary data, float fuel, bool isOn, float maximumFuel = 10f) { if (data == null) { throw new ArgumentNullException("data"); } CheckMaximum(maximumFuel); if (!Finite(fuel) || fuel < 0f || fuel > maximumFuel) { throw new ArgumentOutOfRangeException("fuel"); } string value = fuel.ToString("R", CultureInfo.InvariantCulture); data["vikingrail_passenger_fire_fuel"] = value; data["vikingrail_passenger_fire_on"] = (isOn ? "1" : "0"); } public static PassengerFireState Read(IReadOnlyDictionary data, float maximumFuel = 10f) { if (data == null) { throw new ArgumentNullException("data"); } CheckMaximum(maximumFuel); string value; bool flag = data.TryGetValue("vikingrail_passenger_fire_fuel", out value); string value2; bool flag2 = data.TryGetValue("vikingrail_passenger_fire_on", out value2); if (!flag && !flag2) { return new PassengerFireState(0f, isOn: true); } if (!flag || !flag2 || !float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || !Finite(result) || result < 0f || result > maximumFuel || (value2 != "0" && value2 != "1")) { throw new FormatException("The passenger campfire's saved fuel or switch state is invalid."); } return new PassengerFireState(result, value2 == "1"); } private static void CheckMaximum(float maximum) { if (!Finite(maximum) || maximum <= 0f) { throw new ArgumentOutOfRangeException("maximum"); } } private static bool Finite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } public readonly struct PassengerSeatReservation { public readonly long Player; public readonly long Peer; public readonly string Token; public readonly long ExpiresAt; public PassengerSeatReservation(long player, long peer, string token, long expiresAt) { Player = player; Peer = peer; Token = token ?? ""; ExpiresAt = expiresAt; } public bool IsActive(long now) { if (Player != 0L && Peer != 0L && !string.IsNullOrEmpty(Token)) { return ExpiresAt > now; } return false; } public bool Matches(long player, long peer, string token) { if (player != 0L && peer != 0L && !string.IsNullOrEmpty(token) && Player == player && Peer == peer) { return string.Equals(Token, token, StringComparison.Ordinal); } return false; } public bool CanReserve(long player, long peer, string token, long now) { if (player != 0L && peer != 0L && !string.IsNullOrEmpty(token)) { if (IsActive(now)) { return Matches(player, peer, token); } return true; } return false; } } public static class RailAudioMotion { public const float StopThreshold = 0.025f; public const float MaximumSpeed = 15f; public const long MaximumLeaseTicks = 30000000L; public static float ValidSpeed(float speed) { if (!float.IsNaN(speed) && !float.IsInfinity(speed) && !(speed <= 0.025f) && !(speed > 15f)) { return speed; } return 0f; } public static bool LeaseActive(long nowTicks, long untilTicks, long currentOwner, long publishedOwner, long driverId) { if (currentOwner == 0L || currentOwner != publishedOwner || driverId == 0L || untilTicks <= nowTicks) { return false; } return (ulong)(untilTicks - nowTicks) <= 30000000uL; } public static float RollingPitch(float speed, bool coal) { float num = Math.Min(6f, ValidSpeed(speed)); if (!coal) { return 0.8f + num * 0.22f; } return 0.65f + num * 0.14f; } public static float ChuffsPerSecond(float speed) { float num = ValidSpeed(speed); if (num != 0f) { return Math.Min(8f, 1.2f + num * 1.35f); } return 0f; } } public static class RailAudioSynthesis { private struct Noise { private uint _state; internal Noise(uint seed) { _state = seed; } internal double Next() { _state ^= _state << 13; _state ^= _state >> 17; _state ^= _state << 5; return (double)_state / 4294967295.0 * 2.0 - 1.0; } } public const int SampleRate = 22050; private const int LoopSamples = 44100; private const int OverlapSamples = 2205; private const double Tau = Math.PI * 2.0; private const double HandcartPumpGain = 3.864826125595296; public static float[] GenerateHandcartRoll() { return GenerateLoop(0); } public static float[] GenerateLocomotiveRoll() { return GenerateLoop(1); } public static float[] GenerateSteamHiss() { return GenerateLoop(2); } public static float[] GenerateEitrHum() { float[] array = new float[44100]; for (int i = 0; i < array.Length; i++) { double num = (double)i / 22050.0; double num2 = 0.8 + 0.2 * Math.Cos(Math.PI * 2.0 * num); array[i] = (float)(num2 * (0.28 * Math.Sin(Math.PI * 220.0 * num) + 0.12 * Math.Sin(Math.PI * 330.0 * num) + 0.06 * Math.Sin(Math.PI * 660.0 * num))); } return array; } public static float[] GenerateSteamChuff() { float[] array = new float[3969]; Noise noise = new Noise(4432415u); double num = 0.0; double num2 = 0.0; double num3 = 0.0; double num4 = FilterRate(420.0); double num5 = FilterRate(1900.0); double num6 = FilterRate(70.0); double num7 = ((double)array.Length - 1.0) / 22050.0; for (int i = 0; i < array.Length; i++) { double num8 = (double)i / 22050.0; double num9 = noise.Next(); num += num4 * (num9 - num); num2 += num5 * (num9 - num2); num3 += num6 * (num9 - num3); double num10 = Smooth(num8 / 0.008); double num11 = Smooth((num7 - num8) / 0.05); double num12 = num10 * num11 * Math.Exp((0.0 - num8) * 13.0); double num13 = Math.Sin(Math.PI * 2.0 * (115.0 * num8 - 120.0 * num8 * num8)); array[i] = (float)(num12 * (0.7 * (num2 - num3) + 0.6 * num + 0.1 * num13)); } Normalize(array, 0.8f); return array; } private static float[] GenerateLoop(int kind) { float[] array = new float[46305]; Noise noise = new Noise((kind == 1) ? 7270465u : 1822775u); double num = 0.0; double num2 = 0.0; double num3 = 0.0; double num4 = 0.0; double num5 = FilterRate((kind == 1) ? 100 : 140); double num6 = FilterRate((kind == 2) ? 300 : 430); double num7 = FilterRate((kind == 2) ? 1700 : 1450); double num8 = FilterRate(25.0); for (int i = 0; i < array.Length; i++) { double num9 = (double)i / 22050.0; if (kind != 0) { double num10 = noise.Next(); num += num5 * (num10 - num); num2 += num6 * (num10 - num2); num3 += num7 * (num10 - num3); num4 += num8 * (num10 - num4); } double num12; switch (kind) { case 0: { double num15 = Knock(num9, 0.5, 0.08, 290.0, 37.0) + 0.52 * Knock(num9, 0.5, 0.145, 370.0, 50.0); double num16 = Knock(num9, 1.0, 0.36, 850.0, 65.0); num12 = 0.14 * num15 + 0.025 * num16; break; } case 1: { double num13 = Knock(num9, 0.5, 0.06, 155.0, 21.0) + 0.65 * Knock(num9, 0.5, 0.135, 215.0, 30.0); double num14 = Knock(num9, 1.0, 0.32, 470.0, 44.0); num12 = 0.9 * (num - num4) + 0.2 * (num2 - num) + 0.07 * (num3 - num2) + 0.22 * num13 + 0.045 * num14; break; } default: { double num11 = 0.9 + 0.06 * Math.Sin(Math.PI * 2.0 * num9 * 0.5) + 0.04 * Math.Sin(Math.PI * 2.0 * num9 * 1.5); num12 = (num3 - num2) * num11; break; } } array[i] = (float)num12; } float[] array2 = new float[44100]; Array.Copy(array, array2, array2.Length); for (int j = 0; j < 2205; j++) { double num17 = Smooth((double)j / 2204.0); array2[j] = (float)((double)array[44100 + j] * (1.0 - num17) + (double)array[j] * num17); } if (kind == 0) { for (int k = 0; k < array2.Length; k++) { array2[k] = (float)((double)array2[k] * 3.864826125595296); } } else { Normalize(array2, (kind == 2) ? 0.5f : 0.8f); } return array2; } private static double Knock(double time, double period, double offset, double frequency, double decay) { double num = (time - offset) % period; if (num < 0.0) { num += period; } return Smooth(num / 0.004) * Smooth((period - num) / 0.02) * Math.Exp((0.0 - num) * decay) * (Math.Sin(Math.PI * 2.0 * frequency * num) + 0.25 * Math.Sin(Math.PI * 2.0 * frequency * 2.17 * num)); } private static double FilterRate(double cutoff) { return 1.0 - Math.Exp(Math.PI * -2.0 * cutoff / 22050.0); } private static double Smooth(double value) { value = Math.Max(0.0, Math.Min(1.0, value)); return value * value * (3.0 - 2.0 * value); } private static void Normalize(float[] samples, float peak) { double num = 0.0; foreach (float value in samples) { num = Math.Max(num, Math.Abs(value)); } if (!(num <= 0.0)) { double num2 = (double)peak / num; for (int j = 0; j < samples.Length; j++) { samples[j] = (float)((double)samples[j] * num2); } } } } public static class RailAutoCoupling { public const double ContactTolerance = 0.04; public const double MaximumEndAngleDegrees = 35.0; private const double RouteTolerance = 1E-06; private static readonly double MinimumEndDot = Math.Cos(Math.PI * 7.0 / 36.0); public static bool TryContact(RailNetwork network, RailCursor movingEnd, bool movingForward, RailCursor stationaryEnd, bool stationaryFront, double proposedDistance, double spacing, out double distanceToContact) { if (network == null) { throw new ArgumentNullException("network"); } ValidateSpacing(spacing); Guard.Finite(proposedDistance, "proposedDistance"); if (proposedDistance < 0.0) { throw new ArgumentOutOfRangeException("proposedDistance"); } distanceToContact = 0.0; if (proposedDistance == 0.0 || !ValidCursor(network, movingEnd) || !ValidCursor(network, stationaryEnd)) { return false; } RailCursor railCursor = (movingForward ? movingEnd : movingEnd.Reversed()); RailCursor targetOutward = (stationaryFront ? stationaryEnd : stationaryEnd.Reversed()); double num = spacing + proposedDistance; if (double.IsInfinity(num)) { throw new ArgumentOutOfRangeException("proposedDistance"); } if (!TrySeparation(network, railCursor, targetOutward, num + 1E-06, out var separation) || separation < spacing - 0.04) { return false; } double num2 = Math.Max(0.0, separation - spacing); if (num2 > proposedDistance + 1E-06) { return false; } num2 = Math.Min(num2, proposedDistance); RailAdvanceResult railAdvanceResult = network.Advance(railCursor, num2); if (railAdvanceResult.Stopped || railAdvanceResult.DistanceTravelled < num2 - 1E-06 || !FacingEnds(network, railAdvanceResult.Cursor, targetOutward)) { return false; } distanceToContact = num2; return true; } public static bool AreCouplersTouching(RailNetwork network, RailCursor parentFrontCursor, RailCursor wagonFrontCursor, double spacing) { return AreCouplersTouching(network, parentFrontCursor, firstFront: false, wagonFrontCursor, secondFront: true, spacing); } public static bool AreCouplersTouching(RailNetwork network, RailCursor first, bool firstFront, RailCursor second, bool secondFront, double spacing) { if (network == null) { throw new ArgumentNullException("network"); } ValidateSpacing(spacing); if (!ValidCursor(network, first) || !ValidCursor(network, second)) { return false; } RailCursor movingOutward = (firstFront ? first : first.Reversed()); RailCursor targetOutward = (secondFront ? second : second.Reversed()); if (TrySeparation(network, movingOutward, targetOutward, spacing + 0.04 + 1E-06, out var separation) && Math.Abs(separation - spacing) <= 0.040001) { return FacingEnds(network, movingOutward, targetOutward); } return false; } public static bool CanResetReleasedPair(double worldDistance, double? forwardRouteDistance, double? reverseRouteDistance, double resetDistance) { if (!ValidDistance(worldDistance) || !ValidDistance(resetDistance) || resetDistance <= 0.0) { return false; } if (worldDistance > resetDistance) { return true; } if ((forwardRouteDistance.HasValue && !ValidDistance(forwardRouteDistance.Value)) || (reverseRouteDistance.HasValue && !ValidDistance(reverseRouteDistance.Value))) { return false; } if (!forwardRouteDistance.HasValue && !reverseRouteDistance.HasValue) { return false; } return Math.Min(forwardRouteDistance ?? double.PositiveInfinity, reverseRouteDistance ?? double.PositiveInfinity) > resetDistance; } private static bool ValidDistance(double distance) { if (!double.IsNaN(distance) && !double.IsInfinity(distance)) { return distance >= 0.0; } return false; } private static bool TrySeparation(RailNetwork network, RailCursor movingOutward, RailCursor targetOutward, double maximum, out double separation) { separation = 0.0; if (!network.TryDistanceAlongRoute(movingOutward, targetOutward, maximum, out var distance)) { return false; } if (!network.TryDistanceAlongRoute(targetOutward, movingOutward, distance + 1E-06, out var distance2) || Math.Abs(distance2 - distance) > 1E-06) { return false; } RailAdvanceResult railAdvanceResult = network.Advance(movingOutward, distance); if (railAdvanceResult.Stopped || railAdvanceResult.DistanceTravelled < distance - 1E-06 || RailVector.Dot(network.Sample(railAdvanceResult.Cursor).Tangent, network.Sample(targetOutward).Tangent) > -0.9) { return false; } separation = distance; return true; } private static bool FacingEnds(RailNetwork network, RailCursor movingOutward, RailCursor targetOutward) { return RailVector.Dot(RailVehiclePose.Sample(network, movingOutward).Tangent, RailVehiclePose.Sample(network, targetOutward).Tangent) <= 0.0 - MinimumEndDot + 1E-06; } private static bool ValidCursor(RailNetwork network, RailCursor cursor) { if (!string.IsNullOrEmpty(cursor.SegmentId) && (cursor.Direction == 1 || cursor.Direction == -1) && network.TryGetPath(cursor.SegmentId, out RailPath path)) { return cursor.Distance <= path.Length; } return false; } private static void ValidateSpacing(double spacing) { Guard.Finite(spacing, "spacing"); if (spacing <= 0.04) { throw new ArgumentOutOfRangeException("spacing"); } } } public static class RailAutomaticDrive { public static bool Supports(bool engine, bool coal, bool eitr) { if (engine) { return coal || eitr; } return false; } public static bool SessionValid(bool requested, bool supported, bool reciprocalController, long driver, long owner, int ownerRevision, long authority, int authorityRevision) { if (requested && supported && reciprocalController && driver == 0L && owner != 0L && owner == authority) { return ownerRevision == authorityRevision; } return false; } } public static class RailBridgeTracks { public const string PrefabName = "vr_track_bridge24"; public const string WoodenPrefabName = "vr_track_wood_bridge24"; public const double Length = 24.0; public const double SupportHalfWidth = 1.9; public const double BearingZ = 11.65; public const double BearingBottom = -0.82; public static RailVector[] Points() { return new RailVector[2] { new RailVector(0.0, 0.0, -12.0), new RailVector(0.0, 0.0, 12.0) }; } public static RailVector[] SupportSockets() { return new RailVector[4] { new RailVector(-1.9, -0.82, -11.65), new RailVector(1.9, -0.82, -11.65), new RailVector(-1.9, -0.82, 11.65), new RailVector(1.9, -0.82, 11.65) }; } } public sealed class RailBypassTrackDefinition { public string PrefabName { get; } public bool LightDuty { get; } public bool TurnsLeft { get; } public bool IsSwitch { get; } public int WoodCost { get; } public int NailsCost { get; } private RailVector SwitchCenter => new RailVector((double)((!TurnsLeft) ? 1 : (-1)) * 4.0 * 0.5, 0.0, 5.0); internal RailBypassTrackDefinition(bool lightDuty, bool turnsLeft, bool isSwitch) { LightDuty = lightDuty; TurnsLeft = turnsLeft; IsSwitch = isSwitch; PrefabName = "vr_track_" + (lightDuty ? "wood_" : "") + "bypass_" + (isSwitch ? "switch_" : "") + (turnsLeft ? "left" : "right"); WoodCost = ((!isSwitch) ? (lightDuty ? 18 : 24) : (lightDuty ? 27 : 36)); NailsCost = ((!isSwitch) ? (lightDuty ? 3 : 6) : (lightDuty ? 6 : 12)); } public RailVector[] Points() { RailVector[] array = BranchPoints(); RailVector railVector = (array[0] + array[^1]) * 0.5; for (int i = 0; i < array.Length; i++) { array[i] -= railVector; } return array; } public RailVector[] TrunkPoints() { return new RailVector[2] { new RailVector(0.0, 0.0, -2.0) - SwitchCenter, -SwitchCenter }; } public RailVector[] ThroughPoints() { return new RailVector[2] { -SwitchCenter, new RailVector(0.0, 0.0, 12.0) - SwitchCenter }; } public RailVector[] BranchPoints() { int num = ((!TurnsLeft) ? 1 : (-1)); double num2 = Math.Acos(0.8); int num3 = (int)Math.Ceiling(num2 * 180.0 / Math.PI / 2.8125); RailVector[] array = new RailVector[num3 * 2 + 1]; for (int i = 0; i <= num3; i++) { double num4 = num2 * (double)i / (double)num3; RailVector railVector = (array[i] = new RailVector((double)num * 10.0 * (1.0 - Math.Cos(num4)), 0.0, 10.0 * Math.Sin(num4))); array[array.Length - 1 - i] = new RailVector((double)num * 4.0 - railVector.X, 0.0, 12.0 - railVector.Z); } array[0] = default(RailVector); array[num3] = new RailVector((double)num * 4.0 * 0.5, 0.0, 6.0); array[^1] = new RailVector((double)num * 4.0, 0.0, 12.0); RailVector switchCenter = SwitchCenter; for (int j = 0; j < array.Length; j++) { array[j] -= switchCenter; } return array; } } public static class RailBypassTracks { public const double Radius = 10.0; public const double Offset = 4.0; public const double ForwardLength = 12.0; public const double StemLength = 2.0; public const double MaximumSampleDegrees = 2.8125; public static IReadOnlyList All { get; } = CreateCatalog(); public static bool TryGet(string? prefabName, out RailBypassTrackDefinition definition) { foreach (RailBypassTrackDefinition item in All) { if (string.Equals(item.PrefabName, prefabName, StringComparison.Ordinal)) { definition = item; return true; } } definition = null; return false; } private static IReadOnlyList CreateCatalog() { List list = new List(); bool[] array = new bool[2] { false, true }; foreach (bool lightDuty in array) { bool[] array2 = new bool[2] { false, true }; foreach (bool isSwitch in array2) { bool[] array3 = new bool[2] { true, false }; foreach (bool turnsLeft in array3) { list.Add(new RailBypassTrackDefinition(lightDuty, turnsLeft, isSwitch)); } } } return list.AsReadOnly(); } } public static class RailCargoSnapshot { public static string Digest(string nativeItems) { if (nativeItems == null) { throw new ArgumentNullException("nativeItems"); } using SHA256 sHA = SHA256.Create(); return BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(nativeItems))).Replace("-", ""); } public static bool CanAdopt(long expectedPeer, long actualPeer, int expectedOwnerRevision, int actualOwnerRevision, uint minimumDataRevision, uint actualDataRevision, string expectedDigest, string actualDigest, bool inUse) { if (expectedPeer != 0L && expectedPeer == actualPeer && expectedOwnerRevision >= 0 && expectedOwnerRevision <= 65535 && actualOwnerRevision == expectedOwnerRevision && actualDataRevision >= minimumDataRevision && !inUse && ValidDigest(expectedDigest) && ValidDigest(actualDigest)) { return string.Equals(expectedDigest, actualDigest, StringComparison.Ordinal); } return false; } private static bool ValidDigest(string value) { if (value == null || value.Length != 64) { return false; } foreach (char c in value) { if ((c < '0' || c > '9') && (c < 'A' || c > 'F') && (c < 'a' || c > 'f')) { return false; } } return true; } } public readonly struct RailConsistPowerResult { public RailTractionResult Traction { get; } public double MaximumSpeed { get; } public int ActiveEngineCount { get; } public bool HasPower => ActiveEngineCount > 0; internal RailConsistPowerResult(RailTractionResult traction, double maximumSpeed, int activeEngineCount) { Traction = traction; MaximumSpeed = maximumSpeed; ActiveEngineCount = activeEngineCount; } } public static class RailConsistPower { public const int MaximumActiveEngines = 21; public const double AdditionalEngineSpeedBonus = 0.05; public const double MaximumSpeedBonus = 0.2; public static bool IsCompatible(RailEngineKind operated, RailEngineKind candidate) { if (Known(operated)) { return operated == candidate; } return false; } public static RailConsistPowerResult Evaluate(RailEngineKind engine, RailSettingsValues settings, int wagonCount, double weight, double tangentY, double throttle, int activeEngineCount) { if (activeEngineCount < 0 || activeEngineCount > 21) { throw new ArgumentOutOfRangeException("activeEngineCount"); } RailTractionResult traction = RailTraction.Evaluate(engine, settings, wagonCount, weight, tangentY, throttle); RailTractionResult railTractionResult = RailTraction.Evaluate(engine, settings, 0, 0.0, 0.0, 1.0); if (activeEngineCount <= 1) { return new RailConsistPowerResult(traction, railTractionResult.TargetSpeed, activeEngineCount); } double num = Math.Min(0.2, (double)(activeEngineCount - 1) * 0.05); double num2 = Math.Min(15.0, railTractionResult.TargetSpeed * (1.0 + num)); double num3 = 1.0 + (traction.LoadFactor - 1.0) / (double)activeEngineCount; double num4 = Math.Max(-1.0, Math.Min(1.0, throttle)); return new RailConsistPowerResult(new RailTractionResult(num4 * num2 / num3 / traction.GradeFactor, railTractionResult.PoweredAcceleration / num3, num3, traction.GradeFactor), num2, activeEngineCount); } private static bool Known(RailEngineKind kind) { if (kind != RailEngineKind.Handcart && kind != RailEngineKind.TandemHandcart && kind != RailEngineKind.BronzeEngine && kind != RailEngineKind.CoalLocomotive) { return kind == RailEngineKind.EitrEngine; } return true; } } public static class RailCoupledLayout { public static bool TryCursor(RailNetwork network, RailCursor anchor, int slot, bool reversed, double spacing, out RailCursor cursor) { if (network == null) { throw new ArgumentNullException("network"); } Guard.Finite(spacing, "spacing"); if (spacing <= 0.0) { throw new ArgumentOutOfRangeException("spacing"); } if (slot < -127 || slot > 127) { throw new ArgumentOutOfRangeException("slot"); } cursor = default(RailCursor); if (string.IsNullOrEmpty(anchor.SegmentId) || (anchor.Direction != 1 && anchor.Direction != -1) || !network.TryGetPath(anchor.SegmentId, out RailPath path) || anchor.Distance > path.Length) { return false; } if (slot == 0) { cursor = (reversed ? anchor.Reversed() : anchor); return true; } double num = (double)Math.Abs(slot) * spacing; Guard.Finite(num, "spacing"); RailAdvanceResult railAdvanceResult = network.Advance((slot > 0) ? anchor : anchor.Reversed(), num); if (railAdvanceResult.DistanceTravelled < num - Math.Min(1E-07, num * 1E-09)) { return false; } cursor = ((slot > 0) ? railAdvanceResult.Cursor : railAdvanceResult.Cursor.Reversed()); if (reversed) { cursor = cursor.Reversed(); } return true; } } public readonly struct RailCouplingNode { public string Identity { get; } public bool Engine { get; } public string Front { get; } public string Rear { get; } public RailCouplingNode(string identity, bool engine, string front, string rear) { Identity = identity; Engine = engine; Front = front; Rear = rear; } } public readonly struct RailCouplingLinks { public string Parent { get; } public string Next { get; } public string Front { get; } public bool ParentFront { get; } public RailCouplingLinks(string parent, string next, string front, bool parentFront) { Parent = parent; Next = next; Front = front; ParentFront = parentFront; } } public static class RailCouplingGraph { public static bool TryRoot(IReadOnlyList nodes, string root, out Dictionary links) { links = new Dictionary(StringComparer.Ordinal); if (nodes == null || string.IsNullOrEmpty(root) || nodes.Count == 0 || nodes.Count > 128) { return false; } Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (RailCouplingNode node in nodes) { if (string.IsNullOrEmpty(node.Identity) || node.Front == null || node.Rear == null || node.Front == node.Identity || node.Rear == node.Identity || (node.Front.Length != 0 && node.Front == node.Rear) || dictionary.ContainsKey(node.Identity)) { return false; } dictionary.Add(node.Identity, node); } if (!dictionary.TryGetValue(root, out var value) || (!value.Engine && value.Front.Length != 0 && value.Rear.Length != 0)) { return false; } foreach (RailCouplingNode node2 in nodes) { string[] array = new string[2] { node2.Front, node2.Rear }; foreach (string text in array) { if (text.Length != 0 && (!dictionary.TryGetValue(text, out var value2) || (value2.Front != node2.Identity && value2.Rear != node2.Identity))) { return false; } } } bool flag = value.Rear.Length != 0 || value.Front.Length == 0; links.Add(root, new RailCouplingLinks("", value.Engine ? value.Rear : (flag ? value.Rear : value.Front), value.Engine ? value.Front : "", flag)); if (!Branch(root, value.Front, dictionary, links) || !Branch(root, value.Rear, dictionary, links) || links.Count != nodes.Count) { links.Clear(); return false; } return true; } private static bool Branch(string parent, string next, Dictionary map, Dictionary links) { while (next.Length != 0) { if (links.ContainsKey(next) || !map.TryGetValue(next, out var value)) { return false; } bool flag = value.Front == parent; string text = (flag ? value.Rear : value.Front); links.Add(next, new RailCouplingLinks(parent, text, "", flag)); parent = next; next = text; } return true; } } public static class RailCreatureClearance { public const double HalfWidth = 0.55; public const double FrontInset = 0.35; public static bool BlocksLeadingEnd(bool leading, bool forward, RailVector localCenter, double radius, double halfLength) { if (!leading) { return false; } if (!Finite(localCenter.X) || !Finite(localCenter.Z) || !Finite(radius) || !Finite(halfLength) || radius < 0.0 || halfLength <= 0.0) { return true; } double num = (forward ? localCenter.Z : (0.0 - localCenter.Z)); if (Math.Abs(localCenter.X) <= 0.55 + radius) { return num + radius >= Math.Max(0.0, halfLength - 0.35); } return false; } private static bool Finite(double value) { if (!double.IsNaN(value)) { return !double.IsInfinity(value); } return false; } } public sealed class RailCurveTrackDefinition { public string PrefabName { get; } public double AngleDegrees { get; } public bool Incline { get; } public bool TurnsLeft { get; } public bool LightDuty { get; } public int WoodCost { get; } public int NailsCost { get; } internal RailCurveTrackDefinition(string angleSuffix, double angle, bool incline, bool left, bool lightDuty) { AngleDegrees = angle; Incline = incline; TurnsLeft = left; LightDuty = lightDuty; PrefabName = "vr_track_" + (lightDuty ? "wood_" : "") + "curve_" + (incline ? "slope_" : "") + angleSuffix + ((!incline) ? "" : (left ? "_left" : "_right")); double num = angle / 22.5; WoodCost = (int)Math.Ceiling((double)(lightDuty ? 6 : 8) * num); NailsCost = (int)Math.Ceiling((double)(lightDuty ? 1 : 2) * num); } public RailVector[] Points() { int num = (int)Math.Round(AngleDegrees / 2.8125); double num2 = AngleDegrees * Math.PI / 180.0 / (double)num; double num3 = 16.0 * Math.Sin(num2 / 2.0); double num4 = (Incline ? (num3 * 0.25) : 0.0); int num5 = ((!TurnsLeft) ? 1 : (-1)); RailVector[] array = new RailVector[num + 1]; for (int i = 0; i <= num; i++) { double num6 = num2 * (double)i; array[i] = new RailVector((double)num5 * 8.0 * (1.0 - Math.Cos(num6)), num4 * (double)i, 8.0 * Math.Sin(num6)); } RailVector railVector = (array[0] + array[num]) * 0.5; for (int j = 0; j <= num; j++) { array[j] -= railVector; } return array; } } public static class RailCurveTracks { public const double Radius = 8.0; public const double Grade = 0.25; public const double SampleDegrees = 2.8125; public static IReadOnlyList Additions { get; } = CreateCatalog(); private static IReadOnlyList CreateCatalog() { List list = new List(); string[] array = new string[4] { "11_25", "22_5", "45", "90" }; double[] array2 = new double[4] { 11.25, 22.5, 45.0, 90.0 }; bool[] array3 = new bool[2] { false, true }; foreach (bool lightDuty in array3) { for (int j = 0; j < array2.Length; j++) { if (array2[j] != 22.5) { list.Add(new RailCurveTrackDefinition(array[j], array2[j], incline: false, left: false, lightDuty)); } list.Add(new RailCurveTrackDefinition(array[j], array2[j], incline: true, left: true, lightDuty)); list.Add(new RailCurveTrackDefinition(array[j], array2[j], incline: true, left: false, lightDuty)); } } return list.AsReadOnly(); } } public enum RailFuelType { Coal, Wood, Eitr } public static class RailFuelPolicy { public static string PrefabName(RailFuelType type) { return type switch { RailFuelType.Eitr => "Eitr", RailFuelType.Wood => "Wood", RailFuelType.Coal => "Coal", _ => throw new ArgumentOutOfRangeException("type"), }; } public static bool AcceptsItem(RailFuelType type, string? prefabName) { if ((type != RailFuelType.Coal || !string.Equals(prefabName, "Coal", StringComparison.Ordinal)) && (type != RailFuelType.Wood || !string.Equals(prefabName, "Wood", StringComparison.Ordinal))) { if (type == RailFuelType.Eitr) { return string.Equals(prefabName, "Eitr", StringComparison.Ordinal); } return false; } return true; } } public readonly struct RailGateBody { public string Identity { get; } public string TrainIdentity { get; } public RailVector Center { get; } public RailVector HalfExtents { get; } public RailVector Velocity { get; } public RailVector Forward { get; } public RailGateBody(string identity, string trainIdentity, RailVector center, RailVector halfExtents, RailVector velocity, RailVector forward) { if (string.IsNullOrWhiteSpace(identity)) { throw new ArgumentException("A vehicle identity is required.", "identity"); } if (string.IsNullOrWhiteSpace(trainIdentity)) { throw new ArgumentException("A complete train identity is required.", "trainIdentity"); } if (halfExtents.X <= 0.0 || halfExtents.Y <= 0.0 || halfExtents.Z <= 0.0) { throw new ArgumentOutOfRangeException("halfExtents"); } Guard.Finite(Math.Abs(center.X) + halfExtents.X, "center"); Guard.Finite(Math.Abs(center.Y) + halfExtents.Y, "center"); Guard.Finite(Math.Abs(center.Z) + halfExtents.Z, "center"); Guard.Finite(velocity.Magnitude, "velocity"); Identity = identity; TrainIdentity = trainIdentity; Center = center; HalfExtents = halfExtents; Velocity = velocity; Forward = forward.Normalized(); } } public static class RailGatePolicy { public const double ApproachSeconds = 3.0; public const double ApproachExtraDistance = 8.0; public const double WaitingDistance = 6.0; public const double OpeningSeconds = 2.0; public const double ClearHoldSeconds = 2.0; public const double MaximumCoupledCenterDistance = 4.0; public const double MaximumBridgeAngleDegrees = 45.0; private static readonly double MinimumBridgeAlignment = Math.Cos(Math.PI / 4.0); private const double Epsilon = 1E-07; public static bool OverlapsDoor(RailGateBody body, double halfWidth, double halfDepth, double bottom, double top) { ValidateDoor(halfWidth, halfDepth, bottom, top); if (!Valid(body)) { return false; } if (body.Center.X - body.HalfExtents.X <= halfWidth + 1E-07 && body.Center.X + body.HalfExtents.X >= 0.0 - halfWidth - 1E-07 && body.Center.Z - body.HalfExtents.Z <= halfDepth + 1E-07 && body.Center.Z + body.HalfExtents.Z >= 0.0 - halfDepth - 1E-07 && body.Center.Y - body.HalfExtents.Y <= top + 1E-07) { return body.Center.Y + body.HalfExtents.Y >= bottom - 1E-07; } return false; } public static bool CanWait(RailGateBody body, double halfWidth, double bottom, double top) { if (OverlapsDoor(body, halfWidth, 6.0, bottom, top) && Math.Abs(body.Forward.Z) >= MinimumBridgeAlignment - 1E-07) { return body.Velocity.Magnitude <= 0.10000010000000001; } return false; } public static bool CanApproach(RailGateBody body, double halfWidth, double halfDepth, double bottom, double top) { ValidateDoor(halfWidth, halfDepth, bottom, top); if (!Valid(body)) { return false; } double num = Math.Abs(body.Velocity.Z); if (num < 1E-08 || body.Center.Z == 0.0 || ((body.Center.Z > 0.0) ? (body.Velocity.Z >= 0.0) : (body.Velocity.Z <= 0.0))) { return false; } double enter = 0.0; double leave = 3.0 + 8.0 / num; if (Slab(body.Center.X, body.Velocity.X, 0.0 - halfWidth - body.HalfExtents.X, halfWidth + body.HalfExtents.X, ref enter, ref leave) && Slab(body.Center.Y, body.Velocity.Y, bottom - body.HalfExtents.Y, top + body.HalfExtents.Y, ref enter, ref leave)) { return Slab(body.Center.Z, body.Velocity.Z, 0.0 - halfDepth - body.HalfExtents.Z, halfDepth + body.HalfExtents.Z, ref enter, ref leave); } return false; } public static bool TrainStraddles(IReadOnlyList orderedCompleteTrain, bool complete, double halfWidth, double halfDepth, double bottom, double top) { ValidateDoor(halfWidth, halfDepth, bottom, top); if (orderedCompleteTrain == null) { throw new ArgumentNullException("orderedCompleteTrain"); } if (!complete || orderedCompleteTrain.Count < 2 || orderedCompleteTrain.Count > 128) { return false; } HashSet hashSet = new HashSet(StringComparer.Ordinal); string trainIdentity = orderedCompleteTrain[0].TrainIdentity; foreach (RailGateBody item in orderedCompleteTrain) { if (!Valid(item) || !string.Equals(item.TrainIdentity, trainIdentity, StringComparison.Ordinal) || !hashSet.Add(item.Identity)) { return false; } } for (int i = 1; i < orderedCompleteTrain.Count; i++) { RailGateBody railGateBody = orderedCompleteTrain[i - 1]; RailGateBody railGateBody2 = orderedCompleteTrain[i]; if (Math.Abs(railGateBody.Forward.Z) < MinimumBridgeAlignment - 1E-07 || Math.Abs(railGateBody2.Forward.Z) < MinimumBridgeAlignment - 1E-07 || Math.Abs(RailVector.Dot(railGateBody.Forward, railGateBody2.Forward)) < MinimumBridgeAlignment - 1E-07 || RailVector.Distance(railGateBody.Center, railGateBody2.Center) > 4.0000001) { continue; } double num = railGateBody2.Center.Z - railGateBody.Center.Z; if (Math.Abs(num) < 1E-07) { continue; } double num2 = (0.0 - railGateBody.Center.Z) / num; if (!(num2 < 0.0) && !(num2 > 1.0)) { RailVector railVector = railGateBody.Center + (railGateBody2.Center - railGateBody.Center) * num2; RailVector railVector2 = railGateBody.HalfExtents + (railGateBody2.HalfExtents - railGateBody.HalfExtents) * num2; if (railVector.X - railVector2.X <= halfWidth + 1E-07 && railVector.X + railVector2.X >= 0.0 - halfWidth - 1E-07 && railVector.Y - railVector2.Y <= top + 1E-07 && railVector.Y + railVector2.Y >= bottom - 1E-07) { return true; } } } return false; } private static bool Slab(double position, double velocity, double minimum, double maximum, ref double enter, ref double leave) { if (Math.Abs(velocity) < 1E-12) { if (position >= minimum - 1E-07) { return position <= maximum + 1E-07; } return false; } double num = (minimum - position) / velocity; double num2 = (maximum - position) / velocity; if (num > num2) { double num3 = num; num = num2; num2 = num3; } enter = Math.Max(enter, num); leave = Math.Min(leave, num2); return enter <= leave + 1E-07; } private static bool Valid(RailGateBody body) { if (!string.IsNullOrWhiteSpace(body.Identity) && !string.IsNullOrWhiteSpace(body.TrainIdentity) && body.HalfExtents.X > 0.0 && body.HalfExtents.Y > 0.0) { return body.HalfExtents.Z > 0.0; } return false; } private static void ValidateDoor(double halfWidth, double halfDepth, double bottom, double top) { Guard.Finite(halfWidth, "halfWidth"); Guard.Finite(halfDepth, "halfDepth"); Guard.Finite(bottom, "bottom"); Guard.Finite(top, "top"); if (halfWidth <= 0.0) { throw new ArgumentOutOfRangeException("halfWidth"); } if (halfDepth < 0.0) { throw new ArgumentOutOfRangeException("halfDepth"); } if (top <= bottom) { throw new ArgumentOutOfRangeException("top"); } } } public readonly struct RailVector { public double X { get; } public double Y { get; } public double Z { get; } public double Magnitude => Math.Sqrt(X * X + Y * Y + Z * Z); public RailVector(double x, double y, double z) { Guard.Finite(x, "x"); Guard.Finite(y, "y"); Guard.Finite(z, "z"); X = x; Y = y; Z = z; } public RailVector Normalized() { double magnitude = Magnitude; if (magnitude <= 0.0 || double.IsInfinity(magnitude)) { throw new InvalidOperationException("A direction must have a finite, nonzero length."); } return this / magnitude; } public static double Dot(RailVector a, RailVector b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z; } public static double Distance(RailVector a, RailVector b) { return (a - b).Magnitude; } public static RailVector operator +(RailVector a, RailVector b) { return new RailVector(a.X + b.X, a.Y + b.Y, a.Z + b.Z); } public static RailVector operator -(RailVector a, RailVector b) { return new RailVector(a.X - b.X, a.Y - b.Y, a.Z - b.Z); } public static RailVector operator -(RailVector value) { return new RailVector(0.0 - value.X, 0.0 - value.Y, 0.0 - value.Z); } public static RailVector operator *(RailVector value, double scale) { return new RailVector(value.X * scale, value.Y * scale, value.Z * scale); } public static RailVector operator /(RailVector value, double scale) { return new RailVector(value.X / scale, value.Y / scale, value.Z / scale); } } public readonly struct RailPose { public RailVector Position { get; } public RailVector Tangent { get; } public RailPose(RailVector position, RailVector tangent) { Position = position; Tangent = tangent; } } public readonly struct RailProjection { public double Distance { get; } public double Separation { get; } public RailVector Position { get; } internal RailProjection(double distance, double separation, RailVector position) { Distance = distance; Separation = separation; Position = position; } } public sealed class RailPath { private readonly RailVector[] _points; private readonly double[] _distances; public double Length => _distances[_distances.Length - 1]; public RailPath(IReadOnlyList points) { if (points == null) { throw new ArgumentNullException("points"); } if (points.Count < 2) { throw new ArgumentException("A rail path needs at least two points.", "points"); } _points = new RailVector[points.Count]; _distances = new double[points.Count]; for (int i = 0; i < points.Count; i++) { _points[i] = points[i]; if (i != 0) { double num = RailVector.Distance(_points[i - 1], _points[i]); if (num <= 1E-08 || double.IsInfinity(num)) { throw new ArgumentException("Adjacent rail points must have a finite, nonzero separation.", "points"); } _distances[i] = _distances[i - 1] + num; Guard.Finite(_distances[i], "points"); } } } public RailPose Sample(double distance) { Guard.Finite(distance, "distance"); distance = Math.Max(0.0, Math.Min(Length, distance)); int num = Array.BinarySearch(_distances, distance); if (num < 0) { num = ~num - 1; } num = Math.Min(num, _points.Length - 2); double num2 = _distances[num + 1] - _distances[num]; RailVector railVector = (_points[num + 1] - _points[num]) / num2; return new RailPose(_points[num] + railVector * (distance - _distances[num]), railVector); } public RailProjection Project(RailVector point) { double num = double.PositiveInfinity; double distance = 0.0; RailVector position = _points[0]; for (int i = 0; i < _points.Length - 1; i++) { RailVector a = point - _points[i]; double num2 = _distances[i + 1] - _distances[i]; RailVector railVector = (_points[i + 1] - _points[i]) / num2; double num3 = Math.Max(0.0, Math.Min(num2, RailVector.Dot(a, railVector))); RailVector railVector2 = _points[i] + railVector * num3; double num4 = RailVector.Distance(point, railVector2); if (!(num4 >= num)) { num = num4; distance = _distances[i] + num3; position = railVector2; } } return new RailProjection(distance, num, position); } } internal static class Guard { internal static void Finite(double value, string name) { if (double.IsNaN(value) || double.IsInfinity(value)) { throw new ArgumentOutOfRangeException(name, "Value must be finite."); } } } public static class RailHandPush { public const double MaxSpeed = 0.8; public const double Acceleration = 0.8; public const double Braking = 3.0; public const double AnchorDistance = 1.8; public const double AnchorHeight = 0.18; public static RailPose Anchor(RailNetwork network, RailCursor cursor, out bool trackUnderfoot) { if (network == null) { throw new ArgumentNullException("network"); } RailAdvanceResult railAdvanceResult = network.Advance(cursor.Reversed(), 1.8); trackUnderfoot = railAdvanceResult.DistanceTravelled >= 1.7990000000000002; RailPose railPose = RailVehiclePose.Sample(network, railAdvanceResult.Cursor.Reversed()); double num = Math.Max(0.0, 1.8 - railAdvanceResult.DistanceTravelled); return new RailPose(railPose.Position - railPose.Tangent * num + new RailVector(0.0, 0.18, 0.0), railPose.Tangent); } public static string EvaluateEligibility(bool isEngine, bool hasParent, bool hasNext, bool hasPassengers, bool cargoBusy) { if (isEngine) { return "Use the engine's controls to move it."; } if (hasParent || hasNext) { return "Uncouple this cart at both ends before pushing it."; } if (hasPassengers) { return "Have everyone leave the cart before pushing it."; } if (cargoBusy) { return "Close the cargo inventory before pushing the cart."; } return ""; } public static double StepSpeed(double current, double throttle, bool brake, double dt) { Guard.Finite(current, "current"); Guard.Finite(throttle, "throttle"); Guard.Finite(dt, "dt"); if (dt < 0.0) { throw new ArgumentOutOfRangeException("dt"); } current = Math.Max(-0.8, Math.Min(0.8, current)); throttle = Math.Max(-1.0, Math.Min(1.0, throttle)); double num = ((brake || Math.Abs(throttle) <= 0.05) ? 0.0 : (throttle * 0.8)); if (dt == 0.0 || current == num) { return current; } if (current * num < 0.0) { double num2 = Math.Abs(current) / 3.0; if (dt <= num2) { return Approach(current, 0.0, 3.0 * dt); } dt -= num2; current = 0.0; } double num3 = ((Math.Abs(num) < Math.Abs(current)) ? 3.0 : 0.8); return Approach(current, num, num3 * dt); } private static double Approach(double current, double target, double change) { double value = target - current; return current + (double)Math.Sign(value) * Math.Min(Math.Abs(value), change); } } public static class RailLightingMath { public const double FadeStart = 48.0; public const double CullDistance = 64.0; public const double SnapDistance = 5.0; public const double SnapAngle = 45.0; public const double BeamHalfLife = 0.06; public static double DistanceFade(double distance) { Guard.Finite(distance, "distance"); if (distance < 0.0) { throw new ArgumentOutOfRangeException("distance"); } if (distance <= 48.0) { return 1.0; } if (distance >= 64.0) { return 0.0; } double num = (distance - 48.0) / 16.0; return 1.0 - num * num * (3.0 - 2.0 * num); } public static double SmoothFactor(double deltaTime, double halfLife) { Guard.Finite(deltaTime, "deltaTime"); Guard.Finite(halfLife, "halfLife"); if (deltaTime < 0.0) { throw new ArgumentOutOfRangeException("deltaTime"); } if (halfLife <= 0.0) { throw new ArgumentOutOfRangeException("halfLife"); } double num = Math.Log(2.0) * (deltaTime / halfLife); if (num < 1E-05) { return num * (1.0 - num * 0.5 + num * num / 6.0); } return 1.0 - Math.Exp(0.0 - num); } } public readonly struct RailZoneCoord : IEquatable { public int X { get; } public int Y { get; } public RailZoneCoord(int x, int y) { X = x; Y = y; } public bool Equals(RailZoneCoord other) { if (X == other.X) { return Y == other.Y; } return false; } public override bool Equals(object? obj) { if (obj is RailZoneCoord other) { return Equals(other); } return false; } public override int GetHashCode() { return (X * 397) ^ Y; } public static bool operator ==(RailZoneCoord left, RailZoneCoord right) { return left.Equals(right); } public static bool operator !=(RailZoneCoord left, RailZoneCoord right) { return !left.Equals(right); } } public static class RailLoadingFootprint { public const double ZoneSize = 64.0; public const int ZoneMargin = 1; public const int MaximumAnchors = 129; public const int MaximumZonesPerTrain = 25; private const double MaximumAltitude = 2097088.0; public static bool TryCollect(IEnumerable? centers, int maximumZones, out IReadOnlyCollection zones) { zones = (IReadOnlyCollection)(object)Array.Empty(); if (centers == null || maximumZones < 1 || maximumZones > 25) { return false; } HashSet hashSet = new HashSet(); int num = 0; foreach (RailVector center in centers) { if (++num > 129 || !Finite(center.Y) || Math.Abs(center.Y) > 2097088.0 || !TryZone(center.X, out var zone) || !TryZone(center.Z, out var zone2)) { return false; } for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (hashSet.Add(new RailZoneCoord(zone + i, zone2 + j)) && hashSet.Count > maximumZones) { return false; } } } } if (num == 0) { return false; } List list = new List(hashSet); list.Sort((RailZoneCoord a, RailZoneCoord b) => (a.X == b.X) ? a.Y.CompareTo(b.Y) : a.X.CompareTo(b.X)); zones = list.AsReadOnly(); return true; } private static bool TryZone(double coordinate, out int zone) { zone = 0; if (!Finite(coordinate)) { return false; } double num = Math.Floor((coordinate + 32.0) / 64.0); if (!Finite(num) || num < -32767.0 || num > 32766.0) { return false; } zone = (int)num; return true; } private static bool Finite(double value) { if (!double.IsNaN(value)) { return !double.IsInfinity(value); } return false; } } public static class RailLongTracks { public const double HorizontalLength = 12.0; public const double InclineRise = 3.0; public static RailVector[] StraightPoints() { return new RailVector[2] { new RailVector(0.0, 0.0, -6.0), new RailVector(0.0, 0.0, 6.0) }; } public static RailVector[] InclinePoints() { return new RailVector[2] { new RailVector(0.0, -1.5, -6.0), new RailVector(0.0, 1.5, 6.0) }; } } public sealed class RailManualThrottle { public const int MaximumNotch = 5; private bool _armed; public int Notch { get; private set; } public int Direction => Math.Sign(Notch); public float NormalizedThrottle => (float)Notch / 5f; public void Clear() { Notch = 0; _armed = false; } public int Step(bool forward, bool backward, bool cancel) { if (cancel) { Clear(); return Notch; } if (forward && backward) { _armed = false; return Notch; } if (!forward && !backward) { _armed = true; return Notch; } if (!_armed) { return Notch; } _armed = false; Notch = Math.Max(-5, Math.Min(5, Notch + (forward ? 1 : (-1)))); return Notch; } } public readonly struct RailMomentumResult { public double Speed { get; } public double PoweredSeconds { get; } internal RailMomentumResult(double speed, double poweredSeconds) { Speed = speed; PoweredSeconds = poweredSeconds; } } public static class RailMomentum { public const double GravityAcceleration = 3.0; public const double RollingDeceleration = 0.25; public const double Braking = 8.0; public static RailMomentumResult Step(double speed, double throttle, bool canPower, bool brake, double targetSpeed, double poweredAcceleration, double maxSpeed, double tangentY, double dt) { Guard.Finite(speed, "speed"); Guard.Finite(throttle, "throttle"); Guard.Finite(targetSpeed, "targetSpeed"); Guard.Finite(poweredAcceleration, "poweredAcceleration"); Guard.Finite(maxSpeed, "maxSpeed"); Guard.Finite(tangentY, "tangentY"); Guard.Finite(dt, "dt"); if (poweredAcceleration < 0.0) { throw new ArgumentOutOfRangeException("poweredAcceleration"); } if (maxSpeed < 0.5 || maxSpeed > 15.0) { throw new ArgumentOutOfRangeException("maxSpeed"); } if (dt < 0.0) { throw new ArgumentOutOfRangeException("dt"); } speed = Math.Max(0.0 - maxSpeed, Math.Min(maxSpeed, speed)); if (dt == 0.0) { return new RailMomentumResult(speed, 0.0); } if (brake) { return new RailMomentumResult(Brake(speed, dt), 0.0); } int num = ((Math.Abs(throttle) > 0.05) ? Math.Sign(throttle) : 0); double num2 = dt; if (num != 0 && speed * (double)num < 0.0) { double num3 = Math.Abs(speed) / 8.0; if (num2 <= num3) { return new RailMomentumResult(Brake(speed, num2), 0.0); } num2 -= num3; speed = 0.0; } int num4 = ((speed != 0.0) ? Math.Sign(speed) : num); if (num4 == 0) { return new RailMomentumResult(0.0, 0.0); } double num5 = Math.Abs(speed); double num6 = Math.Max(-1.0, Math.Min(1.0, tangentY)); double num7 = -3.0 * num6 * (double)num4 - 0.25; double num8 = ((num == num4) ? Math.Max(0.0, Math.Min(maxSpeed, targetSpeed * (double)num4)) : 0.0); if (!canPower || num != num4 || num8 == 0.0) { return new RailMomentumResult((double)num4 * Coast(num5, num7, num2, maxSpeed), 0.0); } if (num7 > 0.0) { num8 = maxSpeed; } if (num5 > num8) { if (num7 >= 0.0) { return new RailMomentumResult((double)num4 * Coast(num5, num7, num2, maxSpeed), 0.0); } double num9 = (num5 - num8) / (0.0 - num7); if (num2 <= num9) { return new RailMomentumResult((double)num4 * Math.Max(num8, num5 + num7 * num2), 0.0); } num2 -= num9; num5 = num8; } double num10 = 0.0; if (num5 < num8) { double num11 = poweredAcceleration + Math.Max(0.0, num7); if (num11 == 0.0) { return new RailMomentumResult((double)num4 * num5, num2); } double num12 = (num8 - num5) / num11; if (num2 <= num12) { return new RailMomentumResult((double)num4 * Math.Min(num8, num5 + num11 * num2), num2); } num10 = num12; num2 -= num12; num5 = num8; } if (num7 > 0.0) { num5 = Coast(num5, num7, num2, maxSpeed); } else { num10 += num2; } return new RailMomentumResult((double)num4 * num5, Math.Min(dt, num10)); } public static double WeightedGrade(IReadOnlyList grades, IReadOnlyList masses) { if (grades == null) { throw new ArgumentNullException("grades"); } if (masses == null) { throw new ArgumentNullException("masses"); } if (grades.Count == 0 || grades.Count != masses.Count) { throw new ArgumentException("Each vehicle needs one grade and one mass."); } double num = 0.0; for (int i = 0; i < grades.Count; i++) { Guard.Finite(grades[i], "grades"); Guard.Finite(masses[i], "masses"); if (masses[i] <= 0.0) { throw new ArgumentOutOfRangeException("masses"); } num = Math.Max(num, masses[i]); } double num2 = 0.0; double num3 = 0.0; for (int j = 0; j < grades.Count; j++) { double num4 = masses[j] / num; num2 += Math.Max(-1.0, Math.Min(1.0, grades[j])) * num4; num3 += num4; } return Math.Max(-1.0, Math.Min(1.0, num2 / num3)); } private static double Coast(double speed, double acceleration, double seconds, double limit) { return Math.Max(0.0, Math.Min(limit, speed + acceleration * seconds)); } private static double Brake(double speed, double seconds) { return (double)Math.Sign(speed) * Math.Max(0.0, Math.Abs(speed) - 8.0 * seconds); } } public static class RailMountPolicy { public const int Count = 2; public const string CartPrefab = "vr_mount_cart"; public const float MaximumWidth = 1.64f; public const float MaximumDepth = 1.1f; public const float MaximumHeight = 3.5f; public static bool IsDefender(string? prefab) { if (!(prefab == "piece_DARE")) { return prefab == "piece_GNOME"; } return true; } public static bool IsDummy(string? prefab) { if (!IsDefender(prefab)) { return prefab == "piece_TrainingDummy"; } return true; } public static bool IsAllowed(string? prefab) { if (!IsDummy(prefab)) { switch (prefab) { default: return prefab == "itemstandh"; case "sign": case "piece_groundtorch": case "piece_groundtorch_wood": break; } } return true; } public static Vector3 Socket(int slot) { if (slot < 0 || slot >= 2) { throw new ArgumentOutOfRangeException("slot"); } return new Vector3(0f, 0.92f, (slot == 0) ? (-0.56f) : 0.56f); } public static bool Fits(float width, float height, float depth) { if (Finite(width) && Finite(height) && Finite(depth) && width > 0f && height > 0f && depth > 0f && width <= 1.64f && height <= 3.5f) { return depth <= 1.1f; } return false; } private static bool Finite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } public sealed class RailMusicClientValues : IEquatable { public const double DefaultVolume = 0.5; public const double DefaultModeVolume = 1.0; public static readonly RailMusicClientValues Defaults = new RailMusicClientValues(); public double Volume { get; } public bool Muted { get; } public bool BeatLights { get; } public int MaxAudibleCarts { get; } public double TechnoVolume { get; } public double PumpkinVolume { get; } public double HalloweenTechnoVolume { get; } public RailMusicClientValues(double volume = 0.5, bool muted = false, bool beatLights = false, int maxAudibleCarts = 1, double technoVolume = 1.0, double pumpkinVolume = 1.0, double halloweenTechnoVolume = 1.0) { Guard.Finite(volume, "volume"); if (volume < 0.0 || volume > 1.0) { throw new ArgumentOutOfRangeException("volume"); } if (maxAudibleCarts < 1 || maxAudibleCarts > 4) { throw new ArgumentOutOfRangeException("maxAudibleCarts"); } CheckModeVolume(technoVolume, "technoVolume"); CheckModeVolume(pumpkinVolume, "pumpkinVolume"); CheckModeVolume(halloweenTechnoVolume, "halloweenTechnoVolume"); Volume = volume; Muted = muted; BeatLights = beatLights; MaxAudibleCarts = maxAudibleCarts; TechnoVolume = technoVolume; PumpkinVolume = pumpkinVolume; HalloweenTechnoVolume = halloweenTechnoVolume; } public bool Equals(RailMusicClientValues? other) { if (other != null && Volume == other.Volume && Muted == other.Muted && BeatLights == other.BeatLights && MaxAudibleCarts == other.MaxAudibleCarts && TechnoVolume == other.TechnoVolume && PumpkinVolume == other.PumpkinVolume) { return HalloweenTechnoVolume == other.HalloweenTechnoVolume; } return false; } public override bool Equals(object? obj) { if (obj is RailMusicClientValues other) { return Equals(other); } return false; } public override int GetHashCode() { return (((((((((((Volume.GetHashCode() * 397) ^ Muted.GetHashCode()) * 397) ^ BeatLights.GetHashCode()) * 397) ^ MaxAudibleCarts) * 397) ^ TechnoVolume.GetHashCode()) * 397) ^ PumpkinVolume.GetHashCode()) * 397) ^ HalloweenTechnoVolume.GetHashCode(); } private static void CheckModeVolume(double value, string name) { Guard.Finite(value, name); if (value < 0.0 || value > 1.0) { throw new ArgumentOutOfRangeException(name); } } } public sealed class RailMusicMetadata { public const string TrackKey = "vikingrail_music_track"; public const string BannerKey = "vikingrail_music_banner"; public const string AuthorKey = "vikingrail_music_author"; public const string AuthorNameKey = "vikingrail_music_author_name"; public const string DefaultBanner = "Techno Viking Express"; public RailMusicTrack Track { get; } public string Banner { get; } public string Author { get; } public string AuthorName { get; } public int VolumePercent { get; } public RailMusicMetadata(string banner = "Techno Viking Express", string author = "", string authorName = "") : this(RailMusicTracks.Techno, Check(banner, 50), author, authorName) { } public RailMusicMetadata(RailMusicTrack track, string? banner = null, string author = "", string authorName = "", int volumePercent = 100) { if (track == null || !RailMusicTracks.TryForPrefab(track.PrefabName, out RailMusicTrack track2) || track != track2) { throw new FormatException("The packed cart's soundtrack is unavailable."); } Track = track; if (!RailMusicVolume.IsValidPercent(volumePercent)) { throw new FormatException("The saved music volume is invalid."); } VolumePercent = volumePercent; Banner = Check(banner ?? (track.SupportsBanner ? "Techno Viking Express" : ""), 50); Author = Check(author, 256); AuthorName = Check(authorName, 256); if (!track.SupportsBanner && (Banner.Length != 0 || Author.Length != 0 || AuthorName.Length != 0)) { throw new FormatException("This music cart does not have an editable banner."); } } private static string Check(string text, int maximum) { if (text == null || text.Length > maximum || text.IndexOf('\0') >= 0) { throw new FormatException("The sound cart's saved banner is invalid."); } return text; } public void Capture(IDictionary data) { if (data == null) { throw new ArgumentNullException("data"); } data["vikingrail_music_track"] = Track.TrackId; data["vikingrail_music_banner"] = Banner; data["vikingrail_music_author"] = Author; data["vikingrail_music_author_name"] = AuthorName; if (VolumePercent != 100) { RailMusicVolume.Capture(data, VolumePercent); } else { data.Remove("vikingrail_music_volume"); } } public static RailMusicMetadata Read(IReadOnlyDictionary data, bool musicCart) { return Read(data, musicCart ? RailMusicTracks.Techno.PrefabName : null); } public static RailMusicMetadata Read(IReadOnlyDictionary data, string? prefabName) { if (data == null) { throw new ArgumentNullException("data"); } string value; bool flag = data.TryGetValue("vikingrail_music_track", out value); string value2; bool flag2 = data.TryGetValue("vikingrail_music_banner", out value2); string value3; bool flag3 = data.TryGetValue("vikingrail_music_author", out value3); string value4; bool flag4 = data.TryGetValue("vikingrail_music_author_name", out value4); RailMusicTrack track; bool flag5 = RailMusicTracks.TryForPrefab(prefabName, out track); if (!flag && !flag2 && !flag3 && !flag4 && !data.ContainsKey("vikingrail_music_volume")) { return new RailMusicMetadata(flag5 ? track : RailMusicTracks.Techno); } if (!flag5 || !flag || !flag2 || !flag3 || !flag4 || value != track.TrackId) { throw new FormatException("The packed sound cart's music data is incomplete or incompatible."); } return new RailMusicMetadata(track, Check(value2, 50), value3, value4, RailMusicVolume.ReadPacked(data)); } } public readonly struct RailMusicCommand { public string Identity { get; } public bool Playing { get; } public long Session { get; } public long StartTicks { get; } public long ChangedTicks { get; } public int VolumePercent { get; } public long VolumeChangedTicks { get; } public RailMusicCommand(string identity, bool playing, long session, long startTicks, long changedTicks, int volumePercent, long volumeChangedTicks) { Identity = identity; Playing = playing; Session = session; StartTicks = startTicks; ChangedTicks = changedTicks; VolumePercent = volumePercent; VolumeChangedTicks = volumeChangedTicks; } } public static class RailMusicMix { public const long MaximumFutureTicks = 10000000L; public static int LatestPlayback(IReadOnlyList commands, long session, long now) { if (!DistinctIdentities(commands) || session == 0L || now <= 0) { return -1; } long latest = 0L; long num = MaximumClock(now); int num2 = -1; for (int i = 0; i < commands.Count; i++) { RailMusicCommand railMusicCommand = commands[i]; if (railMusicCommand.Session == session && railMusicCommand.ChangedTicks >= 0) { long num3 = ((railMusicCommand.ChangedTicks == 0L) ? railMusicCommand.StartTicks : railMusicCommand.ChangedTicks); if (num3 > 0 && num3 <= num && (!railMusicCommand.Playing || (railMusicCommand.StartTicks > 0 && railMusicCommand.StartTicks <= now)) && Wins(commands, i, num3, num2, latest)) { num2 = i; latest = num3; } } } return num2; } public static int LatestVolume(IReadOnlyList commands, long now) { if (!DistinctIdentities(commands) || now < 0) { return -1; } long latest = 0L; long num = MaximumClock(now); int num2 = -1; for (int i = 0; i < commands.Count; i++) { RailMusicCommand railMusicCommand = commands[i]; if (railMusicCommand.VolumePercent >= 0 && railMusicCommand.VolumePercent <= 100 && railMusicCommand.VolumeChangedTicks >= 0 && railMusicCommand.VolumeChangedTicks <= num && Wins(commands, i, railMusicCommand.VolumeChangedTicks, num2, latest)) { num2 = i; latest = railMusicCommand.VolumeChangedTicks; } } return num2; } private static bool Wins(IReadOnlyList commands, int candidate, long changed, int winner, long latest) { if (winner >= 0 && changed <= latest) { if (changed == latest) { return string.CompareOrdinal(commands[candidate].Identity, commands[winner].Identity) < 0; } return false; } return true; } private static long MaximumClock(long now) { if (now <= 9223372036844775807L) { return now + 10000000; } return long.MaxValue; } private static bool DistinctIdentities(IReadOnlyList commands) { if (commands == null) { throw new ArgumentNullException("commands"); } if (commands.Count > 128) { return false; } HashSet hashSet = new HashSet(StringComparer.Ordinal); foreach (RailMusicCommand command in commands) { if (string.IsNullOrWhiteSpace(command.Identity) || !hashSet.Add(command.Identity)) { return false; } } return true; } } public static class RailMusicPlayback { public const string TrackId = "thunder_on_the_rails_v1"; public const string Title = "Thunder on the Rails"; public const double BeatsPerMinute = 132.0; public const double Duration = 232.72727272727272; public static bool TryPosition(bool playing, long savedSession, long currentSession, long startTicks, long nowTicks, double duration, out double seconds) { seconds = 0.0; if (!playing || currentSession == 0L || savedSession != currentSession || startTicks <= 0 || nowTicks <= 0 || startTicks > nowTicks || double.IsNaN(duration) || double.IsInfinity(duration) || duration <= 0.0 || duration > 300.0) { return false; } seconds = (double)(nowTicks - startTicks) / 10000000.0 % duration; return true; } public static double Drift(double local, double expected, double duration) { Guard.Finite(local, "local"); Guard.Finite(expected, "expected"); Guard.Finite(duration, "duration"); if (duration <= 0.0 || local < 0.0 || expected < 0.0 || local >= duration || expected >= duration) { throw new ArgumentOutOfRangeException("duration"); } double num = Math.Abs(local - expected); return Math.Min(num, duration - num); } } public sealed class RailMusicTrack { public string PrefabName { get; } public string DisplayName { get; } public string TrackId { get; } public string Title { get; } public double BeatsPerMinute { get; } public double Duration { get; } public string ResourceName { get; } public bool SupportsBanner { get; } internal RailMusicTrack(string prefabName, string displayName, string trackId, string title, double beatsPerMinute, double duration, string resourceName, bool supportsBanner) { if (string.IsNullOrEmpty(prefabName) || string.IsNullOrEmpty(displayName) || string.IsNullOrEmpty(trackId) || string.IsNullOrEmpty(title) || string.IsNullOrEmpty(resourceName)) { throw new ArgumentException("A bundled soundtrack requires complete identity fields."); } Guard.Finite(beatsPerMinute, "beatsPerMinute"); Guard.Finite(duration, "duration"); if (beatsPerMinute <= 0.0 || duration <= 0.0 || duration > 300.0) { throw new ArgumentOutOfRangeException("duration"); } PrefabName = prefabName; DisplayName = displayName; TrackId = trackId; Title = title; BeatsPerMinute = beatsPerMinute; Duration = duration; ResourceName = resourceName; SupportsBanner = supportsBanner; } } public static class RailMusicTracks { public static RailMusicTrack Techno { get; } = new RailMusicTrack("vr_music_cart", "Techno Viking sound cart", "thunder_on_the_rails_v1", "Thunder on the Rails", 132.0, 232.72727272727272, "VikingRail.Audio.thunder_on_the_rails.wav", supportsBanner: true); public static RailMusicTrack Pumpkin { get; } = new RailMusicTrack("vr_pumpkin_cart", "Halloween pumpkin carriage", "hollow_lantern_waltz_v1", "Hollow Lantern Waltz", 72.0, 240.0, "VikingRail.Audio.hollow_lantern_waltz.wav", supportsBanner: false); public static IReadOnlyList All { get; } = Array.AsReadOnly(new RailMusicTrack[2] { Techno, Pumpkin }); public static RailMusicTrack HalloweenTechno { get; } = new RailMusicTrack("vr_music_mix_halloween", "Halloween rail rave", "haunted_rail_rave_v1", "Haunted Rail Rave", 130.0, 236.30769230769232, "VikingRail.Audio.haunted_rail_rave.wav", supportsBanner: false); public static bool TryForPrefab(string? prefabName, out RailMusicTrack track) { foreach (RailMusicTrack item in All) { if (string.Equals(item.PrefabName, prefabName, StringComparison.Ordinal)) { track = item; return true; } } track = null; return false; } public static bool TryForTrackId(string? trackId, out RailMusicTrack track) { if (string.Equals(HalloweenTechno.TrackId, trackId, StringComparison.Ordinal)) { track = HalloweenTechno; return true; } foreach (RailMusicTrack item in All) { if (string.Equals(item.TrackId, trackId, StringComparison.Ordinal)) { track = item; return true; } } track = null; return false; } } public static class RailMusicVolume { public const int DefaultPercent = 100; public const int StepPercent = 10; public const string PackedKey = "vikingrail_music_volume"; public static bool IsValidPercent(int percent) { if (percent >= 0) { return percent <= 100; } return false; } public static int NormalizeSaved(int percent) { if (!IsValidPercent(percent)) { return 100; } return percent; } public static bool TryAdjust(int currentPercent, int direction, out int nextPercent) { nextPercent = currentPercent; if (!IsValidPercent(currentPercent) || (direction != -1 && direction != 1)) { return false; } nextPercent = Math.Max(0, Math.Min(100, currentPercent + direction * 10)); return true; } public static double Gain(double master, double mode, double serverCap, int cartPercent, bool muted = false) { CheckGain(master, "master"); CheckGain(mode, "mode"); CheckGain(serverCap, "serverCap"); if (!IsValidPercent(cartPercent)) { throw new ArgumentOutOfRangeException("cartPercent"); } if (!muted) { return master * mode * serverCap * ((double)cartPercent / 100.0); } return 0.0; } public static int ReadPacked(IReadOnlyDictionary data) { if (data == null) { throw new ArgumentNullException("data"); } if (!data.TryGetValue("vikingrail_music_volume", out string value)) { return 100; } if (value == null || value.Length == 0 || value.Length > 3) { throw new FormatException("The packed music cart's volume is invalid."); } string text = value; foreach (char c in text) { if (c < '0' || c > '9') { throw new FormatException("The packed music cart's volume is invalid."); } } if (!int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out var result) || !IsValidPercent(result)) { throw new FormatException("The packed music cart's volume is invalid."); } return result; } public static void Capture(IDictionary data, int percent) { if (data == null) { throw new ArgumentNullException("data"); } if (!IsValidPercent(percent)) { throw new ArgumentOutOfRangeException("percent"); } data["vikingrail_music_volume"] = percent.ToString(CultureInfo.InvariantCulture); } private static void CheckGain(double value, string name) { Guard.Finite(value, name); if (value < 0.0 || value > 1.0) { throw new ArgumentOutOfRangeException(name); } } } public sealed class RailMusicPcm { public float[] Samples { get; } public int SampleRate { get; } internal RailMusicPcm(float[] samples, int sampleRate) { Samples = samples; SampleRate = sampleRate; } } public static class RailMusicWave { public const int MaximumFileBytes = 16777216; public const int MaximumDurationSeconds = 300; public const int MinimumSampleRate = 16000; public const int MaximumSampleRate = 48000; public static RailMusicPcm Decode(byte[] wave) { if (wave == null) { throw new ArgumentNullException("wave"); } if (wave.Length < 44 || wave.Length > 16777216 || !Tag(wave, 0, "RIFF") || !Tag(wave, 8, "WAVE") || UInt32(wave, 4) != (uint)(wave.Length - 8)) { throw Invalid("Invalid RIFF/WAVE envelope or file size."); } bool flag = false; bool flag2 = false; int num = 0; int num2 = 0; int num3 = 0; int num4 = 12; while (num4 < wave.Length) { if (wave.Length - num4 < 8) { throw Invalid("Truncated WAV chunk header."); } uint num5 = UInt32(wave, num4 + 4); long num6 = (long)num4 + 8L + num5 + (num5 & 1); if (num6 > wave.Length) { throw Invalid("Truncated WAV chunk payload or padding."); } int num7 = num4 + 8; if (Tag(wave, num4, "fmt ")) { if (flag || (num5 != 16 && num5 != 18)) { throw Invalid("Invalid or repeated PCM format chunk."); } if (UInt16(wave, num7) != 1 || UInt16(wave, num7 + 2) != 1 || UInt16(wave, num7 + 14) != 16 || UInt16(wave, num7 + 12) != 2 || (num5 == 18 && UInt16(wave, num7 + 16) != 0)) { throw Invalid("Only mono PCM16 is supported."); } uint num8 = UInt32(wave, num7 + 4); if (num8 < 16000 || num8 > 48000 || UInt32(wave, num7 + 8) != num8 * 2) { throw Invalid("Unsupported sample rate or inconsistent PCM byte rate."); } num = (int)num8; flag = true; } else if (Tag(wave, num4, "data")) { if (!flag || flag2 || num5 == 0 || (num5 & 1) != 0) { throw Invalid("Missing format, empty, misaligned, or repeated sample data."); } if (num5 / 2 > (uint)(num * 300)) { throw Invalid("Music exceeds the five-minute sample budget."); } num2 = num7; num3 = (int)num5; flag2 = true; } num4 = (int)num6; } if (!flag || !flag2) { throw Invalid("Missing PCM format or sample data."); } float[] array = new float[num3 / 2]; for (int i = 0; i < array.Length; i++) { array[i] = (float)(short)UInt16(wave, num2 + i * 2) / 32768f; } return new RailMusicPcm(array, num); } private static bool Tag(byte[] bytes, int offset, string tag) { if (bytes[offset] == tag[0] && bytes[offset + 1] == tag[1] && bytes[offset + 2] == tag[2]) { return bytes[offset + 3] == tag[3]; } return false; } private static ushort UInt16(byte[] bytes, int offset) { return (ushort)(bytes[offset] | (bytes[offset + 1] << 8)); } private static uint UInt32(byte[] bytes, int offset) { return (uint)(bytes[offset] | (bytes[offset + 1] << 8) | (bytes[offset + 2] << 16) | (bytes[offset + 3] << 24)); } private static InvalidDataException Invalid(string reason) { return new InvalidDataException(reason); } } public static class RailNaturalResourcePolicy { public const double VegetationClearanceAboveBed = 3.5; public const double BranchClearanceAboveBed = 3.5; public static bool IsLooseBranchPrefab(string? prefabName) { if (!string.Equals(prefabName, "Pickable_Branch", StringComparison.OrdinalIgnoreCase)) { return string.Equals(prefabName, "Pickable_Branch_Snow", StringComparison.OrdinalIgnoreCase); } return true; } public static bool IsSmallPlantPrefab(string? prefabName) { if (prefabName == null) { return false; } switch (prefabName.ToLowerInvariant()) { case "pickable_flax_wild": case "pickable_smokepuff": case "pickable_dandelion": case "pickable_seedonion": case "bush01_deepnorth": case "pickable_thistle": case "pickable_mushroom": case "pickable_seedkale": case "fernfiddleheadashlands": case "pickable_mushroom_blue": case "pickable_seedcarrot": case "pickable_fiddlehead": case "pickable_seedturnip": case "raspberrybush": case "shrub_2_heath": case "ashlandsbush1": case "ashlandsbush2": case "blueberrybush": case "bush01_heath": case "fernashlands": case "pickable_mushroom_yellow": case "pickable_mushroom_jotunpuffs": case "pickable_mushroom_magecap": case "pickable_barley_wild": case "cloudberrybush": case "lingonberrybush": case "bush01": case "shrub_2": return true; default: return false; } } public static bool IsSoftVegetationPrefab(string? prefabName) { if (!IsLooseBranchPrefab(prefabName)) { return IsSmallPlantPrefab(prefabName); } return true; } public static bool IsSceneryRock(string? prefabName) { if (prefabName == null) { return false; } switch (prefabName.ToLowerInvariant()) { case "rock1_mountain": case "rock2_mountain": case "rock3_mountain": case "rock4_ashlands": case "rock2_heath": case "rock4_coast": case "rock4_heath": case "rock1_mistlands": case "rock3_mountain_1": case "rock3_ice": case "rock4_forest": return true; default: return false; } } public static bool IsSmallRock(double x, double y, double z) { if (x > 0.0 && y > 0.0 && z > 0.0 && x <= 2.5 && y <= 2.5 && z <= 2.5) { return x * x + y * y + z * z > 0.0001; } return false; } } public readonly struct RailCursor { public string SegmentId { get; } public double Distance { get; } public int Direction { get; } public RailCursor(string segmentId, double distance, int direction = 1) { if (string.IsNullOrWhiteSpace(segmentId)) { throw new ArgumentException("A segment ID is required.", "segmentId"); } Guard.Finite(distance, "distance"); if (distance < 0.0) { throw new ArgumentOutOfRangeException("distance"); } if (direction != 1 && direction != -1) { throw new ArgumentOutOfRangeException("direction"); } SegmentId = segmentId; Distance = distance; Direction = direction; } public RailCursor Reversed() { return new RailCursor(SegmentId, Distance, -Direction); } } public enum RailStopReason { None, EndOfTrack, AmbiguousJunction, MissingSegment } public readonly struct RailAdvanceResult { public RailCursor Cursor { get; } public double DistanceTravelled { get; } public RailStopReason StopReason { get; } public bool Stopped => StopReason != RailStopReason.None; internal RailAdvanceResult(RailCursor cursor, double distanceTravelled, RailStopReason stopReason) { Cursor = cursor; DistanceTravelled = distanceTravelled; StopReason = stopReason; } } public sealed class RailNetwork { private readonly struct Endpoint : IEquatable { internal string Id { get; } internal bool AtEnd { get; } internal RailVector Position { get; } internal RailVector Outward { get; } internal Endpoint(string id, bool atEnd, RailPath path) { Id = id; AtEnd = atEnd; RailPose railPose = path.Sample(atEnd ? path.Length : 0.0); Position = railPose.Position; Outward = railPose.Tangent * (atEnd ? 1 : (-1)); } public bool Equals(Endpoint other) { if (Id == other.Id) { return AtEnd == other.AtEnd; } return false; } public override bool Equals(object? obj) { if (obj is Endpoint other) { return Equals(other); } return false; } public override int GetHashCode() { return (StringComparer.Ordinal.GetHashCode(Id) * 397) ^ AtEnd.GetHashCode(); } } private sealed class SwitchRoute { internal readonly Endpoint Trunk; internal readonly Endpoint[] Branches; internal int SelectedRoute; internal bool Enabled; internal SwitchRoute(Endpoint trunk, Endpoint[] branches) { Trunk = trunk; Branches = branches; } internal bool ContainsPath(string id) { if (Trunk.Id == id) { return true; } Endpoint[] branches = Branches; foreach (Endpoint endpoint in branches) { if (endpoint.Id == id) { return true; } } return false; } internal bool HasBranches(string[] ids) { if (Branches.Length != ids.Length) { return false; } for (int i = 0; i < ids.Length; i++) { if (Branches[i].Id != ids[i]) { return false; } } return true; } internal bool TryPartner(Endpoint from, out Endpoint partner) { partner = default(Endpoint); if (!Enabled) { return false; } Endpoint endpoint = Branches[SelectedRoute]; if (from.Equals(Trunk)) { partner = endpoint; } else { if (!from.Equals(endpoint)) { return false; } partner = Trunk; } return true; } } private readonly Dictionary _paths = new Dictionary(StringComparer.Ordinal); private readonly Dictionary> _connections = new Dictionary>(); private readonly Dictionary _switches = new Dictionary(StringComparer.Ordinal); private readonly Dictionary _switchEndpoints = new Dictionary(); private readonly HashSet _isolated = new HashSet(StringComparer.Ordinal); private readonly double _tolerance; private readonly double _minimumDot; private Endpoint[]? _endpoints; public int Count => _paths.Count; public RailNetwork(double connectionTolerance = 0.12, double maxConnectionAngleDegrees = 12.0) { Guard.Finite(connectionTolerance, "connectionTolerance"); Guard.Finite(maxConnectionAngleDegrees, "maxConnectionAngleDegrees"); if (connectionTolerance <= 0.0) { throw new ArgumentOutOfRangeException("connectionTolerance"); } if (maxConnectionAngleDegrees < 0.0 || maxConnectionAngleDegrees >= 90.0) { throw new ArgumentOutOfRangeException("maxConnectionAngleDegrees"); } _tolerance = connectionTolerance; _minimumDot = Math.Cos(maxConnectionAngleDegrees * Math.PI / 180.0); } public void Upsert(string id, RailPath path) { if (string.IsNullOrWhiteSpace(id)) { throw new ArgumentException("A segment ID is required.", "id"); } if (path == null) { throw new ArgumentNullException("path"); } _paths[id] = path; Invalidate(); } public bool Remove(string id) { if (_isolated.Remove(id)) { Invalidate(); } bool flag = _paths.Remove(id); if (flag) { List list = new List(); foreach (KeyValuePair @switch in _switches) { SwitchRoute value = @switch.Value; if (value.ContainsPath(id)) { value.Enabled = false; bool flag2 = _paths.ContainsKey(value.Trunk.Id); Endpoint[] branches = value.Branches; foreach (Endpoint endpoint in branches) { flag2 |= _paths.ContainsKey(endpoint.Id); } if (!flag2) { list.Add(@switch.Key); } } } foreach (string item in list) { SwitchRoute switchRoute = _switches[item]; _switchEndpoints.Remove(switchRoute.Trunk); Endpoint[] branches = switchRoute.Branches; foreach (Endpoint key in branches) { _switchEndpoints.Remove(key); } _switches.Remove(item); } Invalidate(); } return flag; } public void Clear() { _paths.Clear(); _switches.Clear(); _switchEndpoints.Clear(); _isolated.Clear(); Invalidate(); } public bool TryGetPath(string id, out RailPath path) { return _paths.TryGetValue(id, out path); } public void SetIsolated(string pathId, bool isolated) { if (string.IsNullOrWhiteSpace(pathId)) { throw new ArgumentException("A path ID is required.", "pathId"); } if (isolated ? _isolated.Add(pathId) : _isolated.Remove(pathId)) { Invalidate(); } } public bool TryGetConnectedEnd(string id, bool atEnd, out RailCursor connected) { connected = default(RailCursor); if (string.IsNullOrEmpty(id) || !_paths.TryGetValue(id, out RailPath value)) { return false; } Endpoint endpoint = new Endpoint(id, atEnd, value); List connections = GetConnections(endpoint); if (connections.Count != 1) { return false; } Endpoint exit = connections[0]; List connections2 = GetConnections(exit); if (connections2.Count != 1 || !connections2[0].Equals(endpoint)) { return false; } RailPath railPath = _paths[exit.Id]; connected = new RailCursor(exit.Id, exit.AtEnd ? railPath.Length : 0.0, (!exit.AtEnd) ? 1 : (-1)); return true; } public void SetSwitch(string trunkId, string leftId, string rightId, bool selectRight) { if (string.IsNullOrWhiteSpace(leftId)) { throw new ArgumentException("A left branch ID is required.", "leftId"); } if (string.IsNullOrWhiteSpace(rightId)) { throw new ArgumentException("A right branch ID is required.", "rightId"); } SetSwitchBranches(trunkId, new string[2] { leftId, rightId }, selectRight ? 1 : 0); } public void SetThreeWaySwitch(string trunkId, string leftId, string straightId, string rightId, int selectedRoute) { SetSwitchBranches(trunkId, new string[3] { leftId, straightId, rightId }, selectedRoute); } public void SetParallelYardSwitch(string trunkId, IReadOnlyList branchIds, int selectedRoute) { if (branchIds == null) { throw new ArgumentNullException("branchIds"); } if (branchIds.Count != 3 && branchIds.Count != 5) { throw new ArgumentException("A parallel yard has three or five exits.", "branchIds"); } string[] array = new string[branchIds.Count]; for (int i = 0; i < array.Length; i++) { array[i] = branchIds[i]; } SetSwitchBranches(trunkId, array, selectedRoute); } private void SetSwitchBranches(string trunkId, string[] branchIds, int selectedRoute) { if (string.IsNullOrWhiteSpace(trunkId)) { throw new ArgumentException("A trunk ID is required.", "trunkId"); } if (selectedRoute < 0 || selectedRoute >= branchIds.Length) { throw new ArgumentOutOfRangeException("selectedRoute"); } HashSet hashSet = new HashSet(StringComparer.Ordinal) { trunkId }; foreach (string text in branchIds) { if (string.IsNullOrWhiteSpace(text) || !hashSet.Add(text)) { throw new ArgumentException("A switch needs distinct, non-empty branch IDs.", "branchIds"); } } if (!_paths.TryGetValue(trunkId, out RailPath value)) { throw new InvalidOperationException("All switch paths must be registered first."); } Endpoint endpoint = new Endpoint(trunkId, atEnd: true, value); Endpoint[] array = new Endpoint[branchIds.Length]; for (int j = 0; j < branchIds.Length; j++) { if (!_paths.TryGetValue(branchIds[j], out RailPath value2)) { throw new InvalidOperationException("All switch paths must be registered first."); } array[j] = new Endpoint(branchIds[j], atEnd: false, value2); } _switches.TryGetValue(trunkId, out SwitchRoute value3); if (value3 != null && !value3.HasBranches(branchIds)) { throw new InvalidOperationException("An existing switch cannot replace its branch paths."); } List list = new List(array) { endpoint }; foreach (Endpoint item in list) { if (_switchEndpoints.TryGetValue(item, out SwitchRoute value4) && value4 != value3) { throw new InvalidOperationException("A fork endpoint already belongs to another switch."); } } if (value3 == null) { value3 = new SwitchRoute(endpoint, array); _switches.Add(trunkId, value3); foreach (Endpoint item2 in list) { _switchEndpoints.Add(item2, value3); } } if (!value3.Enabled || value3.SelectedRoute != selectedRoute) { value3.SelectedRoute = selectedRoute; value3.Enabled = true; Invalidate(); } } public bool TryProject(RailVector point, double maxDistance, out RailCursor cursor, out double separation) { Guard.Finite(maxDistance, "maxDistance"); if (maxDistance < 0.0) { throw new ArgumentOutOfRangeException("maxDistance"); } cursor = default(RailCursor); separation = double.PositiveInfinity; foreach (KeyValuePair path in _paths) { RailProjection railProjection = path.Value.Project(point); if (!(railProjection.Separation > maxDistance) && !(railProjection.Separation > separation) && (railProjection.Separation != separation || string.CompareOrdinal(path.Key, cursor.SegmentId) < 0)) { separation = railProjection.Separation; cursor = new RailCursor(path.Key, railProjection.Distance); } } return cursor.SegmentId != null; } public RailPose Sample(RailCursor cursor) { ValidateCursor(cursor); RailPath railPath = _paths[cursor.SegmentId]; ValidateDistance(cursor, railPath); RailPose railPose = railPath.Sample(cursor.Distance); return new RailPose(railPose.Position, railPose.Tangent * cursor.Direction); } public bool TryDistanceAlongRoute(RailCursor from, RailCursor to, double maxDistance, out double distance) { ValidateCursor(from); ValidateCursor(to); Guard.Finite(maxDistance, "maxDistance"); if (maxDistance < 0.0) { throw new ArgumentOutOfRangeException("maxDistance"); } distance = 0.0; if (!_paths.TryGetValue(from.SegmentId, out RailPath value) || !_paths.TryGetValue(to.SegmentId, out RailPath value2)) { return false; } ValidateDistance(from, value); ValidateDistance(to, value2); RailCursor railCursor = from; HashSet hashSet = new HashSet(); double num = 0.0; while (true) { if (railCursor.SegmentId == to.SegmentId) { double num2 = (to.Distance - railCursor.Distance) * (double)railCursor.Direction; if (num2 >= 0.0 && num2 <= maxDistance - num) { distance = num + num2; return true; } } if (!hashSet.Add(new Endpoint(railCursor.SegmentId, railCursor.Direction == -1, value))) { return false; } double num3 = ((railCursor.Direction == 1) ? (value.Length - railCursor.Distance) : railCursor.Distance); if (num3 > maxDistance - num) { return false; } num += num3; List connections = GetConnections(new Endpoint(railCursor.SegmentId, railCursor.Direction == 1, value)); if (connections.Count != 1) { break; } Endpoint endpoint = connections[0]; value = _paths[endpoint.Id]; railCursor = new RailCursor(endpoint.Id, endpoint.AtEnd ? value.Length : 0.0, (!endpoint.AtEnd) ? 1 : (-1)); } return false; } internal bool TryDistanceToAnySegment(RailCursor from, ISet segmentIds, double maxDistance, out double distance) { ValidateCursor(from); if (segmentIds == null) { throw new ArgumentNullException("segmentIds"); } Guard.Finite(maxDistance, "maxDistance"); if (maxDistance < 0.0) { throw new ArgumentOutOfRangeException("maxDistance"); } distance = 0.0; if (!_paths.TryGetValue(from.SegmentId, out RailPath value)) { return false; } ValidateDistance(from, value); RailCursor railCursor = from; HashSet hashSet = new HashSet(); double num = 0.0; while (true) { if (segmentIds.Contains(railCursor.SegmentId)) { distance = num; return true; } if (!hashSet.Add(new Endpoint(railCursor.SegmentId, railCursor.Direction == -1, value))) { return false; } double num2 = ((railCursor.Direction == 1) ? (value.Length - railCursor.Distance) : railCursor.Distance); if (num2 > maxDistance - num) { return false; } num += num2; List connections = GetConnections(new Endpoint(railCursor.SegmentId, railCursor.Direction == 1, value)); if (connections.Count != 1) { break; } Endpoint endpoint = connections[0]; value = _paths[endpoint.Id]; railCursor = new RailCursor(endpoint.Id, endpoint.AtEnd ? value.Length : 0.0, (!endpoint.AtEnd) ? 1 : (-1)); } return false; } public RailAdvanceResult Advance(RailCursor cursor, double distance) { ValidateCursor(cursor); Guard.Finite(distance, "distance"); if (distance < 0.0) { throw new ArgumentOutOfRangeException("distance"); } if (!_paths.TryGetValue(cursor.SegmentId, out RailPath value)) { return new RailAdvanceResult(cursor, 0.0, RailStopReason.MissingSegment); } ValidateDistance(cursor, value); double num = distance; double num2 = 0.0; Dictionary dictionary = new Dictionary(); while (num > 0.0) { if ((cursor.Direction == 1 && cursor.Distance == 0.0) || (cursor.Direction == -1 && cursor.Distance == value.Length)) { Endpoint key = new Endpoint(cursor.SegmentId, cursor.Direction == -1, value); if (dictionary.TryGetValue(key, out var value2)) { double num3 = num2 - value2; if (num3 > 0.0 && num >= num3) { double num4 = num % num3; num2 += num - num4; num = num4; if (num == 0.0) { break; } } dictionary.Clear(); } dictionary[key] = num2; } double num5 = ((cursor.Direction == 1) ? (value.Length - cursor.Distance) : cursor.Distance); if (num <= num5) { cursor = new RailCursor(cursor.SegmentId, cursor.Distance + (double)cursor.Direction * num, cursor.Direction); return new RailAdvanceResult(cursor, distance, RailStopReason.None); } num -= num5; num2 += num5; cursor = new RailCursor(cursor.SegmentId, (cursor.Direction == 1) ? value.Length : 0.0, cursor.Direction); List connections = GetConnections(new Endpoint(cursor.SegmentId, cursor.Direction == 1, value)); if (connections.Count != 1) { return new RailAdvanceResult(cursor, num2, (connections.Count == 0) ? RailStopReason.EndOfTrack : RailStopReason.AmbiguousJunction); } Endpoint endpoint = connections[0]; value = _paths[endpoint.Id]; cursor = new RailCursor(endpoint.Id, endpoint.AtEnd ? value.Length : 0.0, (!endpoint.AtEnd) ? 1 : (-1)); } return new RailAdvanceResult(cursor, distance, RailStopReason.None); } private void Invalidate() { _endpoints = null; _connections.Clear(); } private List GetConnections(Endpoint exit) { if (_connections.TryGetValue(exit, out List value)) { return value; } value = new List(); if (_isolated.Contains(exit.Id)) { _connections.Add(exit, value); return value; } if (_switchEndpoints.TryGetValue(exit, out SwitchRoute value2)) { if (value2.TryPartner(exit, out var partner) && _paths.TryGetValue(partner.Id, out RailPath value3)) { Endpoint endpoint = new Endpoint(partner.Id, partner.AtEnd, value3); if (CanJoin(exit, endpoint) && AllowsConnection(endpoint, exit)) { value.Add(endpoint); } } _connections.Add(exit, value); return value; } if (_endpoints == null) { List list = new List(_paths.Count * 2); foreach (KeyValuePair path in _paths) { list.Add(new Endpoint(path.Key, atEnd: false, path.Value)); list.Add(new Endpoint(path.Key, atEnd: true, path.Value)); } list.Sort((Endpoint a, Endpoint b) => a.Position.X.CompareTo(b.Position.X)); _endpoints = list.ToArray(); } int num = 0; int num2 = _endpoints.Length; double num3 = exit.Position.X - _tolerance; while (num < num2) { int num4 = num + (num2 - num) / 2; if (_endpoints[num4].Position.X < num3) { num = num4 + 1; } else { num2 = num4; } } for (int num5 = num; num5 < _endpoints.Length && _endpoints[num5].Position.X <= exit.Position.X + _tolerance; num5++) { Endpoint endpoint2 = _endpoints[num5]; if (!(endpoint2.Id == exit.Id) && CanJoin(exit, endpoint2) && AllowsConnection(endpoint2, exit)) { value.Add(endpoint2); } } _connections.Add(exit, value); return value; } private bool AllowsConnection(Endpoint from, Endpoint to) { if (!_isolated.Contains(from.Id) && !_isolated.Contains(to.Id)) { if (_switchEndpoints.TryGetValue(from, out SwitchRoute value)) { if (value.TryPartner(from, out var partner)) { return partner.Equals(to); } return false; } return true; } return false; } private bool CanJoin(Endpoint a, Endpoint b) { if (RailVector.Distance(a.Position, b.Position) <= _tolerance) { return RailVector.Dot(a.Outward, -b.Outward) + 1E-12 >= _minimumDot; } return false; } private static void ValidateCursor(RailCursor cursor) { if (string.IsNullOrEmpty(cursor.SegmentId) || (cursor.Direction != 1 && cursor.Direction != -1)) { throw new ArgumentException("The cursor must be initialized.", "cursor"); } } private static void ValidateDistance(RailCursor cursor, RailPath path) { if (cursor.Distance > path.Length) { throw new ArgumentOutOfRangeException("cursor", "The cursor exceeds the path length."); } } } public sealed class RailParallelYardTrackDefinition { public string PrefabName { get; } public bool LightDuty { get; } public int ExitCount { get; } public double ForwardLength => (ExitCount == 3) ? 16 : 24; public double BranchStart => 1.0 - ForwardLength / 2.0; public int WoodCost { get { if (ExitCount != 3) { if (!LightDuty) { return 80; } return 64; } if (!LightDuty) { return 50; } return 40; } } public int NailsCost { get { if (ExitCount != 3) { if (!LightDuty) { return 30; } return 18; } if (!LightDuty) { return 20; } return 12; } } internal RailParallelYardTrackDefinition(int exits, bool lightDuty) { ExitCount = exits; LightDuty = lightDuty; PrefabName = "vr_track_" + (lightDuty ? "wood_" : "") + "yard" + exits; } public RailVector[] TrunkPoints() { return new RailVector[2] { new RailVector(0.0, 0.0, BranchStart - 2.0), new RailVector(0.0, 0.0, BranchStart) }; } public RailVector[] BranchPoints(int route) { if (route < 0 || route >= ExitCount) { throw new ArgumentOutOfRangeException("route"); } double num = (double)(route - ExitCount / 2) * 4.0; double num2 = ForwardLength - 2.0; RailVector[] array = new RailVector[37]; array[0] = new RailVector(0.0, 0.0, BranchStart); array[1] = new RailVector(0.0, 0.0, BranchStart + 0.5); for (int i = 0; i <= 32; i++) { double num3 = (double)i / 32.0; double num4 = num3 * num3 * num3 * (10.0 + num3 * (-15.0 + 6.0 * num3)); array[i + 2] = new RailVector(num * num4, 0.0, BranchStart + 1.0 + num2 * num3); } array[^2] = new RailVector(num, 0.0, BranchStart + ForwardLength - 0.5); array[^1] = new RailVector(num, 0.0, BranchStart + ForwardLength); return array; } } public static class RailParallelYardTracks { public const double LaneSpacing = 4.0; public const double StemLength = 2.0; public const double PortLength = 1.0; public const int CurveSegments = 32; public const int MaximumRoutes = 5; public static IReadOnlyList All { get; } = Array.AsReadOnly(new RailParallelYardTrackDefinition[4] { new RailParallelYardTrackDefinition(3, lightDuty: false), new RailParallelYardTrackDefinition(3, lightDuty: true), new RailParallelYardTrackDefinition(5, lightDuty: false), new RailParallelYardTrackDefinition(5, lightDuty: true) }); public static bool TryGet(string? prefabName, out RailParallelYardTrackDefinition definition) { foreach (RailParallelYardTrackDefinition item in All) { if (string.Equals(prefabName, item.PrefabName, StringComparison.Ordinal)) { definition = item; return true; } } definition = null; return false; } } public readonly struct RailPlowPush { public RailVector Direction { get; } public double Speed { get; } internal RailPlowPush(RailVector direction, double speed) { Direction = direction; Speed = speed; } } public static class RailPlowMath { public const double MinimumForwardSpeed = 0.05; public const double MaximumForwardSpeed = 15.0; public const double MaximumContactSweep = 0.75; public const double FrontStart = 0.5; public const double FrontReach = 2.0; public const double HalfWidth = 1.15; public const double MinimumLateralSpeed = 6.0; public const double MaximumLateralSpeed = 10.0; public const double ClearanceHalfWidth = 1.8; public const double ClearancePulseSeconds = 1.25; public static bool TryPlan(RailVector enginePosition, RailVector forward, RailVector creaturePosition, double creatureRadius, double speed, bool attached, bool isPlayer, bool alive, out RailPlowPush push, double contactSweep = 0.0) { push = default(RailPlowPush); if (!attached || isPlayer || !alive || !Finite(speed) || !Finite(creatureRadius) || !Finite(contactSweep) || creatureRadius < 0.0 || speed <= 0.05 || contactSweep < 0.0 || contactSweep > 0.75) { return false; } double num = Math.Max(Math.Abs(forward.X), Math.Abs(forward.Z)); if (num <= 1E-08) { return false; } double num2 = forward.X / num; double num3 = forward.Z / num; double num4 = Math.Sqrt(num2 * num2 + num3 * num3); num2 /= num4; num3 /= num4; double num5 = creaturePosition.X - enginePosition.X; double num6 = creaturePosition.Z - enginePosition.Z; double num7 = num5 * num2 + num6 * num3; double num8 = num5 * num3 - num6 * num2; if (!Finite(num7) || !Finite(num8) || num7 + creatureRadius < 0.5 || num7 > 2.0 + creatureRadius + contactSweep || Math.Abs(num8) > 1.15 + creatureRadius) { return false; } double num9 = ((!(num8 < 0.0)) ? 1 : (-1)); RailVector direction = new RailVector(num3 * num9, 0.0, (0.0 - num2) * num9); double speed2 = Math.Max(6.0, Math.Min(10.0, 6.0 + Math.Min(speed, 15.0) * 0.5)); push = new RailPlowPush(direction, speed2); return true; } private static bool Finite(double value) { if (!double.IsNaN(value)) { return !double.IsInfinity(value); } return false; } } public static class RailPlowImpact { public const double DamageCooldownSeconds = 2.0; public const double ContactSeparationSeconds = 0.6; public const double RequiredEngineTravel = 0.75; public const double MaximumBluntDamage = 65.0; public static double BluntDamage(double forwardSpeed, bool wooden) { if (!Finite(forwardSpeed) || forwardSpeed <= 0.05) { return 0.0; } double num = Math.Min(65.0, 8.0 + Math.Min(forwardSpeed, 15.0) * 6.0); if (!wooden) { return num; } return num * 0.6; } public static bool CanDamageContact(bool previousHit, bool sameEngine, double elapsedSinceHit, double gapSinceContact, double engineTravel) { if (!Finite(elapsedSinceHit) || !Finite(gapSinceContact) || !Finite(engineTravel) || elapsedSinceHit < 0.0 || gapSinceContact < 0.0 || engineTravel < 0.0) { return false; } if (previousHit) { if (elapsedSinceHit >= 2.0) { if (sameEngine) { if (gapSinceContact >= 0.6) { return engineTravel >= 0.75; } return false; } return true; } return false; } return true; } private static bool Finite(double value) { if (!double.IsNaN(value)) { return !double.IsInfinity(value); } return false; } } public static class RailPumpkinShell { public sealed class Face { public RailVector[] Points { get; } public int Surface { get; } internal Face(int surface, params RailVector[] points) { Surface = surface; Points = points; } } public const int Around = 60; public const int Rows = 16; public const double CenterY = 1.78; public const double RadiusX = 1.1; public const double RadiusY = 0.99; public const double RadiusZ = 1.14; public const double Thickness = 0.085; public static RailVector Point(double latitude, double longitude, bool inner = false) { Guard.Finite(latitude, "latitude"); Guard.Finite(longitude, "longitude"); double num = (inner ? 0.085 : 0.0); double num2 = 0.96 + 0.04 * Math.Cos(10.0 * longitude); double num3 = Math.Sin(latitude) * num2; return new RailVector((1.1 - num) * num3 * Math.Sin(longitude), 1.78 + (0.99 - num) * Math.Cos(latitude), (1.14 - num) * num3 * Math.Cos(longitude)); } private static bool Present(int row, int column) { if (row < 0 || row >= 16) { return true; } column = (column % 60 + 60) % 60; double value = -Math.PI + ((double)column + 0.5) * 2.0 * Math.PI / 60.0; if (row >= 2 && row <= 14) { return !(Math.Abs(value) < Math.PI / 5.0); } return true; } public static IReadOnlyList Build() { List list = new List(); for (int i = 0; i < 16; i++) { for (int j = 0; j < 60; j++) { if (Present(i, j)) { double latitude = (double)i * Math.PI / 16.0; double latitude2 = (double)(i + 1) * Math.PI / 16.0; double longitude = -Math.PI + (double)(j * 2) * Math.PI / 60.0; double longitude2 = -Math.PI + (double)((j + 1) * 2) * Math.PI / 60.0; RailVector[] array = new RailVector[4] { Point(latitude, longitude), Point(latitude2, longitude), Point(latitude2, longitude2), Point(latitude, longitude2) }; RailVector[] array2 = new RailVector[4] { Point(latitude, longitude, inner: true), Point(latitude2, longitude, inner: true), Point(latitude2, longitude2, inner: true), Point(latitude, longitude2, inner: true) }; list.Add(new Face(0, array)); list.Add(new Face(1, array2[3], array2[2], array2[1], array2[0])); if (!Present(i, j - 1)) { Rim(list, array, array2, 0, 1); } if (!Present(i + 1, j)) { Rim(list, array, array2, 1, 2); } if (!Present(i, j + 1)) { Rim(list, array, array2, 2, 3); } if (!Present(i - 1, j)) { Rim(list, array, array2, 3, 0); } } } } return list; } private static void Rim(List faces, RailVector[] outer, RailVector[] inner, int a, int b) { faces.Add(new Face(2, outer[b], outer[a], inner[a], inner[b])); } } public sealed class RailPumpStaminaLedger { private bool _observed; private double _lastStamina; private double _issued; private double _acknowledged; private double _checkpointIssued; private long _nextCheckpoint; private long _pendingCheckpoint; public double Available { get { if (!_observed) { return 0.0; } return Math.Max(0.0, _lastStamina - (_issued - _acknowledged)); } } public bool CheckpointPending => _pendingCheckpoint != 0; public bool CanSpend(double cost) { if (Finite(cost) && cost >= 0.0) { if (cost != 0.0) { if (_observed) { return Available > cost; } return false; } return true; } return false; } public long BeginCheckpoint() { _checkpointIssued = _issued; _pendingCheckpoint = checked(++_nextCheckpoint); return _pendingCheckpoint; } public bool Acknowledge(long checkpoint, double observedStamina) { if (checkpoint == 0L || checkpoint != _pendingCheckpoint || !Finite(observedStamina) || observedStamina < 0.0) { return false; } _observed = true; _lastStamina = observedStamina; _acknowledged = _checkpointIssued; _pendingCheckpoint = 0L; return true; } public void RecordSpend(double cost) { if (_observed && Finite(cost) && !(cost <= 0.0)) { _issued = Math.Min(double.MaxValue, _issued + cost); } } public void Reset() { _observed = false; _lastStamina = 0.0; _issued = (_acknowledged = (_checkpointIssued = 0.0)); _pendingCheckpoint = 0L; } private static bool Finite(double value) { if (!double.IsNaN(value)) { return !double.IsInfinity(value); } return false; } } public static class RailRemoteTransfer { public static bool IsAcknowledged(long expectedServerOwner, long actualOwner, ushort actualOwnerRevision, uint actualDataRevision, long acknowledgedStamp, string? expectedDigest, string? actualDigest) { if (expectedServerOwner == 0L || actualOwner != expectedServerOwner || acknowledgedStamp < 0 || acknowledgedStamp >> 48 != 0L || actualOwnerRevision != (ushort)(acknowledgedStamp >> 32) || actualDataRevision < (uint)acknowledgedStamp || !ValidDigest(expectedDigest) || !ValidDigest(actualDigest)) { return false; } return string.Equals(expectedDigest, actualDigest, StringComparison.Ordinal); } private static bool ValidDigest(string? digest) { if (digest == null || digest.Length != 64) { return false; } foreach (char c in digest) { if ((c < '0' || c > '9') && (c < 'A' || c > 'F') && (c < 'a' || c > 'f')) { return false; } } return true; } } public static class RailRepairPolicy { public const int MaximumStationLevel = 4; public static bool CanRepair(bool usesDurability, bool repairable, float durability, float maximumDurability, int minimumStationLevel, string? craftingStation, string? repairStation, string? workbenchStation, string? forgeStation) { if (!usesDurability || !repairable || float.IsNaN(durability) || float.IsInfinity(durability) || durability < 0f || float.IsNaN(maximumDurability) || float.IsInfinity(maximumDurability) || maximumDurability <= 0f || durability >= maximumDurability || minimumStationLevel > 4) { return false; } if (!Matches(craftingStation, workbenchStation) && !Matches(craftingStation, forgeStation) && !Matches(repairStation, workbenchStation)) { return Matches(repairStation, forgeStation); } return true; } private static bool Matches(string? recipeStation, string? supportedStation) { if (!string.IsNullOrWhiteSpace(recipeStation) && !string.IsNullOrWhiteSpace(supportedStation)) { return string.Equals(recipeStation, supportedStation, StringComparison.Ordinal); } return false; } } public sealed class RailRiderPoseHold { public const double SettleSeconds = 0.3; private bool _observed; private int _state; private double _since; private double _last; private double _animationStart; private bool _evaluated; public bool Update(bool eligible, bool neutral, bool transitioning, int state, double now, double animationTime) { if (!eligible || !neutral || transitioning || double.IsNaN(now) || double.IsInfinity(now) || double.IsNaN(animationTime) || double.IsInfinity(animationTime)) { Reset(); return false; } if (!_observed || state != _state || now < _last) { _observed = true; _state = state; _since = now; _animationStart = animationTime; _evaluated = false; } _evaluated |= Math.Abs(animationTime - _animationStart) > 1E-06; _last = now; if (_evaluated) { return now - _since >= 0.3; } return false; } public void Reset() { _observed = false; } } public readonly struct RailStopMarker { public string Id { get; } public RailCursor Cursor { get; } public bool IsBumper { get; } public RailStopMarker(string id, RailCursor cursor, bool isBumper) { if (string.IsNullOrWhiteSpace(id)) { throw new ArgumentException("A marker ID is required.", "id"); } if (string.IsNullOrEmpty(cursor.SegmentId) || (cursor.Direction != -1 && cursor.Direction != 1)) { throw new ArgumentException("The marker cursor must be initialized.", "cursor"); } Id = id; Cursor = cursor; IsBumper = isBumper; } } public readonly struct RailSafetyResult { public bool HasStop => MarkerId != null; public double Distance { get; } public string? MarkerId { get; } public bool IsBumper { get; } internal RailSafetyResult(double distance, string? markerId, bool isBumper) { Distance = distance; MarkerId = markerId; IsBumper = isBumper; } } public static class RailSafety { public static bool CanRelocate(RailNetwork network, RailCursor from, RailCursor to, double maxDistance, bool includeBrakes, IEnumerable markers, ISet bypassBrakeIds, out RailSafetyResult obstruction) { if (network == null) { throw new ArgumentNullException("network"); } if (markers == null) { throw new ArgumentNullException("markers"); } if (bypassBrakeIds == null) { throw new ArgumentNullException("bypassBrakeIds"); } Guard.Finite(maxDistance, "maxDistance"); if (maxDistance < 0.0) { throw new ArgumentOutOfRangeException("maxDistance"); } obstruction = new RailSafetyResult(0.0, null, isBumper: false); double distance; bool flag = network.TryDistanceAlongRoute(from, to, maxDistance, out distance); double distance2; bool flag2 = network.TryDistanceAlongRoute(from.Reversed(), to, maxDistance, out distance2); if (!flag && !flag2) { return false; } bool flag3 = flag && (!flag2 || distance <= distance2); double num = (flag3 ? distance : distance2); if (num == 0.0) { return true; } obstruction = FindFirstStop(network, new RailCursor[1] { from }, flag3, num, RelevantMarkers(markers, includeBrakes), bypassBrakeIds); if (obstruction.HasStop) { return obstruction.Distance >= num - 1E-07; } return true; } private static IEnumerable RelevantMarkers(IEnumerable markers, bool includeBrakes) { foreach (RailStopMarker marker in markers) { if (includeBrakes || marker.IsBumper) { yield return marker; } } } public static RailSafetyResult FindFirstStop(RailNetwork network, IReadOnlyList trainCursors, bool movingForward, double proposedDistance, IEnumerable markers, ISet bypassBrakeIds) { if (network == null) { throw new ArgumentNullException("network"); } if (trainCursors == null) { throw new ArgumentNullException("trainCursors"); } if (markers == null) { throw new ArgumentNullException("markers"); } if (bypassBrakeIds == null) { throw new ArgumentNullException("bypassBrakeIds"); } if (trainCursors.Count == 0) { throw new ArgumentException("A train needs at least one vehicle.", "trainCursors"); } Guard.Finite(proposedDistance, "proposedDistance"); if (proposedDistance < 0.0) { throw new ArgumentOutOfRangeException("proposedDistance"); } for (int i = 0; i < trainCursors.Count; i++) { network.Sample(trainCursors[i]); } RailSafetyResult result = new RailSafetyResult(proposedDistance, null, isBumper: false); int num = ((!movingForward) ? (trainCursors.Count - 1) : 0); foreach (RailStopMarker marker in markers) { if (string.IsNullOrEmpty(marker.Id)) { throw new ArgumentException("Markers must be initialized.", "markers"); } if (!network.TryGetPath(marker.Cursor.SegmentId, out RailPath _)) { continue; } RailPose railPose = network.Sample(marker.Cursor); if (!marker.IsBumper && bypassBrakeIds.Contains(marker.Id)) { continue; } int num2 = ((!marker.IsBumper) ? num : 0); int num3 = (marker.IsBumper ? (trainCursors.Count - 1) : num); for (int j = num2; j <= num3; j++) { RailCursor railCursor = (movingForward ? trainCursors[j] : trainCursors[j].Reversed()); double distance; if (marker.IsBumper && railCursor.SegmentId == marker.Cursor.SegmentId && railCursor.Direction == marker.Cursor.Direction && (railCursor.Distance - marker.Cursor.Distance) * (double)marker.Cursor.Direction >= 0.0) { distance = 0.0; } else { if (!network.TryDistanceAlongRoute(railCursor, marker.Cursor, result.Distance, out distance)) { continue; } if (marker.IsBumper) { RailCursor cursor = network.Advance(railCursor, distance).Cursor; if (RailVector.Dot(network.Sample(cursor).Tangent, railPose.Tangent) <= 0.0) { continue; } } } bool flag = result.HasStop && distance == result.Distance && ((marker.IsBumper && !result.IsBumper) || (marker.IsBumper == result.IsBumper && string.CompareOrdinal(marker.Id, result.MarkerId) < 0)); if (!result.HasStop || distance < result.Distance || flag) { result = new RailSafetyResult(distance, marker.Id, marker.IsBumper); } } } return result; } } public static class RailSettingsCodec { public const int ProtocolVersion = 13; public const string RequestRpc = "VikingRail_RequestSettings_v13"; public const string SettingsRpc = "VikingRail_Settings_v13"; public const int PacketLength = 211; public static byte[] Encode(RailSettingsValues values) { if (values == null) { throw new ArgumentNullException("values"); } using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write(13); binaryWriter.Write(values.AttachedTorchesUseFuel); binaryWriter.Write(values.CoalSecondsPerItem); binaryWriter.Write(values.HandcartMaxCarts); binaryWriter.Write(values.LocomotiveMaxCarts); binaryWriter.Write(values.ClearTerrainOnPlacement); binaryWriter.Write(values.DirtTrackbedOnPlacement); binaryWriter.Write(values.HandcartStaminaPerSecond); binaryWriter.Write(values.FillTerrainOnPlacement); binaryWriter.Write(values.HandcartMaxSpeed); binaryWriter.Write(values.LocomotiveMaxSpeed); binaryWriter.Write(values.TracksTakeDamage); binaryWriter.Write(values.TandemHandcartMaxSpeed); binaryWriter.Write(values.TandemHandcartStaminaPerSecond); binaryWriter.Write(values.TandemHandcartMaxCarts); binaryWriter.Write(values.BronzeFuelSecondsPerItem); binaryWriter.Write(values.BronzeEngineMaxSpeed); binaryWriter.Write(values.BronzeEngineMaxCarts); binaryWriter.Write(values.HandcartLoadPenaltyMultiplier); binaryWriter.Write(values.HandcartHillPenaltyMultiplier); binaryWriter.Write(values.TandemHandcartLoadPenaltyMultiplier); binaryWriter.Write(values.TandemHandcartHillPenaltyMultiplier); binaryWriter.Write(values.BronzeEngineLoadPenaltyMultiplier); binaryWriter.Write(values.BronzeEngineHillPenaltyMultiplier); binaryWriter.Write(values.LocomotiveLoadPenaltyMultiplier); binaryWriter.Write(values.LocomotiveHillPenaltyMultiplier); binaryWriter.Write(values.EitrFuelSecondsPerItem); binaryWriter.Write(values.EitrEngineMaxSpeed); binaryWriter.Write(values.EitrEngineMaxCarts); binaryWriter.Write(values.EitrEngineLoadPenaltyMultiplier); binaryWriter.Write(values.EitrEngineHillPenaltyMultiplier); binaryWriter.Write(values.RemoteSimulationEnabled); binaryWriter.Write(values.RemoteTrainLimit); binaryWriter.Write(values.MusicCartsEnabled); binaryWriter.Write(values.MusicCartRange); binaryWriter.Write(values.MusicCartMaxVolume); return memoryStream.ToArray(); } public static RailSettingsValues Decode(byte[] data) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length != 211) { throw new FormatException("Incomplete or trailing railroad settings data."); } using MemoryStream input = new MemoryStream(data, writable: false); using BinaryReader binaryReader = new BinaryReader(input); if (binaryReader.ReadInt32() != 13) { throw new FormatException("Unsupported railroad settings protocol."); } return new RailSettingsValues(ReadBoolean(binaryReader), binaryReader.ReadDouble(), binaryReader.ReadInt32(), binaryReader.ReadInt32(), ReadBoolean(binaryReader), ReadBoolean(binaryReader), binaryReader.ReadDouble(), ReadBoolean(binaryReader), binaryReader.ReadDouble(), binaryReader.ReadDouble(), ReadBoolean(binaryReader), binaryReader.ReadDouble(), binaryReader.ReadDouble(), binaryReader.ReadInt32(), binaryReader.ReadDouble(), binaryReader.ReadDouble(), binaryReader.ReadInt32(), binaryReader.ReadDouble(), binaryReader.ReadDouble(), binaryReader.ReadDouble(), binaryReader.ReadDouble(), binaryReader.ReadDouble(), binaryReader.ReadDouble(), binaryReader.ReadDouble(), binaryReader.ReadDouble(), binaryReader.ReadDouble(), binaryReader.ReadDouble(), binaryReader.ReadInt32(), binaryReader.ReadDouble(), binaryReader.ReadDouble(), ReadBoolean(binaryReader), binaryReader.ReadInt32(), ReadBoolean(binaryReader), binaryReader.ReadDouble(), binaryReader.ReadDouble()); } private static bool ReadBoolean(BinaryReader reader) { byte num = reader.ReadByte(); if (num > 1) { throw new FormatException("Invalid railroad settings boolean."); } return num == 1; } } public sealed class RailSettingsProposal { public const int FieldCount = 35; public const ulong AllFields = 34359738367uL; public const int PacketLength = 223; public int RequestId { get; } public ulong Mask { get; } public RailSettingsValues Values { get; } public RailSettingsProposal(int requestId, ulong mask, RailSettingsValues values) { if (requestId <= 0) { throw new ArgumentOutOfRangeException("requestId"); } if (mask == 0L || (mask & 0xFFFFFFF800000000uL) != 0L) { throw new ArgumentOutOfRangeException("mask"); } RequestId = requestId; Mask = mask; Values = values ?? throw new ArgumentNullException("values"); } public static ulong ChangedFields(RailSettingsValues before, RailSettingsValues after) { if (before == null) { throw new ArgumentNullException("before"); } if (after == null) { throw new ArgumentNullException("after"); } ulong num = 0uL; if (before.AttachedTorchesUseFuel != after.AttachedTorchesUseFuel) { num |= 1; } if (before.CoalSecondsPerItem != after.CoalSecondsPerItem) { num |= 2; } if (before.HandcartMaxCarts != after.HandcartMaxCarts) { num |= 4; } if (before.LocomotiveMaxCarts != after.LocomotiveMaxCarts) { num |= 8; } if (before.ClearTerrainOnPlacement != after.ClearTerrainOnPlacement) { num |= 0x10; } if (before.DirtTrackbedOnPlacement != after.DirtTrackbedOnPlacement) { num |= 0x20; } if (before.HandcartStaminaPerSecond != after.HandcartStaminaPerSecond) { num |= 0x40; } if (before.FillTerrainOnPlacement != after.FillTerrainOnPlacement) { num |= 0x80; } if (before.HandcartMaxSpeed != after.HandcartMaxSpeed) { num |= 0x100; } if (before.LocomotiveMaxSpeed != after.LocomotiveMaxSpeed) { num |= 0x200; } if (before.TracksTakeDamage != after.TracksTakeDamage) { num |= 0x400; } if (before.TandemHandcartMaxSpeed != after.TandemHandcartMaxSpeed) { num |= 0x800; } if (before.TandemHandcartStaminaPerSecond != after.TandemHandcartStaminaPerSecond) { num |= 0x1000; } if (before.TandemHandcartMaxCarts != after.TandemHandcartMaxCarts) { num |= 0x2000; } if (before.BronzeFuelSecondsPerItem != after.BronzeFuelSecondsPerItem) { num |= 0x4000; } if (before.BronzeEngineMaxSpeed != after.BronzeEngineMaxSpeed) { num |= 0x8000; } if (before.BronzeEngineMaxCarts != after.BronzeEngineMaxCarts) { num |= 0x10000; } if (before.HandcartLoadPenaltyMultiplier != after.HandcartLoadPenaltyMultiplier) { num |= 0x20000; } if (before.HandcartHillPenaltyMultiplier != after.HandcartHillPenaltyMultiplier) { num |= 0x40000; } if (before.TandemHandcartLoadPenaltyMultiplier != after.TandemHandcartLoadPenaltyMultiplier) { num |= 0x80000; } if (before.TandemHandcartHillPenaltyMultiplier != after.TandemHandcartHillPenaltyMultiplier) { num |= 0x100000; } if (before.BronzeEngineLoadPenaltyMultiplier != after.BronzeEngineLoadPenaltyMultiplier) { num |= 0x200000; } if (before.BronzeEngineHillPenaltyMultiplier != after.BronzeEngineHillPenaltyMultiplier) { num |= 0x400000; } if (before.LocomotiveLoadPenaltyMultiplier != after.LocomotiveLoadPenaltyMultiplier) { num |= 0x800000; } if (before.LocomotiveHillPenaltyMultiplier != after.LocomotiveHillPenaltyMultiplier) { num |= 0x1000000; } if (before.EitrFuelSecondsPerItem != after.EitrFuelSecondsPerItem) { num |= 0x2000000; } if (before.EitrEngineMaxSpeed != after.EitrEngineMaxSpeed) { num |= 0x4000000; } if (before.EitrEngineMaxCarts != after.EitrEngineMaxCarts) { num |= 0x8000000; } if (before.EitrEngineLoadPenaltyMultiplier != after.EitrEngineLoadPenaltyMultiplier) { num |= 0x10000000; } if (before.EitrEngineHillPenaltyMultiplier != after.EitrEngineHillPenaltyMultiplier) { num |= 0x20000000; } if (before.RemoteSimulationEnabled != after.RemoteSimulationEnabled) { num |= 0x40000000; } if (before.RemoteTrainLimit != after.RemoteTrainLimit) { num |= 0x80000000u; } if (before.MusicCartsEnabled != after.MusicCartsEnabled) { num |= 0x100000000L; } if (before.MusicCartRange != after.MusicCartRange) { num |= 0x200000000L; } if (before.MusicCartMaxVolume != after.MusicCartMaxVolume) { num |= 0x400000000L; } return num; } public RailSettingsValues ApplyTo(RailSettingsValues current) { if (current == null) { throw new ArgumentNullException("current"); } return new RailSettingsValues(Has(0) ? Values.AttachedTorchesUseFuel : current.AttachedTorchesUseFuel, Has(1) ? Values.CoalSecondsPerItem : current.CoalSecondsPerItem, Has(2) ? Values.HandcartMaxCarts : current.HandcartMaxCarts, Has(3) ? Values.LocomotiveMaxCarts : current.LocomotiveMaxCarts, Has(4) ? Values.ClearTerrainOnPlacement : current.ClearTerrainOnPlacement, Has(5) ? Values.DirtTrackbedOnPlacement : current.DirtTrackbedOnPlacement, Has(6) ? Values.HandcartStaminaPerSecond : current.HandcartStaminaPerSecond, Has(7) ? Values.FillTerrainOnPlacement : current.FillTerrainOnPlacement, Has(8) ? Values.HandcartMaxSpeed : current.HandcartMaxSpeed, Has(9) ? Values.LocomotiveMaxSpeed : current.LocomotiveMaxSpeed, Has(10) ? Values.TracksTakeDamage : current.TracksTakeDamage, Has(11) ? Values.TandemHandcartMaxSpeed : current.TandemHandcartMaxSpeed, Has(12) ? Values.TandemHandcartStaminaPerSecond : current.TandemHandcartStaminaPerSecond, Has(13) ? Values.TandemHandcartMaxCarts : current.TandemHandcartMaxCarts, Has(14) ? Values.BronzeFuelSecondsPerItem : current.BronzeFuelSecondsPerItem, Has(15) ? Values.BronzeEngineMaxSpeed : current.BronzeEngineMaxSpeed, Has(16) ? Values.BronzeEngineMaxCarts : current.BronzeEngineMaxCarts, Has(17) ? Values.HandcartLoadPenaltyMultiplier : current.HandcartLoadPenaltyMultiplier, Has(18) ? Values.HandcartHillPenaltyMultiplier : current.HandcartHillPenaltyMultiplier, Has(19) ? Values.TandemHandcartLoadPenaltyMultiplier : current.TandemHandcartLoadPenaltyMultiplier, Has(20) ? Values.TandemHandcartHillPenaltyMultiplier : current.TandemHandcartHillPenaltyMultiplier, Has(21) ? Values.BronzeEngineLoadPenaltyMultiplier : current.BronzeEngineLoadPenaltyMultiplier, Has(22) ? Values.BronzeEngineHillPenaltyMultiplier : current.BronzeEngineHillPenaltyMultiplier, Has(23) ? Values.LocomotiveLoadPenaltyMultiplier : current.LocomotiveLoadPenaltyMultiplier, Has(24) ? Values.LocomotiveHillPenaltyMultiplier : current.LocomotiveHillPenaltyMultiplier, Has(25) ? Values.EitrFuelSecondsPerItem : current.EitrFuelSecondsPerItem, Has(26) ? Values.EitrEngineMaxSpeed : current.EitrEngineMaxSpeed, Has(27) ? Values.EitrEngineMaxCarts : current.EitrEngineMaxCarts, Has(28) ? Values.EitrEngineLoadPenaltyMultiplier : current.EitrEngineLoadPenaltyMultiplier, Has(29) ? Values.EitrEngineHillPenaltyMultiplier : current.EitrEngineHillPenaltyMultiplier, Has(30) ? Values.RemoteSimulationEnabled : current.RemoteSimulationEnabled, Has(31) ? Values.RemoteTrainLimit : current.RemoteTrainLimit, Has(32) ? Values.MusicCartsEnabled : current.MusicCartsEnabled, Has(33) ? Values.MusicCartRange : current.MusicCartRange, Has(34) ? Values.MusicCartMaxVolume : current.MusicCartMaxVolume); } private bool Has(int field) { return (Mask & (ulong)(1L << field)) != 0; } public byte[] Encode() { using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write(RequestId); binaryWriter.Write(Mask); binaryWriter.Write(RailSettingsCodec.Encode(Values)); return memoryStream.ToArray(); } public static RailSettingsProposal Decode(byte[] data) { if (data == null) { throw new ArgumentNullException("data"); } if (data.Length != 223) { throw new FormatException("Incomplete or trailing railroad settings proposal."); } using BinaryReader binaryReader = new BinaryReader(new MemoryStream(data, writable: false)); return new RailSettingsProposal(binaryReader.ReadInt32(), binaryReader.ReadUInt64(), RailSettingsCodec.Decode(binaryReader.ReadBytes(211))); } } public sealed class RailSettingsRequestLedger { public int LastRequestId { get; private set; } public bool TryStart(int requestId) { if (requestId <= LastRequestId) { return false; } LastRequestId = requestId; return true; } } public static class RailSettingsText { private sealed class Values { private readonly Dictionary _entries; private readonly Action? _warning; internal Values(Dictionary entries, Action? warning) { _entries = entries; _warning = warning; } internal bool Boolean(string name, bool previous, bool fallback) { if (!_entries.TryGetValue(name, out string value)) { return previous; } if (bool.TryParse(value, out var result)) { return result; } Invalid(name, fallback.ToString()); return fallback; } internal double Number(string name, double previous, double fallback, double min, double max) { if (!_entries.TryGetValue(name, out string value)) { return previous; } if (!double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result) || double.IsNaN(result) || double.IsInfinity(result)) { Invalid(name, fallback.ToString(CultureInfo.InvariantCulture)); return fallback; } double num = Math.Max(min, Math.Min(max, result)); if (num != result) { Clamped(name, num.ToString(CultureInfo.InvariantCulture)); } return num; } internal int Integer(string name, int previous, int fallback, int min, int max) { if (!_entries.TryGetValue(name, out string value)) { return previous; } if (!int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { Invalid(name, fallback.ToString(CultureInfo.InvariantCulture)); return fallback; } int num = Math.Max(min, Math.Min(max, result)); if (num != result) { Clamped(name, num.ToString(CultureInfo.InvariantCulture)); } return num; } private void Invalid(string name, string fallback) { _warning?.Invoke("Invalid " + name + "; using its default " + fallback + "."); } private void Clamped(string name, string value) { _warning?.Invoke("Out-of-range " + name + "; clamped to " + value + "."); } } private static readonly HashSet Names = new HashSet(StringComparer.Ordinal) { "Fuel.AttachedTorchesUseFuel", "Fuel.CoalSecondsPerItem", "Trains.HandcartMaxCarts", "Trains.LocomotiveMaxCarts", "Trains.HandcartStaminaPerSecond", "Trains.HandcartMaxSpeed", "Trains.LocomotiveMaxSpeed", "Trains.TandemHandcartMaxSpeed", "Trains.TandemHandcartStaminaPerSecond", "Trains.TandemHandcartMaxCarts", "Fuel.BronzeFuelSecondsPerItem", "Trains.BronzeEngineMaxSpeed", "Trains.BronzeEngineMaxCarts", "Trains.HandcartLoadPenaltyMultiplier", "Trains.HandcartHillPenaltyMultiplier", "Trains.TandemHandcartLoadPenaltyMultiplier", "Trains.TandemHandcartHillPenaltyMultiplier", "Trains.BronzeEngineLoadPenaltyMultiplier", "Trains.BronzeEngineHillPenaltyMultiplier", "Trains.LocomotiveLoadPenaltyMultiplier", "Trains.LocomotiveHillPenaltyMultiplier", "Fuel.EitrFuelSecondsPerItem", "Trains.EitrEngineMaxSpeed", "Trains.EitrEngineMaxCarts", "Trains.EitrEngineLoadPenaltyMultiplier", "Trains.EitrEngineHillPenaltyMultiplier", "Automation.RemoteSimulationEnabled", "Automation.RemoteTrainLimit", "Music.MusicCartsEnabled", "Music.MusicCartRange", "Music.MusicCartMaxVolume", "MusicClient.Volume", "MusicClient.Muted", "MusicClient.BeatLights", "MusicClient.MaxAudibleCarts", "MusicClient.TechnoVolume", "MusicClient.PumpkinVolume", "MusicClient.HalloweenTechnoVolume", "Construction.ClearTerrainOnPlacement", "Construction.DirtTrackbedOnPlacement", "Construction.FillTerrainOnPlacement", "Construction.TracksTakeDamage" }; private static Dictionary ReadEntries(string text, Action? warning) { if (text == null) { throw new ArgumentNullException("text"); } Dictionary dictionary = new Dictionary(StringComparer.Ordinal); string text2 = ""; using (StringReader stringReader = new StringReader(text)) { int num = 0; string text3; while ((text3 = stringReader.ReadLine()) != null) { num++; string text4 = text3.Trim(); if (text4.Length == 0 || text4.StartsWith("#", StringComparison.Ordinal)) { continue; } if (text4.StartsWith("[", StringComparison.Ordinal) && text4.EndsWith("]", StringComparison.Ordinal)) { text2 = text4.Substring(1, text4.Length - 2).Trim(); continue; } int num2 = text4.IndexOf('='); if (num2 < 1 || text2.Length == 0) { throw new FormatException("Malformed railroad configuration at line " + num + "."); } string text5 = text2 + "." + text4.Substring(0, num2).Trim(); if (!Names.Contains(text5)) { warning?.Invoke("Unknown railroad setting " + text5 + "; it was ignored."); continue; } if (dictionary.ContainsKey(text5)) { throw new FormatException("Duplicate railroad setting " + text5 + "."); } dictionary.Add(text5, text4.Substring(num2 + 1).Trim()); } } if (dictionary.Count == 0) { throw new FormatException("The file contains no recognized railroad settings."); } return dictionary; } public static RailMusicClientValues ReadClient(string text, RailMusicClientValues previous, Action? warning = null) { if (previous == null) { throw new ArgumentNullException("previous"); } Values values = new Values(ReadEntries(text, null), warning); return new RailMusicClientValues(values.Number("MusicClient.Volume", previous.Volume, 0.5, 0.0, 1.0), values.Boolean("MusicClient.Muted", previous.Muted, fallback: false), values.Boolean("MusicClient.BeatLights", previous.BeatLights, fallback: false), values.Integer("MusicClient.MaxAudibleCarts", previous.MaxAudibleCarts, 1, 1, 4), values.Number("MusicClient.TechnoVolume", previous.TechnoVolume, 1.0, 0.0, 1.0), values.Number("MusicClient.PumpkinVolume", previous.PumpkinVolume, 1.0, 0.0, 1.0), values.Number("MusicClient.HalloweenTechnoVolume", previous.HalloweenTechnoVolume, 1.0, 0.0, 1.0)); } public static RailSettingsValues Read(string text, RailSettingsValues previous, Action? warning = null) { if (text == null) { throw new ArgumentNullException("text"); } if (previous == null) { throw new ArgumentNullException("previous"); } Values values = new Values(ReadEntries(text, warning), warning); RailSettingsValues defaults = RailSettingsValues.Defaults; return new RailSettingsValues(values.Boolean("Fuel.AttachedTorchesUseFuel", previous.AttachedTorchesUseFuel, defaults.AttachedTorchesUseFuel), values.Number("Fuel.CoalSecondsPerItem", previous.CoalSecondsPerItem, defaults.CoalSecondsPerItem, 1.0, 86400.0), values.Integer("Trains.HandcartMaxCarts", previous.HandcartMaxCarts, defaults.HandcartMaxCarts, 0, 20), values.Integer("Trains.LocomotiveMaxCarts", previous.LocomotiveMaxCarts, defaults.LocomotiveMaxCarts, 0, 20), values.Boolean("Construction.ClearTerrainOnPlacement", previous.ClearTerrainOnPlacement, defaults.ClearTerrainOnPlacement), values.Boolean("Construction.DirtTrackbedOnPlacement", previous.DirtTrackbedOnPlacement, defaults.DirtTrackbedOnPlacement), values.Number("Trains.HandcartStaminaPerSecond", previous.HandcartStaminaPerSecond, defaults.HandcartStaminaPerSecond, 0.0, 100.0), values.Boolean("Construction.FillTerrainOnPlacement", previous.FillTerrainOnPlacement, defaults.FillTerrainOnPlacement), values.Number("Trains.HandcartMaxSpeed", previous.HandcartMaxSpeed, defaults.HandcartMaxSpeed, 0.5, 15.0), values.Number("Trains.LocomotiveMaxSpeed", previous.LocomotiveMaxSpeed, defaults.LocomotiveMaxSpeed, 0.5, 15.0), values.Boolean("Construction.TracksTakeDamage", previous.TracksTakeDamage, defaults.TracksTakeDamage), values.Number("Trains.TandemHandcartMaxSpeed", previous.TandemHandcartMaxSpeed, defaults.TandemHandcartMaxSpeed, 0.5, 15.0), values.Number("Trains.TandemHandcartStaminaPerSecond", previous.TandemHandcartStaminaPerSecond, defaults.TandemHandcartStaminaPerSecond, 0.0, 100.0), values.Integer("Trains.TandemHandcartMaxCarts", previous.TandemHandcartMaxCarts, defaults.TandemHandcartMaxCarts, 0, 20), values.Number("Fuel.BronzeFuelSecondsPerItem", previous.BronzeFuelSecondsPerItem, defaults.BronzeFuelSecondsPerItem, 1.0, 86400.0), values.Number("Trains.BronzeEngineMaxSpeed", previous.BronzeEngineMaxSpeed, defaults.BronzeEngineMaxSpeed, 0.5, 15.0), values.Integer("Trains.BronzeEngineMaxCarts", previous.BronzeEngineMaxCarts, defaults.BronzeEngineMaxCarts, 0, 20), values.Number("Trains.HandcartLoadPenaltyMultiplier", previous.HandcartLoadPenaltyMultiplier, defaults.HandcartLoadPenaltyMultiplier, 0.0, 5.0), values.Number("Trains.HandcartHillPenaltyMultiplier", previous.HandcartHillPenaltyMultiplier, defaults.HandcartHillPenaltyMultiplier, 0.0, 5.0), values.Number("Trains.TandemHandcartLoadPenaltyMultiplier", previous.TandemHandcartLoadPenaltyMultiplier, defaults.TandemHandcartLoadPenaltyMultiplier, 0.0, 5.0), values.Number("Trains.TandemHandcartHillPenaltyMultiplier", previous.TandemHandcartHillPenaltyMultiplier, defaults.TandemHandcartHillPenaltyMultiplier, 0.0, 5.0), values.Number("Trains.BronzeEngineLoadPenaltyMultiplier", previous.BronzeEngineLoadPenaltyMultiplier, defaults.BronzeEngineLoadPenaltyMultiplier, 0.0, 5.0), values.Number("Trains.BronzeEngineHillPenaltyMultiplier", previous.BronzeEngineHillPenaltyMultiplier, defaults.BronzeEngineHillPenaltyMultiplier, 0.0, 5.0), values.Number("Trains.LocomotiveLoadPenaltyMultiplier", previous.LocomotiveLoadPenaltyMultiplier, defaults.LocomotiveLoadPenaltyMultiplier, 0.0, 5.0), values.Number("Trains.LocomotiveHillPenaltyMultiplier", previous.LocomotiveHillPenaltyMultiplier, defaults.LocomotiveHillPenaltyMultiplier, 0.0, 5.0), values.Number("Fuel.EitrFuelSecondsPerItem", previous.EitrFuelSecondsPerItem, defaults.EitrFuelSecondsPerItem, 1.0, 86400.0), values.Number("Trains.EitrEngineMaxSpeed", previous.EitrEngineMaxSpeed, defaults.EitrEngineMaxSpeed, 0.5, 15.0), values.Integer("Trains.EitrEngineMaxCarts", previous.EitrEngineMaxCarts, defaults.EitrEngineMaxCarts, 0, 20), values.Number("Trains.EitrEngineLoadPenaltyMultiplier", previous.EitrEngineLoadPenaltyMultiplier, defaults.EitrEngineLoadPenaltyMultiplier, 0.0, 5.0), values.Number("Trains.EitrEngineHillPenaltyMultiplier", previous.EitrEngineHillPenaltyMultiplier, defaults.EitrEngineHillPenaltyMultiplier, 0.0, 5.0), values.Boolean("Automation.RemoteSimulationEnabled", previous.RemoteSimulationEnabled, defaults.RemoteSimulationEnabled), values.Integer("Automation.RemoteTrainLimit", previous.RemoteTrainLimit, defaults.RemoteTrainLimit, 1, 8), values.Boolean("Music.MusicCartsEnabled", previous.MusicCartsEnabled, defaults.MusicCartsEnabled), values.Number("Music.MusicCartRange", previous.MusicCartRange, defaults.MusicCartRange, 10.0, 80.0), values.Number("Music.MusicCartMaxVolume", previous.MusicCartMaxVolume, defaults.MusicCartMaxVolume, 0.0, 1.0)); } } public sealed class RailSettingsValues : IEquatable { public const int MaximumCarts = 20; public const double MaximumCoalSeconds = 86400.0; public const double DefaultHandcartStaminaPerSecond = 5.0; public const double MaximumHandcartStaminaPerSecond = 100.0; public const double DefaultHandcartMaxSpeed = 4.5; public const double DefaultLocomotiveMaxSpeed = 7.5; public const double DefaultTandemHandcartMaxSpeed = 6.75; public const double DefaultTandemHandcartStaminaPerSecond = 2.5; public const int DefaultTandemHandcartMaxCarts = 4; public const double DefaultBronzeFuelSecondsPerItem = 60.0; public const double MaximumBronzeFuelSeconds = 86400.0; public const double DefaultBronzeEngineMaxSpeed = 6.0; public const int DefaultBronzeEngineMaxCarts = 3; public const double MaximumPenaltyMultiplier = 5.0; public const double DefaultHandcartLoadPenaltyMultiplier = 1.0; public const double DefaultHandcartHillPenaltyMultiplier = 1.0; public const double DefaultTandemHandcartLoadPenaltyMultiplier = 1.0; public const double DefaultTandemHandcartHillPenaltyMultiplier = 1.0; public const double DefaultBronzeEngineLoadPenaltyMultiplier = 0.5; public const double DefaultBronzeEngineHillPenaltyMultiplier = 0.5; public const double DefaultLocomotiveLoadPenaltyMultiplier = 0.5; public const double DefaultLocomotiveHillPenaltyMultiplier = 0.5; public const double DefaultEitrFuelSecondsPerItem = 300.0; public const double MaximumEitrFuelSeconds = 86400.0; public const double DefaultEitrEngineMaxSpeed = 10.5; public const int DefaultEitrEngineMaxCarts = 8; public const double DefaultEitrEngineLoadPenaltyMultiplier = 0.25; public const double DefaultEitrEngineHillPenaltyMultiplier = 0.25; public const bool DefaultRemoteSimulationEnabled = true; public const int DefaultRemoteTrainLimit = 4; public const int MinimumRemoteTrainLimit = 1; public const int MaximumRemoteTrainLimit = 8; public const bool DefaultMusicCartsEnabled = true; public const double DefaultMusicCartRange = 40.0; public const double MinimumMusicCartRange = 10.0; public const double MaximumMusicCartRange = 80.0; public const double DefaultMusicCartMaxVolume = 0.6; public const double MinimumTrainSpeed = 0.5; public const double MaximumTrainSpeed = 15.0; public static readonly RailSettingsValues Defaults = new RailSettingsValues(attachedTorchesUseFuel: true, 90.0, 4, 4); public bool AttachedTorchesUseFuel { get; } public double CoalSecondsPerItem { get; } public int HandcartMaxCarts { get; } public int LocomotiveMaxCarts { get; } public bool ClearTerrainOnPlacement { get; } public bool DirtTrackbedOnPlacement { get; } public double HandcartStaminaPerSecond { get; } public bool FillTerrainOnPlacement { get; } public double HandcartMaxSpeed { get; } public double LocomotiveMaxSpeed { get; } public bool TracksTakeDamage { get; } public double TandemHandcartMaxSpeed { get; } public double TandemHandcartStaminaPerSecond { get; } public int TandemHandcartMaxCarts { get; } public double BronzeFuelSecondsPerItem { get; } public double BronzeEngineMaxSpeed { get; } public int BronzeEngineMaxCarts { get; } public double HandcartLoadPenaltyMultiplier { get; } public double HandcartHillPenaltyMultiplier { get; } public double TandemHandcartLoadPenaltyMultiplier { get; } public double TandemHandcartHillPenaltyMultiplier { get; } public double BronzeEngineLoadPenaltyMultiplier { get; } public double BronzeEngineHillPenaltyMultiplier { get; } public double LocomotiveLoadPenaltyMultiplier { get; } public double LocomotiveHillPenaltyMultiplier { get; } public double EitrFuelSecondsPerItem { get; } public double EitrEngineMaxSpeed { get; } public int EitrEngineMaxCarts { get; } public double EitrEngineLoadPenaltyMultiplier { get; } public double EitrEngineHillPenaltyMultiplier { get; } public bool RemoteSimulationEnabled { get; } public int RemoteTrainLimit { get; } public bool MusicCartsEnabled { get; } public double MusicCartRange { get; } public double MusicCartMaxVolume { get; } public RailSettingsValues(bool attachedTorchesUseFuel, double coalSecondsPerItem, int handcartMaxCarts, int locomotiveMaxCarts, bool clearTerrainOnPlacement = false, bool dirtTrackbedOnPlacement = true, double handcartStaminaPerSecond = 5.0, bool fillTerrainOnPlacement = false, double handcartMaxSpeed = 4.5, double locomotiveMaxSpeed = 7.5, bool tracksTakeDamage = true, double tandemHandcartMaxSpeed = 6.75, double tandemHandcartStaminaPerSecond = 2.5, int tandemHandcartMaxCarts = 4, double bronzeFuelSecondsPerItem = 60.0, double bronzeEngineMaxSpeed = 6.0, int bronzeEngineMaxCarts = 3, double handcartLoadPenaltyMultiplier = 1.0, double handcartHillPenaltyMultiplier = 1.0, double tandemHandcartLoadPenaltyMultiplier = 1.0, double tandemHandcartHillPenaltyMultiplier = 1.0, double bronzeEngineLoadPenaltyMultiplier = 0.5, double bronzeEngineHillPenaltyMultiplier = 0.5, double locomotiveLoadPenaltyMultiplier = 0.5, double locomotiveHillPenaltyMultiplier = 0.5, double eitrFuelSecondsPerItem = 300.0, double eitrEngineMaxSpeed = 10.5, int eitrEngineMaxCarts = 8, double eitrEngineLoadPenaltyMultiplier = 0.25, double eitrEngineHillPenaltyMultiplier = 0.25, bool remoteSimulationEnabled = true, int remoteTrainLimit = 4, bool musicCartsEnabled = true, double musicCartRange = 40.0, double musicCartMaxVolume = 0.6) { Guard.Finite(coalSecondsPerItem, "coalSecondsPerItem"); if (coalSecondsPerItem < 1.0 || coalSecondsPerItem > 86400.0) { throw new ArgumentOutOfRangeException("coalSecondsPerItem"); } if (handcartMaxCarts < 0 || handcartMaxCarts > 20) { throw new ArgumentOutOfRangeException("handcartMaxCarts"); } if (locomotiveMaxCarts < 0 || locomotiveMaxCarts > 20) { throw new ArgumentOutOfRangeException("locomotiveMaxCarts"); } Guard.Finite(handcartStaminaPerSecond, "handcartStaminaPerSecond"); if (handcartStaminaPerSecond < 0.0 || handcartStaminaPerSecond > 100.0) { throw new ArgumentOutOfRangeException("handcartStaminaPerSecond"); } ValidateSpeed(handcartMaxSpeed, "handcartMaxSpeed"); ValidateSpeed(locomotiveMaxSpeed, "locomotiveMaxSpeed"); ValidateSpeed(tandemHandcartMaxSpeed, "tandemHandcartMaxSpeed"); Guard.Finite(tandemHandcartStaminaPerSecond, "tandemHandcartStaminaPerSecond"); if (tandemHandcartStaminaPerSecond < 0.0 || tandemHandcartStaminaPerSecond > 100.0) { throw new ArgumentOutOfRangeException("tandemHandcartStaminaPerSecond"); } if (tandemHandcartMaxCarts < 0 || tandemHandcartMaxCarts > 20) { throw new ArgumentOutOfRangeException("tandemHandcartMaxCarts"); } Guard.Finite(bronzeFuelSecondsPerItem, "bronzeFuelSecondsPerItem"); if (bronzeFuelSecondsPerItem < 1.0 || bronzeFuelSecondsPerItem > 86400.0) { throw new ArgumentOutOfRangeException("bronzeFuelSecondsPerItem"); } ValidateSpeed(bronzeEngineMaxSpeed, "bronzeEngineMaxSpeed"); if (bronzeEngineMaxCarts < 0 || bronzeEngineMaxCarts > 20) { throw new ArgumentOutOfRangeException("bronzeEngineMaxCarts"); } ValidatePenalty(handcartLoadPenaltyMultiplier, "handcartLoadPenaltyMultiplier"); ValidatePenalty(handcartHillPenaltyMultiplier, "handcartHillPenaltyMultiplier"); ValidatePenalty(tandemHandcartLoadPenaltyMultiplier, "tandemHandcartLoadPenaltyMultiplier"); ValidatePenalty(tandemHandcartHillPenaltyMultiplier, "tandemHandcartHillPenaltyMultiplier"); ValidatePenalty(bronzeEngineLoadPenaltyMultiplier, "bronzeEngineLoadPenaltyMultiplier"); ValidatePenalty(bronzeEngineHillPenaltyMultiplier, "bronzeEngineHillPenaltyMultiplier"); ValidatePenalty(locomotiveLoadPenaltyMultiplier, "locomotiveLoadPenaltyMultiplier"); ValidatePenalty(locomotiveHillPenaltyMultiplier, "locomotiveHillPenaltyMultiplier"); Guard.Finite(eitrFuelSecondsPerItem, "eitrFuelSecondsPerItem"); if (eitrFuelSecondsPerItem < 1.0 || eitrFuelSecondsPerItem > 86400.0) { throw new ArgumentOutOfRangeException("eitrFuelSecondsPerItem"); } ValidateSpeed(eitrEngineMaxSpeed, "eitrEngineMaxSpeed"); if (eitrEngineMaxCarts < 0 || eitrEngineMaxCarts > 20) { throw new ArgumentOutOfRangeException("eitrEngineMaxCarts"); } ValidatePenalty(eitrEngineLoadPenaltyMultiplier, "eitrEngineLoadPenaltyMultiplier"); ValidatePenalty(eitrEngineHillPenaltyMultiplier, "eitrEngineHillPenaltyMultiplier"); if (remoteTrainLimit < 1 || remoteTrainLimit > 8) { throw new ArgumentOutOfRangeException("remoteTrainLimit"); } Guard.Finite(musicCartRange, "musicCartRange"); if (musicCartRange < 10.0 || musicCartRange > 80.0) { throw new ArgumentOutOfRangeException("musicCartRange"); } Guard.Finite(musicCartMaxVolume, "musicCartMaxVolume"); if (musicCartMaxVolume < 0.0 || musicCartMaxVolume > 1.0) { throw new ArgumentOutOfRangeException("musicCartMaxVolume"); } AttachedTorchesUseFuel = attachedTorchesUseFuel; CoalSecondsPerItem = coalSecondsPerItem; HandcartMaxCarts = handcartMaxCarts; LocomotiveMaxCarts = locomotiveMaxCarts; ClearTerrainOnPlacement = clearTerrainOnPlacement; DirtTrackbedOnPlacement = dirtTrackbedOnPlacement; HandcartStaminaPerSecond = handcartStaminaPerSecond; FillTerrainOnPlacement = fillTerrainOnPlacement; HandcartMaxSpeed = handcartMaxSpeed; LocomotiveMaxSpeed = locomotiveMaxSpeed; TracksTakeDamage = tracksTakeDamage; TandemHandcartMaxSpeed = tandemHandcartMaxSpeed; TandemHandcartStaminaPerSecond = tandemHandcartStaminaPerSecond; TandemHandcartMaxCarts = tandemHandcartMaxCarts; BronzeFuelSecondsPerItem = bronzeFuelSecondsPerItem; BronzeEngineMaxSpeed = bronzeEngineMaxSpeed; BronzeEngineMaxCarts = bronzeEngineMaxCarts; HandcartLoadPenaltyMultiplier = handcartLoadPenaltyMultiplier; HandcartHillPenaltyMultiplier = handcartHillPenaltyMultiplier; TandemHandcartLoadPenaltyMultiplier = tandemHandcartLoadPenaltyMultiplier; TandemHandcartHillPenaltyMultiplier = tandemHandcartHillPenaltyMultiplier; BronzeEngineLoadPenaltyMultiplier = bronzeEngineLoadPenaltyMultiplier; BronzeEngineHillPenaltyMultiplier = bronzeEngineHillPenaltyMultiplier; LocomotiveLoadPenaltyMultiplier = locomotiveLoadPenaltyMultiplier; LocomotiveHillPenaltyMultiplier = locomotiveHillPenaltyMultiplier; EitrFuelSecondsPerItem = eitrFuelSecondsPerItem; EitrEngineMaxSpeed = eitrEngineMaxSpeed; EitrEngineMaxCarts = eitrEngineMaxCarts; EitrEngineLoadPenaltyMultiplier = eitrEngineLoadPenaltyMultiplier; EitrEngineHillPenaltyMultiplier = eitrEngineHillPenaltyMultiplier; RemoteSimulationEnabled = remoteSimulationEnabled; RemoteTrainLimit = remoteTrainLimit; MusicCartsEnabled = musicCartsEnabled; MusicCartRange = musicCartRange; MusicCartMaxVolume = musicCartMaxVolume; } public bool Equals(RailSettingsValues? other) { if (other != null && AttachedTorchesUseFuel == other.AttachedTorchesUseFuel && CoalSecondsPerItem == other.CoalSecondsPerItem && HandcartMaxCarts == other.HandcartMaxCarts && LocomotiveMaxCarts == other.LocomotiveMaxCarts && ClearTerrainOnPlacement == other.ClearTerrainOnPlacement && DirtTrackbedOnPlacement == other.DirtTrackbedOnPlacement && HandcartStaminaPerSecond == other.HandcartStaminaPerSecond && FillTerrainOnPlacement == other.FillTerrainOnPlacement && HandcartMaxSpeed == other.HandcartMaxSpeed && LocomotiveMaxSpeed == other.LocomotiveMaxSpeed && TracksTakeDamage == other.TracksTakeDamage && TandemHandcartMaxSpeed == other.TandemHandcartMaxSpeed && TandemHandcartStaminaPerSecond == other.TandemHandcartStaminaPerSecond && TandemHandcartMaxCarts == other.TandemHandcartMaxCarts && BronzeFuelSecondsPerItem == other.BronzeFuelSecondsPerItem && BronzeEngineMaxSpeed == other.BronzeEngineMaxSpeed && BronzeEngineMaxCarts == other.BronzeEngineMaxCarts && HandcartLoadPenaltyMultiplier == other.HandcartLoadPenaltyMultiplier && HandcartHillPenaltyMultiplier == other.HandcartHillPenaltyMultiplier && TandemHandcartLoadPenaltyMultiplier == other.TandemHandcartLoadPenaltyMultiplier && TandemHandcartHillPenaltyMultiplier == other.TandemHandcartHillPenaltyMultiplier && BronzeEngineLoadPenaltyMultiplier == other.BronzeEngineLoadPenaltyMultiplier && BronzeEngineHillPenaltyMultiplier == other.BronzeEngineHillPenaltyMultiplier && LocomotiveLoadPenaltyMultiplier == other.LocomotiveLoadPenaltyMultiplier && LocomotiveHillPenaltyMultiplier == other.LocomotiveHillPenaltyMultiplier && EitrFuelSecondsPerItem == other.EitrFuelSecondsPerItem && EitrEngineMaxSpeed == other.EitrEngineMaxSpeed && EitrEngineMaxCarts == other.EitrEngineMaxCarts && EitrEngineLoadPenaltyMultiplier == other.EitrEngineLoadPenaltyMultiplier && EitrEngineHillPenaltyMultiplier == other.EitrEngineHillPenaltyMultiplier && RemoteSimulationEnabled == other.RemoteSimulationEnabled && RemoteTrainLimit == other.RemoteTrainLimit && MusicCartsEnabled == other.MusicCartsEnabled && MusicCartRange == other.MusicCartRange) { return MusicCartMaxVolume == other.MusicCartMaxVolume; } return false; } public override bool Equals(object? obj) { if (obj is RailSettingsValues other) { return Equals(other); } return false; } public override int GetHashCode() { return (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((AttachedTorchesUseFuel.GetHashCode() * 397) ^ CoalSecondsPerItem.GetHashCode()) * 397) ^ HandcartMaxCarts) * 397) ^ LocomotiveMaxCarts) * 397) ^ ClearTerrainOnPlacement.GetHashCode()) * 397) ^ DirtTrackbedOnPlacement.GetHashCode()) * 397) ^ HandcartStaminaPerSecond.GetHashCode()) * 397) ^ FillTerrainOnPlacement.GetHashCode()) * 397) ^ HandcartMaxSpeed.GetHashCode()) * 397) ^ LocomotiveMaxSpeed.GetHashCode()) * 397) ^ TracksTakeDamage.GetHashCode()) * 397) ^ TandemHandcartMaxSpeed.GetHashCode()) * 397) ^ TandemHandcartStaminaPerSecond.GetHashCode()) * 397) ^ TandemHandcartMaxCarts) * 397) ^ BronzeFuelSecondsPerItem.GetHashCode()) * 397) ^ BronzeEngineMaxSpeed.GetHashCode()) * 397) ^ BronzeEngineMaxCarts) * 397) ^ HandcartLoadPenaltyMultiplier.GetHashCode()) * 397) ^ HandcartHillPenaltyMultiplier.GetHashCode()) * 397) ^ TandemHandcartLoadPenaltyMultiplier.GetHashCode()) * 397) ^ TandemHandcartHillPenaltyMultiplier.GetHashCode()) * 397) ^ BronzeEngineLoadPenaltyMultiplier.GetHashCode()) * 397) ^ BronzeEngineHillPenaltyMultiplier.GetHashCode()) * 397) ^ LocomotiveLoadPenaltyMultiplier.GetHashCode()) * 397) ^ LocomotiveHillPenaltyMultiplier.GetHashCode()) * 397) ^ EitrFuelSecondsPerItem.GetHashCode()) * 397) ^ EitrEngineMaxSpeed.GetHashCode()) * 397) ^ EitrEngineMaxCarts) * 397) ^ EitrEngineLoadPenaltyMultiplier.GetHashCode()) * 397) ^ EitrEngineHillPenaltyMultiplier.GetHashCode()) * 397) ^ RemoteSimulationEnabled.GetHashCode()) * 397) ^ RemoteTrainLimit) * 397) ^ MusicCartsEnabled.GetHashCode()) * 397) ^ MusicCartRange.GetHashCode()) * 397) ^ MusicCartMaxVolume.GetHashCode(); } private static void ValidatePenalty(double multiplier, string name) { Guard.Finite(multiplier, name); if (multiplier < 0.0 || multiplier > 5.0) { throw new ArgumentOutOfRangeException(name); } } private static void ValidateSpeed(double speed, string name) { Guard.Finite(speed, name); if (speed < 0.5 || speed > 15.0) { throw new ArgumentOutOfRangeException(name); } } } public readonly struct RailSignLayout { public const double BoardClearance = 1.0; public const double PostOverlap = 0.22; public const double PostWidth = 0.16; public const double PostDepth = 0.18; public const double FootWidth = 0.28; public const double FootHeight = 0.1; public const double PostHeight = 1.22; public double Lift { get; } public double BoardTop { get; } public double PostHalfSeparation { get; } public RailSignLayout(double nativeBottom, double nativeTop, double boardWidth) { Guard.Finite(nativeBottom, "nativeBottom"); Guard.Finite(nativeTop, "nativeTop"); Guard.Finite(boardWidth, "boardWidth"); if (nativeTop <= nativeBottom) { throw new ArgumentOutOfRangeException("nativeTop"); } if (boardWidth < 0.56) { throw new ArgumentOutOfRangeException("boardWidth"); } Lift = 1.0 - nativeBottom; BoardTop = 1.0 + nativeTop - nativeBottom; Guard.Finite(Lift, "nativeBottom"); Guard.Finite(BoardTop, "nativeTop"); PostHalfSeparation = Math.Max(0.14, Math.Min(boardWidth * 0.34, (boardWidth - 0.16) * 0.5)); } } public sealed class RailSpawnFootprint { public const double SideMargin = 2.0; public const double EndExtension = 2.0; public const double AboveAllowance = 0.6; public const double NearBedBelowAllowance = 0.5; private readonly RailTerrainCut _surface; private readonly RailVector[][] _quads; public double MinX => _surface.MinX; public double MaxX => _surface.MaxX; public double MinZ => _surface.MinZ; public double MaxZ => _surface.MaxZ; public RailSpawnFootprint(IEnumerable sleeperQuads) { if (sleeperQuads == null) { throw new ArgumentNullException("sleeperQuads"); } List list = new List(); foreach (RailVector[] sleeperQuad in sleeperQuads) { if (sleeperQuad == null || sleeperQuad.Length != 4) { throw new ArgumentException("A sleeper requires four perimeter corners.", "sleeperQuads"); } if (list.Count >= 256) { throw new ArgumentException("Too many track-bed quads.", "sleeperQuads"); } RailVector railVector = (sleeperQuad[1] - sleeperQuad[0]).Normalized() * 2.0; RailVector railVector2 = (sleeperQuad[3] - sleeperQuad[0]).Normalized() * 2.0; list.Add(new RailVector[4] { sleeperQuad[0] - railVector - railVector2, sleeperQuad[1] + railVector - railVector2, sleeperQuad[2] + railVector + railVector2, sleeperQuad[3] - railVector + railVector2 }); } _surface = new RailTerrainCut(list); _quads = list.ToArray(); } public bool Blocks(RailVector point) { return _surface.HasSurfaceAtOrAbove(point.X, point.Z, point.Y - 0.6); } public bool BlocksBounds(RailVector minimum, RailVector maximum, bool onlyNearBed = false) { ValidateBounds(minimum, maximum); if (maximum.X < MinX || minimum.X > MaxX || maximum.Z < MinZ || minimum.Z > MaxZ) { return false; } RailVector[][] quads = _quads; foreach (RailVector[] array in quads) { double num = array[0].X; double num2 = num; double num3 = array[0].Z; double num4 = num3; RailVector[] array2 = array; for (int j = 0; j < array2.Length; j++) { RailVector railVector = array2[j]; num = Math.Min(num, railVector.X); num2 = Math.Max(num2, railVector.X); num3 = Math.Min(num3, railVector.Z); num4 = Math.Max(num4, railVector.Z); } if (maximum.X < num || minimum.X > num2 || maximum.Z < num3 || minimum.Z > num4) { continue; } List polygon = new List(array); polygon = Clip(polygon, minimum.X, xAxis: true, keepAbove: true); polygon = Clip(polygon, maximum.X, xAxis: true, keepAbove: false); polygon = Clip(polygon, minimum.Z, xAxis: false, keepAbove: true); polygon = Clip(polygon, maximum.Z, xAxis: false, keepAbove: false); if (polygon.Count == 0) { continue; } double num5 = double.PositiveInfinity; double num6 = double.NegativeInfinity; foreach (RailVector item in polygon) { num5 = Math.Min(num5, item.Y); num6 = Math.Max(num6, item.Y); } if (minimum.Y <= num6 + 0.6 + 1E-09 && (!onlyNearBed || maximum.Y >= num5 - 0.5 - 1E-09)) { return true; } } return false; } internal static void ValidateBounds(RailVector minimum, RailVector maximum) { Guard.Finite(minimum.X, "minimum"); Guard.Finite(minimum.Y, "minimum"); Guard.Finite(minimum.Z, "minimum"); Guard.Finite(maximum.X, "maximum"); Guard.Finite(maximum.Y, "maximum"); Guard.Finite(maximum.Z, "maximum"); if (minimum.X > maximum.X || minimum.Y > maximum.Y || minimum.Z > maximum.Z) { throw new ArgumentException("Resource bounds must be ordered.", "maximum"); } } private static List Clip(List polygon, double edge, bool xAxis, bool keepAbove) { List list = new List(); if (polygon.Count == 0) { return list; } RailVector railVector = polygon[polygon.Count - 1]; double num = (xAxis ? railVector.X : railVector.Z) - edge; bool flag = (keepAbove ? (num >= -1E-09) : (num <= 1E-09)); foreach (RailVector item in polygon) { double num2 = (xAxis ? item.X : item.Z) - edge; bool num3 = (keepAbove ? (num2 >= -1E-09) : (num2 <= 1E-09)); if (num3 != flag) { list.Add(railVector + (item - railVector) * (num / (num - num2))); } if (num3) { list.Add(item); } railVector = item; num = num2; flag = num3; } return list; } } public sealed class RailSpawnIndex { private sealed class Entry { internal readonly RailSpawnFootprint Footprint; internal readonly int MinX; internal readonly int MaxX; internal readonly int MinZ; internal readonly int MaxZ; internal Entry(RailSpawnFootprint footprint, int minX, int maxX, int minZ, int maxZ) { Footprint = footprint; MinX = minX; MaxX = maxX; MinZ = minZ; MaxZ = maxZ; } } public const double CellSize = 16.0; private const int MaximumCellsPerFootprint = 4096; private readonly Dictionary _entries = new Dictionary(); private readonly Dictionary<(int X, int Z), HashSet> _cells = new Dictionary<(int, int), HashSet>(); public int Count => _entries.Count; public void Upsert(string key, RailSpawnFootprint footprint) { if (string.IsNullOrEmpty(key)) { throw new ArgumentException("A footprint key is required.", "key"); } if (footprint == null) { throw new ArgumentNullException("footprint"); } int num = Cell(footprint.MinX); int num2 = Cell(footprint.MaxX); int num3 = Cell(footprint.MinZ); int num4 = Cell(footprint.MaxZ); long num5 = (long)num2 - (long)num + 1; long num6 = (long)num4 - (long)num3 + 1; if (num5 > 4096 || num6 > 4096 || num5 * num6 > 4096) { throw new ArgumentOutOfRangeException("footprint", "Track footprint is too large."); } Remove(key); Entry entry = new Entry(footprint, num, num2, num3, num4); _entries.Add(key, entry); Visit(entry, delegate((int X, int Z) cell) { if (!_cells.TryGetValue(cell, out HashSet value)) { _cells.Add(cell, value = new HashSet()); } value.Add(key); }); } public bool Remove(string key) { if (!_entries.TryGetValue(key, out Entry value)) { return false; } Visit(value, delegate((int X, int Z) cell) { HashSet hashSet = _cells[cell]; hashSet.Remove(key); if (hashSet.Count == 0) { _cells.Remove(cell); } }); _entries.Remove(key); return true; } public void Clear() { _entries.Clear(); _cells.Clear(); } public bool Blocks(RailVector point) { if (!_cells.TryGetValue((Cell(point.X), Cell(point.Z)), out HashSet value)) { return false; } foreach (string item in value) { RailSpawnFootprint footprint = _entries[item].Footprint; if (point.X >= footprint.MinX && point.X <= footprint.MaxX && point.Z >= footprint.MinZ && point.Z <= footprint.MaxZ && footprint.Blocks(point)) { return true; } } return false; } public bool BlocksBounds(RailVector minimum, RailVector maximum, bool onlyNearBed = false) { RailSpawnFootprint.ValidateBounds(minimum, maximum); int num = Cell(minimum.X); int num2 = Cell(maximum.X); int num3 = Cell(minimum.Z); int num4 = Cell(maximum.Z); long num5 = (long)num2 - (long)num + 1; long num6 = (long)num4 - (long)num3 + 1; if (num5 > 4096 || num6 > 4096 || num5 * num6 > 4096) { throw new ArgumentOutOfRangeException("maximum", "Resource bounds are too large."); } HashSet hashSet = new HashSet(); for (int i = num; i <= num2; i++) { for (int j = num3; j <= num4; j++) { if (!_cells.TryGetValue((i, j), out HashSet value)) { continue; } foreach (string item in value) { if (hashSet.Add(item) && _entries[item].Footprint.BlocksBounds(minimum, maximum, onlyNearBed)) { return true; } } } } return false; } private static int Cell(double value) { Guard.Finite(value, "value"); double num = Math.Floor(value / 16.0); if (num <= -2147483648.0 || num >= 2147483647.0) { throw new ArgumentOutOfRangeException("value"); } return (int)num; } private static void Visit(Entry entry, Action<(int X, int Z)> action) { for (int i = entry.MinX; i <= entry.MaxX; i++) { for (int j = entry.MinZ; j <= entry.MaxZ; j++) { action((i, j)); } } } } public static class RailSpeedDefaultsUpgrade { public const int Revision = 1; public static RailSettingsValues Apply(RailSettingsValues current, int revision) { if (current == null) { throw new ArgumentNullException("current"); } if (revision >= 1) { return current; } ulong num = 0uL; if (current.HandcartMaxSpeed == 3.0) { num |= 0x100; } if (current.LocomotiveMaxSpeed == 5.0) { num |= 0x200; } if (current.TandemHandcartMaxSpeed == 4.5) { num |= 0x800; } if (current.BronzeEngineMaxSpeed == 4.0) { num |= 0x8000; } if (current.EitrEngineMaxSpeed == 7.0) { num |= 0x4000000; } if (num != 0L) { return new RailSettingsProposal(1, num, RailSettingsValues.Defaults).ApplyTo(current); } return current; } } public readonly struct RailStationSignFrame { public const double JointClearance = 0.001; public const double UprightWidth = 0.12; public const double UprightDepth = 0.14; public const double HeaderHeight = 0.14; public const double HeaderDepth = 0.14; public const double CapWidth = 0.18; public const double CapHeight = 0.06; public const double CapDepth = 0.18; public const double StripeHeight = 0.035; public const double StripeDepth = 0.012; public const double StripeCenterZ = 0.077; public double PostHalfSeparation { get; } public double UprightCenterY { get; } public double UprightHeight { get; } public double HeaderCenterY { get; } public double HeaderWidth { get; } public double CapCenterY { get; } public double StripeWidth { get; } public RailStationSignFrame(double nativeBottom, double nativeTop, double nativeHalfWidth) { Guard.Finite(nativeBottom, "nativeBottom"); Guard.Finite(nativeTop, "nativeTop"); Guard.Finite(nativeHalfWidth, "nativeHalfWidth"); if (nativeTop <= nativeBottom) { throw new ArgumentOutOfRangeException("nativeTop"); } if (nativeHalfWidth <= 0.0) { throw new ArgumentOutOfRangeException("nativeHalfWidth"); } PostHalfSeparation = nativeHalfWidth + 0.13; HeaderCenterY = nativeTop + 0.12; HeaderWidth = PostHalfSeparation * 2.0 + 0.12; StripeWidth = PostHalfSeparation * 2.0 - 0.12; double num = nativeBottom - 0.06; double num2 = HeaderCenterY - 0.07 - 0.001; UprightHeight = num2 - num; UprightCenterY = num + UprightHeight * 0.5; CapCenterY = HeaderCenterY + 0.07 + 0.001 + 0.03; Guard.Finite(HeaderWidth, "nativeHalfWidth"); Guard.Finite(UprightHeight, "nativeTop"); Guard.Finite(UprightCenterY, "nativeBottom"); Guard.Finite(CapCenterY, "nativeTop"); } } public static class RailSteamMotion { public const double WheelRadius = 0.28; public const double CrankRadius = 0.12; private const double Turn = Math.PI * 2.0; public static bool TryRoll(RailVector displacement, RailVector previousForward, RailVector forward, double seconds, out double radians) { radians = 0.0; if (double.IsNaN(seconds) || double.IsInfinity(seconds) || seconds <= 0.0 || seconds > 0.25) { return false; } double magnitude = displacement.Magnitude; if (double.IsInfinity(magnitude) || magnitude > 0.35 + 15.0 * seconds * 1.25) { return false; } double magnitude2 = previousForward.Magnitude; double magnitude3 = forward.Magnitude; if (magnitude2 < 0.5 || magnitude3 < 0.5 || double.IsInfinity(magnitude2) || double.IsInfinity(magnitude3)) { return false; } RailVector railVector = previousForward / magnitude2; RailVector railVector2 = forward / magnitude3; if (RailVector.Dot(railVector, railVector2) < Math.Cos(Math.PI / 4.0)) { return false; } RailVector railVector3 = (railVector + railVector2).Normalized(); double num = RailVector.Dot(displacement, railVector3); if ((displacement - railVector3 * num).Magnitude > 0.1 + magnitude * 0.1) { return false; } if (Math.Abs(num) < 1E-05) { return true; } radians = num / 0.28; return true; } public static double Advance(double phase, double radians) { Guard.Finite(phase, "phase"); Guard.Finite(radians, "radians"); double num = (phase % (Math.PI * 2.0) + radians % (Math.PI * 2.0)) % (Math.PI * 2.0); if (!(num < 0.0)) { return num; } return num + Math.PI * 2.0; } public static RailVector Crank(double phase) { Guard.Finite(phase, "phase"); return new RailVector(0.0, 0.12 * Math.Cos(phase), 0.12 * Math.Sin(phase)); } } public sealed class RailSteepTrackDefinition { public string PrefabName { get; } public bool LightDuty { get; } public bool Long { get; } public double HorizontalLength { get; } public double Rise { get; } public int WoodCost { get; } public int NailsCost { get; } internal RailSteepTrackDefinition(bool lightDuty, bool longSection) { LightDuty = lightDuty; Long = longSection; PrefabName = "vr_track_" + (lightDuty ? "wood_" : "") + "slope_steep" + (longSection ? "_long" : ""); HorizontalLength = (longSection ? 12 : 4); Rise = HorizontalLength * 0.5; WoodCost = (lightDuty ? 6 : 8) * ((!longSection) ? 1 : 3); NailsCost = (lightDuty ? 1 : 2) * ((!longSection) ? 1 : 3); } public RailVector[] Points() { return new RailVector[2] { new RailVector(0.0, (0.0 - Rise) / 2.0, (0.0 - HorizontalLength) / 2.0), new RailVector(0.0, Rise / 2.0, HorizontalLength / 2.0) }; } } public static class RailSteepTracks { public const double Grade = 0.5; public static IReadOnlyList All { get; } = Array.AsReadOnly(new RailSteepTrackDefinition[4] { new RailSteepTrackDefinition(lightDuty: false, longSection: false), new RailSteepTrackDefinition(lightDuty: false, longSection: true), new RailSteepTrackDefinition(lightDuty: true, longSection: false), new RailSteepTrackDefinition(lightDuty: true, longSection: true) }); public static bool TryGet(string? prefabName, out RailSteepTrackDefinition definition) { foreach (RailSteepTrackDefinition item in All) { if (string.Equals(item.PrefabName, prefabName, StringComparison.Ordinal)) { definition = item; return true; } } definition = null; return false; } } public static class RailSupportLayout { public const double HalfGauge = 0.7; public const double RailHeight = 0.115; public const double SocketSpacing = 2.0; public static RailVector Center(IReadOnlyList points, int side) { RailPath railPath = new RailPath(points); RailPose railPose = Sample(railPath, railPath.Length * 0.5); return railPose.Position + Right(railPose.Tangent, side) * 0.7 + new RailVector(0.0, 0.115, 0.0); } public static RailVector[] Sockets(IReadOnlyList points, int side) { RailPath railPath = new RailPath(points); double num = Math.Max(1.0, Math.Ceiling(railPath.Length / 2.0)); if (num > 64.0) { throw new ArgumentOutOfRangeException("points", "Track exceeds the support socket limit."); } int num2 = (int)num; RailVector[] array = new RailVector[num2 + 1]; for (int i = 0; i <= num2; i++) { RailPose railPose = Sample(railPath, railPath.Length * (double)i / (double)num2); RailVector railVector = Right(railPose.Tangent, side); double num3 = Math.Sqrt(railPose.Tangent.X * railPose.Tangent.X + railPose.Tangent.Z * railPose.Tangent.Z); RailVector railVector2 = new RailVector((0.0 - railPose.Tangent.X) * railPose.Tangent.Y / num3, num3, (0.0 - railPose.Tangent.Z) * railPose.Tangent.Y / num3); array[i] = railPose.Position + railVector * 0.7 + new RailVector(0.0, 0.02, 0.0) - railVector2 * 0.06; } return array; } private static RailPose Sample(RailPath path, double distance) { double num = Math.Min(0.01, path.Length * 0.25); RailPose railPose = path.Sample(Math.Max(0.0, distance - num)); RailPose railPose2 = path.Sample(Math.Min(path.Length, distance + num)); return new RailPose(path.Sample(distance).Position, (railPose2.Position - railPose.Position).Normalized()); } private static RailVector Right(RailVector tangent, int side) { if (side != -1 && side != 1) { throw new ArgumentOutOfRangeException("side"); } return new RailVector(tangent.Z, 0.0, 0.0 - tangent.X).Normalized() * side; } } public static class RailSwitchClearance { public const double LateralClearance = 1.2; public static bool Contains(IReadOnlyList paths, RailVector position, double approachClearance) { if (paths == null) { throw new ArgumentNullException("paths"); } Guard.Finite(approachClearance, "approachClearance"); if (approachClearance < 0.0) { throw new ArgumentOutOfRangeException("approachClearance"); } foreach (RailPath path in paths) { RailPath obj = path ?? throw new ArgumentException("A switch path cannot be null.", "paths"); RailProjection railProjection = obj.Project(position); RailPose railPose = obj.Sample(railProjection.Distance); RailVector railVector = position - railProjection.Position; double num = RailVector.Dot(railVector, railPose.Tangent); if ((railVector - railPose.Tangent * num).Magnitude <= 1.2 && Math.Abs(num) <= approachClearance) { return true; } } return false; } } public static class RailTandemPolicy { public const double ConfirmationLifetimeSeconds = 0.75; public static bool HasTwoOperators(long driver, long helper, bool driverAttached, bool helperAttached, double now, double confirmationRequestedAt) { if (driver != 0L && helper != 0L && driver != helper && driverAttached && helperAttached && Finite(now) && Finite(confirmationRequestedAt) && confirmationRequestedAt >= 0.0 && now >= confirmationRequestedAt) { return now - confirmationRequestedAt < 0.75; } return false; } public static double LimitSoloSpeed(double speed, bool hasTwoOperators, double soloMaximum) { Guard.Finite(speed, "speed"); Guard.Finite(soloMaximum, "soloMaximum"); if (soloMaximum <= 0.0) { throw new ArgumentOutOfRangeException("soloMaximum"); } if (!hasTwoOperators) { return Math.Max(0.0 - soloMaximum, Math.Min(soloMaximum, speed)); } return speed; } private static bool Finite(double value) { if (!double.IsNaN(value)) { return !double.IsInfinity(value); } return false; } } public sealed class RailTerrainBed { public const double Shoulder = 0.5; public const double EndExtension = 0.23; public const double GravelShoulder = 2.0; public const double GravelEndExtension = 0.35; public const double MaximumGroundGap = 0.3; public const double MaximumFill = 0.3; private readonly RailTerrainCut _surface; public double MinX => _surface.MinX; public double MaxX => _surface.MaxX; public double MinZ => _surface.MinZ; public double MaxZ => _surface.MaxZ; public RailTerrainBed(IEnumerable sleepers, double shoulder = 0.5, double endExtension = 0.23) { if (sleepers == null) { throw new ArgumentNullException("sleepers"); } Guard.Finite(shoulder, "shoulder"); Guard.Finite(endExtension, "endExtension"); if (shoulder < 0.0 || endExtension < 0.0) { throw new ArgumentOutOfRangeException("shoulder"); } List list = new List(); foreach (RailVector[] sleeper in sleepers) { if (sleeper == null || sleeper.Length != 4) { throw new ArgumentException("A sleeper requires four perimeter corners.", "sleepers"); } RailVector railVector = (sleeper[1] - sleeper[0]).Normalized() * shoulder; RailVector railVector2 = (sleeper[3] - sleeper[0]).Normalized() * endExtension; list.Add(new RailVector[4] { sleeper[0] - railVector - railVector2, sleeper[1] + railVector - railVector2, sleeper[2] + railVector + railVector2, sleeper[3] - railVector + railVector2 }); } _surface = new RailTerrainCut(list); } public double? SurfaceHeight(double x, double z) { return _surface.SurfaceHeight(x, z); } public static bool IsGravelGroundLevel(double bedHeight, double groundHeight) { Guard.Finite(bedHeight, "bedHeight"); Guard.Finite(groundHeight, "groundHeight"); return Math.Abs(bedHeight - groundHeight) <= 0.500000001; } public static double? FillHeight(double bedHeight, double groundHeight, bool interveningPiece) { Guard.Finite(bedHeight, "bedHeight"); Guard.Finite(groundHeight, "groundHeight"); double num = bedHeight - groundHeight; if (interveningPiece || !(num > 0.002000001) || !(num <= 0.300000001)) { return null; } return bedHeight; } public static bool IsGroundLevel(double bedHeight, double finalGroundHeight, bool interveningPiece) { Guard.Finite(bedHeight, "bedHeight"); Guard.Finite(finalGroundHeight, "finalGroundHeight"); double num = bedHeight - finalGroundHeight; if (!interveningPiece && num >= -0.002) { return num <= 0.300000001; } return false; } public static double InterpolateGround(double h00, double h10, double h01, double h11, double x, double z) { Guard.Finite(h00, "h00"); Guard.Finite(h10, "h10"); Guard.Finite(h01, "h01"); Guard.Finite(h11, "h11"); Guard.Finite(x, "x"); Guard.Finite(z, "z"); if (x < 0.0 || x > 1.0 || z < 0.0 || z > 1.0) { throw new ArgumentOutOfRangeException("x"); } if (!(x + z <= 1.0)) { return h11 + (h01 - h11) * (1.0 - x) + (h10 - h11) * (1.0 - z); } return h00 + (h10 - h00) * x + (h01 - h00) * z; } } public sealed class RailTerrainCut { private readonly struct Axis { internal readonly double X; internal readonly double Z; internal readonly double Minimum; internal readonly double Maximum; internal Axis(double x, double z, double minimum, double maximum) { X = x; Z = z; Minimum = minimum; Maximum = maximum; } } private sealed class Quad { internal readonly double MinX; internal readonly double MaxX; internal readonly double MinZ; internal readonly double MaxZ; private readonly RailVector _origin; private readonly double _slopeX; private readonly double _slopeZ; private readonly double _verticalOffset; private readonly Axis[] _axes; internal Quad(RailVector[] vertices) { if (vertices == null || vertices.Length != 4) { throw new ArgumentException("A track-bed quad requires four perimeter vertices.", "vertices"); } RailVector[] array = (RailVector[])vertices.Clone(); _origin = array[0]; RailVector railVector = array[1] - _origin; RailVector railVector2 = array[2] - _origin; double num = railVector.X * railVector2.Z - railVector2.X * railVector.Z; Guard.Finite(num, "vertices"); if (Math.Abs(num) <= 1E-09) { throw new ArgumentException("Track-bed quads must have nonzero horizontal area.", "vertices"); } _slopeX = (railVector.Y * railVector2.Z - railVector2.Y * railVector.Z) / num; _slopeZ = (railVector.X * railVector2.Y - railVector2.X * railVector.Y) / num; Guard.Finite(_slopeX, "vertices"); Guard.Finite(_slopeZ, "vertices"); double num2 = Height(array[3].X, array[3].Z); if (Math.Abs(num2 - array[3].Y) > 0.005) { throw new ArgumentException("Track-bed quad vertices must be coplanar.", "vertices"); } _verticalOffset = Math.Min(0.0, array[3].Y - num2); double num3 = array[0].X; double num4 = array[0].X; double num5 = array[0].Z; double num6 = array[0].Z; _axes = new Axis[4]; int num7 = 0; for (int i = 0; i < array.Length; i++) { RailVector railVector3 = array[(i + 1) % 4] - array[i]; RailVector railVector4 = array[(i + 2) % 4] - array[(i + 1) % 4]; double value = railVector3.X * railVector4.Z - railVector3.Z * railVector4.X; Guard.Finite(value, "vertices"); if (Math.Abs(value) <= 1E-09 || (num7 != 0 && Math.Sign(value) != num7)) { throw new ArgumentException("Track-bed quads must be strictly convex and in perimeter order.", "vertices"); } num7 = Math.Sign(value); double num8 = Math.Sqrt(railVector3.X * railVector3.X + railVector3.Z * railVector3.Z); Guard.Finite(num8, "vertices"); double num9 = (0.0 - railVector3.Z) / num8; double num10 = railVector3.X / num8; double num11 = double.PositiveInfinity; double num12 = double.NegativeInfinity; RailVector[] array2 = array; for (int j = 0; j < array2.Length; j++) { RailVector railVector5 = array2[j]; double num13 = (railVector5.X - _origin.X) * num9 + (railVector5.Z - _origin.Z) * num10; Guard.Finite(num13, "vertices"); num11 = Math.Min(num11, num13); num12 = Math.Max(num12, num13); } _axes[i] = new Axis(num9, num10, num11, num12); num3 = Math.Min(num3, array[i].X); num4 = Math.Max(num4, array[i].X); num5 = Math.Min(num5, array[i].Z); num6 = Math.Max(num6, array[i].Z); } MinX = num3; MaxX = num4; MinZ = num5; MaxZ = num6; } internal double Height(double x, double z) { double num = _origin.Y + _verticalOffset + _slopeX * (x - _origin.X) + _slopeZ * (z - _origin.Z); Guard.Finite(num, "height"); return num; } internal bool Intersects(double x, double z, double halfSize) { if (MaxX <= x - halfSize + 1E-09 || MinX >= x + halfSize - 1E-09 || MaxZ <= z - halfSize + 1E-09 || MinZ >= z + halfSize - 1E-09) { return false; } Axis[] axes = _axes; for (int i = 0; i < axes.Length; i++) { Axis axis = axes[i]; double num = (x - _origin.X) * axis.X + (z - _origin.Z) * axis.Z; double num2 = halfSize * (Math.Abs(axis.X) + Math.Abs(axis.Z)); if (axis.Maximum <= num - num2 + 1E-09 || axis.Minimum >= num + num2 - 1E-09) { return false; } } return true; } internal bool Contains(double x, double z) { if (x < MinX - 1E-09 || x > MaxX + 1E-09 || z < MinZ - 1E-09 || z > MaxZ + 1E-09) { return false; } Axis[] axes = _axes; for (int i = 0; i < axes.Length; i++) { Axis axis = axes[i]; double num = (x - _origin.X) * axis.X + (z - _origin.Z) * axis.Z; if (num < axis.Minimum - 1E-09 || num > axis.Maximum + 1E-09) { return false; } } return true; } } public const int MaximumQuads = 256; private const double EdgeTolerance = 1E-09; private const double PlanarityTolerance = 0.005; private readonly Quad[] _quads; public int QuadCount => _quads.Length; public double MinX { get; } public double MaxX { get; } public double MinZ { get; } public double MaxZ { get; } public RailTerrainCut(IEnumerable quads) { if (quads == null) { throw new ArgumentNullException("quads"); } List list = new List(); double val = double.PositiveInfinity; double val2 = double.NegativeInfinity; double val3 = double.PositiveInfinity; double val4 = double.NegativeInfinity; foreach (RailVector[] quad2 in quads) { if (list.Count >= 256) { throw new ArgumentException("Too many track-bed quads.", "quads"); } Quad quad = new Quad(quad2); list.Add(quad); val = Math.Min(val, quad.MinX); val2 = Math.Max(val2, quad.MaxX); val3 = Math.Min(val3, quad.MinZ); val4 = Math.Max(val4, quad.MaxZ); } if (list.Count == 0) { throw new ArgumentException("At least one track-bed quad is required.", "quads"); } _quads = list.ToArray(); MinX = val; MaxX = val2; MinZ = val3; MaxZ = val4; } public double? TargetHeight(double worldX, double worldZ, double cellSize) { Guard.Finite(worldX, "worldX"); Guard.Finite(worldZ, "worldZ"); Guard.Finite(cellSize, "cellSize"); if (cellSize <= 0.0) { throw new ArgumentOutOfRangeException("cellSize"); } Guard.Finite(worldX - cellSize, "worldX"); Guard.Finite(worldX + cellSize, "worldX"); Guard.Finite(worldZ - cellSize, "worldZ"); Guard.Finite(worldZ + cellSize, "worldZ"); double? result = null; Quad[] quads = _quads; foreach (Quad quad in quads) { if (quad.Intersects(worldX, worldZ, cellSize)) { double num = quad.Height(worldX, worldZ); if (!result.HasValue || num < result.Value) { result = num; } } } return result; } public double? SurfaceHeight(double worldX, double worldZ) { Guard.Finite(worldX, "worldX"); Guard.Finite(worldZ, "worldZ"); double? result = null; Quad[] quads = _quads; foreach (Quad quad in quads) { if (quad.Contains(worldX, worldZ)) { double num = quad.Height(worldX, worldZ); if (!result.HasValue || num < result.Value) { result = num; } } } return result; } public bool HasSurfaceAtOrAbove(double worldX, double worldZ, double minimumHeight) { Guard.Finite(worldX, "worldX"); Guard.Finite(worldZ, "worldZ"); Guard.Finite(minimumHeight, "minimumHeight"); Quad[] quads = _quads; foreach (Quad quad in quads) { if (quad.Contains(worldX, worldZ) && quad.Height(worldX, worldZ) + 1E-09 >= minimumHeight) { return true; } } return false; } public static double LoweredHeight(double current, double target) { Guard.Finite(current, "current"); Guard.Finite(target, "target"); return Math.Min(current, target); } } public static class RailTerrainFillProbe { public static bool Validate(IReadOnlyList before, IReadOnlyList after, IReadOnlyList levels, IReadOnlyList smooth, IReadOnlyList modified, int target, double expectedRaise, out string reason) { reason = "The native fill probe has inconsistent terrain arrays."; if (before == null || after == null || levels == null || smooth == null || modified == null || before.Count == 0 || before.Count != after.Count || before.Count != levels.Count || before.Count != smooth.Count || before.Count != modified.Count || target < 0 || target >= before.Count || double.IsNaN(expectedRaise) || double.IsInfinity(expectedRaise) || expectedRaise < 0.0 || expectedRaise > 0.30000099999999996) { return false; } for (int i = 0; i < before.Count; i++) { if (!Finite(before[i]) || !Finite(after[i]) || !Finite(levels[i]) || !Finite(smooth[i])) { reason = "The native fill probe produced non-finite terrain data."; return false; } if ((double)Math.Abs(before[i] - after[i]) > 1E-05 || (double)Math.Abs(smooth[i]) > 1E-05) { reason = "The native fill brush changed terrain outside its level-delta buffer."; return false; } double num = ((i == target) ? expectedRaise : 0.0); if (Math.Abs((double)levels[i] - num) > 1E-05 || modified[i] != (i == target && expectedRaise > 0.0)) { reason = "The native fill brush did not preserve the bounded, raise-only single-vertex operation."; return false; } } reason = ""; return true; } private static bool Finite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } } public static class RailTerrainMaintenancePolicy { public const double HeightTolerance = 0.002; public const double NativeDigLimit = 7.99; public const double RetrySeconds = 15.0; public const int MaximumUnchangedAttempts = 3; public static double? CutHeight(double current, double bed, double original) { Guard.Finite(current, "current"); Guard.Finite(bed, "bed"); Guard.Finite(original, "original"); if (current - bed <= 0.002 || bed < original - 7.99) { return null; } return bed; } } public sealed class RailTerrainClearanceRequest { public bool Sent { get; private set; } public int Attempts { get; private set; } public double Surface { get; private set; } public double Target { get; private set; } public double LastSent { get; private set; } public bool CanSend(double current, double target, double now) { Check(current, target, now); if (!Sent || Math.Abs(current - Surface) > 0.002 || target < Target - 0.002) { return true; } if (target > Target + 0.002) { return false; } if (Attempts < 3) { return now >= LastSent + 15.0; } return false; } public void Record(double current, double target, double now) { if (!CanSend(current, target, now)) { throw new InvalidOperationException("This unchanged terrain request is still pending."); } bool flag = Sent && Math.Abs(current - Surface) <= 0.002 && Math.Abs(target - Target) <= 0.002; Attempts = ((!flag) ? 1 : (Attempts + 1)); Surface = current; Target = target; LastSent = now; Sent = true; } public bool Satisfied(double current) { Guard.Finite(current, "current"); if (Sent) { return current <= Target + 0.002; } return false; } private static void Check(double current, double target, double now) { Guard.Finite(current, "current"); Guard.Finite(target, "target"); Guard.Finite(now, "now"); if (now < 0.0 || current - target <= 0.002) { throw new ArgumentOutOfRangeException("target", "Only an actual downward soil change can be requested."); } } } public static class RailTerrainPaintProbe { private const float ColorTolerance = 1E-06f; public static bool Validate(float[] beforeRgba, float[] afterRgba, bool[] modifiedPaint, int pitch, int targetIndex, int radiusCells, IReadOnlyList beforeHeights, IReadOnlyList afterHeights, bool[] modifiedHeight, float[] levelDelta, float[] smoothDelta, out string reason) { reason = string.Empty; if (beforeRgba == null || afterRgba == null || modifiedPaint == null || beforeHeights == null || afterHeights == null || modifiedHeight == null || levelDelta == null || smoothDelta == null || pitch <= 0 || radiusCells < 0 || beforeRgba.Length == 0 || beforeRgba.Length % 4 != 0 || beforeRgba.Length != afterRgba.Length || modifiedPaint.Length != beforeRgba.Length / 4 || modifiedPaint.Length % pitch != 0 || targetIndex < 0 || targetIndex >= modifiedPaint.Length || beforeHeights.Count == 0 || beforeHeights.Count != afterHeights.Count || beforeHeights.Count != modifiedHeight.Length || beforeHeights.Count != levelDelta.Length || beforeHeights.Count != smoothDelta.Length) { return Fail("The isolated paint probe has inconsistent grid dimensions.", out reason); } for (int i = 0; i < beforeHeights.Count; i++) { if (!Finite(beforeHeights[i]) || !Finite(afterHeights[i]) || modifiedHeight[i] || beforeHeights[i] != afterHeights[i] || levelDelta[i] != 0f || smoothDelta[i] != 0f) { return Fail("Native stone painting changed a terrain height or height modification.", out reason); } } int num = targetIndex % pitch; int num2 = targetIndex / pitch; for (int j = 0; j < modifiedPaint.Length; j++) { int num3 = j * 4; for (int k = 0; k < 4; k++) { if (!Finite(beforeRgba[num3 + k]) || !Finite(afterRgba[num3 + k])) { return Fail("Native stone painting produced a nonfinite paint channel.", out reason); } } if (j == targetIndex) { if (!modifiedPaint[j] || Math.Abs(afterRgba[num3]) > 0.01f || Math.Abs(afterRgba[num3 + 1]) > 0.01f || Math.Abs(afterRgba[num3 + 2] - 1f) > 0.01f || (Math.Abs(afterRgba[num3] - beforeRgba[num3]) <= 1E-06f && Math.Abs(afterRgba[num3 + 1] - beforeRgba[num3 + 1]) <= 1E-06f && Math.Abs(afterRgba[num3 + 2] - beforeRgba[num3 + 2]) <= 1E-06f)) { return Fail("Native stone painting did not change the requested pixel to stone paving.", out reason); } if (Math.Abs(afterRgba[num3 + 3] - beforeRgba[num3 + 3]) > 1E-06f) { return Fail("Native stone painting changed the terrain vegetation channel.", out reason); } continue; } if (modifiedPaint[j] && (Math.Abs(j % pitch - num) > radiusCells || Math.Abs(j / pitch - num2) > radiusCells)) { return Fail("Native stone painting marked a pixel outside the protected brush stencil.", out reason); } for (int l = 0; l < 4; l++) { if (Math.Abs(afterRgba[num3 + l] - beforeRgba[num3 + l]) > 1E-06f) { return Fail("Native stone painting changed a neighboring terrain pixel.", out reason); } } } return true; } private static bool Finite(float value) { if (!float.IsNaN(value)) { return !float.IsInfinity(value); } return false; } private static bool Fail(string message, out string reason) { reason = message; return false; } } public sealed class RailThreeWayTrackDefinition { public string PrefabName { get; } public bool LightDuty { get; } public int WoodCost { get { if (!LightDuty) { return 30; } return 24; } } public int NailsCost { get { if (!LightDuty) { return 12; } return 6; } } internal RailThreeWayTrackDefinition(bool lightDuty) { LightDuty = lightDuty; PrefabName = (lightDuty ? "vr_track_wood_threeway" : "vr_track_threeway"); } public RailVector[] TrunkPoints() { return new RailVector[2] { new RailVector(0.0, 0.0, -2.0), default(RailVector) }; } public RailVector[] StraightPoints() { return new RailVector[2] { default(RailVector), new RailVector(0.0, 0.0, RailThreeWayTracks.ForwardLength) }; } public RailVector[] LeftPoints() { return Branch(-1); } public RailVector[] RightPoints() { return Branch(1); } private static RailVector[] Branch(int side) { RailVector[] array = new RailVector[17]; for (int i = 0; i < array.Length; i++) { double num = Math.PI / 4.0 * (double)i / 16.0; array[i] = new RailVector((double)side * 8.0 * (1.0 - Math.Cos(num)), 0.0, 8.0 * Math.Sin(num)); } return array; } } public static class RailThreeWayTracks { public const string PrefabName = "vr_track_threeway"; public const string WoodenPrefabName = "vr_track_wood_threeway"; public const double Radius = 8.0; public const double StemLength = 2.0; public const int CurveSegments = 16; public static double ForwardLength => 8.0 * Math.Sin(Math.PI / 4.0); public static IReadOnlyList All { get; } = Array.AsReadOnly(new RailThreeWayTrackDefinition[2] { new RailThreeWayTrackDefinition(lightDuty: false), new RailThreeWayTrackDefinition(lightDuty: true) }); public static bool TryGet(string? prefabName, out RailThreeWayTrackDefinition definition) { foreach (RailThreeWayTrackDefinition item in All) { if (string.Equals(item.PrefabName, prefabName, StringComparison.Ordinal)) { definition = item; return true; } } definition = null; return false; } } public static class RailTorchSockets { public const double SideOffset = 1.65; public const double Height = 0.12; public static RailVector[] Beside(RailPath path) { return new RailVector[2] { Side(path, -1), Side(path, 1) }; } public static RailVector[] OutsideJunction(RailPath left, RailPath right) { return new RailVector[2] { Side(left, -1), Side(right, 1) }; } private static RailVector Side(RailPath path, int side) { if (path == null) { throw new ArgumentNullException("path"); } RailPose railPose = path.Sample(path.Length * 0.5); RailVector railVector = new RailVector(railPose.Tangent.Z, 0.0, 0.0 - railPose.Tangent.X).Normalized(); return railPose.Position + railVector * (1.65 * (double)side) + new RailVector(0.0, 0.12, 0.0); } } public static class RailTrackCapacity { private const double BoundaryTolerance = 0.002; public static bool IsSupported(RailNetwork network, RailCursor locomotive, double halfLength, ISet lightTrackIds) { ValidateArguments(network, halfLength, lightTrackIds); if (network.Advance(locomotive, 0.0).StopReason == RailStopReason.MissingSegment) { return false; } if (lightTrackIds.Contains(locomotive.SegmentId)) { return false; } if (!OverlapsLightTrack(network, locomotive, halfLength, lightTrackIds)) { return !OverlapsLightTrack(network, locomotive.Reversed(), halfLength, lightTrackIds); } return false; } public static double LimitTravel(RailNetwork network, RailCursor locomotive, bool forward, double proposedDistance, double halfLength, ISet lightTrackIds, out bool restricted) { ValidateArguments(network, halfLength, lightTrackIds); Guard.Finite(proposedDistance, "proposedDistance"); if (proposedDistance < 0.0) { throw new ArgumentOutOfRangeException("proposedDistance"); } restricted = false; if (!IsSupported(network, locomotive, halfLength, lightTrackIds)) { restricted = true; return 0.0; } RailCursor railCursor = (forward ? locomotive : locomotive.Reversed()); double maxDistance = ((halfLength > double.MaxValue - proposedDistance) ? double.MaxValue : (halfLength + proposedDistance)); if (!network.TryDistanceToAnySegment(railCursor, lightTrackIds, maxDistance, out var distance)) { return proposedDistance; } restricted = true; return Math.Min(proposedDistance, Math.Max(0.0, distance - halfLength)); } private static bool OverlapsLightTrack(RailNetwork network, RailCursor direction, double halfLength, ISet lightTrackIds) { if (network.TryDistanceToAnySegment(direction, lightTrackIds, halfLength, out var distance)) { return distance < halfLength - 0.002; } return false; } private static void ValidateArguments(RailNetwork network, double halfLength, ISet lightTrackIds) { if (network == null) { throw new ArgumentNullException("network"); } if (lightTrackIds == null) { throw new ArgumentNullException("lightTrackIds"); } Guard.Finite(halfLength, "halfLength"); if (halfLength < 0.0) { throw new ArgumentOutOfRangeException("halfLength"); } } } public readonly struct RailSnapPort { public RailVector Position { get; } public RailVector Outward { get; } public RailSnapPort(RailVector position, RailVector outward) { Position = position; Outward = outward.Normalized(); } } public readonly struct RailSnapPlacement { public RailVector Position { get; } public double YawDegrees { get; } public double RotationChange { get; } internal RailSnapPlacement(RailVector position, double yaw, double change) { Position = position; YawDegrees = yaw; RotationChange = change; } } public static class RailTrackSnapping { public const double AimRadius = 2.0; public const double ConnectionTolerance = 0.16; public const double MaximumConnectionAngle = 18.0; public static RailSnapPort Endpoint(IReadOnlyList path, bool start) { if (path == null) { throw new ArgumentNullException("path"); } if (path.Count < 2) { throw new ArgumentException("A rail needs at least two points.", "path"); } int num = ((!start) ? (path.Count - 1) : 0); return Endpoint(path[num], path[start ? 1 : (num - 1)], (path.Count > 2) ? new RailVector?(path[start ? 2 : (num - 2)]) : ((RailVector?)null)); } public static RailSnapPort Endpoint(RailVector endpoint, RailVector neighbor, RailVector? nextNeighbor = null) { RailVector railVector = endpoint - neighbor; if (nextNeighbor.HasValue) { RailVector direction = neighbor - nextNeighbor.Value; if (HorizontalLength(railVector) > 1E-08 && HorizontalLength(direction) > 1E-08) { double to = Heading(railVector); double yawDegrees = Delta(Heading(direction), to) * 0.5; railVector = Rotate(railVector, yawDegrees); } } return new RailSnapPort(endpoint, railVector); } public static bool TryAlign(RailSnapPort local, RailSnapPort target, double requestedYaw, out RailSnapPlacement placement) { Guard.Finite(requestedYaw, "requestedYaw"); placement = default(RailSnapPlacement); if (HorizontalLength(local.Outward) < 1E-08 || HorizontalLength(target.Outward) < 1E-08) { return false; } double num = Delta(Heading(local.Outward), Heading(-target.Outward)); if (RailVector.Dot(Rotate(local.Outward, num), -target.Outward) + 1E-10 < Math.Cos(Math.PI / 10.0)) { return false; } placement = new RailSnapPlacement(target.Position - Rotate(local.Position, num), num, Math.Abs(Delta(requestedYaw, num))); return true; } public static bool IsReachable(RailSnapPort target, RailVector aim, RailVector eye, double buildReach) { Guard.Finite(buildReach, "buildReach"); if (buildReach > 0.0 && RailVector.Distance(aim, target.Position) <= 2.0) { return RailVector.Distance(eye, target.Position) < buildReach; } return false; } public static bool IsConnected(RailSnapPort a, RailSnapPort b) { if (RailVector.Distance(a.Position, b.Position) <= 0.16) { return RailVector.Dot(a.Outward, -b.Outward) + 1E-10 >= Math.Cos(Math.PI / 10.0); } return false; } public static RailVector Rotate(RailVector point, double yawDegrees) { Guard.Finite(yawDegrees, "yawDegrees"); double num = yawDegrees * Math.PI / 180.0; return new RailVector(point.X * Math.Cos(num) + point.Z * Math.Sin(num), point.Y, point.Z * Math.Cos(num) - point.X * Math.Sin(num)); } private static double HorizontalLength(RailVector direction) { return Math.Sqrt(direction.X * direction.X + direction.Z * direction.Z); } private static double Heading(RailVector direction) { return Math.Atan2(direction.X, direction.Z) * 180.0 / Math.PI; } private static double Delta(double from, double to) { return ((to - from) % 360.0 + 540.0) % 360.0 - 180.0; } } public sealed class RailTrackUpgradeDefinition { public string WoodenPrefab { get; } public string MetalPrefab { get; } public int IronNailsCost { get; } internal RailTrackUpgradeDefinition(string woodenPrefab, string metalPrefab, int ironNailsCost) { WoodenPrefab = woodenPrefab; MetalPrefab = metalPrefab; IronNailsCost = ironNailsCost; } } public static class RailTrackUpgrade { public static IReadOnlyList Definitions { get; } = CreateCatalog(); public static bool TryGet(string? prefabName, out RailTrackUpgradeDefinition definition) { foreach (RailTrackUpgradeDefinition definition2 in Definitions) { if (string.Equals(definition2.WoodenPrefab, prefabName, StringComparison.Ordinal)) { definition = definition2; return true; } } definition = null; return false; } private static IReadOnlyList CreateCatalog() { List list = new List { new RailTrackUpgradeDefinition("vr_track_wood_straight", "vr_track_straight", 2), new RailTrackUpgradeDefinition("vr_track_wood_curve", "vr_track_curve", 2), new RailTrackUpgradeDefinition("vr_track_wood_slope", "vr_track_slope", 2), new RailTrackUpgradeDefinition("vr_track_wood_brake", "vr_track_brake", 4), new RailTrackUpgradeDefinition("vr_track_wood_bumper", "vr_track_bumper", 4), new RailTrackUpgradeDefinition("vr_track_wood_straight_long", "vr_track_straight_long", 6), new RailTrackUpgradeDefinition("vr_track_wood_slope_long", "vr_track_slope_long", 6), new RailTrackUpgradeDefinition("vr_track_wood_slope_steep", "vr_track_slope_steep", 2), new RailTrackUpgradeDefinition("vr_track_wood_slope_steep_long", "vr_track_slope_steep_long", 6), new RailTrackUpgradeDefinition("vr_track_wood_switch", "vr_track_switch", 8), new RailTrackUpgradeDefinition("vr_track_wood_threeway", "vr_track_threeway", 12), new RailTrackUpgradeDefinition("vr_track_wood_bridge24", "vr_track_bridge24", 20) }; foreach (RailCurveTrackDefinition addition in RailCurveTracks.Additions) { if (!addition.LightDuty) { continue; } RailCurveTrackDefinition railCurveTrackDefinition = null; foreach (RailCurveTrackDefinition addition2 in RailCurveTracks.Additions) { if (!addition2.LightDuty && addition2.AngleDegrees == addition.AngleDegrees && addition2.Incline == addition.Incline && addition2.TurnsLeft == addition.TurnsLeft) { if (railCurveTrackDefinition != null) { throw new InvalidOperationException("Ambiguous metal curve for " + addition.PrefabName); } railCurveTrackDefinition = addition2; } } if (railCurveTrackDefinition == null) { throw new InvalidOperationException("Missing metal curve for " + addition.PrefabName); } list.Add(new RailTrackUpgradeDefinition(addition.PrefabName, railCurveTrackDefinition.PrefabName, railCurveTrackDefinition.NailsCost)); } foreach (RailBypassTrackDefinition item in RailBypassTracks.All) { if (!item.LightDuty) { continue; } RailBypassTrackDefinition railBypassTrackDefinition = null; foreach (RailBypassTrackDefinition item2 in RailBypassTracks.All) { if (!item2.LightDuty && item2.IsSwitch == item.IsSwitch && item2.TurnsLeft == item.TurnsLeft) { if (railBypassTrackDefinition != null) { throw new InvalidOperationException("Ambiguous metal bypass for " + item.PrefabName); } railBypassTrackDefinition = item2; } } if (railBypassTrackDefinition == null) { throw new InvalidOperationException("Missing metal bypass for " + item.PrefabName); } list.Add(new RailTrackUpgradeDefinition(item.PrefabName, railBypassTrackDefinition.PrefabName, railBypassTrackDefinition.NailsCost)); } foreach (RailParallelYardTrackDefinition item3 in RailParallelYardTracks.All) { if (!item3.LightDuty) { continue; } RailParallelYardTrackDefinition railParallelYardTrackDefinition = null; foreach (RailParallelYardTrackDefinition item4 in RailParallelYardTracks.All) { if (!item4.LightDuty && item4.ExitCount == item3.ExitCount) { railParallelYardTrackDefinition = item4; } } if (railParallelYardTrackDefinition == null) { throw new InvalidOperationException("Missing metal parallel yard for " + item3.PrefabName); } list.Add(new RailTrackUpgradeDefinition(item3.PrefabName, railParallelYardTrackDefinition.PrefabName, railParallelYardTrackDefinition.NailsCost)); } return list.AsReadOnly(); } } public enum RailEngineKind { Handcart, TandemHandcart, BronzeEngine, CoalLocomotive, EitrEngine } public readonly struct RailTractionResult { public double TargetSpeed { get; } public double PoweredAcceleration { get; } public double LoadFactor { get; } public double GradeFactor { get; } internal RailTractionResult(double targetSpeed, double acceleration, double load, double grade) { TargetSpeed = targetSpeed; PoweredAcceleration = acceleration; LoadFactor = load; GradeFactor = grade; } } public static class RailTraction { public static RailEngineKind Resolve(bool coalPowered, bool bronzePowered, bool tandem, bool hasPoweredPartner, bool eitrPowered = false) { if (!eitrPowered) { if (!coalPowered) { if (!bronzePowered) { if (!(tandem && hasPoweredPartner)) { return RailEngineKind.Handcart; } return RailEngineKind.TandemHandcart; } return RailEngineKind.BronzeEngine; } return RailEngineKind.CoalLocomotive; } return RailEngineKind.EitrEngine; } public static RailTractionResult Evaluate(RailEngineKind engine, RailSettingsValues settings, int wagonCount, double weight, double tangentY, double throttle) { if (settings == null) { throw new ArgumentNullException("settings"); } if (wagonCount < 0) { throw new ArgumentOutOfRangeException("wagonCount"); } Guard.Finite(weight, "weight"); Guard.Finite(tangentY, "tangentY"); Guard.Finite(throttle, "throttle"); if (weight < 0.0) { throw new ArgumentOutOfRangeException("weight"); } double num; double num2; double num3; double num4; double num5; double num6; switch (engine) { case RailEngineKind.Handcart: case RailEngineKind.TandemHandcart: { bool num7 = engine == RailEngineKind.TandemHandcart; num = (num7 ? settings.TandemHandcartMaxSpeed : settings.HandcartMaxSpeed); num2 = 1.5; num3 = 0.2; num4 = 400.0; num5 = (num7 ? settings.TandemHandcartLoadPenaltyMultiplier : settings.HandcartLoadPenaltyMultiplier); num6 = (num7 ? settings.TandemHandcartHillPenaltyMultiplier : settings.HandcartHillPenaltyMultiplier); break; } case RailEngineKind.BronzeEngine: num = settings.BronzeEngineMaxSpeed; num2 = 2.0; num3 = 0.16; num4 = 600.0; num5 = settings.BronzeEngineLoadPenaltyMultiplier; num6 = settings.BronzeEngineHillPenaltyMultiplier; break; case RailEngineKind.CoalLocomotive: num = settings.LocomotiveMaxSpeed; num2 = 2.5; num3 = 0.12; num4 = 800.0; num5 = settings.LocomotiveLoadPenaltyMultiplier; num6 = settings.LocomotiveHillPenaltyMultiplier; break; case RailEngineKind.EitrEngine: num = settings.EitrEngineMaxSpeed; num2 = 3.0; num3 = 0.12; num4 = 800.0; num5 = settings.EitrEngineLoadPenaltyMultiplier; num6 = settings.EitrEngineHillPenaltyMultiplier; break; default: throw new ArgumentOutOfRangeException("engine"); } throttle = Math.Max(-1.0, Math.Min(1.0, throttle)); double num8 = Math.Max(0.0, Math.Max(-1.0, Math.Min(1.0, tangentY)) * (double)Math.Sign(throttle)); double num9 = 1.0 + num5 * ((double)wagonCount * num3 + weight / num4); double num10 = 1.0 + num6 * num8 * 6.0; return new RailTractionResult(throttle * num / num9 / num10, num2 / num9, num9, num10); } } public static class RailTrainLimits { public const int MaximumConfigurableCarts = 20; public const int MaximumEnginesInTrain = 21; public const int MaximumVehiclesInChain = 128; public static bool CanAttachDetached(int wagonCount, int suffixCount) { if (wagonCount >= 1 && suffixCount >= 1 && wagonCount <= 20) { return suffixCount <= 20 - wagonCount; } return false; } public static bool CanAttach(int trainVehicleCount, int suffixCartCount, int maximumCarts) { if (trainVehicleCount >= 1 && trainVehicleCount <= 128 && suffixCartCount >= 1 && suffixCartCount <= 128) { return CanAttach(trainVehicleCount - 1, 1, suffixCartCount, 0, maximumCarts); } return false; } public static bool CanAttach(int trainCarts, int trainEngines, int incomingCarts, int incomingEngines, int maximumCarts) { if (maximumCarts < 0 || maximumCarts > 20 || !ValidGroup(trainCarts, trainEngines) || !ValidGroup(incomingCarts, incomingEngines)) { return false; } int num = trainEngines + incomingEngines; int num2 = trainCarts + incomingCarts; if (num < 1 || num > 21 || num2 + num > 128) { return false; } if (num2 <= maximumCarts) { return true; } if (trainEngines <= 0 || incomingCarts != 0) { if (incomingEngines > 0) { return trainCarts == 0; } return false; } return true; } private static bool ValidGroup(int carts, int engines) { if (carts >= 0 && carts <= 128 && engines >= 0 && engines <= 21 && carts + engines >= 1) { return carts + engines <= 128; } return false; } public static bool TryVisit(ISet visited, string identity) { if (!string.IsNullOrEmpty(identity) && visited.Count < 128) { return visited.Add(identity); } return false; } } public readonly struct RailTurntableLoad { public string Identity { get; } public RailCursor Cursor { get; } public RailVector Minimum { get; } public RailVector Maximum { get; } public RailTurntableLoad(string identity, RailCursor cursor, RailVector minimum, RailVector maximum) { if (string.IsNullOrWhiteSpace(identity)) { throw new ArgumentException("A vehicle identity is required.", "identity"); } if (minimum.X >= maximum.X || minimum.Y >= maximum.Y || minimum.Z >= maximum.Z) { throw new ArgumentException("The complete vehicle bounds must have positive width, height and length.", "maximum"); } Identity = identity; Cursor = cursor; Minimum = minimum; Maximum = maximum; } } [Flags] public enum RailTurntableBlocker { None = 0, Unready = 1, Ownership = 2, Moving = 4, Occupied = 8, Busy = 0x10, Attachment = 0x20, Obstructed = 0x40, Access = 0x80 } public static class RailTurntable { public const string SmallPrefabName = "vr_turntable12"; public const string LargePrefabName = "vr_turntable24"; public const double SmallLength = 12.0; public const double LargeLength = 24.0; public const double HalfWidth = 1.8; public const double EndClearance = 0.15; public const double SideClearance = 0.15; public const int Steps = 8; public const double StepDegrees = 45.0; private const double Epsilon = 1E-07; public static bool IsLength(double length) { if (length != 12.0) { return length == 24.0; } return true; } public static int NormalizeStep(int step) { int num = step % 8; if (num >= 0) { return num; } return num + 8; } public static double Yaw(int step) { return (double)NormalizeStep(step) * 45.0; } public static RailVector Rotate(RailVector point, int step) { return RotateDegrees(point, Yaw(step)); } public static RailVector RotateDegrees(RailVector point, double degrees) { Guard.Finite(degrees, "degrees"); double num = degrees % 360.0 * Math.PI / 180.0; double num2 = Math.Sin(num); double num3 = Math.Cos(num); return new RailVector(point.X * num3 + point.Z * num2, point.Y, point.Z * num3 - point.X * num2); } public static RailVector[] Points(double length, int step = 0) { ValidateLength(length); return new RailVector[2] { Rotate(new RailVector(0.0, 0.0, (0.0 - length) / 2.0), step), Rotate(new RailVector(0.0, 0.0, length / 2.0), step) }; } public static int StepDelta(int fromStep, int toStep) { int num = NormalizeStep(toStep) - NormalizeStep(fromStep); if (num > 4) { num -= 8; } if (num <= -4) { num += 8; } return num; } public static double[] RotationSamples(int fromStep, int toStep, double maximumStepDegrees = 5.0) { Guard.Finite(maximumStepDegrees, "maximumStepDegrees"); if (maximumStepDegrees < 0.25 || maximumStepDegrees > 45.0) { throw new ArgumentOutOfRangeException("maximumStepDegrees"); } double num = Yaw(fromStep); double num2 = (double)StepDelta(fromStep, toStep) * 45.0; if (num2 == 0.0) { return new double[1] { num }; } int num3 = (int)Math.Ceiling(Math.Abs(num2) / maximumStepDegrees); double[] array = new double[num3 + 1]; for (int i = 0; i <= num3; i++) { array[i] = num + num2 * (double)i / (double)num3; } return array; } public static double SweepPadding(double maximumRadius, double sampleStepDegrees) { Guard.Finite(maximumRadius, "maximumRadius"); Guard.Finite(sampleStepDegrees, "sampleStepDegrees"); if (maximumRadius < 0.0) { throw new ArgumentOutOfRangeException("maximumRadius"); } if (sampleStepDegrees < 0.0 || sampleStepDegrees > 45.0) { throw new ArgumentOutOfRangeException("sampleStepDegrees"); } return 2.0 * maximumRadius * Math.Sin(sampleStepDegrees * Math.PI / 720.0); } public static double DeckRadius(double length) { ValidateLength(length); return Math.Sqrt(length * length / 4.0 + 3.24); } public static bool TryFit(double length, string segmentId, IReadOnlyList loads, IReadOnlyCollection expectedVehicleIds, out string reason) { ValidateLength(length); if (string.IsNullOrWhiteSpace(segmentId)) { throw new ArgumentException("A turntable segment is required.", "segmentId"); } if (loads == null) { throw new ArgumentNullException("loads"); } if (expectedVehicleIds == null) { throw new ArgumentNullException("expectedVehicleIds"); } reason = "Wait for every connected vehicle to load onto the turntable."; if (loads.Count > 128 || expectedVehicleIds.Count > 128) { return false; } HashSet hashSet = new HashSet(StringComparer.Ordinal); foreach (string expectedVehicleId in expectedVehicleIds) { if (string.IsNullOrWhiteSpace(expectedVehicleId) || !hashSet.Add(expectedVehicleId)) { return false; } } if (hashSet.Count != loads.Count) { return false; } foreach (RailTurntableLoad load in loads) { if (string.IsNullOrWhiteSpace(load.Identity) || !hashSet.Remove(load.Identity)) { return false; } RailCursor cursor = load.Cursor; if (!string.Equals(cursor.SegmentId, segmentId, StringComparison.Ordinal) || (cursor.Direction != 1 && cursor.Direction != -1) || cursor.Distance < 0.0 || cursor.Distance > length || double.IsNaN(cursor.Distance) || double.IsInfinity(cursor.Distance)) { return false; } if (load.Minimum.X >= load.Maximum.X || load.Minimum.Y >= load.Maximum.Y || load.Minimum.Z >= load.Maximum.Z) { return false; } reason = "Move the entire train and its attachments inside the turntable deck."; if (load.Minimum.X < -1.6500001000000002 || load.Maximum.X > 1.6500001000000002 || load.Minimum.Z < (0.0 - length) / 2.0 + 0.15 - 1E-07 || load.Maximum.Z > length / 2.0 - 0.15 + 1E-07) { return false; } double num = cursor.Distance - length / 2.0; if (load.Minimum.Z > num + 1E-07 || load.Maximum.Z < num - 1E-07 || load.Minimum.X > 1E-07 || load.Maximum.X < -1E-07) { reason = "Wait for the train's position to finish synchronizing."; return false; } reason = "Wait for every connected vehicle to load onto the turntable."; } reason = ""; return true; } public static bool CanRotate(RailTurntableBlocker blockers, out string reason) { if (blockers == RailTurntableBlocker.None) { reason = ""; return true; } if ((blockers & RailTurntableBlocker.Access) != RailTurntableBlocker.None) { reason = "The turntable or train is protected by a ward."; } else if ((blockers & RailTurntableBlocker.Unready) != RailTurntableBlocker.None) { reason = "Wait for the turntable and complete train to load."; } else if ((blockers & RailTurntableBlocker.Ownership) != RailTurntableBlocker.None) { reason = "Wait for the train's network ownership to settle."; } else if ((blockers & RailTurntableBlocker.Moving) != RailTurntableBlocker.None) { reason = "Stop the whole train and switch off automatic drive first."; } else if ((blockers & RailTurntableBlocker.Occupied) != RailTurntableBlocker.None) { reason = "Have everyone leave the train and turntable before rotating."; } else if ((blockers & RailTurntableBlocker.Busy) != RailTurntableBlocker.None) { reason = "Close storage and finish mounting, packing or coupling first."; } else if ((blockers & RailTurntableBlocker.Attachment) != RailTurntableBlocker.None) { reason = "Wait for all attached plows, torches and mounted objects to load."; } else if ((blockers & RailTurntableBlocker.Obstructed) != RailTurntableBlocker.None) { reason = "Clear the turntable's complete turning area."; } else { reason = "The turntable is not ready to rotate."; } return false; } private static void ValidateLength(double length) { if (!IsLength(length)) { throw new ArgumentOutOfRangeException("length", "Turntables are 12 or 24 metres long."); } } } public readonly struct RailUpgradeClaim { public const long LeaseMilliseconds = 15000L; public const int MaximumTokenLength = 64; public readonly long PeerId; public readonly long PlayerId; public readonly string Token; public readonly long ExpiresAt; public RailUpgradeClaim(long peerId, long playerId, string? token, long expiresAt) { PeerId = peerId; PlayerId = playerId; Token = token ?? ""; ExpiresAt = expiresAt; } public bool IsActive(long now) { if (now >= 0 && ExpiresAt > now) { return ValidIdentity(PeerId, PlayerId, Token); } return false; } public bool Matches(long peerId, long playerId, string? token) { if (ValidIdentity(peerId, playerId, token) && PeerId == peerId && PlayerId == playerId) { return string.Equals(Token, token, StringComparison.Ordinal); } return false; } public bool CanGrant(long peerId, long playerId, string? token, long now) { if (now >= 0 && now <= 9223372036854760807L && ValidIdentity(peerId, playerId, token)) { if (IsActive(now)) { return Matches(peerId, playerId, token); } return true; } return false; } private static bool ValidIdentity(long peerId, long playerId, string? token) { if (peerId != 0L && playerId != 0L && !string.IsNullOrWhiteSpace(token)) { return token.Length <= 64; } return false; } } public static class RailVehicleAnchor { public const double PositionTolerance = 0.02; public const double HeadingToleranceDegrees = 0.5; public const double EndpointRoundoffTolerance = 0.001; private static readonly double MinimumHeadingDot = Math.Cos(Math.PI / 360.0); public static bool TryRestore(RailNetwork network, string? id, double savedDistance, int direction, RailVector worldPosition, RailVector forward, out RailCursor cursor) { cursor = default(RailCursor); if (network == null || string.IsNullOrWhiteSpace(id) || (direction != 1 && direction != -1) || double.IsNaN(savedDistance) || double.IsInfinity(savedDistance) || savedDistance < 0.0 || !network.TryGetPath(id, out RailPath path) || savedDistance > path.Length + 0.001) { return false; } double magnitude = forward.Magnitude; if (magnitude <= 1E-08 || double.IsInfinity(magnitude)) { return false; } RailCursor railCursor = new RailCursor(id, Math.Min(savedDistance, path.Length), direction); RailPose railPose = RailVehiclePose.Sample(network, railCursor); if (RailVector.Distance(railPose.Position, worldPosition) > 0.02 || RailVector.Dot(railPose.Tangent, forward / magnitude) < MinimumHeadingDot) { return false; } cursor = railCursor; return true; } } public static class RailVehiclePose { public const double HalfAxleSpan = 0.68; private const double SeamWindow = 0.5; public static RailPose Sample(RailNetwork network, RailCursor cursor) { if (network == null) { throw new ArgumentNullException("network"); } RailPose railPose = network.Sample(cursor); RailVector railVector = AxlePoint(network, cursor); RailVector railVector2 = AxlePoint(network, cursor.Reversed()); RailVector railVector3 = railVector - railVector2; return new RailPose(tangent: (railVector3.Magnitude > 1E-08) ? railVector3.Normalized() : railPose.Tangent, position: (railVector + railVector2) * 0.5); } private static RailVector AxlePoint(RailNetwork network, RailCursor travel) { RailAdvanceResult railAdvanceResult = network.Advance(travel, 0.68); RailPose railPose = network.Sample(railAdvanceResult.Cursor); return ContinuousPoint(network, railAdvanceResult.Cursor, railPose.Position) + railPose.Tangent * Math.Max(0.0, 0.68 - railAdvanceResult.DistanceTravelled); } private static RailVector ContinuousPoint(RailNetwork network, RailCursor cursor, RailVector position) { if (!network.TryGetPath(cursor.SegmentId, out RailPath path)) { return position; } double window = Math.Min(0.5, path.Length * 0.5); position += SeamCorrection(network, cursor.SegmentId, path, atEnd: false, cursor.Distance, window); position += SeamCorrection(network, cursor.SegmentId, path, atEnd: true, path.Length - cursor.Distance, window); return position; } private static RailVector SeamCorrection(RailNetwork network, string id, RailPath path, bool atEnd, double distance, double window) { if (distance >= window || !network.TryGetConnectedEnd(id, atEnd, out var connected)) { return new RailVector(0.0, 0.0, 0.0); } if (!network.TryGetPath(connected.SegmentId, out RailPath path2)) { return new RailVector(0.0, 0.0, 0.0); } window = Math.Min(window, path2.Length * 0.5); if (distance >= window) { return new RailVector(0.0, 0.0, 0.0); } RailVector position = path.Sample(atEnd ? path.Length : 0.0).Position; RailVector position2 = network.Sample(connected).Position; double num = 1.0 - distance / window; double num2 = num * num * (3.0 - 2.0 * num); return (position2 - position) * (0.5 * num2); } } public static class RailWorkshopUpgrades { public static bool IsWorkbenchUpgrade(string prefab) { switch (prefab) { default: return prefab == "piece_workbench_ext4"; case "piece_workbench_ext1": case "piece_workbench_ext2": case "piece_workbench_ext3": return true; } } } public readonly struct SwitchRouteReservation { public const long LeaseMilliseconds = 6000L; public const long DriverSafetyMilliseconds = 2000L; public readonly string Engine; public readonly long Peer; public readonly string Token; public readonly bool SelectRight; public readonly int SelectedRoute; public readonly long ExpiresAt; public SwitchRouteReservation(string engine, long peer, string token, bool selectRight, long expiresAt) : this(engine, peer, token, selectRight ? 1 : 0, expiresAt) { } public SwitchRouteReservation(string engine, long peer, string token, int selectedRoute, long expiresAt) { Engine = engine ?? ""; Peer = peer; Token = token ?? ""; SelectedRoute = selectedRoute; SelectRight = selectedRoute == 1; ExpiresAt = expiresAt; } public bool IsActive(long now) { if (!string.IsNullOrEmpty(Engine) && Peer != 0L && !string.IsNullOrEmpty(Token)) { return ExpiresAt > now; } return false; } public bool Matches(string engine, long peer, string token) { if (!string.IsNullOrEmpty(engine) && peer != 0L && !string.IsNullOrEmpty(token) && string.Equals(Engine, engine, StringComparison.Ordinal) && Peer == peer) { return string.Equals(Token, token, StringComparison.Ordinal); } return false; } public bool CanReserve(string engine, long peer, string token, bool selectRight, long now) { return CanReserve(engine, peer, token, selectRight ? 1 : 0, now); } public bool CanReserve(string engine, long peer, string token, int selectedRoute, long now) { return CanReserve(engine, peer, token, selectedRoute, 3, now); } public bool CanReserve(string engine, long peer, string token, int selectedRoute, int routeCount, long now) { if (ValidRoute(selectedRoute, routeCount) && !string.IsNullOrEmpty(engine) && peer != 0L && !string.IsNullOrEmpty(token)) { if (IsActive(now)) { if (Matches(engine, peer, token)) { return SelectedRoute == selectedRoute; } return false; } return true; } return false; } public bool CanDrive(string engine, long peer, string token, bool selectedRight, long now) { return CanDrive(engine, peer, token, selectedRight ? 1 : 0, now); } public bool CanDrive(string engine, long peer, string token, int selectedRoute, long now) { return CanDrive(engine, peer, token, selectedRoute, 3, now); } public bool CanDrive(string engine, long peer, string token, int selectedRoute, int routeCount, long now) { if (ValidRoute(selectedRoute, routeCount) && IsActive(now) && Matches(engine, peer, token) && SelectedRoute == selectedRoute) { return ExpiresAt - now > 2000; } return false; } private static bool ValidRoute(int route, int count) { if ((count == 2 || count == 3 || count == 5) && route >= 0) { return route < count; } return false; } } }