using 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 System.Text;
using BepInEx;
using BepInEx.Logging;
using EntityStates;
using EntityStates.Barrel;
using HG.Reflection;
using IL.RoR2;
using Microsoft.CodeAnalysis;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using On.EntityStates.Barrel;
using On.RoR2;
using R2API.Utils;
using RoR2;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using VFiX.ChestZipper;
using VFiX.LightningStrikeImpact;
using VFiX.MeteorStrikePredictionEffect;
using VFiX.PooledEffectCleanup;
using VFiX.PooledEffectParent;
using VFiX.PooledEffectStart;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: NetworkCompatibility(/*Could not decode attribute arguments.*/)]
[assembly: OptIn]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("VFiX")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+882ce46c709032f764d78d032556fcd319a3db6f")]
[assembly: AssemblyProduct("VFiX")]
[assembly: AssemblyTitle("VFiX")]
[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.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace VFiX
{
public static class AddressableExtensions
{
public static void CallOnSuccess<T>(this AsyncOperationHandle<T> handle, Action<T> onSuccess)
{
handle.Completed += delegate(AsyncOperationHandle<T> handle)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Invalid comparison between Unknown and I4
if ((int)handle.Status != 1)
{
Log.Error("Failed to load asset " + handle.LocationName, "X:\\Git\\RoR2\\VFiX\\VFiX\\AddressableExtensions.cs", "CallOnSuccess", 24);
}
else
{
onSuccess(handle.Result);
}
};
}
}
internal static class Log
{
private static readonly StringBuilder _sharedStringBuilder;
private static readonly int _cachedCallerPathPrefixLength;
private static ManualLogSource _logSource;
static Log()
{
_sharedStringBuilder = new StringBuilder(256);
_cachedCallerPathPrefixLength = getCallerPathPrefixLength("X:\\Git\\RoR2\\VFiX\\VFiX\\Log.cs");
static int getCallerPathPrefixLength([CallerFilePath] string callerPath = null)
{
int num = callerPath.LastIndexOf("VFiX\\");
if (num >= 0)
{
return num + "VFiX\\".Length;
}
Debug.LogError((object)"[VFiX] Logger failed to determine caller path prefix length");
return 0;
}
}
internal static void Init(ManualLogSource logSource)
{
_logSource = logSource;
}
private static StringBuilder AppendCallerPrefix(this StringBuilder stringBuilder, string callerPath, string callerMemberName, int callerLineNumber)
{
return stringBuilder.Append(callerPath, _cachedCallerPathPrefixLength, callerPath.Length - _cachedCallerPathPrefixLength).Append(':').Append(callerLineNumber)
.Append(" (")
.Append(callerMemberName)
.Append("):");
}
private static StringBuilder buildCallerLogString(string callerPath, string callerMemberName, int callerLineNumber, object data)
{
return _sharedStringBuilder.Clear().AppendCallerPrefix(callerPath, callerMemberName, callerLineNumber).Append(' ')
.Append(data);
}
[Conditional("DEBUG")]
internal static void Debug(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
{
_logSource.LogDebug((object)buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[Conditional("DEBUG")]
internal static void Debug_NoCallerPrefix(object data)
{
_logSource.LogDebug(data);
}
internal static void Error(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
{
_logSource.LogError((object)buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Error_NoCallerPrefix(object data)
{
_logSource.LogError(data);
}
internal static void Fatal(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
{
_logSource.LogFatal((object)buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Fatal_NoCallerPrefix(object data)
{
_logSource.LogFatal(data);
}
internal static void Info(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
{
_logSource.LogInfo((object)buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Info_NoCallerPrefix(object data)
{
_logSource.LogInfo(data);
}
internal static void Message(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
{
_logSource.LogMessage((object)buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Message_NoCallerPrefix(object data)
{
_logSource.LogMessage(data);
}
internal static void Warning(object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
{
_logSource.LogWarning((object)buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Warning_NoCallerPrefix(object data)
{
_logSource.LogWarning(data);
}
internal static void LogType(LogLevel level, object data, [CallerFilePath] string callerPath = "", [CallerMemberName] string callerMemberName = "", [CallerLineNumber] int callerLineNumber = -1)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
LogType_NoCallerPrefix(level, buildCallerLogString(callerPath, callerMemberName, callerLineNumber, data));
}
internal static void LogType_NoCallerPrefix(LogLevel level, object data)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0002: 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_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
if ((level & 1) != 0)
{
Fatal_NoCallerPrefix(data);
}
else if ((level & 2) != 0)
{
Error_NoCallerPrefix(data);
}
else if ((level & 4) != 0)
{
Warning_NoCallerPrefix(data);
}
else if ((level & 8) != 0)
{
Message_NoCallerPrefix(data);
}
else if ((level & 0x10) != 0)
{
Info_NoCallerPrefix(data);
}
else
{
_ = level & 0x20;
}
}
}
[BepInPlugin("Gorakh.VFiX", "VFiX", "1.0.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class VFiXPlugin : BaseUnityPlugin
{
public const string PluginGUID = "Gorakh.VFiX";
public const string PluginAuthor = "Gorakh";
public const string PluginName = "VFiX";
public const string PluginVersion = "1.0.1";
private static VFiXPlugin _instance;
internal static VFiXPlugin Instance => _instance;
private void Awake()
{
Stopwatch stopwatch = Stopwatch.StartNew();
SingletonHelper.Assign<VFiXPlugin>(ref _instance, this);
Log.Init(((BaseUnityPlugin)this).Logger);
PooledEffectParentFix.Init();
PooledEffectStartFix.Init();
PooledEffectCleanupSoundFix.Init();
EffectPoolPreventInUsePoolClearFix.Init();
LightningStrikeImpactFix.Init();
ChestZipperFix.Init();
MeteorStrikePredictionEffectFix.Init();
stopwatch.Stop();
Log.Message_NoCallerPrefix($"Initialized in {stopwatch.Elapsed.TotalMilliseconds:F0}ms");
}
private void OnDestroy()
{
SingletonHelper.Unassign<VFiXPlugin>(ref _instance, this);
}
}
}
namespace VFiX.PooledEffectStart
{
public class AlignToNormalRestarter : MonoBehaviour, IEffectRestarter
{
[SerializeField]
private EffectRestarterController _restarter;
public AlignToNormal AlignToNormal;
EffectRestarterController IEffectRestarter.RestarterController
{
get
{
return _restarter;
}
set
{
_restarter = value;
}
}
private void Awake()
{
if (!Object.op_Implicit((Object)(object)_restarter))
{
_restarter = ((Component)this).GetComponentInParent<EffectRestarterController>();
}
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset += reset;
}
if (!Object.op_Implicit((Object)(object)AlignToNormal))
{
AlignToNormal = ((Component)this).GetComponent<AlignToNormal>();
}
}
private void OnDestroy()
{
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset -= reset;
}
}
private void reset()
{
if (Object.op_Implicit((Object)(object)AlignToNormal))
{
AlignToNormal.Start();
}
}
}
public class ApplyForceOnStartRestarter : MonoBehaviour, IEffectRestarter
{
[SerializeField]
private EffectRestarterController _restarter;
public ApplyForceOnStart ApplyForceOnStart;
EffectRestarterController IEffectRestarter.RestarterController
{
get
{
return _restarter;
}
set
{
_restarter = value;
}
}
private void Awake()
{
if (!Object.op_Implicit((Object)(object)_restarter))
{
_restarter = ((Component)this).GetComponentInParent<EffectRestarterController>();
}
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset += reset;
}
if (!Object.op_Implicit((Object)(object)ApplyForceOnStart))
{
ApplyForceOnStart = ((Component)this).GetComponent<ApplyForceOnStart>();
}
}
private void OnDestroy()
{
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset -= reset;
}
}
private void reset()
{
if (Object.op_Implicit((Object)(object)ApplyForceOnStart))
{
ApplyForceOnStart.Start();
}
}
}
public class ApplyTorqueOnStartRestarter : MonoBehaviour, IEffectRestarter
{
[SerializeField]
private EffectRestarterController _restarter;
public ApplyTorqueOnStart ApplyTorqueOnStart;
EffectRestarterController IEffectRestarter.RestarterController
{
get
{
return _restarter;
}
set
{
_restarter = value;
}
}
private void Awake()
{
if (!Object.op_Implicit((Object)(object)_restarter))
{
_restarter = ((Component)this).GetComponentInParent<EffectRestarterController>();
}
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset += reset;
}
if (!Object.op_Implicit((Object)(object)ApplyTorqueOnStart))
{
ApplyTorqueOnStart = ((Component)this).GetComponent<ApplyTorqueOnStart>();
}
}
private void OnDestroy()
{
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset -= reset;
}
}
private void reset()
{
if (Object.op_Implicit((Object)(object)ApplyTorqueOnStart))
{
ApplyTorqueOnStart.Start();
}
}
}
public class CoinBehaviorRestarter : MonoBehaviour, IEffectRestarter
{
[SerializeField]
private EffectRestarterController _restarter;
public CoinBehavior CoinBehavior;
EffectRestarterController IEffectRestarter.RestarterController
{
get
{
return _restarter;
}
set
{
_restarter = value;
}
}
private void Awake()
{
if (!Object.op_Implicit((Object)(object)_restarter))
{
_restarter = ((Component)this).GetComponentInParent<EffectRestarterController>();
}
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset += reset;
}
if (!Object.op_Implicit((Object)(object)CoinBehavior))
{
CoinBehavior = ((Component)this).GetComponent<CoinBehavior>();
}
}
private void OnDestroy()
{
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset -= reset;
}
}
private void reset()
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
if (!Object.op_Implicit((Object)(object)CoinBehavior))
{
return;
}
CoinTier[] coinTiers = CoinBehavior.coinTiers;
for (int i = 0; i < coinTiers.Length; i++)
{
ParticleSystem particleSystem = coinTiers[i].particleSystem;
if (Object.op_Implicit((Object)(object)particleSystem))
{
EmissionModule emission = particleSystem.emission;
((EmissionModule)(ref emission)).enabled = false;
particleSystem.Stop();
particleSystem.Clear();
((Component)particleSystem).gameObject.SetActive(false);
}
}
CoinBehavior.Start();
}
}
public sealed class EffectRestarterController : MonoBehaviour
{
private Rigidbody[] _rigidbodies;
private bool _hasStarted;
private bool _shouldReset;
public event Action OnReset;
private void Awake()
{
_rigidbodies = ((Component)this).GetComponentsInChildren<Rigidbody>(true);
}
private void Start()
{
_hasStarted = true;
}
private void OnEnable()
{
if (_hasStarted)
{
_shouldReset = true;
}
}
private void Update()
{
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
if (_shouldReset)
{
_shouldReset = false;
Rigidbody[] rigidbodies = _rigidbodies;
foreach (Rigidbody obj in rigidbodies)
{
obj.velocity = Vector3.zero;
obj.angularVelocity = Vector3.zero;
}
this.OnReset?.Invoke();
}
}
}
public class ExplodeRigidbodiesOnStartRestarter : MonoBehaviour, IEffectRestarter
{
[SerializeField]
private EffectRestarterController _restarter;
public ExplodeRigidbodiesOnStart ExplodeRigidbodiesOnStart;
EffectRestarterController IEffectRestarter.RestarterController
{
get
{
return _restarter;
}
set
{
_restarter = value;
}
}
private void Awake()
{
if (!Object.op_Implicit((Object)(object)_restarter))
{
_restarter = ((Component)this).GetComponentInParent<EffectRestarterController>();
}
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset += reset;
}
if (!Object.op_Implicit((Object)(object)ExplodeRigidbodiesOnStart))
{
ExplodeRigidbodiesOnStart = ((Component)this).GetComponent<ExplodeRigidbodiesOnStart>();
}
}
private void OnDestroy()
{
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset -= reset;
}
}
private void reset()
{
if (Object.op_Implicit((Object)(object)ExplodeRigidbodiesOnStart))
{
ExplodeRigidbodiesOnStart.Start();
}
}
}
public interface IEffectRestarter
{
EffectRestarterController RestarterController { get; set; }
}
public class ImpactEffectRestarter : MonoBehaviour, IEffectRestarter
{
[SerializeField]
private EffectRestarterController _restarter;
public ImpactEffect ImpactEffect;
EffectRestarterController IEffectRestarter.RestarterController
{
get
{
return _restarter;
}
set
{
_restarter = value;
}
}
private void Awake()
{
if (!Object.op_Implicit((Object)(object)_restarter))
{
_restarter = ((Component)this).GetComponentInParent<EffectRestarterController>();
}
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset += reset;
}
if (!Object.op_Implicit((Object)(object)ImpactEffect))
{
ImpactEffect = ((Component)this).GetComponent<ImpactEffect>();
}
}
private void OnDestroy()
{
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset -= reset;
}
}
private void reset()
{
if (Object.op_Implicit((Object)(object)ImpactEffect))
{
ParticleSystem[] particleSystems = ImpactEffect.particleSystems;
foreach (ParticleSystem obj in particleSystems)
{
obj.Stop();
obj.Clear();
}
ImpactEffect.Start();
}
}
}
public class LightScaleFromParentRestarter : MonoBehaviour, IEffectRestarter
{
[SerializeField]
private EffectRestarterController _restarter;
public LightScaleFromParent LightScaleFromParent;
private Light _light;
private float _originalRange;
EffectRestarterController IEffectRestarter.RestarterController
{
get
{
return _restarter;
}
set
{
_restarter = value;
}
}
private void Awake()
{
if (!Object.op_Implicit((Object)(object)_restarter))
{
_restarter = ((Component)this).GetComponentInParent<EffectRestarterController>();
}
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset += reset;
}
if (!Object.op_Implicit((Object)(object)LightScaleFromParent))
{
LightScaleFromParent = ((Component)this).GetComponent<LightScaleFromParent>();
}
if (((Component)this).TryGetComponent<Light>(ref _light))
{
_originalRange = _light.range;
}
}
private void OnDestroy()
{
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset -= reset;
}
}
private void reset()
{
if (Object.op_Implicit((Object)(object)_light))
{
_light.range = _originalRange;
}
if (Object.op_Implicit((Object)(object)LightScaleFromParent))
{
LightScaleFromParent.Start();
}
}
}
public class ParticleSystemColorFromEffectDataRestarter : MonoBehaviour, IEffectRestarter
{
[SerializeField]
private EffectRestarterController _restarter;
public ParticleSystemColorFromEffectData ParticleSystemColorFromEffectData;
EffectRestarterController IEffectRestarter.RestarterController
{
get
{
return _restarter;
}
set
{
_restarter = value;
}
}
private void Awake()
{
if (!Object.op_Implicit((Object)(object)_restarter))
{
_restarter = ((Component)this).GetComponentInParent<EffectRestarterController>();
}
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset += reset;
}
if (!Object.op_Implicit((Object)(object)ParticleSystemColorFromEffectData))
{
ParticleSystemColorFromEffectData = ((Component)this).GetComponent<ParticleSystemColorFromEffectData>();
}
}
private void OnDestroy()
{
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset -= reset;
}
}
private void reset()
{
if (Object.op_Implicit((Object)(object)ParticleSystemColorFromEffectData))
{
ParticleSystem[] particleSystems = ParticleSystemColorFromEffectData.particleSystems;
foreach (ParticleSystem obj in particleSystems)
{
obj.Stop();
obj.Clear();
}
ParticleSystemColorFromEffectData.Start();
}
}
}
public class ParticleSystemRandomColorRestarter : MonoBehaviour, IEffectRestarter
{
[SerializeField]
private EffectRestarterController _restarter;
public ParticleSystemRandomColor ParticleSystemRandomColor;
EffectRestarterController IEffectRestarter.RestarterController
{
get
{
return _restarter;
}
set
{
_restarter = value;
}
}
private void Awake()
{
if (!Object.op_Implicit((Object)(object)_restarter))
{
_restarter = ((Component)this).GetComponentInParent<EffectRestarterController>();
}
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset += reset;
}
if (!Object.op_Implicit((Object)(object)ParticleSystemRandomColor))
{
ParticleSystemRandomColor = ((Component)this).GetComponent<ParticleSystemRandomColor>();
}
}
private void OnDestroy()
{
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset -= reset;
}
}
private void reset()
{
if (Object.op_Implicit((Object)(object)ParticleSystemRandomColor))
{
ParticleSystemRandomColor.Awake();
}
}
}
internal static class PooledEffectStartFix
{
[SystemInitializer(new Type[] { typeof(EffectCatalog) })]
public static void Init()
{
GameObject prefab;
EffectRestarterController restarterController;
for (int i = 0; i < EffectCatalog.effectCount; i++)
{
EffectDef effectDef = EffectCatalog.GetEffectDef((EffectIndex)i);
if (effectDef != null && Object.op_Implicit((Object)(object)effectDef.prefab) && (!Object.op_Implicit((Object)(object)effectDef.prefabVfxAttributes) || !effectDef.prefabVfxAttributes.DoNotPool))
{
prefab = effectDef.prefab;
restarterController = null;
tryAddRestarters<LightScaleFromParent, LightScaleFromParentRestarter>("LightScaleFromParent");
tryAddRestarters<RTPCController, RTPCControllerRestarter>("RTPCController");
tryAddRestarters<AlignToNormal, AlignToNormalRestarter>("AlignToNormal");
tryAddRestarters<ImpactEffect, ImpactEffectRestarter>("ImpactEffect");
tryAddRestarters<ParticleSystemColorFromEffectData, ParticleSystemColorFromEffectDataRestarter>("ParticleSystemColorFromEffectData");
tryAddRestarters<CoinBehavior, CoinBehaviorRestarter>("CoinBehavior");
tryAddRestarters<VelocityRandomOnStart, VelocityRandomOnStartRestarter>("VelocityRandomOnStart");
tryAddRestarters<ParticleSystemRandomColor, ParticleSystemRandomColorRestarter>("ParticleSystemRandomColor");
tryAddRestarters<ApplyTorqueOnStart, ApplyTorqueOnStartRestarter>("ApplyTorqueOnStart");
tryAddRestarters<ApplyForceOnStart, ApplyForceOnStartRestarter>("ApplyForceOnStart");
tryAddRestarters<ExplodeRigidbodiesOnStart, ExplodeRigidbodiesOnStartRestarter>("ExplodeRigidbodiesOnStart");
tryAddRestarters<SetRandomRotation, SetRandomRotationRestarter>("SetRandomRotation");
Object.op_Implicit((Object)(object)restarterController);
}
void tryAddRestarters<TComponent, TRestarter>(string componentFieldName = null) where TComponent : Component where TRestarter : MonoBehaviour, IEffectRestarter
{
FieldInfo fieldInfo = null;
if (!string.IsNullOrEmpty(componentFieldName))
{
fieldInfo = typeof(TRestarter).GetField(componentFieldName, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
TComponent[] componentsInChildren = prefab.GetComponentsInChildren<TComponent>(true);
foreach (TComponent val in componentsInChildren)
{
TRestarter val2 = ((Component)val).gameObject.AddComponent<TRestarter>();
val2.RestarterController = getOrAddRestarterController();
if (fieldInfo != null)
{
fieldInfo.SetValue(val2, val);
}
}
}
}
EffectRestarterController getOrAddRestarterController()
{
if (!Object.op_Implicit((Object)(object)restarterController))
{
restarterController = prefab.AddComponent<EffectRestarterController>();
}
return restarterController;
}
}
[Conditional("DEBUG")]
private static void logUnhandledStartComponents(EffectDef effectDef)
{
MonoBehaviour[] componentsInChildren = effectDef.prefab.GetComponentsInChildren<MonoBehaviour>();
foreach (MonoBehaviour val in componentsInChildren)
{
Type type = ((object)val).GetType();
if (type == typeof(EffectComponent) || type == typeof(DestroyOnTimer) || type == typeof(DestroyOnParticleEnd) || type == typeof(AnimateShaderAlpha) || type == typeof(LightScaleFromParent) || type == typeof(RTPCController) || type == typeof(TeamFilter) || type == typeof(ScaleParticleSystemDuration) || type == typeof(RotateObject) || type == typeof(AlignToNormal) || type == typeof(OmniEffect) || type == typeof(ImpactEffect) || type == typeof(ParticleSystemColorFromEffectData) || type == typeof(LaserPointer) || type == typeof(CoinBehavior) || type == typeof(VelocityRandomOnStart) || type == typeof(ParticleSystemRandomColor) || type == typeof(RigidbodyStickOnImpact) || type == typeof(ApplyTorqueOnStart) || type == typeof(ApplyForceOnStart) || type == typeof(ExplodeRigidbodiesOnStart) || type == typeof(MaintainRotation) || type == typeof(RotateItem) || type == typeof(SetRandomRotation) || type == typeof(Tracer) || type == typeof(BeamPointsFromTransforms))
{
continue;
}
bool num = type.GetMethod("Awake", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null || type.GetMethod("Start", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null;
bool flag = type.GetMethod("OnEnable", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null;
if (num && !flag)
{
string text = "Init-only component " + type.FullName + " on " + effectDef.prefabName;
if ((Object)(object)((Component)val).transform != (Object)(object)effectDef.prefab.transform)
{
text = text + ", at " + Util.BuildPrefabTransformPath(effectDef.prefab.transform, ((Component)val).transform, false, true);
}
Log.Info(text, "X:\\Git\\RoR2\\VFiX\\VFiX\\PooledEffectStart\\PooledEffectStartFix.cs", "logUnhandledStartComponents", 109);
}
}
}
}
public class RTPCControllerRestarter : MonoBehaviour, IEffectRestarter
{
[SerializeField]
private EffectRestarterController _restarter;
public RTPCController RTPCController;
EffectRestarterController IEffectRestarter.RestarterController
{
get
{
return _restarter;
}
set
{
_restarter = value;
}
}
private void Awake()
{
if (!Object.op_Implicit((Object)(object)_restarter))
{
_restarter = ((Component)this).GetComponentInParent<EffectRestarterController>();
}
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset += reset;
}
if (!Object.op_Implicit((Object)(object)RTPCController))
{
RTPCController = ((Component)this).GetComponent<RTPCController>();
}
}
private void OnDestroy()
{
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset -= reset;
}
}
private void reset()
{
if (Object.op_Implicit((Object)(object)RTPCController))
{
RTPCController.fixedAge = 0f;
RTPCController.Start();
}
}
}
public class SetRandomRotationRestarter : MonoBehaviour, IEffectRestarter
{
[SerializeField]
private EffectRestarterController _restarter;
public SetRandomRotation SetRandomRotation;
private Vector3 _originalEulerAngles;
EffectRestarterController IEffectRestarter.RestarterController
{
get
{
return _restarter;
}
set
{
_restarter = value;
}
}
private void Awake()
{
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
if (!Object.op_Implicit((Object)(object)_restarter))
{
_restarter = ((Component)this).GetComponentInParent<EffectRestarterController>();
}
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset += reset;
}
if (!Object.op_Implicit((Object)(object)SetRandomRotation))
{
SetRandomRotation = ((Component)this).GetComponent<SetRandomRotation>();
}
_originalEulerAngles = ((Component)this).transform.localEulerAngles;
}
private void OnDestroy()
{
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset -= reset;
}
}
private void reset()
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
if (Object.op_Implicit((Object)(object)SetRandomRotation))
{
((Component)this).transform.localEulerAngles = _originalEulerAngles;
SetRandomRotation.Start();
}
}
}
public class VelocityRandomOnStartRestarter : MonoBehaviour, IEffectRestarter
{
[SerializeField]
private EffectRestarterController _restarter;
public VelocityRandomOnStart VelocityRandomOnStart;
EffectRestarterController IEffectRestarter.RestarterController
{
get
{
return _restarter;
}
set
{
_restarter = value;
}
}
private void Awake()
{
if (!Object.op_Implicit((Object)(object)_restarter))
{
_restarter = ((Component)this).GetComponentInParent<EffectRestarterController>();
}
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset += reset;
}
if (!Object.op_Implicit((Object)(object)VelocityRandomOnStart))
{
VelocityRandomOnStart = ((Component)this).GetComponent<VelocityRandomOnStart>();
}
}
private void OnDestroy()
{
if (Object.op_Implicit((Object)(object)_restarter))
{
_restarter.OnReset -= reset;
}
}
private void reset()
{
if (Object.op_Implicit((Object)(object)VelocityRandomOnStart))
{
VelocityRandomOnStart.Start();
}
}
}
}
namespace VFiX.PooledEffectParent
{
internal static class PooledEffectParentFix
{
[CompilerGenerated]
private static class <>O
{
public static hook_GetPooledEffect_GameObject_Vector3_Quaternion_Transform <0>__EffectManager_GetPooledEffect_GameObject_Vector3_Quaternion_Transform;
public static hook_OnReturnToPool <1>__EffectManagerHelper_OnReturnToPool;
}
public static void Init()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Expected O, but got Unknown
//IL_0030: 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_003b: Expected O, but got Unknown
object obj = <>O.<0>__EffectManager_GetPooledEffect_GameObject_Vector3_Quaternion_Transform;
if (obj == null)
{
hook_GetPooledEffect_GameObject_Vector3_Quaternion_Transform val = EffectManager_GetPooledEffect_GameObject_Vector3_Quaternion_Transform;
<>O.<0>__EffectManager_GetPooledEffect_GameObject_Vector3_Quaternion_Transform = val;
obj = (object)val;
}
EffectManager.GetPooledEffect_GameObject_Vector3_Quaternion_Transform += (hook_GetPooledEffect_GameObject_Vector3_Quaternion_Transform)obj;
object obj2 = <>O.<1>__EffectManagerHelper_OnReturnToPool;
if (obj2 == null)
{
hook_OnReturnToPool val2 = EffectManagerHelper_OnReturnToPool;
<>O.<1>__EffectManagerHelper_OnReturnToPool = val2;
obj2 = (object)val2;
}
EffectManagerHelper.OnReturnToPool += (hook_OnReturnToPool)obj2;
}
private static EffectManagerHelper EffectManager_GetPooledEffect_GameObject_Vector3_Quaternion_Transform(orig_GetPooledEffect_GameObject_Vector3_Quaternion_Transform orig, GameObject inPrefab, Vector3 inPosition, Quaternion inRotation, Transform inTransform)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0003: Unknown result type (might be due to invalid IL or missing references)
EffectManagerHelper val = orig.Invoke(inPrefab, inPosition, inRotation, inTransform);
if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)inTransform))
{
((Component)val).transform.SetParent(inTransform, true);
}
return val;
}
private static void EffectManagerHelper_OnReturnToPool(orig_OnReturnToPool orig, EffectManagerHelper self)
{
orig.Invoke(self);
((Component)self).transform.SetParent((Transform)null, true);
}
}
}
namespace VFiX.PooledEffectCleanup
{
internal static class EffectPoolPreventInUsePoolClearFix
{
[CompilerGenerated]
private static class <>O
{
public static Manipulator <0>__EffectManager_UnloadOutdatedPools;
}
public static void Init()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Expected O, but got Unknown
object obj = <>O.<0>__EffectManager_UnloadOutdatedPools;
if (obj == null)
{
Manipulator val = EffectManager_UnloadOutdatedPools;
<>O.<0>__EffectManager_UnloadOutdatedPools = val;
obj = (object)val;
}
EffectManager.UnloadOutdatedPools += (Manipulator)obj;
}
private static void EffectManager_UnloadOutdatedPools(ILContext il)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: Expected O, but got Unknown
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
ILCursor val = new ILCursor(il);
PropertyInfo effectPrefabMapCount = typeof(Dictionary<GameObject, EffectPool>).GetProperty("Count");
int num = default(int);
if (effectPrefabMapCount == null)
{
Log.Error("Failed to find Dictionary Count property", "X:\\Git\\RoR2\\VFiX\\VFiX\\PooledEffectCleanup\\EffectPoolPreventInUsePoolClearFix.cs", "EffectManager_UnloadOutdatedPools", 26);
}
else if (val.TryGotoNext((MoveType)2, new Func<Instruction, bool>[2]
{
(Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt(x, (MethodBase)effectPrefabMapCount.GetMethod),
(Instruction x) => ILPatternMatchingExt.MatchLdcI4(x, ref num)
}))
{
val.Emit(OpCodes.Pop);
val.Emit(OpCodes.Ldc_I4, int.MaxValue);
}
}
}
internal static class PooledEffectCleanupSoundFix
{
[CompilerGenerated]
private static class <>O
{
public static hook_PreDestroyObject <0>__EffectPool_PreDestroyObject;
}
public static void Init()
{
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Expected O, but got Unknown
object obj = <>O.<0>__EffectPool_PreDestroyObject;
if (obj == null)
{
hook_PreDestroyObject val = EffectPool_PreDestroyObject;
<>O.<0>__EffectPool_PreDestroyObject = val;
obj = (object)val;
}
EffectPool.PreDestroyObject += (hook_PreDestroyObject)obj;
}
private static void EffectPool_PreDestroyObject(orig_PreDestroyObject orig, EffectPool self, EffectManagerHelper inKillObject)
{
orig.Invoke(self, inKillObject);
AkTriggerHandler val = default(AkTriggerHandler);
if (((Component)inKillObject).TryGetComponent<AkTriggerHandler>(ref val))
{
val.triggerList.Clear();
}
}
}
}
namespace VFiX.MeteorStrikePredictionEffect
{
internal static class MeteorStrikePredictionEffectFix
{
public static void Init()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
Addressables.LoadAssetAsync<GameObject>((object)"RoR2/Base/Meteor/MeteorStrikePredictionEffect.prefab").CallOnSuccess(delegate(GameObject meteorStrikePredictionEffect)
{
Transform val = meteorStrikePredictionEffect.transform.Find("GroundSlamIndicator");
AnimateShaderAlpha val2 = default(AnimateShaderAlpha);
if (!Object.op_Implicit((Object)(object)val))
{
Log.Error("Failed to find GroundSlamIndicator", "X:\\Git\\RoR2\\VFiX\\VFiX\\MeteorStrikePredictionEffect\\MeteorStrikePredictionEffectFix.cs", "Init", 16);
}
else if (!((Component)val).TryGetComponent<AnimateShaderAlpha>(ref val2))
{
Log.Error(((Object)val).name + " is missing AnimateShaderAlpha component", "X:\\Git\\RoR2\\VFiX\\VFiX\\MeteorStrikePredictionEffect\\MeteorStrikePredictionEffectFix.cs", "Init", 22);
}
else
{
val2.continueExistingAfterTimeMaxIsReached = true;
}
});
}
}
}
namespace VFiX.LightningStrikeImpact
{
internal static class LightningStrikeImpactFix
{
public static void Init()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
Addressables.LoadAssetAsync<GameObject>((object)"RoR2/Base/Lightning/LightningStrikeImpact.prefab").CallOnSuccess(delegate(GameObject lightningStrikeImpactPrefab)
{
EffectComponent val2 = default(EffectComponent);
if (!lightningStrikeImpactPrefab.TryGetComponent<EffectComponent>(ref val2))
{
Log.Error("Lightning strike impact is missing EffectComponent", "X:\\Git\\RoR2\\VFiX\\VFiX\\LightningStrikeImpact\\LightningStrikeImpactFix.cs", "Init", 15);
}
else if (string.IsNullOrEmpty(val2.soundName))
{
val2.soundName = "Play_item_use_lighningArm";
}
});
Addressables.LoadAssetAsync<GameObject>((object)"RoR2/Base/LightningStrikeOnHit/SimpleLightningStrikeImpact.prefab").CallOnSuccess(delegate(GameObject simpleLightningStrikeImpactPrefab)
{
EffectComponent val = default(EffectComponent);
if (!simpleLightningStrikeImpactPrefab.TryGetComponent<EffectComponent>(ref val))
{
Log.Error("Simple lightning strike impact is missing EffectComponent", "X:\\Git\\RoR2\\VFiX\\VFiX\\LightningStrikeImpact\\LightningStrikeImpactFix.cs", "Init", 29);
}
else if (string.IsNullOrEmpty(val.soundName))
{
val.soundName = "Play_item_use_lighningArm";
}
});
}
}
}
namespace VFiX.ChestZipper
{
public class ChestZipperController : MonoBehaviour
{
private EffectManagerHelper _effectManagerHelper;
private ChestZipperTracker _ownerZipperTracker;
private bool _isTracked;
private float _untrackedAge;
private void Start()
{
_effectManagerHelper = ((Component)this).GetComponent<EffectManagerHelper>();
}
private void OnEnable()
{
_isTracked = false;
_untrackedAge = 0f;
}
private void OnDisable()
{
if (_isTracked && Object.op_Implicit((Object)(object)_ownerZipperTracker))
{
_ownerZipperTracker.RemoveZipperInstance(this);
}
}
private void FixedUpdate()
{
if (_isTracked)
{
return;
}
_untrackedAge += Time.fixedDeltaTime;
if (_untrackedAge > 10f)
{
Log.Warning(((Object)this).name + ": Timed out, returning to pool", "X:\\Git\\RoR2\\VFiX\\VFiX\\ChestZipper\\ChestZipperController.cs", "FixedUpdate", 41);
DestroyOrReturnToPool();
return;
}
GameObject val = null;
EntityLocator componentInParent = ((Component)this).GetComponentInParent<EntityLocator>();
if (Object.op_Implicit((Object)(object)componentInParent))
{
val = componentInParent.entity;
}
if (Object.op_Implicit((Object)(object)val) && val.TryGetComponent<ChestZipperTracker>(ref _ownerZipperTracker))
{
_ownerZipperTracker.TrackZipperInstance(this);
_isTracked = true;
}
}
public void DestroyOrReturnToPool()
{
if (Object.op_Implicit((Object)(object)_effectManagerHelper))
{
_effectManagerHelper.ReturnToPool();
}
else
{
Object.Destroy((Object)(object)((Component)this).gameObject);
}
}
}
internal static class ChestZipperFix
{
[CompilerGenerated]
private static class <>O
{
public static hook_Awake <0>__ChestBehavior_Awake;
public static hook_OnEnter <1>__Opened_OnEnter;
}
public static void Init()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Expected O, but got Unknown
//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
//IL_00fd: Expected O, but got Unknown
Addressables.LoadAssetAsync<GameObject>((object)"RoR2/Base/Chest1/ChestUnzip.prefab").CallOnSuccess(delegate(GameObject chestUnzip)
{
chestUnzip.AddComponent<ChestZipperController>();
Transform val7 = chestUnzip.transform.Find("Sparks (1)");
if (Object.op_Implicit((Object)(object)val7))
{
((Component)val7).gameObject.SetActive(true);
}
});
Addressables.LoadAssetAsync<GameObject>((object)"RoR2/Base/GoldChest/GoldChestUnzip.prefab").CallOnSuccess(delegate(GameObject goldChestUnzip)
{
goldChestUnzip.AddComponent<ChestZipperController>();
Transform val6 = goldChestUnzip.transform.Find("Sparks (1)");
if (Object.op_Implicit((Object)(object)val6))
{
((Component)val6).gameObject.SetActive(true);
}
});
string[] zipperPaths2 = new string[2] { "CategoryChestArmature/zipper1", "CategoryChestArmature/zipper1.001" };
fixChestZipperReferences("RoR2/Base/CategoryChest/CategoryChestDamage.prefab", zipperPaths2);
fixChestZipperReferences("RoR2/Base/CategoryChest/CategoryChestHealing.prefab", zipperPaths2);
fixChestZipperReferences("RoR2/Base/CategoryChest/CategoryChestUtility.prefab", zipperPaths2);
Addressables.LoadAssetAsync<RuntimeAnimatorController>((object)"RoR2/Base/CategoryChest/animCategoryChest.controller").CallOnSuccess(delegate(RuntimeAnimatorController categoryChestAnimatorController)
{
AnimationClip[] animationClips = categoryChestAnimatorController.animationClips;
for (int j = 0; j < animationClips.Length; j++)
{
if (!(((Object)animationClips[j]).name != "CategoryChestArmature|Open"))
{
AnimationEvent[] events = animationClips[j].events;
bool flag = false;
AnimationEvent[] array = events;
foreach (AnimationEvent val5 in array)
{
if (val5.functionName == "CreatePrefab" && val5.stringParameter.Contains("Zipper", StringComparison.OrdinalIgnoreCase) && val5.intParameter == 0)
{
val5.intParameter = 1;
flag = true;
}
}
if (flag)
{
animationClips[j].events = events;
}
}
}
});
object obj = <>O.<0>__ChestBehavior_Awake;
if (obj == null)
{
hook_Awake val = ChestBehavior_Awake;
<>O.<0>__ChestBehavior_Awake = val;
obj = (object)val;
}
ChestBehavior.Awake += (hook_Awake)obj;
object obj2 = <>O.<1>__Opened_OnEnter;
if (obj2 == null)
{
hook_OnEnter val2 = Opened_OnEnter;
<>O.<1>__Opened_OnEnter = val2;
obj2 = (object)val2;
}
Opened.OnEnter += (hook_OnEnter)obj2;
static void fixChestZipperReferences(string assetPath, string[] zipperPaths)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
Addressables.LoadAssetAsync<GameObject>((object)assetPath).CallOnSuccess(delegate(GameObject prefab)
{
ModelLocator val3 = default(ModelLocator);
Transform modelTransform;
ChildLocator childLocator = default(ChildLocator);
if (!prefab.TryGetComponent<ModelLocator>(ref val3))
{
Log.Error($"{prefab} is missing model locator", "X:\\Git\\RoR2\\VFiX\\VFiX\\ChestZipper\\ChestZipperFix.cs", "Init", 41);
}
else
{
modelTransform = val3.modelTransform;
if (!Object.op_Implicit((Object)(object)modelTransform))
{
Log.Error($"{prefab} is missing model transform", "X:\\Git\\RoR2\\VFiX\\VFiX\\ChestZipper\\ChestZipperFix.cs", "Init", 48);
}
else if (!((Component)modelTransform).TryGetComponent<ChildLocator>(ref childLocator))
{
Log.Error($"{modelTransform} is missing child locator", "X:\\Git\\RoR2\\VFiX\\VFiX\\ChestZipper\\ChestZipperFix.cs", "Init", 54);
}
else
{
int num = 0;
for (int i = 0; i < zipperPaths.Length; i++)
{
int num2 = childLocator.FindChildIndex($"Zipper{i + 1}");
if (num2 != -1 && tryAssignZipperReference(num2, zipperPaths[i]))
{
num++;
}
}
if (num == 0)
{
Log.Error($"Failed to fix zipper references for {prefab}", "X:\\Git\\RoR2\\VFiX\\VFiX\\ChestZipper\\ChestZipperFix.cs", "Init", 91);
}
}
}
bool tryAssignZipperReference(int childIndex, string modelPath)
{
ref NameTransformPair reference = ref childLocator.transformPairs[childIndex];
if (Object.op_Implicit((Object)(object)reference.transform))
{
return false;
}
Transform val4 = modelTransform.Find(modelPath);
if (!Object.op_Implicit((Object)(object)val4))
{
Log.Warning($"Failed to find {modelPath} relative to {modelTransform} ({prefab})", "X:\\Git\\RoR2\\VFiX\\VFiX\\ChestZipper\\ChestZipperFix.cs", "Init", 67);
return false;
}
reference.transform = val4;
return true;
}
});
}
}
private static void ChestBehavior_Awake(orig_Awake orig, ChestBehavior self)
{
orig.Invoke(self);
((Component)self).gameObject.AddComponent<ChestZipperTracker>();
}
private static void Opened_OnEnter(orig_OnEnter orig, Opened self)
{
orig.Invoke(self);
ChestZipperTracker component = ((EntityState)self).GetComponent<ChestZipperTracker>();
if (Object.op_Implicit((Object)(object)component))
{
component.DestroyAllTrackedZippers();
}
}
}
public class ChestZipperTracker : MonoBehaviour
{
private readonly List<ChestZipperController> _ownedZipperControllers = new List<ChestZipperController>();
public void DestroyAllTrackedZippers()
{
for (int num = _ownedZipperControllers.Count - 1; num >= 0; num--)
{
ChestZipperController chestZipperController = _ownedZipperControllers[num];
if (Object.op_Implicit((Object)(object)chestZipperController))
{
chestZipperController.DestroyOrReturnToPool();
}
}
_ownedZipperControllers.Clear();
}
public void TrackZipperInstance(ChestZipperController zipperController)
{
_ownedZipperControllers.Add(zipperController);
}
public void RemoveZipperInstance(ChestZipperController zipperController)
{
_ownedZipperControllers.Remove(zipperController);
}
}
}