using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Pigeon.Movement;
using UnityEngine;
using UnityEngine.SceneManagement;
using XpScaling;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("HidePlayerExplosions")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+ae4467691bf4c871254e0db66c519e3d61aeb370")]
[assembly: AssemblyProduct("HidePlayerExplosions")]
[assembly: AssemblyTitle("HidePlayerExplosions")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[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 XpScaling
{
internal static class PatchGroup
{
public static bool TryApply(string harmonyId, Action<string> logError, params Type[] patches)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Expected O, but got Unknown
Harmony val = new Harmony(harmonyId);
try
{
foreach (Type type in patches)
{
val.PatchAll(type);
}
return true;
}
catch (Exception arg)
{
val.UnpatchSelf();
logError($"{harmonyId} is off, could not patch: {arg}");
return false;
}
}
}
}
namespace HidePlayerExplosions
{
internal enum Maker
{
Unknown,
Player,
Other
}
internal static class ExplosionRules
{
public const int Never = -2;
public const int Always = -1;
public static int VisualRule(string methodName, string[] parameterNames)
{
if (methodName.Contains("FirstPerson") || methodName.Contains("ClientSwitch"))
{
return -1;
}
for (int i = 0; i < parameterNames.Length; i++)
{
if (parameterNames[i] == "firstPerson")
{
return i;
}
}
return -2;
}
public static bool LeadsTo<T>(T source, Func<T, bool> isWanted, Func<T, T> baseOf, Func<T, T> parentOf, int maxDepth = 8) where T : class
{
int num = 0;
while (source != null && num < maxDepth)
{
if (isWanted(source))
{
return true;
}
T val = baseOf(source);
if (val != null && isWanted(val))
{
return true;
}
source = parentOf(source);
num++;
}
return false;
}
public static Maker EnterSourced(bool playerMade)
{
if (!playerMade)
{
return Maker.Other;
}
return Maker.Player;
}
public static Maker EnterVisual(Maker current, bool playerVisual)
{
if (!(current == Maker.Unknown && playerVisual))
{
return current;
}
return Maker.Player;
}
public static Maker EnterTarget(Maker current)
{
if (current != Maker.Player)
{
return current;
}
return Maker.Unknown;
}
}
internal sealed class Hider<TEffect, TPart>
{
private readonly Func<TEffect, TPart[]> partsOf;
private readonly Func<TPart, bool> isOn;
private readonly Action<TPart, bool> turn;
private readonly Dictionary<TEffect, TPart[]> parts = new Dictionary<TEffect, TPart[]>();
private readonly Dictionary<TEffect, List<TPart>> turnedOff = new Dictionary<TEffect, List<TPart>>();
public int Count => turnedOff.Count;
public Hider(Func<TEffect, TPart[]> partsOf, Func<TPart, bool> isOn, Action<TPart, bool> turn)
{
this.partsOf = partsOf;
this.isOn = isOn;
this.turn = turn;
}
public void Hide(TEffect effect)
{
if (!parts.TryGetValue(effect, out var value))
{
value = (parts[effect] = partsOf(effect));
}
if (!turnedOff.TryGetValue(effect, out var value2))
{
value2 = (turnedOff[effect] = new List<TPart>());
}
TPart[] array2 = value;
foreach (TPart val in array2)
{
if (isOn(val))
{
turn(val, arg2: false);
value2.Add(val);
}
}
}
public bool Show(TEffect effect)
{
if (!turnedOff.TryGetValue(effect, out var value))
{
return false;
}
turnedOff.Remove(effect);
foreach (TPart item in value)
{
turn(item, arg2: true);
}
return true;
}
public void Forget(Func<TEffect, bool> gone)
{
foreach (TEffect item in parts.Keys.Where(gone).ToList())
{
parts.Remove(item);
turnedOff.Remove(item);
}
}
}
[MycoMod(/*Could not decode attribute arguments.*/)]
[BepInPlugin("hideplayerexplosions", "HidePlayerExplosions", "0.1.4")]
[BepInProcess("Mycopunk.exe")]
public class Plugin : BaseUnityPlugin
{
[HarmonyPatch]
private static class SourcedExplosionPatch
{
private static IEnumerable<MethodBase> TargetMethods()
{
return Found(from m in AccessTools.GetDeclaredMethods(typeof(GameManager))
where m.Name.StartsWith("SpawnExplosion") && m.GetParameters().Any((ParameterInfo p) => p.Name == "source" && p.ParameterType == typeof(IDamageSource))
select m, "sourced explosion methods");
}
private static void Prefix(IDamageSource source, out Maker? __state)
{
__state = maker;
maker = ExplosionRules.EnterSourced(IsPlayerMade(source));
}
private static void Finalizer(Maker? __state)
{
Restore(__state);
}
}
[HarmonyPatch]
private static class BulletExplosionPatch
{
private static IEnumerable<MethodBase> TargetMethods()
{
return Found(Find(), "bullet Detonate and OnFire methods");
}
private static IEnumerable<MethodBase> Find()
{
Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(typeof(IBullet).Assembly);
foreach (Type type in typesFromAssembly)
{
if (!type.IsClass || !typeof(IBullet).IsAssignableFrom(type))
{
continue;
}
foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type))
{
if (!declaredMethod.IsStatic && !declaredMethod.IsAbstract && !declaredMethod.IsGenericMethod && (declaredMethod.Name == "Detonate" || declaredMethod.Name == "OnFire"))
{
yield return declaredMethod;
}
}
}
}
private static void Prefix(IDamageSource __instance, out Maker? __state)
{
__state = maker;
maker = ExplosionRules.EnterSourced(IsPlayerMade(__instance));
}
private static void Finalizer(Maker? __state)
{
Restore(__state);
}
}
[HarmonyPatch]
private static class TargetDamagePatch
{
private static IEnumerable<MethodBase> TargetMethods()
{
return Found(Find(), "target Damage methods");
}
private static IEnumerable<MethodBase> Find()
{
Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(typeof(ITarget).Assembly);
foreach (Type type in typesFromAssembly)
{
if (!type.IsClass || !typeof(ITarget).IsAssignableFrom(type))
{
continue;
}
foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type))
{
if (!declaredMethod.IsStatic && !declaredMethod.IsAbstract && !declaredMethod.IsGenericMethod && (declaredMethod.Name == "Damage" || declaredMethod.Name.EndsWith(".Damage")) && declaredMethod.GetParameters().Any((ParameterInfo p) => p.ParameterType == typeof(IDamageSource)))
{
yield return declaredMethod;
}
}
}
}
private static void Prefix(out Maker? __state)
{
__state = maker;
maker = ExplosionRules.EnterTarget(maker);
}
private static void Finalizer(Maker? __state)
{
Restore(__state);
}
}
[HarmonyPatch]
private static class OwnedVisualPatch
{
private static IEnumerable<MethodBase> TargetMethods()
{
return Found(VisualMethods((int rule) => rule == -1), "owner-switching explosion methods");
}
private static void Prefix(out Maker? __state)
{
__state = maker;
maker = ExplosionRules.EnterVisual(maker, playerVisual: true);
}
private static void Finalizer(Maker? __state)
{
Restore(__state);
}
}
[HarmonyPatch]
private static class FirstPersonFlagPatch
{
private static IEnumerable<MethodBase> TargetMethods()
{
return Found(VisualMethods((int rule) => rule >= 0), "first-person explosion methods");
}
private static void Prefix(bool firstPerson, out Maker? __state)
{
__state = maker;
maker = ExplosionRules.EnterVisual(maker, firstPerson);
}
private static void Finalizer(Maker? __state)
{
Restore(__state);
}
}
[HarmonyPatch]
private static class ExplosionPrefabPatch
{
private static IEnumerable<MethodBase> TargetMethods()
{
return Found(from m in AccessTools.GetDeclaredMethods(typeof(Global))
where m.ReturnType == typeof(BurstEffect) && (m.Name == "GetExplosionEffect" || m.Name == "get_DefaultExplosionEffect")
select m, "explosion effect lookups");
}
private static void Postfix(BurstEffect __result)
{
if ((Object)(object)__result != (Object)null)
{
explosionPrefabs.Add(__result);
}
}
}
[HarmonyPatch]
private static class BurstEffectSpawnPatch
{
private static IEnumerable<MethodBase> TargetMethods()
{
return Found(Find(), "effect spawn methods");
}
private static IEnumerable<MethodBase> Find()
{
foreach (Type item in BurstEffectTypes())
{
foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(item))
{
ParameterInfo[] parameters = declaredMethod.GetParameters();
if (declaredMethod.IsStatic && !declaredMethod.IsGenericMethod && typeof(BurstEffect).IsAssignableFrom(declaredMethod.ReturnType) && parameters.Length != 0 && typeof(BurstEffect).IsAssignableFrom(parameters[0].ParameterType))
{
yield return declaredMethod;
}
}
}
}
private static void Postfix(BurstEffect __0, BurstEffect __result)
{
HideOrShow(__0, __result, atSpawn: true);
}
}
[HarmonyPatch]
private static class BurstEffectPlayPatch
{
private static IEnumerable<MethodBase> TargetMethods()
{
return Found(Find(), "effect Play methods");
}
private static IEnumerable<MethodBase> Find()
{
foreach (Type item in BurstEffectTypes())
{
foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(item))
{
if (!declaredMethod.IsStatic && !declaredMethod.IsAbstract && !declaredMethod.IsGenericMethod && declaredMethod.Name == "Play")
{
yield return declaredMethod;
}
}
}
}
private static void Prefix(BurstEffect __instance, out bool __state)
{
__state = __instance.isPlaying;
}
private static void Postfix(BurstEffect __instance, bool __state)
{
if (!__state)
{
HideOrShow(__instance.prefab, __instance, atSpawn: false);
}
}
}
private static Maker maker;
private static readonly HashSet<BurstEffect> explosionPrefabs = new HashSet<BurstEffect>();
private static bool listedElementPrefabs;
private static readonly Hider<BurstEffect, Renderer> hider = new Hider<BurstEffect, Renderer>((BurstEffect effect) => ((Component)effect).GetComponentsInChildren<Renderer>(true), (Renderer renderer) => (Object)(object)renderer != (Object)null && renderer.enabled, delegate(Renderer renderer, bool on)
{
if ((Object)(object)renderer != (Object)null)
{
renderer.enabled = on;
}
});
private static readonly HashSet<BurstEffect> hiddenAtSpawn = new HashSet<BurstEffect>();
private static readonly Func<IDamageSource, bool> isPlayers = IsPlayers;
private static readonly Func<IDamageSource, IDamageSource> baseOf = (IDamageSource source) => source.BaseSource;
private static readonly Func<IDamageSource, IDamageSource> parentOf = (IDamageSource source) => source.ParentSource;
private void Awake()
{
if (PatchGroup.TryApply("hideplayerexplosions", (Action<string>)((BaseUnityPlugin)this).Logger.LogError, new Type[8]
{
typeof(SourcedExplosionPatch),
typeof(BulletExplosionPatch),
typeof(TargetDamagePatch),
typeof(OwnedVisualPatch),
typeof(FirstPersonFlagPatch),
typeof(ExplosionPrefabPatch),
typeof(BurstEffectSpawnPatch),
typeof(BurstEffectPlayPatch)
}))
{
SceneManager.sceneLoaded += delegate
{
ForgetDestroyed();
};
}
}
private static void ForgetDestroyed()
{
hider.Forget((BurstEffect effect) => (Object)(object)effect == (Object)null);
hiddenAtSpawn.RemoveWhere((BurstEffect effect) => (Object)(object)effect == (Object)null);
}
private static bool IsPlayers(IDamageSource source)
{
if (!(source is Player) && !(source is IGear))
{
Turret val = (Turret)(object)((source is Turret) ? source : null);
if (val != null)
{
return (Object)(object)val.player != (Object)null;
}
return false;
}
return true;
}
private static bool IsPlayerMade(IDamageSource source)
{
try
{
return ExplosionRules.LeadsTo(source, isPlayers, baseOf, parentOf);
}
catch (Exception)
{
return false;
}
}
private static void ListElementPrefabs()
{
Global instance = Global.Instance;
if ((Object)(object)instance == (Object)null || instance.statusEffects == null)
{
return;
}
listedElementPrefabs = true;
StatusEffectData[] statusEffects = instance.statusEffects;
foreach (StatusEffectData val in statusEffects)
{
if (!((Object)(object)val == (Object)null))
{
Add(val.explosionEffect);
Add(val.minimalExplosionEffect);
Add(val.firstPersonExplosionEffect);
}
}
static void Add(BurstEffect prefab)
{
if ((Object)(object)prefab != (Object)null)
{
explosionPrefabs.Add(prefab);
}
}
}
private static void HideOrShow(BurstEffect prefab, BurstEffect effect, bool atSpawn)
{
bool flag = maker == Maker.Player;
if ((!flag && hider.Count == 0) || (Object)(object)effect == (Object)null)
{
return;
}
if (flag)
{
if (!listedElementPrefabs)
{
ListElementPrefabs();
}
flag = (Object)(object)prefab != (Object)null && explosionPrefabs.Contains(prefab);
}
if (flag)
{
hider.Hide(effect);
if (atSpawn)
{
hiddenAtSpawn.Add(effect);
}
}
else if (atSpawn || !hiddenAtSpawn.Contains(effect))
{
hider.Show(effect);
hiddenAtSpawn.Remove(effect);
}
}
private static void Restore(Maker? saved)
{
if (saved.HasValue)
{
maker = saved.Value;
}
}
private static List<MethodBase> Found(IEnumerable<MethodBase> methods, string what)
{
List<MethodBase> list = methods.ToList();
if (list.Count == 0)
{
throw new MissingMethodException("no " + what + " found in the game");
}
return list;
}
private static IEnumerable<MethodBase> VisualMethods(Func<int, bool> rule)
{
return from m in AccessTools.GetDeclaredMethods(typeof(GameManager))
where m.Name.StartsWith("SpawnExplosionVisual") && rule(ExplosionRules.VisualRule(m.Name, (from p in m.GetParameters()
select p.Name).ToArray()))
select m;
}
private static IEnumerable<Type> BurstEffectTypes()
{
return AccessTools.GetTypesFromAssembly(typeof(BurstEffect).Assembly).Where(typeof(BurstEffect).IsAssignableFrom);
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}