forked from nikita/muzika-gromche
144 lines
6.0 KiB
C#
144 lines
6.0 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|