Files
BepInEx/Projects/TerraTech/TerraTech/ModuleShieldGeneratorManager.cs

134 lines
5.3 KiB
C#

using System;
using System.Collections.Generic;
using BepInEx.Configuration;
using HarmonyLib;
namespace TerraTech {
public class MultipliedField<TObject, TValue> {
private readonly string fieldName;
private readonly ConfigEntry<TValue> multiplier;
private readonly Traverse parentTraverse;
private TValue originalValue;
public MultipliedField(string fieldName, ConfigEntry<TValue> multiplier, Traverse parentTraverse) {
this.fieldName = fieldName;
this.multiplier = multiplier;
this.parentTraverse = parentTraverse;
}
public TValue GetValue() => (TValue)parentTraverse.Field(fieldName).GetValue();
public void SetValue(TValue value) => parentTraverse.Field(fieldName).SetValue(value);
public void CaptureOriginal() => originalValue = GetValue();
public void Restore() => SetValue(originalValue);
public void Apply() {
dynamic originalDynamic = originalValue;
dynamic multiplierDynamic = multiplier.Value;
SetValue((TValue)(originalDynamic * multiplierDynamic));
}
public void LogValue(string prefix) {
if (!Main.debug.Value)
return;
Console.WriteLine("{0} {1}; {2}: {3}", prefix, parentTraverse.ToString(), fieldName, GetValue());
}
}
public class MultipliedObject<T> {
private readonly Traverse objectTraverse;
private readonly List<MultipliedField<T, float>> fields = new List<MultipliedField<T, float>>();
public MultipliedObject(T instance) => objectTraverse = Traverse.Create(instance);
public void AddField(string fieldName, ConfigEntry<float> multiplier) =>
fields.Add(new MultipliedField<T, float>(fieldName, multiplier, objectTraverse));
public void CaptureFrom() => fields.ForEach(f => f.CaptureOriginal());
public void ApplyTo() => fields.ForEach(f => f.Apply());
public void RestoreTo() => fields.ForEach(f => f.Restore());
public void LogValues(string prefix) {
if (!Main.debug.Value)
return;
fields.ForEach(f => f.LogValue(prefix));
}
}
public class MultipliedObjectManager<T>
where T : class {
private readonly Dictionary<T, MultipliedObject<T>> managedObjects = new Dictionary<T, MultipliedObject<T>>();
private readonly Action<MultipliedObject<T>> configureObject;
public MultipliedObjectManager(Action<MultipliedObject<T>> configureObject) {
this.configureObject = configureObject;
}
public void OnObjectAttached(T instance) {
if (!managedObjects.ContainsKey(instance)) {
if (Main.debug.Value)
Console.WriteLine($"{typeof(T).Name}.OnAttached");
var multipliedObject = new MultipliedObject<T>(instance);
configureObject(multipliedObject);
multipliedObject.CaptureFrom();
managedObjects.Add(instance, multipliedObject);
multipliedObject.LogValues("Patching");
ApplyTo(instance);
multipliedObject.LogValues("Patched");
}
}
public void OnObjectDetached(T instance) {
if (managedObjects.TryGetValue(instance, out var multipliedObject)) {
if (Main.debug.Value) {
Console.WriteLine($"{typeof(T).Name}.OnDetaching");
multipliedObject.LogValues("Restoring");
}
RestoreTo(instance);
multipliedObject.LogValues("Restored");
managedObjects.Remove(instance);
}
}
public void ApplyAll() {
if (Main.debug.Value)
Console.WriteLine($"Modifying {managedObjects.Count} {typeof(T).Name}");
foreach (var instance in managedObjects.Keys) {
RestoreTo(instance);
ApplyTo(instance);
}
}
private void ApplyTo(T instance) {
if (managedObjects.TryGetValue(instance, out var obj))
obj.ApplyTo();
}
private void RestoreTo(T instance) {
if (managedObjects.TryGetValue(instance, out var obj))
obj.RestoreTo();
}
}
[HarmonyPatch]
public class ModuleShieldGeneratorManager {
private static readonly MultipliedObjectManager<ModuleShieldGenerator> manager =
new MultipliedObjectManager<ModuleShieldGenerator>(ConfigureShieldGenerator);
private static void ConfigureShieldGenerator(MultipliedObject<ModuleShieldGenerator> obj) {
obj.AddField("m_HealingHeartbeatInterval", Main.shieldHeartbeatIntervalMultiplier);
obj.AddField("m_Radius", Main.shieldRadiusMultiplier);
obj.AddField("m_PowerUpDelay", Main.powerUpDelayMultiplier);
}
[HarmonyPrefix]
[HarmonyPatch(typeof(ModuleShieldGenerator), "OnAttached")]
static void PostfixCreate(ModuleShieldGenerator __instance) => manager.OnObjectAttached(__instance);
[HarmonyPrefix]
[HarmonyPatch(typeof(ModuleShieldGenerator), "OnDetaching")]
static void PostfixDestroy(ModuleShieldGenerator __instance) => manager.OnObjectDetached(__instance);
public static void DoPatch() => manager.ApplyAll();
}
}