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 SummonSnapshot v0.2.0
SummonSnapshotMod/SummonSnapshotMod.dll
Decompiled 9 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HG; using Microsoft.CodeAnalysis; using RoR2; using UnityEngine; using UnityEngine.Networking; [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("SummonSnapshotMod")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SummonSnapshotMod")] [assembly: AssemblyTitle("SummonSnapshotMod")] [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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SummonSnapshotMod { [BepInPlugin("com.chronicrick.summonsnapshot", "Summon Snapshot", "0.2.0")] public sealed class Plugin : BaseUnityPlugin { private ConfigEntry<bool> rexFlowers; private ConfigEntry<bool> engineerEquipment; private ConfigEntry<bool> squidItems; private ConfigEntry<float> equipmentCheckSeconds; private ConfigEntry<bool> allowGooboOnSummons; private readonly HashSet<CharacterMaster> processed = new HashSet<CharacterMaster>(); private void Awake() { rexFlowers = ((BaseUnityPlugin)this).Config.Bind<bool>("Summons", "RexFlowers", true, "Snapshot items and equipment to REX Proliferation flowers."); engineerEquipment = ((BaseUnityPlugin)this).Config.Bind<bool>("Summons", "EngineerEquipment", true, "Automatically use Engineer turret equipment when ready."); squidItems = ((BaseUnityPlugin)this).Config.Bind<bool>("Summons", "SquidPolyp", true, "Copy the spawning player's items once to Squid Polyp turrets."); equipmentCheckSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Equipment", "CheckIntervalSeconds", 0.25f, "How often turrets check equipment readiness."); allowGooboOnSummons = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "AllowGooboOnSummons", false, "EXPERIMENTAL: Let flowers/turrets activate Goobo Jr. once. Leave false until clone-loop testing is complete."); RoR2Application.onLoad = (Action)Delegate.Combine(RoR2Application.onLoad, new Action(PatchSummonBodyPrefabs)); CharacterMaster.onStartGlobal += OnMasterStarted; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Summon Snapshot v0.2.0 safe prefab equipment-slot patch installed"); } private void OnDestroy() { RoR2Application.onLoad = (Action)Delegate.Remove(RoR2Application.onLoad, new Action(PatchSummonBodyPrefabs)); CharacterMaster.onStartGlobal -= OnMasterStarted; } private void PatchSummonBodyPrefabs() { int num = 0; for (int i = 0; i < BodyCatalog.bodyCount; i++) { GameObject bodyPrefab = BodyCatalog.GetBodyPrefab((BodyIndex)i); if (Object.op_Implicit((Object)(object)bodyPrefab)) { string text = ((Object)bodyPrefab).name.ToLowerInvariant(); bool flag = text.Contains("proliferationflowerturret") || text.Contains("rexflower"); bool flag2 = text.Contains("engiturret") || text.Contains("engiwalker"); if (((flag && rexFlowers.Value) || (flag2 && engineerEquipment.Value)) && !Object.op_Implicit((Object)(object)bodyPrefab.GetComponent<EquipmentSlot>())) { bodyPrefab.AddComponent<EquipmentSlot>(); num++; ((BaseUnityPlugin)this).Logger.LogInfo((object)("[PREFAB PATCH] EquipmentSlot added to " + ((Object)bodyPrefab).name)); } } } ((BaseUnityPlugin)this).Logger.LogInfo((object)("[PREFAB PATCH] Finished. Patched " + num + " body prefabs.")); } private void OnMasterStarted(CharacterMaster master) { if (NetworkServer.active && Object.op_Implicit((Object)(object)master)) { ((MonoBehaviour)this).StartCoroutine(GuardGooboClone(master)); ((MonoBehaviour)this).StartCoroutine(InitializeSummon(master)); } } private static bool IsGummyClone(CharacterMaster master, CharacterBody body) { string text = (Object.op_Implicit((Object)(object)master) ? ((Object)master).name.ToLowerInvariant() : ""); string text2 = (Object.op_Implicit((Object)(object)body) ? ((Object)body).name.ToLowerInvariant() : ""); string text3 = (Object.op_Implicit((Object)(object)body) ? body.GetDisplayName().ToLowerInvariant() : ""); return text.Contains("gummy") || text.Contains("goob") || text2.Contains("gummy") || text2.Contains("goob") || text3.Contains("gummy") || text3.Contains("goobo"); } private static bool IsGooboEquipment(EquipmentDef def) { if (!Object.op_Implicit((Object)(object)def)) { return false; } string text = (((Object)def).name ?? "").ToLowerInvariant(); string text2 = (def.nameToken ?? "").ToLowerInvariant(); return text.Contains("gummyclone") || text.Contains("goobo") || text2.Contains("gummyclone") || text2.Contains("goobo"); } private IEnumerator GuardGooboClone(CharacterMaster master) { for (int i = 0; i < 180; i++) { if (!Object.op_Implicit((Object)(object)master)) { break; } CharacterBody body = master.GetBody(); if (Object.op_Implicit((Object)(object)body) && IsGummyClone(master, body)) { if (Object.op_Implicit((Object)(object)master.inventory)) { master.inventory.SetEquipmentIndex((EquipmentIndex)(-1)); } if (Object.op_Implicit((Object)(object)body.inventory) && (Object)(object)body.inventory != (Object)(object)master.inventory) { body.inventory.SetEquipmentIndex((EquipmentIndex)(-1)); } AutoEquipment activator = ((Component)body).GetComponent<AutoEquipment>(); if (Object.op_Implicit((Object)(object)activator)) { Object.Destroy((Object)(object)activator); } ((BaseUnityPlugin)this).Logger.LogInfo((object)("[GOOBO GUARD] Clone equipment removed: " + body.GetDisplayName())); break; } yield return null; } } private unsafe IEnumerator InitializeSummon(CharacterMaster summon) { bool isFlowerMaster = ((Object)summon).name.ToLowerInvariant().Contains("proliferationflowerturret"); if (isFlowerMaster) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[FLOWER DEBUG] master started: " + ((Object)summon).name)); } for (int i = 0; i < 120; i++) { if (!Object.op_Implicit((Object)(object)summon)) { yield break; } MinionOwnership ownership = summon.minionOwnership; CharacterMaster owner = (Object.op_Implicit((Object)(object)ownership) ? ownership.ownerMaster : null); CharacterBody body = summon.GetBody(); if (Object.op_Implicit((Object)(object)owner) && Object.op_Implicit((Object)(object)body) && Object.op_Implicit((Object)(object)owner.inventory) && Object.op_Implicit((Object)(object)summon.inventory)) { if (!processed.Add(summon)) { yield break; } if (isFlowerMaster) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[FLOWER DEBUG] resolved owner=" + ((Object)owner).name + " body=" + ((Object)body).name)); } string name = ((Object)body).name.ToLowerInvariant(); if (IsGummyClone(summon, body)) { summon.inventory.SetEquipmentIndex((EquipmentIndex)(-1)); AutoEquipment existingActivator = ((Component)body).GetComponent<AutoEquipment>(); if (Object.op_Implicit((Object)(object)existingActivator)) { Object.Destroy((Object)(object)existingActivator); } ((BaseUnityPlugin)this).Logger.LogInfo((object)("[GOOBO GUARD] Clone skipped: " + body.GetDisplayName())); yield break; } if (Object.op_Implicit((Object)(object)owner.minionOwnership) && Object.op_Implicit((Object)(object)owner.minionOwnership.ownerMaster)) { EquipmentIndex inheritedEquipment = summon.inventory.currentEquipmentIndex; EquipmentDef inheritedDef = EquipmentCatalog.GetEquipmentDef(inheritedEquipment); if (IsGooboEquipment(inheritedDef)) { summon.inventory.SetEquipmentIndex((EquipmentIndex)(-1)); } ((BaseUnityPlugin)this).Logger.LogInfo((object)("[GOOBO GUARD] Nested summon skipped: " + ((Object)summon).name + " owner=" + ((Object)owner).name)); yield break; } if (!Object.op_Implicit((Object)(object)((Component)owner).GetComponent<PlayerCharacterMasterController>())) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[SAFETY] Non-player-owned summon skipped: " + ((Object)summon).name)); yield break; } bool rex = name.Contains("proliferationflowerturret") || name.Contains("offshoot") || name.Contains("rexflower"); bool engi = name.Contains("engiturret") || name.Contains("engiwalker"); bool squid = name.Contains("squidturret") || name.Contains("squidpolyp"); if ((rex && rexFlowers.Value) || (squid && squidItems.Value)) { int copied = CopyItemsOnce(owner.inventory, summon.inventory); if (rex) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[FLOWER DEBUG] owner=" + ((Object)owner).name + " body=" + ((Object)body).name + " itemsCopied=" + copied + " inventory=" + ((Object)summon.inventory).name)); } } if ((rex && rexFlowers.Value) || (engi && engineerEquipment.Value)) { EquipmentIndex equipment = owner.inventory.currentEquipmentIndex; EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(equipment); if (IsGooboEquipment(equipmentDef) && !allowGooboOnSummons.Value) { equipment = (EquipmentIndex)(-1); ((BaseUnityPlugin)this).Logger.LogInfo((object)("[SAFETY] Goobo Jr. excluded from " + ((Object)body).name)); } summon.inventory.SetEquipmentIndex(equipment); AutoEquipment activator = ((Component)body).GetComponent<AutoEquipment>(); if (!Object.op_Implicit((Object)(object)activator)) { activator = ((Component)body).gameObject.AddComponent<AutoEquipment>(); } activator.Initialize(equipmentCheckSeconds.Value, allowGooboOnSummons.Value); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Turret equipment enabled: " + ((Object)body).name + " / " + ((object)(*(EquipmentIndex*)(&equipment))/*cast due to .constrained prefix*/).ToString())); if (rex) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("[FLOWER DEBUG] equipment owner=" + ((object)(*(EquipmentIndex*)(&equipment))/*cast due to .constrained prefix*/).ToString() + " flower=" + ((object)summon.inventory.currentEquipmentIndex/*cast due to .constrained prefix*/).ToString() + " activator=" + ((Object)(object)activator != (Object)null))); } } yield break; } yield return null; } if (isFlowerMaster) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("[FLOWER DEBUG] Initialization timed out: master=" + ((Object)summon).name + " body=" + (Object.op_Implicit((Object)(object)summon.GetBody()) ? ((Object)summon.GetBody()).name : "null") + " owner=" + ((Object.op_Implicit((Object)(object)summon.minionOwnership) && Object.op_Implicit((Object)(object)summon.minionOwnership.ownerMaster)) ? ((Object)summon.minionOwnership.ownerMaster).name : "null") + " inventory=" + (Object.op_Implicit((Object)(object)summon.inventory) ? "yes" : "no"))); } } private static bool IsUnsafeSummonItem(ItemDef def) { if (!Object.op_Implicit((Object)(object)def) || def.hidden) { return true; } string text = (((Object)def).name ?? "").ToLowerInvariant(); string text2 = (def.nameToken ?? "").ToLowerInvariant(); string text3 = text + " " + text2; string[] array = new string[23] { "squid", "beetlegland", "queensgland", "roboballbuddy", "empathycores", "empathycore", "minorconstructonkill", "constructonkill", "droneparts", "droneweapons", "happiestmask", "ghostonkill", "ghostmask", "defensenucleus", "defencenucleus", "proliferation", "offshoot", "gummy", "goobo", "spawnminion", "summon", "allyspawn", "spawnally" }; string[] array2 = array; foreach (string value in array2) { if (text3.Contains(value)) { return true; } } return false; } private static int CopyItemsOnce(Inventory owner, Inventory summon) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) int num = 0; Enumerator<ItemDef> enumerator = ItemCatalog.allItemDefs.GetEnumerator(); try { while (enumerator.MoveNext()) { ItemDef current = enumerator.Current; if (!IsUnsafeSummonItem(current)) { int itemCountPermanent = owner.GetItemCountPermanent(current.itemIndex); if (itemCountPermanent > 0) { summon.GiveItemPermanent(current.itemIndex, itemCountPermanent); num += itemCountPermanent; } } } } finally { ((IDisposable)enumerator/*cast due to .constrained prefix*/).Dispose(); } return num; } } internal sealed class AutoEquipment : MonoBehaviour { private float interval = 0.25f; private float nextAttempt; private EquipmentSlot slot; private bool gooboUsed; private bool allowGoobo; private bool missingSlotLogged; private static bool IsGooboEquipmentLocal(EquipmentDef def) { if (!Object.op_Implicit((Object)(object)def)) { return false; } string text = (((Object)def).name ?? "").ToLowerInvariant(); string text2 = (def.nameToken ?? "").ToLowerInvariant(); return text.Contains("gummyclone") || text.Contains("goobo") || text2.Contains("gummyclone") || text2.Contains("goobo"); } private static bool IsGummyCloneBody(CharacterBody body) { if (!Object.op_Implicit((Object)(object)body)) { return false; } string text = body.GetDisplayName().ToLowerInvariant(); string text2 = ((Object)body).name.ToLowerInvariant(); CharacterMaster master = body.master; string text3 = (Object.op_Implicit((Object)(object)master) ? ((Object)master).name.ToLowerInvariant() : ""); return text.Contains("gummy") || text.Contains("goobo") || text2.Contains("gummy") || text2.Contains("goob") || text3.Contains("gummy") || text3.Contains("goob"); } public void Initialize(float seconds, bool allowGooboEquipment) { interval = Mathf.Max(0.1f, seconds); allowGoobo = allowGooboEquipment; } private void FixedUpdate() { //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Invalid comparison between Unknown and I4 //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) if (!NetworkServer.active || Time.fixedTime < nextAttempt) { return; } nextAttempt = Time.fixedTime + interval; if (!Object.op_Implicit((Object)(object)slot)) { slot = ((Component)this).GetComponent<EquipmentSlot>(); } CharacterBody component = ((Component)this).GetComponent<CharacterBody>(); if (!Object.op_Implicit((Object)(object)component) || !Object.op_Implicit((Object)(object)component.inventory)) { return; } if (!Object.op_Implicit((Object)(object)slot)) { if (!missingSlotLogged) { missingSlotLogged = true; Debug.LogWarning((object)("[Summon Snapshot] No prefab EquipmentSlot on " + ((Object)component).name + "; skipping activation to avoid network RPC corruption.")); } return; } CharacterMaster master = component.master; if (IsGummyCloneBody(component)) { component.inventory.SetEquipmentIndex((EquipmentIndex)(-1)); ((Behaviour)this).enabled = false; return; } if (Object.op_Implicit((Object)(object)master) && Object.op_Implicit((Object)(object)master.minionOwnership) && Object.op_Implicit((Object)(object)master.minionOwnership.ownerMaster)) { CharacterMaster ownerMaster = master.minionOwnership.ownerMaster; if (Object.op_Implicit((Object)(object)ownerMaster.minionOwnership) && Object.op_Implicit((Object)(object)ownerMaster.minionOwnership.ownerMaster)) { EquipmentDef equipmentDef = EquipmentCatalog.GetEquipmentDef(component.inventory.currentEquipmentIndex); if (IsGooboEquipmentLocal(equipmentDef)) { component.inventory.SetEquipmentIndex((EquipmentIndex)(-1)); } ((Behaviour)this).enabled = false; return; } } EquipmentIndex currentEquipmentIndex = component.inventory.currentEquipmentIndex; if ((int)currentEquipmentIndex == -1) { return; } EquipmentDef equipmentDef2 = EquipmentCatalog.GetEquipmentDef(currentEquipmentIndex); if (!Object.op_Implicit((Object)(object)equipmentDef2)) { return; } bool flag = IsGooboEquipmentLocal(equipmentDef2); if (!flag || (allowGoobo && !gooboUsed)) { if (flag) { gooboUsed = true; } slot.ExecuteIfReady(); } } } }