Decompiled source of Railroads v0.1.9

plugins/Railroads/Railroads.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Blackforge.Hot;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Blackforge
{
	public static class Bodies
	{
		private const float MissingFor = 3f;

		private static readonly Dictionary<ZDOID, float> missingSince = new Dictionary<ZDOID, float>();

		private static float nextCheck;

		private static string ReportFile => Path.Combine(Paths.BepInExRootPath, "rail-bodies.txt");

		public static void Reset()
		{
			missingSince.Clear();
			nextCheck = 0f;
		}

		private static IEnumerable<ZDOID> Parts(ZDO loco)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			return ((IEnumerable<ZDOID>)(object)new ZDOID[1] { loco.m_uid }).Concat(Train.WagonIds(loco));
		}

		public static void Report()
		{
			//IL_0029: 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_002e: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			StringBuilder stringBuilder = new StringBuilder();
			Player localPlayer = Player.m_localPlayer;
			Vector3 me = (((Object)(object)localPlayer != (Object)null) ? ((Component)localPlayer).transform.position : Vector3.zero);
			Vector3 val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetReferencePosition() : me);
			stringBuilder.Append($"time {Time.time:0.0}, player at {Point(me)}, reference {Point(val)}, session {ZDOMan.GetSessionID()}, rail in sync {RailPlugin.InSync}\n");
			foreach (ZDO item in Train.Trains().OrderBy(delegate(ZDO l)
			{
				//IL_0001: Unknown result type (might be due to invalid IL or missing references)
				//IL_0007: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val2 = l.GetPosition() - me;
				return ((Vector3)(ref val2)).sqrMagnitude;
			}))
			{
				stringBuilder.Append($"train {item.m_uid}, {Train.WagonIds(item).Count} wagons\n");
				foreach (ZDOID item2 in Parts(item))
				{
					stringBuilder.Append("  ").Append(Describe(item2, me, val)).Append('\n');
				}
			}
			File.WriteAllText(ReportFile, stringBuilder.ToString());
		}

		public static string Describe(ZDOID id, Vector3 me, Vector3 center)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = ZDOMan.instance.GetZDO(id);
			if (zDO == null)
			{
				return $"{id}: no saved data on this machine";
			}
			Vector3 position = zDO.GetPosition();
			Vector2s zone = ZoneSystem.GetZone(position);
			ZNetView val = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.FindInstance(zDO) : null);
			string arg = "no object";
			if ((Object)(object)val != (Object)null)
			{
				Renderer[] componentsInChildren = ((Component)val).GetComponentsInChildren<Renderer>(true);
				int num = componentsInChildren.Count((Renderer r) => r.enabled && ((Component)r).gameObject.activeInHierarchy);
				arg = $"object at {Point(((Component)val).transform.position)}, {Vector3.Distance(((Component)val).transform.position, position):0.0} m from saved, active {((Component)val).gameObject.activeInHierarchy}, valid {val.IsValid()}, renderers {num} of {componentsInChildren.Length} on";
			}
			string text = ((zDO.GetPrefab() == Train.LocomotiveHash) ? "locomotive" : "wagon");
			return string.Format("{0} {1}: owner {2}{3}, in use {4}, saved at {5}, ", text, id, zDO.GetOwner(), zDO.IsOwner() ? " me" : "", zDO.GetInt(ZDOVars.s_inUse, 0), Point(position)) + $"{Vector3.Distance(position, me):0} m from the player, zone {zone.x},{zone.y} active {ZNetScene.InActiveArea(position, center)} loaded {ZoneSystem.instance.IsZoneLoaded(position)}, " + $"created {zDO.Created}, {arg}";
		}

		public static void Heal()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_024a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0251: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: 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_0169: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time < nextCheck || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ZNet.instance == (Object)null || ZNet.instance.IsDedicated() || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return;
			}
			nextCheck = Time.time + 1f;
			Vector3 position = ((Component)Player.m_localPlayer).transform.position;
			Vector3 referencePosition = ZNet.instance.GetReferencePosition();
			HashSet<ZDOID> seen = new HashSet<ZDOID>();
			foreach (ZDO item in Train.Trains())
			{
				foreach (ZDOID item2 in Parts(item))
				{
					ZDO zDO = ZDOMan.instance.GetZDO(item2);
					if (zDO == null)
					{
						continue;
					}
					Vector3 position2 = zDO.GetPosition();
					if (!ZNetScene.InActiveArea(position2, referencePosition) || !ZoneSystem.instance.IsZoneLoaded(position2) || (Object)(object)ZNetScene.instance.FindInstance(zDO) != (Object)null)
					{
						continue;
					}
					seen.Add(item2);
					if (!missingSince.TryGetValue(item2, out var value))
					{
						missingSince[item2] = Time.time;
					}
					else if (!(Time.time - value < 3f))
					{
						if (!zDO.Created)
						{
							RailPlugin.Log.LogInfo((object)$"rail: a train body waits for the scene for {Time.time - value:0} s: {Describe(item2, position, referencePosition)}");
							missingSince[item2] = Time.time;
						}
						else
						{
							RailPlugin.Log.LogWarning((object)$"rail: a train body has no object for {Time.time - value:0} s, it is built again: {Describe(item2, position, referencePosition)}");
							zDO.Created = false;
							missingSince[item2] = Time.time;
						}
					}
				}
			}
			foreach (ZDOID item3 in missingSince.Keys.Where((ZDOID id) => !seen.Contains(id)).ToList())
			{
				missingSince.Remove(item3);
			}
		}

		private static string Point(Vector3 p)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			return string.Format(CultureInfo.InvariantCulture, "{0:0.0} {1:0.0} {2:0.0}", p.x, p.y, p.z);
		}
	}
	public class RailCargo : MonoBehaviour
	{
		public static readonly float[] Stages = new float[4] { 0.01f, 25f, 50f, 75f };

		public GameObject[] m_stages = (GameObject[])(object)new GameObject[0];

		private Container m_container;

		private float m_next;

		private void Awake()
		{
			m_container = ((Component)this).GetComponent<Container>();
		}

		private void Update()
		{
			if (Time.time < m_next || (Object)(object)m_container == (Object)null || m_container.GetInventory() == null)
			{
				return;
			}
			m_next = Time.time + 1f;
			float num = m_container.GetInventory().SlotsUsedPercentage();
			for (int i = 0; i < m_stages.Length && i < Stages.Length; i++)
			{
				if (m_stages[i].activeSelf != num >= Stages[i])
				{
					m_stages[i].SetActive(num >= Stages[i]);
				}
			}
		}
	}
	public static class Carry
	{
		private const float Reach = 8f;

		private static Transform ride;

		private static Vector3 spot;

		public static void Before()
		{
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsAttached() || ((Character)localPlayer).IsTeleporting())
			{
				ride = null;
				return;
			}
			if (((Character)localPlayer).IsOnGround())
			{
				Rigidbody lastGroundBody = ((Character)localPlayer).m_lastGroundBody;
				ride = (((Object)(object)lastGroundBody != (Object)null && ((Object)(object)((Component)lastGroundBody).GetComponent<RailBody>() != (Object)null || (Object)(object)((Component)lastGroundBody).GetComponent<FlatbedDeck>() != (Object)null)) ? ((Component)lastGroundBody).transform : null);
			}
			if (!((Object)(object)ride == (Object)null))
			{
				Vector3 val = ride.position - ((Component)localPlayer).transform.position;
				if (!(((Vector3)(ref val)).sqrMagnitude > 64f))
				{
					spot = ride.InverseTransformPoint(((Component)localPlayer).transform.position);
					return;
				}
			}
			ride = null;
		}

		public static void After()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (!((Object)(object)ride == (Object)null) && !((Object)(object)localPlayer == (Object)null))
			{
				Vector3 val = ride.TransformPoint(spot) - ((Component)localPlayer).transform.position;
				if (!(val == Vector3.zero))
				{
					Transform transform = ((Component)localPlayer).transform;
					transform.position += val;
					((Character)localPlayer).m_body.position = ((Component)localPlayer).transform.position;
				}
			}
		}

		public static void Reset()
		{
			ride = null;
		}
	}
	public static class LocoLayout
	{
		public const float Lift = 0.9f;

		public static readonly Vector3 BigAxle = new Vector3(0f, 1.19f, -1.8f);

		public const float BigRadius = 0.85f;

		public const float Crank = 0.28f;

		public const float MainRod = 1.2f;

		public const float RodX = 0.9f;

		public const float MainX = 1f;

		public const float Eccentric = 0.12f;

		public const float EccentricRod = 1.5f;

		public const float ValveX = 1.16f;

		public const float ValveY = 1.3f;

		public const float CylinderFront = 0.5f;

		public static readonly Vector3 Seat = new Vector3(0f, 2.85f, -2.45f);

		public static readonly Vector3 Chimney = new Vector3(0f, 5.25f, 1.45f);

		public static readonly Vector3 Lever = new Vector3(0.72f, 2.46f, -1.45f);

		public static readonly Vector3 SpeedLever = new Vector3(-0.72f, 2.46f, -1.45f);

		public static readonly Vector3 Panel = new Vector3(0f, 3.45f, -0.925f);

		public static readonly Vector3 PanelSize = new Vector3(1f, 0.42f, 0.04f);

		public static readonly Vector3 Firebox = new Vector3(0f, 2.4f, 0.37f);

		public static readonly Vector3 FireDoor = new Vector3(0.8f, 2.53f, 0.37f);

		public static readonly Vector3 FireGlow = new Vector3(0.95f, 2.6f, 0.37f);

		public static readonly Vector3[] Cores = (Vector3[])(object)new Vector3[4]
		{
			new Vector3(0.6f, 2.42f, -0.43f),
			new Vector3(0.6f, 2.42f, 1.17f),
			new Vector3(-0.6f, 2.42f, -0.43f),
			new Vector3(-0.6f, 2.42f, 1.17f)
		};
	}
	public class RailDrive : MonoBehaviour
	{
		private static readonly float[] Sides = new float[2] { 1f, -1f };

		private static readonly float[] Phases = new float[2] { 0f, 90f };

		public RailMotion m_motion;

		public int m_axle;

		public Transform[] m_mainRods = (Transform[])(object)new Transform[2];

		public Transform[] m_crossheads = (Transform[])(object)new Transform[2];

		public Transform[] m_eccentricRods = (Transform[])(object)new Transform[2];

		public Transform[] m_valveRods = (Transform[])(object)new Transform[2];

		public ParticleSystem[] m_steam = (ParticleSystem[])(object)new ParticleSystem[2];

		private readonly int[] m_strokes = new int[2] { -1, -1 };

		private void LateUpdate()
		{
			if (!((Object)(object)m_motion == (Object)null))
			{
				float num = m_motion.Angle(m_axle);
				for (int i = 0; i < 2; i++)
				{
					Place(i, num + Phases[i]);
				}
			}
		}

		private static Vector3 Around(float angle, float radius)
		{
			//IL_0000: 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_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			return LocoLayout.BigAxle + Quaternion.Euler(angle, 0f, 0f) * new Vector3(0f, 0f, radius);
		}

		private void Place(int i, float angle)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			float num = Sides[i];
			Vector3 val = Around(angle, 0.28f);
			float num2 = val.y - LocoLayout.BigAxle.y;
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(0f, LocoLayout.BigAxle.y, val.z + Mathf.Sqrt(1.44f - num2 * num2));
			Aim(m_mainRods[i], num * 1f, val, val2);
			Put(m_crossheads[i], num * 0.9f, val2);
			Vector3 val3 = Around(angle + 90f, 0.12f);
			float num3 = 1.3f - val3.y;
			Vector3 val4 = default(Vector3);
			((Vector3)(ref val4))..ctor(0f, 1.3f, val3.z + Mathf.Sqrt(2.25f - num3 * num3));
			Aim(m_eccentricRods[i], num * 1.16f, val3, val4);
			Put(m_valveRods[i], num * 1.16f, val4);
			int num4 = Mathf.FloorToInt(Mathf.Repeat(angle, 360f) / 180f);
			if (num4 != m_strokes[i])
			{
				if (m_strokes[i] >= 0 && m_motion.Speed > 0.3f)
				{
					Puff(i, num);
				}
				m_strokes[i] = num4;
			}
		}

		private static void Put(Transform part, float x, Vector3 at)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)part != (Object)null)
			{
				part.localPosition = new Vector3(x, at.y, at.z);
			}
		}

		private static void Aim(Transform rod, float x, Vector3 from, Vector3 to)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)rod != (Object)null)
			{
				rod.localPosition = new Vector3(x, from.y, from.z);
				rod.localRotation = Quaternion.LookRotation(new Vector3(0f, to.y - from.y, to.z - from.z), Vector3.up);
			}
		}

		private void Puff(int i, float side)
		{
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			ParticleSystem val = m_steam[i];
			if (!((Object)(object)val == (Object)null))
			{
				float num = Mathf.Clamp01(m_motion.Speed / 10f);
				Vector3 val2 = ((Component)this).transform.rotation * new Vector3(side, -0.3f, 0.2f);
				int num2 = 3 + Mathf.RoundToInt(num * 4f);
				for (int j = 0; j < num2; j++)
				{
					EmitParams val3 = default(EmitParams);
					((EmitParams)(ref val3)).position = ((Component)val).transform.position;
					((EmitParams)(ref val3)).applyShapeToPosition = false;
					((EmitParams)(ref val3)).velocity = val2 * Random.Range(0.8f, 1.6f) + Random.insideUnitSphere * 0.3f;
					EmitParams val4 = val3;
					val.Emit(val4, 1);
				}
			}
		}
	}
	public static class Flatbed
	{
		[HarmonyPatch(typeof(ZDOMan), "AddIfPortal")]
		private static class Added
		{
			private static void Postfix(ZDOMan __instance, ZDO zdo)
			{
				if (__instance == seeded)
				{
					Index(zdo);
				}
			}
		}

		[HarmonyPatch(typeof(ZDOMan), "HandleDestroyedZDO")]
		private static class Destroyed
		{
			private static void Prefix(ZDOMan __instance, ZDOID uid)
			{
				//IL_0008: Unknown result type (might be due to invalid IL or missing references)
				if (__instance == seeded)
				{
					Forget(uid);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "PieceRayTest")]
		private static class AimAtDeck
		{
			private static void Postfix(Player __instance, ref bool __result, ref Vector3 point, ref Vector3 normal, ref Piece piece, ref Heightmap heightmap, ref Collider waterSurface, bool water)
			{
				//IL_004b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00da: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
				aim = 0L;
				aimAt = null;
				if (__result || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || (Object)(object)GameCamera.instance == (Object)null)
				{
					return;
				}
				Transform transform = ((Component)GameCamera.instance).transform;
				int num = (water ? __instance.m_placeWaterRayMask : __instance.m_placeRayMask);
				RaycastHit val = default(RaycastHit);
				if (!Physics.Raycast(transform.position, transform.forward, ref val, 50f, num))
				{
					return;
				}
				Transform deck;
				long num2 = DeckOf(((RaycastHit)(ref val)).collider, out deck);
				if (num2 != 0L)
				{
					float num3 = __instance.m_maxPlaceDistance;
					Piece val2 = (((Object)(object)__instance.m_placementGhost != (Object)null) ? __instance.m_placementGhost.GetComponent<Piece>() : null);
					if ((Object)(object)val2 != (Object)null)
					{
						num3 += (float)val2.m_extraPlacementDistance;
					}
					if (!(Vector3.Distance(((Character)__instance).m_eye.position, ((RaycastHit)(ref val)).point) >= num3))
					{
						point = ((RaycastHit)(ref val)).point;
						normal = ((RaycastHit)(ref val)).normal;
						piece = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Piece>();
						heightmap = null;
						waterSurface = null;
						aim = num2;
						aimAt = deck;
						__result = true;
					}
				}
			}
		}

		[HarmonyPatch(typeof(Player), "UpdatePlacementGhost")]
		private static class TurnWithDeck
		{
			private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
			{
				MethodInfo euler = AccessTools.Method(typeof(Quaternion), "Euler", new Type[3]
				{
					typeof(float),
					typeof(float),
					typeof(float)
				}, (Type[])null);
				MethodInfo turn = AccessTools.Method(typeof(Flatbed), "GhostTurn", (Type[])null, (Type[])null);
				foreach (CodeInstruction instruction in instructions)
				{
					if (CodeInstructionExtensions.Calls(instruction, euler))
					{
						instruction.operand = turn;
					}
					yield return instruction;
				}
			}

			private static void Prefix(Player __instance)
			{
				GameObject placementGhost = __instance.m_placementGhost;
				Piece val = (((Object)(object)placementGhost != (Object)null) ? placementGhost.GetComponent<Piece>() : null);
				bool flag = (Object)(object)val != (Object)null && aim != 0L && ((Settings.DeckSmelters && IsSmelter(placementGhost)) || (Settings.DeckFires && IsFire(placementGhost)));
				if (flag && val.m_notOnWood)
				{
					val.m_notOnWood = false;
					onWood = val;
				}
				else if (!flag && (Object)(object)onWood != (Object)null && (Object)(object)onWood == (Object)(object)val)
				{
					val.m_notOnWood = true;
					onWood = null;
				}
			}

			private static void Postfix(Player __instance)
			{
				//IL_0047: Unknown result type (might be due to invalid IL or missing references)
				refusal = null;
				GameObject placementGhost = __instance.m_placementGhost;
				if (aim != 0L && !((Object)(object)aimAt == (Object)null) && !((Object)(object)placementGhost == (Object)null) && placementGhost.activeSelf)
				{
					refusal = Refusal(placementGhost);
					if (refusal != null)
					{
						__instance.m_placementStatus = (PlacementStatus)1;
						__instance.SetPlacementGhostValid(false);
					}
				}
			}
		}

		private enum Fit
		{
			Inside,
			Past,
			TooHigh
		}

		[HarmonyPatch(typeof(Player), "TryPlacePiece")]
		private static class SayWhy
		{
			private static void Postfix(Player __instance, bool __result)
			{
				if (!__result && refusal != null && aim != 0L)
				{
					((Character)__instance).Message((MessageType)2, refusal, 0, (Sprite)null, false);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "PlacePiece")]
		private static class Placed
		{
			private static void Prefix(Player __instance, Vector3 pos)
			{
				//IL_003b: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0041: Unknown result type (might be due to invalid IL or missing references)
				//IL_0042: Unknown result type (might be due to invalid IL or missing references)
				//IL_0060: Unknown result type (might be due to invalid IL or missing references)
				//IL_007e: Unknown result type (might be due to invalid IL or missing references)
				//IL_008b: Unknown result type (might be due to invalid IL or missing references)
				placing = 0L;
				placingAt = null;
				if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && aim != 0L && !((Object)(object)aimAt == (Object)null) && refusal == null)
				{
					Vector3 val = aimAt.InverseTransformPoint(pos);
					if (!(Mathf.Abs(val.x) > 2f + Settings.DeckReachLeftRight + 0.01f) && !(Mathf.Abs(val.z) > 3f + Settings.DeckReachFrontBack + 0.01f) && !(val.y < 0.5f) && !(val.y > 1.5f + Settings.DeckHeight + 0.5f))
					{
						placing = aim;
						placingAt = aimAt;
					}
				}
			}

			private static void Finalizer()
			{
				placing = 0L;
				placingAt = null;
			}
		}

		[HarmonyPatch(typeof(ZNetView), "Awake")]
		private static class Arrived
		{
			private static void Postfix(ZNetView __instance)
			{
				//IL_0067: Unknown result type (might be due to invalid IL or missing references)
				//IL_006c: Unknown result type (might be due to invalid IL or missing references)
				//IL_007d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0082: Unknown result type (might be due to invalid IL or missing references)
				//IL_008d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0092: Unknown result type (might be due to invalid IL or missing references)
				ZDO zdo = __instance.m_zdo;
				if (zdo == null)
				{
					return;
				}
				try
				{
					if (Flatbed.placing != 0L)
					{
						long placing = Flatbed.placing;
						Transform placingAt = Flatbed.placingAt;
						Flatbed.placing = 0L;
						Flatbed.placingAt = null;
						if ((Object)(object)placingAt != (Object)null && zdo.IsOwner() && (Object)(object)((Component)__instance).GetComponent<Piece>() != (Object)null)
						{
							zdo.Set("bf_deck", placing);
							zdo.Set("bf_deck_pos", placingAt.InverseTransformPoint(((Component)__instance).transform.position));
							zdo.Set("bf_deck_rot", Quaternion.Inverse(placingAt.rotation) * ((Component)__instance).transform.rotation);
						}
					}
					if (zdo.GetLong(OnHash, 0L) != 0L)
					{
						Attach(__instance);
					}
				}
				catch (Exception arg)
				{
					if (!failed)
					{
						failed = true;
						RailPlugin.Log.LogWarning((object)$"rail flatbed: a piece could not be put on its deck: {arg}");
					}
				}
			}
		}

		[HarmonyPatch(typeof(Player), "FindHoverObject")]
		private static class UseWhatRides
		{
			private static void Postfix(Player __instance, ref GameObject hover)
			{
				//IL_0027: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)hover == (Object)null || (Object)(object)hover.GetComponent<FlatbedDeck>() == (Object)null)
				{
					return;
				}
				RaycastHit[] raycastHoverHits = __instance.m_raycastHoverHits;
				for (int i = 0; i < raycastHoverHits.Length; i++)
				{
					RaycastHit val = raycastHoverHits[i];
					Collider collider = ((RaycastHit)(ref val)).collider;
					if ((Object)(object)collider != (Object)null && (Object)(object)collider.attachedRigidbody != (Object)null && (Object)(object)((Component)collider.attachedRigidbody).gameObject == (Object)(object)hover)
					{
						hover = ((Component)collider).gameObject;
						break;
					}
				}
			}
		}

		[HarmonyPatch(typeof(Player), "RemovePiece")]
		private static class Removing
		{
			private static void Prefix()
			{
				removing = true;
			}

			private static void Finalizer()
			{
				removing = false;
			}
		}

		[HarmonyPatch(typeof(Player), "CheckCanRemovePiece")]
		private static class KeepLoaded
		{
			private static void Postfix(Player __instance, Piece piece, ref bool __result)
			{
				if (removing && __result && !((Object)(object)piece == (Object)null))
				{
					RailFlatbed component = ((Component)piece).GetComponent<RailFlatbed>();
					if ((Object)(object)component != (Object)null && Count(component.DeckKey) > 0)
					{
						((Character)__instance).Message((MessageType)2, "Remove what is built on it first", 0, (Sprite)null, false);
						__result = false;
					}
				}
			}
		}

		[HarmonyPatch(typeof(WearNTear), "RPC_Damage")]
		private static class NoHits
		{
			private static bool Prefix(WearNTear __instance)
			{
				return !Safe(__instance);
			}
		}

		[HarmonyPatch(typeof(WearNTear), "UpdateWear")]
		private static class Wearing
		{
			private static void Prefix(WearNTear __instance)
			{
				wearing = __instance;
			}

			private static void Finalizer()
			{
				wearing = null;
			}
		}

		[HarmonyPatch(typeof(WearNTear), "ApplyDamage")]
		private static class NoWear
		{
			private static bool Prefix(WearNTear __instance, HitData hitData, ref bool __result)
			{
				if (hitData != null || !Safe(__instance) || ((Object)(object)wearing == (Object)(object)__instance && !__instance.HaveSupport()))
				{
					return true;
				}
				__result = false;
				return false;
			}
		}

		[HarmonyPatch(typeof(WearNTear), "UpdateSupport")]
		private static class OnDeck
		{
			private static readonly Collider[] found = (Collider[])(object)new Collider[128];

			private static bool Prefix(WearNTear __instance)
			{
				Transform parent = ((Component)__instance).transform.parent;
				FlatbedDeck flatbedDeck = (((Object)(object)parent != (Object)null) ? ((Component)parent).GetComponent<FlatbedDeck>() : null);
				if ((Object)(object)flatbedDeck == (Object)null)
				{
					return true;
				}
				if ((Object)(object)__instance.m_nview == (Object)null || !__instance.m_nview.IsValid() || !__instance.m_nview.IsOwner())
				{
					return false;
				}
				float maxSupport = default(float);
				float num = default(float);
				float horizontalLoss = default(float);
				float verticalLoss = default(float);
				__instance.GetMaterialProperties(ref maxSupport, ref num, ref horizontalLoss, ref verticalLoss);
				Set(__instance, Support(__instance, flatbedDeck, maxSupport, horizontalLoss, verticalLoss));
				return false;
			}

			private static void Set(WearNTear wear, float support)
			{
				if (!wear.m_support.Equals(support))
				{
					wear.m_support = support;
					wear.m_nview.GetZDO().Set(ZDOVars.s_support, support);
				}
			}

			private static float Support(WearNTear wear, FlatbedDeck deck, float maxSupport, float horizontalLoss, float verticalLoss)
			{
				//IL_0033: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
				//IL_0102: Unknown result type (might be due to invalid IL or missing references)
				//IL_0107: Unknown result type (might be due to invalid IL or missing references)
				//IL_010b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0110: Unknown result type (might be due to invalid IL or missing references)
				//IL_0114: Unknown result type (might be due to invalid IL or missing references)
				//IL_0119: Unknown result type (might be due to invalid IL or missing references)
				//IL_0081: Unknown result type (might be due to invalid IL or missing references)
				//IL_0086: Unknown result type (might be due to invalid IL or missing references)
				//IL_008f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0094: Unknown result type (might be due to invalid IL or missing references)
				//IL_009f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
				//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00de: Unknown result type (might be due to invalid IL or missing references)
				//IL_011b: Unknown result type (might be due to invalid IL or missing references)
				//IL_011d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0127: Unknown result type (might be due to invalid IL or missing references)
				//IL_012c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0136: Unknown result type (might be due to invalid IL or missing references)
				//IL_013b: Unknown result type (might be due to invalid IL or missing references)
				//IL_013d: Unknown result type (might be due to invalid IL or missing references)
				//IL_013f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0146: Unknown result type (might be due to invalid IL or missing references)
				//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
				//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
				//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
				//IL_021f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0224: Unknown result type (might be due to invalid IL or missing references)
				//IL_0229: Unknown result type (might be due to invalid IL or missing references)
				//IL_022b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0232: Unknown result type (might be due to invalid IL or missing references)
				//IL_0240: Unknown result type (might be due to invalid IL or missing references)
				//IL_0242: 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_0248: Unknown result type (might be due to invalid IL or missing references)
				//IL_024c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0251: Unknown result type (might be due to invalid IL or missing references)
				//IL_0253: Unknown result type (might be due to invalid IL or missing references)
				//IL_0266: Unknown result type (might be due to invalid IL or missing references)
				ZDO val = Find(deck.Key);
				if (val == null || (Object)(object)ZNetScene.instance.FindInstance(val) == (Object)null)
				{
					return maxSupport;
				}
				if (wear.m_colliders == null)
				{
					wear.SetupColliders();
				}
				Vector3 cOM = wear.GetCOM();
				float num = 0f;
				Collider[] colliders = wear.m_colliders;
				Vector3 val6 = default(Vector3);
				foreach (Collider val2 in colliders)
				{
					if ((Object)(object)val2 == (Object)null || val2.isTrigger)
					{
						continue;
					}
					BoxCollider val3 = (BoxCollider)(object)((val2 is BoxCollider) ? val2 : null);
					Quaternion val4;
					Vector3 val5;
					if (val3 != null)
					{
						Vector3 lossyScale = ((Component)val3).transform.lossyScale;
						val4 = ((Component)val3).transform.rotation;
						val5 = ((Component)val3).transform.TransformPoint(val3.center);
						((Vector3)(ref val6))..ctor(lossyScale.x * val3.size.x, lossyScale.y * val3.size.y, lossyScale.z * val3.size.z);
					}
					else
					{
						val4 = Quaternion.identity;
						Bounds bounds = val2.bounds;
						val5 = ((Bounds)(ref bounds)).center;
						bounds = val2.bounds;
						val6 = ((Bounds)(ref bounds)).size;
					}
					val6 = (val6 + Vector3.one * 0.3f) * 0.5f;
					int num2 = Physics.OverlapBoxNonAlloc(val5, val6, found, val4, WearNTear.s_rayMask);
					for (int j = 0; j < num2; j++)
					{
						Collider val7 = found[j];
						if (val7.isTrigger || Array.IndexOf(wear.m_colliders, val7) >= 0 || DeckOf(val7, out var _) != deck.Key)
						{
							continue;
						}
						WearNTear componentInParent = ((Component)val7).GetComponentInParent<WearNTear>();
						if ((Object)(object)componentInParent == (Object)null || (Object)(object)componentInParent == (Object)(object)wear)
						{
							continue;
						}
						if ((Object)(object)((Component)componentInParent).GetComponent<RailFlatbed>() != (Object)null)
						{
							return maxSupport;
						}
						if (!componentInParent.m_supports)
						{
							continue;
						}
						float num3 = Mathf.Min(Vector3.Distance(cOM, componentInParent.GetCOM()), Vector3.Distance(cOM, ((Component)componentInParent).transform.position)) + 0.1f;
						float support = componentInParent.GetSupport();
						num = Mathf.Max(num, support - horizontalLoss * num3 * support);
						Vector3 val8 = WearNTear.FindSupportPoint(cOM, componentInParent, val7);
						if (val8.y < cOM.y + 0.05f)
						{
							Vector3 val9 = val8 - cOM;
							Vector3 normalized = ((Vector3)(ref val9)).normalized;
							if (normalized.y < 0f)
							{
								float num4 = Mathf.Acos(1f - Mathf.Abs(normalized.y)) / (MathF.PI / 2f);
								float num5 = Mathf.Lerp(horizontalLoss, verticalLoss, num4);
								num = Mathf.Max(num, support - num5 * num3 * support);
							}
						}
					}
				}
				return Mathf.Min(num, maxSupport);
			}
		}

		public const string Prefab = "bf_wagon_flat";

		public static readonly int Hash = StringExtensionMethods.GetStableHashCode("bf_wagon_flat");

		public const string Key = "bf_deck_key";

		public const string On = "bf_deck";

		public const string Pos = "bf_deck_pos";

		public const string Rot = "bf_deck_rot";

		private static readonly int KeyHash = StringExtensionMethods.GetStableHashCode("bf_deck_key");

		private static readonly int OnHash = StringExtensionMethods.GetStableHashCode("bf_deck");

		private static readonly int PosHash = StringExtensionMethods.GetStableHashCode("bf_deck_pos");

		private static readonly int RotHash = StringExtensionMethods.GetStableHashCode("bf_deck_rot");

		public const float HalfWidth = 2f;

		public const float HalfLength = 3f;

		public const float Floor = 1.5f;

		public const float Cover = 0.02f;

		private const float Top = 0.5f;

		private const float Sunk = 0.35f;

		private const float SyncEvery = 8f;

		private static readonly Dictionary<long, HashSet<ZDOID>> riders = new Dictionary<long, HashSet<ZDOID>>();

		private static readonly Dictionary<ZDOID, long> deckOf = new Dictionary<ZDOID, long>();

		private static readonly Dictionary<long, ZDO> wagons = new Dictionary<long, ZDO>();

		private static readonly Dictionary<long, (Vector3 position, Quaternion rotation, bool settled)> synced = new Dictionary<long, (Vector3, Quaternion, bool)>();

		private static readonly Dictionary<Material, Material> still = new Dictionary<Material, Material>();

		private static readonly List<ZDOID> gone = new List<ZDOID>();

		private static ZDOMan seeded;

		private static long aim;

		private static Transform aimAt;

		private static string refusal;

		private static long placing;

		private static Transform placingAt;

		private static bool removing;

		private static bool failed;

		private static Piece onWood;

		private static WearNTear wearing;

		public static void Reset()
		{
			riders.Clear();
			deckOf.Clear();
			wagons.Clear();
			synced.Clear();
			seeded = null;
			aim = 0L;
			aimAt = null;
			refusal = null;
			placing = 0L;
			placingAt = null;
			FlatbedDeck.Clear();
		}

		public static void Unload()
		{
			FlatbedDeck.Release();
			Reset();
		}

		public static void Restore()
		{
			if ((Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			foreach (ZNetView item in ZNetScene.instance.m_instances.Values.ToList())
			{
				if ((Object)(object)item != (Object)null && item.GetZDO() != null && item.GetZDO().GetLong(OnHash, 0L) != 0L)
				{
					Attach(item);
				}
			}
		}

		public static void Update()
		{
			ZDOMan instance = ZDOMan.instance;
			if (instance == null || seeded == instance)
			{
				return;
			}
			riders.Clear();
			deckOf.Clear();
			foreach (ZDO value in instance.m_objectsByID.Values)
			{
				Index(value);
			}
			seeded = instance;
			if (deckOf.Count > 0)
			{
				RailPlugin.Log.LogInfo((object)$"rail flatbeds: {deckOf.Count} pieces ride on {riders.Count} of them");
			}
		}

		private static void Index(ZDO zdo)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			long num = zdo.GetLong(OnHash, 0L);
			if (deckOf.TryGetValue(zdo.m_uid, out var value))
			{
				if (value == num)
				{
					return;
				}
				Forget(zdo.m_uid);
			}
			if (num != 0L)
			{
				deckOf[zdo.m_uid] = num;
				if (!riders.TryGetValue(num, out var value2))
				{
					value2 = (riders[num] = new HashSet<ZDOID>());
				}
				value2.Add(zdo.m_uid);
			}
		}

		private static void Forget(ZDOID id)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (deckOf.TryGetValue(id, out var value))
			{
				deckOf.Remove(id);
				if (riders.TryGetValue(value, out var value2) && value2.Remove(id) && value2.Count == 0)
				{
					riders.Remove(value);
				}
			}
		}

		public static int Count(long key)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			if (key == 0L || !riders.TryGetValue(key, out var value))
			{
				return 0;
			}
			gone.Clear();
			foreach (ZDOID item in value)
			{
				ZDO zDO = ZDOMan.instance.GetZDO(item);
				if (zDO == null || zDO.GetLong(OnHash, 0L) != key)
				{
					gone.Add(item);
				}
			}
			foreach (ZDOID item2 in gone)
			{
				Forget(item2);
			}
			if (!riders.TryGetValue(key, out value))
			{
				return 0;
			}
			return value.Count;
		}

		public static long KeyOf(ZDO flatbed)
		{
			if (flatbed == null)
			{
				return 0L;
			}
			return flatbed.GetLong(KeyHash, 0L);
		}

		public static ZDO Find(long key)
		{
			if (key == 0L)
			{
				return null;
			}
			if (wagons.TryGetValue(key, out var value) && value.IsValid() && value.GetLong(KeyHash, 0L) == key)
			{
				return value;
			}
			wagons.Remove(key);
			foreach (ZDO wagon in Scan.Wagons)
			{
				if (wagon.GetPrefab() == Hash && wagon.GetLong(KeyHash, 0L) == key)
				{
					wagons[key] = wagon;
					return wagon;
				}
			}
			return null;
		}

		public static void GiveKey(ZDO flatbed)
		{
			if (flatbed != null && flatbed.IsOwner() && flatbed.GetLong(KeyHash, 0L) == 0L)
			{
				long num = BitConverter.ToInt64(Guid.NewGuid().ToByteArray(), 0);
				flatbed.Set("bf_deck_key", (num == 0L) ? 1 : num);
			}
		}

		public static void ServerTick()
		{
			foreach (ZDO wagon in Scan.Wagons)
			{
				if (wagon.GetPrefab() == Hash)
				{
					GiveKey(wagon);
				}
			}
		}

		private static bool Moving(ZDOID wagon)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			ZDO val = Train.Pulling(wagon);
			if (val != null)
			{
				return Mathf.Abs(val.GetFloat("bf_speed", 0f)) > 0.01f;
			}
			return false;
		}

		public static void Sync(ZDO flatbed, Vector3 position, Quaternion rotation, bool standing)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01de: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Unknown result type (might be due to invalid IL or missing references)
			long num = flatbed.GetLong(KeyHash, 0L);
			if (num == 0L || !riders.TryGetValue(num, out var value) || value.Count == 0)
			{
				return;
			}
			Vector3 val;
			if (synced.TryGetValue(num, out (Vector3, Quaternion, bool) value2))
			{
				val = value2.Item1 - position;
				if (!(((Vector3)(ref val)).sqrMagnitude > 64f) && (!standing || value2.Item3))
				{
					if (!standing && value2.Item3)
					{
						synced[num] = (value2.Item1, value2.Item2, false);
					}
					return;
				}
			}
			long sessionID = ZDOMan.GetSessionID();
			bool flag = true;
			gone.Clear();
			foreach (ZDOID item in value)
			{
				ZDO zDO = ZDOMan.instance.GetZDO(item);
				if (zDO == null || zDO.GetLong(OnHash, 0L) != num)
				{
					gone.Add(item);
					continue;
				}
				Vector3 val2 = position + rotation * zDO.GetVec3(PosHash, Vector3.zero);
				Quaternion val3 = rotation * zDO.GetQuaternion(RotHash, Quaternion.identity);
				val = zDO.GetPosition() - val2;
				if (((Vector3)(ref val)).sqrMagnitude < 0.0001f && Quaternion.Angle(zDO.GetRotation(), val3) < 0.1f)
				{
					continue;
				}
				if (!zDO.IsOwner())
				{
					if (zDO.GetInt(ZDOVars.s_inUse, 0) != 0)
					{
						flag = false;
						continue;
					}
					zDO.SetOwner(sessionID);
				}
				zDO.SetPosition(val2);
				zDO.SetRotation(val3);
			}
			foreach (ZDOID item2 in gone)
			{
				Forget(item2);
			}
			synced[num] = (position, rotation, standing && flag);
		}

		public static void Follow()
		{
			FlatbedDeck.FollowAll();
		}

		private static void Attach(ZNetView view)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0092: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = view.GetZDO();
			long num = zDO.GetLong(OnHash, 0L);
			if (num != 0L)
			{
				Index(zDO);
				Vector3 vec = zDO.GetVec3(PosHash, Vector3.zero);
				Quaternion quaternion = zDO.GetQuaternion(RotHash, Quaternion.identity);
				FlatbedDeck flatbedDeck = FlatbedDeck.Get(num);
				if (!flatbedDeck.Place() && ((Component)flatbedDeck).transform.childCount == 0)
				{
					Quaternion val = ((Component)view).transform.rotation * Quaternion.Inverse(quaternion);
					((Component)flatbedDeck).transform.SetPositionAndRotation(((Component)view).transform.position - val * vec, val);
				}
				((Component)view).transform.SetParent(((Component)flatbedDeck).transform, false);
				((Component)view).transform.localPosition = vec;
				((Component)view).transform.localRotation = quaternion;
				WearNTear component = ((Component)view).GetComponent<WearNTear>();
				if ((Object)(object)component != (Object)null)
				{
					component.m_staticPosition = false;
				}
				flatbedDeck.Burns(view);
				if (!ZNet.instance.IsDedicated())
				{
					Still(view);
				}
			}
		}

		private static void Still(ZNetView view)
		{
			Renderer[] componentsInChildren = ((Component)view).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (!(val is MeshRenderer) && !(val is SkinnedMeshRenderer))
				{
					continue;
				}
				Material[] sharedMaterials = val.sharedMaterials;
				bool flag = false;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					Material val2 = sharedMaterials[j];
					if (!((Object)(object)val2 == (Object)null) && !((Object)val2).name.EndsWith(" moving") && (val2.HasProperty("_RippleDistance") || val2.HasProperty("_ValueNoise")))
					{
						if (!still.TryGetValue(val2, out var value) || (Object)(object)value == (Object)null)
						{
							value = (still[val2] = Pieces.Moveable(val2));
						}
						sharedMaterials[j] = value;
						flag = true;
					}
				}
				if (flag)
				{
					val.sharedMaterials = sharedMaterials;
				}
			}
		}

		private static long DeckOf(Collider collider, out Transform deck)
		{
			deck = null;
			Rigidbody val = (((Object)(object)collider != (Object)null) ? collider.attachedRigidbody : null);
			if ((Object)(object)val == (Object)null)
			{
				return 0L;
			}
			RailFlatbed component = ((Component)val).GetComponent<RailFlatbed>();
			if ((Object)(object)component != (Object)null)
			{
				deck = ((Component)component).transform;
				return component.DeckKey;
			}
			FlatbedDeck component2 = ((Component)val).GetComponent<FlatbedDeck>();
			if ((Object)(object)component2 != (Object)null)
			{
				deck = ((Component)component2).transform;
				return component2.Key;
			}
			return 0L;
		}

		public static Quaternion GhostTurn(float x, float y, float z)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			Quaternion val = Quaternion.Euler(x, y, z);
			if (!((Object)(object)aimAt != (Object)null))
			{
				return val;
			}
			return aimAt.rotation * val;
		}

		private static string Refusal(GameObject ghost)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ghost.GetComponent<RailPiece>() != (Object)null)
			{
				return "Rail pieces do not go on a flatbed";
			}
			if ((Object)(object)ghost.GetComponentInChildren<TeleportWorld>(true) != (Object)null)
			{
				return "Use the portal wagon";
			}
			if ((Object)(object)ghost.GetComponentInChildren<Bed>(true) != (Object)null)
			{
				return "No beds on a train";
			}
			if ((Object)(object)ghost.GetComponent<Rigidbody>() != (Object)null || (Object)(object)ghost.GetComponent<ZSyncTransform>() != (Object)null)
			{
				return "It does not ride on a train";
			}
			ZDO val = Find(aim);
			if (val == null)
			{
				return "The flatbed is not ready, try again";
			}
			if (Moving(val.m_uid))
			{
				return "The train is moving";
			}
			if (Count(aim) >= Settings.MaxDeckPieces)
			{
				return $"A flatbed carries at most {Settings.MaxDeckPieces} pieces";
			}
			if (!Settings.DeckSmelters && IsSmelter(ghost))
			{
				return "Smelters on a flatbed are off, the setting DeckSmelters";
			}
			if (!Settings.DeckFires && IsFire(ghost))
			{
				return "Fires on a flatbed are off, the setting DeckFires";
			}
			return InBox(ghost, aimAt) switch
			{
				Fit.Inside => null, 
				Fit.TooHigh => $"It reaches higher than {Settings.DeckHeight:0.##} m over the deck, the setting DeckHeight", 
				_ => "It reaches past the deck", 
			};
		}

		private static bool IsSmelter(GameObject ghost)
		{
			if (!((Object)(object)ghost.GetComponentInChildren<Smelter>(true) != (Object)null))
			{
				return (Object)(object)ghost.GetComponentInChildren<Incinerator>(true) != (Object)null;
			}
			return true;
		}

		private static bool IsFire(GameObject ghost)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ghost.GetComponentInChildren<Fireplace>(true) == (Object)null)
			{
				return false;
			}
			EffectArea[] componentsInChildren = ghost.GetComponentsInChildren<EffectArea>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				if ((componentsInChildren[i].m_type & 9) != 0)
				{
					return true;
				}
			}
			return false;
		}

		private static Fit InBox(GameObject ghost, Transform deck)
		{
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: 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)
			Fit result = Fit.Inside;
			bool flag = false;
			Collider[] componentsInChildren = ghost.GetComponentsInChildren<Collider>();
			Bounds bounds = default(Bounds);
			Vector3 val5 = default(Vector3);
			foreach (Collider val in componentsInChildren)
			{
				if (val.isTrigger || !val.enabled)
				{
					continue;
				}
				flag = true;
				Transform val2 = ((Component)val).transform;
				BoxCollider val3 = (BoxCollider)(object)((val is BoxCollider) ? val : null);
				if (val3 != null)
				{
					((Bounds)(ref bounds))..ctor(val3.center, val3.size);
				}
				else
				{
					MeshCollider val4 = (MeshCollider)(object)((val is MeshCollider) ? val : null);
					if (val4 != null && (Object)(object)val4.sharedMesh != (Object)null)
					{
						bounds = val4.sharedMesh.bounds;
					}
					else
					{
						bounds = val.bounds;
						val2 = null;
					}
				}
				Vector3 min = ((Bounds)(ref bounds)).min;
				Vector3 max = ((Bounds)(ref bounds)).max;
				for (int j = 0; j < 8; j++)
				{
					((Vector3)(ref val5))..ctor(((j & 1) == 0) ? min.x : max.x, ((j & 2) == 0) ? min.y : max.y, ((j & 4) == 0) ? min.z : max.z);
					switch (Inside(deck.InverseTransformPoint(((Object)(object)val2 != (Object)null) ? val2.TransformPoint(val5) : val5)))
					{
					case Fit.Past:
						return Fit.Past;
					case Fit.TooHigh:
						result = Fit.TooHigh;
						break;
					}
				}
			}
			if (!flag)
			{
				return Inside(deck.InverseTransformPoint(ghost.transform.position));
			}
			return result;
		}

		private static Fit Inside(Vector3 local)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (Mathf.Abs(local.x) > 2f + Settings.DeckReachLeftRight || Mathf.Abs(local.z) > 3f + Settings.DeckReachFrontBack || local.y < 1.15f)
			{
				return Fit.Past;
			}
			if (!(local.y > 1.5f + Settings.DeckHeight + 0.5f))
			{
				return Fit.Inside;
			}
			return Fit.TooHigh;
		}

		private static bool Safe(WearNTear wear)
		{
			if (Settings.DeckPiecesIndestructible && (Object)(object)wear.m_nview != (Object)null && wear.m_nview.IsValid())
			{
				return wear.m_nview.GetZDO().GetLong(OnHash, 0L) != 0;
			}
			return false;
		}
	}
	public class RailFlatbed : MonoBehaviour, Hoverable, Interactable
	{
		private ZNetView m_nview;

		public long DeckKey
		{
			get
			{
				if (!((Object)(object)m_nview != (Object)null) || !m_nview.IsValid())
				{
					return 0L;
				}
				return Flatbed.KeyOf(m_nview.GetZDO());
			}
		}

		private void Start()
		{
			m_nview = ((Component)this).GetComponent<ZNetView>();
			((MonoBehaviour)this).InvokeRepeating("GiveKey", 0f, 1f);
		}

		private void GiveKey()
		{
			if ((Object)(object)m_nview != (Object)null && m_nview.IsValid())
			{
				Flatbed.GiveKey(m_nview.GetZDO());
			}
		}

		public string GetHoverText()
		{
			return Localization.instance.Localize($"Flatbed wagon\n{Flatbed.Count(DeckKey)} of {Settings.MaxDeckPieces} pieces built on it\n[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>] Couple or uncouple");
		}

		public string GetHoverName()
		{
			return "Flatbed wagon";
		}

		public float GetHoverOffset()
		{
			return 0f;
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			if (hold || !alt)
			{
				return false;
			}
			return Coupling.Toggle(((Component)this).GetComponent<ZNetView>(), user);
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			return false;
		}
	}
	public class FlatbedDeck : MonoBehaviour
	{
		private static readonly Dictionary<long, FlatbedDeck> all = new Dictionary<long, FlatbedDeck>();

		private static readonly List<long> empty = new List<long>();

		public long Key;

		private readonly List<EffectArea> burning = new List<EffectArea>();

		private Vector3 burntAt;

		private Quaternion burntTurn;

		public void Burns(ZNetView view)
		{
			//IL_0011: 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)
			EffectArea[] componentsInChildren = ((Component)view).GetComponentsInChildren<EffectArea>(true);
			foreach (EffectArea val in componentsInChildren)
			{
				if ((val.m_type & 8) != 0 && !burning.Contains(val))
				{
					burning.Add(val);
				}
			}
		}

		private void Rekindle()
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_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_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			if (burning.Count == 0 || (((Component)this).transform.position == burntAt && ((Component)this).transform.rotation == burntTurn))
			{
				return;
			}
			burntAt = ((Component)this).transform.position;
			burntTurn = ((Component)this).transform.rotation;
			for (int num = burning.Count - 1; num >= 0; num--)
			{
				EffectArea val = burning[num];
				if ((Object)(object)val == (Object)null)
				{
					burning.RemoveAt(num);
				}
				else
				{
					int num2 = EffectArea.s_BurningAreas.IndexOf(val.burnCloseToArea);
					Collider component = ((Component)val).GetComponent<Collider>();
					if (num2 >= 0 && !((Object)(object)component == (Object)null))
					{
						Bounds key = Box(component);
						((Bounds)(ref key)).Expand(new Vector3(0.25f, 0.25f, 0.25f));
						val.burnCloseToArea = new KeyValuePair<Bounds, EffectArea>(key, val);
						EffectArea.s_BurningAreas[num2] = val.burnCloseToArea;
					}
				}
			}
		}

		private static Bounds Box(Collider shape)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: 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_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: 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_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_0169: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)shape).transform;
			Vector3 lossyScale = transform.lossyScale;
			SphereCollider val = (SphereCollider)(object)((shape is SphereCollider) ? shape : null);
			if (val != null)
			{
				float num = val.radius * Mathf.Max(new float[3]
				{
					Mathf.Abs(lossyScale.x),
					Mathf.Abs(lossyScale.y),
					Mathf.Abs(lossyScale.z)
				});
				return new Bounds(transform.TransformPoint(val.center), Vector3.one * num * 2f);
			}
			BoxCollider val2 = (BoxCollider)(object)((shape is BoxCollider) ? shape : null);
			Vector3 center;
			Vector3 val3;
			if (val2 != null)
			{
				center = val2.center;
				val3 = val2.size * 0.5f;
			}
			else
			{
				CapsuleCollider val4 = (CapsuleCollider)(object)((shape is CapsuleCollider) ? shape : null);
				if (val4 == null)
				{
					return shape.bounds;
				}
				center = val4.center;
				val3 = Vector3.one * val4.radius;
				((Vector3)(ref val3))[val4.direction] = Mathf.Max(val4.height * 0.5f, val4.radius);
			}
			Bounds result = default(Bounds);
			((Bounds)(ref result))..ctor(transform.TransformPoint(center), Vector3.zero);
			for (int i = 0; i < 8; i++)
			{
				((Bounds)(ref result)).Encapsulate(transform.TransformPoint(center + new Vector3(((i & 1) == 0) ? (0f - val3.x) : val3.x, ((i & 2) == 0) ? (0f - val3.y) : val3.y, ((i & 4) == 0) ? (0f - val3.z) : val3.z)));
			}
			return result;
		}

		public static FlatbedDeck Get(long key)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (all.TryGetValue(key, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			GameObject val = new GameObject("bf_deck");
			value = val.AddComponent<FlatbedDeck>();
			value.Key = key;
			val.AddComponent<Rigidbody>().isKinematic = true;
			all[key] = value;
			return value;
		}

		public bool Place()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			ZDO val = Flatbed.Find(Key);
			if (val == null)
			{
				return false;
			}
			ZNetView val2 = (((Object)(object)ZNetScene.instance != (Object)null) ? ZNetScene.instance.FindInstance(val) : null);
			if ((Object)(object)val2 != (Object)null)
			{
				((Component)this).transform.SetPositionAndRotation(((Component)val2).transform.position, ((Component)val2).transform.rotation);
			}
			else
			{
				((Component)this).transform.SetPositionAndRotation(val.GetPosition(), val.GetRotation());
			}
			return true;
		}

		public static void FollowAll()
		{
			empty.Clear();
			foreach (KeyValuePair<long, FlatbedDeck> item in all)
			{
				if ((Object)(object)item.Value == (Object)null)
				{
					empty.Add(item.Key);
				}
				else if (((Component)item.Value).transform.childCount == 0)
				{
					Object.Destroy((Object)(object)((Component)item.Value).gameObject);
					empty.Add(item.Key);
				}
				else
				{
					item.Value.Place();
					item.Value.Rekindle();
				}
			}
			foreach (long item2 in empty)
			{
				all.Remove(item2);
			}
		}

		public static void Release()
		{
			foreach (FlatbedDeck value in all.Values)
			{
				if (!((Object)(object)value == (Object)null))
				{
					for (int num = ((Component)value).transform.childCount - 1; num >= 0; num--)
					{
						((Component)value).transform.GetChild(num).SetParent((Transform)null, true);
					}
					Object.Destroy((Object)(object)((Component)value).gameObject);
				}
			}
			all.Clear();
		}

		public static void Clear()
		{
			all.Clear();
		}
	}
	public static class Follow
	{
		private class Copy
		{
			public TrackCursor cursor;

			public uint revision;

			public float receivedAt;
		}

		public static bool Enabled = true;

		private const float Pull = 2f;

		private const float Snap = 6f;

		private const float MaxAge = 0.5f;

		private static readonly Dictionary<ZDOID, Copy> copies = new Dictionary<ZDOID, Copy>();

		public static void Reset()
		{
			copies.Clear();
		}

		public static void Forget(ZDOID loco)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			copies.Remove(loco);
		}

		public static bool Step(ZDO loco, float dt)
		{
			//IL_002d: 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_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0197: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02da: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			if (!Train.Load(loco, out var owner))
			{
				copies.Remove(loco.m_uid);
				return false;
			}
			if (!copies.TryGetValue(loco.m_uid, out var value) || Graph.Find(value.cursor.line.Id) == null)
			{
				value = new Copy
				{
					cursor = owner,
					revision = loco.DataRevision,
					receivedAt = Time.time
				};
				copies[loco.m_uid] = value;
			}
			if (loco.DataRevision != value.revision)
			{
				value.revision = loco.DataRevision;
				value.receivedAt = Time.time;
			}
			float num = loco.GetFloat("bf_speed", 0f);
			IReadOnlyList<LineId> route = Saved.Lines(loco, "bf_route");
			IReadOnlyList<LineId> readOnlyList = Saved.Lines(loco, "bf_trail");
			TrackCursor now = owner;
			float num2 = Mathf.Min(Time.time - value.receivedAt, 0.5f);
			IReadOnlyList<LineId> rear = ((loco.GetBool("bf_moving", false) && loco.GetLong("bf_driver", 0L) == 0L && loco.GetInt("bf_way", 1) < 0) ? route : readOnlyList);
			now.Walk(num * num2, (List<Step> steps, bool backward) => Choose(steps, backward, now, route, rear, owner.line));
			Vector3 val = now.Position - value.cursor.Position;
			if (((Vector3)(ref val)).sqrMagnitude > 36f || Vector3.Dot(now.Forward, value.cursor.Forward) < 0f)
			{
				value.cursor = now;
			}
			else
			{
				float num3 = Vector3.Dot(val, value.cursor.Forward);
				float distance = num * dt + num3 * Mathf.Min(1f, 2f * dt);
				TrackCursor next = value.cursor;
				next.Walk(distance, (List<Step> steps, bool backward) => Choose(steps, backward, next, route, rear, owner.line));
				value.cursor = next;
			}
			List<LineId> list = new List<LineId>(readOnlyList);
			if (value.cursor.line != owner.line)
			{
				if (list.Count > 0 && value.cursor.line.Matches(list[0]))
				{
					list.RemoveAt(0);
				}
				else
				{
					list.Insert(0, owner.line.Id);
				}
			}
			IReadOnlyList<LineId> ahead = (Train.GoesForward(loco) ? route : null);
			LineQueue rest;
			List<Train.Body> list2 = Train.Layout(loco, value.cursor, list, ahead, out rest);
			Train.Draw(list2);
			foreach (Train.Body item in list2.Skip(1))
			{
				ZDO zDO = ZDOMan.instance.GetZDO(item.id);
				if (zDO != null && zDO.IsOwner())
				{
					zDO.SetPosition(item.position);
					zDO.SetRotation(item.rotation);
					Train.Save(zDO, item.cursor);
					Mend.Mark(zDO);
				}
			}
			return true;
		}

		private static Step? Choose(List<Step> steps, bool backward, TrackCursor at, IReadOnlyList<LineId> route, IReadOnlyList<LineId> trail, Line ownerLine)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			if (backward)
			{
				LineQueue trail2 = new LineQueue(trail);
				return Train.FromTrail(steps, ref trail2, at.Forward);
			}
			foreach (Step step in steps)
			{
				if (step.line == ownerLine || route.Any((LineId id) => step.line.Matches(id)))
				{
					return step;
				}
			}
			return TrackCursor.Straightest(steps, at.Forward, 0);
		}
	}
	public readonly struct LineId : IEquatable<LineId>
	{
		public readonly Vector3 a;

		public readonly Vector3 b;

		public LineId(Vector3 a, Vector3 b)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			this.a = a;
			this.b = b;
		}

		public bool Equals(LineId other)
		{
			//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_000a: 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_0020: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = a;
			if (((Vector3)(ref val)).Equals(other.a))
			{
				val = b;
				return ((Vector3)(ref val)).Equals(other.b);
			}
			return false;
		}

		public override bool Equals(object other)
		{
			if (other is LineId other2)
			{
				return Equals(other2);
			}
			return false;
		}

		public override int GetHashCode()
		{
			//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_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			return (((object)a/*cast due to .constrained prefix*/).GetHashCode() * 397) ^ ((object)b/*cast due to .constrained prefix*/).GetHashCode();
		}

		public override string ToString()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			return $"{a}-{b}";
		}
	}
	public class Line
	{
		public readonly ZDOID piece;

		public readonly Vector3[] points;

		public readonly float[] along;

		public readonly LineId Id;

		internal List<Step> nextAtA = new List<Step>();

		internal List<Step> nextAtB = new List<Step>();

		public Vector3 A => points[0];

		public Vector3 B => points[points.Length - 1];

		public float Length => along[along.Length - 1];

		public Line(ZDOID piece, Vector3[] points)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			this.piece = piece;
			this.points = points;
			along = new float[points.Length];
			for (int i = 1; i < points.Length; i++)
			{
				along[i] = along[i - 1] + Vector3.Distance(points[i - 1], points[i]);
			}
			Id = new LineId(A, B);
		}

		public void At(float s, out Vector3 position, out Vector3 forward)
		{
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			s = Mathf.Clamp(s, 0f, Length);
			int i;
			for (i = 1; i < points.Length - 1 && along[i] < s; i++)
			{
			}
			float num = Mathf.Max(along[i] - along[i - 1], 1E-06f);
			position = Vector3.Lerp(points[i - 1], points[i], (s - along[i - 1]) / num);
			Vector3 val = points[i] - points[i - 1];
			forward = ((Vector3)(ref val)).normalized;
		}

		public Vector3 Leaving(bool atB)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			int num = points.Length;
			Vector3 val;
			if (!atB)
			{
				val = points[0] - points[1];
				return ((Vector3)(ref val)).normalized;
			}
			val = points[num - 1] - points[num - 2];
			return ((Vector3)(ref val)).normalized;
		}

		public bool Matches(LineId id)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (!Id.Equals(id))
			{
				Vector3 val = A - id.a;
				if (((Vector3)(ref val)).sqrMagnitude < 0.09f)
				{
					val = B - id.b;
					return ((Vector3)(ref val)).sqrMagnitude < 0.09f;
				}
				return false;
			}
			return true;
		}
	}
	public struct Step
	{
		public Line line;

		public bool fromA;
	}
	public static class Scan
	{
		private enum Kind
		{
			Track,
			Locomotive,
			Wagon,
			Station
		}

		[HarmonyPatch(typeof(ZDOMan), "AddIfPortal")]
		private static class Added
		{
			private static void Postfix(ZDOMan __instance, ZDO zdo, int prefabHash)
			{
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				if (__instance == seeded && KindOf(prefabHash, out var kind) && (!known.TryGetValue(zdo.m_uid, out (ZDO, Kind) value) || value.Item1 != zdo))
				{
					known[zdo.m_uid] = (zdo, kind);
					dirty = true;
				}
			}
		}

		[HarmonyPatch(typeof(ZDOMan), "HandleDestroyedZDO")]
		private static class Destroyed
		{
			private static void Prefix(ZDOMan __instance, ZDOID uid)
			{
				//IL_000d: Unknown result type (might be due to invalid IL or missing references)
				if (__instance == seeded && known.Remove(uid))
				{
					dirty = true;
				}
			}
		}

		[HarmonyPatch(typeof(ZDOMan), "Load")]
		private static class Loaded
		{
			private static void Postfix()
			{
				seeded = null;
			}
		}

		[HarmonyPatch(typeof(ZDOMan), "LoadChunks")]
		private static class LoadedChunks
		{
			private static void Postfix()
			{
				seeded = null;
			}
		}

		private static readonly Dictionary<ZDOID, (ZDO zdo, Kind kind)> known = new Dictionary<ZDOID, (ZDO, Kind)>();

		private static Dictionary<int, Kind> kinds;

		private static ZDOMan seeded;

		private static bool dirty;

		private static List<ZDO> tracks = new List<ZDO>();

		private static List<ZDO> locomotives = new List<ZDO>();

		private static List<ZDO> wagons = new List<ZDO>();

		private static List<ZDO> stations = new List<ZDO>();

		public static int Pass;

		public static List<ZDO> Tracks
		{
			get
			{
				Update();
				return tracks;
			}
		}

		public static List<ZDO> Locomotives
		{
			get
			{
				Update();
				return locomotives;
			}
		}

		public static List<ZDO> Wagons
		{
			get
			{
				Update();
				return wagons;
			}
		}

		public static List<ZDO> Stations
		{
			get
			{
				Update();
				return stations;
			}
		}

		public static void Reset()
		{
			known.Clear();
			seeded = null;
			tracks = new List<ZDO>();
			locomotives = new List<ZDO>();
			wagons = new List<ZDO>();
			stations = new List<ZDO>();
			dirty = false;
			Pass++;
		}

		public static void Update()
		{
			ZDOMan instance = ZDOMan.instance;
			if (instance != null)
			{
				if (seeded != instance)
				{
					Seed(instance);
				}
				if (dirty)
				{
					Split();
				}
			}
		}

		private static bool KindOf(int prefab, out Kind kind)
		{
			if (kinds == null)
			{
				kinds = Pieces.Specs.Where((Pieces.Spec s) => s.model.StartsWith("track_")).ToDictionary((Pieces.Spec s) => StringExtensionMethods.GetStableHashCode(s.prefab), (Pieces.Spec s) => Kind.Track);
				kinds[Train.LocomotiveHash] = Kind.Locomotive;
				kinds[Train.WagonHash] = Kind.Wagon;
				kinds[Train.RestaurantHash] = Kind.Wagon;
				kinds[RailPortal.Hash] = Kind.Wagon;
				kinds[Flatbed.Hash] = Kind.Wagon;
				kinds[Station.Hash] = Kind.Station;
			}
			return kinds.TryGetValue(prefab, out kind);
		}

		private static void Seed(ZDOMan man)
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			Stopwatch stopwatch = Stopwatch.StartNew();
			known.Clear();
			foreach (ZDO value in man.m_objectsByID.Values)
			{
				if (KindOf(value.GetPrefab(), out var kind))
				{
					known[value.m_uid] = (value, kind);
				}
			}
			seeded = man;
			Split();
			RailPlugin.Log.LogInfo((object)$"rail objects: {known.Count} of {man.m_objectsByID.Count} in {stopwatch.ElapsedMilliseconds} ms");
		}

		private static void Split()
		{
			dirty = false;
			List<ZDO> list = new List<ZDO>();
			List<ZDO> list2 = new List<ZDO>();
			List<ZDO> list3 = new List<ZDO>();
			List<ZDO> list4 = new List<ZDO>();
			foreach (var value in known.Values)
			{
				var (item, _) = value;
				switch (value.kind)
				{
				case Kind.Track:
					list.Add(item);
					break;
				case Kind.Locomotive:
					list2.Add(item);
					break;
				case Kind.Wagon:
					list3.Add(item);
					break;
				default:
					list4.Add(item);
					break;
				}
			}
			tracks = list;
			locomotives = list2;
			wagons = list3;
			stations = list4;
			Pass++;
		}
	}
	public static class Graph
	{
		private class Piece
		{
			public string model;

			public Vector3 position;

			public Quaternion rotation;

			public List<Line> lines;
		}

		public const float Join = 0.3f;

		private static readonly Dictionary<ZDOID, Piece> pieces = new Dictionary<ZDOID, Piece>();

		private static readonly Dictionary<Vector3Int, List<(Line line, bool atB)>> ends = new Dictionary<Vector3Int, List<(Line, bool)>>();

		private static readonly Dictionary<LineId, Line> byId = new Dictionary<LineId, Line>();

		private static Dictionary<int, string> trackPrefabs;

		private static int builtFrom = -1;

		public static int Version;

		private static float nextBuild;

		private static readonly HashSet<string> Crossings = new HashSet<string> { "track_crossing", "track_junction_x" };

		public static IEnumerable<Line> Lines => pieces.Values.SelectMany((Piece p) => p.lines);

		public static void Reset()
		{
			pieces.Clear();
			ends.Clear();
			byId.Clear();
			builtFrom = -1;
			nextBuild = 0f;
		}

		public static void Update()
		{
			Scan.Update();
			if (builtFrom != Scan.Pass || Time.time >= nextBuild)
			{
				Build();
			}
		}

		public static void Rebuild()
		{
			Scan.Update();
			Build();
		}

		private static void Build()
		{
			//IL_0100: 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_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: 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_0161: 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_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: 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_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			builtFrom = Scan.Pass;
			nextBuild = Time.time + 1f;
			if (trackPrefabs == null)
			{
				trackPrefabs = Pieces.Specs.Where((Pieces.Spec s) => s.model.StartsWith("track_")).ToDictionary((Pieces.Spec s) => StringExtensionMethods.GetStableHashCode(s.prefab), (Pieces.Spec s) => s.model);
			}
			HashSet<ZDOID> seen = new HashSet<ZDOID>();
			bool flag = false;
			foreach (ZDO zdo in Scan.Tracks)
			{
				if (!zdo.IsValid() || !trackPrefabs.TryGetValue(zdo.GetPrefab(), out var value))
				{
					continue;
				}
				seen.Add(zdo.m_uid);
				Vector3 position = zdo.GetPosition();
				Quaternion rotation = zdo.GetRotation();
				if (pieces.TryGetValue(zdo.m_uid, out var value2) && value2.position == position && value2.rotation == rotation)
				{
					continue;
				}
				Matrix4x4 world = Matrix4x4.TRS(position, rotation, Vector3.one);
				pieces[zdo.m_uid] = new Piece
				{
					model = value,
					position = position,
					rotation = rotation,
					lines = Models.Load(value).lines.Select((Vector3[] l) => new Line(zdo.m_uid, l.Select((Vector3 p) => ((Matrix4x4)(ref world)).MultiplyPoint3x4(p)).ToArray())).ToList()
				};
				flag = true;
			}
			foreach (ZDOID item in pieces.Keys.Where((ZDOID id) => !seen.Contains(id)).ToList())
			{
				pieces.Remove(item);
				flag = true;
			}
			if (!flag)
			{
				return;
			}
			ends.Clear();
			byId.Clear();
			foreach (Line line in Lines)
			{
				byId[line.Id] = line;
				AddEnd(line, atB: false);
				AddEnd(line, atB: true);
			}
			foreach (Line line2 in Lines)
			{
				line2.nextAtA = Search(line2, atB: false);
				line2.nextAtB = Search(line2, atB: true);
			}
			Version++;
		}

		private static Vector3Int Cell(Vector3 p)
		{
			//IL_0000: 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_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3Int(Mathf.FloorToInt(p.x), Mathf.FloorToInt(p.y), Mathf.FloorToInt(p.z));
		}

		private static void AddEnd(Line line, bool atB)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			Vector3Int key = Cell(atB ? line.B : line.A);
			if (!ends.TryGetValue(key, out List<(Line, bool)> value))
			{
				value = new List<(Line, bool)>();
				ends[key] = value;
			}
			value.Add((line, atB));
		}

		public static List<Step> Next(Line line, bool atB)
		{
			if (!atB)
			{
				return line.nextAtA;
			}
			return line.nextAtB;
		}

		private static List<Step> Search(Line line, bool atB)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = (atB ? line.B : line.A);
			Vector3 val