Make both the multiplier and field generic

This commit is contained in:
2025-02-24 09:57:36 +01:00
parent 95fdbc7cda
commit 11c7d74489

View File

@@ -5,43 +5,51 @@ using BepInEx.Configuration;
using HarmonyLib; using HarmonyLib;
namespace TerraTech { namespace TerraTech {
public interface IMultipliedField {
void CaptureOriginal();
void Apply();
void Restore();
void LogValue(string prefix);
}
/// <summary> /// <summary>
/// Represents a field that can be multiplied by a configurable value /// Represents a field that can be multiplied by a configurable value
/// </summary> /// </summary>
/// <typeparam name="TValue">The type of the field value</typeparam> /// <typeparam name="TField">The type of the field value</typeparam>
public class FieldConfiguration<TValue> { /// <typeparam name="TMul">The type of the multiplier</typeparam>
public class FieldConfiguration<TField, TMul> {
private string _fieldName; private string _fieldName;
private ConfigEntry<TValue> _defaultMultiplier; private ConfigEntry<TMul> _defaultMultiplier;
private Func<object, ConfigEntry<TValue>> _conditionalMultiplier; private Func<object, ConfigEntry<TMul>> _conditionalMultiplier;
public string FieldName { public string FieldName {
get { return _fieldName; } get { return _fieldName; }
set { _fieldName = value; } set { _fieldName = value; }
} }
public ConfigEntry<TValue> DefaultMultiplier { public ConfigEntry<TMul> DefaultMultiplier {
get { return _defaultMultiplier; } get { return _defaultMultiplier; }
set { _defaultMultiplier = value; } set { _defaultMultiplier = value; }
} }
public Func<object, ConfigEntry<TValue>> ConditionalMultiplier { public Func<object, ConfigEntry<TMul>> ConditionalMultiplier {
get { return _conditionalMultiplier; } get { return _conditionalMultiplier; }
set { _conditionalMultiplier = value; } set { _conditionalMultiplier = value; }
} }
public FieldConfiguration(string fieldName, ConfigEntry<TValue> defaultMultiplier) { public FieldConfiguration(string fieldName, ConfigEntry<TMul> defaultMultiplier) {
_fieldName = fieldName; _fieldName = fieldName;
_defaultMultiplier = defaultMultiplier; _defaultMultiplier = defaultMultiplier;
} }
public FieldConfiguration(string fieldName, ConfigEntry<TValue> defaultMultiplier, public FieldConfiguration(string fieldName, ConfigEntry<TMul> defaultMultiplier,
Func<object, ConfigEntry<TValue>> conditionalMultiplier) { Func<object, ConfigEntry<TMul>> conditionalMultiplier) {
_fieldName = fieldName; _fieldName = fieldName;
_defaultMultiplier = defaultMultiplier; _defaultMultiplier = defaultMultiplier;
_conditionalMultiplier = conditionalMultiplier; _conditionalMultiplier = conditionalMultiplier;
} }
public ConfigEntry<TValue> GetMultiplier(object instance) { public ConfigEntry<TMul> GetMultiplier(object instance) {
if (_conditionalMultiplier == null) { if (_conditionalMultiplier == null) {
return _defaultMultiplier; return _defaultMultiplier;
} }
@@ -49,17 +57,17 @@ namespace TerraTech {
} }
} }
public class MultipliedField<TValue> { public class MultipliedField<TField, TMul> : IMultipliedField {
private readonly string _fieldName; private readonly string _fieldName;
private readonly ConfigEntry<TValue> _multiplier; private readonly ConfigEntry<TMul> _multiplier;
private readonly Traverse _parentTraverse; private readonly Traverse _parentTraverse;
private TValue _originalValue; private TField _originalValue;
public string FieldName { public string FieldName {
get { return _fieldName; } get { return _fieldName; }
} }
public MultipliedField(string fieldName, ConfigEntry<TValue> multiplier, Traverse parentTraverse) { public MultipliedField(string fieldName, ConfigEntry<TMul> multiplier, Traverse parentTraverse) {
_fieldName = fieldName; _fieldName = fieldName;
_multiplier = multiplier; _multiplier = multiplier;
_parentTraverse = parentTraverse; _parentTraverse = parentTraverse;
@@ -69,9 +77,16 @@ namespace TerraTech {
string.Format("Field {0} does not exist on {1}", fieldName, parentTraverse)); string.Format("Field {0} does not exist on {1}", fieldName, parentTraverse));
} }
// Verify TValue is a numeric type // Verify TField is a numeric type
if (!IsNumericType(typeof(TValue))) { if (!IsNumericType(typeof(TField))) {
throw new ArgumentException(string.Format("Type {0} must be a numeric type", typeof(TValue).Name)); throw new ArgumentException(
string.Format("Field type {0} must be a numeric type", typeof(TField).Name));
}
// Verify TMul is a numeric type
if (!IsNumericType(typeof(TMul))) {
throw new ArgumentException(
string.Format("Multiplier type {0} must be a numeric type", typeof(TMul).Name));
} }
} }
@@ -81,21 +96,23 @@ namespace TerraTech {
type == typeof(float) || type == typeof(double) || type == typeof(decimal); type == typeof(float) || type == typeof(double) || type == typeof(decimal);
} }
private static TValue MultiplyValues(TValue a, TValue b) { private TField MultiplyValues(TField fieldValue, TMul multiplierValue) {
// Convert to double for the multiplication // Convert both to double for the multiplication
double result = Convert.ToDouble(a) * Convert.ToDouble(b); double fieldDouble = Convert.ToDouble(fieldValue);
// Convert back to TValue double multiplierDouble = Convert.ToDouble(multiplierValue);
return (TValue)Convert.ChangeType(result, typeof(TValue)); double result = fieldDouble * multiplierDouble;
// Convert back to TField
return (TField)Convert.ChangeType(result, typeof(TField));
} }
public TValue GetValue() { public TField GetValue() {
var value = _parentTraverse.Field(_fieldName).GetValue(); var value = _parentTraverse.Field(_fieldName).GetValue();
if (value == null) if (value == null)
throw new InvalidOperationException(string.Format("Field {0} returned null", _fieldName)); throw new InvalidOperationException(string.Format("Field {0} returned null", _fieldName));
return (TValue)value; return (TField)value;
} }
public void SetValue(TValue value) { public void SetValue(TField value) {
_parentTraverse.Field(_fieldName).SetValue(value); _parentTraverse.Field(_fieldName).SetValue(value);
var verifyValue = GetValue(); var verifyValue = GetValue();
if (!verifyValue.Equals(value)) if (!verifyValue.Equals(value))
@@ -146,17 +163,18 @@ namespace TerraTech {
public class MultipliedObject<T> { public class MultipliedObject<T> {
private readonly T _instance; private readonly T _instance;
private readonly Traverse _objectTraverse; private readonly Traverse _objectTraverse;
private readonly Dictionary<string, MultipliedField<float>> _fields; private readonly Dictionary<string, IMultipliedField> _fields;
public MultipliedObject(T instance) { public MultipliedObject(T instance) {
_instance = instance; _instance = instance;
_objectTraverse = Traverse.Create(instance); _objectTraverse = Traverse.Create(instance);
_fields = new Dictionary<string, MultipliedField<float>>(); _fields = new Dictionary<string, IMultipliedField>();
} }
public void AddField(FieldConfiguration<float> config) { public void AddField<TField, TMul>(FieldConfiguration<TField, TMul> config) {
var multiplier = config.GetMultiplier(_instance); var multiplier = config.GetMultiplier(_instance);
_fields[config.FieldName] = new MultipliedField<float>(config.FieldName, multiplier, _objectTraverse); _fields[config.FieldName] =
new MultipliedField<TField, TMul>(config.FieldName, multiplier, _objectTraverse);
} }
public void CaptureFrom() { public void CaptureFrom() {
@@ -166,28 +184,16 @@ namespace TerraTech {
} }
public void ApplyTo(IEnumerable<string> fieldNames = null) { public void ApplyTo(IEnumerable<string> fieldNames = null) {
IEnumerable<MultipliedField<float>> fieldsToApply; IEnumerable<string> fieldsToApply = fieldNames ?? _fields.Keys;
if (fieldNames != null) { foreach (var fieldName in fieldsToApply.Where(name => _fields.ContainsKey(name))) {
fieldsToApply = fieldNames.Where(name => _fields.ContainsKey(name)).Select(name => _fields[name]); _fields[fieldName].Apply();
} else {
fieldsToApply = _fields.Values;
}
foreach (var field in fieldsToApply) {
field.Apply();
} }
} }
public void RestoreTo(IEnumerable<string> fieldNames = null) { public void RestoreTo(IEnumerable<string> fieldNames = null) {
IEnumerable<MultipliedField<float>> fieldsToRestore; IEnumerable<string> fieldsToRestore = fieldNames ?? _fields.Keys;
if (fieldNames != null) { foreach (var fieldName in fieldsToRestore.Where(name => _fields.ContainsKey(name))) {
fieldsToRestore = fieldNames.Where(name => _fields.ContainsKey(name)).Select(name => _fields[name]); _fields[fieldName].Restore();
} else {
fieldsToRestore = _fields.Values;
}
foreach (var field in fieldsToRestore) {
field.Restore();
} }
} }
@@ -247,7 +253,8 @@ namespace TerraTech {
public void ApplyAll(IEnumerable<string> fieldNames = null) { public void ApplyAll(IEnumerable<string> fieldNames = null) {
if (Main.debug.Value) if (Main.debug.Value)
Console.WriteLine("Modifying {0} {1}", _managedObjects.Count, typeof(T).Name); Console.WriteLine("Modifying {0} {1}", _managedObjects.Count, typeof(T).Name);
foreach (var instance in _managedObjects.Keys) { foreach (var instance in _managedObjects.Keys
.ToList()) { // ToList to avoid modification during enumeration
RestoreTo(instance, fieldNames); RestoreTo(instance, fieldNames);
ApplyTo(instance, fieldNames); ApplyTo(instance, fieldNames);
} }