Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5f9eba9
Add INotifyValueChanged interface and events args for wrapper objects
Banane9 Jan 25, 2025
5a53d06
Add initial objects for MonkeySync system
Banane9 Jan 25, 2025
98e056f
Make use of NotifyValueChanged as base for ConfigKeyChanged
Banane9 Jan 25, 2025
a9c2db1
Finish implementation of MonkeySyncValue
Banane9 Jan 25, 2025
03775f2
Finish pre-release version of MonkeySync feature
Banane9 Jan 25, 2025
d4f9ee0
Tweak MonkeySync base
Banane9 Jan 26, 2025
f8e8212
Add more features to MonkeySyncObject
Banane9 Jan 28, 2025
42a0d2a
Add MonkeySyncObjectRegistry
Banane9 Jan 28, 2025
8e6e5cd
Add linked SyncObject instance registration to SyncObjectRegistry
Banane9 Jan 30, 2025
7aa2361
Tweak registry behavior and make MonkeySyncValue.Value virtual
Banane9 Feb 2, 2025
abbe1c8
Restructure how SyncValues work
Banane9 Feb 2, 2025
3a8949c
Tweak MonkeySyncValue link establishing
Banane9 Feb 2, 2025
610e2d0
Fix missing MonkeySyncMethodAttribute check
Banane9 Feb 2, 2025
61aa203
Adjust link establishment
Banane9 Feb 6, 2025
83567b2
Add link restoring method to SyncValue and automatically dispose them…
Banane9 Feb 13, 2025
e9aca64
Tweak sync method system
Banane9 Mar 7, 2025
5f13612
Move SyncObject registration
Banane9 Mar 7, 2025
f00fe3e
Make MonkeySync methods tied to a value and support fields + properties
Banane9 Mar 8, 2025
8d831b1
Add SyncObject type parameter to sync values
Banane9 Mar 8, 2025
d2850a3
More generics make everything better... right?
Banane9 Mar 8, 2025
390e365
Tweak generic signature of SyncObject
Banane9 Mar 9, 2025
c7e7ce9
Fix typeparam docs
Banane9 Mar 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 4 additions & 84 deletions MonkeyLoader/Configuration/ConfigKeyChangedEvent.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Collections.Specialized;
using System.ComponentModel;
using System;
using System.Diagnostics.CodeAnalysis;
using MonkeyLoader.Meta;

