Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of VikingRail v0.46.1
plugins/VikingRail/VikingRail.dll
Decompiled 3 weeks ago
The result has been truncated due to the large size, download it to view full contents!
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<Vagon>(); 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<AudioSource>() : null); if (Object.op_Implicit((Object)(object)val3) && Object.op_Implicit((Object)(object)val3.outputAudioMixerGroup)) { return val3.outputAudioMixerGroup; } } } AudioSource[] componentsInChildren = val.GetComponentsInChildren<AudioSource>(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<RailAutoDrive> Controllers = new HashSet<RailAutoDrive>(); private static readonly HashSet<string> DestroyedIdentities = new HashSet<string>(); 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<RailAutoDrive> 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<ZNetView>(); _body = ((Component)this).GetComponent<Rigidbody>(); _wear = ((Component)this).GetComponent<WearNTear>(); _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<long, ZDOID, bool>("VR_AutoAttach", (Action<long, long, ZDOID, bool>)RequestAttachment); _view.Register<bool, string>("VR_AutoAttachReply", (Action<long, bool, string>)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[<color=yellow>$KEY_Use</color>] " + text2 + (IsAttached ? "\n[<color=yellow>$KEY_AltPlace + $KEY_Use</color>] 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<RailAutoDrive>() == (Object)(object)this) && !((Object)(object)((Component)val).GetComponentInParent<RailVehicle>() == (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<ZDO>)Delegate.Remove(trackedManager.m_onZDODestroyed, new Action<ZDO>(TrackDestroyed)); } _trackedManager = ZDOMan.instance; DestroyedIdentities.Clear(); ZDOMan? trackedManager2 = _trackedManager; trackedManager2.m_onZDODestroyed = (Action<ZDO>)Delegate.Combine(trackedManager2.m_onZDODestroyed, new Action<ZDO>(TrackDestroyed)); } } internal static void Cleanup() { if (_trackedManager != null) { ZDOMan? trackedManager = _trackedManager; trackedManager.m_onZDODestroyed = (Action<ZDO>)Delegate.Remove(trackedManager.m_onZDODestroyed, new Action<ZDO>(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<ZDO> list = new List<ZDO>(); ZDOMan.instance.FindSectorObjects(origin.GetSector(), new SimulationDistance(1, 0, false), list, (List<ZDO>)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<RailAutoDrive>(); 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<RailAutoDrive>(); 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<Piece>(); 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<RailVehicle>() == (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<Inventory, RailCargoInventory> Inventories = new ConditionalWeakTable<Inventory, RailCargoInventory>(); 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<Container>(); _cart = ((Component)this).GetComponent<RailVehicle>(); _view = ((Component)this).GetComponent<ZNetView>(); 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<long, string, int>("VR_CargoNative", (Action<long, long, string, int>)OwnerRequest); _view.Register<string, int, bool>("VR_CargoNativeReply", (Action<long, string, int, bool>)NativeReply); _rpcRegistered = true; } } private static RailCargoInventory Get(Container container) { return ((Component)container).GetComponent<RailCargoInventory>() ?? ((Component)container).gameObject.AddComponent<RailCargoInventory>(); } internal static void Ensure(Container container) { Get(container).RegisterRpc(); } internal static bool HasPending(RailVehicle cart) { RailCargoInventory component = ((Component)cart).GetComponent<RailCargoInventory>(); 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<RailCargoInventory>(); 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<RailCargoInventory>(); 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<RailVehicle>())) { 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<ItemData> collection = new List<ItemData>(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<RailVehicle>())) { 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<RailVehicle>())) { 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<RailCargoInventory>())) { return ((Component)container).GetComponent<RailCargoInventory>()._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<RailVehicle>())) { 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<RailVehicle>())) { 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<RailVehicle>())) { 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<MethodBase> 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<MethodBase> 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<MethodBase> 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<MethodBase> 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<Container>(); _cart = ((Component)this).GetComponent<RailVehicle>(); _view = ((Component)this).GetComponent<ZNetView>(); } 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<ItemData> 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<MeshFilter>(); _boxMesh = ((component != null) ? component.sharedMesh : null); MeshRenderer component2 = ((Component)val).GetComponent<MeshRenderer>(); _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<MeshRenderer>(true); if (componentsInChildren.Length == 0 || componentsInChildren.Length > 96) { return false; } HashSet<Renderer> hashSet = LowerLodRenderers(val); List<MeshRenderer> list = new List<MeshRenderer>(); 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<MeshFilter>(); 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<Transform, Transform> copies = new Dictionary<Transform, Transform> { [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<MeshFilter>().sharedMesh; ((Component)val5).gameObject.AddComponent<MeshFilter>().sharedMesh = sharedMesh; MeshRenderer obj = ((Component)val5).gameObject.AddComponent<MeshRenderer>(); ((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<MeshRenderer>(true))) { return val; } } } return prefab; } private static HashSet<Renderer> LowerLodRenderers(Transform source) { HashSet<Renderer> hashSet = new HashSet<Renderer>(); HashSet<Renderer> hashSet2 = new HashSet<Renderer>(); LODGroup[] componentsInChildren = ((Component)source).GetComponentsInChildren<LODGroup>(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<Transform, Transform> 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<MeshFilter>().sharedMesh = _boxMesh; MeshRenderer obj = val.AddComponent<MeshRenderer>(); ((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<RailVehicle>(); _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[<color=yellow>$KEY_Use</color>] Uncouple this end\nStop the train before releasing." : "\n[<color=yellow>$KEY_Use</color>] 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 && !((