Decompiled source of Katana v1.0.1

plugins\Katana.dll

Decompiled a day ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using BoplFixedMath;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Events;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Katana")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Bopl Battle instant melee katana. Kills on touch, 5s cooldown.")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("Katana")]
[assembly: AssemblyTitle("Katana")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace Katana
{
	public static class AbilityApiClonesFix
	{
		private const string Culprit = "AbilityApi";

		private static bool done;

		public static void Ensure()
		{
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			if (done)
			{
				return;
			}
			MethodInfo methodInfo = AccessTools.Method(typeof(PlayerCollision), "killPlayer", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				done = true;
				return;
			}
			Patches patchInfo = Harmony.GetPatchInfo((MethodBase)methodInfo);
			if (patchInfo == null || patchInfo.Prefixes == null || patchInfo.Prefixes.Count == 0)
			{
				return;
			}
			List<MethodInfo> list = new List<MethodInfo>();
			foreach (Patch prefix in patchInfo.Prefixes)
			{
				MethodInfo patchMethod = prefix.PatchMethod;
				if (!(patchMethod == null) && !(patchMethod.DeclaringType == null) && patchMethod.DeclaringType.FullName.Contains("AbilityApi"))
				{
					list.Add(patchMethod);
				}
			}
			if (list.Count == 0)
			{
				done = true;
				return;
			}
			Harmony val = new Harmony("katana.abilityapi.clonefix");
			foreach (MethodInfo item in list)
			{
				val.Unpatch((MethodBase)methodInfo, item);
			}
			done = true;
		}
	}
	public static class KatanaAbility
	{
		public const string AbilityName = "katana";

		public const string TemplateNameFragment = "invis";

		public const string IconTextureName = "KatanaIcon";

		public const int CooldownSeconds = 5;

		public static readonly Fix BoplDiameter = (Fix)2.2f;

		public static readonly Fix RangeMultiplier = (Fix)2f;

		public const float HeldWorldSize = 2.2f;

		public const float HoldDistance = 1.15f;

		public const float HoldHeight = -0.05f;

		public const float HeldRotateFixDegrees = -45f;

		public const int SlashVisualTicks = 48;

		public static readonly Vector4 CircleExtents = new Vector4(0.04882813f, 0.04882813f, 0.08300781f, 0.9287109f);

		public static bool IsKatana(GameObject go)
		{
			if ((Object)(object)go != (Object)null)
			{
				return ((Object)go).name.ToLower().Contains("katana");
			}
			return false;
		}

		public static bool IsKatanaIcon(Sprite sprite)
		{
			if ((Object)(object)sprite != (Object)null && (Object)(object)sprite.texture != (Object)null)
			{
				return ((Object)sprite.texture).name == "KatanaIcon";
			}
			return false;
		}

		public static Vec2 AimOf(int playerId)
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: 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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: 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_0056: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			PlayerHandler val = PlayerHandler.Get();
			Player val2 = ((val == null) ? null : val.GetPlayer(playerId));
			if (val2 == null)
			{
				return new Vec2(Fix.One, Fix.Zero);
			}
			Vec2 val3 = val2.AimVector();
			if (Vec2.Magnitude(val3) > (Fix)0.2f)
			{
				return Vec2.Normalized(val3);
			}
			return new Vec2(Fix.One, Fix.Zero);
		}

		public static float PlayerScale(int playerId)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			PlayerHandler val = PlayerHandler.Get();
			Player val2 = ((val == null) ? null : val.GetPlayer(playerId));
			if (val2 != null)
			{
				return Mathf.Max(0.01f, (float)val2.Scale);
			}
			return 1f;
		}

		public static Sprite LoadIcon(Sprite template)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: 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_0046: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = LoadTexture("Katana.AbilityIcon.png");
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			int size = 128;
			float pixelsPerUnit = 100f;
			if ((Object)(object)template != (Object)null)
			{
				Rect rect = template.rect;
				if (((Rect)(ref rect)).width > 8f)
				{
					rect = template.rect;
					size = Mathf.RoundToInt(((Rect)(ref rect)).width);
				}
				pixelsPerUnit = template.pixelsPerUnit;
			}
			Texture2D obj = BlitCentered(val, size, 0.72f);
			((Object)obj).name = "KatanaIcon";
			((Texture)obj).filterMode = (FilterMode)1;
			((Texture)obj).wrapMode = (TextureWrapMode)1;
			obj.Apply(false, false);
			Sprite obj2 = Build(obj, pixelsPerUnit);
			((Object)obj2).name = "katana";
			return obj2;
		}

		public static Sprite LoadHeldKatana()
		{
			Texture2D val = LoadTexture("Katana.AbilityIcon.png");
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			((Object)val).name = "KatanaHeld";
			return Build(val, (float)((Texture)val).width / 2.2f);
		}

		private static Texture2D BlitCentered(Texture2D source, int size, float fill)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: 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)
			Texture2D val = new Texture2D(size, size, (TextureFormat)4, false);
			Color[] pixels = (Color[])(object)new Color[size * size];
			val.SetPixels(pixels);
			int num = Mathf.Max(1, Mathf.RoundToInt((float)size * fill));
			int num2 = (size - num) / 2;
			int num3 = (size - num) / 2;
			Color[] pixels2 = source.GetPixels();
			int width = ((Texture)source).width;
			int height = ((Texture)source).height;
			for (int i = 0; i < num; i++)
			{
				int num4 = Mathf.Clamp(i * height / num, 0, height - 1);
				for (int j = 0; j < num; j++)
				{
					int num5 = Mathf.Clamp(j * width / num, 0, width - 1);
					Color val2 = pixels2[num4 * width + num5];
					if (!(val2.a < 0.05f))
					{
						val.SetPixel(num2 + j, num3 + i, val2);
					}
				}
			}
			return val;
		}

		private static Sprite Build(Texture2D texture, float pixelsPerUnit)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			((Texture)texture).filterMode = (FilterMode)1;
			((Texture)texture).wrapMode = (TextureWrapMode)1;
			return Sprite.Create(texture, new Rect(0f, 0f, (float)((Texture)texture).width, (float)((Texture)texture).height), new Vector2(0.5f, 0.5f), pixelsPerUnit, 0u, (SpriteMeshType)0);
		}

		private static Texture2D LoadTexture(string resourceName)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Expected O, but got Unknown
			using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
			if (stream == null)
			{
				Plugin.Log.LogError((object)("Katana: embedded resource '" + resourceName + "' not found."));
				return null;
			}
			byte[] array;
			using (MemoryStream memoryStream = new MemoryStream())
			{
				stream.CopyTo(memoryStream);
				array = memoryStream.ToArray();
			}
			Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false);
			if (!ImageConversion.LoadImage(val, array))
			{
				Plugin.Log.LogError((object)("Katana: '" + resourceName + "' failed to decode as a PNG."));
				return null;
			}
			val.Apply(false, false);
			return val;
		}
	}
	[HarmonyPatch(typeof(AbilityGrid), "Awake")]
	public static class KatanaInjectionPatch
	{
		private static bool hasInjected;

		public static void Prefix(AbilityGrid __instance)
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0147: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			if (hasInjected)
			{
				return;
			}
			NamedSpriteList abilityIcons = __instance.abilityIcons;
			if ((Object)(object)abilityIcons == (Object)null || abilityIcons.sprites == null)
			{
				Plugin.Log.LogWarning((object)"Katana: AbilityGrid.abilityIcons was empty this Awake; not injecting yet (will retry on the next grid build).");
				return;
			}
			NamedSprite val = default(NamedSprite);
			bool flag = false;
			foreach (NamedSprite sprite in abilityIcons.sprites)
			{
				if (sprite.name != null && sprite.name.ToLower().Contains("invis"))
				{
					val = sprite;
					flag = true;
					break;
				}
			}
			if (!flag || (Object)(object)val.associatedGameObject == (Object)null)
			{
				Plugin.Log.LogError((object)"Katana: could not find a native instant ability to clone, so the katana was not added. (Looked for an ability whose name contains 'invis'.)");
				return;
			}
			GameObject val2 = Object.Instantiate<GameObject>(val.associatedGameObject);
			Object.DontDestroyOnLoad((Object)(object)val2);
			((Object)val2).name = "katana";
			StripTemplateEffect(val2);
			InstantAbility component = val2.GetComponent<InstantAbility>();
			if ((Object)(object)component == (Object)null)
			{
				Plugin.Log.LogError((object)"Katana: the cloned ability has no InstantAbility component.");
				return;
			}
			component.SetCoolDown((Fix)5L);
			Sprite val3 = KatanaAbility.LoadIcon(val.sprite) ?? val.sprite;
			abilityIcons.sprites.Add(new NamedSprite("katana", val3, val2, true));
			hasInjected = true;
			Plugin.Log.LogInfo((object)("Katana: ability injected (cloned '" + val.name + "', " + $"cooldown {5}s)."));
		}

		private static void StripTemplateEffect(GameObject clone)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Expected O, but got Unknown
			InstantAbility component = clone.GetComponent<InstantAbility>();
			if ((Object)(object)component != (Object)null)
			{
				component.funcOnEnter = new UnityEvent();
				component.isInvisibilty = false;
				component.EffectOnEnter = null;
			}
			Invisibility component2 = clone.GetComponent<Invisibility>();
			if ((Object)(object)component2 != (Object)null)
			{
				Object.Destroy((Object)(object)component2);
			}
			SpriteRenderer[] componentsInChildren = clone.GetComponentsInChildren<SpriteRenderer>(true);
			foreach (SpriteRenderer obj in componentsInChildren)
			{
				obj.sprite = null;
				((Renderer)obj).enabled = false;
			}
		}
	}
	[HarmonyPatch(typeof(AbilityReadyIndicator), "SetSprite")]
	public static class KatanaCirclePatch
	{
		public static void Postfix(AbilityReadyIndicator __instance, Sprite sprite)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (KatanaAbility.IsKatanaIcon(sprite))
			{
				SpriteRenderer spriteRen = __instance.GetSpriteRen();
				if (!((Object)(object)spriteRen == (Object)null) && !((Object)(object)((Renderer)spriteRen).material == (Object)null))
				{
					((Renderer)spriteRen).material.SetVector("_CircleExtents", KatanaAbility.CircleExtents);
				}
			}
		}
	}
	[HarmonyPatch(typeof(InstantAbility), "EnterAbility")]
	public static class KatanaCastPatch
	{
		public static void Postfix(InstantAbility __instance)
		{
			if (KatanaAbility.IsKatana(((Component)__instance).gameObject))
			{
				SpriteRenderer[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<SpriteRenderer>(true);
				foreach (SpriteRenderer obj in componentsInChildren)
				{
					obj.sprite = null;
					((Renderer)obj).enabled = false;
				}
				Slash(__instance.playerInfo.playerId);
			}
		}

		private static void Slash(int playerId)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//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)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: 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)
			List<Vec2> origins = PlayerBodies.PositionsOf(playerId);
			if (origins.Count == 0)
			{
				Plugin.Log.LogWarning((object)$"Katana: player {playerId} cast the slash but no live body was found.");
				return;
			}
			Fix val = PlayerBodies.RadiusOf(playerId, KatanaAbility.BoplDiameter / (Fix)2L) * (Fix)2L * KatanaAbility.RangeMultiplier;
			Fix slashRadiusSqr = val * val;
			PlayerBodies.KillOthersWhere(playerId, playerId, (CauseOfDeath)0, delegate(Vec2 position)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0010: Unknown result type (might be due to invalid IL or missing references)
				//IL_0011: Unknown result type (might be due to invalid IL or missing references)
				//IL_0016: Unknown result type (might be due to invalid IL or missing references)
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				for (int i = 0; i < origins.Count; i++)
				{
					if (Vec2.SqrMagnitude(origins[i] - position) <= slashRadiusSqr)
					{
						return true;
					}
				}
				return false;
			});
			ProjectileReflect.ReflectNear(playerId, origins, val);
			ProjectileReflect.BeginSwing(playerId, val);
			SlashVisuals.Spawn(playerId);
		}
	}
	[HarmonyPatch(typeof(Updater), "TickSimulation")]
	public static class KatanaTickPatch
	{
		public static void Postfix()
		{
			AbilityApiClonesFix.Ensure();
			ProjectileReflect.Tick();
			SlashVisuals.Tick();
		}
	}
	[HarmonyPatch(typeof(PlayerHandler), "ResetForNextStage")]
	public static class KatanaResetPatch
	{
		public static void Prefix()
		{
			PlayerBodies.ForgetAll();
			ProjectileReflect.Forget();
			SlashVisuals.DestroyAll();
		}
	}
	[HarmonyPatch(typeof(Updater), "PreLevelLoad")]
	public static class KatanaLevelLoadPatch
	{
		public static void Prefix()
		{
			PlayerBodies.ForgetAll();
			ProjectileReflect.Forget();
			SlashVisuals.DestroyAll();
		}
	}
	internal static class PlayerBodies
	{
		private static readonly HashSet<int> alreadyKilled = new HashSet<int>();

		public static void ForgetAll()
		{
			alreadyKilled.Clear();
		}

		public static bool IsProtected(int playerId)
		{
			PlayerHandler val = PlayerHandler.Get();
			Player val2 = ((val == null) ? null : val.GetPlayer(playerId));
			if (val2 != null && val2.InPlatformTransform)
			{
				return true;
			}
			ControlPlatform[] array = Object.FindObjectsOfType<ControlPlatform>();
			foreach (ControlPlatform val3 in array)
			{
				if (!((Object)(object)val3 == (Object)null) && ((Behaviour)val3).isActiveAndEnabled)
				{
					IPlayerIdHolder component = ((Component)val3).GetComponent<IPlayerIdHolder>();
					if (component != null && component.GetPlayerId() == playerId)
					{
						return true;
					}
				}
			}
			return false;
		}

		public static List<Vec2> PositionsOf(int playerId)
		{
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			List<Vec2> list = new List<Vec2>();
			PlayerCollision[] array = Object.FindObjectsOfType<PlayerCollision>();
			foreach (PlayerCollision val in array)
			{
				if (!((Object)(object)val == (Object)null) && !((MonoUpdatable)val).IsDestroyed && ((Component)val).gameObject.activeInHierarchy && val.GetPlayerId() == playerId)
				{
					FixTransform component = ((Component)val).GetComponent<FixTransform>();
					if ((Object)(object)component != (Object)null && !component.IsDestroyed)
					{
						list.Add(component.position);
					}
				}
			}
			return list;
		}

		public static Fix RadiusOf(int playerId, Fix fallback)
		{
			//IL_0068: 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_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			PlayerCollision[] array = Object.FindObjectsOfType<PlayerCollision>();
			foreach (PlayerCollision val in array)
			{
				if (!((Object)(object)val == (Object)null) && !((MonoUpdatable)val).IsDestroyed && ((Component)val).gameObject.activeInHierarchy && val.GetPlayerId() == playerId)
				{
					PlayerPhysics component = ((Component)val).GetComponent<PlayerPhysics>();
					if ((Object)(object)component != (Object)null && component.radius > Fix.Zero)
					{
						return component.radius;
					}
				}
			}
			return fallback;
		}

		public static int KillOthersWhere(int killerId, int reportedKillerId, CauseOfDeath causeOfDeath, Func<Vec2, bool> isInside)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			int num = 0;
			PlayerCollision[] array = Object.FindObjectsOfType<PlayerCollision>();
			foreach (PlayerCollision val in array)
			{
				if ((Object)(object)val == (Object)null || ((MonoUpdatable)val).IsDestroyed || !((Component)val).gameObject.activeInHierarchy)
				{
					continue;
				}
				int playerId = val.GetPlayerId();
				if (playerId != killerId && !IsProtected(playerId))
				{
					FixTransform component = ((Component)val).GetComponent<FixTransform>();
					if (!((Object)(object)component == (Object)null) && !component.IsDestroyed && isInside(component.position) && !alreadyKilled.Contains(((Object)val).GetInstanceID()) && val.killPlayer(reportedKillerId, true, false, causeOfDeath))
					{
						alreadyKilled.Add(((Object)val).GetInstanceID());
						num++;
					}
				}
			}
			return num;
		}
	}
	[BepInPlugin("com.solsticio.boplbattle.katana", "Katana", "1.0.1")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "com.solsticio.boplbattle.katana";

		public const string PluginName = "Katana";

		public const string PluginVersion = "1.0.1";

		internal static ManualLogSource Log;

		private void Awake()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"Katana: loading...");
			new Harmony("com.solsticio.boplbattle.katana").PatchAll();
			Log.LogInfo((object)$"Katana: loaded (instant melee, cooldown {5}s).");
		}
	}
	internal static class ProjectileReflect
	{
		private sealed class Window
		{
			public int playerId;

			public Fix radius;

			public int ticksLeft;
		}

		private static readonly HashSet<int> reflected = new HashSet<int>();

		private static readonly List<Window> windows = new List<Window>();

		public static void Forget()
		{
			reflected.Clear();
			windows.Clear();
		}

		public static void BeginSwing(int playerId, Fix radius)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			windows.Add(new Window
			{
				playerId = playerId,
				radius = radius,
				ticksLeft = 48
			});
		}

		public static void Tick()
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			for (int num = windows.Count - 1; num >= 0; num--)
			{
				Window window = windows[num];
				List<Vec2> origins = PlayerBodies.PositionsOf(window.playerId);
				ReflectNear(window.playerId, origins, window.radius);
				window.ticksLeft--;
				if (window.ticksLeft <= 0)
				{
					windows.RemoveAt(num);
				}
			}
		}

		public static int ReflectNear(int playerId, List<Vec2> origins, Fix radius)
		{
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: 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_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: 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_0130: 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_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: 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_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: 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_010c: Unknown result type (might be due to invalid IL or missing references)
			if (origins == null || origins.Count == 0)
			{
				return 0;
			}
			Fix val = radius * radius;
			int num = 0;
			BoplBody[] array = Object.FindObjectsOfType<BoplBody>();
			foreach (BoplBody val2 in array)
			{
				if ((Object)(object)val2 == (Object)null || ((MonoUpdatable)val2).IsDestroyed || (Object)(object)((Component)val2).GetComponent<PlayerCollision>() != (Object)null)
				{
					continue;
				}
				Vec2 position = val2.position;
				bool flag = false;
				for (int j = 0; j < origins.Count; j++)
				{
					if (Vec2.SqrMagnitude(origins[j] - position) <= val)
					{
						flag = true;
						break;
					}
				}
				if (!flag)
				{
					continue;
				}
				int instanceID = ((Object)val2).GetInstanceID();
				if (reflected.Contains(instanceID))
				{
					continue;
				}
				Vec2 val3 = val2.StartVelocity;
				try
				{
					if (AccessTools.Property(typeof(BoplBody), "velocity")?.GetValue(val2, null) is Vec2 val4 && Vec2.SqrMagnitude(val4) > Fix.Zero)
					{
						val3 = val4;
					}
				}
				catch (Exception)
				{
				}
				if (Vec2.SqrMagnitude(val3) <= Fix.Zero)
				{
					continue;
				}
				Vec2 val5 = (val2.StartVelocity = -val3);
				try
				{
					PropertyInfo propertyInfo = AccessTools.Property(typeof(BoplBody), "velocity");
					if (propertyInfo != null && propertyInfo.CanWrite)
					{
						propertyInfo.SetValue(val2, val5, null);
					}
				}
				catch (Exception)
				{
				}
				FieldInfo fieldInfo = AccessTools.Field(typeof(BoplBody), "ownerId");
				if (fieldInfo != null)
				{
					fieldInfo.SetValue(val2, playerId);
				}
				reflected.Add(instanceID);
				num++;
			}
			return num;
		}
	}
	internal static class SlashVisuals
	{
		private sealed class SlashFx
		{
			public GameObject go;

			public int playerId;

			public int ticksLeft;
		}

		private static readonly List<SlashFx> live = new List<SlashFx>();

		private static Sprite heldSprite;

		public static void Spawn(int playerId)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)heldSprite == (Object)null)
			{
				heldSprite = KatanaAbility.LoadHeldKatana();
			}
			if (!((Object)(object)heldSprite == (Object)null))
			{
				GameObject val = new GameObject("KatanaHeld");
				SpriteRenderer obj = val.AddComponent<SpriteRenderer>();
				obj.sprite = heldSprite;
				obj.color = Color.white;
				((Renderer)obj).sortingOrder = 80;
				live.Add(new SlashFx
				{
					go = val,
					playerId = playerId,
					ticksLeft = 48
				});
				Place(val, playerId);
			}
		}

		public static void Tick()
		{
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			for (int num = live.Count - 1; num >= 0; num--)
			{
				SlashFx slashFx = live[num];
				slashFx.ticksLeft--;
				if ((Object)(object)slashFx.go != (Object)null && slashFx.ticksLeft > 0)
				{
					Place(slashFx.go, slashFx.playerId);
					SpriteRenderer component = slashFx.go.GetComponent<SpriteRenderer>();
					if ((Object)(object)component != (Object)null && slashFx.ticksLeft <= 4)
					{
						Color color = component.color;
						color.a = (float)slashFx.ticksLeft / 4f;
						component.color = color;
					}
				}
				if (slashFx.ticksLeft <= 0)
				{
					if ((Object)(object)slashFx.go != (Object)null)
					{
						Object.Destroy((Object)(object)slashFx.go);
					}
					live.RemoveAt(num);
				}
			}
		}

		public static void DestroyAll()
		{
			foreach (SlashFx item in live)
			{
				if ((Object)(object)item.go != (Object)null)
				{
					Object.Destroy((Object)(object)item.go);
				}
			}
			live.Clear();
		}

		private static void Place(GameObject go, int playerId)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_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_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: 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_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: 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_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			SpriteRenderer val = FindPlayerSprite(playerId);
			Vec2 val2 = KatanaAbility.AimOf(playerId);
			float num = KatanaAbility.PlayerScale(playerId);
			int sortingLayerID = 0;
			int sortingOrder = 80;
			Vector3 position = default(Vector3);
			if ((Object)(object)val != (Object)null)
			{
				position = ((Component)val).transform.position;
				sortingLayerID = ((Renderer)val).sortingLayerID;
				sortingOrder = ((Renderer)val).sortingOrder + 2;
			}
			else
			{
				List<Vec2> list = PlayerBodies.PositionsOf(playerId);
				if (list.Count == 0)
				{
					return;
				}
				((Vector3)(ref position))..ctor((float)list[0].x, (float)list[0].y, 0f);
			}
			Vector3 val3 = new Vector3((float)val2.x, (float)val2.y, 0f) * (1.15f * num);
			val3.y += -0.05f * num;
			go.transform.position = position + val3;
			float num2 = Mathf.Atan2((float)val2.y, (float)val2.x) * 57.29578f + -45f;
			go.transform.rotation = Quaternion.Euler(0f, 0f, num2);
			go.transform.localScale = new Vector3(num, num, 1f);
			SpriteRenderer component = go.GetComponent<SpriteRenderer>();
			if ((Object)(object)component != (Object)null)
			{
				((Renderer)component).sortingLayerID = sortingLayerID;
				((Renderer)component).sortingOrder = sortingOrder;
			}
		}

		private static SpriteRenderer FindPlayerSprite(int playerId)
		{
			SlimeController[] array = Object.FindObjectsOfType<SlimeController>();
			foreach (SlimeController val in array)
			{
				if (val.GetPlayerId() == playerId)
				{
					SpriteRenderer playerSprite = val.GetPlayerSprite();
					if ((Object)(object)playerSprite != (Object)null && ((Component)playerSprite).gameObject.activeInHierarchy)
					{
						return playerSprite;
					}
				}
			}
			return null;
		}
	}
	internal static class UniqueKatanaSlots
	{
		public static void Ensure(SlimeController slime)
		{
			if ((Object)(object)slime == (Object)null || slime.abilities == null)
			{
				return;
			}
			HashSet<int> hashSet = new HashSet<int>();
			for (int i = 0; i < slime.abilities.Count; i++)
			{
				AbilityMonoBehaviour val = slime.abilities[i];
				if ((Object)(object)val == (Object)null || !KatanaAbility.IsKatana(((Component)val).gameObject))
				{
					continue;
				}
				int instanceID = ((Object)val).GetInstanceID();
				if (!hashSet.Add(instanceID))
				{
					InstantAbility val2 = Clone(val);
					if ((Object)(object)val2 != (Object)null)
					{
						slime.abilities[i] = (AbilityMonoBehaviour)(object)val2;
					}
				}
			}
		}

		public static AbilityMonoBehaviour CloneIfKatana(AbilityMonoBehaviour ability)
		{
			if ((Object)(object)ability == (Object)null || !KatanaAbility.IsKatana(((Component)ability).gameObject))
			{
				return ability;
			}
			return (AbilityMonoBehaviour)(((object)Clone(ability)) ?? ((object)ability));
		}

		private static InstantAbility Clone(AbilityMonoBehaviour ability)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			GameObject obj = Object.Instantiate<GameObject>(((Component)ability).gameObject);
			Object.DontDestroyOnLoad((Object)(object)obj);
			((Object)obj).name = "katana";
			InstantAbility component = obj.GetComponent<InstantAbility>();
			if ((Object)(object)component != (Object)null)
			{
				component.SetCoolDown((Fix)5L);
			}
			return component;
		}
	}
	[HarmonyPatch(typeof(SlimeController), "AddAbility")]
	public static class KatanaAddAbilityPatch
	{
		public static void Prefix(ref AbilityMonoBehaviour ability)
		{
			ability = UniqueKatanaSlots.CloneIfKatana(ability);
		}
	}
	[HarmonyPatch(typeof(SlimeController), "AddAdditionalAbility")]
	public static class KatanaAddAdditionalAbilityPatch
	{
		public static void Prefix(ref AbilityMonoBehaviour ability)
		{
			ability = UniqueKatanaSlots.CloneIfKatana(ability);
		}
	}
	[HarmonyPatch(typeof(SlimeController), "OldUpdate")]
	public static class KatanaUniqueSlotsPatch
	{
		public static void Postfix(SlimeController __instance)
		{
			UniqueKatanaSlots.Ensure(__instance);
		}
	}
}