Decompiled source of ForeverGolfCart v0.3.2

ForeverGolfCart.dll

Decompiled 3 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

[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("ForeverGolfCart")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ForeverGolfCart")]
[assembly: AssemblyTitle("ForeverGolfCart")]
[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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ForeverGolfCart
{
	internal static class InputBridge
	{
		internal static bool WasPressedThisFrame(KeyCode keyCode)
		{
			//IL_0000: 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_0020: Expected I4, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: 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)
			switch (keyCode - 323)
			{
			case 0:
				if (Mouse.current != null)
				{
					return Mouse.current.leftButton.wasPressedThisFrame;
				}
				return false;
			case 1:
				if (Mouse.current != null)
				{
					return Mouse.current.rightButton.wasPressedThisFrame;
				}
				return false;
			case 2:
				if (Mouse.current != null)
				{
					return Mouse.current.middleButton.wasPressedThisFrame;
				}
				return false;
			case 3:
				if (Mouse.current != null)
				{
					return Mouse.current.backButton.wasPressedThisFrame;
				}
				return false;
			case 4:
				if (Mouse.current != null)
				{
					return Mouse.current.forwardButton.wasPressedThisFrame;
				}
				return false;
			default:
			{
				Key val = TranslateKey(keyCode);
				if ((int)val == 0 || Keyboard.current == null)
				{
					return false;
				}
				return ((ButtonControl)Keyboard.current[val]).wasPressedThisFrame;
			}
			}
		}

		internal static bool IsHeld(KeyCode keyCode)
		{
			//IL_0000: 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_0020: Expected I4, but got Unknown
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: 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)
			switch (keyCode - 323)
			{
			case 0:
				if (Mouse.current != null)
				{
					return Mouse.current.leftButton.isPressed;
				}
				return false;
			case 1:
				if (Mouse.current != null)
				{
					return Mouse.current.rightButton.isPressed;
				}
				return false;
			case 2:
				if (Mouse.current != null)
				{
					return Mouse.current.middleButton.isPressed;
				}
				return false;
			case 3:
				if (Mouse.current != null)
				{
					return Mouse.current.backButton.isPressed;
				}
				return false;
			case 4:
				if (Mouse.current != null)
				{
					return Mouse.current.forwardButton.isPressed;
				}
				return false;
			default:
			{
				Key val = TranslateKey(keyCode);
				if ((int)val == 0 || Keyboard.current == null)
				{
					return false;
				}
				return ((ButtonControl)Keyboard.current[val]).isPressed;
			}
			}
		}

		private static Key TranslateKey(KeyCode keyCode)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Invalid comparison between Unknown and I4
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Invalid comparison between Unknown and I4
			//IL_0076: 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_00fb: Expected I4, but got Unknown
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Invalid comparison between Unknown and I4
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			//IL_00fb: 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_0197: Expected I4, but got Unknown
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected I4, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Invalid comparison between Unknown and I4
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			if ((int)keyCode <= 27)
			{
				if ((int)keyCode <= 9)
				{
					if ((int)keyCode == 8)
					{
						return (Key)65;
					}
					if ((int)keyCode == 9)
					{
						return (Key)3;
					}
				}
				else
				{
					if ((int)keyCode == 13)
					{
						return (Key)2;
					}
					if ((int)keyCode == 27)
					{
						return (Key)60;
					}
				}
			}
			else if ((int)keyCode <= 57)
			{
				if ((int)keyCode == 32)
				{
					return (Key)1;
				}
				switch (keyCode - 48)
				{
				case 0:
					return (Key)50;
				case 1:
					return (Key)41;
				case 2:
					return (Key)42;
				case 3:
					return (Key)43;
				case 4:
					return (Key)44;
				case 5:
					return (Key)45;
				case 6:
					return (Key)46;
				case 7:
					return (Key)47;
				case 8:
					return (Key)48;
				case 9:
					return (Key)49;
				}
			}
			else
			{
				switch (keyCode - 97)
				{
				default:
					switch (keyCode - 273)
					{
					case 9:
						return (Key)94;
					case 10:
						return (Key)95;
					case 11:
						return (Key)96;
					case 12:
						return (Key)97;
					case 13:
						return (Key)98;
					case 14:
						return (Key)99;
					case 15:
						return (Key)100;
					case 16:
						return (Key)101;
					case 17:
						return (Key)102;
					case 18:
						return (Key)103;
					case 19:
						return (Key)104;
					case 20:
						return (Key)105;
					case 31:
						return (Key)51;
					case 30:
						return (Key)52;
					case 33:
						return (Key)55;
					case 32:
						return (Key)56;
					case 35:
						return (Key)53;
					case 34:
						return (Key)54;
					case 0:
						return (Key)63;
					case 1:
						return (Key)64;
					case 3:
						return (Key)61;
					case 2:
						return (Key)62;
					}
					break;
				case 0:
					return (Key)15;
				case 1:
					return (Key)16;
				case 2:
					return (Key)17;
				case 3:
					return (Key)18;
				case 4:
					return (Key)19;
				case 5:
					return (Key)20;
				case 6:
					return (Key)21;
				case 7:
					return (Key)22;
				case 8:
					return (Key)23;
				case 9:
					return (Key)24;
				case 10:
					return (Key)25;
				case 11:
					return (Key)26;
				case 12:
					return (Key)27;
				case 13:
					return (Key)28;
				case 14:
					return (Key)29;
				case 15:
					return (Key)30;
				case 16:
					return (Key)31;
				case 17:
					return (Key)32;
				case 18:
					return (Key)33;
				case 19:
					return (Key)34;
				case 20:
					return (Key)35;
				case 21:
					return (Key)36;
				case 22:
					return (Key)37;
				case 23:
					return (Key)38;
				case 24:
					return (Key)39;
				case 25:
					return (Key)40;
				case 30:
					return (Key)71;
				case 26:
				case 27:
				case 28:
				case 29:
					break;
				}
			}
			return (Key)0;
		}
	}
	[BepInPlugin("sbg.forevergolfcart", "ForeverGolfCart", "0.3.2")]
	public sealed class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(GolfCartInfo), "OnStartClient")]
		internal static class Patch_GolfCartInfo_OnStartClient
		{
			private static void Postfix(GolfCartInfo __instance)
			{
				if (!((Object)(object)Instance == (Object)null) && Instance.pastelTintEnabledConfig.Value && !((Object)(object)__instance == (Object)null) && ((NetworkBehaviour)__instance).netId != 0 && ClientTintedCarts.Contains(((NetworkBehaviour)__instance).netId))
				{
					ApplyPastelTint(__instance);
				}
			}
		}

		public const string ModGuid = "sbg.forevergolfcart";

		public const string ModName = "ForeverGolfCart";

		public const string ModVersion = "0.3.2";

		internal static ManualLogSource Log;

		internal static Plugin Instance;

		internal ConfigEntry<float> hotkeyHoldDurationConfig;

		internal ConfigEntry<KeyCode> summonKeyConfig;

		internal ConfigEntry<bool> pastelTintEnabledConfig;

		internal ConfigEntry<bool> verboseLoggingConfig;

		private static MethodInfo serverEnterMethod;

		private static readonly HashSet<uint> ServerTrackedCarts = new HashSet<uint>();

		private static readonly HashSet<uint> ClientTintedCarts = new HashSet<uint>();

		private static bool serializerRegistered;

		private static bool serverHandlerRegistered;

		private static bool clientHandlerRegistered;

		private float keyHeldFor;

		private bool summonedThisHold;

		private void Awake()
		{
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			hotkeyHoldDurationConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Spawn", "HotkeyHoldDuration", 0.4f, "Seconds to hold the summon key before the cart spawns. Prevents accidental Q taps from summoning a cart.");
			summonKeyConfig = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Spawn", "SummonKey", (KeyCode)113, "Key to summon a cart. Any UnityEngine.KeyCode value (letters, numbers, function keys, modifiers, mouse buttons via Mouse0..4).");
			pastelTintEnabledConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Visuals", "PastelTintEnabled", true, "Tint summoned carts with a pastel hue derived from their netId so non-natural carts are recognisable. Each cart's color is consistent across modded clients.");
			verboseLoggingConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "VerboseLogging", false, "Emit lines whenever the summon key fires, the summon request lands on the server, and the cart spawns / auto-seat. Off by default.");
			serverEnterMethod = AccessTools.Method(typeof(GolfCartInfo), "ServerEnter", (Type[])null, (Type[])null);
			RegisterSerializers();
			new Harmony("sbg.forevergolfcart").PatchAll();
			Log.LogInfo((object)"ForeverGolfCart v0.3.2 loaded.");
		}

		private void OnDestroy()
		{
		}

		private static void EnsureHandlersRegistered()
		{
			if (!serverHandlerRegistered && NetworkServer.active)
			{
				NetworkServer.ReplaceHandler<ForeverGolfCartSummonMsg>((Action<NetworkConnectionToClient, ForeverGolfCartSummonMsg>)OnSummonRequest, true);
				serverHandlerRegistered = true;
				LogVerbose("registered server handler ForeverGolfCartSummonMsg.");
			}
			if (!clientHandlerRegistered && NetworkClient.active)
			{
				NetworkClient.ReplaceHandler<ForeverGolfCartTintMsg>((Action<ForeverGolfCartTintMsg>)OnTintMessage, true);
				clientHandlerRegistered = true;
				LogVerbose("registered client handler ForeverGolfCartTintMsg.");
			}
			if (serverHandlerRegistered && !NetworkServer.active)
			{
				serverHandlerRegistered = false;
			}
			if (clientHandlerRegistered && !NetworkClient.active)
			{
				clientHandlerRegistered = false;
			}
		}

		private static void RegisterSerializers()
		{
			if (!serializerRegistered)
			{
				Writer<ForeverGolfCartSummonMsg>.write = delegate
				{
				};
				Reader<ForeverGolfCartSummonMsg>.read = (NetworkReader r) => default(ForeverGolfCartSummonMsg);
				Writer<ForeverGolfCartTintMsg>.write = delegate(NetworkWriter w, ForeverGolfCartTintMsg m)
				{
					NetworkWriterExtensions.WriteUInt(w, m.netId);
				};
				Reader<ForeverGolfCartTintMsg>.read = delegate(NetworkReader r)
				{
					ForeverGolfCartTintMsg result = default(ForeverGolfCartTintMsg);
					result.netId = NetworkReaderExtensions.ReadUInt(r);
					return result;
				};
				serializerRegistered = true;
			}
		}

		private void Update()
		{
			EnsureHandlersRegistered();
			UpdateHotkey();
			if (NetworkServer.active)
			{
				UpdateServerCartTracking();
			}
		}

		private void UpdateHotkey()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (InputBridge.IsHeld(summonKeyConfig.Value))
			{
				keyHeldFor += Time.deltaTime;
				if (!summonedThisHold && keyHeldFor >= hotkeyHoldDurationConfig.Value)
				{
					LogVerbose($"summon key {summonKeyConfig.Value} held for {keyHeldFor:F2}s — invoking summon.");
					TrySummonCart();
					summonedThisHold = true;
				}
			}
			else
			{
				keyHeldFor = 0f;
				summonedThisHold = false;
			}
		}

		internal static void LogVerbose(string message)
		{
			if ((Object)(object)Instance != (Object)null && Instance.verboseLoggingConfig.Value)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogInfo((object)("ForeverGolfCart: " + message));
				}
			}
		}

		private void TrySummonCart()
		{
			//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)
			PlayerInfo localPlayerInfo = GameManager.LocalPlayerInfo;
			if ((Object)(object)localPlayerInfo == (Object)null)
			{
				return;
			}
			GolfCartSeat activeGolfCartSeat = localPlayerInfo.ActiveGolfCartSeat;
			if (!((GolfCartSeat)(ref activeGolfCartSeat)).IsValid() && (!((Object)(object)localPlayerInfo.AsGolfer != (Object)null) || !localPlayerInfo.AsGolfer.IsMatchResolved))
			{
				if (NetworkServer.active)
				{
					ServerSummonForPlayer(localPlayerInfo);
				}
				else if (NetworkClient.active && NetworkClient.ready)
				{
					NetworkClient.Send<ForeverGolfCartSummonMsg>(default(ForeverGolfCartSummonMsg), 0);
				}
			}
		}

		private static void OnSummonRequest(NetworkConnectionToClient conn, ForeverGolfCartSummonMsg _)
		{
			if (conn != null && !((Object)(object)((NetworkConnection)conn).identity == (Object)null))
			{
				PlayerInfo component = ((Component)((NetworkConnection)conn).identity).GetComponent<PlayerInfo>();
				if (!((Object)(object)component == (Object)null))
				{
					ServerSummonForPlayer(component);
				}
			}
		}

		private static void ServerSummonForPlayer(PlayerInfo target)
		{
			//IL_0055: 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_0074: Unknown result type (might be due to invalid IL or missing references)
			if (!NetworkServer.active || (Object)(object)target == (Object)null)
			{
				return;
			}
			if ((Object)(object)GameManager.GolfCartSettings == (Object)null || (Object)(object)GameManager.GolfCartSettings.Prefab == (Object)null)
			{
				ManualLogSource log = Log;
				if (log != null)
				{
					log.LogWarning((object)"ForeverGolfCart summon ignored: GolfCartSettings.Prefab missing.");
				}
				return;
			}
			GolfCartInfo val = Object.Instantiate<GolfCartInfo>(GameManager.GolfCartSettings.Prefab, ((Component)target).transform.position, Quaternion.Euler(0f, ((Component)target).transform.eulerAngles.y, 0f));
			if ((Object)(object)val == (Object)null)
			{
				ManualLogSource log2 = Log;
				if (log2 != null)
				{
					log2.LogWarning((object)"ForeverGolfCart: cart prefab failed to instantiate.");
				}
				return;
			}
			NetworkServer.Spawn(((Component)val).gameObject, (NetworkConnectionToClient)null);
			uint netId = ((NetworkBehaviour)val).netId;
			ServerTrackedCarts.Add(netId);
			ClientTintedCarts.Add(netId);
			LogVerbose($"summoned cart netId={netId} for {((Object)target).name} — invoking ServerEnter.");
			if (serverEnterMethod != null)
			{
				try
				{
					serverEnterMethod.Invoke(val, new object[1] { target });
				}
				catch (Exception ex)
				{
					ManualLogSource log3 = Log;
					if (log3 != null)
					{
						log3.LogWarning((object)("ForeverGolfCart: ServerEnter reflection invoke failed: " + ex.Message));
					}
				}
			}
			if ((Object)(object)Instance != (Object)null && Instance.pastelTintEnabledConfig.Value)
			{
				ApplyPastelTint(val);
				if ((Object)(object)Instance != (Object)null)
				{
					((MonoBehaviour)Instance).StartCoroutine(ReapplyTintNextFrames(val));
				}
			}
			ForeverGolfCartTintMsg foreverGolfCartTintMsg = default(ForeverGolfCartTintMsg);
			foreverGolfCartTintMsg.netId = netId;
			NetworkServer.SendToAll<ForeverGolfCartTintMsg>(foreverGolfCartTintMsg, 0, false);
		}

		private static IEnumerator ReapplyTintNextFrames(GolfCartInfo cart)
		{
			for (int i = 0; i < 6; i++)
			{
				if (!((Object)(object)cart != (Object)null))
				{
					break;
				}
				yield return null;
				ApplyPastelTint(cart);
			}
		}

		private static void OnTintMessage(ForeverGolfCartTintMsg msg)
		{
			ClientTintedCarts.Add(msg.netId);
			if ((Object)(object)Instance == (Object)null || !Instance.pastelTintEnabledConfig.Value || !NetworkClient.spawned.TryGetValue(msg.netId, out var value) || !((Object)(object)value != (Object)null))
			{
				return;
			}
			GolfCartInfo component = ((Component)value).GetComponent<GolfCartInfo>();
			if ((Object)(object)component != (Object)null)
			{
				ApplyPastelTint(component);
				if ((Object)(object)Instance != (Object)null)
				{
					((MonoBehaviour)Instance).StartCoroutine(ReapplyTintNextFrames(component));
				}
			}
		}

		private void UpdateServerCartTracking()
		{
			if (ServerTrackedCarts.Count == 0)
			{
				return;
			}
			List<uint> list = null;
			foreach (uint serverTrackedCart in ServerTrackedCarts)
			{
				if (!NetworkServer.spawned.TryGetValue(serverTrackedCart, out var value) || (Object)(object)value == (Object)null)
				{
					if (list == null)
					{
						list = new List<uint>();
					}
					list.Add(serverTrackedCart);
					continue;
				}
				GolfCartInfo component = ((Component)value).GetComponent<GolfCartInfo>();
				if ((Object)(object)component == (Object)null)
				{
					if (list == null)
					{
						list = new List<uint>();
					}
					list.Add(serverTrackedCart);
				}
				else if (IsCartFullyEmpty(component))
				{
					if (list == null)
					{
						list = new List<uint>();
					}
					list.Add(serverTrackedCart);
					NetworkServer.Destroy(((Component)component).gameObject);
				}
			}
			if (list == null)
			{
				return;
			}
			foreach (uint item in list)
			{
				ServerTrackedCarts.Remove(item);
				ClientTintedCarts.Remove(item);
			}
		}

		private static bool IsCartFullyEmpty(GolfCartInfo cart)
		{
			if ((Object)(object)cart.NetworkdriverSeatReserver != (Object)null)
			{
				return false;
			}
			for (int i = 0; i < cart.passengers.Count; i++)
			{
				if ((Object)(object)cart.passengers[i] != (Object)null)
				{
					return false;
				}
			}
			return true;
		}

		private static void ApplyPastelTint(GolfCartInfo cart)
		{
			//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_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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)cart == (Object)null)
			{
				return;
			}
			Color val = Color.HSVToRGB((float)((NetworkBehaviour)cart).netId * 0.618034f % 1f, 0.55f, 0.92f);
			val.a = 1f;
			Renderer[] componentsInChildren = ((Component)cart).GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val2 in componentsInChildren)
			{
				if ((Object)(object)val2 == (Object)null)
				{
					continue;
				}
				Material[] materials = val2.materials;
				if (materials == null)
				{
					continue;
				}
				bool flag = false;
				foreach (Material val3 in materials)
				{
					if (!((Object)(object)val3 == (Object)null))
					{
						if (val3.HasProperty("_Color"))
						{
							val3.color *= val;
							flag = true;
						}
						if (val3.HasProperty("_BaseColor"))
						{
							val3.SetColor("_BaseColor", val3.GetColor("_BaseColor") * val);
							flag = true;
						}
					}
				}
				if (flag)
				{
					val2.materials = materials;
				}
			}
		}
	}
	[StructLayout(LayoutKind.Sequential, Size = 1)]
	internal struct ForeverGolfCartSummonMsg : NetworkMessage
	{
	}
	internal struct ForeverGolfCartTintMsg : NetworkMessage
	{
		public uint netId;
	}
}