namespace MonkeyLoader.Configuration
{
Expand All @@ -24,14 +24,8 @@ namespace MonkeyLoader.Configuration
/// Represents the data for the <see cref="Config.ItemChanged"/> and <see cref="MonkeyLoader.AnyConfigChanged"/> events.
/// </summary>
/// <typeparam name="T">The type of the key's value.</typeparam>
public sealed class ConfigKeyChangedEventArgs<T> : IConfigKeyChangedEventArgs
public sealed class ConfigKeyChangedEventArgs<T> : ValueChangedEventArgs<T>, IConfigKeyChangedEventArgs
{
/// <inheritdoc/>
public NotifyCollectionChangedEventArgs? ChangedCollection { get; }

/// <inheritdoc/>
public string? ChangedProperty { get; }

/// <inheritdoc/>
public Config Config { get; }

Expand All @@ -45,14 +39,6 @@ public sealed class ConfigKeyChangedEventArgs<T> : IConfigKeyChangedEventArgs
/// <inheritdoc/>
public bool HasValue { get; }

/// <inheritdoc/>
[MemberNotNullWhen(true, nameof(ChangedCollection))]
public bool IsChangedCollection => ChangedCollection is not null;

/// <inheritdoc/>
[MemberNotNullWhen(true, nameof(ChangedProperty))]
public bool IsChangedProperty => ChangedProperty is not null;

/// <summary>
/// Gets the configuration item who's value changed.
/// </summary>
Expand All @@ -63,22 +49,6 @@ public sealed class ConfigKeyChangedEventArgs<T> : IConfigKeyChangedEventArgs
/// <inheritdoc/>
public string? Label { get; }

/// <summary>
/// Gets the new value of the <see cref="DefiningConfigKey{T}"/>.<br/>
/// This can be the default value.
/// </summary>
public T? NewValue { get; }

object? IConfigKeyChangedEventArgs.NewValue => NewValue;

/// <summary>
/// Gets the old value of the <see cref="DefiningConfigKey{T}"/>.<br/>
/// This can be the default value.
/// </summary>
public T? OldValue { get; }

object? IConfigKeyChangedEventArgs.OldValue => OldValue;

/// <summary>
/// Creates a new event args instance for a changed config item.
/// </summary>
Expand All @@ -94,41 +64,23 @@ public sealed class ConfigKeyChangedEventArgs<T> : IConfigKeyChangedEventArgs
public ConfigKeyChangedEventArgs(Config config, IDefiningConfigKey<T> key,
bool hadValue, T? oldValue, bool hasValue, T? newValue, string? label,
string? changedProperty, NotifyCollectionChangedEventArgs? changedCollection)
: base(oldValue, newValue, changedProperty, changedCollection)
{
Config = config;
Key = key;

OldValue = oldValue;
HadValue = hadValue;
NewValue = newValue;
HasValue = hasValue;

Label = label;

ChangedProperty = changedProperty;
ChangedCollection = changedCollection;
}
}

/// <summary>
/// Represents a non-generic <see cref="ConfigKeyChangedEventArgs{T}"/>.
/// </summary>
public interface IConfigKeyChangedEventArgs
public interface IConfigKeyChangedEventArgs : IValueChangedEventArgs
{
/// <summary>
/// Gets the changed collection event arguments,
/// if this configuration item's changed value originated
/// from an <see cref="INotifyCollectionChanged.CollectionChanged"/> event.
/// </summary>
public NotifyCollectionChangedEventArgs? ChangedCollection { get; }

/// <summary>
/// Gets the name of the property that changed,
/// if this configuration item's changed value originated
/// from an <see cref="INotifyPropertyChanged.PropertyChanged"/> event.
/// </summary>
public string? ChangedProperty { get; }

/// <summary>
/// Gets the <see cref="Configuration.Config"/> in which the change occured.
/// </summary>
Expand All @@ -153,26 +105,6 @@ public interface IConfigKeyChangedEventArgs
/// </summary>
public bool HasValue { get; }

/// <summary>
/// Gets whether this configuration item's changed value originated
/// from an <see cref="INotifyCollectionChanged.CollectionChanged"/> event.
/// </summary>
/// <value>
/// <c>true</c> if <see cref="ChangedCollection">ChangedCollection</see> is not <c>null</c>; otherwise, <c>false</c>.
/// </value>
[MemberNotNullWhen(true, nameof(ChangedCollection))]
public bool IsChangedCollection { get; }

/// <summary>
/// Gets whether this configuration item's changed value originated
/// from an <see cref="INotifyPropertyChanged.PropertyChanged"/> event.
/// </summary>
/// <value>
/// <c>true</c> if <see cref="ChangedProperty">ChangedProperty</see> is not <c>null</c>; otherwise, <c>false</c>.
/// </value>
[MemberNotNullWhen(true, nameof(ChangedProperty))]
public bool IsChangedProperty { get; }

/// <summary>
/// Gets the configuration item who's value changed.
/// </summary>
Expand All @@ -182,17 +114,5 @@ public interface IConfigKeyChangedEventArgs
/// Gets a custom label that may be set by whoever changed the configuration.
/// </summary>
public string? Label { get; }

/// <summary>
/// Gets the new value of the configuration item.<br/>
/// This can be the default value.
/// </summary>
public object? NewValue { get; }

/// <summary>
/// Gets the old value of the configuration item.<br/>
/// This can be the default value.
/// </summary>
public object? OldValue { get; }
}
}
81 changes: 61 additions & 20 deletions MonkeyLoader/Configuration/DefiningConfigKey.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,16 @@ namespace MonkeyLoader.Configuration
/// <typeparam name="T">The type of the config item's value.</typeparam>
public sealed class DefiningConfigKey<T> : Entity<DefiningConfigKey<T>>, IDefiningConfigKey<T>
{
private readonly bool _canAlwaysHaveChanges;
private static readonly Type _valueType = typeof(T);

private readonly bool _canAlwaysHaveChanges;
private readonly Lazy<string> _fullId;
private ConfigSection? _configSection;
private bool _hasChanges;
private ConfigKeyChangedEventHandler? _untypedChanged;
private ValueChangedEventHandler? _untypedValueChanged;
private T? _value;
private ValueChangedEventHandler<T>? _valueChanged;

/// <inheritdoc/>
public IConfigKey AsUntyped { get; }
Expand Down Expand Up @@ -117,7 +120,7 @@ public ConfigSection Section
IDefiningConfigKey<T> IEntity<IDefiningConfigKey<T>>.Self => this;

/// <inheritdoc/>
public Type ValueType { get; } = typeof(T);
public Type ValueType => _valueType;

/// <summary>
/// Gets the logger of the config this item belongs to.
Expand Down Expand Up @@ -367,27 +370,34 @@ public bool Validate(T value)
/// <param name="changedCollection">The collection change arguments for the value.</param>
private void OnChanged(bool hadValue, T? oldValue, string? eventLabel, string? changedProperty = null, NotifyCollectionChangedEventArgs? changedCollection = null)
{
// Add notify changed integration
if (hadValue)
var sameReferences = ReferenceEquals(oldValue, _value);

if (!sameReferences)
{
if (oldValue is INotifyPropertyChanged oldPropertyChanged)
oldPropertyChanged.PropertyChanged -= ValuePropertyChanged;
// Remove NotifyChanged integration from old value
if (hadValue)
{
if (oldValue is INotifyPropertyChanged oldPropertyChanged)
oldPropertyChanged.PropertyChanged -= ValuePropertyChanged;

if (oldValue is INotifyCollectionChanged oldCollectionChanged)
oldCollectionChanged.CollectionChanged -= ValueCollectionChanged;
}
if (oldValue is INotifyCollectionChanged oldCollectionChanged)
oldCollectionChanged.CollectionChanged -= ValueCollectionChanged;
}

if (HasValue)
{
if (_value is INotifyPropertyChanged newPropertyChanged)
newPropertyChanged.PropertyChanged += ValuePropertyChanged;
// Add NotifyChanged integration to new value
if (HasValue)
{
if (_value is INotifyPropertyChanged newPropertyChanged)
newPropertyChanged.PropertyChanged += ValuePropertyChanged;

if (_value is INotifyCollectionChanged newCollectionChanged)
newCollectionChanged.CollectionChanged += ValueCollectionChanged;
if (_value is INotifyCollectionChanged newCollectionChanged)
newCollectionChanged.CollectionChanged += ValueCollectionChanged;
}
}

// Don't fire event if value didn't change
if (ReferenceEquals(oldValue, _value) || (oldValue is not null && _value is not null && _value.Equals(oldValue)))
// Don't fire event if it wasn't triggered by event and the value didn't change
if ((sameReferences && changedProperty is null && changedCollection is null)
|| (oldValue is not null && _value is not null && _value.Equals(oldValue)))
return;

HasChanges = true;
Expand All @@ -411,6 +421,24 @@ private void OnChanged(bool hadValue, T? oldValue, string? eventLabel, string? c
Logger.Error(ex.LogFormat($"Some untyped {nameof(Changed)} event subscriber(s) of key [{Id}] threw an exception:"));
}

try
{
_valueChanged?.TryInvokeAll(this, eventArgs);
}
catch (AggregateException ex)
{
Logger.Error(ex.LogFormat($"Some typed {nameof(INotifyValueChanged)}<T>.{nameof(Changed)} event subscriber(s) of key [{Id}] threw an exception:"));
}

try
{
_untypedValueChanged?.TryInvokeAll(this, eventArgs);
}
catch (AggregateException ex)
{
Logger.Error(ex.LogFormat($"Some untyped {nameof(INotifyValueChanged)}<T>.{nameof(Changed)} event subscriber(s) of key [{Id}] threw an exception:"));
}

Section.OnItemChanged(eventArgs);
}

Expand All @@ -431,13 +459,25 @@ event ConfigKeyChangedEventHandler? IDefiningConfigKey.Changed
add => _untypedChanged += value;
remove => _untypedChanged -= value;
}

