Extract generic object field multiplier logic to separate file

This commit is contained in:
2025-02-24 00:13:43 +01:00
parent 741ab21977
commit 89a557dc96
4 changed files with 169 additions and 137 deletions

View File

@@ -1,4 +1,6 @@
using HarmonyLib;
using System;
using System.Collections.Generic;
using HarmonyLib;
namespace TerraTech {
[HarmonyPatch]

View File

@@ -4,142 +4,6 @@ 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;
if (!parentTraverse.Field(fieldName).FieldExists()) {
throw new ArgumentException($"Field {fieldName} does not exist on {parentTraverse.ToString()}");
}
}
public TValue GetValue() {
var value = parentTraverse.Field(fieldName).GetValue();
if (value == null)
throw new InvalidOperationException($"Field {fieldName} returned null");
return (TValue)value;
}
public void SetValue(TValue value) {
if (value == null)
throw new ArgumentNullException(nameof(value));
parentTraverse.Field(fieldName).SetValue(value);
var verifyValue = GetValue();
if (!verifyValue.Equals(value))
throw new InvalidOperationException($"Field {fieldName} set to {value} but read back as {verifyValue}");
}
public void CaptureOriginal() {
originalValue = GetValue();
if (Main.debug.Value)
Console.WriteLine($"Captured original value for {fieldName}: {originalValue}");
}
public void Apply() {
try {
dynamic originalDynamic = originalValue;
dynamic multiplierDynamic = multiplier.Value;
var newValue = (TValue)(originalDynamic * multiplierDynamic);
if (Main.debug.Value)
Console.WriteLine($"Applying to {fieldName}: {originalValue} * {multiplier.Value} = {newValue}");
SetValue(newValue);
} catch (Exception e) {
throw new InvalidOperationException($"Failed to apply multiplication to {fieldName}", e);
}
}
public void Restore() {
if (Main.debug.Value)
Console.WriteLine($"Restoring {fieldName} to original value: {originalValue}");
SetValue(originalValue);
}
public void LogValue(string prefix) {
if (!Main.debug.Value)
return;
var currentValue = GetValue();
Console.WriteLine(
$"{prefix} {parentTraverse}; {fieldName}: {currentValue} (original: {originalValue}, multiplier: {multiplier.Value})");
}
}
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 =

View File

@@ -0,0 +1,165 @@
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;
if (!parentTraverse.Field(fieldName).FieldExists()) {
throw new ArgumentException(
string.Format("Field {0} does not exist on {1}", fieldName, parentTraverse.ToString()));
}
}
public TValue GetValue() {
var value = parentTraverse.Field(fieldName).GetValue();
if (value == null)
throw new InvalidOperationException(string.Format("Field {0} returned null", fieldName));
return (TValue)value;
}
public void SetValue(TValue value) {
parentTraverse.Field(fieldName).SetValue(value);
var verifyValue = GetValue();
if (!verifyValue.Equals(value))
throw new InvalidOperationException(
string.Format("Field {0} set to {1} but read back as {2}", fieldName, value, verifyValue));
}
public void CaptureOriginal() {
originalValue = GetValue();
if (Main.debug.Value)
Console.WriteLine(string.Format("Captured original value for {0}: {1}", fieldName, originalValue));
}
public void Apply() {
try {
dynamic originalDynamic = originalValue;
dynamic multiplierDynamic = multiplier.Value;
var newValue = (TValue)(originalDynamic * multiplierDynamic);
if (Main.debug.Value)
Console.WriteLine(string.Format("Applying to {0}: {1} * {2} = {3}", fieldName, originalValue,
multiplier.Value, newValue));
SetValue(newValue);
} catch (Exception e) {
throw new InvalidOperationException(string.Format("Failed to apply multiplication to {0}", fieldName),
e);
}
}
public void Restore() {
if (Main.debug.Value)
Console.WriteLine(string.Format("Restoring {0} to original value: {1}", fieldName, originalValue));
SetValue(originalValue);
}
public void LogValue(string prefix) {
if (!Main.debug.Value)
return;
var currentValue = GetValue();
Console.WriteLine(
$"{prefix} {parentTraverse}; {fieldName}: {currentValue} (original: {originalValue}, multiplier: {multiplier.Value})");
}
}
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(string.Format("{0}.OnAttached", typeof(T).Name));
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()
}
}
}

View File

@@ -48,6 +48,7 @@
<Compile Include="ModuleEnergy.cs" />
<Compile Include="ModuleEnergyStoreManager.cs" />
<Compile Include="ModuleShieldGeneratorManager.cs" />
<Compile Include="ObjectFieldMultiplier.cs" />
<Compile Include="Patches.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SeekingProjectileManager.cs" />