using System; 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.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Microsoft.CodeAnalysis; using On.RoR2; using On.RoR2.Artifacts; using RiskOfOptions; using RiskOfOptions.Options; using RoR2; using RoR2.Artifacts; using RoR2.ContentManagement; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("VenganceSwarmRedux")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+5386fc89406137ecc94121205261f577ee3b131d")] [assembly: AssemblyProduct("VenganceSwarmRedux")] [assembly: AssemblyTitle("VenganceSwarmRedux")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [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 VengeanceSwarmRedux { [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("com.FortressForce.VengeanceSwarmRedux", "VengeanceSwarmRedux", "1.0.0")] public class Plugin : BaseUnityPlugin { public const string PluginGUID = "com.FortressForce.VengeanceSwarmRedux"; public const string PluginName = "VengeanceSwarmRedux"; public const string PluginVersion = "1.0.0"; private static readonly FieldInfo FieldSrcItemStacks = typeof(MasterCopySpawnCard).GetField("srcItemStacks", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo FieldSrcTempItemRawValues = typeof(MasterCopySpawnCard).GetField("srcTempItemRawValues", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo FieldSrcEquipment = typeof(MasterCopySpawnCard).GetField("srcEquipment", BindingFlags.Instance | BindingFlags.NonPublic); private static readonly FieldInfo FieldOnPreSpawnSetup = typeof(MasterCopySpawnCard).GetField("onPreSpawnSetup", BindingFlags.Instance | BindingFlags.NonPublic); private static int _lastInvasionCycleDropped = -1; public static ManualLogSource InstanceLogger { get; private set; } = null; public static Plugin Instance { get; private set; } = null; public static ConfigEntry IsEnabled { get; private set; } = null; public static ConfigEntry AllowBothDrops { get; private set; } = null; public static ConfigEntry EnableHighPopFix { get; private set; } = null; public static ConfigEntry EnableDebugLogging { get; private set; } = null; public void Awake() { Instance = this; InstanceLogger = ((BaseUnityPlugin)this).Logger; InitConfig(); RiskOfOptionsIntegration.Init(IsEnabled, AllowBothDrops, EnableHighPopFix, EnableDebugLogging); RegisterHooks(); InstanceLogger.LogInfo((object)"VengeanceSwarmRedux v1.0.0 initialized successfully."); } private void InitConfig() { IsEnabled = ((BaseUnityPlugin)this).Config.Bind("1. General", "Enabled", true, "Enables or disables the mod entirely."); AllowBothDrops = ((BaseUnityPlugin)this).Config.Bind("2. Gameplay", "Allow Both Swarm Drops", true, "If true, both Doppelgangers spawned under Artifact of Swarms will drop an item when defeated. If false, only one drop is awarded per invasion wave."); EnableHighPopFix = ((BaseUnityPlugin)this).Config.Bind("2. Gameplay", "High Population Fix", true, "Ensures Swarms Doppelganger clones ignore team member limits so they always spawn even when the map has high enemy population."); EnableDebugLogging = ((BaseUnityPlugin)this).Config.Bind("3. Debug", "Enable Debug Logging", false, "Enables detailed console logging for spawn events, item copies, and skin applications."); } private void RegisterHooks() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown MasterCopySpawnCard.GetPreSpawnSetupCallback += new hook_GetPreSpawnSetupCallback(OnMasterCopySpawnCardGetPreSpawnSetupCallback); SwarmsArtifactManager.OnSpawnCardOnSpawnedServerGlobal += new hook_OnSpawnCardOnSpawnedServerGlobal(OnSwarmsArtifactManagerOnSpawnCardOnSpawnedServerGlobal); CharacterBody.SetLoadoutServer += new hook_SetLoadoutServer(OnCharacterBodySetLoadoutServer); CharacterBody.UpdateMasterLink += new hook_UpdateMasterLink(OnCharacterBodyUpdateMasterLink); ModelSkinController.Start += new hook_Start(OnModelSkinControllerStart); CharacterMaster.OnDeserialize += new hook_OnDeserialize(OnCharacterMasterOnDeserialize); DoppelgangerInvasionManager.OnCharacterDeathGlobal += new hook_OnCharacterDeathGlobal(OnDoppelgangerDeathGlobal); } private Action OnMasterCopySpawnCardGetPreSpawnSetupCallback(orig_GetPreSpawnSetupCallback orig, MasterCopySpawnCard self) { if (!IsEnabled.Value) { return orig.Invoke(self); } return delegate(CharacterMaster spawnedMaster) { if (!Object.op_Implicit((Object)(object)spawnedMaster) || !Object.op_Implicit((Object)(object)spawnedMaster.inventory)) { return; } try { if (FieldSrcItemStacks?.GetValue(self) is int[] array) { spawnedMaster.inventory.AddItemsFrom(array, (Func)((ItemIndex _) => true)); } if (FieldSrcTempItemRawValues?.GetValue(self) is float[] array2) { for (int num = 0; num < array2.Length; num++) { if (array2[num] > 0f) { spawnedMaster.inventory.GiveItemTemp((ItemIndex)num, array2[num]); } } } if (FieldSrcEquipment?.GetValue(self) is EquipmentIndex[][] array3) { for (uint num2 = 0u; num2 < array3.Length; num2++) { if (array3[num2] != null) { for (uint num3 = 0u; num3 < array3[num2].Length; num3++) { spawnedMaster.inventory.SetEquipmentIndexForSlot(array3[num2][num3], num2, num3); } } } } if (self is DoppelgangerSpawnCard && spawnedMaster.inventory.GetItemCountEffective(Items.InvadingDoppelganger) == 0) { spawnedMaster.inventory.GiveItemPermanent(Items.InvadingDoppelganger, 1); } (FieldOnPreSpawnSetup?.GetValue(self) as Action)?.Invoke(spawnedMaster); if (EnableDebugLogging.Value) { InstanceLogger.LogInfo((object)("[ItemSync] Successfully applied inventory snapshot to spawned master: " + ((Object)spawnedMaster).name)); } } catch (Exception arg) { InstanceLogger.LogError((object)$"[ItemSync] Error in pre-spawn setup callback: {arg}"); } }; } private void OnSwarmsArtifactManagerOnSpawnCardOnSpawnedServerGlobal(orig_OnSpawnCardOnSpawnedServerGlobal orig, SpawnResult result) { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) if (IsEnabled.Value && EnableHighPopFix.Value && result.spawnRequest != null) { if (result.spawnRequest.spawnCard is DoppelgangerSpawnCard) { goto IL_008e; } if (Object.op_Implicit((Object)(object)result.spawnedInstance)) { CharacterMaster component = result.spawnedInstance.GetComponent(); if (component != null) { Inventory inventory = component.inventory; if (((inventory != null) ? new int?(inventory.GetItemCountEffective(Items.InvadingDoppelganger)) : ((int?)null)) > 0) { goto IL_008e; } } } } goto IL_009a; IL_009a: orig.Invoke(result); return; IL_008e: result.spawnRequest.ignoreTeamMemberLimit = true; goto IL_009a; } private void OnCharacterBodySetLoadoutServer(orig_SetLoadoutServer orig, CharacterBody self, Loadout loadout) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) orig.Invoke(self, loadout); if (!IsEnabled.Value || !Object.op_Implicit((Object)(object)self) || loadout == null) { return; } try { uint num = (self.skinIndex = loadout.bodyLoadoutManager.GetSkinIndex(self.bodyIndex)); if (EnableDebugLogging.Value) { InstanceLogger.LogInfo((object)$"[SkinSync] SetLoadoutServer: Body {((Object)self).name} assigned skinIndex {num}"); } } catch (Exception arg) { InstanceLogger.LogError((object)$"[SkinSync] Error in SetLoadoutServer hook: {arg}"); } } private void OnCharacterBodyUpdateMasterLink(orig_UpdateMasterLink orig, CharacterBody self) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) orig.Invoke(self); if (!IsEnabled.Value || !Object.op_Implicit((Object)(object)self) || !Object.op_Implicit((Object)(object)self.master) || self.master.loadout == null) { return; } try { uint skinIndex = self.master.loadout.bodyLoadoutManager.GetSkinIndex(self.bodyIndex); ApplySkinToBody(self, skinIndex); } catch (Exception arg) { InstanceLogger.LogError((object)$"[SkinSync] Error in UpdateMasterLink hook: {arg}"); } } private void OnModelSkinControllerStart(orig_Start orig, ModelSkinController self) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) if (IsEnabled.Value && Object.op_Implicit((Object)(object)self)) { try { CharacterModel component = ((Component)self).GetComponent(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.body) && Object.op_Implicit((Object)(object)component.body.master) && component.body.master.loadout != null) { uint skinIndex = component.body.master.loadout.bodyLoadoutManager.GetSkinIndex(component.body.bodyIndex); if (skinIndex != 0) { component.body.skinIndex = skinIndex; } } } catch (Exception arg) { InstanceLogger.LogError((object)$"[SkinSync] Error in ModelSkinController.Start hook: {arg}"); } } orig.Invoke(self); } private void OnCharacterMasterOnDeserialize(orig_OnDeserialize orig, CharacterMaster self, NetworkReader reader, bool initialState) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) orig.Invoke(self, reader, initialState); if (!IsEnabled.Value || !Object.op_Implicit((Object)(object)self) || NetworkServer.active || self.loadout == null) { return; } try { CharacterBody body = self.GetBody(); if (Object.op_Implicit((Object)(object)body)) { uint skinIndex = self.loadout.bodyLoadoutManager.GetSkinIndex(body.bodyIndex); ApplySkinToBody(body, skinIndex); } } catch (Exception arg) { InstanceLogger.LogError((object)$"[SkinSync] Error in CharacterMaster.OnDeserialize hook: {arg}"); } } private static void ApplySkinToBody(CharacterBody body, uint skinIndex) { if (!Object.op_Implicit((Object)(object)body)) { return; } body.skinIndex = skinIndex; if (!Object.op_Implicit((Object)(object)body.modelLocator) || !Object.op_Implicit((Object)(object)body.modelLocator.modelTransform)) { return; } ModelSkinController component = ((Component)body.modelLocator.modelTransform).GetComponent(); if (Object.op_Implicit((Object)(object)component) && component.skins != null && skinIndex < (uint)component.skins.Length && component.currentSkinIndex != (int)skinIndex) { if (EnableDebugLogging.Value) { InstanceLogger.LogInfo((object)$"[SkinSync] Applying skinIndex {skinIndex} to ModelSkinController on body {((Object)body).name}"); } ((MonoBehaviour)component).StartCoroutine(component.ApplySkinAsync((int)skinIndex, (AsyncReferenceHandleUnloadType)2)); } } private void OnDoppelgangerDeathGlobal(orig_OnCharacterDeathGlobal orig, DoppelgangerInvasionManager self, DamageReport damageReport) { if (!IsEnabled.Value || AllowBothDrops.Value || !Object.op_Implicit((Object)(object)self)) { orig.Invoke(self, damageReport); return; } int num = -1; try { MethodInfo method = typeof(DoppelgangerInvasionManager).GetMethod("GetCurrentInvasionCycle", BindingFlags.Instance | BindingFlags.NonPublic); if (method != null) { num = (int)method.Invoke(self, null); } } catch { num = (Object.op_Implicit((Object)(object)Run.instance) ? Mathf.FloorToInt(Run.instance.GetRunStopwatch() / 600f) : (-1)); } if (_lastInvasionCycleDropped == num && num != -1) { if (EnableDebugLogging.Value) { InstanceLogger.LogInfo((object)$"[LootDrop] Suppressing second swarm doppelganger drop for cycle {num} (AllowBothDrops is disabled)."); } } else { _lastInvasionCycleDropped = num; orig.Invoke(self, damageReport); } } } public static class RiskOfOptionsIntegration { public const string GUID = "com.rune580.riskofoptions"; public static bool IsLoaded => Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions"); public static void Init(ConfigEntry isEnabled, ConfigEntry allowBothDrops, ConfigEntry enableHighPopFix, ConfigEntry enableDebugLogging) { if (!IsLoaded) { return; } try { InitInternal(isEnabled, allowBothDrops, enableHighPopFix, enableDebugLogging); } catch (Exception ex) { ManualLogSource instanceLogger = Plugin.InstanceLogger; if (instanceLogger != null) { instanceLogger.LogWarning((object)("RiskOfOptions integration failed to initialize: " + ex.Message)); } } } [MethodImpl(MethodImplOptions.NoInlining)] private static void InitInternal(ConfigEntry isEnabled, ConfigEntry allowBothDrops, ConfigEntry enableHighPopFix, ConfigEntry enableDebugLogging) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown ModSettingsManager.SetModDescription("Fixes Doppelgangers (Umbras) skin synchronization and item/drop distribution when using Artifact of Vengeance and Artifact of Swarms."); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(isEnabled)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(allowBothDrops)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(enableHighPopFix)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(enableDebugLogging)); } } }