event ValueChangedEventHandler? INotifyValueChanged.Changed
{
add => _untypedValueChanged += value;
remove => _untypedValueChanged -= value;
}

event ValueChangedEventHandler<T>? INotifyValueChanged<T>.Changed
{
add => _valueChanged += value;
remove => _valueChanged -= value;
}
}

/// <summary>
/// Defines the definition for a config item.
/// </summary>
public interface IDefiningConfigKey : ITypedConfigKey, IEntity<IDefiningConfigKey>,
INestedIdentifiable<ConfigSection>, IPrioritizable
INestedIdentifiable<ConfigSection>, IPrioritizable, INotifyValueChanged
{
/// <summary>
/// Gets the config this item belongs to.
Expand Down Expand Up @@ -541,14 +581,15 @@ public interface IDefiningConfigKey : ITypedConfigKey, IEntity<IDefiningConfigKe
/// <summary>
/// Triggered when the internal value of this config item changes.
/// </summary>
public event ConfigKeyChangedEventHandler? Changed;
public new event ConfigKeyChangedEventHandler? Changed;
}

/// <summary>
/// Defines the typed definition for a config item.
/// </summary>
/// <typeparam name="T">The type of the config item's value.</typeparam>
public interface IDefiningConfigKey<T> : IDefiningConfigKey, ITypedConfigKey<T>, IEntity<IDefiningConfigKey<T>>
public interface IDefiningConfigKey<T> : IDefiningConfigKey, ITypedConfigKey<T>,
IEntity<IDefiningConfigKey<T>>, INotifyValueChanged<T>
{
/// <summary>
/// Gets this config item's set value, falling back to the <see cref="TryComputeDefault">computed default</see>.
Expand Down
Loading