Decompiled source of MuzikaGromche v1337.420.9002
Ratijas.MuzikaGromche.dll
Decompiled 21 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using DunGen; using GameNetcodeStuff; using HarmonyLib; using LethalConfig; using LethalConfig.ConfigItems; using LethalConfig.ConfigItems.Options; using LobbyCompatibility.Enums; using LobbyCompatibility.Features; using Microsoft.CodeAnalysis; using Ratijas.MuzikaGromche.NetcodePatcher; using Unity.Netcode; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: IgnoresAccessChecksTo("Unity.Netcode.Runtime")] [assembly: AssemblyCompany("Ratijas.MuzikaGromche")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Add some content to your inverse teleporter experience on Titan!")] [assembly: AssemblyFileVersion("1337.420.9002.0")] [assembly: AssemblyInformationalVersion("1337.420.9002+63de62111f871cc6d55304b3c2d0c135b51975cc")] [assembly: AssemblyProduct("Muzika Gromche")] [assembly: AssemblyTitle("Ratijas.MuzikaGromche")] [assembly: AssemblyMetadata("RepositoryUrl", "https://git.vilunov.me/ratijas/muzika-gromche")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1337.420.9002.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] internal class <Module> { static <Module>() { } } 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.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = 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 MuzikaGromche { internal static class Compatibility { [MethodImpl(MethodImplOptions.NoInlining)] public static void Register(BaseUnityPlugin plugin) { if (Chainloader.PluginInfos.ContainsKey("BMX.LobbyCompatibility")) { RegisterLobbyCompatibility(plugin.Info.Metadata); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void RegisterLobbyCompatibility(BepInPlugin plugin) { PluginHelper.RegisterPlugin(plugin.GUID, plugin.Version, (CompatibilityLevel)2, (VersionStrictness)3); } } public static class DiscoBallManager { private readonly record struct TilePatch(string TileName, GameObject DiscoBallContainer) { public readonly string TileCloneName = TileName + "(Clone)"; } [CompilerGenerated] private sealed class <FindDiscoBallAnimators>d__8 : IEnumerable<Animator>, IEnumerable, IEnumerator<Animator>, IEnumerator, IDisposable { private int <>1__state; private Animator <>2__current; private int <>l__initialThreadId; private GameObject discoBall; public GameObject <>3__discoBall; private string[] <>7__wrap1; private int <>7__wrap2; Animator IEnumerator<Animator>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FindDiscoBallAnimators>d__8(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_0087; } <>1__state = -1; <>7__wrap1 = AnimatorContainersNames; <>7__wrap2 = 0; goto IL_0095; IL_0087: <>7__wrap2++; goto IL_0095; IL_0095: if (<>7__wrap2 < <>7__wrap1.Length) { string text = <>7__wrap1[<>7__wrap2]; Transform val = discoBall.transform.Find(text); if (!((Object)(object)val == (Object)null)) { GameObject gameObject = ((Component)val).gameObject; Animator val2 = ((gameObject != null) ? gameObject.GetComponent<Animator>() : null); if (!((Object)(object)val2 == (Object)null)) { <>2__current = val2; <>1__state = 1; return true; } } goto IL_0087; } <>7__wrap1 = 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(); } [DebuggerHidden] IEnumerator<Animator> IEnumerable<Animator>.GetEnumerator() { <FindDiscoBallAnimators>d__8 <FindDiscoBallAnimators>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <FindDiscoBallAnimators>d__ = this; } else { <FindDiscoBallAnimators>d__ = new <FindDiscoBallAnimators>d__8(0); } <FindDiscoBallAnimators>d__.discoBall = <>3__discoBall; return <FindDiscoBallAnimators>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<Animator>)this).GetEnumerator(); } } private static TilePatch[] Patches = Array.Empty<TilePatch>(); private static readonly List<GameObject> CachedDiscoBalls = new List<GameObject>(); private static readonly List<Animator> CachedDiscoBallAnimators = new List<Animator>(); private static readonly string[] AnimatorContainersNames = new string[6] { "DiscoBallProp/AnimContainer", "DiscoBallProp1/AnimContainer", "DiscoBallProp2/AnimContainer", "DiscoBallProp3/AnimContainer", "DiscoBallProp4/AnimContainer", "DiscoBallProp5/AnimContainer" }; public static void Load() { string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "muzikagromche_discoball"); AssetBundle assetBundle = AssetBundle.LoadFromFile(text) ?? throw new NullReferenceException("Failed to load bundle"); Patches = new(string, string)[6] { ("Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerManor.prefab", "ManorStartRoomSmall"), ("Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerManorOLD.prefab", "ManorStartRoom"), ("Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerFactory.prefab", "StartRoom"), ("Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerMineShaft.prefab", "MineshaftStartTile"), ("Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerLargeForkTileB.prefab", "LargeForkTileB"), ("Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerBirthdayRoomTile.prefab", "BirthdayRoomTile") }.Select(((string PrefabPath, string TileName) d) => new TilePatch(d.TileName, assetBundle.LoadAsset<GameObject>(d.PrefabPath))).ToArray(); } internal static void Patch(Tile tile) { Tile tile2 = tile; foreach (TilePatch item in Patches.Where((TilePatch patch) => ((Object)((Component)tile2).gameObject).name == patch.TileCloneName)) { Patch(tile2, item); } } private static void Patch(Tile tile, TilePatch patch) { GameObject val = Object.Instantiate<GameObject>(patch.DiscoBallContainer, ((Component)tile).transform); if ((Object)(object)val == (Object)null) { return; } foreach (Animator item in FindDiscoBallAnimators(val)) { CachedDiscoBallAnimators.Add(item); } CachedDiscoBalls.Add(val); val.SetActive(false); Debug.Log((object)("MuzikaGromche DiscoBallManager Patched tile '" + ((Object)((Component)tile).gameObject).name + "'")); } [IteratorStateMachine(typeof(<FindDiscoBallAnimators>d__8))] private static IEnumerable<Animator> FindDiscoBallAnimators(GameObject discoBall) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <FindDiscoBallAnimators>d__8(-2) { <>3__discoBall = discoBall }; } public static void Toggle(bool on) { Debug.Log((object)string.Format("{0} {1} Toggle {2} {3} animators", "MuzikaGromche", "DiscoBallManager", on ? "ON" : "OFF", CachedDiscoBallAnimators.Count)); foreach (GameObject cachedDiscoBall in CachedDiscoBalls) { cachedDiscoBall.SetActive(on); } foreach (Animator cachedDiscoBallAnimator in CachedDiscoBallAnimators) { if (cachedDiscoBallAnimator != null) { cachedDiscoBallAnimator.SetBool("on", on); } } } public static void Enable() { Toggle(on: true); } public static void Disable() { Toggle(on: false); } internal static void Clear() { Debug.Log((object)string.Format("{0} {1} Clearing {2} disco balls & {3} animators", "MuzikaGromche", "DiscoBallManager", CachedDiscoBalls.Count, CachedDiscoBallAnimators.Count)); CachedDiscoBallAnimators.Clear(); CachedDiscoBalls.Clear(); } } [HarmonyPatch(typeof(Tile))] internal static class DiscoBallTilePatch { [HarmonyPatch("AddTriggerVolume")] [HarmonyPostfix] private static void OnAddTriggerVolume(Tile __instance) { DiscoBallManager.Patch(__instance); } } [HarmonyPatch(typeof(RoundManager))] internal static class DiscoBallDespawnPatch { [HarmonyPatch("DespawnPropsAtEndOfRound")] [HarmonyPatch("OnDestroy")] [HarmonyPrefix] private static void OnDestroy(RoundManager __instance) { DiscoBallManager.Clear(); } } [BepInPlugin("Ratijas.MuzikaGromche", "Muzika Gromche", "1337.420.9002")] [BepInDependency("ainavt.lc.lethalconfig", "1.4.6")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { internal static Dictionary<Light, Color> InitialLightsColors = new Dictionary<Light, Color>(); private static readonly string[] PwnLyricsVariants; public static readonly ISelectableTrack[] Tracks; public const float AudioMaxDistance = 150f; internal static Config Config { get; private set; } = null; public static ISelectableTrack ChooseTrack() { int chosenSeed = RoundManager.Instance.dungeonGenerator.Generator.ChosenSeed; ISelectableTrack[] array = (MuzikaGromche.Config.SkipExplicitTracks.Value ? Tracks.Where((ISelectableTrack track) => !track.IsExplicit).ToArray() : Tracks); int[] weights = array.Select((ISelectableTrack track) => track.Weight.Value).ToArray(); RandomWeightedIndex randomWeightedIndex = new RandomWeightedIndex(weights); int randomWeightedIndex2 = randomWeightedIndex.GetRandomWeightedIndex(chosenSeed); ISelectableTrack selectableTrack = array[randomWeightedIndex2]; Debug.Log((object)string.Format("{0} Seed is {1}, chosen track is \"{2}\", #{3} of {4}", "MuzikaGromche", chosenSeed, selectableTrack.Name, randomWeightedIndex2, randomWeightedIndex)); return array[randomWeightedIndex2]; } public static IAudioTrack? FindTrackNamed(string name) { string name2 = name; return Tracks.SelectMany((ISelectableTrack track) => track.GetTracks()).FirstOrDefault((IAudioTrack track) => track.Name == name2); } public static void SetLightColor(Color color) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) foreach (Light allPoweredLight in RoundManager.Instance.allPoweredLights) { allPoweredLight.color = color; } } public static void ResetLightColor() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) foreach (var (val3, color) in InitialLightsColors) { val3.color = color; } } public static bool LocalPlayerCanHearMusic(EnemyAI jester) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) PlayerControllerB localPlayerController = GameNetworkManager.Instance.localPlayerController; AudioListener audioListener = StartOfRound.Instance.audioListener; if ((Object)(object)localPlayerController == (Object)null || (Object)(object)audioListener == (Object)null || !localPlayerController.isInsideFactory) { return false; } return Vector3.Distance(((Component)audioListener).transform.position, ((Component)jester).transform.position) <= 150f; } public static void DisplayLyrics(string text) { HUDManager.Instance.DisplayTip("[Lyrics]", text, false, false, "LC_Tip1"); HUDManager.Instance.UIAudio.Stop(); } private void Awake() { //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_02c3: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) Array.Sort(Tracks.Select((ISelectableTrack track) => track.Name).ToArray(), Tracks); string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); Dictionary<string, (UnityWebRequest, List<Action<AudioClip>>)> dictionary = new Dictionary<string, (UnityWebRequest, List<Action<AudioClip>>)>(); dictionary.EnsureCapacity(Tracks.Length * 2); foreach (IAudioTrack track2 in Tracks.SelectMany((ISelectableTrack track) => track.GetTracks())) { (string, Action<AudioClip>)[] array = new(string, Action<AudioClip>)[2] { (track2.FileNameIntro, delegate(AudioClip clip) { track2.LoadedIntro = clip; }), (track2.FileNameLoop, delegate(AudioClip clip) { track2.LoadedLoop = clip; }) }; for (int i = 0; i < array.Length; i++) { var (text, item) = array[i]; if (dictionary.TryGetValue(text, out var value)) { value.Item2.Add(item); continue; } UnityWebRequest audioClip = UnityWebRequestMultimedia.GetAudioClip("file://" + directoryName + "/" + text, track2.AudioType); audioClip.SendWebRequest(); dictionary[text] = (audioClip, new List<Action<AudioClip>>(1) { item }); } } while (!dictionary.Values.All<(UnityWebRequest, List<Action<AudioClip>>)>(((UnityWebRequest Request, List<Action<AudioClip>> Setters) tuple) => tuple.Request.isDone)) { } if (dictionary.Values.All<(UnityWebRequest, List<Action<AudioClip>>)>(((UnityWebRequest Request, List<Action<AudioClip>> Setters) tuple) => (int)tuple.Request.result == 1)) { foreach (KeyValuePair<string, (UnityWebRequest, List<Action<AudioClip>>)> item2 in dictionary) { item2.Deconstruct(out var _, out var value2); (UnityWebRequest, List<Action<AudioClip>>) tuple3 = value2; AudioClip content = DownloadHandlerAudioClip.GetContent(tuple3.Item1); foreach (Action<AudioClip> item3 in tuple3.Item2) { item3(content); } } Config = new Config(((BaseUnityPlugin)this).Config); DiscoBallManager.Load(); PoweredLightsAnimators.Load(); Harmony val = new Harmony("Muzika Gromche"); val.PatchAll(typeof(GameNetworkManagerPatch)); val.PatchAll(typeof(JesterPatch)); val.PatchAll(typeof(EnemyAIPatch)); val.PatchAll(typeof(PoweredLightsAnimatorsPatch)); val.PatchAll(typeof(AllPoweredLightsPatch)); val.PatchAll(typeof(DiscoBallTilePatch)); val.PatchAll(typeof(DiscoBallDespawnPatch)); val.PatchAll(typeof(SpawnRatePatch)); NetcodePatcher(); Compatibility.Register((BaseUnityPlugin)(object)this); } else { IEnumerable<string> values = from tuple in dictionary.Values where (int)tuple.Request.result != 1 select tuple.Request.GetUrl(); ((BaseUnityPlugin)this).Logger.LogError((object)("Could not load audio file " + string.Join(", ", values))); } } private static void NetcodePatcher() { Type[] types = Assembly.GetExecutingAssembly().GetTypes(); for (int i = 0; i < types.Length; i++) { MethodInfo[] methods = types[i].GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); foreach (MethodInfo methodInfo in methods) { if (methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false).Length != 0) { methodInfo.Invoke(null, null); } } } } static Plugin() { List<string> list = new List<string>(); list.Add(""); list.Add(""); list.Add(""); list.AddRange(from a in (from n in NetworkInterface.GetAllNetworkInterfaces() where n.OperationalStatus == OperationalStatus.Up select n).SelectMany((NetworkInterface n) => n.GetIPProperties().UnicastAddresses) where a.Address.AddressFamily == AddressFamily.InterNetwork select a.Address.ToString() into a select " Trying... " + a); PwnLyricsVariants = list.ToArray(); Tracks = new ISelectableTrack[18] { new SelectableAudioTrack { Name = "MuzikaGromche", AudioType = (AudioType)14, Language = Language.RUSSIAN, WindUpTimer = 46.3f, Bars = 16, BeatsOffset = 0f, FadeOutBeat = -3f, FadeOutDuration = 3f, ColorTransitionIn = 0.25f, ColorTransitionOut = 0.25f, ColorTransitionEasing = Easing.OutExpo, FlickerLightsTimeSeries = new float[3] { -5f, 29f, 61f }, Palette = Palette.Parse(new string[6] { "#B300FF", "#FFF100", "#00FF51", "#474747", "#FF00B3", "#0070FF" }), Lyrics = new(float, string)[22] { (-68f, "Devchata pljashut pod spidami"), (-60f, "A ty stoish', kak vkopannyj"), (-52f, "Krossovkami lomajut pol"), (-44f, "A ty stoish', kak vkopannyj"), (-36f, "Ja-ja-ja znaju, chto ty hochesh',"), (-32f, "Ja-ja-ja znaju, chto ty hochesh',\nTy hochesh' tancevat'"), (-28f, "Nu-nu zhe, nu davaj zhe,"), (-24f, "Nu-nu zhe, nu davaj zhe,\nNu-nu zhe, nu davaj zhe"), (-20f, "Ja znaju, chto ty znaesh'\nJetot trek, gotov'sja podpevat'"), (-12f, "1) RAZ"), (-10f, "raz, DVA"), (-8f, "raz, 2wo,\nTRI"), (-6f, "ras, dva,\n7ri, 4ETYRE"), (-1f, "Muzyka Gromche\nGlaza zakryty >_<"), (6f, "This is NON-STOP,\nNoch'ju otkrytij"), (12f, "Delaj chto hochesh', ja zabyvajus'"), (22f, "This is NON-STOP,\nne prekrashhajas'"), (31f, "Muzyka Gromche\nGlaza zakryty -.-"), (38f, "This is NON-STOP,\nNoch'ju otkrytij"), (46f, "Budu s toboju,\nsamoj primernoju"), (54f, "Utro v okne\nyi my budem pervye"), (63f, "Muzyka Gromche\nGlaza zakryty >_<") } }, new SelectableAudioTrack { Name = "VseVZale", AudioType = (AudioType)14, Language = Language.RUSSIAN, WindUpTimer = 38.28f, Bars = 16, LoopOffset = 0, BeatsOffset = 0.25f, FadeOutBeat = -3f, FadeOutDuration = 2.5f, ColorTransitionIn = 0.25f, ColorTransitionOut = 0.25f, ColorTransitionEasing = Easing.OutExpo, FlickerLightsTimeSeries = new float[3] { -5f, 29f, 59f }, Palette = Palette.Parse(new string[6] { "#FF7F00", "#FFB600", "#FFED00", "#00D1FF", "#6696FB", "#704DF8" }).Use((Palette palette) => palette * 5 + new Palette(palette.Colors[0..2]) + (new Palette(palette.Colors[2..]) + palette * 2).Stretch(2)), Lyrics = new(float, string)[12] { (-30f, "VSE V ZALE\nDvigajtes' s nami"), (-24f, "Chtob sotrjasalis'\nSami my, steny i pol!"), (-14f, "Vse znaem - jeto examen na dom nam zadan"), (-4f, "HIP-HOP, HOUSE & ROCK-N-ROLL"), (2f, "VSE V ZALE\nDvigajtes' s nami"), (8f, "Chtob sotrjasalis'\nSami my, steny i pol!"), (18f, "Vse znaem - jeto examen na dom nam zadan"), (28f, "HIP-HOP, HOUSE & ROCK-N-ROLL"), (32f, "O-o-o-o! Zdes' startuet hip-hop party"), (44f, "Tolstyj paren', nam igraj!"), (48f, "O-o-o-o! Pesen i devchonok hvatit!"), (60f, "Everybody shake your body") } }, new SelectableAudioTrack { Name = "DeployDestroy", AudioType = (AudioType)14, Language = Language.RUSSIAN, WindUpTimer = 40.68f, Bars = 8, LoopOffset = 32, BeatsOffset = 0.2f, FadeOutBeat = -38f, FadeOutDuration = 4f, ColorTransitionIn = 0.25f, ColorTransitionOut = 0.25f, ColorTransitionEasing = Easing.OutExpo, FlickerLightsTimeSeries = new float[7] { -101f, -93f, -77f, -61f, -37f, -5f, 27f }, Palette = Palette.Parse(new string[5] { "#217F87", "#BAFF00", "#73BE25", "#78AB4E", "#FFFF00" }), Lyrics = new(float, string)[24] { (-111f, "Deploy Destroy, porjadok eto otstoj"), (-103f, "Krushi, lomaj, trjasi bashkoju pustoj"), (-95f, "Dopej, razbej i novuju otkryvaj"), (-87f, "Davaj-davaj!"), (-79f, "Chestnoe slovo ja nevinoven"), (-75f, "Ja ne pomnju, otkuda stol'ko krovi"), (-71f, "Na moih ladonjah\nyi moej odezhde"), (-67f, "Ja nikogda nikogo\nne bil prezhde"), (-63f, "Ja nikogda nichego\nne pil prezhde"), (-59f, "Byl tih, spokoen,\nso vsemi vezhliv"), (-55f, "Vsegda tol'ko v urnu\nbrosal musor"), (-51f, "Obhodil storonoj shumnye tusy"), (-47f, "Zapreshhjonnyh veshhestv nikakih ne juzal"), (-43f, "Byl polozhitel'nej samogo pljusa"), (-39f, "A potom kak-to raz\njetu pesnju uslyshal"), (-35f, "I vsjo proshhaj, moja krysha"), (-31f, "Deploy Destroy, porjadok eto otstoj"), (-23f, "Krushi, lomaj, trjasi bashkoju pustoj"), (-15f, "Dopej, razbej i novuju otkryvaj"), (-7f, "Davaj-davaj!"), (1f, "Deploy Destroy, porjadok eto otstoj"), (9f, "Krushi, lomaj, trjasi bashkoju pustoj"), (17f, "Dopej, razbej i novuju otkryvaj"), (25f, "Davaj-davaj!") } }, new SelectableAudioTrack { Name = "MoyaZhittya", AudioType = (AudioType)14, Language = Language.ENGLISH, WindUpTimer = 34.53f, Bars = 8, LoopOffset = 32, BeatsOffset = 0f, FadeOutBeat = -35f, FadeOutDuration = 3.3f, ColorTransitionIn = 0.25f, ColorTransitionOut = 0.25f, ColorTransitionEasing = Easing.OutExpo, Palette = Palette.Parse(new string[8] { "#A3A3A3", "#BE3D39", "#5CBC69", "#BE3D39", "#BABC5C", "#BE3D39", "#5C96BC", "#BE3D39" }), FlickerLightsTimeSeries = new float[14] { -100.5f, -99.5f, -92.5f, -91.5f, -76.5f, -75.5f, -60.5f, -59.5f, -37f, -36f, -4.5f, -3.5f, 27.5f, 28.5f }, Lyrics = new(float, string)[28] { (-84f, "This ain't a song for the broken-hearted"), (-68f, "No silent prayer for the faith-departed"), (-52f, "I ain't gonna be"), (-48f, "I ain't gonna be\njust a face in the crowd"), (-45f, "YOU'RE"), (-44f, "you're GONNA"), (-43.5f, "you're gonna HEAR"), (-43f, "you're gonna hear\nMY"), (-42f, "you're gonna hear\nmy VOICE"), (-41f, "WHEN I"), (-40f, "When I SHOUT IT"), (-39f, "When I shout it\nOUT LOUD"), (-34f, "IT'S MY"), (-32f, "IT'S MY\nLIIIIIFE"), (-28f, "And it's now or never"), (-22f, "I ain't gonna"), (-20f, "I ain't gonna\nlive forever"), (-14f, "I just want to live"), (-10f, "I just want to live\nwhile I'm alive"), (-2f, "IT'S MY"), (0f, "IT'S MY\nLIIIIIFE"), (2f, "My heart is like"), (4f, "My heart is like\nan open highway"), (10f, "Like Frankie said,"), (12f, "Like Frankie said,\n\"I did it my way\""), (18f, "I just want to live"), (22f, "I just want to live\nwhile I'm alive"), (30f, "IT'S MY") } }, new SelectableAudioTrack { Name = "Gorgorod", AudioType = (AudioType)14, Language = Language.RUSSIAN, WindUpTimer = 43.2f, Bars = 6, BeatsOffset = 0f, ColorTransitionIn = 0.25f, ColorTransitionOut = 0.25f, ColorTransitionEasing = Easing.InExpo, Palette = Palette.Parse(new string[8] { "#42367E", "#FF9400", "#932A04", "#FF9400", "#932A04", "#42367E", "#FF9400", "#932A04" }), LoopOffset = 0, FadeOutBeat = -2f, FadeOutDuration = 2f, FlickerLightsTimeSeries = new float[1] { 20f }, Lyrics = Array.Empty<(float, string)>() }, new SelectableAudioTrack { Name = "Durochka", AudioType = (AudioType)14, Language = Language.RUSSIAN, WindUpTimer = 37f, Bars = 10, BeatsOffset = 0f, ColorTransitionIn = 0.25f, ColorTransitionOut = 0.3f, ColorTransitionEasing = Easing.OutExpo, Palette = Palette.Parse(new string[8] { "#5986FE", "#FEFEDC", "#FF4FDF", "#FEFEDC", "#FFAA23", "#FEFEDC", "#F95A5A", "#FEFEDC" }), LoopOffset = 0, FadeOutBeat = -7f, FadeOutDuration = 7f, FlickerLightsTimeSeries = new float[1] { -9f }, Lyrics = Array.Empty<(float, string)>() }, new SelectableAudioTrack { Name = "ZmeiGorynich", AudioType = (AudioType)14, Language = Language.KOREAN, WindUpTimer = 46.13f, Bars = 8, BeatsOffset = 0.1f, ColorTransitionIn = 0.4f, ColorTransitionOut = 0.4f, ColorTransitionEasing = Easing.OutExpo, Palette = Palette.Parse(new string[6] { "#4C8AC5", "#AF326A", "#0B1666", "#AFD2FC", "#C55297", "#540070" }), LoopOffset = 0, FadeOutBeat = -4f, FadeOutDuration = 4f, FlickerLightsTimeSeries = new float[2] { -5f, 31f }, Lyrics = Array.Empty<(float, string)>() }, new SelectableAudioTrack { Name = "GodMode", AudioType = (AudioType)14, Language = Language.ENGLISH, WindUpTimer = 40.38f, Bars = 16, BeatsOffset = 0.1f, ColorTransitionIn = 0.5f, ColorTransitionOut = 0.5f, ColorTransitionEasing = Easing.OutCubic, Palette = Palette.Parse(new string[8] { "#FBDBDB", "#4B81FF", "#564242", "#C90AE2", "#FBDBDB", "#61CBE3", "#564242", "#ED3131" }), LoopOffset = 0, FadeOutBeat = -4f, FadeOutDuration = 4f, FlickerLightsTimeSeries = new float[1] { -5f }, Lyrics = Array.Empty<(float, string)>() }, new SelectableAudioTrack { Name = "RiseAndShine", AudioType = (AudioType)14, Language = Language.ENGLISH, WindUpTimer = 59.87f, Bars = 16, BeatsOffset = 0.1f, ColorTransitionIn = 0.5f, ColorTransitionOut = 0.5f, ColorTransitionEasing = Easing.OutCubic, Palette = Palette.Parse(new string[8] { "#FC6F3C", "#3CB0FC", "#FCD489", "#564242", "#FC6F3C", "#3CB0FC", "#63E98C", "#866868" }), LoopOffset = 0, FadeOutBeat = -4.5f, FadeOutDuration = 4f, FlickerLightsTimeSeries = new float[3] { -5.5f, 31f, 63.9f }, Lyrics = Array.Empty<(float, string)>() }, new SelectableAudioTrack { Name = "Song2", AudioType = (AudioType)14, Language = Language.RUSSIAN, WindUpTimer = 38.63f, Beats = 34, BeatsOffset = 0.1f, ColorTransitionIn = 0.3f, ColorTransitionOut = 0.3f, ColorTransitionEasing = Easing.InCubic, Palette = Palette.Parse(new string[8] { "#FFD3E3", "#78A0FF", "#FFD3E3", "#74A392", "#FFD3E3", "#E4B082", "#FFD3E3", "#E277AA" }), LoopOffset = 0, FadeOutBeat = -2f, FadeOutDuration = 2f, FlickerLightsTimeSeries = new float[1] { 2.5f }, Lyrics = Array.Empty<(float, string)>() }, new SelectableAudioTrack { Name = "Peretasovka", AudioType = (AudioType)14, Language = Language.ENGLISH, WindUpTimer = 59.07f, Bars = 8, BeatsOffset = 0.3f, ColorTransitionIn = 0.4f, ColorTransitionOut = 0.4f, ColorTransitionEasing = Easing.OutExpo, Palette = Palette.Parse(new string[8] { "#65C7FA", "#FCEB3C", "#89FC8F", "#FEE9E9", "#FC3C9D", "#FCEB3C", "#89FC8F", "#FC3C9D" }), LoopOffset = 0, FadeOutBeat = -6f, FadeOutDuration = 4f, FlickerLightsTimeSeries = new float[2] { -8f, 31f }, Lyrics = Array.Empty<(float, string)>() }, new SelectableAudioTrack { Name = "Yalgaar", AudioType = (AudioType)14, Language = Language.HINDI, WindUpTimer = 52.17f, Bars = 8, BeatsOffset = 0f, ColorTransitionIn = 0.1f, ColorTransitionOut = 0.35f, ColorTransitionEasing = Easing.OutExpo, Palette = Palette.Parse(new string[8] { "#C0402D", "#906F0B", "#DC8044", "#70190A", "#929FAF", "#4248A2", "#AE2727", "#2D2D42" }), LoopOffset = 0, FadeOutBeat = -4f, FadeOutDuration = 4f, FlickerLightsTimeSeries = new float[1] { -5f }, Lyrics = Array.Empty<(float, string)>() }, new SelectableAudioTrack { Name = "Chereshnya", AudioType = (AudioType)14, Language = Language.RUSSIAN, WindUpTimer = 45.58f, Bars = 16, BeatsOffset = 0f, ColorTransitionIn = 0.3f, ColorTransitionOut = 0.35f, ColorTransitionEasing = Easing.InOutCubic, Palette = Palette.Parse(new string[16] { "#A01471", "#CB2243", "#4CAF50", "#F01D7A", "#AF005A", "#EF355F", "#FFD85D", "#FF66B2", "#A01471", "#4CAF50", "#CB2243", "#F01D7A", "#AF005A", "#FFD85D", "#EF355F", "#FF66B2" }), LoopOffset = 0, FadeOutBeat = -4f, FadeOutDuration = 4f, FlickerLightsTimeSeries = new float[5] { -5f, 27f, 29f, 59f, 61f }, Lyrics = Array.Empty<(float, string)>() }, new SelectableAudioTrack { Name = "PWNED", AudioType = (AudioType)14, Language = Language.ENGLISH, IsExplicit = true, WindUpTimer = 39.73f, Bars = 32, BeatsOffset = -0.2f, ColorTransitionIn = 0.5f, ColorTransitionOut = 0.3f, ColorTransitionEasing = Easing.InExpo, Palette = Palette.Parse(new string[8] { "#9E9E9E", "#383838", "#5E5E5E", "#2E2E2E", "#666666", "#4B4B4B", "#8E8E8E", "#1D1D1D" }).Use(delegate(Palette gray8) { Palette palette2 = Palette.Parse(new string[4] { "#FFFFFF", "#0032A0", "#DA291C", "#000000" }); Palette palette3 = new Palette(gray8.Colors[0..6]); Palette palette4 = palette2 + (gray8 + palette3).Stretch(2); Palette palette5 = gray8.Stretch(4); return palette4 * 2 + palette5 * 2; }), LoopOffset = 0, FadeOutBeat = -8f, FadeOutDuration = 6f, FlickerLightsTimeSeries = new float[4] { -136f, -72f, -12f, 88f }, Lyrics = new(float, string)[44] { (-190f, "These Russian hackers have been"), (-184f, "in these US governments\nsince March"), (-172f, "and it is an extraordinary invasion of our cyberspace"), (-152f, "Russian hackers got access to sensitive"), (-142f, "parts of the White House email system..."), (-134f, "[They began to recognize...]"), (-126f, "<Russian hackers/>"), (-118f, "<Russian hackers/>\n X__X"), (-110f, "Gonna crack your"), (-102f, "Gonna crack your\nStrongest pa$$words%123"), (-94f, "You popped online"), (-86f, "You popped online\nTo look for sneakers"), (-78f, "My hand just popped"), (-70f, "My hand just popped\nRight in your knickers >_< "), (-62f, "Keystrokes like Uzi"), (-54f, "Keystrokes like Uzi\nWill make you go all goosey"), (-46f, "Kicking down your backdoor"), (-38f, "Kicking down your backdoor\nCount down before you lose it"), (-30f, "Keystrokes like Uzi"), (-22f, "Keystrokes like Uzi\nWill make you go all goosey"), (-14f, "Kicking down your backdoor"), (-6f, "Kicking down your backdoor\nCount down before you lose it"), (0f, "C:\\> $Ru55ian hack3rs"), (4f, "C:\\> $Ru55ian hack3rs\n O__o"), (8f, "Infamous White House attackers"), (16f, "Stealing your cookies\nto this beat"), (24f, "Counting crypto to\nembarrass Wall Street"), (32f, "Russi?n ^hackers\tЯushan h@ckers###"), (34f, "\tЯushan h@ckers###\n X_X"), (36f, "Russi?n ^hackers\n--.--\tЯushan h@ckers###\n X___X"), (38f, "\tЯushan h@ckers###\n X_____X"), (40f, "Infamous White House attackers"), (48f, "Stealing your cookies\nto this beat"), (56f, "Counting crypto to\nembarrass Wall Street"), (80f, "Instling min3r.exe\t\t\tresolving ur private IP\n/"), (82f, "Instling min3r.exe\n00% [8=D ]\tHenllo ${username = \"" + Environment.UserName + "\"}\t\tresolving ur private IP\n-" + PwnLyricsVariants[^3]), (84f, "Instling min3r.exe\n33% [8====D ]\t\t\tresolving ur private IP\n\\" + PwnLyricsVariants[^3]), (86f, "Instling min3r.exe\n66% [8=========D ]\t\t\tresolving ur private IP\n|" + PwnLyricsVariants[^2]), (88f, "Instling min3r.exe\n95% [8============D ]\t\tWhere did you download\nthis < mod / dll > from?\tresolving ur private IP\n" + PwnLyricsVariants[^2] + "/"), (90f, "Instling min3r.exe\n99% [8=============D]\t\t\tresolving ur private IP\n-" + PwnLyricsVariants[^2]), (92f, "Encrpt1ng f!les.. \n99% [8=============D]\t\t\tresolving ur private IP\n\\" + PwnLyricsVariants[^1]), (94f, "Encrpt1ng f!les...\n100% enj0y \\o/\t\t\tresolving ur private IP\n|" + PwnLyricsVariants[^1]), (96f, "\t\t\tresolving ur private IP\n/" + PwnLyricsVariants[^1]), (98f, "\t\t\tresolving ur private IP\nP_WNED") } }, new SelectableAudioTrack { Name = "Kach", AudioType = (AudioType)14, Language = Language.ENGLISH, WindUpTimer = 48.3f, Bars = 12, BeatsOffset = 0.4f, ColorTransitionIn = 0.8f, ColorTransitionOut = 0.4f, ColorTransitionEasing = Easing.OutExpo, Palette = Palette.Parse(new string[12] { "#7774DE", "#1EA59A", "#3BC457", "#3BC457", "#CA6935", "#A82615", "#A7AA43", "#A7AA43", "#4C2B81", "#2E802B", "#C952E7", "#C952E7" }), LoopOffset = 0, FadeOutBeat = -6f, FadeOutDuration = 6f, FlickerLightsTimeSeries = new float[6] { -120.5f, -105f, -89f, -8f, 44f, 45f }, Lyrics = Array.Empty<(float, string)>() }, new SelectableAudioTrack { Name = "BeefLiver", AudioType = (AudioType)14, Language = Language.ENGLISH, WindUpTimer = 39.35f, Bars = 12, BeatsOffset = 0.2f, ColorTransitionIn = 0.4f, ColorTransitionOut = 0.4f, ColorTransitionEasing = Easing.OutExpo, Palette = Palette.Parse(new string[8] { "#FFEBEB", "#FFEBEB", "#445782", "#EBA602", "#5EEBB9", "#8EE3DC", "#A23045", "#262222" }), LoopOffset = 0, FadeOutBeat = -3f, FadeOutDuration = 3f, FlickerLightsTimeSeries = new float[4] { -48f, -40f, -4.5f, 44f }, Lyrics = Array.Empty<(float, string)>() }, new SelectableTracksGroup { Name = "Beha", Language = Language.RUSSIAN, IsExplicit = true, Tracks = new IAudioTrack[3] { new CoreAudioTrack { Name = "Beha1", FileNameLoop = "BehaLoop.ogg", AudioType = (AudioType)14, WindUpTimer = 35.23f, Beats = 34, BeatsOffset = 0f, ColorTransitionIn = 0.1f, ColorTransitionOut = 0.6f, ColorTransitionEasing = Easing.OutExpo, Palette = Palette.Parse(new string[6] { "#9554F9", "#3769FD", "#E43B65", "#59CFEA", "#7F3FEE", "#C831FE" }), LoopOffset = 0, FadeOutBeat = -4f, FadeOutDuration = 3.9f, FlickerLightsTimeSeries = new float[2] { -6f, 16.5f }, Lyrics = Array.Empty<(float, string)>() }, new CoreAudioTrack { Name = "Beha2", FileNameLoop = "BehaLoop.ogg", AudioType = (AudioType)14, WindUpTimer = 38.16f, Beats = 34, BeatsOffset = 0f, ColorTransitionIn = 0.1f, ColorTransitionOut = 0.6f, ColorTransitionEasing = Easing.OutExpo, Palette = Palette.Parse(new string[6] { "#9554F9", "#3769FD", "#E43B65", "#59CFEA", "#7F3FEE", "#C831FE" }), LoopOffset = 0, FadeOutBeat = -4f, FadeOutDuration = 3.9f, FlickerLightsTimeSeries = new float[2] { -6f, 16.5f }, Lyrics = Array.Empty<(float, string)>() }, new CoreAudioTrack { Name = "Beha3", FileNameLoop = "BehaLoop.ogg", AudioType = (AudioType)14, WindUpTimer = 35.21f, Beats = 34, BeatsOffset = 0f, ColorTransitionIn = 0.1f, ColorTransitionOut = 0.6f, ColorTransitionEasing = Easing.OutExpo, Palette = Palette.Parse(new string[6] { "#9554F9", "#3769FD", "#E43B65", "#59CFEA", "#7F3FEE", "#C831FE" }), LoopOffset = 0, FadeOutBeat = -4f, FadeOutDuration = 3.9f, FlickerLightsTimeSeries = new float[2] { -6f, 16.5f }, Lyrics = Array.Empty<(float, string)>() } } }, new SelectableAudioTrack { Name = "OnePartiyaUdar", AudioType = (AudioType)14, Language = Language.JAPANESE, WindUpTimer = 41.27f, Bars = 12, BeatsOffset = 0.3f, ColorTransitionIn = 0.6f, ColorTransitionOut = 0.15f, ColorTransitionEasing = Easing.InOutExpo, Palette = Palette.Parse(new string[6] { "#9C3C37", "#E9BF5C", "#B5E3EA", "#662422", "#EBC3A8", "#AA8238" }), LoopOffset = 0, FadeOutBeat = -8f, FadeOutDuration = 6f, FlickerLightsTimeSeries = new float[3] { -68.5f, -16.5f, 30.5f }, Lyrics = Array.Empty<(float, string)>() } }; } } public readonly record struct Language(string Short, string Full) { public static readonly Language ENGLISH = new Language("EN", "English"); public static readonly Language RUSSIAN = new Language("RU", "Russian"); public static readonly Language KOREAN = new Language("KO", "Korean"); public static readonly Language JAPANESE = new Language("JP", "Japanese"); public static readonly Language HINDI = new Language("HI", "Hindi"); } public readonly record struct Easing(string Name, Func<float, float> Eval) { public static Easing Linear = new Easing("Linear", (float x) => x); public static Easing OutCubic = new Easing("OutCubic", (float x) => 1f - Mathf.Pow(1f - x, 3f)); public static Easing InCubic = new Easing("InCubic", (float x) => x * x * x); public static Easing InOutCubic = new Easing("InOutCubic", (float x) => (!(x < 0.5f)) ? (1f - Mathf.Pow(-2f * x + 2f, 3f) / 2f) : (4f * x * x * x)); public static Easing InExpo = new Easing("InExpo", (float x) => (x != 0f) ? Mathf.Pow(2f, 10f * x - 10f) : 0f); public static Easing OutExpo = new Easing("OutExpo", (float x) => (x != 1f) ? (1f - Mathf.Pow(2f, -10f * x)) : 1f); public static Easing InOutExpo = new Easing("InOutExpo", (float x) => (x != 0f) ? ((x != 1f) ? ((!(x < 0.5f)) ? ((2f - Mathf.Pow(2f, -20f * x + 10f)) / 2f) : (Mathf.Pow(2f, 20f * x - 10f) / 2f)) : 1f) : 0f); public static readonly Easing[] All = new Easing[7] { Linear, InCubic, OutCubic, InOutCubic, InExpo, OutExpo, InOutExpo }; public static readonly string[] AllNames = All.Select((Easing easing) => easing.Name).ToArray(); public static Easing FindByName(string Name) { string Name2 = Name; return All.Where((Easing easing) => easing.Name == Name2).DefaultIfEmpty(Linear).First(); } public override string ToString() { return Name; } } public readonly record struct Palette(Color[] Colors) { public static readonly Palette DEFAULT = new Palette((Color[])(object)new Color[4] { Color.magenta, Color.cyan, Color.green, Color.yellow }); public static Palette Parse(string[] hexColors) { Color[] array = (Color[])(object)new Color[hexColors.Length]; for (int i = 0; i < hexColors.Length; i++) { if (!ColorUtility.TryParseHtmlString(hexColors[i], ref array[i])) { throw new ArgumentException($"Unable to parse color #{i}: {hexColors}"); } } return new Palette(array); } public static Palette operator +(Palette before, Palette after) { Color[] colors = before.Colors; Color[] colors2 = after.Colors; int num = 0; Color[] array = (Color[])(object)new Color[colors.Length + colors2.Length]; ReadOnlySpan<Color> readOnlySpan = new ReadOnlySpan<Color>(colors); readOnlySpan.CopyTo(new Span<Color>(array).Slice(num, readOnlySpan.Length)); num += readOnlySpan.Length; ReadOnlySpan<Color> readOnlySpan2 = new ReadOnlySpan<Color>(colors2); readOnlySpan2.CopyTo(new Span<Color>(array).Slice(num, readOnlySpan2.Length)); num += readOnlySpan2.Length; return new Palette(array); } public static Palette operator *(Palette palette, int repeat) { return new Palette(Enumerable.Repeat(palette.Colors, repeat).SelectMany((Color[] x) => x).ToArray()); } public Palette Stretch(int times) { return new Palette(Colors.SelectMany((Color color) => Enumerable.Repeat<Color>(color, times)).ToArray()); } public Palette Use(Func<Palette, Palette> op) { return op(this); } } public interface ISelectableTrack { string Name { get; init; } Language Language { get; init; } bool IsExplicit { get; init; } internal ConfigEntry<int> Weight { get; set; } internal IAudioTrack[] GetTracks(); internal IAudioTrack SelectTrack(int index); internal void Debug(); } public interface IAudioTrack { string Name { get; } float WindUpTimer { get; } float Bpm => 60f / (LoadedLoop.length / (float)Beats); int Beats { get; } int LoopOffset { get; } float LoopOffsetInSeconds => (float)(LoopOffset / Beats) * LoadedLoop.length; AudioType AudioType { get; } AudioClip LoadedIntro { get; internal set; } AudioClip LoadedLoop { get; internal set; } string FileNameIntro { get; } string FileNameLoop { get; } string Ext { get { //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_000a: Invalid comparison between Unknown and I4 //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Invalid comparison between Unknown and I4 //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 AudioType audioType = AudioType; if ((int)audioType != 13) { if ((int)audioType != 14) { if ((int)audioType == 20) { return "wav"; } return ""; } return "ogg"; } return "mp3"; } } float BeatsOffset { get; } float BeatsOffsetInSeconds => BeatsOffset / (float)Beats * LoadedLoop.length; float FadeOutBeat { get; } float FadeOutDuration { get; } float ColorTransitionIn { get; } float ColorTransitionOut { get; } Easing ColorTransitionEasing { get; } float[] FlickerLightsTimeSeries { get; } float[] LyricsTimeSeries { get; } string[] LyricsLines { get; } Palette Palette { get; } } public abstract class ProxyAudioTrack : IAudioTrack { internal IAudioTrack Track; string IAudioTrack.Name => Track.Name; float IAudioTrack.WindUpTimer => Track.WindUpTimer; int IAudioTrack.Beats => Track.Beats; int IAudioTrack.LoopOffset => Track.LoopOffset; AudioType IAudioTrack.AudioType => Track.AudioType; AudioClip IAudioTrack.LoadedIntro { get { return Track.LoadedIntro; } set { Track.LoadedIntro = value; } } AudioClip IAudioTrack.LoadedLoop { get { return Track.LoadedLoop; } set { Track.LoadedLoop = value; } } string IAudioTrack.FileNameIntro => Track.FileNameIntro; string IAudioTrack.FileNameLoop => Track.FileNameLoop; float IAudioTrack.BeatsOffset => Track.BeatsOffset; float IAudioTrack.FadeOutBeat => Track.FadeOutBeat; float IAudioTrack.FadeOutDuration => Track.FadeOutDuration; float IAudioTrack.ColorTransitionIn => Track.ColorTransitionIn; float IAudioTrack.ColorTransitionOut => Track.ColorTransitionOut; Easing IAudioTrack.ColorTransitionEasing => Track.ColorTransitionEasing; float[] IAudioTrack.FlickerLightsTimeSeries => Track.FlickerLightsTimeSeries; float[] IAudioTrack.LyricsTimeSeries => Track.LyricsTimeSeries; string[] IAudioTrack.LyricsLines => Track.LyricsLines; Palette IAudioTrack.Palette => Track.Palette; protected ProxyAudioTrack(IAudioTrack track) { Track = track; base..ctor(); } } public class CoreAudioTrack : IAudioTrack { private string? FileNameIntroOverride; private string? FileNameLoopOverride; public float[] _FlickerLightsTimeSeries = Array.Empty<float>(); public string Name { get; init; } = ""; public float WindUpTimer { get; init; } public int Beats { get; init; } public int Bars { init { Beats = value * 4; } } public int LoopOffset { get; init; } public AudioType AudioType { get; init; } = (AudioType)13; public AudioClip LoadedIntro { get; set; } public AudioClip LoadedLoop { get; set; } public string FileNameIntro { get { return FileNameIntroOverride ?? (Name + "Intro." + ((IAudioTrack)this).Ext); } init { FileNameIntroOverride = value; } } public string FileNameLoop { get { return FileNameLoopOverride ?? (Name + "Loop." + ((IAudioTrack)this).Ext); } init { FileNameLoopOverride = value; } } public float BeatsOffset { get; init; } public float FadeOutBeat { get; init; } = float.NaN; public float FadeOutDuration { get; init; } = 2f; public float ColorTransitionIn { get; init; } = 0.25f; public float ColorTransitionOut { get; init; } = 0.25f; public Easing ColorTransitionEasing { get; init; } = Easing.OutExpo; public float[] FlickerLightsTimeSeries { get { return _FlickerLightsTimeSeries; } init { Array.Sort(value); _FlickerLightsTimeSeries = value; } } public float[] LyricsTimeSeries { get; private set; } = Array.Empty<float>(); public string[] LyricsLines { get; private set; } = Array.Empty<string>(); public (float, string)[] Lyrics { set { SortedDictionary<float, string> sortedDictionary = new SortedDictionary<float, string>(); for (int i = 0; i < value.Length; i++) { var (key, value2) = value[i]; sortedDictionary.Add(key, value2); } LyricsTimeSeries = sortedDictionary.Keys.ToArray(); LyricsLines = sortedDictionary.Values.ToArray(); } } public Palette Palette { get; set; } = Palette.DEFAULT; } public class SelectableAudioTrack : CoreAudioTrack, ISelectableTrack { public Language Language { get; init; } public bool IsExplicit { get; init; } ConfigEntry<int> ISelectableTrack.Weight { get; set; } IAudioTrack[] ISelectableTrack.GetTracks() { return new IAudioTrack[1] { this }; } IAudioTrack ISelectableTrack.SelectTrack(int index) { return this; } void ISelectableTrack.Debug() { Debug.Log((object)string.Format("{0} Track \"{1}\", Intro={2:N4}, Loop={3:N4}", "MuzikaGromche", base.Name, base.LoadedIntro.length, base.LoadedLoop.length)); } } public class SelectableTracksGroup : ISelectableTrack { public IAudioTrack[] Tracks = Array.Empty<IAudioTrack>(); public string Name { get; init; } = ""; public Language Language { get; init; } public bool IsExplicit { get; init; } ConfigEntry<int> ISelectableTrack.Weight { get; set; } IAudioTrack[] ISelectableTrack.GetTracks() { return Tracks; } IAudioTrack ISelectableTrack.SelectTrack(int index) { if (Tracks.Length == 0) { throw new IndexOutOfRangeException("Tracks list is empty"); } return Mod.Index(Tracks, index); } void ISelectableTrack.Debug() { Debug.Log((object)string.Format("{0} Track Group \"{1}\", Count={2}", "MuzikaGromche", Name, Tracks.Length)); foreach (var (audioTrack, num) in Tracks.Select((IAudioTrack x, int i) => (x, i))) { Debug.Log((object)string.Format("{0} Track {1} \"{2}\", Intro={3:N4}, Loop={4:N4}", "MuzikaGromche", num, audioTrack.Name, audioTrack.LoadedIntro.length, audioTrack.LoadedLoop.length)); } } } internal readonly record struct BeatTimestamp { public float HalfLoopBeats => (float)LoopBeats / 2f; public readonly int LoopBeats; public readonly bool IsLooping; public readonly float Beat; public readonly bool IsExtrapolated; public BeatTimestamp(int loopBeats, bool isLooping, float beat, bool isExtrapolated) { IsLooping = false; Beat = 0f; IsExtrapolated = false; LoopBeats = loopBeats; IsLooping = isLooping || beat >= HalfLoopBeats; Beat = ((isLooping || beat >= (float)LoopBeats) ? Mod.Positive(beat, LoopBeats) : beat); IsExtrapolated = isExtrapolated; } public static BeatTimestamp operator +(BeatTimestamp self, float delta) { if (delta < 0f - self.HalfLoopBeats && self.Beat > self.HalfLoopBeats) { _ = self.IsLooping; } return new BeatTimestamp(self.LoopBeats, self.IsLooping, self.Beat + delta, self.IsExtrapolated); } public static BeatTimestamp operator -(BeatTimestamp self, float delta) { return self + (0f - delta); } public BeatTimestamp Floor() { float beat = Mathf.Floor(Beat); return new BeatTimestamp(LoopBeats, IsLooping, beat, IsExtrapolated); } public override string ToString() { return string.Format("{0}({1}{2} {3:N4}/{4})", "BeatTimestamp", IsLooping ? 'Y' : 'n', IsExtrapolated ? 'E' : '_', Beat, LoopBeats); } [CompilerGenerated] private bool PrintMembers(StringBuilder builder) { builder.Append("LoopBeats = "); builder.Append(LoopBeats.ToString()); builder.Append(", HalfLoopBeats = "); builder.Append(HalfLoopBeats.ToString()); builder.Append(", IsLooping = "); builder.Append(IsLooping.ToString()); builder.Append(", Beat = "); builder.Append(Beat.ToString()); builder.Append(", IsExtrapolated = "); builder.Append(IsExtrapolated.ToString()); return true; } } internal readonly record struct BeatTimeSpan { public float HalfLoopBeats => (float)LoopBeats / 2f; public readonly int LoopBeats; public readonly bool IsLooping; public readonly float BeatFromExclusive; public readonly float BeatToInclusive; public readonly bool IsExtrapolated; public static BeatTimeSpan Empty; public BeatTimeSpan(int loopBeats, bool isLooping, float beatFromExclusive, float beatToInclusive, bool isExtrapolated) { IsLooping = false; BeatFromExclusive = 0f; BeatToInclusive = 0f; IsExtrapolated = false; LoopBeats = loopBeats; IsLooping = isLooping || beatToInclusive >= HalfLoopBeats; BeatFromExclusive = wrap(beatFromExclusive); BeatToInclusive = wrap(beatToInclusive); IsExtrapolated = isExtrapolated; float wrap(float beat) { if (!isLooping && !(beat >= (float)loopBeats)) { return beat; } return Mod.Positive(beat, loopBeats); } } public static BeatTimeSpan Between(BeatTimestamp timestampFromExclusive, BeatTimestamp timestampToInclusive) { bool isExtrapolated = timestampFromExclusive.IsExtrapolated || timestampToInclusive.IsExtrapolated; return new BeatTimeSpan(timestampToInclusive.LoopBeats, timestampToInclusive.IsLooping, timestampFromExclusive.Beat, timestampToInclusive.Beat, isExtrapolated); } public static BeatTimeSpan Between(float beatFromExclusive, BeatTimestamp timestampToInclusive) { return new BeatTimeSpan(timestampToInclusive.LoopBeats, timestampToInclusive.IsLooping, beatFromExclusive, timestampToInclusive.Beat, timestampToInclusive.IsExtrapolated); } public BeatTimestamp ToTimestamp() { return new BeatTimestamp(LoopBeats, IsLooping, BeatToInclusive, IsExtrapolated); } public bool ContainsExact(float beat) { if (BeatFromExclusive < beat) { return beat <= BeatToInclusive; } return false; } public int? GetLastIndex(float[] timeSeries) { if (IsEmpty() || timeSeries == null || timeSeries.Length == 0) { return null; } if (IsWrapped()) { int? lastIndex = new BeatTimeSpan(LoopBeats, isLooping: false, -0.001f, BeatToInclusive, IsExtrapolated).GetLastIndex(timeSeries); if (lastIndex.HasValue) { return lastIndex; } int num = timeSeries.Length - 1; if (timeSeries[num] > BeatFromExclusive) { return num; } } else { int num2 = Array.BinarySearch(timeSeries, BeatToInclusive); if (num2 > 0 && num2 < timeSeries.Length && timeSeries[num2] > BeatFromExclusive) { return num2; } num2 = ~num2; num2--; if (num2 >= 0 && timeSeries[num2] > BeatFromExclusive && timeSeries[num2] <= BeatToInclusive) { return num2; } } return null; } public float Duration() { if (IsEmpty()) { return 0f; } if (IsWrapped()) { float num = (float)LoopBeats - BeatFromExclusive; float num2 = BeatToInclusive - 0f; return num + num2; } return BeatToInclusive - BeatFromExclusive; } public bool IsEmpty() { if (IsLooping) { float num = BeatToInclusive; if (BeatToInclusive < BeatFromExclusive) { num = BeatToInclusive + (float)LoopBeats; } return num - BeatFromExclusive > HalfLoopBeats; } return BeatFromExclusive > BeatToInclusive; } public bool IsWrapped() { if (IsLooping && !IsEmpty()) { return BeatToInclusive < BeatFromExclusive; } return false; } public override string ToString() { return string.Format("{0}({1}{2}, {3:N4}..{4:N4}/{5}{6})", "BeatTimeSpan", IsLooping ? 'Y' : 'n', IsExtrapolated ? 'E' : '_', BeatFromExclusive, BeatToInclusive, LoopBeats, IsEmpty() ? " Empty!" : ""); } [CompilerGenerated] private bool PrintMembers(StringBuilder builder) { builder.Append("LoopBeats = "); builder.Append(LoopBeats.ToString()); builder.Append(", HalfLoopBeats = "); builder.Append(HalfLoopBeats.ToString()); builder.Append(", IsLooping = "); builder.Append(IsLooping.ToString()); builder.Append(", BeatFromExclusive = "); builder.Append(BeatFromExclusive.ToString()); builder.Append(", BeatToInclusive = "); builder.Append(BeatToInclusive.ToString()); builder.Append(", IsExtrapolated = "); builder.Append(IsExtrapolated.ToString()); return true; } } internal class ExtrapolatedAudioSourceState { private float ExtrapolatedTime; private float LastKnownNonExtrapolatedTime; private float LastKnownRealtime; private const float MaxExtrapolationInterval = 0.5f; public bool IsPlaying { get; private set; } public float Time => ExtrapolatedTime; public bool HasStarted { get; private set; } public bool IsExtrapolated => LastKnownNonExtrapolatedTime != ExtrapolatedTime; public void Update(AudioSource audioSource, float realtime) { IsPlaying = audioSource.isPlaying; HasStarted |= audioSource.time != 0f; if (LastKnownNonExtrapolatedTime != audioSource.time) { LastKnownRealtime = realtime; LastKnownNonExtrapolatedTime = (ExtrapolatedTime = audioSource.time); } else if (IsPlaying && HasStarted && Config.ExtrapolateTime) { float num = realtime - LastKnownRealtime; if (0f < num && num < 0.5f) { ExtrapolatedTime = LastKnownNonExtrapolatedTime + num; } } } public override string ToString() { return string.Format("{0}({1}{2} ", "ExtrapolatedAudioSourceState", IsPlaying ? 'P' : '_', HasStarted ? 'S' : '0') + (IsExtrapolated ? $"{LastKnownRealtime:N4}, {LastKnownNonExtrapolatedTime:N4} => {ExtrapolatedTime:N4}" : $"{LastKnownRealtime:N4}, {LastKnownNonExtrapolatedTime:N4}") + ")"; } } internal class JesterAudioSourcesState { private readonly float IntroClipLength; private readonly ExtrapolatedAudioSourceState Intro = new ExtrapolatedAudioSourceState(); private readonly ExtrapolatedAudioSourceState Loop = new ExtrapolatedAudioSourceState(); private bool ReferenceIsIntro = true; public bool HasStarted => Intro.HasStarted; public bool IsExtrapolated { get { if (!ReferenceIsIntro) { return Loop.IsExtrapolated; } return Intro.IsExtrapolated; } } public float Time { get { if (!ReferenceIsIntro) { return IntroClipLength + Loop.Time; } return Intro.Time; } } public JesterAudioSourcesState(float introClipLength) { IntroClipLength = introClipLength; } public void Update(AudioSource intro, AudioSource loop, float realtime) { Loop.Update(loop, realtime); if (!Loop.HasStarted) { Intro.Update(intro, realtime); } else { ReferenceIsIntro = false; } } } internal class AudioLoopingState { private readonly float StartOfLoop; private readonly float LoopLength; private readonly int Beats; public bool IsLooping { get; private set; } public AudioLoopingState(float startOfLoop, float loopLength, int beats) { StartOfLoop = startOfLoop; LoopLength = loopLength; Beats = beats; } public BeatTimestamp Update(float time, bool isExtrapolated, float additionalOffset) { float num = StartOfLoop + additionalOffset; float beat = (time - num) / LoopLength * (float)Beats; BeatTimestamp result = new BeatTimestamp(Beats, IsLooping, beat, isExtrapolated); IsLooping |= result.IsLooping; return result; } } internal class BeatTimeState { private readonly IAudioTrack track; private readonly JesterAudioSourcesState AudioState; private readonly AudioLoopingState WindUpLoopingState; private readonly AudioLoopingState LoopLoopingState; private float LastKnownLoopOffsetBeat = float.NegativeInfinity; private static Random LyricsRandom; private int LyricsRandomPerLoop; private bool WindUpZeroBeatEventTriggered; public BeatTimeState(IAudioTrack track) { if (LyricsRandom == null) { LyricsRandom = new Random(RoundManager.Instance.playersManager.randomMapSeed + 1337); LyricsRandomPerLoop = LyricsRandom.Next(); } this.track = track; AudioState = new JesterAudioSourcesState(track.LoadedIntro.length); WindUpLoopingState = new AudioLoopingState(track.WindUpTimer, track.LoadedLoop.length, track.Beats); LoopLoopingState = new AudioLoopingState(track.WindUpTimer + track.LoopOffsetInSeconds, track.LoadedLoop.length, track.Beats); } public List<BaseEvent> Update(AudioSource intro, AudioSource loop) { float realtimeSinceStartup = Time.realtimeSinceStartup; AudioState.Update(intro, loop, realtimeSinceStartup); if (AudioState.HasStarted) { BeatTimestamp timestampToInclusive = Update(LoopLoopingState); BeatTimeSpan loopOffsetSpan = BeatTimeSpan.Between(LastKnownLoopOffsetBeat, timestampToInclusive); if (!loopOffsetSpan.IsEmpty()) { if (loopOffsetSpan.BeatFromExclusive > loopOffsetSpan.BeatToInclusive) { LyricsRandomPerLoop = LyricsRandom.Next(); } BeatTimestamp windUpOffsetTimestamp = Update(WindUpLoopingState); LastKnownLoopOffsetBeat = timestampToInclusive.Beat; return GetEvents(loopOffsetSpan, windUpOffsetTimestamp); } } return new List<BaseEvent>(); } private BeatTimestamp Update(AudioLoopingState loopingState) { return loopingState.Update(AudioState.Time, AudioState.IsExtrapolated, AdditionalOffset()); } private float AdditionalOffset() { return Config.AudioOffset.Value + track.BeatsOffsetInSeconds; } private List<BaseEvent> GetEvents(BeatTimeSpan loopOffsetSpan, BeatTimestamp windUpOffsetTimestamp) { List<BaseEvent> list = new List<BaseEvent>(); if (windUpOffsetTimestamp.Beat >= 0f && !WindUpZeroBeatEventTriggered) { list.Add(new WindUpZeroBeatEvent()); WindUpZeroBeatEventTriggered = true; } SetLightsColorEvent colorEvent = GetColorEvent(loopOffsetSpan, windUpOffsetTimestamp); if (colorEvent != null) { list.Add(colorEvent); } if (loopOffsetSpan.GetLastIndex(track.FlickerLightsTimeSeries).HasValue) { list.Add(new FlickerLightsEvent()); } if (Config.DisplayLyrics.Value) { int? lastIndex = loopOffsetSpan.GetLastIndex(track.LyricsTimeSeries); if (lastIndex.HasValue) { int valueOrDefault = lastIndex.GetValueOrDefault(); if (valueOrDefault < track.LyricsLines.Length) { string[] array = track.LyricsLines[valueOrDefault].Split('\t'); int num = LyricsRandomPerLoop % array.Length; string text = array[num]; if (text != "") { list.Add(new LyricsEvent(text)); } } } } return list; } private SetLightsColorEvent? GetColorEvent(BeatTimeSpan loopOffsetSpan, BeatTimestamp windUpOffsetTimestamp) { SetLightsColorTransitionEvent setLightsColorTransitionEvent = FadeOut(loopOffsetSpan, windUpOffsetTimestamp); if (setLightsColorTransitionEvent != null) { return setLightsColorTransitionEvent; } SetLightsColorEvent setLightsColorEvent = ColorFromPaletteAtTimestamp(windUpOffsetTimestamp); if (setLightsColorEvent != null) { return setLightsColorEvent; } return null; } private SetLightsColorTransitionEvent? FadeOut(BeatTimeSpan loopOffsetSpan, BeatTimestamp windUpOffsetTimestamp) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) float num = track.FadeOutBeat + track.FadeOutDuration; if (windUpOffsetTimestamp.Beat < 0f && track.FadeOutBeat < loopOffsetSpan.BeatToInclusive && loopOffsetSpan.BeatFromExclusive <= num) { float t = (loopOffsetSpan.BeatToInclusive - track.FadeOutBeat) / track.FadeOutDuration; return new SetLightsColorTransitionEvent(Color.white, Color.black, Easing.Linear, t); } return null; } public SetLightsColorEvent? ColorFromPaletteAtTimestamp(BeatTimestamp timestamp) { //IL_00d3: Unknown result type (might be due to invalid IL or missing references) if (timestamp.Beat <= 0f - track.ColorTransitionIn) { return null; } BeatTimestamp beatTimestamp = timestamp.Floor(); BeatTimestamp beatTimestamp2 = beatTimestamp + 1f; float transitionLength = track.ColorTransitionIn + track.ColorTransitionOut; if ((double)transitionLength > 0.01) { if (BeatTimeSpan.Between(beatTimestamp, timestamp).Duration() < track.ColorTransitionOut) { return ColorTransition(beatTimestamp); } if (BeatTimeSpan.Between(timestamp, beatTimestamp2).Duration() < track.ColorTransitionIn) { return ColorTransition(beatTimestamp2); } } return new SetLightsColorEvent(ColorAtWholeBeat(timestamp)); Color ColorAtWholeBeat(BeatTimestamp timestamp) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) if (timestamp.Beat >= 0f) { int index = Mathf.FloorToInt(timestamp.Beat); return Mod.Index(track.Palette.Colors, index); } Color white = Color.white; if (!float.IsNaN(track.FadeOutBeat)) { return Color.black; } return white; } SetLightsColorEvent ColorTransition(BeatTimestamp clipsBoundary) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) BeatTimestamp beatTimestamp3 = clipsBoundary - track.ColorTransitionIn; BeatTimestamp timestamp2 = clipsBoundary + track.ColorTransitionOut; float t = BeatTimeSpan.Between(beatTimestamp3, timestamp).Duration() / transitionLength; if (track.ColorTransitionIn == 0f) { beatTimestamp3 -= 0.01f; } return new SetLightsColorTransitionEvent(ColorAtWholeBeat(beatTimestamp3), ColorAtWholeBeat(timestamp2), track.ColorTransitionEasing, t); } } } internal abstract class BaseEvent { } internal class SetLightsColorEvent : BaseEvent { public readonly Color Color; public SetLightsColorEvent(Color color) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) Color = color; base..ctor(); } public override string ToString() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) return "Color(#" + ColorUtility.ToHtmlStringRGB(Color) + ")"; } } internal class SetLightsColorTransitionEvent : SetLightsColorEvent { public readonly Color From; public readonly Color To; public readonly Easing Easing; public readonly float T; public SetLightsColorTransitionEvent(Color from, Color to, Easing easing, float t) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: 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_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) From = from; To = to; Easing = easing; T = t; base..ctor(Color.Lerp(from, to, Mathf.Clamp(easing.Eval(t), 0f, 1f))); } public override string ToString() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) return $"Color(#{ColorUtility.ToHtmlStringRGB(Color)} = #{ColorUtility.ToHtmlStringRGB(From)}..#{ColorUtility.ToHtmlStringRGB(To)} {Easing} {T:N4})"; } } internal class FlickerLightsEvent : BaseEvent { public override string ToString() { return "Flicker"; } } internal class LyricsEvent : BaseEvent { public readonly string Text; public LyricsEvent(string text) { Text = text; base..ctor(); } public override string ToString() { return "Lyrics(" + Text.Replace("\n", "\\n") + ")"; } } internal class WindUpZeroBeatEvent : BaseEvent { public override string ToString() { return "WindUp"; } } internal static class Mod { public static int Positive(int x, int m) { int num = x % m; if (num >= 0) { return num; } return num + m; } public static float Positive(float x, float m) { float num = x % m; if (!(num < 0f)) { return num; } return num + m; } public static T Index<T>(IList<T> array, int index) { return array[Positive(index, array.Count)]; } } internal readonly struct RandomWeightedIndex { private readonly int[] Weights; public int TotalWeights { get; } public RandomWeightedIndex(int[] weights) { Weights = weights; TotalWeights = Weights.Sum(); if (TotalWeights == 0) { Weights = Weights.Select((int _) => 1).ToArray(); TotalWeights = Weights.Length; } } private byte[] GetHash(int seed) { byte[] array = new byte[4 * (1 + Weights.Length)]; int num = 0; Buffer.BlockCopy(BitConverter.GetBytes(seed), 0, array, num, 4); int[] weights = Weights; foreach (int value in weights) { num += 4; Buffer.BlockCopy(BitConverter.GetBytes(value), 0, array, num, 4); } return SHA256.Create().ComputeHash(array); } private int GetRawIndex(byte[] hash) { if (TotalWeights == 0) { return -1; } int num = 0; foreach (byte b in hash) { num *= 256 % TotalWeights; num %= TotalWeights; num += b % TotalWeights; num %= TotalWeights; } return num; } private int GetWeightedIndex(int rawIndex) { if (rawIndex < 0 || rawIndex >= TotalWeights) { return -1; } int num = 0; foreach (var item3 in Weights.Select((int x, int i) => (x, i))) { int item = item3.Item1; int item2 = item3.Item2; num += item; if (rawIndex < num) { return item2; } } return -1; } public int GetRandomWeightedIndex(int seed) { byte[] hash = GetHash(seed); int rawIndex = GetRawIndex(hash); return GetWeightedIndex(rawIndex); } public override string ToString() { return $"Weighted(Total={TotalWeights}, Weights=[{string.Join(',', Weights)}])"; } } internal class Config { [CompilerGenerated] private static class <>O { public static CanModifyDelegate <0>__CanModifyWeightsNow; public static CanModifyDelegate <1>__CanModifyIfHost; } public static ConfigEntry<bool> DisplayLyrics { get; private set; } = null; public static ConfigEntry<float> AudioOffset { get; private set; } = null; public static ConfigEntry<bool> SkipExplicitTracks { get; private set; } = null; public static ConfigEntry<bool> OverrideSpawnRates { get; private set; } = null; public static bool ExtrapolateTime { get; private set; } = true; public static bool ShouldSkipWindingPhase { get; private set; } = false; internal Config(ConfigFile configFile) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Expected O, but got Unknown //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Expected O, but got Unknown //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Expected O, but got Unknown //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Expected O, but got Unknown //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Expected O, but got Unknown //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Expected O, but got Unknown //IL_025a: Expected O, but got Unknown //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Expected O, but got Unknown //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Expected O, but got Unknown DisplayLyrics = configFile.Bind<bool>("General", "Display Lyrics", true, new ConfigDescription("Display lyrics in the HUD tooltip when you hear the music.", (AcceptableValueBase)null, Array.Empty<object>())); LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(DisplayLyrics, false)); AudioOffset = configFile.Bind<float>("General", "Audio Offset", 0f, new ConfigDescription("Adjust audio offset (in seconds).\n\nIf you are playing with Bluetooth headphones and experiencing a visual desync, try setting this to about negative 0.2.\n\nIf your video output has high latency (like a long HDMI cable etc.), try positive values instead.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-0.5f, 0.5f), Array.Empty<object>())); LethalConfigManager.AddConfigItem((BaseConfigItem)new FloatSliderConfigItem(AudioOffset, false)); SkipExplicitTracks = configFile.Bind<bool>("General", "Skip Explicit Tracks", false, new ConfigDescription("When choosing tracks at random, skip the ones with Explicit Content/Lyrics.", (AcceptableValueBase)null, Array.Empty<object>())); LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(SkipExplicitTracks, Default<BoolCheckBoxOptions>(new BoolCheckBoxOptions()))); OverrideSpawnRates = configFile.Bind<bool>("General", "Override Spawn Rates", true, new ConfigDescription("Deviate from vanilla spawn rates to experience content of this mod more often.", (AcceptableValueBase)null, Array.Empty<object>())); LethalConfigManager.AddConfigItem((BaseConfigItem)new BoolCheckBoxConfigItem(OverrideSpawnRates, Default<BoolCheckBoxOptions>(new BoolCheckBoxOptions()))); AcceptableValueRange<int> val = new AcceptableValueRange<int>(0, 100); HashSet<Language> hashSet = new HashSet<Language>(); ISelectableTrack[] tracks = Plugin.Tracks; foreach (ISelectableTrack selectableTrack in tracks) { Language language = selectableTrack.Language; string text = "Tracks." + language.Short; if (!hashSet.Contains(language)) { hashSet.Add(language); string text2 = "Toggle all " + language.Full + " tracks"; string text3 = "Toggle all tracks in this section ON or OFF. Effective immediately."; string text4 = "Toggle"; GenericButtonConfigItem val2 = new GenericButtonConfigItem(text, text2, text3, text4, (GenericButtonHandler)delegate { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (CanModifyResult.op_Implicit(CanModifyWeightsNow())) { List<ISelectableTrack> list = Plugin.Tracks.Where((ISelectableTrack t) => t.Language.Equals(language)).ToList(); int value = (list.All((ISelectableTrack t) => t.Weight.Value == 0) ? 50 : 0); foreach (ISelectableTrack item in list) { item.Weight.Value = value; } } }); GenericButtonOptions buttonOptions = val2.ButtonOptions; object obj = <>O.<0>__CanModifyWeightsNow; if (obj == null) { CanModifyDelegate val3 = CanModifyWeightsNow; <>O.<0>__CanModifyWeightsNow = val3; obj = (object)val3; } ((BaseOptions)buttonOptions).CanModifyCallback = (CanModifyDelegate)obj; LethalConfigManager.AddConfigItem((BaseConfigItem)val2); } string text5 = (selectableTrack.IsExplicit ? "Explicit Content/Lyrics!\n\n" : ""); string text6 = "Language: " + language.Full + "\n\n" + text5 + "Random (relative) chance of selecting this track.\n\nSet to zero to effectively disable the track."; selectableTrack.Weight = configFile.Bind<int>(new ConfigDefinition(text, selectableTrack.Name), 50, new ConfigDescription(text6, (AcceptableValueBase)(object)val, new object[1] { selectableTrack })); LethalConfigManager.AddConfigItem((BaseConfigItem)new IntSliderConfigItem(selectableTrack.Weight, Default<IntSliderOptions>(new IntSliderOptions()))); } } internal static IAudioTrack OverrideCurrentTrack(IAudioTrack track) { return track; } public static CanModifyResult CanModifyIfHost() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) StartOfRound instance = StartOfRound.Instance; if (!Object.op_Implicit((Object)(object)instance)) { return CanModifyResult.True(); } if (!((NetworkBehaviour)instance).IsHost) { return CanModifyResult.False("Only for host"); } return CanModifyResult.True(); } public static CanModifyResult CanModifyWeightsNow() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) StartOfRound instance = StartOfRound.Instance; if (!Object.op_Implicit((Object)(object)instance)) { return CanModifyResult.True(); } if (!((NetworkBehaviour)instance).IsHost) { return CanModifyResult.False("Only for host"); } if (!instance.inShipPhase) { return CanModifyResult.False("Only while orbiting"); } return CanModifyResult.True(); } private T Default<T>(T options) where T : BaseOptions { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown ((BaseOptions)options).RequiresRestart = false; object obj = options; object obj2 = <>O.<1>__CanModifyIfHost; if (obj2 == null) { CanModifyDelegate val = CanModifyIfHost; <>O.<1>__CanModifyIfHost = val; obj2 = (object)val; } ((BaseOptions)obj).CanModifyCallback = (CanModifyDelegate)obj2; return options; } } [HarmonyPatch(typeof(GameNetworkManager))] internal static class GameNetworkManagerPatch { private const string JesterEnemyPrefabName = "JesterEnemy"; [HarmonyPatch("Start")] [HarmonyPrefix] private static void StartPrefix(GameNetworkManager __instance) { NetworkPrefab val = ((IEnumerable<NetworkPrefab>)NetworkManager.Singleton.NetworkConfig.Prefabs.Prefabs).FirstOrDefault((Func<NetworkPrefab, bool>)((NetworkPrefab prefab) => ((Object)prefab.Prefab).name == "JesterEnemy")); if (val == null) { Debug.LogError((object)"MuzikaGromche JesterEnemy prefab not found!"); return; } val.Prefab.AddComponent<MuzikaGromcheJesterNetworkBehaviour>(); Debug.Log((object)"MuzikaGromche Patched JesterEnemy"); } } internal class MuzikaGromcheJesterNetworkBehaviour : NetworkBehaviour { [CompilerGenerated] private sealed class <ChooseTrackDeferredCoroutine>d__13 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public MuzikaGromcheJesterNetworkBehaviour <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ChooseTrackDeferredCoroutine>d__13(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown int num = <>1__state; MuzikaGromcheJesterNetworkBehaviour muzikaGromcheJesterNetworkBehaviour = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForEndOfFrame(); <>1__state = 1; return true; case 1: <>1__state = -1; muzikaGromcheJesterNetworkBehaviour.DeferredCoroutine = null; muzikaGromcheJesterNetworkBehaviour.ChooseTrackServerRpc(); 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 const string IntroAudioGameObjectName = "MuzikaGromcheAudio (Intro)"; private const string LoopAudioGameObjectName = "MuzikaGromcheAudio (Loop)"; private int SelectedTrackIndex; internal IAudioTrack? CurrentTrack; internal BeatTimeState? BeatTimeState; internal AudioSource IntroAudioSource; internal AudioSource LoopAudioSource; private Coroutine? DeferredCoroutine; private void Awake() { Transform val = ((Component)this).gameObject.transform.Find("FarAudio"); if ((Object)(object)val == (Object)null) { Debug.LogError((object)"MuzikaGromche JesterEnemy->FarAudio prefab not found!"); return; } GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)this).gameObject.transform); ((Object)val2).name = "MuzikaGromcheAudio (Intro)"; GameObject val3 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)this).gameObject.transform); ((Object)val3).name = "MuzikaGromcheAudio (Loop)"; IntroAudioSource = val2.GetComponent<AudioSource>(); IntroAudioSource.maxDistance = 150f; IntroAudioSource.dopplerLevel = 0f; IntroAudioSource.loop = false; LoopAudioSource = val3.GetComponent<AudioSource>(); LoopAudioSource.maxDistance = 150f; LoopAudioSource.dopplerLevel = 0f; LoopAudioSource.loop = true; Debug.Log((object)"MuzikaGromche MuzikaGromcheJesterNetworkBehaviour Patched JesterEnemy"); } public override void OnNetworkSpawn() { ChooseTrackDeferred(); ISelectableTrack[] tracks = Plugin.Tracks; for (int i = 0; i < tracks.Length; i++) { tracks[i].Weight.SettingChanged += ChooseTrackDeferredDelegate; } Config.SkipExplicitTracks.SettingChanged += ChooseTrackDeferredDelegate; ((NetworkBehaviour)this).OnNetworkSpawn(); } public override void OnNetworkDespawn() { ISelectableTrack[] tracks = Plugin.Tracks; for (int i = 0; i < tracks.Length; i++) { tracks[i].Weight.SettingChanged -= ChooseTrackDeferredDelegate; } Config.SkipExplicitTracks.SettingChanged -= ChooseTrackDeferredDelegate; ((NetworkBehaviour)this).OnNetworkDespawn(); } private void ChooseTrackDeferredDelegate(object sender, EventArgs e) { SelectedTrackIndex = 0; ChooseTrackDeferred(); } private void ChooseTrackDeferred() { if (DeferredCoroutine != null) { ((MonoBehaviour)this).StopCoroutine(DeferredCoroutine); DeferredCoroutine = null; } DeferredCoroutine = ((MonoBehaviour)this).StartCoroutine(ChooseTrackDeferredCoroutine()); } [IteratorStateMachine(typeof(<ChooseTrackDeferredCoroutine>d__13))] private IEnumerator ChooseTrackDeferredCoroutine() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ChooseTrackDeferredCoroutine>d__13(0) { <>4__this = this }; } [ClientRpc] public void SetTrackClientRpc(string name) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 2 && (networkManager.IsServer || networkManager.IsHost)) { ClientRpcParams val = default(ClientRpcParams); FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendClientRpc(357426583u, val, (RpcDelivery)0); bool flag = name != null; ((FastBufferWriter)(ref val2)).WriteValueSafe<bool>(ref flag, default(ForPrimitives)); if (flag) { ((FastBufferWriter)(ref val2)).WriteValueSafe(name, false); } ((NetworkBehaviour)this).__endSendClientRpc(ref val2, 357426583u, val, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 2 && (networkManager.IsClient || networkManager.IsHost)) { Debug.Log((object)("MuzikaGromche SetTrackClientRpc " + name)); IAudioTrack audioTrack = Plugin.FindTrackNamed(name); if (audioTrack != null) { CurrentTrack = Config.OverrideCurrentTrack(audioTrack); } } } [ServerRpc] public void ChooseTrackServerRpc() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Invalid comparison between Unknown and I4 //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Invalid comparison between Unknown and I4 NetworkManager networkManager = ((NetworkBehaviour)this).NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if ((int)base.__rpc_exec_stage != 1 && (networkManager.IsClient || networkManager.IsHost)) { if (((NetworkBehaviour)this).OwnerClientId != networkManager.LocalClientId) { if ((int)networkManager.LogLevel <= 1) { Debug.LogError((object)"Only the owner can invoke a ServerRpc that requires ownership!"); } return; } ServerRpcParams val = default(ServerRpcParams); FastBufferWriter val2 = ((NetworkBehaviour)this).__beginSendServerRpc(2436221149u, val, (RpcDelivery)0); ((NetworkBehaviour)this).__endSendServerRpc(ref val2, 2436221149u, val, (RpcDelivery)0); } if ((int)base.__rpc_exec_stage == 1 && (networkManager.IsServer || networkManager.IsHost)) { ISelectableTrack selectableTrack = Plugin.ChooseTrack(); IAudioTrack audioTrack = selectableTrack.SelectTrack(SelectedTrackIndex); Debug.Log((object)string.Format("{0} ChooseTrackServerRpc {1} #{2} {3}", "MuzikaGromche", selectableTrack.Name, SelectedTrackIndex, audioTrack.Name)); SetTrackClientRpc(audioTrack.Name); SelectedTrackIndex++; } } internal void PlayScheduledLoop() { double num = AudioSettings.dspTime + (double)IntroAudioSource.clip.length - (double)IntroAudioSource.time; LoopAudioSource.PlayScheduled(num); Debug.Log((object)string.Format("{0} Play Intro: dspTime={1:N4}, intro.time={2:N4}/{3:N4}, scheduled Loop={4}", "MuzikaGromche", AudioSettings.dspTime, IntroAudioSource.time, IntroAudioSource.clip.length, num)); } protected override void __initializeVariables() { ((NetworkBehaviour)this).__initializeVariables(); } [RuntimeInitializeOnLoadMethod] internal static void InitializeRPCS_MuzikaGromcheJesterNetworkBehaviour() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown NetworkManager.__rpc_func_table.Add(357426583u, new RpcReceiveHandler(__rpc_handler_357426583)); NetworkManager.__rpc_func_table.Add(2436221149u, new RpcReceiveHandler(__rpc_handler_2436221149)); } private static void __rpc_handler_357426583(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) NetworkManager networkManager = target.NetworkManager; if (networkManager != null && networkManager.IsListening) { bool flag = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref flag, default(ForPrimitives)); string trackClientRpc = null; if (flag) { ((FastBufferReader)(ref reader)).ReadValueSafe(ref trackClientRpc, false); } target.__rpc_exec_stage = (__RpcExecStage)2; ((MuzikaGromcheJesterNetworkBehaviour)(object)target).SetTrackClientRpc(trackClientRpc); target.__rpc_exec_stage = (__RpcExecStage)0; } } private static void __rpc_handler_2436221149(NetworkBehaviour target, FastBufferReader reader, __RpcParams rpcParams) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Invalid comparison between Unknown and I4 NetworkManager networkManager = target.NetworkManager; if (networkManager == null || !networkManager.IsListening) { return; } if (rpcParams.Server.Receive.SenderClientId != target.OwnerClientId) { if ((int)networkManager.LogLevel <= 1) { Debug.LogError((object)"Only the owner can invoke a ServerRpc that requires ownership!"); } } else { target.__rpc_exec_stage = (__RpcExecStage)1; ((MuzikaGromcheJesterNetworkBehaviour)(object)target).ChooseTrackServerRpc(); target.__rpc_exec_stage = (__RpcExecStage)0; } } protected internal override string __getTypeName() { return "MuzikaGromcheJesterNetworkBehaviour"; } } [HarmonyPatch(typeof(JesterAI))] internal static class JesterPatch { private class State { public int currentBehaviourStateIndex; public int previousState; public float stunNormalizedTimer; } [HarmonyPatch("SetJesterInitialValues")] [HarmonyPostfix] private static void SetJesterInitialValuesPostfix(JesterAI __instance) { MuzikaGromcheJesterNetworkBehaviour component = ((Component)__instance).GetComponent<MuzikaGromcheJesterNetworkBehaviour>(); component.IntroAudioSource.Stop(); component.LoopAudioSource.Stop(); } [HarmonyPatch("Update")] [HarmonyPrefix] private static void JesterUpdatePrefix(JesterAI __instance, out State __state) { __state = new State { currentBehaviourStateIndex = ((EnemyAI)__instance).currentBehaviourStateIndex, previousState = __instance.previousState, stunNormalizedTimer = ((EnemyAI)__instance).stunNormalizedTimer }; } [HarmonyPatch("Update")] [HarmonyPostfix] private static void JesterUpdatePostfix(JesterAI __instance, State __state) { //IL_01c3: Unknown result type (might be due to invalid IL or missing references) MuzikaGromcheJesterNetworkBehaviour component = ((Component)__instance).GetComponent<MuzikaGromcheJesterNetworkBehaviour>(); AudioSource introAudioSource = component.IntroAudioSource; AudioSource loopAudioSource = component.LoopAudioSource; if (component.CurrentTrack == null) { return; } switch (__state.currentBehaviourStateIndex) { case 1: if (__state.previousState != 1) { introAudioSource.clip = component.CurrentTrack.LoadedIntro; loopAudioSource.clip = component.CurrentTrack.LoadedLoop; component.BeatTimeState = new BeatTimeState(component.CurrentTrack); __instance.popUpTimer = component.CurrentTrack.WindUpTimer; if (Config.ShouldSkipWindingPhase) { float num = (__instance.popUpTimer = 5f); introAudioSource.time = component.CurrentTrack.WindUpTimer - num; } else { introAudioSource.time = 0f; } __instance.farAudio.Stop(); introAudioSource.Play(); component.PlayScheduledLoop(); } if (((EnemyAI)__instance).stunNormalizedTimer > 0f) { introAudioSource.Pause(); loopAudioSource.Stop(); } else if (!introAudioSource.isPlaying) { __instance.farAudio.Stop(); introAudioSource.UnPause(); component.PlayScheduledLoop(); } break; case 2: if (__state.previousState != 2) { ((EnemyAI)__instance).creatureVoice.Stop(); } break; } if (__state.previousState == 2 && __instance.previousState != 2) { Plugin.ResetLightColor(); DiscoBallManager.Disable(); component.ChooseTrackServerRpc(); component.BeatTimeState = null; } else { if (__instance.previousState != 1 && __instance.previousState != 2) { return; } BeatTimeState beatTimeState = component.BeatTimeState; if (beatTimeState == null) { return; } foreach (BaseEvent item in beatTimeState.Update(introAudioSource, loopAudioSource)) { if (!(item is WindUpZeroBeatEvent)) { if (!(item is SetLightsColorEvent setLightsColorEvent)) { if (!(item is FlickerLightsEvent)) { if (item is LyricsEvent lyricsEvent && Plugin.LocalPlayerCanHearMusic((EnemyAI)(object)__instance)) { Plugin.DisplayLyrics(lyricsEvent.Text); } } else { RoundManager.Instance.FlickerLights(true, false); } } else { Plugin.SetLightColor(setLightsColorEvent.Color); } } else { DiscoBallManager.Enable(); } } } } } [HarmonyPatch(typeof(EnemyAI))] internal static class EnemyAIPatch { [HarmonyPatch("OnDestroy")] [HarmonyPrefix] private static void CleanUpOnDestroy(EnemyAI __instance) { if (__instance is JesterAI) { Plugin.ResetLightColor(); DiscoBallManager.Disable(); } } } internal static class PoweredLightsAnimators { private delegate void ManualPatch(GameObject animatorContainer); private readonly record struct AnimatorPatch(string AnimatorContainerPath, RuntimeAnimatorController AnimatorController, bool AddTagAndAnimator, ManualPatch? ManualPatch); private readonly record struct TilePatch(string TileName, AnimatorPatch[] Patches) { public readonly string TileCloneName = TileName + "(Clone)"; } private readonly record struct AnimatorPatchDescriptor(string AnimatorContainerPath, string AnimatorControllerAssetPath, bool AddTagAndAnimator = false, ManualPatch? ManualPatch = null) { public AnimatorPatch Load(AssetBundle assetBundle) { RuntimeAnimatorController animatorController = assetBundle.LoadAsset<RuntimeAnimatorController>(AnimatorControllerAssetPath) ?? throw new FileNotFoundException("RuntimeAnimatorController not found: " + AnimatorControllerAssetPath, AnimatorControllerAssetPath); return new AnimatorPatch(AnimatorContainerPath, animatorController, AddTagAndAnimator, ManualPatch); } } private readonly record struct TilePatchDescriptor(string[] TileNames, AnimatorPatchDescriptor[] Descriptors) { public TilePatchDescriptor(string[] TileNames, AnimatorPatchDescriptor[] Descriptors) { this.TileNames = TileNames; this.Descriptors = Descriptors; } public TilePatchDescriptor(string TileName, AnimatorPatchDescriptor[] Descriptors) : this(new string[1] { TileName }, Descriptors) { } public TilePatch[] Load(AssetBundle assetBundle) { AssetBundle assetBundle2 = assetBundle; AnimatorPatch[] patches = Descriptors.Select((AnimatorPatchDescriptor d) => d.Load(assetBundle2)).ToArray(); return TileNames.Select((string tileName) => new TilePatch(tileName, patches)).ToArray(); } } private const string PoweredLightTag = "PoweredLight"; private static IDictionary<string, TilePatch> Patches = new Dictionary<string, TilePatch>(); private static AudioClip AudioClipOn = null; private static AudioClip AudioClipOff = null; private static AudioClip AudioClipFlicker = null; public static void Load() { string text = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "muzikagromche_poweredlightsanimators"); AssetBundle assetBundle = AssetBundle.LoadFromFile(text) ?? throw new NullReferenceException("Failed to load bundle"); AudioClipOn = assetBundle.LoadAsset<AudioClip>("Assets/LethalCompany/Mods/MuzikaGromche/AudioClips/LightOn.ogg"); AudioClipOff = assetBundle.LoadAsset<AudioClip>("Assets/LethalCompany/Mods/MuzikaGromche/AudioClips/LightOff.ogg"); AudioClipFlicker = assetBundle.LoadAsset<AudioClip>("Assets/LethalCompany/Mods/MuzikaGromche/AudioClips/LightFlicker.ogg"); Patches = new TilePatchDescriptor[10] { new TilePatchDescriptor("KitchenTile", new AnimatorPatchDescriptor[2] { new AnimatorPatchDescriptor("PoweredLightTypeB", "Assets/LethalCompany/Mods/MuzikaGromche/AnimatorControllers/Point Light (4) (Patched).controller"), new AnimatorPatchDescriptor("PoweredLightTypeB (1)", "Assets/LethalCompany/Mods/MuzikaGromche/AnimatorControllers/Point Light (4) (Patched).controller") }), new TilePatchDescriptor("ManorStartRoom", new AnimatorPatchDescriptor[2] { new AnimatorPatchDescriptor("ManorStartRoom/Chandelier/PoweredLightTypeB (1)", "Assets/LethalCompany/Mods/MuzikaGromche/AnimatorControllers/Point Light (4) (Patched).controller"), new AnimatorPatchDescriptor("ManorStartRoom/Chandelier2/PoweredLightTypeB", "Assets/LethalCompany/Mods/MuzikaGromche/AnimatorControllers/Point Light (4) (Patched).controller") }), new TilePatchDescriptor("ManorStartRoomSmall", new AnimatorPatchDescriptor[2] { new AnimatorPatchDescriptor("ManorStartRoomMesh/Chandelier/PoweredLightTypeB (1)", "Assets/LethalCompany/Mods/MuzikaGromche/AnimatorControllers/Point Light (4) (Patched).controller"), new AnimatorPatchDescriptor("ManorStartRoomMesh/Chandelier2/PoweredLightTypeB", "Assets/LethalCompany/Mods/MuzikaGromche/AnimatorControllers/Point Light (4) (Patched).controller") }), new TilePatchDescriptor("NarrowHallwayTile2x2", new AnimatorPatchDescriptor[2] { new AnimatorPatchDescriptor("MineshaftSpotlight (1)", "Assets/LethalCompany/Mods/MuzikaGromche/AnimatorControllers/MineshaftSpotlight (Patched).controller"), new AnimatorPatchDescriptor("MineshaftSpotlight (2)", "Assets/LethalCompany/Mods/MuzikaGromche/AnimatorControllers/MineshaftSpotlight (Patched).controller") }), new TilePatchDescriptor("BirthdayRoomTile", new AnimatorPatchDescriptor[1] { new AnimatorPatchDescriptor("Lights/MineshaftSpotlight", "Assets/LethalCompany/Mods/MuzikaGromche/AnimatorControllers/MineshaftSpotlight (Patched).controller") }), new TilePatchDescriptor("BathroomTileContainer", new AnimatorPatchDescriptor[2] { new AnimatorPatchDescriptor("MineshaftSpotlight", "Assets/LethalCompany/Mods/MuzikaGromche/AnimatorControllers/MineshaftSpotlight (Patched).controller"), new AnimatorPatchDescriptor("LightbulbLine/lightbulbsLineMesh", "Assets/LethalCompany/Mods/MuzikaGromche/AnimatorControllers/lightbulbsLineMesh (Patched).controller") }), new TilePatchDescriptor(new string[2] { "BedroomTile", "BedroomTileB" }, new AnimatorPatchDescriptor[2] { new AnimatorPatchDescriptor("CeilingFanAnimContainer", "Assets/LethalCompany/Mods/MuzikaGromche/AnimatorControllers/CeilingFan (originally GameObject) (Patched).controller"), new AnimatorPatchDescriptor("MineshaftSpotlight (1)", "Assets/LethalCompany/Mods/MuzikaGromche/AnimatorControllers/MineshaftSpotlight (Patched).controller") }), new TilePatchDescriptor("GarageTile", new AnimatorPatchDescriptor[2] { new AnimatorPatchDescriptor("HangingLEDBarLight (3)", "Asse