Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Repo Gameplay Tweaks v1.0.4
RepoGameplayTweaks.dll
Decompiled 8 hours agousing System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace RepoGameplayTweaks; [BepInPlugin("RepoGameplayTweaks", "Repo Gameplay Tweaks", "1.0.4")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "RepoGameplayTweaks"; public const string PluginName = "Repo Gameplay Tweaks"; public const string PluginVersion = "1.0.4"; internal static ManualLogSource Log; internal static ConfigEntry<bool> ModEnabled; internal static ConfigEntry<string> TargetNames; internal static ConfigEntry<int> LowestLevel; private static string[] _targets = new string[0]; private static string[] _targetsNorm = new string[0]; private static ConfigFile _config; internal static int PatchedCount; internal static volatile string PendingReversedName; private static DateTime _configWriteTime; private static readonly HashSet<string> _loggedChecks = new HashSet<string>(); [ThreadStatic] private static bool _busy; private Harmony _harmony; private void Awake() { //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; _config = ((BaseUnityPlugin)this).Config; ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Turn the reversed upgrades on or off."); TargetNames = ((BaseUnityPlugin)this).Config.Bind<string>("General", "TargetPlayerNames", "Nyxeon", "Comma-separated player names (or Steam IDs) to prank. Capitals, spaces and symbols are ignored, so 'Nyxeon', 'nyxeon' and 'NYXEON' all match. Changes apply without restarting the game."); LowestLevel = ((BaseUnityPlugin)this).Config.Bind<int>("General", "LowestUpgradeLevel", -3, "How far below zero an upgrade level can go. Lower = harsher. Very low values (e.g. -5 health or stamina) can leave a stat at zero."); RefreshTargets(); TargetNames.SettingChanged += delegate { RefreshTargets(); }; try { _configWriteTime = File.GetLastWriteTimeUtc(((BaseUnityPlugin)this).Config.ConfigFilePath); } catch { } _harmony = new Harmony("RepoGameplayTweaks"); PatchUpgradeMethods(); Start("Pranks", StartPranks); Start("Startup check", StartIndicator); Start("Weapon hotkey", StartPerks); } private static void Start(string feature, Action start) { try { start(); } catch (Exception ex) { Log.LogError((object)(feature + " failed to start: " + ex)); } } [MethodImpl(MethodImplOptions.NoInlining)] private void StartPranks() { Pranks.Init(((BaseUnityPlugin)this).Config, _harmony); } [MethodImpl(MethodImplOptions.NoInlining)] private void StartIndicator() { Indicator.Init(((BaseUnityPlugin)this).Config); } [MethodImpl(MethodImplOptions.NoInlining)] private void StartPerks() { Perks.Init(((BaseUnityPlugin)this).Config); } private static void RefreshTargets() { _targets = (from n in (TargetNames.Value ?? string.Empty).Split(',') select n.Trim() into n where n.Length > 0 select n).ToArray(); _targetsNorm = _targets.Select(Norm).ToArray(); _loggedChecks.Clear(); Log.LogInfo((object)("Target players: " + ((_targets.Length != 0) ? string.Join(", ", _targets) : "(none)"))); } internal static string TargetListText() { return (_targets.Length != 0) ? string.Join(", ", _targets) : "(none)"; } internal static void PollConfigFile() { try { DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(_config.ConfigFilePath); if (!(lastWriteTimeUtc == _configWriteTime)) { _configWriteTime = lastWriteTimeUtc; _config.Reload(); RefreshTargets(); Log.LogInfo((object)"Settings file changed, reloaded."); } } catch (Exception ex) { Log.LogWarning((object)("Couldn't reload settings: " + ex.Message)); } } private static string Norm(string s) { if (s == null) { return string.Empty; } return new string(s.Where(char.IsLetterOrDigit).Select(char.ToLowerInvariant).ToArray()); } private void PatchUpgradeMethods() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown Type type = AccessTools.TypeByName("PunManager"); if (type == null) { Log.LogError((object)"Couldn't find PunManager. The game may have updated; nothing was patched."); return; } HarmonyMethod val = new HarmonyMethod(typeof(Plugin).GetMethod("UpgradePrefix", BindingFlags.Static | BindingFlags.NonPublic)); int num = 0; foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type)) { if (!declaredMethod.Name.StartsWith("Upgrade") || declaredMethod.Name.EndsWith("RPC")) { continue; } ParameterInfo[] parameters = declaredMethod.GetParameters(); if (parameters.Length == 2 && !(parameters[0].ParameterType != typeof(string)) && !(parameters[1].ParameterType != typeof(int)) && !(declaredMethod.ReturnType != typeof(int))) { try { _harmony.Patch((MethodBase)declaredMethod, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)("Reversing: PunManager." + declaredMethod.Name)); num++; } catch (Exception ex) { Log.LogWarning((object)("Couldn't patch " + declaredMethod.Name + ": " + ex.Message)); } } } PatchedCount = num; if (num == 0) { Log.LogWarning((object)"No upgrade methods matched. The game may have changed how upgrades work."); } else { Log.LogInfo((object)("Repo Gameplay Tweaks loaded. Patched " + num + " upgrade types.")); } } private static bool UpgradePrefix(object __instance, MethodBase __originalMethod, object[] __args, ref int __result) { if (_busy || !ModEnabled.Value || __args == null || __args.Length < 2) { return true; } string text = __args[0] as string; if (!(__args[1] is int)) { return true; } int num = (int)__args[1]; if (num <= 0 || !IsTargetPlayer(text)) { return true; } _busy = true; try { int num2 = (int)__originalMethod.Invoke(__instance, new object[2] { text, -num }); int value = LowestLevel.Value; if (num2 < value) { num2 = (int)__originalMethod.Invoke(__instance, new object[2] { text, value - num2 }); } __result = num2; Log.LogInfo((object)(__originalMethod.Name + " reversed for " + text + " -> level " + num2)); PendingReversedName = GetPlayerName(text) ?? "the target"; return false; } catch (Exception ex) { Log.LogError((object)("Reverse failed, letting the normal upgrade through: " + ex)); return true; } finally { _busy = false; } } private static bool IsTargetPlayer(string steamId) { if (string.IsNullOrEmpty(steamId) || _targets.Length == 0) { return false; } string playerName = GetPlayerName(steamId); bool flag = IdIsTarget(steamId) || NameIsTarget(playerName); string item = steamId + "|" + playerName + "|" + flag; if (_loggedChecks.Add(item)) { Log.LogInfo((object)("Upgrade by '" + (playerName ?? "?") + "' (Steam ID " + steamId + "): " + ((!flag) ? "not a target" : "TARGET, reversing"))); } return flag; } internal static bool IdIsTarget(string steamId) { return !string.IsNullOrEmpty(steamId) && _targets.Any((string t) => t == steamId.Trim()); } internal static bool NameIsTarget(string name) { if (string.IsNullOrEmpty(name) || _targets.Length == 0) { return false; } string n = Norm(name); if (n.Length > 0 && _targetsNorm.Any((string t) => t.Length > 0 && t == n)) { return true; } name = name.Trim(); return _targets.Any((string t) => string.Equals(t, name, StringComparison.OrdinalIgnoreCase)); } internal static bool AvatarIsTarget(object avatar) { if (IsMissing(avatar)) { return false; } if (NameIsTarget(AvatarName(avatar))) { return true; } Type type = AccessTools.TypeByName("SemiFunc"); return type != null && IdIsTarget(GetSteamId(type, avatar)); } private static string GetPlayerName(string steamId) { Type type = AccessTools.TypeByName("SemiFunc"); if (type == null) { return null; } object obj = null; MethodInfo methodInfo = AccessTools.Method(type, "PlayerAvatarGetFromSteamID", new Type[1] { typeof(string) }, (Type[])null); if (methodInfo != null) { obj = methodInfo.Invoke(null, new object[1] { steamId }); } if (IsMissing(obj)) { obj = null; if (AccessTools.Method(type, "PlayerGetAll", (Type[])null, (Type[])null)?.Invoke(null, null) is IEnumerable enumerable) { foreach (object item in enumerable) { if (!IsMissing(item) && GetSteamId(type, item) == steamId) { obj = item; break; } } } } return AvatarName(obj); } internal static string AvatarName(object avatar) { if (IsMissing(avatar)) { return null; } Type type = AccessTools.TypeByName("SemiFunc"); string text = Traverse.Create(avatar).Field("playerName").GetValue() as string; if (string.IsNullOrEmpty(text) && type != null) { MethodInfo methodInfo = AccessTools.Method(type, "PlayerGetName", (Type[])null, (Type[])null); if (methodInfo != null) { text = methodInfo.Invoke(null, new object[1] { avatar }) as string; } } return text; } internal static string GetSteamId(Type semiFunc, object avatar) { MethodInfo methodInfo = AccessTools.Method(semiFunc, "PlayerGetSteamID", (Type[])null, (Type[])null); if (methodInfo != null) { return methodInfo.Invoke(null, new object[1] { avatar }) as string; } return Traverse.Create(avatar).Field("steamID").GetValue() as string; } internal static bool IsMissing(object obj) { if (obj == null) { return true; } Object val = (Object)((obj is Object) ? obj : null); return val != (Object)null && val == (Object)null; } } internal class Pranks : MonoBehaviour { private static ConfigEntry<bool> _butterOn; private static ConfigEntry<bool> _drunkOn; private static ConfigEntry<bool> _tumbleOn; private static ConfigEntry<bool> _staminaOn; private static ConfigEntry<bool> _ghostOn; private static ConfigEntry<bool> _mapOn; private static ConfigEntry<bool> _mapDecoys; private static ConfigEntry<float> _butterAvg; private static ConfigEntry<float> _drunkAvg; private static ConfigEntry<float> _drunkLength; private static ConfigEntry<float> _driftStrength; private static ConfigEntry<float> _tumbleAvg; private static ConfigEntry<float> _drainMult; private static ConfigEntry<float> _regenMult; private static ConfigEntry<float> _ghostAvg; private static ConfigEntry<float> _ghostVolume; private static ConfigEntry<float> _mapHideChance; internal static bool ControlsSwapped; private static Type _semiFunc; private static Type _playerAvatar; private static Type _playerController; private static Type _physGrabber; private static Type _mapValuable; private object _avatar; private bool _isTarget; private bool _inLevel; private float _configTimer; private bool _checkedOldMod; private string _lastStatus; private float _checkTimer; private float _drunkTimer; private float _tumbleEndTimer; private float _mapTimer; private float _ghostScanTimer; private float _lastEnergy = -1f; private object _tumblingObject; private List<AudioClip> _ghostClips = new List<AudioClip>(); private readonly Dictionary<int, bool> _mapDecided = new Dictionary<int, bool>(); private readonly List<GameObject> _decoys = new List<GameObject>(); private static readonly string[] GhostWords = new string[13] { "footstep", "step", "growl", "scream", "breath", "whisper", "monster", "enemy", "creak", "knock", "door", "groan", "laugh" }; private readonly HashSet<string> _broken = new HashSet<string>(); public static void Init(ConfigFile cfg, Harmony harmony) { //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Expected O, but got Unknown _butterOn = cfg.Bind<bool>("1. Butterfingers", "Enabled", true, "Randomly drop whatever is being held."); _butterAvg = cfg.Bind<float>("1. Butterfingers", "AverageSecondsBetweenDrops", 45f, "Average seconds of holding something before it slips."); _drunkOn = cfg.Bind<bool>("4. Drunk Walk", "Enabled", true, "Left/right controls swap now and then, with a sideways drift."); _drunkAvg = cfg.Bind<float>("4. Drunk Walk", "AverageSecondsBetweenSpells", 120f, "Average seconds between drunk spells."); _drunkLength = cfg.Bind<float>("4. Drunk Walk", "SpellLengthSeconds", 8f, "How long each drunk spell lasts."); _driftStrength = cfg.Bind<float>("4. Drunk Walk", "DriftStrength", 4f, "How hard the sideways drift pushes. 0 = no drift."); _tumbleOn = cfg.Bind<bool>("5. Random Tumbles", "Enabled", true, "Trip into a tumble for no reason."); _tumbleAvg = cfg.Bind<float>("5. Random Tumbles", "AverageSecondsBetweenTrips", 180f, "Average seconds between trips."); _staminaOn = cfg.Bind<bool>("6. Shrinking Stamina", "Enabled", true, "Stamina drains faster and refills slower."); _drainMult = cfg.Bind<float>("6. Shrinking Stamina", "DrainMultiplier", 1.4f, "1.4 = stamina drains 40% faster."); _regenMult = cfg.Bind<float>("6. Shrinking Stamina", "RegenMultiplier", 0.6f, "0.6 = stamina refills at 60% speed."); _ghostOn = cfg.Bind<bool>("11. Ghost Sounds", "Enabled", true, "Play creepy game sounds behind the player. Only they hear them."); _ghostAvg = cfg.Bind<float>("11. Ghost Sounds", "AverageSecondsBetweenSounds", 75f, "Average seconds between ghost sounds."); _ghostVolume = cfg.Bind<float>("11. Ghost Sounds", "Volume", 0.8f, "0 to 1."); _mapOn = cfg.Bind<bool>("13. Map Lies", "Enabled", true, "Hide some valuables from the map."); _mapHideChance = cfg.Bind<float>("13. Map Lies", "HideChance", 0.4f, "Chance (0 to 1) that each valuable is hidden from the map."); _mapDecoys = cfg.Bind<bool>("13. Map Lies", "FakeMarkers", true, "Put a fake marker in the wrong spot for each hidden one."); _semiFunc = AccessTools.TypeByName("SemiFunc"); _playerAvatar = AccessTools.TypeByName("PlayerAvatar"); _playerController = AccessTools.TypeByName("PlayerController"); _physGrabber = AccessTools.TypeByName("PhysGrabber"); _mapValuable = AccessTools.TypeByName("MapValuable"); PatchMovementInput(harmony); GameObject val = new GameObject("RepoGameplayTweaks.Pranks"); ((Object)val).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)val); val.AddComponent<Pranks>(); } private void Update() { float dt = Time.deltaTime; if (!_checkedOldMod) { _checkedOldMod = true; try { if (Chainloader.PluginInfos.ContainsKey("RepoOptimization")) { Plugin.Log.LogError((object)"The old 'Repo Optimization' mod is also installed! Uninstall it in r2modman, or the two mods cancel each other out."); } } catch { } } _configTimer -= dt; if (_configTimer <= 0f) { _configTimer = 2f; Plugin.PollConfigFile(); } _checkTimer -= dt; if (_checkTimer <= 0f) { _checkTimer = 1f; _avatar = GetLocalAvatar(); _isTarget = Plugin.ModEnabled.Value && Plugin.AvatarIsTarget(_avatar); _inLevel = IsInLevel(); if (_avatar != null) { string text = "You are '" + Plugin.AvatarName(_avatar) + "': " + ((!_isTarget) ? "not a target, pranks are off" : "you ARE a target, pranks are ON"); if (text != _lastStatus) { _lastStatus = text; Plugin.Log.LogInfo((object)text); } } } if (!_isTarget || !_inLevel) { ControlsSwapped = false; _lastEnergy = -1f; return; } Safe("Butterfingers", delegate { if (_butterOn.Value) { Butterfingers(); } }); Safe("Drunk walk", delegate { DrunkWalk(dt); }); Safe("Random tumbles", delegate { RandomTumbles(dt); }); Safe("Ghost sounds", delegate { if (_ghostOn.Value) { GhostSounds(dt); } }); Safe("Map lies", delegate { if (_mapOn.Value) { MapLies(dt); } }); } private void LateUpdate() { if (!_isTarget || !_inLevel) { return; } Safe("Shrinking stamina", delegate { if (_staminaOn.Value) { ShrinkingStamina(); } else { _lastEnergy = -1f; } }); } private void FixedUpdate() { if (!_isTarget || !_inLevel || !ControlsSwapped || _driftStrength.Value <= 0f) { return; } Safe("Drunk drift", delegate { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) object field = GetField(StaticInstance(_playerController), "rb"); Rigidbody val = (Rigidbody)((field is Rigidbody) ? field : null); Camera main = Camera.main; if (!((Object)(object)val == (Object)null) && !((Object)(object)main == (Object)null)) { Vector3 right = ((Component)main).transform.right; right.y = 0f; float num = Mathf.Sin(Time.time * 1.3f); val.AddForce(((Vector3)(ref right)).normalized * num * _driftStrength.Value, (ForceMode)5); } }); } private void Butterfingers() { object obj = StaticInstance(_physGrabber); if (Plugin.IsMissing(obj)) { return; } object field = GetField(obj, "grabbed"); if (field is bool && (bool)field && Roll(_butterAvg.Value)) { MethodInfo methodInfo = AccessTools.GetDeclaredMethods(_physGrabber).FirstOrDefault((MethodInfo m) => m.Name == "ReleaseObject"); if (methodInfo != null) { methodInfo.Invoke(obj, DefaultArgs(methodInfo)); } } } private void DrunkWalk(float dt) { if (!_drunkOn.Value) { ControlsSwapped = false; } else if (ControlsSwapped) { _drunkTimer -= dt; if (_drunkTimer <= 0f) { ControlsSwapped = false; } } else if (Roll(_drunkAvg.Value)) { ControlsSwapped = true; _drunkTimer = _drunkLength.Value; } } private static void PatchMovementInput(Harmony harmony) { //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Expected O, but got Unknown Type type = AccessTools.TypeByName("InputManager"); List<MethodInfo> list = new List<MethodInfo>(); if (type != null) { list.Add(AccessTools.Method(type, "GetMovementX", (Type[])null, (Type[])null)); list.Add(AccessTools.Method(type, "GetMovement", (Type[])null, (Type[])null)); } if (_semiFunc != null) { list.Add(AccessTools.Method(_semiFunc, "InputMovementX", (Type[])null, (Type[])null)); } foreach (MethodInfo item in list) { if (item == null) { continue; } string text = ((item.ReturnType == typeof(float)) ? "FlipFloat" : ((!(item.ReturnType == typeof(Vector2))) ? null : "FlipVector2")); if (text != null) { try { MethodInfo methodInfo = item; HarmonyMethod val = new HarmonyMethod(typeof(Pranks).GetMethod(text, BindingFlags.Static | BindingFlags.NonPublic)); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log.LogInfo((object)("Drunk walk hooked into " + item.DeclaringType.Name + "." + item.Name)); return; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Couldn't hook " + item.Name + ": " + ex.Message)); } } } Plugin.Log.LogWarning((object)"Drunk walk: no movement input found to swap, so only the drift will happen."); } private static void FlipFloat(ref float __result) { if (ControlsSwapped) { __result = 0f - __result; } } private static void FlipVector2(ref Vector2 __result) { if (ControlsSwapped) { __result.x = 0f - __result.x; } } private void RandomTumbles(float dt) { if (_tumblingObject != null) { _tumbleEndTimer -= dt; if (_tumbleEndTimer <= 0f) { InvokeTumble(_tumblingObject, start: false); _tumblingObject = null; } } else { if (!_tumbleOn.Value || !Roll(_tumbleAvg.Value)) { return; } object field = GetField(_avatar, "tumble"); if (!Plugin.IsMissing(field)) { object field2 = GetField(field, "isTumbling"); if ((!(field2 is bool) || !(bool)field2) && InvokeTumble(field, start: true)) { _tumblingObject = field; _tumbleEndTimer = Random.Range(1.5f, 3f); } } } } private static bool InvokeTumble(object tumble, bool start) { MethodInfo methodInfo = AccessTools.GetDeclaredMethods(tumble.GetType()).FirstOrDefault((MethodInfo m) => m.Name == "TumbleRequest"); if (methodInfo == null) { return false; } object[] array = DefaultArgs(methodInfo); if (array.Length > 0 && array[0] is bool) { array[0] = start; } if (array.Length > 1 && array[1] is bool) { array[1] = false; } methodInfo.Invoke(tumble, array); return true; } private void ShrinkingStamina() { object obj = StaticInstance(_playerController); FieldInfo fieldInfo = ((!(_playerController != null)) ? null : AccessTools.Field(_playerController, "EnergyCurrent")); if (Plugin.IsMissing(obj) || fieldInfo == null || fieldInfo.FieldType != typeof(float)) { return; } float num = (float)fieldInfo.GetValue(obj); if (_lastEnergy >= 0f) { float num2 = num - _lastEnergy; if (num2 > 0f && num2 < 20f) { num = _lastEnergy + num2 * _regenMult.Value; } else if (num2 < 0f) { num = Mathf.Max(0f, _lastEnergy + num2 * _drainMult.Value); } fieldInfo.SetValue(obj, num); } _lastEnergy = num; } private void GhostSounds(float dt) { //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) _ghostScanTimer -= dt; if (_ghostClips.Count == 0 && _ghostScanTimer <= 0f) { _ghostScanTimer = 30f; _ghostClips = (from c in Resources.FindObjectsOfTypeAll<AudioClip>() where (Object)(object)c != (Object)null && c.length > 0.2f && c.length < 8f && GhostWords.Any((string w) => ((Object)c).name.IndexOf(w, StringComparison.OrdinalIgnoreCase) >= 0) select c).ToList(); if (_ghostClips.Count > 0) { Plugin.Log.LogInfo((object)("Ghost sounds: found " + _ghostClips.Count + " creepy clips.")); } } if (_ghostClips.Count == 0 || !Roll(_ghostAvg.Value)) { return; } Camera main = Camera.main; if (!((Object)(object)main == (Object)null)) { AudioClip val = _ghostClips[Random.Range(0, _ghostClips.Count)]; if ((Object)(object)val == (Object)null) { _ghostClips.Clear(); return; } Transform transform = ((Component)main).transform; Vector3 val2 = transform.position - transform.forward * Random.Range(3f, 7f) + transform.right * Random.Range(-3f, 3f); AudioSource.PlayClipAtPoint(val, val2, Mathf.Clamp01(_ghostVolume.Value)); } } private void MapLies(float dt) { _mapTimer -= dt; if (_mapTimer > 0f || _mapValuable == null) { return; } _mapTimer = 0.3f; Object[] array = Object.FindObjectsOfType(_mapValuable); if (array.Length == 0) { _mapDecided.Clear(); _decoys.RemoveAll((GameObject d) => (Object)(object)d == (Object)null); return; } List<Component> list = (from c in array.OfType<Component>() where (Object)(object)c != (Object)null && (Object)(object)c.GetComponentInParent<Rigidbody>() == (Object)null select c).ToList(); foreach (Component item in list) { int instanceID = ((Object)item).GetInstanceID(); if (!_mapDecided.TryGetValue(instanceID, out var value)) { value = Random.value < _mapHideChance.Value; _mapDecided[instanceID] = value; if (value && _mapDecoys.Value && list.Count >= 2) { MakeDecoy(item, list); } } if (value) { Renderer[] componentsInChildren = item.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { val.enabled = false; } } } } private void MakeDecoy(Component marker, List<Component> all) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) GameObject val = Object.Instantiate<GameObject>(marker.gameObject, marker.transform.parent); MonoBehaviour[] componentsInChildren = val.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val2 in componentsInChildren) { Object.Destroy((Object)(object)val2); } Renderer[] componentsInChildren2 = val.GetComponentsInChildren<Renderer>(true); foreach (Renderer val3 in componentsInChildren2) { val3.enabled = true; } Vector3 position = all[Random.Range(0, all.Count)].transform.position; Vector3 position2 = all[Random.Range(0, all.Count)].transform.position; val.transform.position = Vector3.Lerp(position, position2, Random.Range(0.3f, 0.7f)); _decoys.Add(val); } private static bool Roll(float avgSeconds) { if (avgSeconds <= 0f) { return false; } return Random.value < Time.deltaTime / avgSeconds; } internal static object GetLocalAvatar() { if (_semiFunc != null) { MethodInfo methodInfo = AccessTools.Method(_semiFunc, "PlayerAvatarLocal", (Type[])null, (Type[])null); if (methodInfo != null) { object obj = methodInfo.Invoke(null, null); if (!Plugin.IsMissing(obj)) { return obj; } } } object obj2 = StaticInstance(_playerAvatar); return (!Plugin.IsMissing(obj2)) ? obj2 : null; } internal static bool IsInLevel() { if (_semiFunc == null) { return true; } MethodInfo methodInfo = AccessTools.Method(_semiFunc, "RunIsLevel", (Type[])null, (Type[])null); if (methodInfo == null) { return true; } object obj = methodInfo.Invoke(null, null); return !(obj is bool) || (bool)obj; } private static object StaticInstance(Type t) { if (t == null) { return null; } FieldInfo fieldInfo = AccessTools.Field(t, "instance") ?? AccessTools.Field(t, "Instance"); return (!(fieldInfo != null) || !fieldInfo.IsStatic) ? null : fieldInfo.GetValue(null); } private static object GetField(object obj, string name) { if (Plugin.IsMissing(obj)) { return null; } FieldInfo fieldInfo = AccessTools.Field(obj.GetType(), name); return (!(fieldInfo != null)) ? null : fieldInfo.GetValue(obj); } private static object[] DefaultArgs(MethodInfo m) { return (from p in m.GetParameters() select p.HasDefaultValue ? p.DefaultValue : ((!p.ParameterType.IsValueType) ? null : Activator.CreateInstance(p.ParameterType))).ToArray(); } private void Safe(string effect, Action action) { if (_broken.Contains(effect)) { return; } try { action(); } catch (Exception ex) { _broken.Add(effect); Plugin.Log.LogWarning((object)(effect + " stopped working and was turned off: " + ex.Message)); } } } internal class Perks : MonoBehaviour { private static ConfigEntry<bool> _enabled; private static ConfigEntry<KeyboardShortcut> _weaponKey; private static ConfigEntry<string> _itemFilter; private static ConfigEntry<string> _specificItem; private static Type _semiFunc; private static Type _statsManager; private static Type _photonNetwork; private float _cooldown; public static void Init(ConfigFile cfg) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown _enabled = cfg.Bind<bool>("Perk: Spawn Weapon", "Enabled", true, "Press the hotkey to spawn a weapon in front of you. Only works as the host or in single player."); _weaponKey = cfg.Bind<KeyboardShortcut>("Perk: Spawn Weapon", "Hotkey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Key to press."); _itemFilter = cfg.Bind<string>("Perk: Spawn Weapon", "ItemFilter", "gun,melee", "Comma-separated words. A random item whose name or type contains one of these is spawned."); _specificItem = cfg.Bind<string>("Perk: Spawn Weapon", "SpecificItem", string.Empty, "Leave blank for random. Or type an exact item name (e.g. Item Gun Shotgun) to always spawn that."); _semiFunc = AccessTools.TypeByName("SemiFunc"); _statsManager = AccessTools.TypeByName("StatsManager"); _photonNetwork = AccessTools.TypeByName("Photon.Pun.PhotonNetwork"); GameObject val = new GameObject("RepoGameplayTweaks.Perks"); ((Object)val).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)val); val.AddComponent<Perks>(); } private void Update() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) if (_cooldown > 0f) { _cooldown -= Time.deltaTime; } if (!Plugin.ModEnabled.Value || !_enabled.Value || _cooldown > 0f) { return; } KeyboardShortcut value = _weaponKey.Value; if (!((KeyboardShortcut)(ref value)).IsDown()) { return; } _cooldown = 0.5f; try { SpawnWeapon(); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Spawn weapon failed: " + ex.Message)); } } private static void SpawnWeapon() { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009b: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) object obj = AccessTools.Method(_semiFunc, "PlayerAvatarLocal", (Type[])null, (Type[])null)?.Invoke(null, null); if (Plugin.IsMissing(obj) || Plugin.AvatarIsTarget(obj)) { return; } if (!CallBool("IsMasterClientOrSingleplayer", fallback: true)) { Plugin.Log.LogWarning((object)"Spawn weapon only works when you're the host (or in single player)."); return; } object obj2 = PickItem(); if (obj2 == null) { Plugin.Log.LogWarning((object)"Spawn weapon: no item matched ItemFilter / SpecificItem."); return; } Camera main = Camera.main; if ((Object)(object)main == (Object)null) { return; } Vector3 val = ((Component)main).transform.position + ((Component)main).transform.forward * 1.5f; Quaternion identity = Quaternion.identity; string name = ((Object)obj2).name; object value = Traverse.Create(obj2).Field("prefab").GetValue(); GameObject val2 = (GameObject)((value is GameObject) ? value : null); string text; if ((Object)(object)val2 != (Object)null) { text = "Items/" + ((Object)val2).name; } else if (value != null) { Traverse val3 = Traverse.Create(value); text = (val3.Property("ResourcePath", (object[])null).GetValue() ?? val3.Field("resourcePath").GetValue()) as string; object value2 = val3.Property("Prefab", (object[])null).GetValue(); val2 = (GameObject)((value2 is GameObject) ? value2 : null); } else { text = "Items/" + name; } if (CallBool("IsMultiplayer", fallback: false)) { MethodInfo methodInfo = ((!(_photonNetwork == null)) ? AccessTools.GetDeclaredMethods(_photonNetwork).FirstOrDefault((MethodInfo m) => m.Name == "InstantiateRoomObject" && m.GetParameters().Length == 5) : null); if (methodInfo == null || string.IsNullOrEmpty(text)) { Plugin.Log.LogWarning((object)"Spawn weapon: couldn't find how to spawn items online."); return; } methodInfo.Invoke(null, new object[5] { text, val, identity, (byte)0, null }); } else { if ((Object)(object)val2 == (Object)null && !string.IsNullOrEmpty(text)) { val2 = Resources.Load<GameObject>(text); } if ((Object)(object)val2 == (Object)null) { Plugin.Log.LogWarning((object)("Spawn weapon: couldn't load " + name)); return; } Object.Instantiate<GameObject>(val2, val, identity); } Plugin.Log.LogInfo((object)("Spawned " + name)); } private static object PickItem() { object obj = ((_statsManager == null) ? null : AccessTools.Field(_statsManager, "instance")?.GetValue(null)); if (!(Traverse.Create(obj).Field("itemDictionary").GetValue() is IDictionary dictionary)) { return null; } List<object> source = (from object i in dictionary.Values where !Plugin.IsMissing(i) select i).ToList(); string specific = (_specificItem.Value ?? string.Empty).Trim(); if (specific.Length > 0) { return source.FirstOrDefault((object i) => string.Equals(((Object)i).name, specific, StringComparison.OrdinalIgnoreCase) || string.Equals(Traverse.Create(i).Field("itemName").GetValue() as string, specific, StringComparison.OrdinalIgnoreCase)); } string[] words = (from w in (_itemFilter.Value ?? string.Empty).Split(',') select w.Trim() into w where w.Length > 0 select w).ToArray(); List<object> list = source.Where(delegate(object i) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) string name = ((Object)i).name ?? string.Empty; string type = (Traverse.Create(i).Field("itemType").GetValue() ?? string.Empty).ToString(); return words.Any((string w) => name.IndexOf(w, StringComparison.OrdinalIgnoreCase) >= 0 || type.IndexOf(w, StringComparison.OrdinalIgnoreCase) >= 0); }).ToList(); return (list.Count != 0) ? list[Random.Range(0, list.Count)] : null; } private static bool CallBool(string method, bool fallback) { MethodInfo methodInfo = ((!(_semiFunc == null)) ? AccessTools.Method(_semiFunc, method, (Type[])null, (Type[])null) : null); if (methodInfo == null) { return fallback; } object obj = methodInfo.Invoke(null, null); return (!(obj is bool)) ? fallback : ((bool)obj); } } internal class Indicator : MonoBehaviour { private static ConfigEntry<bool> _enabled; private static ConfigEntry<bool> _sound; private static ConfigEntry<bool> _text; private static ConfigEntry<float> _volume; private static Indicator _instance; private AudioSource _source; private AudioClip _chime; private AudioClip _bwomp; private bool _wasInLevel; private float _levelCheckTimer; private string _message; private float _messageUntil; private GUIStyle _style; private GUIStyle _shadowStyle; private const int Rate = 44100; public static void Init(ConfigFile cfg) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown _enabled = cfg.Bind<bool>("Startup Check", "Enabled", true, "Show that the mod is working. Never shown to target players."); _sound = cfg.Bind<bool>("Startup Check", "PlaySounds", true, "Chime when a level starts, and a 'bwomp' when a target's upgrade gets reversed."); _text = cfg.Bind<bool>("Startup Check", "ShowText", true, "Small message in the top-left corner for a few seconds."); _volume = cfg.Bind<float>("Startup Check", "Volume", 0.5f, "0 to 1."); GameObject val = new GameObject("RepoGameplayTweaks.Indicator"); ((Object)val).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)val); _instance = val.AddComponent<Indicator>(); } private void Awake() { _source = ((Component)this).gameObject.AddComponent<AudioSource>(); _source.spatialBlend = 0f; _chime = MakeChime(); _bwomp = MakeBwomp(); } private void Update() { if (Plugin.PendingReversedName != null) { string pendingReversedName = Plugin.PendingReversedName; Plugin.PendingReversedName = null; if (ShouldSignal()) { Play(_bwomp); Show("Reversed " + pendingReversedName + "'s upgrade", 4f); } } _levelCheckTimer -= Time.deltaTime; if (!(_levelCheckTimer > 0f)) { _levelCheckTimer = 1f; bool flag = Pranks.IsInLevel() && !Plugin.IsMissing(Pranks.GetLocalAvatar()); if (flag && !_wasInLevel && ShouldSignal()) { Play(_chime); Show("Repo Gameplay Tweaks is working | Targets: " + Plugin.TargetListText() + " | " + Plugin.PatchedCount + " upgrade types hooked", 6f); } _wasInLevel = flag; } } private static bool ShouldSignal() { if (!Plugin.ModEnabled.Value || !_enabled.Value) { return false; } object localAvatar = Pranks.GetLocalAvatar(); return !Plugin.IsMissing(localAvatar) && !Plugin.AvatarIsTarget(localAvatar); } private void Play(AudioClip clip) { if (_sound.Value && (Object)(object)clip != (Object)null && (Object)(object)_source != (Object)null) { _source.PlayOneShot(clip, Mathf.Clamp01(_volume.Value)); } } private void Show(string message, float seconds) { Plugin.Log.LogInfo((object)message); if (_text.Value) { _message = message; _messageUntil = Time.time + seconds; } } private void OnGUI() { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) if (_message != null && !(Time.time > _messageUntil)) { if (_style == null) { GUIStyle val = new GUIStyle(GUI.skin.label); val.fontSize = 20; _style = val; _shadowStyle = new GUIStyle(_style); _shadowStyle.normal.textColor = new Color(0f, 0f, 0f, 0.8f); _style.normal.textColor = new Color(0.45f, 1f, 0.6f, 1f); } GUI.Label(new Rect(22f, 22f, 1200f, 40f), _message, _shadowStyle); GUI.Label(new Rect(20f, 20f, 1200f, 40f), _message, _style); } } private static AudioClip MakeChime() { float[] array = Tone(659.25f, 0.11f); float[] array2 = Tone(880f, 0.2f); float[] array3 = new float[array.Length + array2.Length]; Array.Copy(array, array3, array.Length); Array.Copy(array2, 0, array3, array.Length, array2.Length); return MakeClip("RGT_Chime", array3); } private static AudioClip MakeBwomp() { int num = 19844; float[] array = new float[num]; double num2 = 0.0; for (int i = 0; i < num; i++) { float num3 = (float)i / (float)num; float num4 = Mathf.Lerp(320f, 110f, num3); num2 += Math.PI * 2.0 * (double)num4 / 44100.0; float num5 = Mathf.Min(1f, (float)i / 441f) * (1f - num3); array[i] = (float)Math.Sin(num2) * 0.5f * num5 + (float)Math.Sin(num2 * 2.0) * 0.15f * num5; } return MakeClip("RGT_Bwomp", array); } private static float[] Tone(float freq, float seconds) { int num = (int)(44100f * seconds); float[] array = new float[num]; for (int i = 0; i < num; i++) { float num2 = (float)i / (float)num; float num3 = Mathf.Min(1f, (float)i / 220.5f) * (1f - num2) * (1f - num2); array[i] = (float)Math.Sin(Math.PI * 2.0 * (double)freq * (double)i / 44100.0) * 0.45f * num3; } return array; } private static AudioClip MakeClip(string name, float[] data) { AudioClip val = AudioClip.Create(name, data.Length, 1, 44100, false); val.SetData(data, 0); return val; } }