Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Voidsong v1.3.0
HKVoidsongMod.dll
Decompiled 8 months agousing 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__29 : 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__29(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_0170: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Expected O, but got Unknown //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Expected O, but got Unknown //IL_008b: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (!ninjaMode && !IsEnemyActiveAndVisible(((Component)__instance).gameObject)) { Debug.Log((object)("Enemy isnt visible, skipping on " + ((Object)__instance).name)); return false; } <attackObjClone>5__1 = Object.Instantiate<GameObject>(attackObj, ((Component)__instance).transform.position, Quaternion.identity); if ((Object)(object)<attackObjClone>5__1 == (Object)null) { Debug.Log((object)("Attack is null, returning on " + ((Object)__instance).name)); 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__30 : 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__30(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__26 : 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__26(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_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Expected O, but got Unknown //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: 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; } if (!ninjaMode) { if (((Component)state).gameObject.activeInHierarchy) { <startAttackTest>5__4?.Invoke(state, null); } else { Debug.Log((object)("Instance " + ((Object)((Component)state).gameObject).name + " isnt active, skipping attack")); } } else { <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__21 : 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__21(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__11 : 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__11(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 bool ninjaMode = false; private static float maximumAttackRange = 150f; private static int voidedHpMultiplier = 2; 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__11))] private IEnumerator WaitFix() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <WaitFix>d__11(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"); } } } [HarmonyPriority(600)] [HarmonyPatch(typeof(HealthManager), "Awake")] [HarmonyPrefix] private static void HealthManager_OnAwake_Prefix(HealthManager __instance) { FieldInfo field = typeof(HealthManager).GetField("initHp", BindingFlags.Instance | BindingFlags.NonPublic); if (field != null) { int num = (int)field.GetValue(__instance); field.SetValue(__instance, num * voidedHpMultiplier); Debug.Log((object)$"HP multiplied for {((Object)__instance).name}: {__instance.hp}/{num * voidedHpMultiplier}"); } __instance.hp *= voidedHpMultiplier; } [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(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, 0.8f); } [HarmonyPatch(typeof(HealthManager), "HealToMax")] [HarmonyPrefix] private static void HealthManager_HealToMax_Prefix(HealthManager __instance) { FieldInfo field = typeof(HealthManager).GetField("initHp", BindingFlags.Instance | BindingFlags.NonPublic); if (field != null) { int num = (int)field.GetValue(__instance); int num2 = voidedHpMultiplier; if (num > 0 && num < 99999) { field.SetValue(__instance, num * num2); } } } [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)); if (!ninjaMode) { if (IsInBattleWave(((Component)__instance).gameObject)) { Debug.Log((object)("Battle wave handle's threading, skipping initalization on " + ((Object)__instance).name)); } else { __instance.BecomeThreadedNoSing(); } } else { __instance.BecomeThreadedNoSing(); } } private static bool IsInBattleWave(GameObject enemy) { if ((Object)(object)enemy == (Object)null) { return false; } Transform val = enemy.transform; while ((Object)(object)val != (Object)null) { if ((Object)(object)((Component)val).GetComponent<BattleWave>() != (Object)null) { return true; } val = val.parent; } return false; } [IteratorStateMachine(typeof(<SpawnPrefabsDeferred>d__21))] private static IEnumerator SpawnPrefabsDeferred(BlackThreadState state) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SpawnPrefabsDeferred>d__21(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__26))] private static IEnumerator SimpleThreadRoutine(BlackThreadState state) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SimpleThreadRoutine>d__26(0) { state = state }; } private static bool IsEnemyActiveAndVisible(GameObject enemy) { if ((Object)(object)enemy == (Object)null) { return false; } if (!enemy.activeInHierarchy) { return false; } return true; } [HarmonyPatch(typeof(BlackThreadState), "ThreadAttackTest")] [HarmonyPrefix] private static bool ThreadAttackTest_Prefix(BlackThreadState __instance, ref IEnumerator __result) { //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) if (!ninjaMode && !IsEnemyActiveAndVisible(((Component)__instance).gameObject)) { Debug.Log((object)("VoidSong: " + ((Object)__instance).name + " inactive or not visible, skipping attack.")); __result = DummyIdleRoutine(); return false; } 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__29))] private static IEnumerator ActivateAttackRoutine(BlackThreadState __instance, GameObject attackObj) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ActivateAttackRoutine>d__29(0) { __instance = __instance, attackObj = attackObj }; } [IteratorStateMachine(typeof(<DummyIdleRoutine>d__30))] private static IEnumerator DummyIdleRoutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <DummyIdleRoutine>d__30(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)); } } [HarmonyPatch(typeof(BattleWave), "SetActive")] [HarmonyPostfix] private static void BattleWave_SetActive_Postfix(BattleWave __instance, bool value) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown if (ninjaMode || !value) { return; } foreach (Transform item in ((Component)__instance).transform) { Transform val = item; HealthManager component = ((Component)val).GetComponent<HealthManager>(); BlackThreadState component2 = ((Component)val).GetComponent<BlackThreadState>(); if ((Object)(object)component2 == (Object)null) { ((Component)val).gameObject.AddComponent<BlackThreadState>(); } component2 = ((Component)val).GetComponent<BlackThreadState>(); if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null) { Debug.Log((object)("Voidsong: Threading enemy " + ((Object)val).name + " on wave activation.")); component2.BecomeThreadedNoSing(); } } } }