1
0
Fork 0

Fix/add light flickering with animator controllers

This commit is contained in:
ivan tkachenko 2025-08-01 02:54:47 +03:00
parent 3a2eaad493
commit 9062f386de
5 changed files with 147 additions and 0 deletions

View File

@ -8,6 +8,7 @@
- Fixed visual glitch at the last beat of a loop. - Fixed visual glitch at the last beat of a loop.
- Fixed timings of one of the tracks. - Fixed timings of one of the tracks.
- Removed unnecessary "Enable Color Animations" config option. - Removed unnecessary "Enable Color Animations" config option.
- Fixed missing flickering behaviours for some animators controllers.
## MuzikaGromche 13.37.911 - Sri Lanka Bus hotfix ## MuzikaGromche 13.37.911 - Sri Lanka Bus hotfix

View File

@ -55,6 +55,7 @@
<PackagedResources Include="$(SolutionDir)icon.png" /> <PackagedResources Include="$(SolutionDir)icon.png" />
<PackagedResources Include="$(SolutionDir)manifest.json" /> <PackagedResources Include="$(SolutionDir)manifest.json" />
<PackagedResources Include="$(ProjectDir)UnityAssets\muzikagromche_discoball" /> <PackagedResources Include="$(ProjectDir)UnityAssets\muzikagromche_discoball" />
<PackagedResources Include="$(ProjectDir)UnityAssets\muzikagromche_poweredlightsanimators" />
<PackagedResources Include="$(TargetDir)MuzikaGromche.dll" /> <PackagedResources Include="$(TargetDir)MuzikaGromche.dll" />
</ItemGroup> </ItemGroup>

View File

@ -536,9 +536,11 @@ namespace MuzikaGromche
} }
Config = new Config(base.Config); Config = new Config(base.Config);
DiscoBallManager.Initialize(); DiscoBallManager.Initialize();
PoweredLightsAnimators.Load();
var harmony = new Harmony(PluginInfo.PLUGIN_NAME); var harmony = new Harmony(PluginInfo.PLUGIN_NAME);
harmony.PatchAll(typeof(JesterPatch)); harmony.PatchAll(typeof(JesterPatch));
harmony.PatchAll(typeof(EnemyAIPatch)); harmony.PatchAll(typeof(EnemyAIPatch));
harmony.PatchAll(typeof(PoweredLightsAnimatorsPatch));
} }
else else
{ {

View File

@ -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<RuntimeAnimatorController>(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<string, TilePatch> Patches = new Dictionary<string, TilePatch>();
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<Animator>();
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);
}
}
}