Decompiled source of EffectsControl v1.0.1

BepInEx/plugins/EffectsControl/EffectsControl.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("EffectsControl")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1+eeb528b28c25607007c89dd2879bde52435d99d9")]
[assembly: AssemblyProduct("EffectsControl")]
[assembly: AssemblyTitle("EffectsControl")]
[assembly: AssemblyVersion("1.0.1.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 EffectsControl
{
	public sealed class EffectCatalog
	{
		private sealed class StageBox
		{
			public EffectStage Stage;
		}

		private ConditionalWeakTable<EffectList, StageBox> lists = new ConditionalWeakTable<EffectList, StageBox>();

		private int registeredLists;

		private readonly Dictionary<string, EffectStage> projectiles = new Dictionary<string, EffectStage>(StringComparer.Ordinal);

		private readonly Dictionary<string, EffectStage> effects = new Dictionary<string, EffectStage>(StringComparer.Ordinal);

		private readonly HashSet<GameObject> visited = new HashSet<GameObject>();

		public int ListCount => registeredLists;

		public int ProjectileCount => projectiles.Count;

		public void Clear()
		{
			lists = new ConditionalWeakTable<EffectList, StageBox>();
			registeredLists = 0;
			projectiles.Clear();
			effects.Clear();
			visited.Clear();
		}

		public bool TryList(EffectList list, out EffectStage stage)
		{
			if (list != null && lists.TryGetValue(list, out var value))
			{
				stage = value.Stage;
				return true;
			}
			stage = EffectStage.Launch;
			return false;
		}

		public bool TryProjectile(GameObject instance, out EffectStage stage)
		{
			return TryInstance(projectiles, instance, out stage);
		}

		public bool TryEffect(GameObject instance, out EffectStage stage)
		{
			return TryInstance(effects, instance, out stage);
		}

		private static bool TryInstance(Dictionary<string, EffectStage> prefabs, GameObject instance, out EffectStage stage)
		{
			stage = EffectStage.Launch;
			if (!Object.op_Implicit((Object)(object)instance))
			{
				return false;
			}
			string text = ((Object)instance).name;
			if (text.EndsWith("(Clone)", StringComparison.Ordinal))
			{
				text = text.Substring(0, text.Length - 7);
			}
			return prefabs.TryGetValue(text, out stage);
		}

		public static bool IsWeapon(ItemData item)
		{
			//IL_0013: 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_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Invalid comparison between Unknown and I4
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Invalid comparison between Unknown and I4
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Invalid comparison between Unknown and I4
			//IL_0035: 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)
			//IL_003a: Invalid comparison between Unknown and I4
			if (item == null || item.m_shared == null)
			{
				return false;
			}
			ItemType itemType = item.m_shared.m_itemType;
			if ((int)itemType <= 9)
			{
				if (itemType - 3 <= 1 || (int)itemType == 9)
				{
					goto IL_003c;
				}
			}
			else if ((int)itemType == 14 || (int)itemType == 20 || itemType - 22 <= 1)
			{
				goto IL_003c;
			}
			return false;
			IL_003c:
			return true;
		}

		public void RegisterItem(ItemData item)
		{
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Invalid comparison between Unknown and I4
			if (IsWeapon(item))
			{
				SharedData shared = item.m_shared;
				RegisterAttack(shared.m_attack);
				RegisterAttack(shared.m_secondaryAttack);
				Add(shared.m_startEffect, EffectStage.Launch);
				Add(shared.m_holdStartEffect, EffectStage.Launch);
				Add(shared.m_trailStartEffect, EffectStage.Launch);
				Add(shared.m_triggerEffect, (shared.m_attack != null && (int)shared.m_attack.m_attackType == 4) ? EffectStage.Impact : EffectStage.Launch);
				Add(shared.m_hitEffect, EffectStage.Impact);
				Add(shared.m_hitTerrainEffect, EffectStage.Impact);
				Visit(shared.m_spawnOnHit, EffectStage.Impact);
				Visit(shared.m_spawnOnHitTerrain, EffectStage.Impact);
			}
		}

		public void RegisterAttack(Attack attack)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Invalid comparison between Unknown and I4
			if (attack != null)
			{
				Add(attack.m_startEffect, EffectStage.Launch);
				Add(attack.m_trailStartEffect, EffectStage.Launch);
				Add(attack.m_burstEffect, EffectStage.Launch);
				Add(attack.m_triggerEffect, ((int)attack.m_attackType == 4) ? EffectStage.Impact : EffectStage.Launch);
				Add(attack.m_hitEffect, EffectStage.Impact);
				Add(attack.m_hitTerrainEffect, EffectStage.Impact);
				Visit(attack.m_attackProjectile, EffectStage.Flight);
				Visit(attack.m_spawnOnTrigger, EffectStage.Impact);
				Visit(attack.m_spawnOnHit, EffectStage.Impact);
			}
		}

		public void RegisterProjectile(Projectile projectile)
		{
			Add(projectile.m_hitEffects, EffectStage.Impact);
			Add(projectile.m_hitWaterEffects, EffectStage.Impact);
			Add(projectile.m_spawnOnHitEffects, EffectStage.Impact);
			Visit(projectile.m_spawnOnHit, EffectStage.Impact);
			foreach (GameObject item in projectile.m_randomSpawnOnHit)
			{
				Visit(item, EffectStage.Impact);
			}
		}

		public void RegisterAoe(Aoe aoe)
		{
			Add(aoe.m_hitEffects, EffectStage.Impact);
			Add(aoe.m_initiateEffect, EffectStage.Impact);
			Add(aoe.m_chainEffects, EffectStage.Impact);
			Visit(aoe.m_chainObj, EffectStage.Impact);
			Visit(aoe.m_spawnOnHitTerrain, EffectStage.Impact);
		}

		public void RegisterShield(SE_Shield shield)
		{
			Add(((StatusEffect)shield).m_startEffects, EffectStage.Shield);
			Add(shield.m_hitEffects, EffectStage.Shield);
			Add(shield.m_breakEffects, EffectStage.Shield);
			Add(((StatusEffect)shield).m_stopEffects, EffectStage.Shield);
		}

		private void Add(EffectList list, EffectStage stage)
		{
			if (list == null || list.m_effectPrefabs == null || list.m_effectPrefabs.Length == 0)
			{
				return;
			}
			if (!lists.TryGetValue(list, out var value))
			{
				lists.Add(list, new StageBox
				{
					Stage = stage
				});
				registeredLists++;
			}
			else if (stage == EffectStage.Shield)
			{
				value.Stage = stage;
			}
			EffectData[] effectPrefabs = list.m_effectPrefabs;
			foreach (EffectData val in effectPrefabs)
			{
				if (val != null)
				{
					Visit(val.m_prefab, stage);
				}
			}
		}

		private void Visit(GameObject prefab, EffectStage stage)
		{
			if (!Object.op_Implicit((Object)(object)prefab) || Object.op_Implicit((Object)(object)prefab.GetComponentInChildren<Character>(true)) || Object.op_Implicit((Object)(object)prefab.GetComponentInChildren<Piece>(true)))
			{
				return;
			}
			Projectile component = prefab.GetComponent<Projectile>();
			Aoe component2 = prefab.GetComponent<Aoe>();
			EffectStage effectStage = ((stage == EffectStage.Shield) ? stage : (Object.op_Implicit((Object)(object)component2) ? EffectStage.Impact : stage));
			if (!effects.ContainsKey(((Object)prefab).name) || effectStage == EffectStage.Shield)
			{
				effects[((Object)prefab).name] = effectStage;
			}
			if (visited.Add(prefab) && (Object.op_Implicit((Object)(object)component) || Object.op_Implicit((Object)(object)component2)))
			{
				projectiles[((Object)prefab).name] = (Object.op_Implicit((Object)(object)component2) ? EffectStage.Impact : stage);
				if (Object.op_Implicit((Object)(object)component))
				{
					RegisterProjectile(component);
				}
				if (Object.op_Implicit((Object)(object)component2))
				{
					RegisterAoe(component2);
				}
			}
		}
	}
	[BepInPlugin("Slikfoul.EffectsControl", "EffectsControl", "1.0.1")]
	[DefaultExecutionOrder(10000)]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "Slikfoul.EffectsControl";

		public const string PluginName = "EffectsControl";

		public const string PluginVersion = "1.0.1";

		internal static Plugin Instance;

		internal readonly EffectCatalog Catalog = new EffectCatalog();

		private readonly Dictionary<GameObject, VisualState> active = new Dictionary<GameObject, VisualState>();

		private readonly Dictionary<GameObject, EffectStage> pending = new Dictionary<GameObject, EffectStage>();

		private readonly HashSet<GameObject> pendingNetwork = new HashSet<GameObject>();

		private readonly List<GameObject> expired = new List<GameObject>();

		private readonly VisualOptions[] options = new VisualOptions[4];

		private Settings settings;

		private Harmony harmony;

		private bool rebuild = true;

		private bool ready;

		private bool shieldConflict;

		private bool optionsDirty = true;

		private int failures;

		private void Awake()
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Invalid comparison between Unknown and I4
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			Instance = this;
			settings = new Settings(((BaseUnityPlugin)this).Config);
			settings.Changed += delegate
			{
				optionsDirty = true;
			};
			if ((int)SystemInfo.graphicsDeviceType == 4)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Client visual mod: headless host skipped.");
				return;
			}
			harmony = new Harmony("Slikfoul.EffectsControl");
			try
			{
				harmony.PatchAll(typeof(Plugin).Assembly);
				ready = true;
			}
			catch (Exception ex)
			{
				harmony.UnpatchSelf();
				((BaseUnityPlugin)this).Logger.LogError((object)("EffectsControl patches failed; original visuals retained. " + ex));
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)"EffectsControl 1.0.1: weapon and magic shield visual controls ready.");
		}

		internal void RequestCatalog()
		{
			rebuild = true;
		}

		private void RebuildCatalog()
		{
			Catalog.Clear();
			if (Object.op_Implicit((Object)(object)ObjectDB.instance))
			{
				foreach (GameObject item in ObjectDB.instance.m_items)
				{
					if (Object.op_Implicit((Object)(object)item))
					{
						ItemDrop component = item.GetComponent<ItemDrop>();
						if (Object.op_Implicit((Object)(object)component))
						{
							Catalog.RegisterItem(component.m_itemData);
						}
					}
				}
				foreach (StatusEffect statusEffect in ObjectDB.instance.m_StatusEffects)
				{
					SE_Shield val = (SE_Shield)(object)((statusEffect is SE_Shield) ? statusEffect : null);
					if (Object.op_Implicit((Object)(object)val))
					{
						Catalog.RegisterShield(val);
					}
				}
			}
			foreach (GameObject key in active.Keys)
			{
				if (Object.op_Implicit((Object)(object)key))
				{
					Projectile component2 = key.GetComponent<Projectile>();
					if (Object.op_Implicit((Object)(object)component2))
					{
						Catalog.RegisterProjectile(component2);
					}
					Aoe component3 = key.GetComponent<Aoe>();
					if (Object.op_Implicit((Object)(object)component3))
					{
						Catalog.RegisterAoe(component3);
					}
				}
			}
			bool flag = false;
			foreach (PluginInfo value in Chainloader.PluginInfos.Values)
			{
				if (string.Equals(value.Metadata.Name, "SubtleShield", StringComparison.OrdinalIgnoreCase) || value.Metadata.GUID.IndexOf("subtleshield", StringComparison.OrdinalIgnoreCase) >= 0)
				{
					flag = true;
				}
			}
			if (flag && !shieldConflict)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"SubtleShield is active. EffectsControl shield controls are suspended; disable SubtleShield and restart to use this mod's shield settings.");
			}
			shieldConflict = flag;
			optionsDirty = true;
			rebuild = false;
		}

		private void Update()
		{
			if (ready && rebuild)
			{
				Guard(RebuildCatalog);
			}
		}

		private void LateUpdate()
		{
			if (!ready)
			{
				return;
			}
			if (!rebuild)
			{
				foreach (GameObject item in pendingNetwork)
				{
					ObserveNetworkEffect(item);
				}
				pendingNetwork.Clear();
			}
			RefreshOptions();
			foreach (KeyValuePair<GameObject, EffectStage> pair in pending)
			{
				if (!Object.op_Implicit((Object)(object)pair.Key) || active.ContainsKey(pair.Key) || (pair.Value == EffectStage.Shield && shieldConflict))
				{
					continue;
				}
				Guard(delegate
				{
					VisualState visualState = new VisualState(pair.Key, pair.Value);
					if (visualState.Empty)
					{
						visualState.Dispose();
					}
					else
					{
						active.Add(pair.Key, visualState);
					}
				});
			}
			pending.Clear();
			expired.Clear();
			foreach (KeyValuePair<GameObject, VisualState> item2 in active)
			{
				if (!Object.op_Implicit((Object)(object)item2.Key))
				{
					item2.Value.Dispose();
					expired.Add(item2.Key);
					continue;
				}
				try
				{
					item2.Value.Apply(options[(int)item2.Value.Stage]);
				}
				catch (Exception error)
				{
					item2.Value.Dispose();
					expired.Add(item2.Key);
					Report(error);
				}
			}
			foreach (GameObject item3 in expired)
			{
				active.Remove(item3);
			}
		}

		internal void Observe(GameObject root, EffectStage stage)
		{
			if (ready && Object.op_Implicit((Object)(object)root) && !active.ContainsKey(root) && !pending.ContainsKey(root) && (stage != EffectStage.Shield || !shieldConflict) && !Object.op_Implicit((Object)(object)root.GetComponentInChildren<Character>(true)) && !Object.op_Implicit((Object)(object)root.GetComponentInChildren<Piece>(true)))
			{
				pending.Add(root, stage);
			}
		}

		private void RefreshOptions()
		{
			if (optionsDirty)
			{
				for (int i = 0; i < options.Length; i++)
				{
					options[i] = settings.Get((EffectStage)i, shieldConflict);
				}
				optionsDirty = false;
			}
		}

		internal void ObserveProjectile(GameObject root)
		{
			if (!ready || !Object.op_Implicit((Object)(object)root) || !Catalog.TryProjectile(root, out var stage))
			{
				return;
			}
			Guard(delegate
			{
				Projectile component = root.GetComponent<Projectile>();
				if (Object.op_Implicit((Object)(object)component))
				{
					Catalog.RegisterProjectile(component);
				}
				Aoe component2 = root.GetComponent<Aoe>();
				if (Object.op_Implicit((Object)(object)component2))
				{
					Catalog.RegisterAoe(component2);
				}
				Observe(root, stage);
			});
		}

		internal void ObserveNetworkEffect(GameObject root)
		{
			if (!ready || !Object.op_Implicit((Object)(object)root))
			{
				return;
			}
			if (rebuild)
			{
				pendingNetwork.Add(root);
			}
			else
			{
				if (!Catalog.TryEffect(root, out var stage))
				{
					return;
				}
				Guard(delegate
				{
					Projectile component = root.GetComponent<Projectile>();
					if (Object.op_Implicit((Object)(object)component))
					{
						Catalog.RegisterProjectile(component);
					}
					Aoe component2 = root.GetComponent<Aoe>();
					if (Object.op_Implicit((Object)(object)component2))
					{
						Catalog.RegisterAoe(component2);
					}
					Observe(root, stage);
				});
			}
		}

		internal void Guard(Action action)
		{
			try
			{
				action();
			}
			catch (Exception error)
			{
				Report(error);
			}
		}

		private void Report(Exception error)
		{
			if (failures++ < 5)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Visual control failed; gameplay continues. " + error));
			}
		}

		private void OnDestroy()
		{
			ready = false;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			foreach (VisualState value in active.Values)
			{
				value.Dispose();
			}
			active.Clear();
			pending.Clear();
			pendingNetwork.Clear();
			Catalog.Clear();
			Instance = null;
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "Awake")]
	internal static class DatabaseAwakePatch
	{
		private static void Postfix()
		{
			if (Object.op_Implicit((Object)(object)Plugin.Instance))
			{
				Plugin.Instance.RequestCatalog();
			}
		}
	}
	[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
	internal static class DatabaseCopyPatch
	{
		private static void Postfix()
		{
			if (Object.op_Implicit((Object)(object)Plugin.Instance))
			{
				Plugin.Instance.RequestCatalog();
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "Awake")]
	internal static class ScenePatch
	{
		private static void Postfix()
		{
			if (Object.op_Implicit((Object)(object)Plugin.Instance))
			{
				Plugin.Instance.RequestCatalog();
			}
		}
	}
	[HarmonyPatch(typeof(Attack), "Start")]
	internal static class AttackPatch
	{
		private static void Prefix(Attack __instance, ItemData weapon)
		{
			Plugin plugin = Plugin.Instance;
			if (Object.op_Implicit((Object)(object)plugin) && EffectCatalog.IsWeapon(weapon))
			{
				plugin.Guard(delegate
				{
					plugin.Catalog.RegisterItem(weapon);
					plugin.Catalog.RegisterAttack(__instance);
				});
			}
		}
	}
	[HarmonyPatch(typeof(EffectList), "Create")]
	internal static class EffectsPatch
	{
		private static void Postfix(EffectList __instance, GameObject[] __result)
		{
			Plugin instance = Plugin.Instance;
			if (Object.op_Implicit((Object)(object)instance) && __result != null && instance.Catalog.TryList(__instance, out var stage))
			{
				foreach (GameObject root in __result)
				{
					instance.Observe(root, stage);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Projectile), "Awake")]
	internal static class ProjectileAwakePatch
	{
		private static void Postfix(Projectile __instance)
		{
			if (Object.op_Implicit((Object)(object)Plugin.Instance))
			{
				Plugin.Instance.ObserveProjectile(((Component)__instance).gameObject);
			}
		}
	}
	[HarmonyPatch(typeof(Aoe), "Awake")]
	internal static class AoeAwakePatch
	{
		private static void Postfix(Aoe __instance)
		{
			if (Object.op_Implicit((Object)(object)Plugin.Instance))
			{
				Plugin.Instance.ObserveProjectile(((Component)__instance).gameObject);
			}
		}
	}
	[HarmonyPatch(typeof(ZNetScene), "CreateObject")]
	internal static class NetworkEffectsPatch
	{
		private static void Postfix(GameObject __result)
		{
			if (Object.op_Implicit((Object)(object)Plugin.Instance) && Object.op_Implicit((Object)(object)__result))
			{
				Plugin.Instance.ObserveNetworkEffect(__result);
			}
		}
	}
	[HarmonyPatch(typeof(Projectile), "Setup")]
	internal static class ProjectileSetupPatch
	{
		private static void Postfix(Projectile __instance, ItemData item, ItemData ammo)
		{
			Plugin p = Plugin.Instance;
			if (Object.op_Implicit((Object)(object)p) && (EffectCatalog.IsWeapon(item) || EffectCatalog.IsWeapon(ammo)))
			{
				p.Guard(delegate
				{
					p.Catalog.RegisterProjectile(__instance);
					p.Observe(((Component)__instance).gameObject, EffectStage.Flight);
				});
			}
		}
	}
	[HarmonyPatch(typeof(Aoe), "Setup")]
	internal static class AoeSetupPatch
	{
		private static void Postfix(Aoe __instance, ItemData item, ItemData ammo)
		{
			Plugin p = Plugin.Instance;
			if (Object.op_Implicit((Object)(object)p) && (EffectCatalog.IsWeapon(item) || EffectCatalog.IsWeapon(ammo)))
			{
				p.Guard(delegate
				{
					p.Catalog.RegisterAoe(__instance);
					p.Observe(((Component)__instance).gameObject, EffectStage.Impact);
				});
			}
		}
	}
	[HarmonyPatch(typeof(SE_Shield), "Setup")]
	internal static class ShieldPatch
	{
		private static void Prefix(SE_Shield __instance)
		{
			Plugin p = Plugin.Instance;
			if (Object.op_Implicit((Object)(object)p))
			{
				p.Guard(delegate
				{
					p.Catalog.RegisterShield(__instance);
				});
			}
		}
	}
	public enum EffectStage
	{
		Launch,
		Flight,
		Impact,
		Shield
	}
	public sealed class VisualOptions
	{
		public float Light = 1f;

		public float Glow = 1f;

		public float Opacity = 1f;

		public float Size = 1f;

		public float Density = 1f;

		public float ShieldOvality;

		public bool TintEnabled;

		public Color Tint = Color.white;

		public static VisualOptions Original()
		{
			return new VisualOptions();
		}
	}
	internal sealed class Settings
	{
		public readonly ConfigEntry<bool> Enabled;

		public readonly ConfigEntry<bool> Weapons;

		public readonly ConfigEntry<bool> Shields;

		public readonly ConfigEntry<bool> ShieldTint;

		public readonly ConfigEntry<int> Light;

		public readonly ConfigEntry<int> Glow;

		public readonly ConfigEntry<int> Opacity;

		public readonly ConfigEntry<int> Size;

		public readonly ConfigEntry<int> Density;

		public readonly ConfigEntry<int> Launch;

		public readonly ConfigEntry<int> Flight;

		public readonly ConfigEntry<int> Impact;

		public readonly ConfigEntry<int> ShieldLight;

		public readonly ConfigEntry<int> ShieldGlow;

		public readonly ConfigEntry<int> ShieldOpacity;

		public readonly ConfigEntry<int> ShieldOvality;

		public readonly ConfigEntry<int> ShieldColor;

		public event Action Changed;

		public Settings(ConfigFile config)
		{
			Enabled = config.Bind<bool>("1. General", "Enable mod", true, "Enable visual settings. Disabling restores the saved original appearance of active effects.");
			Weapons = config.Bind<bool>("1. General", "Weapon effects", true, "Control attack launch, flight and impact effects. Weather, fog and building lights are excluded.");
			Shields = config.Bind<bool>("1. General", "Magic shield", true, "Control Staff of Protection visuals. Shield control is suspended while SubtleShield is active; disable it and restart to use these settings.");
			Light = Percent(config, "2. Weapons - General", "Light brightness", 0, "Light intensity: reduce surrounding illumination and whiteout. Light range is unchanged.");
			Glow = Percent(config, "2. Weapons - General", "Glow", 50, "Particle colors and supported emissive/additive material colors. Some custom shaders ignore these properties.");
			Opacity = Percent(config, "2. Weapons - General", "Opacity", 25, "Particle and material alpha. Lower values increase transparency. Custom and opaque shaders may ignore alpha; 0 hides the visual renderers.");
			Size = Percent(config, "2. Weapons - General", "Size", 100, "Particle size, readable mesh geometry and trail width. Root transforms, colliders, trajectories, damage radius and particle travel distance are unchanged.");
			Density = Percent(config, "2. Weapons - General", "Particle count", 100, "Emission rates and burst counts relative to the original. Existing particles retain their lifetime; 0 hides particles. Direct Emit calls from other code are not limited at intermediate values.");
			Launch = Influence(config, "Attack launch", 100, "Influence of general settings on windup and projectile launch effects.");
			Flight = Influence(config, "Flight", 0, "Influence of general settings on a flying projectile. Speed and collisions are unchanged.");
			Impact = Influence(config, "Impact", 100, "Influence of general settings on hits, explosions and Aoe, including Demolisher hits.");
			ShieldLight = Percent(config, "4. Magic Shield", "Light brightness", 35, "Intensity of lights in the magic shield effect.");
			ShieldGlow = Percent(config, "4. Magic Shield", "Glow", 45, "Supported emissive/additive colors of the bubble and particles.");
			ShieldOpacity = Percent(config, "4. Magic Shield", "Opacity", 30, "Bubble and particle alpha. 0 hides the visual shield; protection and duration are unchanged.");
			ShieldOvality = Integer(config, "Ovality", 50, 0, 100, "Bubble shape: 0 is round; 50 is oval; 100 is a narrower oval. Height, protection and colliders are unchanged. Whole numbers only.");
			ShieldTint = config.Bind<bool>("4. Magic Shield", "Change color", false, "Replace supported material and particle RGB colors. Disable for original colors; alpha is controlled separately.");
			ShieldColor = Integer(config, "Color", 0, 0, 360, "Hue slider: 0/360 red, 60 yellow, 120 green, 180 cyan, 240 blue, 300 magenta. Used when Change color is enabled. Glow controls intensity; Opacity controls transparency. Whole numbers only.");
			config.SettingChanged += delegate
			{
				if (this.Changed != null)
				{
					this.Changed();
				}
			};
		}

		private static ConfigEntry<int> Percent(ConfigFile config, string section, string key, int value, string description)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			return config.Bind<int>(section, key, value, new ConfigDescription(description + " 100% is the original value; 0% disables this visual component. Whole numbers only. Scaling does not accumulate.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
		}

		private static ConfigEntry<int> Influence(ConfigFile config, string key, int value, string description)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			return config.Bind<int>("3. Weapons - Stages", key, value, new ConfigDescription(description + " 100% fully applies section 2 settings; 0% restores the original effect without their influence. Intermediate values blend the influence. Whole numbers only.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>()));
		}

		private static ConfigEntry<int> Integer(ConfigFile config, string key, int value, int min, int max, string description)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			return config.Bind<int>("4. Magic Shield", key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<int>(min, max), Array.Empty<object>()));
		}

		public VisualOptions Get(EffectStage stage, bool shieldConflict)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			if (!Enabled.Value || ((stage == EffectStage.Shield) ? (!Shields.Value || shieldConflict) : (!Weapons.Value)))
			{
				return VisualOptions.Original();
			}
			int value;
			switch (stage)
			{
			case EffectStage.Shield:
			{
				Color tint = Color.HSVToRGB((float)ShieldColor.Value / 360f, 1f, 1f);
				return new VisualOptions
				{
					Light = (float)ShieldLight.Value / 100f,
					Glow = (float)ShieldGlow.Value / 100f,
					Opacity = (float)ShieldOpacity.Value / 100f,
					ShieldOvality = (float)ShieldOvality.Value / 100f,
					TintEnabled = ShieldTint.Value,
					Tint = tint
				};
			}
			default:
				value = Impact.Value;
				break;
			case EffectStage.Flight:
				value = Flight.Value;
				break;
			case EffectStage.Launch:
				value = Launch.Value;
				break;
			}
			float num = (float)value / 100f;
			return new VisualOptions
			{
				Light = Mathf.Lerp(1f, (float)Light.Value / 100f, num),
				Glow = Mathf.Lerp(1f, (float)Glow.Value / 100f, num),
				Opacity = Mathf.Lerp(1f, (float)Opacity.Value / 100f, num),
				Size = Mathf.Lerp(1f, (float)Size.Value / 100f, num),
				Density = Mathf.Lerp(1f, (float)Density.Value / 100f, num)
			};
		}
	}
	public sealed class VisualState : IDisposable
	{
		public readonly EffectStage Stage;

		private readonly List<ParticleState> particles = new List<ParticleState>();

		private readonly List<LightState> lights = new List<LightState>();

		private readonly List<RendererState> renderers = new List<RendererState>();

		private readonly List<MeshState> meshes = new List<MeshState>();

		private bool disposed;

		public bool Empty => particles.Count + lights.Count + renderers.Count == 0;

		public VisualState(GameObject root, EffectStage stage)
		{
			Stage = stage;
			try
			{
				ParticleSystem[] componentsInChildren = root.GetComponentsInChildren<ParticleSystem>(true);
				foreach (ParticleSystem system in componentsInChildren)
				{
					particles.Add(new ParticleState(system));
				}
				Light[] componentsInChildren2 = root.GetComponentsInChildren<Light>(true);
				foreach (Light light in componentsInChildren2)
				{
					lights.Add(new LightState(light));
				}
				Renderer[] componentsInChildren3 = root.GetComponentsInChildren<Renderer>(true);
				foreach (Renderer val in componentsInChildren3)
				{
					renderers.Add(new RendererState(val));
					if (val is MeshRenderer)
					{
						MeshFilter component = ((Component)val).GetComponent<MeshFilter>();
						if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.sharedMesh) && component.sharedMesh.isReadable)
						{
							meshes.Add(new MeshState(component, stage == EffectStage.Shield && string.Equals(((Object)component).name, "Sphere", StringComparison.OrdinalIgnoreCase)));
						}
					}
				}
			}
			catch
			{
				Dispose();
				throw;
			}
		}

		public void Apply(VisualOptions options)
		{
			if (disposed)
			{
				return;
			}
			foreach (LightState light in lights)
			{
				light.Apply(options.Light);
			}
			foreach (ParticleState particle in particles)
			{
				particle.Apply(options);
			}
			foreach (RendererState renderer in renderers)
			{
				renderer.Apply(options);
			}
			foreach (MeshState mesh in meshes)
			{
				mesh.Apply(options);
			}
		}

		public void Dispose()
		{
			if (disposed)
			{
				return;
			}
			foreach (ParticleState particle in particles)
			{
				try
				{
					particle.Restore();
				}
				catch
				{
				}
			}
			foreach (LightState light in lights)
			{
				try
				{
					light.Restore();
				}
				catch
				{
				}
			}
			foreach (RendererState renderer in renderers)
			{
				try
				{
					renderer.Dispose();
				}
				catch
				{
				}
			}
			foreach (MeshState mesh in meshes)
			{
				try
				{
					mesh.Dispose();
				}
				catch
				{
				}
			}
			disposed = true;
		}
	}
	internal sealed class LightState
	{
		private readonly Light light;

		private float native;

		private float lastWritten;

		private bool wrote;

		public LightState(Light light)
		{
			this.light = light;
			native = light.intensity;
		}

		public void Apply(float factor)
		{
			if (Object.op_Implicit((Object)(object)light))
			{
				if (wrote && light.intensity != lastWritten)
				{
					native = light.intensity;
				}
				lastWritten = native * factor;
				light.intensity = lastWritten;
				wrote = true;
			}
		}

		public void Restore()
		{
			if (Object.op_Implicit((Object)(object)light) && wrote && light.intensity == lastWritten)
			{
				light.intensity = native;
			}
		}
	}
	internal static class CurveScale
	{
		public static MinMaxCurve Multiply(MinMaxCurve original, float factor)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Invalid comparison between Unknown and I4
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			ParticleSystemCurveMode mode = ((MinMaxCurve)(ref original)).mode;
			if ((int)mode != 0)
			{
				if ((int)mode == 3)
				{
					((MinMaxCurve)(ref original)).constantMin = ((MinMaxCurve)(ref original)).constantMin * factor;
					((MinMaxCurve)(ref original)).constantMax = ((MinMaxCurve)(ref original)).constantMax * factor;
				}
				else
				{
					((MinMaxCurve)(ref original)).curveMultiplier = ((MinMaxCurve)(ref original)).curveMultiplier * factor;
				}
			}
			else
			{
				((MinMaxCurve)(ref original)).constant = ((MinMaxCurve)(ref original)).constant * factor;
			}
			return original;
		}
	}
	internal sealed class ParticleState
	{
		private sealed class NativeParticle
		{
			public Color32 Color;

			public Vector3 Size;

			public float Remaining;

			public float Lifetime;

			public int Ticket;
		}

		private readonly ParticleSystem system;

		private readonly MinMaxCurve timeRate;

		private readonly MinMaxCurve distanceRate;

		private readonly Burst[] bursts;

		private readonly Dictionary<uint, List<NativeParticle>> live = new Dictionary<uint, List<NativeParticle>>();

		private readonly List<uint> emptySeeds = new List<uint>();

		private Particle[] buffer = (Particle[])(object)new Particle[64];

		private float density = -1f;

		private int ticket;

		public ParticleState(ParticleSystem system)
		{
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			this.system = system;
			EmissionModule emission = system.emission;
			timeRate = ((EmissionModule)(ref emission)).rateOverTime;
			distanceRate = ((EmissionModule)(ref emission)).rateOverDistance;
			bursts = (Burst[])(object)new Burst[((EmissionModule)(ref emission)).burstCount];
			((EmissionModule)(ref emission)).GetBursts(bursts);
		}

		public void Apply(VisualOptions options)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)system))
			{
				return;
			}
			if (density != options.Density)
			{
				EmissionModule emission = system.emission;
				((EmissionModule)(ref emission)).rateOverTime = CurveScale.Multiply(timeRate, options.Density);
				((EmissionModule)(ref emission)).rateOverDistance = CurveScale.Multiply(distanceRate, options.Density);
				Burst[] array = (Burst[])(object)new Burst[bursts.Length];
				for (int i = 0; i < bursts.Length; i++)
				{
					array[i] = bursts[i];
					((Burst)(ref array[i])).count = CurveScale.Multiply(((Burst)(ref bursts[i])).count, options.Density);
				}
				((EmissionModule)(ref emission)).SetBursts(array);
				density = options.Density;
			}
			ApplyLive(options);
		}

		private void ApplyLive(VisualOptions options)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_020f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)system) || !((Component)system).gameObject.activeInHierarchy)
			{
				return;
			}
			int particleCount = system.particleCount;
			if (particleCount > buffer.Length)
			{
				buffer = (Particle[])(object)new Particle[Mathf.NextPowerOfTwo(particleCount)];
			}
			particleCount = system.GetParticles(buffer);
			ticket++;
			for (int i = 0; i < particleCount; i++)
			{
				Particle val = buffer[i];
				if (!live.TryGetValue(((Particle)(ref val)).randomSeed, out var value))
				{
					value = new List<NativeParticle>();
					live.Add(((Particle)(ref val)).randomSeed, value);
				}
				NativeParticle nativeParticle = null;
				float num = float.MaxValue;
				foreach (NativeParticle item in value)
				{
					float num2 = item.Remaining - ((Particle)(ref val)).remainingLifetime;
					if (item.Ticket != ticket && item.Lifetime == ((Particle)(ref val)).startLifetime && !(num2 < -0.0001f) && num2 < num)
					{
						nativeParticle = item;
						num = num2;
					}
				}
				if (nativeParticle == null)
				{
					nativeParticle = new NativeParticle
					{
						Color = ((Particle)(ref val)).startColor,
						Size = ((Particle)(ref val)).startSize3D,
						Lifetime = ((Particle)(ref val)).startLifetime
					};
					value.Add(nativeParticle);
				}
				nativeParticle.Ticket = ticket;
				nativeParticle.Remaining = ((Particle)(ref val)).remainingLifetime;
				Color val2 = Color32.op_Implicit(nativeParticle.Color);
				if (options.TintEnabled)
				{
					val2.r = options.Tint.r;
					val2.g = options.Tint.g;
					val2.b = options.Tint.b;
				}
				val2.r *= options.Glow;
				val2.g *= options.Glow;
				val2.b *= options.Glow;
				val2.a *= options.Opacity;
				((Particle)(ref val)).startColor = Color32.op_Implicit(val2);
				((Particle)(ref val)).startSize3D = nativeParticle.Size * options.Size;
				buffer[i] = val;
			}
			system.SetParticles(buffer, particleCount);
			emptySeeds.Clear();
			foreach (KeyValuePair<uint, List<NativeParticle>> item2 in live)
			{
				item2.Value.RemoveAll((NativeParticle p) => p.Ticket != ticket);
				if (item2.Value.Count == 0)
				{
					emptySeeds.Add(item2.Key);
				}
			}
			foreach (uint emptySeed in emptySeeds)
			{
				live.Remove(emptySeed);
			}
		}

		public void Restore()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)system))
			{
				EmissionModule emission = system.emission;
				((EmissionModule)(ref emission)).rateOverTime = timeRate;
				((EmissionModule)(ref emission)).rateOverDistance = distanceRate;
				((EmissionModule)(ref emission)).SetBursts(bursts);
				ApplyLive(VisualOptions.Original());
				live.Clear();
			}
		}
	}
	internal sealed class RendererState : IDisposable
	{
		private readonly Renderer renderer;

		private readonly bool forceOff;

		private readonly List<MaterialState> materials = new List<MaterialState>();

		private readonly Material[] originals;

		private readonly Material[] clones;

		private readonly float width;

		private readonly bool particle;

		public RendererState(Renderer renderer)
		{
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Expected O, but got Unknown
			this.renderer = renderer;
			forceOff = renderer.forceRenderingOff;
			particle = renderer is ParticleSystemRenderer;
			TrailRenderer val = (TrailRenderer)(object)((renderer is TrailRenderer) ? renderer : null);
			LineRenderer val2 = (LineRenderer)(object)((renderer is LineRenderer) ? renderer : null);
			width = (Object.op_Implicit((Object)(object)val) ? val.widthMultiplier : (Object.op_Implicit((Object)(object)val2) ? val2.widthMultiplier : 1f));
			originals = renderer.sharedMaterials;
			clones = (Material[])(object)new Material[originals.Length];
			try
			{
				for (int i = 0; i < originals.Length; i++)
				{
					if (Object.op_Implicit((Object)(object)originals[i]))
					{
						clones[i] = new Material(originals[i]);
						materials.Add(new MaterialState(clones[i], particle));
					}
				}
				renderer.sharedMaterials = clones;
			}
			catch
			{
				Dispose();
				throw;
			}
		}

		public void Apply(VisualOptions options)
		{
			if (!Object.op_Implicit((Object)(object)renderer))
			{
				return;
			}
			renderer.forceRenderingOff = forceOff || options.Opacity <= 0f || options.Size <= 0f || (particle && options.Density <= 0f);
			foreach (MaterialState material in materials)
			{
				material.Apply(options);
			}
			Renderer obj = renderer;
			TrailRenderer val = (TrailRenderer)(object)((obj is TrailRenderer) ? obj : null);
			if (Object.op_Implicit((Object)(object)val))
			{
				val.widthMultiplier = width * options.Size;
			}
			Renderer obj2 = renderer;
			LineRenderer val2 = (LineRenderer)(object)((obj2 is LineRenderer) ? obj2 : null);
			if (Object.op_Implicit((Object)(object)val2))
			{
				val2.widthMultiplier = width * options.Size;
			}
		}

		public void Dispose()
		{
			if (Object.op_Implicit((Object)(object)renderer))
			{
				renderer.forceRenderingOff = forceOff;
				Material[] sharedMaterials = renderer.sharedMaterials;
				for (int i = 0; i < Math.Min(sharedMaterials.Length, originals.Length); i++)
				{
					if ((Object)(object)sharedMaterials[i] == (Object)(object)clones[i])
					{
						sharedMaterials[i] = originals[i];
					}
				}
				renderer.sharedMaterials = sharedMaterials;
				Renderer obj = renderer;
				TrailRenderer val = (TrailRenderer)(object)((obj is TrailRenderer) ? obj : null);
				if (Object.op_Implicit((Object)(object)val))
				{
					val.widthMultiplier = width;
				}
				Renderer obj2 = renderer;
				LineRenderer val2 = (LineRenderer)(object)((obj2 is LineRenderer) ? obj2 : null);
				if (Object.op_Implicit((Object)(object)val2))
				{
					val2.widthMultiplier = width;
				}
			}
			Material[] array = clones;
			foreach (Material val3 in array)
			{
				if (Object.op_Implicit((Object)(object)val3))
				{
					ReleaseVisual.Destroy((Object)(object)val3);
				}
			}
		}
	}
	internal sealed class MaterialState
	{
		private sealed class ColorProperty
		{
			public string Name;

			public Color Native;

			public Color Last;

			public bool Written;

			public bool Emission;
		}

		private readonly Material material;

		private readonly bool particle;

		private readonly List<ColorProperty> colors = new List<ColorProperty>();

		public MaterialState(Material material, bool particle)
		{
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			this.material = material;
			this.particle = particle;
			string[] array = new string[6] { "_Color", "_BaseColor", "_TintColor", "_EmissionColor", "_EmissiveColor", "_EmisColor" };
			foreach (string text in array)
			{
				if (material.HasProperty(text))
				{
					colors.Add(new ColorProperty
					{
						Name = text,
						Native = material.GetColor(text),
						Emission = (text.IndexOf("Emis", StringComparison.Ordinal) >= 0)
					});
				}
			}
		}

		public void Apply(VisualOptions options)
		{
			//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)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)material))
			{
				return;
			}
			foreach (ColorProperty color2 in colors)
			{
				Color color = material.GetColor(color2.Name);
				if (color2.Written && color != color2.Last)
				{
					color2.Native = color;
				}
				Color native = color2.Native;
				if (options.TintEnabled)
				{
					native.r = options.Tint.r;
					native.g = options.Tint.g;
					native.b = options.Tint.b;
				}
				if (color2.Emission || !particle)
				{
					native.r *= options.Glow;
					native.g *= options.Glow;
					native.b *= options.Glow;
				}
				if (!particle)
				{
					native.a *= options.Opacity;
				}
				material.SetColor(color2.Name, native);
				color2.Last = native;
				color2.Written = true;
			}
		}
	}
	internal sealed class MeshState : IDisposable
	{
		private readonly MeshFilter filter;

		private readonly Mesh original;

		private readonly Mesh clone;

		private readonly Vector3[] vertices;

		private readonly Vector3[] adjusted;

		private readonly Vector3[] normals;

		private readonly Vector3[] adjustedNormals;

		private readonly Vector4[] tangents;

		private readonly Vector4[] adjustedTangents;

		private readonly Vector3 center;

		private readonly bool shieldBubble;

		private float size = -1f;

		private float ovality = -1f;

		public MeshState(MeshFilter filter, bool shieldBubble)
		{
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
			this.filter = filter;
			this.shieldBubble = shieldBubble;
			original = filter.sharedMesh;
			clone = Object.Instantiate<Mesh>(original);
			vertices = original.vertices;
			normals = original.normals;
			adjustedNormals = (Vector3[])(object)new Vector3[normals.Length];
			tangents = original.tangents;
			adjustedTangents = (Vector4[])(object)new Vector4[tangents.Length];
			adjusted = (Vector3[])(object)new Vector3[vertices.Length];
			Bounds bounds = original.bounds;
			center = ((Bounds)(ref bounds)).center;
			filter.sharedMesh = clone;
		}

		public void Apply(VisualOptions options)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_021b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0222: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0240: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)filter) || (Object)(object)filter.sharedMesh != (Object)(object)clone)
			{
				return;
			}
			float num = (shieldBubble ? Mathf.Clamp01(options.ShieldOvality) : 0f);
			if (options.Size == size && num == ovality)
			{
				return;
			}
			float num2 = 1f - num * 0.5f;
			Vector3 val = new Vector3(num2, 1f, num2) * options.Size;
			for (int i = 0; i < vertices.Length; i++)
			{
				adjusted[i] = center + Vector3.Scale(vertices[i] - center, val);
			}
			clone.vertices = adjusted;
			for (int j = 0; j < normals.Length; j++)
			{
				Vector3[] array = adjustedNormals;
				int num3 = j;
				? val3;
				if (num != 0f)
				{
					Vector3 val2 = new Vector3(normals[j].x / num2, normals[j].y, normals[j].z / num2);
					val3 = ((Vector3)(ref val2)).normalized;
				}
				else
				{
					val3 = normals[j];
				}
				array[num3] = (Vector3)val3;
			}
			Vector3 val4 = default(Vector3);
			for (int k = 0; k < tangents.Length; k++)
			{
				if (num == 0f)
				{
					adjustedTangents[k] = tangents[k];
					continue;
				}
				((Vector3)(ref val4))..ctor(tangents[k].x * num2, tangents[k].y, tangents[k].z * num2);
				if (k < adjustedNormals.Length)
				{
					val4 -= adjustedNormals[k] * Vector3.Dot(adjustedNormals[k], val4);
				}
				((Vector3)(ref val4)).Normalize();
				adjustedTangents[k] = new Vector4(val4.x, val4.y, val4.z, tangents[k].w);
			}
			clone.normals = adjustedNormals;
			clone.tangents = adjustedTangents;
			clone.RecalculateBounds();
			size = options.Size;
			ovality = num;
		}

		public void Dispose()
		{
			if (Object.op_Implicit((Object)(object)filter) && (Object)(object)filter.sharedMesh == (Object)(object)clone)
			{
				filter.sharedMesh = original;
			}
			if (Object.op_Implicit((Object)(object)clone))
			{
				ReleaseVisual.Destroy((Object)(object)clone);
			}
		}
	}
	internal static class ReleaseVisual
	{
		public static void Destroy(Object resource)
		{
			if (Application.isPlaying)
			{
				Object.Destroy(resource);
			}
			else
			{
				Object.DestroyImmediate(resource);
			}
		}
	}
}