Decompiled source of Voidsong v1.2.0

HKVoidsongMod.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using GlobalSettings;
using HarmonyLib;
using HutongGames.PlayMaker;
using HutongGames.PlayMaker.Actions;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("HKVoidsongMod")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("HKVoidsongMod")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("1d46aad1-ba46-46ed-ad7e-6a5ad731ed2e")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
[BepInPlugin("com.layeredone.SSVS", "Voidsong", "1.0.0")]
public class VoidSongMod : BaseUnityPlugin
{
	[CompilerGenerated]
	private sealed class <ActivateAttackRoutine>d__24 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public BlackThreadState __instance;

		public GameObject attackObj;

		private GameObject <attackObjClone>5__1;

		private FieldInfo <atkField>5__2;

		private BlackThreadAttack <atk>5__3;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <ActivateAttackRoutine>d__24(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<attackObjClone>5__1 = null;
			<atkField>5__2 = null;
			<atk>5__3 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Expected O, but got Unknown
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<attackObjClone>5__1 = Object.Instantiate<GameObject>(attackObj, ((Component)__instance).transform.position, Quaternion.identity);
				if ((Object)(object)<attackObjClone>5__1 == (Object)null)
				{
					return false;
				}
				<>2__current = (object)new WaitForSeconds(0.1f);
				<>1__state = 1;
				return true;
			case 1:
			{
				<>1__state = -1;
				<atkField>5__2 = typeof(BlackThreadState).GetField("chosenAttack", BindingFlags.Instance | BindingFlags.NonPublic);
				ref BlackThreadAttack reference = ref <atk>5__3;
				object? obj = <atkField>5__2?.GetValue(__instance);
				reference = (BlackThreadAttack)((obj is BlackThreadAttack) ? obj : null);
				<attackObjClone>5__1.SetActive(true);
				<>2__current = (object)new WaitForSeconds(1f);
				<>1__state = 2;
				return true;
			}
			case 2:
				<>1__state = -1;
				Object.Destroy((Object)(object)<attackObjClone>5__1, 3f);
				<>2__current = (object)new WaitForSeconds(3f);
				<>1__state = 3;
				return true;
			case 3:
				<>1__state = -1;
				return false;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <DummyIdleRoutine>d__25 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <DummyIdleRoutine>d__25(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				break;
			case 1:
				<>1__state = -1;
				break;
			}
			<>2__current = null;
			<>1__state = 1;
			return true;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <SimpleThreadRoutine>d__22 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public BlackThreadState state;

		private MethodInfo <setVisiblyThreaded>5__1;

		private GameObject <startEffect>5__2;

		private MethodInfo <setBlackThreadAmount>5__3;

		private MethodInfo <startAttackTest>5__4;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <SimpleThreadRoutine>d__22(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<setVisiblyThreaded>5__1 = null;
			<startEffect>5__2 = null;
			<setBlackThreadAmount>5__3 = null;
			<startAttackTest>5__4 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0092: 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_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Expected O, but got Unknown
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<setVisiblyThreaded>5__1 = typeof(BlackThreadState).GetMethod("SetVisiblyThreaded", BindingFlags.Instance | BindingFlags.NonPublic);
				<setVisiblyThreaded>5__1?.Invoke(state, null);
				<startEffect>5__2 = Effects.BlackThreadEnemyStartEffect;
				if ((Object)(object)<startEffect>5__2 != (Object)null)
				{
					ObjectPoolExtensions.Spawn(<startEffect>5__2, ((Component)state).transform, Vector2.op_Implicit(Vector2.zero));
				}
				<setBlackThreadAmount>5__3 = typeof(BlackThreadState).GetMethod("SetBlackThreadAmount", BindingFlags.Instance | BindingFlags.NonPublic);
				<setBlackThreadAmount>5__3?.Invoke(state, new object[1] { 1f });
				<>2__current = (object)new WaitForSeconds(2f);
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				<startAttackTest>5__4 = typeof(BlackThreadState).GetMethod("StartAttackTest", BindingFlags.Instance | BindingFlags.NonPublic);
				break;
			case 2:
				<>1__state = -1;
				break;
			}
			<startAttackTest>5__4?.Invoke(state, null);
			<>2__current = (object)new WaitForSeconds(Random.Range(3f, 10f));
			<>1__state = 2;
			return true;
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <SpawnPrefabsDeferred>d__17 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public BlackThreadState state;

		private FieldInfo <fieldAttacks>5__1;

		private BlackThreadAttack[] <attacks>5__2;

		private FieldInfo <fieldSpawned>5__3;

		private Dictionary<BlackThreadAttack, GameObject> <spawned>5__4;

		private BlackThreadAttack[] <>s__5;

		private int <>s__6;

		private BlackThreadAttack <atk>5__7;

		private GameObject <go>5__8;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <SpawnPrefabsDeferred>d__17(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<fieldAttacks>5__1 = null;
			<attacks>5__2 = null;
			<fieldSpawned>5__3 = null;
			<spawned>5__4 = null;
			<>s__5 = null;
			<atk>5__7 = null;
			<go>5__8 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = null;
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				<fieldAttacks>5__1 = typeof(BlackThreadState).GetField("attacks", BindingFlags.Instance | BindingFlags.NonPublic);
				<attacks>5__2 = <fieldAttacks>5__1?.GetValue(state) as BlackThreadAttack[];
				<fieldSpawned>5__3 = typeof(BlackThreadState).GetField("spawnedAttackObjs", BindingFlags.Instance | BindingFlags.NonPublic);
				<spawned>5__4 = <fieldSpawned>5__3?.GetValue(state) as Dictionary<BlackThreadAttack, GameObject>;
				if (<attacks>5__2 != null && <spawned>5__4 != null)
				{
					<>s__5 = <attacks>5__2;
					for (<>s__6 = 0; <>s__6 < <>s__5.Length; <>s__6++)
					{
						<atk>5__7 = <>s__5[<>s__6];
						if ((Object)(object)<atk>5__7 != (Object)null && (Object)(object)<atk>5__7.Prefab != (Object)null && !<spawned>5__4.ContainsKey(<atk>5__7))
						{
							<go>5__8 = Object.Instantiate<GameObject>(<atk>5__7.Prefab);
							<go>5__8.transform.SetParent(((Component)state).transform, false);
							<go>5__8.transform.localPosition = Vector3.zero;
							<go>5__8.SetActive(false);
							<spawned>5__4[<atk>5__7] = <go>5__8;
							Debug.Log((object)("VoidSong: Spawned prefab for " + ((Object)<atk>5__7).name));
							<go>5__8 = null;
						}
						<atk>5__7 = null;
					}
					<>s__5 = null;
				}
				return false;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	[CompilerGenerated]
	private sealed class <WaitFix>d__9 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public VoidSongMod <>4__this;

		private IEnumerable<AssetBundle> <existingBundles>5__1;

		private string <markedAsset>5__2;

		private IEnumerator<AssetBundle> <>s__3;

		private AssetBundle <ab>5__4;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <WaitFix>d__9(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<existingBundles>5__1 = null;
			<markedAsset>5__2 = null;
			<>s__3 = null;
			<ab>5__4 = null;
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = (object)new WaitForSeconds(5f);
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)">>>VoidHelper>>>Loading Void Attacks AssetBundle...");
				<existingBundles>5__1 = AssetBundle.GetAllLoadedAssetBundles();
				<markedAsset>5__2 = "Assets/Data Assets/Black Thread Attacks/Ball.asset";
				voidAttacksBundle = null;
				<>s__3 = <existingBundles>5__1.GetEnumerator();
				try
				{
					while (<>s__3.MoveNext())
					{
						<ab>5__4 = <>s__3.Current;
						if (<ab>5__4.Contains(<markedAsset>5__2))
						{
							voidAttacksBundle = <ab>5__4;
							((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)(">>>VoidHelper>>>Found VoidAttacksBundle: " + ((Object)<ab>5__4).name));
							break;
						}
						<ab>5__4 = null;
					}
				}
				finally
				{
					if (<>s__3 != null)
					{
						<>s__3.Dispose();
					}
				}
				<>s__3 = null;
				if ((Object)(object)voidAttacksBundle == (Object)null)
				{
					voidAttacksBundle = <>4__this.LoadBundleHelper("blackthread_assets_all.bundle");
				}
				createBlackThreadMaterial();
				((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)">>>VoidHelper>>>AssetBundle Load Attempt Finished.");
				Harmony.CreateAndPatchAll(typeof(VoidSongMod), (string)null);
				return false;
			}
		}

		bool IEnumerator.MoveNext()
		{
			//ILSpy generated this explicit interface implementation from .override directive in MoveNext
			return this.MoveNext();
		}

		[DebuggerHidden]
		void IEnumerator.Reset()
		{
			throw new NotSupportedException();
		}
	}

	private static AssetBundle voidAttacksBundle;

	private static bool canRandomizeAttacks = true;

	private static bool hasDistanceCheck = true;

	private static float maximumAttackRange = 150f;

	private static Material blackThreadMat;

	private static GameObject cachedWorkingAttackPrefab = new GameObject();

	private static string GetPlatformFolderName()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: 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_0009: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Invalid comparison between Unknown and I4
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: Invalid comparison between Unknown and I4
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_000f: Invalid comparison between Unknown and I4
		//IL_001f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0022: Invalid comparison between Unknown and I4
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Invalid comparison between Unknown and I4
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Invalid comparison between Unknown and I4
		RuntimePlatform platform = Application.platform;
		RuntimePlatform val = platform;
		if ((int)val <= 2)
		{
			if ((int)val <= 1)
			{
				return "StandaloneOSX";
			}
			if ((int)val == 2)
			{
				goto IL_002d;
			}
		}
		else
		{
			if ((int)val == 7)
			{
				goto IL_002d;
			}
			if ((int)val == 13 || (int)val == 16)
			{
				return "StandaloneLinux64";
			}
		}
		Debug.LogWarning((object)"Didnt find platform, going to default StandaloneWindows64");
		return "StandaloneWindows64";
		IL_002d:
		return "StandaloneWindows64";
	}

	private AssetBundle LoadBundleHelper(string bundleName)
	{
		if ((Object)(object)voidAttacksBundle != (Object)null)
		{
			return voidAttacksBundle;
		}
		string text = Path.Combine(Application.dataPath, "StreamingAssets", "aa", GetPlatformFolderName(), bundleName);
		if (File.Exists(text))
		{
			AssetBundle val = AssetBundle.LoadFromFile(text);
			if ((Object)(object)val == (Object)null)
			{
				Debug.LogWarning((object)"Failed to load AssetBundle!");
				return null;
			}
			Debug.Log((object)"AssetBundle loaded successfully.");
			string[] allAssetNames = val.GetAllAssetNames();
			foreach (string text2 in allAssetNames)
			{
				Debug.Log((object)(">>>VoidSong:AssetLogger>>>Asset in bundle: " + text2));
			}
			if (bundleName == "blackthread_assets_all.bundle")
			{
				voidAttacksBundle = val;
			}
			return val;
		}
		Debug.LogWarning((object)("AssetBundle file not found at path: " + text));
		return null;
	}

	private static GameObject LoadPref(string prefName)
	{
		if ((Object)(object)voidAttacksBundle == (Object)null)
		{
			return null;
		}
		return voidAttacksBundle.LoadAsset<GameObject>(prefName);
	}

	private static BlackThreadAttack LoadAttackAsset(string assetName)
	{
		if ((Object)(object)voidAttacksBundle == (Object)null)
		{
			return null;
		}
		return voidAttacksBundle.LoadAsset<BlackThreadAttack>(assetName);
	}

	private void Awake()
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin loaded and initialized.");
		((MonoBehaviour)this).StartCoroutine(WaitFix());
	}

	[IteratorStateMachine(typeof(<WaitFix>d__9))]
	private IEnumerator WaitFix()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <WaitFix>d__9(0)
		{
			<>4__this = this
		};
	}

	private static void createBlackThreadMaterial()
	{
		if ((Object)(object)voidAttacksBundle != (Object)null && (Object)(object)blackThreadMat == (Object)null)
		{
			blackThreadMat = voidAttacksBundle.LoadAsset<Material>("Assets/Materials/black thread strand.mat");
			if ((Object)(object)blackThreadMat != (Object)null)
			{
				Debug.Log((object)">>>VoidHelper>>>Loaded BlackThread material from bundle.");
			}
			else
			{
				Debug.Log((object)">>>Error<<<Failed to load blackthreadmaterial from bundle");
			}
		}
	}

	[HarmonyPatch(typeof(PlayMakerFSM), "Awake")]
	private static void PostFix(PlayMakerFSM __instance)
	{
		GameObject gameObject = ((Component)__instance).gameObject;
		if ((Object)(object)gameObject == (Object)null || (Object)(object)__instance == (Object)null || __instance.Fsm == null)
		{
			return;
		}
		FsmState state = __instance.Fsm.GetState("P1");
		if (state != null)
		{
			safeSet<SetFloatValue>(state.Actions.OfType<SetFloatValue>().FirstOrDefault((Func<SetFloatValue, bool>)((SetFloatValue a) => a.floatVariable != null && ((NamedVariable)a.floatVariable).Name == "Idle Time")), delegate(SetFloatValue a)
			{
				a.floatValue = FsmFloat.op_Implicit(0f);
			});
			safeSet<SetFloatValue>(state.Actions.OfType<SetFloatValue>().FirstOrDefault((Func<SetFloatValue, bool>)((SetFloatValue a) => a.floatVariable != null && ((NamedVariable)a.floatVariable).Name == "Time Between Attacks")), delegate(SetFloatValue a)
			{
				a.floatValue = FsmFloat.op_Implicit(0f);
			});
			safeSet<SetStringValue>(state.Actions.OfType<SetStringValue>().FirstOrDefault((Func<SetStringValue, bool>)((SetStringValue a) => a.stringVariable != null && ((NamedVariable)a.stringVariable).Name == "isFalse")), delegate(SetStringValue a)
			{
				a.stringValue = FsmString.op_Implicit("");
			});
			safeSet<SetFloatValue>(state.Actions.OfType<SetFloatValue>().FirstOrDefault((Func<SetFloatValue, bool>)((SetFloatValue a) => a.floatVariable != null && ((NamedVariable)a.floatVariable).Name == "time")), delegate(SetFloatValue a)
			{
				a.floatValue = FsmFloat.op_Implicit(0f);
			});
			safeSet<SetFloatValue>(state.Actions.OfType<SetFloatValue>().FirstOrDefault((Func<SetFloatValue, bool>)((SetFloatValue a) => a.floatVariable != null && ((NamedVariable)a.floatVariable).Name == "delay")), delegate(SetFloatValue a)
			{
				a.floatValue = FsmFloat.op_Implicit(0f);
			});
			safeSet<SetFloatValue>(state.Actions.OfType<SetFloatValue>().FirstOrDefault((Func<SetFloatValue, bool>)((SetFloatValue a) => a.floatVariable != null && ((NamedVariable)a.floatVariable).Name == "Delay")), delegate(SetFloatValue a)
			{
				a.floatValue = FsmFloat.op_Implicit(0f);
			});
			safeSet<SetIntValue>(state.Actions.OfType<SetIntValue>().FirstOrDefault((Func<SetIntValue, bool>)((SetIntValue a) => a.intVariable != null && ((NamedVariable)a.intVariable).Name == "damageAmount")), delegate(SetIntValue a)
			{
				a.intValue = FsmInt.op_Implicit(3);
			});
		}
		static void safeSet<T>(T action, Action<T> setter) where T : class
		{
			if (action != null)
			{
				setter(action);
			}
		}
	}

	[HarmonyPatch(typeof(PlayerData), "Awake")]
	private static void PlayerData_PostFix(PlayerData __instance)
	{
		if (__instance != null)
		{
			__instance.blackThreadWorld = true;
			__instance.defeatedCloverDancers = false;
			__instance.cloverDancerRegrowth = false;
			__instance.pilbyKilled = false;
			Debug.Log((object)"PlayerData modified to allow access to verdania again and other qol.");
		}
	}

	[HarmonyPatch(typeof(HealthManager), "Start")]
	[HarmonyPostfix]
	private static void HealthManager_PostFix(HealthManager __instance)
	{
		GameObject gameObject = ((Component)__instance).gameObject;
		BlackThreadState val = gameObject.GetComponent<BlackThreadState>();
		if ((Object)(object)val == (Object)null)
		{
			val = gameObject.AddComponent<BlackThreadState>();
			Debug.Log((object)("Added BlackThreadState to " + ((Object)gameObject).name));
		}
		ApplyOriginalBlackThreadEffectRobust(val);
		__instance.hp *= 3;
	}

	[HarmonyPatch(typeof(BlackThreadState), "Start")]
	[HarmonyPrefix]
	private static void InjectCustomAttacksToBlackThreadAttack_PreFix(BlackThreadState __instance)
	{
		if ((Object)(object)__instance == (Object)null)
		{
			return;
		}
		FieldInfo field = typeof(BlackThreadState).GetField("attacks", BindingFlags.Instance | BindingFlags.NonPublic);
		FieldInfo field2 = typeof(BlackThreadState).GetField("spawnedAttackObjs", BindingFlags.Instance | BindingFlags.NonPublic);
		if (field != null)
		{
			BlackThreadAttack[] array = (BlackThreadAttack[])(object)new BlackThreadAttack[9]
			{
				LoadAttackAsset("Assets/Data Assets/Black Thread Attacks/Ball.asset"),
				LoadAttackAsset("Assets/Data Assets/Black Thread Attacks/Grand Vomit.asset"),
				LoadAttackAsset("Assets/Data Assets/Black Thread Attacks/Heavy Vomit.asset"),
				LoadAttackAsset("Assets/Data Assets/Black Thread Attacks/MachineGun Shot Garmond.asset"),
				LoadAttackAsset("Assets/Data Assets/Black Thread Attacks/MachineGun Shot.asset"),
				LoadAttackAsset("Assets/Data Assets/Black Thread Attacks/Shot.asset"),
				LoadAttackAsset("Assets/Data Assets/Black Thread Attacks/Vomit Drop.asset"),
				LoadAttackAsset("Assets/Data Assets/Black Thread Attacks/Vomit.asset"),
				LoadAttackAsset("Assets/Data Assets/Black Thread Attacks/Whip.asset")
			};
			field.SetValue(__instance, array);
			Debug.Log((object)$">>>VoidHelper>>>Injected {array.Length} BlackThreadAttacks for: {((Object)__instance).name}");
			Dictionary<BlackThreadAttack, GameObject> dictionary = field2?.GetValue(__instance) as Dictionary<BlackThreadAttack, GameObject>;
			if (dictionary == null)
			{
				dictionary = new Dictionary<BlackThreadAttack, GameObject>();
				field2?.SetValue(__instance, dictionary);
				Debug.Log((object)(">>>VoidHelper>>>spawnedAttackObjs dictionary initialized for " + ((Object)__instance).name));
			}
		}
		EnsureValidPrefabs(__instance);
	}

	[HarmonyPatch(typeof(BlackThreadState), "Start")]
	[HarmonyPostfix]
	private static void BlackThreadState_Start_Postfix(BlackThreadState __instance)
	{
		((MonoBehaviour)__instance).StartCoroutine(SpawnPrefabsDeferred(__instance));
		__instance.BecomeThreadedNoSing();
	}

	[IteratorStateMachine(typeof(<SpawnPrefabsDeferred>d__17))]
	private static IEnumerator SpawnPrefabsDeferred(BlackThreadState state)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <SpawnPrefabsDeferred>d__17(0)
		{
			state = state
		};
	}

	private static void EnsureValidPrefabs(BlackThreadState state)
	{
		if (!(typeof(BlackThreadState).GetField("attacks", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(state) is BlackThreadAttack[] array))
		{
			return;
		}
		BlackThreadAttack[] array2 = array;
		foreach (BlackThreadAttack val in array2)
		{
			if ((Object)(object)val == (Object)null)
			{
				continue;
			}
			FieldInfo field = typeof(BlackThreadAttack).GetField("Prefab", BindingFlags.Instance | BindingFlags.Public);
			object? obj = field?.GetValue(val);
			GameObject val2 = (GameObject)((obj is GameObject) ? obj : null);
			if ((Object)(object)val2 == (Object)null)
			{
				GameObject val3 = null;
				if ((Object)(object)cachedWorkingAttackPrefab != (Object)null)
				{
					val3 = Object.Instantiate<GameObject>(cachedWorkingAttackPrefab);
					Debug.Log((object)("VoidSong_FallbackManager: Using cached working prefab " + ((Object)val3).name + " for attack " + ((Object)val).name));
				}
				else
				{
					val3 = LoadPref("Assets/Prefabs/Props/Thread Spines/thread_spines_standard.prefab");
				}
				if ((Object)(object)val3 != (Object)null)
				{
					field?.SetValue(val, val3);
					if (!((Object)val).name.EndsWith("_VsFallbackFix"))
					{
						((Object)val).name = ((Object)val).name + "_VsFallbackFix";
					}
					Debug.Log((object)("VoidSong_FallbackManager: Assigned real prefab " + ((Object)val3).name + " to attack " + ((Object)val).name));
				}
			}
			else
			{
				Debug.Log((object)("VoidSong_FallbackManager: Attack " + ((Object)val).name + " already has a valid prefab: " + ((Object)val2).name));
				Debug.Log((object)"VoidSong_FallbackManager: This prefab will be new fallback obj");
				cachedWorkingAttackPrefab = val2;
			}
		}
	}

	[HarmonyPatch(typeof(BlackThreadState), "ChooseAttack")]
	[HarmonyPrefix]
	private static bool ForceChooseAttack_Prefix(BlackThreadState __instance, bool force)
	{
		if (typeof(BlackThreadState).GetField("attacks", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(__instance) is BlackThreadAttack[] array && array.Length != 0)
		{
			BlackThreadAttack val = array[Random.Range(0, array.Length)];
			typeof(BlackThreadState).GetField("chosenAttack", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(__instance, val);
			typeof(BlackThreadState).GetField("hasChosenAttack", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(__instance, true);
			Debug.Log((object)("Forced attack: " + ((Object)val).name + " | for: " + ((Object)__instance).name));
			return false;
		}
		return true;
	}

	[HarmonyPatch(typeof(BlackThreadState), "BecomeThreadedRoutine")]
	[HarmonyPrefix]
	private static bool BecomeThreadedRoutine_Prefix(BlackThreadState __instance, ref IEnumerator __result, bool waitForSing)
	{
		FieldInfo field = typeof(BlackThreadState).GetField("singFsm", BindingFlags.Instance | BindingFlags.NonPublic);
		FieldInfo field2 = typeof(BlackThreadState).GetField("stunControlFsm", BindingFlags.Instance | BindingFlags.NonPublic);
		object? obj = field?.GetValue(__instance);
		PlayMakerFSM val = (PlayMakerFSM)((obj is PlayMakerFSM) ? obj : null);
		object? obj2 = field2?.GetValue(__instance);
		PlayMakerFSM val2 = (PlayMakerFSM)((obj2 is PlayMakerFSM) ? obj2 : null);
		Debug.Log((object)(">>>VoidsongBlackThreadAttackPatterns>>>: " + ((Object)__instance).name + " made to be blackThreaded with simple routine"));
		__result = SimpleThreadRoutine(__instance);
		return false;
	}

	[IteratorStateMachine(typeof(<SimpleThreadRoutine>d__22))]
	private static IEnumerator SimpleThreadRoutine(BlackThreadState state)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <SimpleThreadRoutine>d__22(0)
		{
			state = state
		};
	}

	[HarmonyPatch(typeof(BlackThreadState), "ThreadAttackTest")]
	[HarmonyPrefix]
	private static bool ThreadAttackTest_Prefix(BlackThreadState __instance, ref IEnumerator __result)
	{
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
		if (hasDistanceCheck)
		{
			HeroController instance = HeroController.instance;
			GameObject val = ((instance != null) ? ((Component)instance).gameObject : null);
			if ((Object)(object)val == (Object)null)
			{
				__result = DummyIdleRoutine();
				return false;
			}
			float num = Vector3.Distance(((Component)__instance).transform.position, val.transform.position);
			if (num > maximumAttackRange)
			{
				Debug.Log((object)$">>VoidsongEnemyDistance: The enemy {((Object)__instance).name} is too far away (distance: {num}/cap: {maximumAttackRange}) cast attack on player, return idle");
				__result = DummyIdleRoutine();
				return false;
			}
		}
		object? obj = typeof(BlackThreadState).GetField("chosenAttack", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(__instance);
		BlackThreadAttack val2 = (BlackThreadAttack)((obj is BlackThreadAttack) ? obj : null);
		BlackThreadAttack[] array = typeof(BlackThreadState).GetField("attacks", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(__instance) as BlackThreadAttack[];
		Dictionary<BlackThreadAttack, GameObject> dictionary = typeof(BlackThreadState).GetField("spawnedAttackObjs", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(__instance) as Dictionary<BlackThreadAttack, GameObject>;
		if ((Object)(object)val2 == (Object)null)
		{
			Debug.LogWarning((object)("VoidSong: " + ((Object)__instance).name + " has no chosenAttack, skipping."));
			__result = DummyIdleRoutine();
			return false;
		}
		if (canRandomizeAttacks)
		{
			val2 = array[Random.Range(0, array.Length)];
		}
		GameObject val3 = null;
		if (dictionary != null && dictionary.ContainsKey(val2))
		{
			val3 = dictionary[val2];
		}
		if ((Object)(object)val3 == (Object)null)
		{
			object? obj2 = typeof(BlackThreadAttack).GetField("Prefab", BindingFlags.Instance | BindingFlags.Public)?.GetValue(val2);
			GameObject val4 = (GameObject)((obj2 is GameObject) ? obj2 : null);
			if (!((Object)(object)val4 != (Object)null))
			{
				Debug.LogWarning((object)("VoidSong: " + ((Object)__instance).name + " has no prefab for " + ((Object)val2).name + ", skipping."));
				__result = SimpleThreadRoutine(__instance);
				return false;
			}
			val3 = Object.Instantiate<GameObject>(val4, ((Component)__instance).transform.position, Quaternion.identity);
			val3.SetActive(true);
			Debug.Log((object)("VoidSong: Fallback-spawned prefab " + ((Object)val4).name + " for " + ((Object)__instance).name));
		}
		__result = ActivateAttackRoutine(__instance, val3);
		return false;
	}

	[IteratorStateMachine(typeof(<ActivateAttackRoutine>d__24))]
	private static IEnumerator ActivateAttackRoutine(BlackThreadState __instance, GameObject attackObj)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <ActivateAttackRoutine>d__24(0)
		{
			__instance = __instance,
			attackObj = attackObj
		};
	}

	[IteratorStateMachine(typeof(<DummyIdleRoutine>d__25))]
	private static IEnumerator DummyIdleRoutine()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <DummyIdleRoutine>d__25(0);
	}

	[HarmonyPatch(typeof(BlackThreadState), "FirstThreadedSetUp")]
	[HarmonyPrefix]
	private static bool FirstThreadedSetUp_Prefix(BlackThreadState __instance)
	{
		//IL_0154: Unknown result type (might be due to invalid IL or missing references)
		Debug.Log((object)(">>>VoidHelper>>>Custom FirstThreadedSetUp for " + ((Object)__instance).name));
		if (!(typeof(BlackThreadState).GetField("attacks", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(__instance) is BlackThreadAttack[] array) || array.Length == 0)
		{
			Debug.LogWarning((object)(">>>VoidHelper>>>No attacks injected for " + ((Object)__instance).name));
			return false;
		}
		FieldInfo field = typeof(BlackThreadState).GetField("spawnedAttackObjs", BindingFlags.Instance | BindingFlags.NonPublic);
		Dictionary<BlackThreadAttack, GameObject> dictionary = field?.GetValue(__instance) as Dictionary<BlackThreadAttack, GameObject>;
		if (dictionary == null)
		{
			dictionary = new Dictionary<BlackThreadAttack, GameObject>();
			field?.SetValue(__instance, dictionary);
		}
		BlackThreadAttack[] array2 = array;
		foreach (BlackThreadAttack val in array2)
		{
			if (!((Object)(object)val == (Object)null))
			{
				object? obj = typeof(BlackThreadAttack).GetField("Prefab", BindingFlags.Instance | BindingFlags.Public)?.GetValue(val);
				GameObject val2 = (GameObject)((obj is GameObject) ? obj : null);
				if ((Object)(object)val2 != (Object)null && !dictionary.ContainsKey(val))
				{
					GameObject val3 = Object.Instantiate<GameObject>(val2);
					val3.transform.SetParent(((Component)__instance).transform, false);
					val3.transform.localPosition = Vector3.zero;
					val3.SetActive(false);
					dictionary[val] = val3;
					Debug.Log((object)(">>>VoidHelper>>>Spawned prefab for " + ((Object)val).name));
				}
			}
		}
		MethodInfo method = typeof(BlackThreadState).GetMethod("SetVisiblyThreaded", BindingFlags.Instance | BindingFlags.NonPublic);
		if (method != null)
		{
			method.Invoke(__instance, null);
		}
		typeof(BlackThreadState).GetMethod("SetBlackThreadAmount", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(__instance, new object[1] { 1f });
		return false;
	}

	private static void ApplyOriginalBlackThreadEffectRobust(BlackThreadState state, float tintAlpha = 0.6f)
	{
		//IL_016a: Unknown result type (might be due to invalid IL or missing references)
		if (!((Object)(object)state == (Object)null))
		{
			state.OnAwake();
			typeof(BlackThreadState).GetMethod("PreSpawnBlackThreadEffects", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(state, null);
			typeof(BlackThreadState).GetMethod("SetVisiblyThreaded", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(state, null);
			typeof(BlackThreadState).GetMethod("SetBlackThreadAmount", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(state, new object[1] { 1f });
			FieldInfo field = typeof(BlackThreadState).GetField("blackThreadEffectsObject", BindingFlags.Instance | BindingFlags.NonPublic);
			FieldInfo field2 = typeof(BlackThreadState).GetField("blackThreadEffectsFader", BindingFlags.Instance | BindingFlags.NonPublic);
			object? obj = field?.GetValue(state);
			GameObject val = (GameObject)((obj is GameObject) ? obj : null);
			object obj2 = field2?.GetValue(state);
			if ((Object)(object)val != (Object)null)
			{
				val.SetActive(true);
				(obj2?.GetType().GetProperty("AlphaSelf"))?.SetValue(obj2, 1f, null);
			}
			SpriteRenderer[] componentsInChildren = ((Component)state).GetComponentsInChildren<SpriteRenderer>(true);
			SpriteRenderer[] array = componentsInChildren;
			foreach (SpriteRenderer val2 in array)
			{
				val2.color = new Color(0f, 0f, 0f, tintAlpha);
			}
			Debug.Log((object)(">>>VoidHelper>>> Robust blackthread effect applied to " + ((Object)state).name));
		}
	}
}