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));
}
}
}