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