Decompiled source of Trippy v1.0.0

Trippy.dll

Decompiled 8 hours 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.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

[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("Trippy")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+3408f12aa5db26b88198b5a801f5d0a0a1e671c5")]
[assembly: AssemblyProduct("Trippy")]
[assembly: AssemblyTitle("Trippy")]
[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.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Trippy
{
	internal static class InputGuard
	{
		private static readonly Type? ChatManagerType = AccessTools.TypeByName("ChatManager");

		private static readonly Func<object?, object?>? GetInstance = MemberGetter(ChatManagerType, "instance");

		private static readonly Func<object?, object?>? GetChatActive = MemberGetter(ChatManagerType, "chatActive");

		private static readonly Func<object?, object?>? GetChatState = MemberGetter(ChatManagerType, "chatState");

		public static bool Available
		{
			get
			{
				if (GetInstance != null)
				{
					if (GetChatActive == null)
					{
						return GetChatState != null;
					}
					return true;
				}
				return false;
			}
		}

		public static bool IsTyping()
		{
			if (!Available)
			{
				return false;
			}
			try
			{
				object obj = GetInstance(null);
				if (obj == null)
				{
					return false;
				}
				if (GetChatActive != null)
				{
					object obj2 = GetChatActive(obj);
					bool flag = default(bool);
					int num;
					if (obj2 is bool)
					{
						flag = (bool)obj2;
						num = 1;
					}
					else
					{
						num = 0;
					}
					return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
				}
				object obj3 = GetChatState(obj);
				return obj3 != null && Convert.ToInt32(obj3) != 0;
			}
			catch (Exception)
			{
				return false;
			}
		}

		private static Func<object?, object?>? MemberGetter(Type? type, string name)
		{
			if (type == null)
			{
				return null;
			}
			FieldInfo field = AccessTools.Field(type, name);
			if (field != null)
			{
				return (object? instance) => field.GetValue(instance);
			}
			MethodInfo getter = AccessTools.Property(type, name)?.GetGetMethod(nonPublic: true);
			if (getter != null)
			{
				return (object? instance) => getter.Invoke(instance, null);
			}
			return null;
		}
	}
	internal sealed class KeyCombo
	{
		private readonly Key _key;

		private readonly Key[][] _modifiers;

		private static readonly Dictionary<string, Key[]> ModifierAliases = new Dictionary<string, Key[]>(StringComparer.OrdinalIgnoreCase)
		{
			["ctrl"] = (Key[])(object)new Key[2]
			{
				(Key)55,
				(Key)56
			},
			["control"] = (Key[])(object)new Key[2]
			{
				(Key)55,
				(Key)56
			},
			["shift"] = (Key[])(object)new Key[2]
			{
				(Key)51,
				(Key)52
			},
			["alt"] = (Key[])(object)new Key[2]
			{
				(Key)53,
				(Key)54
			}
		};

		private KeyCombo(Key key, Key[][] modifiers)
		{
			//IL_0007: 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)
			_key = key;
			_modifiers = modifiers;
		}

		public static bool TryParse(string? value, out KeyCombo combo, out string error)
		{
			//IL_0105: 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_011d: 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_00c5: Expected I4, but got Unknown
			combo = null;
			error = "";
			string[] array = (from p in (value ?? "").Split(new char[1] { '+' }, StringSplitOptions.RemoveEmptyEntries)
				select p.Trim() into p
				where p.Length > 0
				select p).ToArray();
			if (array.Length == 0)
			{
				error = "no key name given";
				return false;
			}
			List<Key[]> list = new List<Key[]>();
			for (int num = 0; num < array.Length - 1; num++)
			{
				if (ModifierAliases.TryGetValue(array[num], out Key[] value2))
				{
					list.Add(value2);
					continue;
				}
				if (Enum.TryParse<Key>(array[num], ignoreCase: true, out Key result) && (int)result != 0)
				{
					list.Add((Key[])(object)new Key[1] { (Key)(int)result });
					continue;
				}
				error = "'" + array[num] + "' is not a modifier (Ctrl/Shift/Alt) or a UnityEngine.InputSystem.Key name";
				return false;
			}
			string text = array[^1];
			if (!Enum.TryParse<Key>(text, ignoreCase: true, out Key result2) || (int)result2 == 0)
			{
				error = "'" + text + "' is not a UnityEngine.InputSystem.Key name";
				return false;
			}
			combo = new KeyCombo(result2, list.ToArray());
			return true;
		}

		public bool WasPressedThisFrame(Keyboard keyboard)
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			if (!((ButtonControl)keyboard[_key]).wasPressedThisFrame)
			{
				return false;
			}
			Key[][] modifiers = _modifiers;
			for (int i = 0; i < modifiers.Length; i++)
			{
				if (!modifiers[i].Any((Key k) => ((ButtonControl)keyboard[k]).isPressed))
				{
					return false;
				}
			}
			return true;
		}

		public override string ToString()
		{
			//IL_0030: 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)
			return string.Join("+", _modifiers.Select((Key[] m) => ((object)Unsafe.As<Key, Key>(ref m[0])/*cast due to .constrained prefix*/).ToString()).Append(((object)_key/*cast due to .constrained prefix*/).ToString()));
		}
	}
	internal static class PlayerReflection
	{
		private static readonly FieldInfo? TumbleField = AccessTools.Field(typeof(PlayerAvatar), "tumble");

		private static readonly FieldInfo? IsTumblingField = AccessTools.Field(typeof(PlayerAvatar), "isTumbling");

		private static readonly FieldInfo? DeadSetField = AccessTools.Field(typeof(PlayerAvatar), "deadSet");

		public static bool Ready
		{
			get
			{
				if (TumbleField != null && IsTumblingField != null)
				{
					return DeadSetField != null;
				}
				return false;
			}
		}

		public static PlayerTumble? GetTumble(PlayerAvatar avatar)
		{
			object? obj = TumbleField?.GetValue(avatar);
			return (PlayerTumble?)((obj is PlayerTumble) ? obj : null);
		}

		public static bool IsTumbling(PlayerAvatar avatar)
		{
			if (IsTumblingField != null)
			{
				return (bool)IsTumblingField.GetValue(avatar);
			}
			return false;
		}

		public static bool IsDead(PlayerAvatar avatar)
		{
			if (DeadSetField != null)
			{
				return (bool)DeadSetField.GetValue(avatar);
			}
			return false;
		}
	}
	[BepInPlugin("Trippy", "Trippy", "1.0.0")]
	public class Plugin : BaseUnityPlugin
	{
		private const string DefaultTripKey = "G";

		internal static ManualLogSource Log;

		internal static ConfigEntry<string> TripKeyName;

		internal static ConfigEntry<float> Range;

		internal static ConfigEntry<float> Cooldown;

		internal static ConfigEntry<bool> IncludeSelf;

		internal static ConfigEntry<bool> IgnoreWhileTyping;

		private KeyCombo _tripKey;

		private float _cooldownTimer;

		private void Awake()
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			TripKeyName = ((BaseUnityPlugin)this).Config.Bind<string>("General", "TripKey", "G", "Key that trips nearby players. Any UnityEngine.InputSystem.Key name (e.g. G, Semicolon, F9), optionally with modifiers (e.g. Ctrl+G, LeftAlt+Shift+T). Applies as soon as it's changed - no restart needed.");
			Range = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Range", 6f, new ConfigDescription("How far from you (in meters) other players get tripped.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 25f), Array.Empty<object>()));
			Cooldown = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Cooldown", 1.5f, new ConfigDescription("Minimum seconds between trips, so holding/mashing the key doesn't spam RPCs.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
			IncludeSelf = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "IncludeSelf", false, "If true, you also trip yourself along with anyone nearby.");
			IgnoreWhileTyping = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "IgnoreWhileTyping", true, "If true, the trip key does nothing while the in-game chat box is open, so typing a message can't trip the lobby.");
			ApplyTripKey();
			TripKeyName.SettingChanged += delegate
			{
				ApplyTripKey();
			};
			if (IgnoreWhileTyping.Value && !InputGuard.Available)
			{
				Log.LogWarning((object)"Couldn't find the game's ChatManager, so IgnoreWhileTyping can't do anything - the trip key will also fire while typing in chat. Bind TripKey to a function key or a modifier combo if that's a problem.");
			}
			if (!PlayerReflection.Ready)
			{
				Log.LogWarning((object)"PlayerAvatar's tumble/isTumbling/deadSet fields weren't found; a game update likely renamed them. Trippy will stay loaded but do nothing.");
			}
			Log.LogInfo((object)string.Format("{0} {1} loaded. Press {2} to trip nearby players.", "Trippy", "1.0.0", _tripKey));
		}

		private void ApplyTripKey()
		{
			if (KeyCombo.TryParse(TripKeyName.Value, out KeyCombo combo, out string error))
			{
				_tripKey = combo;
			}
			else if (_tripKey == null)
			{
				KeyCombo.TryParse("G", out _tripKey, out string _);
				Log.LogWarning((object)$"Invalid TripKey '{TripKeyName.Value}' ({error}); using {_tripKey} instead.");
			}
			else
			{
				Log.LogWarning((object)$"Invalid TripKey '{TripKeyName.Value}' ({error}); keeping {_tripKey}.");
			}
		}

		private void Update()
		{
			if (_cooldownTimer > 0f)
			{
				_cooldownTimer -= Time.deltaTime;
				return;
			}
			Keyboard current = Keyboard.current;
			if (current != null && _tripKey != null && _tripKey.WasPressedThisFrame(current) && (!IgnoreWhileTyping.Value || !InputGuard.IsTyping()))
			{
				int num = TripAction.TripNearby(Range.Value, IncludeSelf.Value);
				_cooldownTimer = Cooldown.Value;
				if (num > 0)
				{
					Log.LogInfo((object)$"Tripped {num} nearby player(s).");
				}
			}
		}
	}
	internal static class TripAction
	{
		public static int TripNearby(float range, bool includeSelf)
		{
			//IL_0021: 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_002f: Unknown result type (might be due to invalid IL or missing references)
			if (!PlayerReflection.Ready)
			{
				return 0;
			}
			PlayerAvatar val = SemiFunc.PlayerAvatarLocal();
			if ((Object)(object)val == (Object)null)
			{
				return 0;
			}
			List<PlayerAvatar> list = SemiFunc.PlayerGetAllPlayerAvatarWithinRange(range, ((Component)val).transform.position, false, default(LayerMask));
			int num = 0;
			foreach (PlayerAvatar item in list)
			{
				if (!((Object)(object)item == (Object)null) && (!((Object)(object)item == (Object)(object)val) || includeSelf) && !PlayerReflection.IsDead(item) && !PlayerReflection.IsTumbling(item))
				{
					PlayerTumble tumble = PlayerReflection.GetTumble(item);
					if (!((Object)(object)tumble == (Object)null))
					{
						tumble.TumbleRequest(true, false);
						num++;
					}
				}
			}
			return num;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "Trippy";

		public const string PLUGIN_NAME = "Trippy";

		public const string PLUGIN_VERSION = "1.0.0";
	}
}