Decompiled source of QualityTeleporter ByTihi v1.1.0

BepInEx\plugins\TeleporterFix\TeleporterFix.dll

Decompiled a week ago
using System;
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.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("TeleporterFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+cb007ec1a4a66dcc2cd88036f6d65307c71ab6ad")]
[assembly: AssemblyProduct("TeleporterFix")]
[assembly: AssemblyTitle("TeleporterFix")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 TeleporterFix
{
	internal static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "Tihi.QualityTeleporter";

		public const string PLUGIN_NAME = "QualityTeleporter_ByTihi";

		public const string PLUGIN_VERSION = "1.1.0";
	}
	[BepInPlugin("Tihi.QualityTeleporter", "QualityTeleporter_ByTihi", "1.1.0")]
	public class Plugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log = null;

		private static readonly Harmony Harmony = new Harmony("Tihi.QualityTeleporter");

		private void Awake()
		{
			Log = ((BaseUnityPlugin)this).Logger;
			Harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"QualityTeleporter_ByTihi v1.1.0 loaded!");
		}
	}
	internal static class TeleportContext
	{
		internal static readonly HashSet<ulong> RegularTeleporting = new HashSet<ulong>();

		internal static readonly HashSet<ulong> InverseTeleporting = new HashSet<ulong>();

		internal static readonly Dictionary<ulong, GrabbableObject?[]> SavedSlots = new Dictionary<ulong, GrabbableObject[]>();

		internal static bool InverseBeamInProgress = false;

		internal static bool IsRegularTeleporting(PlayerControllerB player)
		{
			return RegularTeleporting.Contains(player.playerClientId);
		}

		internal static bool IsInverseTeleporting(PlayerControllerB player)
		{
			return InverseTeleporting.Contains(player.playerClientId);
		}

		internal static void Clear(PlayerControllerB player)
		{
			ulong playerClientId = player.playerClientId;
			RegularTeleporting.Remove(playerClientId);
			InverseTeleporting.Remove(playerClientId);
			SavedSlots.Remove(playerClientId);
			InverseBeamInProgress = false;
		}
	}
}
namespace TeleporterFix.Patches
{
	[HarmonyPatch(typeof(ShipTeleporter), "PressTeleportButtonOnLocalClient")]
	internal static class CooldownPatch
	{
		private static void Postfix(ShipTeleporter __instance, ref float ___cooldownTime, ref float ___cooldownAmount)
		{
			___cooldownTime = 5f;
			___cooldownAmount = 5f;
		}
	}
	[HarmonyPatch(typeof(ShipTeleporter), "SetPlayerTeleporterId")]
	internal static class TrackTeleportPatch
	{
		private static void Prefix(ShipTeleporter __instance, PlayerControllerB playerScript, int teleporterId)
		{
			if ((Object)(object)playerScript == (Object)null)
			{
				return;
			}
			switch (teleporterId)
			{
			case 1:
				if (__instance.isInverseTeleporter)
				{
					TeleportContext.InverseTeleporting.Add(playerScript.playerClientId);
				}
				else
				{
					TeleportContext.RegularTeleporting.Add(playerScript.playerClientId);
				}
				break;
			case -1:
				TeleportContext.Clear(playerScript);
				break;
			}
		}
	}
	[HarmonyPatch(typeof(ShipTeleporter), "TeleportPlayerOutWithInverseTeleporter")]
	internal static class TeleportPlayerOutWithInversePatch
	{
		private static void Prefix()
		{
			TeleportContext.InverseBeamInProgress = true;
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "DropAllHeldItems")]
	internal static class DropAllHeldItemsPatch
	{
		private static void Prefix(PlayerControllerB __instance)
		{
			ItemSaver.ApplyInverseContextIfNeeded(__instance);
			ItemSaver.Save(__instance);
		}

