Decompiled source of LightFlickerGB v1.0.0

Mods/LightFlickerGB.dll

Decompiled 10 hours 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.Versioning;
using System.Security;
using System.Security.Permissions;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using LightFlickerZooks;
using MelonLoader;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Audio;
using UnityEngine.SceneManagement;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(LightFlickerMod), "LightFlickerGB", "1.0.0", "Zooks", null)]
[assembly: MelonGame("Boneloaf", "Gang Beasts")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("SubwayDeathGB")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("sd for GB")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("SubwayDeathGB")]
[assembly: AssemblyTitle("SubwayDeathGB")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LightFlickerZooks
{
	public class LightFlickerMod : MelonMod
	{
		[CompilerGenerated]
		private sealed class <DelayedCacheMapLights>d__17 : IEnumerator<object>, IEnumerator, IDisposable
		{
			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 <DelayedCacheMapLights>d__17(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

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

			private bool MoveNext()
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(2f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					CacheMapLights();
					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 <FlickerRoutine>d__23 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public List<Light> lights;

			private float <duration>5__2;

			private float <elapsed>5__3;

			private Dictionary<Light, bool> <originalStates>5__4;

			private float <originalAmbientIntensity>5__5;

			private Color <originalAmbientLight>5__6;

			private float <originalReflectionIntensity>5__7;

			private float <waitTime>5__8;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<originalStates>5__4 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0096: Unknown result type (might be due to invalid IL or missing references)
				//IL_009b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0168: Unknown result type (might be due to invalid IL or missing references)
				//IL_016e: Unknown result type (might be due to invalid IL or missing references)
				//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
				//IL_01ab: Expected O, but got Unknown
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						isFlickering = true;
						<duration>5__2 = 1.5f;
						<elapsed>5__3 = 0f;
						<originalStates>5__4 = lights.ToDictionary((Light l) => l, (Light l) => ((Behaviour)l).enabled);
						<originalAmbientIntensity>5__5 = RenderSettings.ambientIntensity;
						<originalAmbientLight>5__6 = RenderSettings.ambientLight;
						<originalReflectionIntensity>5__7 = RenderSettings.reflectionIntensity;
						<>1__state = -3;
						break;
					case 1:
						<>1__state = -3;
						<elapsed>5__3 += <waitTime>5__8;
						break;
					}
					if (<elapsed>5__3 < <duration>5__2)
					{
						bool flag = Random.value > 0.45f;
						float num = (flag ? 1f : 0f);
						foreach (Light light in lights)
						{
							if ((Object)(object)light != (Object)null)
							{
								((Behaviour)light).enabled = <originalStates>5__4[light] && flag;
							}
						}
						foreach (Renderer lightRenderer in lightRenderers)
						{
							SetRendererColor(lightRenderer, flag);
						}
						RenderSettings.ambientIntensity = <originalAmbientIntensity>5__5 * num;
						RenderSettings.ambientLight = <originalAmbientLight>5__6 * num;
						RenderSettings.reflectionIntensity = <originalReflectionIntensity>5__7 * num;
						<waitTime>5__8 = Random.Range(0.04f, 0.12f);
						<>2__current = (object)new WaitForSeconds(<waitTime>5__8);
						<>1__state = 1;
						return true;
					}
					<>m__Finally1();
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

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

			private void <>m__Finally1()
			{
				//IL_009e: Unknown result type (might be due to invalid IL or missing references)
				<>1__state = -1;
				foreach (Light light in lights)
				{
					if ((Object)(object)light != (Object)null && <originalStates>5__4.ContainsKey(light))
					{
						((Behaviour)light).enabled = <originalStates>5__4[light];
					}
				}
				foreach (Renderer lightRenderer in lightRenderers)
				{
					SetRendererColor(lightRenderer, restore: true);
				}
				RenderSettings.ambientIntensity = <originalAmbientIntensity>5__5;
				RenderSettings.ambientLight = <originalAmbientLight>5__6;
				RenderSettings.reflectionIntensity = <originalReflectionIntensity>5__7;
				isFlickering = false;
			}

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

		private static string soundFilePath;

		private static AudioClip deathClip;

		private static bool isFlickering = false;

		private static bool isMapActive = false;

		private static float lastTriggerTime = -999f;

		private static AudioSource activeSource = null;

		private static readonly string[] AllowedMaps = new string[4] { "subway", "lighthouse", "chute", "grind" };

		private static readonly string[] LightKeywords = new string[8] { "light", "neon", "bulb", "lamp", "fixture", "glow", "emiss", "spotlight" };

		private static List<Light> cachedMapLights = new List<Light>();

		private static List<Renderer> lightRenderers = new List<Renderer>();

		private static Dictionary<Renderer, Color> originalEmissionColors = new Dictionary<Renderer, Color>();

		private static Dictionary<Renderer, bool> originalEmissionKeywords = new Dictionary<Renderer, bool>();

		private static Dictionary<Renderer, Color> originalBaseColors = new Dictionary<Renderer, Color>();

		public override void OnInitializeMelon()
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Expected O, but got Unknown
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Expected O, but got Unknown
			soundFilePath = Path.Combine(MelonEnvironment.UserDataDirectory, "LightFlicker", "lightflicker.wav");
			Directory.CreateDirectory(Path.GetDirectoryName(soundFilePath));
			if (!File.Exists(soundFilePath))
			{
				MelonLogger.Error("[LightFlicker] Place 'lightflicker.wav' in: " + Path.GetDirectoryName(soundFilePath));
			}
			Harmony val = new Harmony("LightFlicker");
			Dictionary<string, string> dictionary = new Dictionary<string, string>
			{
				{ "Actor", "Eliminate" },
				{ "HealthTracker", "Kill" },
				{ "ActorDeathAudio", "OnBeastDeath" },
				{ "BreakJointsOnDeath", "OnDeath" }
			};
			foreach (Assembly item in from a in AppDomain.CurrentDomain.GetAssemblies()
				where ((ReadOnlySpan<string>)new string[4] { "Il2CppAssembly-CSharp", "Il2CppFemur", "Il2CppGB", "Assembly-CSharp" }).Contains(a.GetName().Name)
				select a)
			{
				try
				{
					Type[] types = item.GetTypes();
					foreach (Type type in types)
					{
						if (type == null || !dictionary.ContainsKey(type.Name))
						{
							continue;
						}
						string methodTarget = dictionary[type.Name];
						foreach (MethodInfo item2 in from m in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
							where m.Name == methodTarget && !m.IsGenericMethod
							select m)
						{
							try
							{
								HarmonyMethod val2 = new HarmonyMethod(typeof(LightFlickerMod).GetMethod((type.Name == "Actor") ? "OnActorEliminatedPostfix" : "OnGenericDeathPostfix"));
								val.Patch((MethodBase)item2, (HarmonyMethod)null, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
								MelonLogger.Msg("[LightFlicker] Patched " + type.Name + "." + methodTarget);
							}
							catch
							{
							}
						}
					}
				}
				catch
				{
				}
			}
		}

		public override void OnLateInitializeMelon()
		{
			if (File.Exists(soundFilePath))
			{
				deathClip = LoadWavFile(soundFilePath);
			}
		}

		private static AudioClip LoadWavFile(string filePath)
		{
			try
			{
				byte[] array = File.ReadAllBytes(filePath);
				if (array.Length < 44)
				{
					return null;
				}
				int num = 12;
				int num2 = 0;
				int num3 = 0;
				int num4 = 0;
				int num5 = 0;
				int num6 = 0;
				while (num < array.Length - 8)
				{
					char c = (char)array[num];
					string text = c.ToString();
					c = (char)array[num + 1];
					string text2 = c.ToString();
					c = (char)array[num + 2];
					string text3 = c.ToString();
					c = (char)array[num + 3];
					string text4 = text + text2 + text3 + c;
					int num7 = BitConverter.ToInt32(array, num + 4);
					num += 8;
					if (num + num7 > array.Length)
					{
						break;
					}
					if (text4 == "fmt ")
					{
						num2 = BitConverter.ToInt16(array, num + 2);
						num3 = BitConverter.ToInt32(array, num + 4);
						num4 = BitConverter.ToInt16(array, num + 14);
					}
					else if (text4 == "data")
					{
						num5 = num;
						num6 = num7;
						break;
					}
					num += num7;
				}
				if (num5 == 0 || num6 == 0 || num2 == 0)
				{
					return null;
				}
				int num8 = num6 / (num4 / 8);
				float[] array2 = new float[num8];
				for (int i = 0; i < num8; i++)
				{
					switch (num4)
					{
					case 16:
						array2[i] = (float)BitConverter.ToInt16(array, num5 + i * 2) / 32768f;
						break;
					case 24:
					{
						int num9 = num5 + i * 3;
						int num10 = array[num9] | (array[num9 + 1] << 8) | (array[num9 + 2] << 16);
						if (((uint)num10 & 0x800000u) != 0)
						{
							num10 |= -16777216;
						}
						array2[i] = (float)num10 / 8388608f;
						break;
					}
					case 32:
						array2[i] = BitConverter.ToSingle(array, num5 + i * 4);
						break;
					case 8:
						array2[i] = (float)(array[num5 + i] - 128) / 128f;
						break;
					}
				}
				AudioClip obj = AudioClip.Create("LightFlickerSound", num8 / num2, num2, num3, false);
				obj.SetData(Il2CppStructArray<float>.op_Implicit(array2), 0);
				((Object)obj).hideFlags = (HideFlags)52;
				return obj;
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[LightFlicker] WAV Error: " + ex.Message);
				return null;
			}
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			isMapActive = AllowedMaps.Any((string map) => sceneName.ToLower().Contains(map));
			isFlickering = false;
			if (isMapActive)
			{
				MelonCoroutines.Start(DelayedCacheMapLights());
				return;
			}
			cachedMapLights.Clear();
			lightRenderers.Clear();
		}

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

		private static void CacheMapLights()
		{
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0141: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				cachedMapLights.Clear();
				lightRenderers.Clear();
				originalEmissionColors.Clear();
				originalEmissionKeywords.Clear();
				originalBaseColors.Clear();
				cachedMapLights.AddRange(((IEnumerable<Light>)Resources.FindObjectsOfTypeAll<Light>()).Where(delegate(Light l)
				{
					//IL_0013: Unknown result type (might be due to invalid IL or missing references)
					//IL_0018: Unknown result type (might be due to invalid IL or missing references)
					object obj3;
					if (l == null)
					{
						obj3 = null;
					}
					else
					{
						GameObject gameObject2 = ((Component)l).gameObject;
						if (gameObject2 == null)
						{
							obj3 = null;
						}
						else
						{
							Scene scene2 = gameObject2.scene;
							obj3 = ((Scene)(ref scene2)).name;
						}
					}
					return obj3 != null;
				}));
				foreach (Renderer item in ((IEnumerable<Renderer>)Resources.FindObjectsOfTypeAll<Renderer>()).Where(delegate(Renderer r)
				{
					//IL_0026: Unknown result type (might be due to invalid IL or missing references)
					//IL_002b: Unknown result type (might be due to invalid IL or missing references)
					Renderer obj = r;
					object obj2;
					if (obj == null)
					{
						obj2 = null;
					}
					else
					{
						GameObject gameObject = ((Component)obj).gameObject;
						if (gameObject == null)
						{
							obj2 = null;
						}
						else
						{
							Scene scene = gameObject.scene;
							obj2 = ((Scene)(ref scene)).name;
						}
					}
					return obj2 != null && LightKeywords.Any((string k) => ((Object)((Component)r).gameObject).name.ToLower().Contains(k) || ((Object)(object)r.sharedMaterial != (Object)null && ((Object)r.sharedMaterial).name.ToLower().Contains(k)));
				}))
				{
					Material material = item.material;
					if (!((Object)(object)material != (Object)null))
					{
						continue;
					}
					bool flag = false;
					if (material.HasProperty("_EmissionColor"))
					{
						lightRenderers.Add(item);
						originalEmissionColors[item] = material.GetColor("_EmissionColor");
						originalEmissionKeywords[item] = material.IsKeywordEnabled("_EMISSION");
						flag = true;
					}
					string text = (material.HasProperty("_BaseColor") ? "_BaseColor" : (material.HasProperty("_Color") ? "_Color" : null));
					if (text != null)
					{
						if (!flag)
						{
							lightRenderers.Add(item);
						}
						originalBaseColors[item] = material.GetColor(text);
					}
				}
				MelonLogger.Msg($"[LightFlicker] Cached {cachedMapLights.Count} lights & {lightRenderers.Count} meshes.");
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[LightFlicker] Cache Error: " + ex.Message);
			}
		}

		public static void OnPlayerDeath(Vector3 position)
		{
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			if (isMapActive && !(Time.time - lastTriggerTime < 0.15f))
			{
				lastTriggerTime = Time.time;
				Play3DSound(position);
				TriggerFlicker();
			}
		}

		private static void Play3DSound(Vector3 position)
		{
			if ((Object)(object)deathClip == (Object)null || ((Object)(object)activeSource != (Object)null && activeSource.isPlaying))
			{
				return;
			}
			try
			{
				if (!((Object)(object)Camera.main == (Object)null))
				{
					activeSource = ((Component)Camera.main).gameObject.AddComponent<AudioSource>();
					activeSource.clip = deathClip;
					AudioMixerGroup val = ((IEnumerable<AudioMixerGroup>)Resources.FindObjectsOfTypeAll<AudioMixerGroup>()).FirstOrDefault((Func<AudioMixerGroup, bool>)((AudioMixerGroup g) => (Object)(object)g != (Object)null && ((Object)g).name.Equals("Vocals", StringComparison.OrdinalIgnoreCase)));
					if ((Object)(object)val != (Object)null)
					{
						activeSource.outputAudioMixerGroup = val;
					}
					activeSource.spatialBlend = 1f;
					activeSource.volume = 0.75f;
					activeSource.minDistance = 100f;
					activeSource.maxDistance = 1000f;
					activeSource.rolloffMode = (AudioRolloffMode)0;
					activeSource.Play();
					Object.Destroy((Object)(object)activeSource, deathClip.length + 0.5f);
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[LightFlicker] PlayAudio Error: " + ex.Message);
			}
		}

		private static void TriggerFlicker()
		{
			if (!isFlickering)
			{
				if (cachedMapLights.Count == 0)
				{
					CacheMapLights();
				}
				cachedMapLights.RemoveAll((Light l) => (Object)(object)l == (Object)null);
				lightRenderers.RemoveAll((Renderer r) => (Object)(object)r == (Object)null);
				if (cachedMapLights.Count > 0)
				{
					MelonCoroutines.Start(FlickerRoutine(cachedMapLights));
				}
			}
		}

		private static void SetRendererColor(Renderer r, bool restore)
		{
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)r == (Object)null || (Object)(object)r.material == (Object)null)
			{
				return;
			}
			Material material = r.material;
			string text = (material.HasProperty("_BaseColor") ? "_BaseColor" : (material.HasProperty("_Color") ? "_Color" : null));
			if (text != null && originalBaseColors.ContainsKey(r))
			{
				material.SetColor(text, restore ? originalBaseColors[r] : Color.black);
			}
			if (!material.HasProperty("_EmissionColor"))
			{
				return;
			}
			if (restore)
			{
				if (originalEmissionColors.ContainsKey(r))
				{
					material.SetColor("_EmissionColor", originalEmissionColors[r]);
				}
				if (originalEmissionKeywords.ContainsKey(r) && originalEmissionKeywords[r])
				{
					material.EnableKeyword("_EMISSION");
				}
				else
				{
					material.DisableKeyword("_EMISSION");
				}
			}
			else
			{
				material.SetColor("_EmissionColor", Color.black);
				material.DisableKeyword("_EMISSION");
			}
		}

		[IteratorStateMachine(typeof(<FlickerRoutine>d__23))]
		private static IEnumerator FlickerRoutine(List<Light> lights)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <FlickerRoutine>d__23(0)
			{
				lights = lights
			};
		}

		private static void TriggerDeath(object instance)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			Component val = (Component)((instance is Component) ? instance : null);
			if (val != null)
			{
				OnPlayerDeath(val.transform.position);
			}
		}

		public static void OnActorEliminatedPostfix(object __instance)
		{
			TriggerDeath(__instance);
		}

		public static void OnGenericDeathPostfix(object __instance)
		{
			TriggerDeath(__instance);
		}
	}
}