Decompiled source of SummonSnapshot v0.2.0

SummonSnapshotMod/SummonSnapshotMod.dll

Decompiled 16 hours ago
using 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();
			}
		}
	}
}