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