Skip to content

Commit 6a00004

Browse files
committed
Introduce ConfigSection wrapper to hide ML in ModConfiguration
1 parent 1e6fc90 commit 6a00004

7 files changed

Lines changed: 166 additions & 121 deletions

File tree

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace ResoniteModLoader
5+
{
6+
/// <summary>
7+
/// Represents an interface for mod configurations.
8+
/// </summary>
9+
public interface IModConfigurationDefinition
10+
{
11+
/// <summary>
12+
/// Gets the set of configuration keys defined in this configuration definition.
13+
/// </summary>
14+
ISet<ModConfigurationKey> ConfigurationItemDefinitions { get; }
15+
16+
/// <summary>
17+
/// Gets the mod that owns this configuration definition.
18+
/// </summary>
19+
ResoniteModBase Owner { get; }
20+
21+
/// <summary>
22+
/// Gets the semantic version for this configuration definition. This is used to check if the defined and saved configs are compatible.
23+
/// </summary>
24+
Version Version { get; }
25+
}
26+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using MonkeyLoader.Configuration;
2+
3+
namespace ResoniteModLoader
4+
{
5+
/// <summary>
6+
/// Defines options for the handling of incompatible configuration versions.
7+
/// </summary>
8+
public enum IncompatibleConfigurationHandlingOption
9+
{
10+
/// <summary>
11+
/// Fail to read the config, and block saving over the config on disk.
12+
/// </summary>
13+
ERROR = IncompatibleConfigHandling.Error,
14+
15+
/// <summary>
16+
/// Destroy the saved config and start over from scratch.
17+
/// </summary>
18+
CLOBBER = IncompatibleConfigHandling.Clobber,
19+
20+
/// <summary>
21+
/// Ignore the version number and attempt to load the config from disk.
22+
/// </summary>
23+
FORCELOAD = IncompatibleConfigHandling.ForceLoad,
24+
}
25+
}
Lines changed: 27 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,36 @@
11
using System;
22
using System.Collections.Generic;
3-
using System.Diagnostics;
4-
using System.IO;
5-
using System.Linq;
63
using EnumerableToolkit;
7-
using FrooxEngine;
8-
using HarmonyLib;
94
using MonkeyLoader;
10-
using MonkeyLoader.Configuration;
11-
using Newtonsoft.Json;
12-
using Newtonsoft.Json.Linq;
135

146
namespace ResoniteModLoader
157
{
168
/// <summary>
17-
/// Represents an interface for mod configurations.
18-
/// </summary>
19-
public interface IModConfigurationDefinition
20-
{
21-
/// <summary>
22-
/// Gets the set of configuration keys defined in this configuration definition.
23-
/// </summary>
24-
ISet<ModConfigurationKey> ConfigurationItemDefinitions { get; }
25-
26-
/// <summary>
27-
/// Gets the mod that owns this configuration definition.
28-
/// </summary>
29-
ResoniteModBase Owner { get; }
30-
31-
/// <summary>
32-
/// Gets the semantic version for this configuration definition. This is used to check if the defined and saved configs are compatible.
33-
/// </summary>
34-
Version Version { get; }
35-
}
36-
37-
/// <summary>
38-
/// Defines options for the handling of incompatible configuration versions.
9+
/// The configuration for a mod. Each mod has zero or one configuration. The configuration object will never be reassigned once initialized.
3910
/// </summary>
40-
public enum IncompatibleConfigurationHandlingOption
11+
public class ModConfiguration : IModConfigurationDefinition
4112
{
42-
/// <summary>
43-
/// Fail to read the config, and block saving over the config on disk.
44-
/// </summary>
45-
ERROR = IncompatibleConfigHandling.Error,
13+
internal ModConfigurationDefinition Definition { get; }
4614

4715
/// <summary>
48-
/// Destroy the saved config and start over from scratch.
16+
/// Gets the internal <see cref="MonkeyLoader.Configuration.ConfigSection"/>
17+
/// that actually handles storing the data for this.
4918
/// </summary>
50-
CLOBBER = IncompatibleConfigHandling.Clobber,
51-
52-
/// <summary>
53-
/// Ignore the version number and attempt to load the config from disk.
54-
/// </summary>
55-
FORCELOAD = IncompatibleConfigHandling.ForceLoad,
56-
}
57-
58-
/// <summary>
59-
/// The configuration for a mod. Each mod has zero or one configuration. The configuration object will never be reassigned once initialized.
60-
/// </summary>
61-
public class ModConfiguration : ConfigSection, IModConfigurationDefinition
62-
{
63-
private readonly ModConfigurationDefinition _definition;
64-
65-
/// <inheritdoc/>
66-
public ISet<ModConfigurationKey> ConfigurationItemDefinitions => _definition.ConfigurationItemDefinitions;
67-
68-
/// <inheritdoc/>
69-
public override string Description => "RML Mod Config";
19+
internal RmlModConfigSection ConfigSection { get; }
7020

7121
/// <inheritdoc/>
72-
public override string Id => "values";
22+
public Version Version => Definition.Version;
7323

7424
/// <inheritdoc/>
75-
public ResoniteModBase Owner => _definition.Owner;
25+
public ISet<ModConfigurationKey> ConfigurationItemDefinitions => Definition.ConfigurationItemDefinitions;
7626

7727
/// <inheritdoc/>
78-
public override Version Version => _definition.Version;
28+
public ResoniteModBase Owner => Definition.Owner;
7929

8030
internal ModConfiguration(ModConfigurationDefinition definition)
8131
{
82-
_definition = definition;
83-
}
84-
85-
/// <inheritdoc/>
86-
protected override IncompatibleConfigHandling HandleIncompatibleVersions(Version serializedVersion)
87-
{
88-
if (Owner is ResoniteMod resoniteMod)
89-
return (IncompatibleConfigHandling)resoniteMod.HandleIncompatibleConfigurationVersions(serializedVersion, Version);
90-
91-
return base.HandleIncompatibleVersions(serializedVersion);
32+
Definition = definition;
33+
ConfigSection = new(this);
9234
}
9335

9436
/// <summary>
@@ -97,7 +39,8 @@ protected override IncompatibleConfigHandling HandleIncompatibleVersions(Version
9739
/// <param name="key">The key to get the value for.</param>
9840
/// <returns>The value for the key.</returns>
9941
/// <exception cref="KeyNotFoundException">The given key does not exist in the configuration.</exception>
100-
public object GetValue(ModConfigurationKey key) => GetDefinedKey(key.UntypedKey).GetValue()!;
42+
public object GetValue(ModConfigurationKey key)
43+
=> ConfigSection.GetDefinedKey(key.UntypedKey).GetValue()!;
10144

10245
/// <summary>
10346
/// Get a value, throwing a <see cref="KeyNotFoundException"/> if the key is not found.
@@ -106,14 +49,16 @@ protected override IncompatibleConfigHandling HandleIncompatibleVersions(Version
10649
/// <param name="key">The key to get the value for.</param>
10750
/// <returns>The value for the key.</returns>
10851
/// <exception cref="KeyNotFoundException">The given key does not exist in the configuration.</exception>
109-
public T? GetValue<T>(ModConfigurationKey<T> key) => GetDefinedKey(key.Key).GetValue();
52+
public T? GetValue<T>(ModConfigurationKey<T> key)
53+
=> ConfigSection.GetDefinedKey(key.Key).GetValue();
11054

11155
/// <summary>
11256
/// Checks if the given key is defined in this config.
11357
/// </summary>
11458
/// <param name="key">The key to check.</param>
11559
/// <returns><c>true</c> if the key is defined.</returns>
116-
public bool IsKeyDefined(ModConfigurationKey key) => TryGetDefinedKey(key.UntypedKey, out _);
60+
public bool IsKeyDefined(ModConfigurationKey key)
61+
=> ConfigSection.TryGetDefinedKey(key.UntypedKey, out _);
11762

11863
/// <summary>
11964
/// Persist this configuration to disk.<br/>
@@ -125,7 +70,8 @@ protected override IncompatibleConfigHandling HandleIncompatibleVersions(Version
12570
/// </remarks>
12671
#pragma warning disable IDE0060 // Remove unused parameter
12772

128-
public void Save(bool saveDefaultValues = false) => Config.Save();
73+
public void Save(bool saveDefaultValues = false)
74+
=> ConfigSection.Config.Save();
12975

13076
#pragma warning restore IDE0060 // Remove unused parameter
13177

@@ -139,7 +85,7 @@ protected override IncompatibleConfigHandling HandleIncompatibleVersions(Version
13985
/// <exception cref="KeyNotFoundException">The given key does not exist in the configuration.</exception>
14086
/// <exception cref="ArgumentException">The new value is not valid for the given key.</exception>
14187
public void Set(ModConfigurationKey key, object? value, string? eventLabel = null)
142-
=> GetDefinedKey(key.UntypedKey).SetValue(value, eventLabel);
88+
=> ConfigSection.GetDefinedKey(key.UntypedKey).SetValue(value, eventLabel);
14389

14490
/// <summary>
14591
/// Sets a configuration value for the given key, throwing a <see cref="KeyNotFoundException"/> if the key is not found
@@ -152,7 +98,7 @@ public void Set(ModConfigurationKey key, object? value, string? eventLabel = nul
15298
/// <exception cref="KeyNotFoundException">The given key does not exist in the configuration.</exception>
15399
/// <exception cref="ArgumentException">The new value is not valid for the given key.</exception>
154100
public void Set<T>(ModConfigurationKey<T> key, T value, string? eventLabel = null)
155-
=> GetDefinedKey(key.Key).SetValue(value, eventLabel);
101+
=> ConfigSection.GetDefinedKey(key.Key).SetValue(value, eventLabel);
156102

157103
/// <summary>
158104
/// Tries to get a value, returning <c>default</c> if the key is not found.
@@ -162,7 +108,7 @@ public void Set<T>(ModConfigurationKey<T> key, T value, string? eventLabel = nul
162108
/// <returns><c>true</c> if the value was read successfully.</returns>
163109
public bool TryGetValue(ModConfigurationKey key, out object? value)
164110
{
165-
if (TryGetDefinedKey(key.UntypedKey, out var definingKey))
111+
if (ConfigSection.TryGetDefinedKey(key.UntypedKey, out var definingKey))
166112
{
167113
value = definingKey.GetValue();
168114
return true;
@@ -180,7 +126,7 @@ public bool TryGetValue(ModConfigurationKey key, out object? value)
180126
/// <returns><c>true</c> if the value was read successfully.</returns>
181127
public bool TryGetValue<T>(ModConfigurationKey<T> key, out T? value)
182128
{
183-
if (TryGetDefinedKey(key.Key, out var definingKey))
129+
if (ConfigSection.TryGetDefinedKey(key.Key, out var definingKey))
184130
{
185131
value = definingKey.GetValue();
186132
return true;
@@ -196,7 +142,8 @@ public bool TryGetValue<T>(ModConfigurationKey<T> key, out T? value)
196142
/// <param name="key">The key to remove the value for.</param>
197143
/// <returns><c>true</c> if a value was successfully found and removed, <c>false</c> if there was no value to remove.</returns>
198144
/// <exception cref="KeyNotFoundException">The given key does not exist in the configuration.</exception>
199-
public bool Unset(ModConfigurationKey key) => GetDefinedKey(key.UntypedKey).Unset();
145+
public bool Unset(ModConfigurationKey key)
146+
=> ConfigSection.GetDefinedKey(key.UntypedKey).Unset();
200147

201148
internal void FireConfigurationChangedEvent(ModConfigurationKey key, string? label)
202149
{
@@ -208,7 +155,7 @@ internal void FireConfigurationChangedEvent(ModConfigurationKey key, string? lab
208155
}
209156
catch (AggregateException ex)
210157
{
211-
Config.Logger.Error(() => ex.Format($"An OnAnyConfigurationChanged event subscriber threw an exception:"));
158+
ConfigSection.Config.Logger.Error(() => ex.Format($"An OnAnyConfigurationChanged event subscriber threw an exception:"));
212159
}
213160

214161
try
@@ -217,14 +164,10 @@ internal void FireConfigurationChangedEvent(ModConfigurationKey key, string? lab
217164
}
218165
catch (AggregateException ex)
219166
{
220-
Config.Logger.Error(() => ex.Format($"An OnThisConfigurationChanged event subscriber threw an exception:"));
167+
ConfigSection.Config.Logger.Error(() => ex.Format($"An OnThisConfigurationChanged event subscriber threw an exception:"));
221168
}
222169
}
223170

224-
/// <inheritdoc/>
225-
protected override IEnumerable<IDefiningConfigKey> GetConfigKeys()
226-
=> _definition.ConfigurationItemDefinitions.Select(item => item.UntypedKey);
227-
228171
/// <summary>
229172
/// Called if any config value for any mod changed.
230173
/// </summary>
@@ -241,39 +184,4 @@ protected override IEnumerable<IDefiningConfigKey> GetConfigKeys()
241184
/// </summary>
242185
public event ConfigurationChangedHandler? OnThisConfigurationChanged;
243186
}
244-
245-
/// <summary>
246-
/// Defines a mod configuration. This should be defined by a <see cref="ResoniteMod"/> using the <see cref="ResoniteMod.DefineConfiguration(ModConfigurationDefinitionBuilder)"/> method.
247-
/// </summary>
248-
public class ModConfigurationDefinition : IModConfigurationDefinition
249-
{
250-
internal readonly HashSet<ModConfigurationKey> ConfigurationItems;
251-
internal bool AutoSave;
252-
253-
/// <inheritdoc/>
254-
// clone the collection because I don't trust giving public API users shallow copies one bit
255-
public ISet<ModConfigurationKey> ConfigurationItemDefinitions
256-
=> new HashSet<ModConfigurationKey>(ConfigurationItems);
257-
258-
/// <inheritdoc/>
259-
public ResoniteModBase Owner { get; private set; }
260-
261-
/// <inheritdoc/>
262-
public Version Version { get; private set; }
263-
264-
/// <summary>
265-
/// Creates a new <see cref="ModConfiguration"/> definition.
266-
/// </summary>
267-
/// <param name="owner">The mod owning the config.</param>
268-
/// <param name="configVersion">The version of the config.</param>
269-
/// <param name="keys">The config keys for the config.</param>
270-
/// <param name="autoSaveConfig">Whether to automatically save the config.</param>
271-
public ModConfigurationDefinition(ResoniteModBase owner, Version configVersion, HashSet<ModConfigurationKey> keys, bool autoSaveConfig)
272-
{
273-
Owner = owner;
274-
Version = configVersion;
275-
ConfigurationItems = [.. keys];
276-
AutoSave = autoSaveConfig;
277-
}
278-
}
279187
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace ResoniteModLoader
5+
{
6+
/// <summary>
7+
/// Defines a mod configuration. This should be defined by a <see cref="ResoniteMod"/> using the <see cref="ResoniteMod.DefineConfiguration(ModConfigurationDefinitionBuilder)"/> method.
8+
/// </summary>
9+
public class ModConfigurationDefinition : IModConfigurationDefinition
10+
{
11+
internal readonly HashSet<ModConfigurationKey> ConfigurationItems;
12+
internal bool AutoSave;
13+
14+
/// <inheritdoc/>
15+
// clone the collection because I don't trust giving public API users shallow copies one bit
16+
public ISet<ModConfigurationKey> ConfigurationItemDefinitions
17+
=> new HashSet<ModConfigurationKey>(ConfigurationItems);
18+
19+
/// <inheritdoc/>
20+
public ResoniteModBase Owner { get; private set; }
21+
22+
/// <inheritdoc/>
23+
public Version Version { get; private set; }
24+
25+
/// <summary>
26+
/// Creates a new <see cref="ModConfiguration"/> definition.
27+
/// </summary>
28+
/// <param name="owner">The mod owning the config.</param>
29+
/// <param name="configVersion">The version of the config.</param>
30+
/// <param name="keys">The config keys for the config.</param>
31+
/// <param name="autoSaveConfig">Whether to automatically save the config.</param>
32+
public ModConfigurationDefinition(ResoniteModBase owner, Version configVersion, HashSet<ModConfigurationKey> keys, bool autoSaveConfig)
33+
{
34+
Owner = owner;
35+
Version = configVersion;
36+
ConfigurationItems = [.. keys];
37+
AutoSave = autoSaveConfig;
38+
}
39+
}
40+
}

MonkeyLoader.GamePacks.ResoniteModLoader/ModConfigurationKey.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ public T? Value
146146

147147
internal override IDefiningConfigKey UntypedKey => Key;
148148

149-
private ModConfiguration ModConfiguration => (ModConfiguration)Key.Section;
149+
private ModConfiguration ModConfiguration => ((RmlModConfigSection)Key.Section).ModConfiguration;
150150

151151
/// <summary>
152152
/// Creates a new instance of the <see cref="ModConfigurationKey{T}"/> class with the given parameters.

MonkeyLoader.GamePacks.ResoniteModLoader/ResoniteMod.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ protected ResoniteMod()
3434
if (BuildConfigurationDefinition() is not ModConfigurationDefinition definition)
3535
return null;
3636

37-
return Config.LoadSection(new ModConfiguration(definition));
37+
var modConfiguration = new ModConfiguration(definition);
38+
Config.LoadSection(modConfiguration.ConfigSection);
39+
40+
return modConfiguration;
3841
});
3942
}
4043

0 commit comments

Comments
 (0)