		private static void Postfix(PlayerControllerB __instance)
		{
			ItemSaver.Restore(__instance);
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB), "DropAllHeldItemsAndSync")]
	internal static class DropAllHeldItemsAndSyncPatch
	{
		private static void Prefix(PlayerControllerB __instance)
		{
			ItemSaver.ApplyInverseContextIfNeeded(__instance);
			ItemSaver.Save(__instance);
		}

		private static void Postfix(PlayerControllerB __instance)
		{
			ItemSaver.Restore(__instance);
		}
	}
	internal static class ItemSaver
	{
		private static readonly HashSet<string> EquipmentNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "Shovel", "Stop sign", "Yield sign", "Weed killer", "Walkie-talkie", "Flashlight", "Pro-flashlight", "Lockpicker", "Key" };

		internal static void ApplyInverseContextIfNeeded(PlayerControllerB player)
		{
			if (TeleportContext.InverseBeamInProgress && !TeleportContext.IsInverseTeleporting(player))
			{
				TeleportContext.InverseTeleporting.Add(player.playerClientId);
			}
		}

		private static bool IsEquipment(GrabbableObject item)
		{
			if ((Object)(object)item.itemProperties != (Object)null)
			{
				return EquipmentNames.Contains(item.itemProperties.itemName);
			}
			return false;
		}

		internal static void Save(PlayerControllerB player)
		{
			bool num = TeleportContext.IsRegularTeleporting(player);
			bool flag = TeleportContext.IsInverseTeleporting(player);
			if (!num && !flag)
			{
				return;
			}
			GrabbableObject[] itemSlots = player.ItemSlots;
			GrabbableObject[] array = (GrabbableObject[])(object)new GrabbableObject[itemSlots.Length];
			bool flag2 = false;
			for (int i = 0; i < itemSlots.Length; i++)
			{
				GrabbableObject val = itemSlots[i];
				if (!((Object)(object)val == (Object)null) && IsEquipment(val))
				{
					array[i] = val;
					itemSlots[i] = null;
					flag2 = true;
				}
			}
			if (flag2)
			{
				TeleportContext.SavedSlots[player.playerClientId] = array;
				Plugin.Log.LogInfo((object)$"[TeleporterFix] Saved items for player {player.playerClientId} (inverse={flag})");
			}
		}

		internal static void Restore(PlayerControllerB player)
		{
			if (!TeleportContext.SavedSlots.TryGetValue(player.playerClientId, out GrabbableObject[] value))
			{
				return;
			}
			GrabbableObject[] itemSlots = player.ItemSlots;
			bool flag = (Object)(object)player == (Object)(object)GameNetworkManager.Instance.localPlayerController;
			for (int i = 0; i < value.Length && i < itemSlots.Length; i++)
			{
				GrabbableObject val = value[i];
				if (!((Object)(object)val == (Object)null))
				{
					itemSlots[i] = val;
					val.isHeld = true;
					val.playerHeldBy = player;
					val.hasHitGround = false;
					val.EnablePhysics(false);
					if ((Object)(object)val.parentObject != (Object)null)
					{
						((Component)val).transform.SetParent(val.parentObject, false);
					}
					if (flag && (Object)(object)HUDManager.Instance != (Object)null && i < HUDManager.Instance.itemSlotIcons.Length && (Object)(object)val.itemProperties != (Object)null)
					{
						HUDManager.Instance.itemSlotIcons[i].sprite = val.itemProperties.itemIcon;
					}
				}
			}
			TeleportContext.SavedSlots.Remove(player.playerClientId);
			Plugin.Log.LogInfo((object)$"[TeleporterFix] Restored items for player {player.playerClientId}");
		}
	}
	[HarmonyPatch(typeof(Terminal), "ParsePlayerSentence")]
	internal static class TerminalCommandPatch
	{
		private static FieldInfo? _inCooldownField;

		private static MethodInfo? _switchRadarMethod;

		private static bool Prefix(Terminal __instance, ref TerminalNode __result)
		{
			string text = __instance.screenText.text;
			if (__instance.textAdded <= 0 || __instance.textAdded > text.Length)
			{
				return true;
			}
			string text2 = text.Substring(text.Length - __instance.textAdded).Trim();
			if (string.IsNullOrEmpty(text2))
			{
				return true;
			}
			string text3 = text2.ToLowerInvariant();
			if (text3.StartsWith("tp ") || text3 == "tp")
			{
				__result = HandleTeleport((text2.Length > 3) ? text2.Substring(3).Trim() : "", inverse: false);
				return false;
			}
			if (text3.StartsWith("itp ") || text3 == "itp")
			{
				__result = HandleTeleport((text2.Length > 4) ? text2.Substring(4).Trim() : "", inverse: true);
				return false;
			}
			return true;
		}

		private static TerminalNode HandleTeleport(string name, bool inverse)
		{
			string text = (inverse ? "itp" : "tp");
			if (string.IsNullOrWhiteSpace(name))
			{
				return MakeNode("Usage: " + text + " [player name]\n");
			}
			List<PlayerControllerB> list = FindPlayers(name);
			if (list.Count == 0)
			{
				return MakeNode("No active player found matching \"" + name + "\".\n");
			}
			if (list.Count > 1)
			{
				string text2 = string.Join(", ", list.Select((PlayerControllerB p) => p.playerUsername));
				return MakeNode("Multiple players match \"" + name + "\": " + text2 + "\nPlease be more specific.\n");
			}
			PlayerControllerB val = list[0];
			if (!inverse && val.isInHangarShipRoom)
			{
				return MakeNode(val.playerUsername + " is already on the ship.\n");
			}
			if (inverse && !val.isInHangarShipRoom)
			{
				return MakeNode(val.playerUsername + " is not on the ship.\n");
			}
			ShipTeleporter val2 = FindTeleporter(inverse);
			if ((Object)(object)val2 == (Object)null)
			{
				return MakeNode((inverse ? "Inverse t" : "T") + "eleporter not found on the ship.\n");
			}
			if (IsTeleporterOnCooldown(val2))
			{
				return MakeNode((inverse ? "Inverse t" : "T") + "eleporter is on cooldown.\n");
			}
			int num = Array.IndexOf(StartOfRound.Instance.allPlayerScripts, val);
			if (num >= 0)
			{
				SwitchRadarTarget(num);
			}
			val2.PressTeleportButtonOnLocalClient();
			Plugin.Log.LogInfo((object)("[TeleporterFix] Terminal " + text.ToUpper() + " → " + val.playerUsername));
			return MakeNode("Teleporting " + val.playerUsername + "...\n");
		}

		private static List<PlayerControllerB> FindPlayers(string name)
		{
			string lower = name.ToLowerInvariant();
			return (from p in StartOfRound.Instance.allPlayerScripts
				where p.isPlayerControlled && !p.isPlayerDead
				where p.playerUsername.ToLowerInvariant().Contains(lower)
				select p).ToList();
		}

		private static ShipTeleporter? FindTeleporter(bool inverse)
		{
			return ((IEnumerable<ShipTeleporter>)Object.FindObjectsOfType<ShipTeleporter>()).FirstOrDefault((Func<ShipTeleporter, bool>)((ShipTeleporter t) => t.isInverseTeleporter == inverse));
		}

		private static bool IsTeleporterOnCooldown(ShipTeleporter teleporter)
		{
			if ((object)_inCooldownField == null)
			{
				_inCooldownField = AccessTools.Field(typeof(ShipTeleporter), "inCooldown");
			}
			if (_inCooldownField != null)
			{
				return (bool)(_inCooldownField.GetValue(teleporter) ?? ((object)false));
			}
			return false;
		}

		private static void SwitchRadarTarget(int playerIndex)
		{
			if ((object)_switchRadarMethod == null)
			{
				_switchRadarMethod = AccessTools.Method(typeof(StartOfRound), "SwitchRadarTargetAndSync", (Type[])null, (Type[])null);
			}
			_switchRadarMethod?.Invoke(StartOfRound.Instance, new object[1] { playerIndex });
		}

		private static TerminalNode MakeNode(string text)
		{
			TerminalNode obj = ScriptableObject.CreateInstance<TerminalNode>();
			obj.displayText = text;
			obj.clearPreviousText = true;
			return obj;
		}
	}
}