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? GetInstance = MemberGetter(ChatManagerType, "instance"); private static readonly Func? GetChatActive = MemberGetter(ChatManagerType, "chatActive"); private static readonly Func? 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? 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 ModifierAliases = new Dictionary(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 list = new List(); for (int num = 0; num < array.Length - 1; num++) { if (ModifierAliases.TryGetValue(array[num], out Key[] value2)) { list.Add(value2); continue; } if (Enum.TryParse(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(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(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 TripKeyName; internal static ConfigEntry Range; internal static ConfigEntry Cooldown; internal static ConfigEntry IncludeSelf; internal static ConfigEntry 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("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("General", "Range", 6f, new ConfigDescription("How far from you (in meters) other players get tripped.", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 25f), Array.Empty())); Cooldown = ((BaseUnityPlugin)this).Config.Bind("General", "Cooldown", 1.5f, new ConfigDescription("Minimum seconds between trips, so holding/mashing the key doesn't spam RPCs.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 10f), Array.Empty())); IncludeSelf = ((BaseUnityPlugin)this).Config.Bind("General", "IncludeSelf", false, "If true, you also trip yourself along with anyone nearby."); IgnoreWhileTyping = ((BaseUnityPlugin)this).Config.Bind("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 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"; } }