Decompiled source of Cart Unloader v0.1.0

plugins/CrackCartUnloader.dll

Decompiled 17 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("CrackCartUnloader")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("CrackCartUnloader")]
[assembly: AssemblyTitle("CrackCartUnloader")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace CrackCartUnloader
{
	[BepInPlugin("com.altma.crackhost.cartunloader", "CRACK Cart Unloader", "0.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		public const string Guid = "com.altma.crackhost.cartunloader";

		public const string Name = "CRACK Cart Unloader";

		public const string Version = "0.1.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<float> Radius;

		internal static ConfigEntry<float> GlideSeconds;

		internal static ConfigEntry<bool> ReturnEmpties;

		private void Awake()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Radius = ((BaseUnityPlugin)this).Config.Bind<float>("Unloader", "Radius", 5f, "How close (metres) a cart has to be to the deposit conveyor to be unloaded.");
			GlideSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Unloader", "GlideSeconds", 0.6f, "How long each bucket takes to move between cart and belt.");
			ReturnEmpties = ((BaseUnityPlugin)this).Config.Bind<bool>("Unloader", "ReturnEmpties", true, "Load emptied buckets back onto the cart as they come out of the machine.");
			new Harmony("com.altma.crackhost.cartunloader").PatchAll(typeof(Plugin).Assembly);
			Log.LogInfo((object)"CRACK Cart Unloader 0.1.0 loaded");
		}
	}
	[HarmonyPatch(typeof(DepositMachine), "OnStartServer")]
	internal static class AttachPatch
	{
		private static void Postfix(DepositMachine __instance)
		{
			Unloader.Attach(__instance);
		}
	}
	internal sealed class Unloader : MonoBehaviour
	{
		private sealed class Returning
		{
			public Bucket bucket;

			public CartCargoBed bed;

			public bool seized;

			public float waited;
		}

		private const float SeizeTimeout = 5f;

		private const float ExitSettle = 0.4f;

		private const float ReturnRangeFactor = 2f;

		private static readonly FieldRef<DepositMachine, BadgeReader> ReaderRef = AccessTools.FieldRefAccess<DepositMachine, BadgeReader>("badgeReader");

		private static readonly FieldRef<DepositMachine, Transform> EnterStartRef = AccessTools.FieldRefAccess<DepositMachine, Transform>("enterStart");

		private static readonly FieldRef<DepositMachine, bool> AcceptingRef = AccessTools.FieldRefAccess<DepositMachine, bool>("_accepting");

		private static readonly FieldRef<CartCargoBed, Transform[]> SlotsRef = AccessTools.FieldRefAccess<CartCargoBed, Transform[]>("slots");

		private static readonly FieldInfo BedsField = AccessTools.Field(typeof(CartCargoBed), "Beds");

		private static readonly FieldInfo ServerSlotsField = AccessTools.Field(typeof(CartCargoBed), "_server");

		private static readonly FieldInfo SlotItemField = AccessTools.Field(ServerSlotsField.FieldType.GetElementType(), "item");

		private DepositMachine _machine;

		private Coroutine _feeding;

		private bool _badgeWasIn;

		private readonly List<Returning> _returning = new List<Returning>();

		private Vector3 Intake
		{
			get
			{
				//IL_003b: 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 (!((Object)(object)EnterStartRef.Invoke(_machine) != (Object)null))
				{
					return ((Component)_machine).transform.position;
				}
				return EnterStartRef.Invoke(_machine).position;
			}
		}

		internal static void Attach(DepositMachine machine)
		{
			if (!((Object)(object)machine == (Object)null) && !((Object)(object)((Component)machine).GetComponent<Unloader>() != (Object)null))
			{
				((Component)machine).gameObject.AddComponent<Unloader>()._machine = machine;
			}
		}

		private bool BadgeIn()
		{
			BadgeReader val = ReaderRef.Invoke(_machine);
			if ((Object)(object)val != (Object)null)
			{
				return val.HasBadgeAuthoritative;
			}
			return false;
		}

		private bool InRange(CartCargoBed bed, float radius)
		{
			//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)
			if ((Object)(object)bed != (Object)null)
			{
				Vector3 val = ((Component)bed).transform.position - Intake;
				return ((Vector3)(ref val)).sqrMagnitude <= radius * radius;
			}
			return false;
		}

		private CartCargoBed NearestBed()
		{
			return (BedsField.GetValue(null) as List<CartCargoBed>)?.Where((CartCargoBed b) => (Object)(object)b != (Object)null && ((Behaviour)b).isActiveAndEnabled && (int)b.Accepts == 0 && InRange(b, Plugin.Radius.Value)).OrderBy(delegate(CartCargoBed b)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				//IL_000c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				Vector3 val = ((Component)b).transform.position - Intake;
				return ((Vector3)(ref val)).sqrMagnitude;
			}).FirstOrDefault();
		}

		private static HeldItem SlotItem(CartCargoBed bed, int slot)
		{
			if (!(ServerSlotsField.GetValue(bed) is Array array) || slot >= array.Length)
			{
				return null;
			}
			object value = array.GetValue(slot);
			if (value == null)
			{
				return null;
			}
			object? value2 = SlotItemField.GetValue(value);
			return (HeldItem)((value2 is HeldItem) ? value2 : null);
		}

		private static int FindSlot(CartCargoBed bed, Func<int, bool> match)
		{
			int num = (ServerSlotsField.GetValue(bed) as Array)?.Length ?? 0;
			for (int i = 0; i < num; i++)
			{
				if (match(i))
				{
					return i;
				}
			}
			return -1;
		}

		private IEnumerator Feed()
		{
			CartCargoBed bed = NearestBed();
			Transform drop = (from p in DepositDropPoint.All.Where((DepositDropPoint p) => (Object)(object)p != (Object)null).OrderBy(delegate(DepositDropPoint p)
				{
					//IL_0006: Unknown result type (might be due to invalid IL or missing references)
					//IL_0011: Unknown result type (might be due to invalid IL or missing references)
					//IL_0016: Unknown result type (might be due to invalid IL or missing references)
					//IL_001b: Unknown result type (might be due to invalid IL or missing references)
					Vector3 val = ((Component)p).transform.position - Intake;
					return ((Vector3)(ref val)).sqrMagnitude;
				})
				select ((Component)p).transform).FirstOrDefault();
			if ((Object)(object)bed == (Object)null || (Object)(object)drop == (Object)null)
			{
				_feeding = null;
				yield break;
			}
			Plugin.Log.LogInfo((object)("Unloading '" + ((Object)bed).name + "' at '" + ((Object)_machine).name + "'"));
			while (BadgeIn() && InRange(bed, Plugin.Radius.Value))
			{
				int slot = FindSlot(bed, delegate(int i)
				{
					HeldItem obj = SlotItem(bed, i);
					Bucket val = (Bucket)(object)((obj is Bucket) ? obj : null);
					return val != null && val.CurrentUnits > 0;
				});
				if (slot < 0)
				{
					break;
				}
				Bucket bucket = (Bucket)SlotItem(bed, slot);
				while (AcceptingRef.Invoke(_machine))
				{
					yield return null;
				}
				if (!BadgeIn())
				{
					break;
				}
				bed.ServerReleaseSlot(slot, false);
				yield return Glide(bucket, drop.position, Quaternion.Euler(0f, ((Component)bucket).transform.eulerAngles.y, 0f));
				Release(bucket, physics: true);
				Returning entry = new Returning
				{
					bucket = bucket,
					bed = bed
				};
				float t = 0f;
				while (!DepositMachine.InAnyPipeline(((NetworkBehaviour)bucket).netId))
				{
					float num;
					t = (num = t + Time.deltaTime);
					if (!(num < 5f))
					{
						break;
					}
					yield return null;
				}
				if (!DepositMachine.InAnyPipeline(((NetworkBehaviour)bucket).netId))
				{
					break;
				}
				entry.seized = true;
				if (Plugin.ReturnEmpties.Value)
				{
					_returning.Add(entry);
				}
			}
			_feeding = null;
		}

		private void Update()
		{
			if (!NetworkServer.active || (Object)(object)_machine == (Object)null)
			{
				return;
			}
			bool flag = BadgeIn();
			if (flag && !_badgeWasIn && _feeding == null)
			{
				_feeding = ((MonoBehaviour)this).StartCoroutine(Feed());
			}
			_badgeWasIn = flag;
			for (int num = _returning.Count - 1; num >= 0; num--)
			{
				Returning r = _returning[num];
				if ((Object)(object)r.bucket == (Object)null || (Object)(object)r.bed == (Object)null)
				{
					_returning.RemoveAt(num);
				}
				else if (!DepositMachine.InAnyPipeline(((NetworkBehaviour)r.bucket).netId))
				{
					if ((Object)(object)((HeldItem)r.bucket).Holder != (Object)null || RobotCargo.IsCarried((Component)(object)r.bucket))
					{
						_returning.RemoveAt(num);
					}
					else if (!((r.waited += Time.deltaTime) < 0.4f))
					{
						_returning.RemoveAt(num);
						if (InRange(r.bed, Plugin.Radius.Value * 2f))
						{
							int num2 = FindSlot(r.bed, (int s) => (Object)(object)SlotItem(r.bed, s) == (Object)null && (Object)(object)SlotsRef.Invoke(r.bed)[s] != (Object)null);
							if (num2 >= 0)
							{
								((MonoBehaviour)this).StartCoroutine(Stow(r.bucket, r.bed, num2));
							}
						}
					}
				}
			}
		}

		private IEnumerator Stow(Bucket bucket, CartCargoBed bed, int slot)
		{
			Transform val = SlotsRef.Invoke(bed)[slot];
			yield return Glide(bucket, val.position, val.rotation);
			Release(bucket, physics: false);
			if (!bed.ServerStow((HeldItem)(object)bucket, slot))
			{
				Release(bucket, physics: true);
			}
		}

		private IEnumerator Glide(Bucket bucket, Vector3 to, Quaternion toRot)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			((HeldItem)bucket).ServerGiveToHost();
			((HeldItem)bucket).ServerEnsureNetworkTransform();
			RobotCargo.ForceClaim((Component)(object)bucket, (Component)(object)this);
			RobotCargo.SetCarried((Component)(object)bucket, (Component)(object)this);
			Rigidbody component = ((Component)bucket).GetComponent<Rigidbody>();
			if ((Object)(object)component != (Object)null)
			{
				component.isKinematic = true;
				component.linearVelocity = Vector3.zero;
				component.angularVelocity = Vector3.zero;
			}
			Vector3 from = ((Component)bucket).transform.position;
			Quaternion fromRot = ((Component)bucket).transform.rotation;
			float lift = Mathf.Clamp(Vector3.Distance(from, to) * 0.25f, 0.3f, 1f);
			float duration = Mathf.Max(0.05f, Plugin.GlideSeconds.Value);
			for (float t = 0f; t < 1f; t += Time.deltaTime / duration)
			{
				if (!((Object)(object)bucket != (Object)null))
				{
					break;
				}
				float num = t * t * (3f - 2f * t);
				((Component)bucket).transform.SetPositionAndRotation(Vector3.Lerp(from, to, num) + Vector3.up * (lift * 4f * num * (1f - num)), Quaternion.Slerp(fromRot, toRot, num));
				yield return null;
			}
			if ((Object)(object)bucket != (Object)null)
			{
				((Component)bucket).transform.SetPositionAndRotation(to, toRot);
			}
		}

		private void Release(Bucket bucket, bool physics)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)bucket == (Object)null))
			{
				RobotCargo.ClearCarried((Component)(object)bucket, (Component)(object)this);
				RobotCargo.Release((Component)(object)bucket, (Component)(object)this);
				Rigidbody component = ((Component)bucket).GetComponent<Rigidbody>();
				if (!((Object)(object)component == (Object)null) && physics)
				{
					component.isKinematic = false;
					component.linearVelocity = Vector3.zero;
					component.angularVelocity = Vector3.zero;
				}
			}
		}
	}
}