Decompiled source of SSVoidsong v1.1.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", "SSVoidsong", "1.0.0")]
public class VoidSongMod : BaseUnityPlugin
{
	[CompilerGenerated]
	private sealed class <ActivateAttackRoutine>d__20 : 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__20(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__21 : 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__21(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__18 : 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__18(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 <WaitFix>d__7 : 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;

		private string[] <>s__5;

		private int <>s__6;

		private string <assetName>5__7;

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

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

		[DebuggerHidden]
		public <WaitFix>d__7(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;
			<>s__5 = null;
			<assetName>5__7 = 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");
				}
				<>s__5 = voidAttacksBundle.GetAllAssetNames();
				for (<>s__6 = 0; <>s__6 < <>s__5.Length; <>s__6++)
				{
					<assetName>5__7 = <>s__5[<>s__6];
					Debug.Log((object)(">>>VoidSong:AssetLogger>>>Asset in bundle: " + <assetName>5__7));
					<assetName>5__7 = null;
				}
				<>s__5 = null;
				((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 Dictionary<AssetBundle, string> bundlePaths = new Dictionary<AssetBundle, string>();

	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__7))]
	private IEnumerator WaitFix()
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <WaitFix>d__7(0)
		{
			<>4__this = this
		};
	}

	[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);
			});
			safeSet<SetColorValue>(state.Actions.OfType<SetColorValue>().FirstOrDefault((Func<SetColorValue, bool>)((SetColorValue a) => a.colorVariable != null && ((NamedVariable)a.colorVariable).Name == "color")), delegate(SetColorValue a)
			{
				//IL_0015: Unknown result type (might be due to invalid IL or missing references)
				a.color = FsmColor.op_Implicit(new Color(23f / 85f, 1f / 85f, 0.47843137f, 1f));
			});
		}
		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)
	{
		if ((Object)(object)__instance != (Object)null)
		{
			GameObject gameObject = ((Component)__instance).gameObject;
			__instance.hp *= 3;
			if ((Object)(object)gameObject.GetComponent<BlackThreadState>() == (Object)null)
			{
				gameObject.AddComponent<BlackThreadState>();
				Debug.Log((object)("Added CustomEnemyBlackThreadState to " + ((Object)gameObject).name));
			}
		}
	}

	[HarmonyPatch(typeof(BlackThreadState), "Start")]
	[HarmonyPrefix]
	private static void InjectCustomAttacksToBlackThreadAttack_PreFix(BlackThreadState __instance)
	{
		GameObject gameObject = ((Component)__instance).gameObject;
		if ((Object)(object)__instance == (Object)null)
		{
			__instance = gameObject.AddComponent<BlackThreadState>();
		}
		if (!((Object)(object)__instance != (Object)null))
		{
			return;
		}
		FieldInfo field = typeof(BlackThreadState).GetField("attacks", BindingFlags.Instance | BindingFlags.NonPublic);
		if (field != null)
		{
			Debug.Log((object)"Found BlackThreadAttack.attacks field");
			BlackThreadAttack val = LoadAttackAsset("Assets/Data Assets/Black Thread Attacks/Ball.asset");
			BlackThreadAttack val2 = LoadAttackAsset("Assets/Data Assets/Black Thread Attacks/Grand Vomit.asset");
			BlackThreadAttack val3 = LoadAttackAsset("Assets/Data Assets/Black Thread Attacks/Heavy Vomit.asset");
			BlackThreadAttack val4 = LoadAttackAsset("Assets/Data Assets/Black Thread Attacks/MachineGun Shot Garmond.asset");
			BlackThreadAttack val5 = LoadAttackAsset("Assets/Data Assets/Black Thread Attacks/MachineGun Shot.asset");
			BlackThreadAttack val6 = LoadAttackAsset("Assets/Data Assets/Black Thread Attacks/Shot.asset");
			BlackThreadAttack val7 = LoadAttackAsset("Assets/Data Assets/Black Thread Attacks/Vomit Drop.asset");
			BlackThreadAttack val8 = LoadAttackAsset("Assets/Data Assets/Black Thread Attacks/Vomit.asset");
			BlackThreadAttack val9 = LoadAttackAsset("Assets/Data Assets/Black Thread Attacks/Whip.asset");
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null)
			{
				Debug.Log((object)">>>VoidHelper>>>One or more BlackThreadAttack assets failed to load!");
			}
			field.SetValue(__instance, new BlackThreadAttack[9] { val, val2, val3, val4, val5, val6, val7, val8, val9 });
			Debug.Log((object)(">>>VoidHelper>>>3 BlackThreadAttacks Added for: " + ((Object)__instance).name));
		}
	}

	[HarmonyPatch(typeof(BlackThreadState), "Start")]
	[HarmonyPostfix]
	private static void BlackThreadState_Start_Postfix(BlackThreadState __instance)
	{
		//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
		EnsureValidPrefabs(__instance);
		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 (array != null && dictionary != null)
		{
			BlackThreadAttack[] array2 = array;
			foreach (BlackThreadAttack val in array2)
			{
				if ((Object)(object)val != (Object)null && (Object)(object)val.Prefab != (Object)null && !dictionary.ContainsKey(val))
				{
					GameObject val2 = Object.Instantiate<GameObject>(val.Prefab, ((Component)__instance).transform);
					val2.transform.localPosition = Vector3.zero;
					val2.SetActive(false);
					dictionary[val] = val2;
					Debug.Log((object)("VoidSong: Spawned prefab for " + ((Object)val).name));
				}
			}
		}
		__instance.BecomeThreadedNoSing();
	}

	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);
					((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);
		if ((Object)(object)val != (Object)null || (Object)(object)val2 != (Object)null)
		{
			Debug.Log((object)(">>>VoidSong_EnemyVoidSkipper>>>: " + ((Object)__instance).name + " has no sing/stun FSM, using Simple threading that avoids waits."));
			__result = SimpleThreadRoutine(__instance);
			return false;
		}
		return true;
	}

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

	[HarmonyPatch(typeof(BlackThreadState), "ThreadAttackTest")]
	[HarmonyPrefix]
	private static bool ThreadAttackTest_Prefix(BlackThreadState __instance, ref IEnumerator __result)
	{
		//IL_014f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0154: Unknown result type (might be due to invalid IL or missing references)
		object? obj = typeof(BlackThreadState).GetField("chosenAttack", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(__instance);
		BlackThreadAttack val = (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)val == (Object)null)
		{
			Debug.LogWarning((object)("VoidSong: " + ((Object)__instance).name + " has no chosenAttack, skipping."));
			__result = DummyIdleRoutine();
			return false;
		}
		if (canRandomizeAttacks)
		{
			val = array[Random.Range(0, array.Length)];
		}
		GameObject val2 = null;
		if (dictionary != null && dictionary.ContainsKey(val))
		{
			val2 = dictionary[val];
		}
		if ((Object)(object)val2 == (Object)null)
		{
			object? obj2 = typeof(BlackThreadAttack).GetField("Prefab", BindingFlags.Instance | BindingFlags.Public)?.GetValue(val);
			GameObject val3 = (GameObject)((obj2 is GameObject) ? obj2 : null);
			if (!((Object)(object)val3 != (Object)null))
			{
				Debug.LogWarning((object)("VoidSong: " + ((Object)__instance).name + " has no prefab for " + ((Object)val).name + ", skipping."));
				__result = DummyIdleRoutine();
				return false;
			}
			val2 = Object.Instantiate<GameObject>(val3, ((Component)__instance).transform.position, Quaternion.identity);
			val2.SetActive(true);
			Debug.Log((object)("VoidSong: Fallback-spawned prefab " + ((Object)val3).name + " for " + ((Object)__instance).name));
		}
		__result = ActivateAttackRoutine(__instance, val2);
		return false;
	}

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

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