diff --git a/CHANGELOG.md b/CHANGELOG.md index 909ab86..f97c13c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Fixed visual glitch at the last beat of a loop. - Fixed timings of one of the tracks. - Removed unnecessary "Enable Color Animations" config option. +- Fixed missing flickering behaviours for some animators controllers. ## MuzikaGromche 13.37.911 - Sri Lanka Bus hotfix diff --git a/MuzikaGromche/MuzikaGromche.csproj b/MuzikaGromche/MuzikaGromche.csproj index 0f74d09..ae5a67b 100644 --- a/MuzikaGromche/MuzikaGromche.csproj +++ b/MuzikaGromche/MuzikaGromche.csproj @@ -55,6 +55,7 @@ + diff --git a/MuzikaGromche/Plugin.cs b/MuzikaGromche/Plugin.cs index bedb894..29029ec 100644 --- a/MuzikaGromche/Plugin.cs +++ b/MuzikaGromche/Plugin.cs @@ -536,9 +536,11 @@ namespace MuzikaGromche } Config = new Config(base.Config); DiscoBallManager.Initialize(); + PoweredLightsAnimators.Load(); var harmony = new Harmony(PluginInfo.PLUGIN_NAME); harmony.PatchAll(typeof(JesterPatch)); harmony.PatchAll(typeof(EnemyAIPatch)); + harmony.PatchAll(typeof(PoweredLightsAnimatorsPatch)); } else { diff --git a/MuzikaGromche/PoweredLightsAnimators.cs b/MuzikaGromche/PoweredLightsAnimators.cs new file mode 100644 index 0000000..397b685 --- /dev/null +++ b/MuzikaGromche/PoweredLightsAnimators.cs @@ -0,0 +1,143 @@ +using DunGen; +using HarmonyLib; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using UnityEngine; + +namespace MuzikaGromche +{ + internal class PoweredLightsAnimators + { + private readonly record struct AnimatorPatch(string AnimatorContainerPath, RuntimeAnimatorController AnimatorController); + + private readonly record struct TilePatch(string TileName, AnimatorPatch[] Patches) + { + // We are specifically looking for cloned tiles, not the original prototypes. + public readonly string TileCloneName = $"{TileName}(Clone)"; + } + + private readonly record struct AnimatorPatchDescriptor(string AnimatorContainerPath, string AnimatorControllerAssetPath) + { + public AnimatorPatch Load(AssetBundle assetBundle) + { + var animationController = assetBundle.LoadAsset(AnimatorControllerAssetPath) + ?? throw new FileNotFoundException($"RuntimeAnimatorController not found: {AnimatorControllerAssetPath}", AnimatorControllerAssetPath); + return new(AnimatorContainerPath, animationController); + } + } + + private readonly record struct TilePatchDescriptor(string[] TileNames, AnimatorPatchDescriptor[] Descriptors) + { + public TilePatchDescriptor(string TileName, AnimatorPatchDescriptor[] Descriptors) + : this([TileName], Descriptors) + { + } + + public TilePatch[] Load(AssetBundle assetBundle) + { + var patches = Descriptors.Select(d => d.Load(assetBundle)).ToArray(); + return [.. TileNames.Select(tileName => new TilePatch(tileName, patches))]; + } + } + + private static IDictionary Patches = new Dictionary(); + + public static void Load() + { + const string BundleFileName = "muzikagromche_poweredlightsanimators"; + string bundlePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), BundleFileName); + var assetBundle = AssetBundle.LoadFromFile(bundlePath) + ?? throw new NullReferenceException("Failed to load bundle"); + + const string BasePath = "Assets/LethalCompany/Mods/MuzikaGromche/AnimatorControllers/"; + + const string PointLight4 = $"{BasePath}Point Light (4) (Patched).controller"; + const string MineshaftSpotlight = $"{BasePath}MineshaftSpotlight (Patched).controller"; + const string LightbulbsLine = $"{BasePath}lightbulbsLineMesh (Patched).controller"; + const string CeilingFan = $"{BasePath}CeilingFan (originally GameObject) (Patched).controller"; + + + TilePatchDescriptor[] descriptors = + [ + // < v70 + new("ManorStartRoom", [ + new("ManorStartRoom/Chandelier/PoweredLightTypeB (1)", PointLight4), + new("ManorStartRoom/Chandelier2/PoweredLightTypeB", PointLight4), + ]), + // v70+ + new("ManorStartRoomSmall", [ + new("ManorStartRoomMesh/Chandelier/PoweredLightTypeB (1)", PointLight4), + new("ManorStartRoomMesh/Chandelier2/PoweredLightTypeB", PointLight4), + ]), + new("BirthdayRoomTile", [ + new("Lights/MineshaftSpotlight", MineshaftSpotlight), + ]), + new("BathroomTileContainer", [ + new("MineshaftSpotlight", MineshaftSpotlight), + new("LightbulbLine/lightbulbsLineMesh", LightbulbsLine), + ]), + new(["BedroomTile", "BedroomTileB"], [ + new("CeilingFanAnimContainer", CeilingFan), + new("MineshaftSpotlight (1)", MineshaftSpotlight), + ]), + ]; + + Patches = descriptors + .SelectMany(d => d.Load(assetBundle)) + .ToDictionary(d => d.TileCloneName, d => d); + } + + public static void Patch(Tile tile) + { + if (tile == null) + { + throw new ArgumentNullException(nameof(tile)); + } + + if (Patches.TryGetValue(tile.gameObject.name, out var tilePatch)) + { + foreach (var patch in tilePatch.Patches) + { + Transform animationContainerTransform = tile.gameObject.transform.Find(patch.AnimatorContainerPath); + if (animationContainerTransform == null) + { +#if DEBUG + throw new NullReferenceException($"{tilePatch.TileName}/{patch.AnimatorContainerPath} Animation Container not found"); +#endif +#pragma warning disable CS0162 // Unreachable code detected + continue; +#pragma warning restore CS0162 // Unreachable code detected + } + + var animator = animationContainerTransform.gameObject.GetComponent(); + if (animator == null) + { +#if DEBUG + throw new NullReferenceException($"{tilePatch.TileName}/{patch.AnimatorContainerPath} Animation Component not found"); +#endif +#pragma warning disable CS0162 // Unreachable code detected + continue; +#pragma warning restore CS0162 // Unreachable code detected + } + + animator.runtimeAnimatorController = patch.AnimatorController; + Debug.Log($"{nameof(MuzikaGromche)} {nameof(PoweredLightsAnimatorsPatch)} {tilePatch.TileName}/{patch.AnimatorContainerPath}: Replaced animator controller"); + } + } + } + } + + [HarmonyPatch(typeof(Tile))] + internal class PoweredLightsAnimatorsPatch + { + [HarmonyPatch("AddTriggerVolume")] + [HarmonyPostfix] + public static void OnAddTriggerVolume(Tile __instance) + { + PoweredLightsAnimators.Patch(__instance); + } + } +} diff --git a/MuzikaGromche/UnityAssets/muzikagromche_poweredlightsanimators b/MuzikaGromche/UnityAssets/muzikagromche_poweredlightsanimators new file mode 100644 index 0000000..c425ab2 Binary files /dev/null and b/MuzikaGromche/UnityAssets/muzikagromche_poweredlightsanimators differ