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 Mimic Panic v1.0.0
EmpressMimic.dll
Decompiled 5 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Omniscye")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("EmpressMimic")] [assembly: AssemblyTitle("EmpressMimic")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [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.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] [Microsoft.CodeAnalysis.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] [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 Empress.MimicPanic { [BepInPlugin("Empress.MimicPanic", "Mimic Panic", "1.1.3")] public sealed class MimicPanicPlugin : BaseUnityPlugin { private struct PendingTransform { public GameObject go; public Vector3 pos; public SourceKind kind; public int key; } internal enum SourceKind { Item, Valuable } [HarmonyPatch(typeof(PhysGrabObject), "GrabStarted")] private static class PhysGrabObject_GrabStarted_Patch { private static void Postfix(PhysGrabObject __instance, PhysGrabber player) { if (!((Object)(object)__instance == (Object)null)) { GameObject gameObject = ((Component)__instance).gameObject; bool flag = (Object)(object)gameObject.GetComponent<ValuableObject>() != (Object)null; bool flag2 = !flag && (Object)(object)gameObject.GetComponent<ItemAttributes>() != (Object)null; if (VerboseGrabs.Value) { PhotonView component = gameObject.GetComponent<PhotonView>(); int num = (((Object)(object)component != (Object)null) ? component.ViewID : 0); Logger.LogInfo((object)$"[MimicPanic] Grab: \"{((Object)gameObject).name}\" PV:{num} isValuable:{flag} isItem:{flag2}"); } if (flag && EnableValuables.Value) { RequestTransformOnGrab(__instance, SourceKind.Valuable); } else if (flag2 && EnableItems.Value) { RequestTransformOnGrab(__instance, SourceKind.Item); } } } } [HarmonyPatch(typeof(PhysGrabObject), "GrabPlayerAddRPC")] private static class PhysGrabObject_GrabPlayerAddRPC_Patch { private static void Postfix(PhysGrabObject __instance, int photonViewID) { if (SemiFunc.IsMasterClientOrSingleplayer()) { GameObject gameObject = ((Component)__instance).gameObject; bool flag = (Object)(object)gameObject.GetComponent<ValuableObject>() != (Object)null; bool flag2 = !flag && (Object)(object)gameObject.GetComponent<ItemAttributes>() != (Object)null; if (flag && EnableValuables.Value) { RequestTransformOnGrab(__instance, SourceKind.Valuable); } else if (flag2 && EnableItems.Value) { RequestTransformOnGrab(__instance, SourceKind.Item); } } } } public const string PluginGuid = "Empress.MimicPanic"; public const string PluginName = "Mimic Panic"; public const string PluginVersion = "1.1.3"; internal static ConfigEntry<float> ChanceItemsPercent = null; internal static ConfigEntry<float> ChanceValuablesPercent = null; internal static ConfigEntry<bool> EnableItems = null; internal static ConfigEntry<bool> EnableValuables = null; internal static ConfigEntry<bool> BlockInStartRoom = null; internal static ConfigEntry<bool> RollOncePerObject = null; internal static ConfigEntry<bool> VerboseGrabs = null; internal static ConfigEntry<bool> LogRolls = null; internal static ConfigEntry<bool> AlwaysPassRoll = null; private static readonly Queue<PendingTransform> _queue = new Queue<PendingTransform>(64); private static readonly HashSet<int> _queuedOrDoneKeys = new HashSet<int>(); private static readonly HashSet<int> _attemptedKeys = new HashSet<int>(); internal static MimicPanicPlugin Instance { get; private set; } = null; internal static ManualLogSource Logger => Instance._logger; private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger; internal Harmony? Harmony { get; private set; } private void Awake() { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown Instance = this; EnableItems = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableItems", true, "Allow items (ItemAttributes) to transform on grab."); EnableValuables = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableValuables", true, "Allow valuables (ValuableObject) to transform on grab."); AcceptableValueRange<float> val = new AcceptableValueRange<float>(0f, 100f); ChanceItemsPercent = ((BaseUnityPlugin)this).Config.Bind<float>("Chances", "ItemsPercent", 5f, new ConfigDescription("Percent chance an item becomes an enemy when grabbed.", (AcceptableValueBase)(object)val, Array.Empty<object>())); ChanceValuablesPercent = ((BaseUnityPlugin)this).Config.Bind<float>("Chances", "ValuablesPercent", 5f, new ConfigDescription("Percent chance a valuable becomes an enemy when grabbed.", (AcceptableValueBase)(object)val, Array.Empty<object>())); BlockInStartRoom = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "BlockInStartRoom", true, "Block transformations in start/extraction rooms."); RollOncePerObject = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "RollOncePerObject", true, "If true, each object only rolls once — first time it’s grabbed."); VerboseGrabs = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseGrabs", false, "Log every grab with classification and IDs."); LogRolls = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogRolls", true, "Log RNG rolls and thresholds on attempted transforms."); AlwaysPassRoll = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "AlwaysPassRoll", false, "Force the RNG to pass (host-only). Use for quick verification."); ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; Patch(); Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} loaded. Don’t get handsy with the loot."); } private void Update() { if (LevelReady()) { int num = 32; while (_queue.Count > 0 && num-- > 0) { PendingTransform p = _queue.Dequeue(); TryTransformNow(p); } } } private static bool LevelReady() { return (Object)(object)LevelGenerator.Instance != (Object)null && LevelGenerator.Instance.Generated; } internal void Patch() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0026: Expected O, but got Unknown if (Harmony == null) { Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); Harmony val2 = val; Harmony = val; } Harmony.PatchAll(typeof(PhysGrabObject_GrabStarted_Patch)); Harmony.PatchAll(typeof(PhysGrabObject_GrabPlayerAddRPC_Patch)); } internal void Unpatch() { Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } } internal static void RequestTransformOnGrab(PhysGrabObject pgo, SourceKind kind) { //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)pgo == (Object)null) { return; } GameObject gameObject = ((Component)pgo).gameObject; if (!SemiFunc.IsMasterClientOrSingleplayer() || SemiFunc.RunIsShop()) { return; } if (BlockInStartRoom.Value) { RoomVolumeCheck component = gameObject.GetComponent<RoomVolumeCheck>(); if ((Object)(object)component != (Object)null && component.CurrentRooms != null) { foreach (RoomVolume currentRoom in component.CurrentRooms) { if ((Object)(object)currentRoom != (Object)null && currentRoom.Extraction) { if (VerboseGrabs.Value) { Logger.LogInfo((object)("[MimicPanic] Blocked in Extraction room: \"" + ((Object)gameObject).name + "\".")); } return; } } } } int num = MakeKey(gameObject); if (!RollOncePerObject.Value || !_attemptedKeys.Contains(num)) { _attemptedKeys.Add(num); float num2 = ((kind == SourceKind.Item) ? Mathf.Clamp(ChanceItemsPercent.Value, 0f, 100f) : Mathf.Clamp(ChanceValuablesPercent.Value, 0f, 100f)); float num3 = (AlwaysPassRoll.Value ? 0f : Random.Range(0f, 100f)); if (LogRolls.Value) { PhotonView component2 = gameObject.GetComponent<PhotonView>(); int num4 = (((Object)(object)component2 != (Object)null) ? component2.ViewID : 0); Logger.LogInfo((object)$"[MimicPanic] Roll {num3:F2} <= {num2:F2}? kind={kind} name=\"{((Object)gameObject).name}\" PV:{num4}"); } if (!(num3 > num2) && !_queuedOrDoneKeys.Contains(num)) { _queuedOrDoneKeys.Add(num); _queue.Enqueue(new PendingTransform { go = gameObject, pos = gameObject.transform.position, kind = kind, key = num }); } } } private static int MakeKey(GameObject go) { PhotonView component = go.GetComponent<PhotonView>(); if ((Object)(object)component != (Object)null && component.ViewID != 0) { return component.ViewID; } return ((Object)go).GetInstanceID() * -1 - 7; } private static void TryTransformNow(PendingTransform p) { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.IsMasterClientOrSingleplayer() || (Object)(object)p.go == (Object)null || (Object)(object)EnemyDirector.instance == (Object)null || (Object)(object)LevelGenerator.Instance == (Object)null) { return; } List<EnemySetup> list = CollectEnemySetups(); if (list.Count == 0) { Logger.LogWarning((object)"[MimicPanic] No enemy setups available — skipping transform."); return; } EnemySetup val = list[Random.Range(0, list.Count)]; if ((Object)(object)val == (Object)null) { Logger.LogWarning((object)"[MimicPanic] Picked null enemy setup — skipping transform."); return; } LevelGenerator.Instance.EnemySpawn(val, p.pos); DestroyNetworked(p.go); Logger.LogInfo((object)$"[MimicPanic] OnGrab transform: {p.kind} at {p.pos} -> enemy \"{((Object)val).name}\"."); } private static List<EnemySetup> CollectEnemySetups() { List<EnemySetup> list = new List<EnemySetup>(32); EnemyDirector instance = EnemyDirector.instance; if (instance.enemiesDifficulty1 != null) { list.AddRange(instance.enemiesDifficulty1); } if (instance.enemiesDifficulty2 != null) { list.AddRange(instance.enemiesDifficulty2); } if (instance.enemiesDifficulty3 != null) { list.AddRange(instance.enemiesDifficulty3); } int index = list.Count - 1; while (index-- > 0) { if ((Object)(object)list[index] == (Object)null) { list.RemoveAt(index); } } return list; } private static void DestroyNetworked(GameObject go) { if ((Object)(object)go == (Object)null) { return; } if (SemiFunc.IsMultiplayer()) { PhotonView component = go.GetComponent<PhotonView>(); if ((Object)(object)component != (Object)null && component.ViewID != 0) { PhotonNetwork.Destroy(go); } else { Object.Destroy((Object)(object)go); } } else { Object.Destroy((Object)(object)go); } } } }