Skip to content

Commit 2861521

Browse files
committed
Restructure generation of settings data feed items to be usable from custom generators and implement subgroups
1 parent 10dd1df commit 2861521

4 files changed

Lines changed: 422 additions & 275 deletions

File tree

Lines changed: 17 additions & 262 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,14 @@
1-
using Elements.Assets;
2-
using Elements.Core;
3-
using Elements.Quantity;
1+
using Elements.Core;
42
using EnumerableToolkit;
53
using FrooxEngine;
64
using FrooxEngine.UIX;
7-
using HarmonyLib;
8-
using MonkeyLoader.Components;
95
using MonkeyLoader.Configuration;
106
using MonkeyLoader.Meta;
11-
using MonkeyLoader.Patching;
12-
using MonkeyLoader.Resonite.Configuration;
13-
using System;
14-
using System.Collections.Generic;
15-
using System.IO;
16-
using System.Linq;
17-
using System.Reflection;
18-
using System.Text;
19-
using System.Threading.Tasks;
207

218
namespace MonkeyLoader.Resonite.DataFeeds.Settings
229
{
2310
internal sealed class ConfigSectionSettingsItems : DataFeedBuildingBlockMonkey<ConfigSectionSettingsItems, SettingsDataFeed>
2411
{
25-
private static readonly Type _dummyType = typeof(dummy);
26-
private static readonly MethodInfo _generateEnumItemsAsync = AccessTools.Method(typeof(ConfigSectionSettingsItems), nameof(GenerateEnumItemsAsync));
27-
private static readonly MethodInfo _generateFlagsEnumFieldsAsync = AccessTools.Method(typeof(ConfigSectionSettingsItems), nameof(GenerateFlagsEnumFieldsAsync));
28-
private static readonly MethodInfo _generateItemsForConfigKey = AccessTools.Method(typeof(ConfigSectionSettingsItems), nameof(GenerateItemsForConfigKey));
29-
private static readonly MethodInfo _generateNullableEnumItemsAsync = AccessTools.Method(typeof(ConfigSectionSettingsItems), nameof(GenerateNullableEnumItemsAsync));
30-
private static readonly MethodInfo _generateQuantityField = AccessTools.Method(typeof(ConfigSectionSettingsItems), nameof(GenerateQuantityField));
31-
3212
public override int Priority => HarmonyLib.Priority.Normal;
3313

3414
public override IAsyncEnumerable<DataFeedItem> Apply(IAsyncEnumerable<DataFeedItem> current, EnumerateDataFeedParameters<SettingsDataFeed> parameters)
@@ -53,18 +33,25 @@ public override IAsyncEnumerable<DataFeedItem> Apply(IAsyncEnumerable<DataFeedIt
5333
return current.Concat(EnumerateConfigAsync(parameters, config));
5434
}
5535

56-
protected override IEnumerable<IFeaturePatch> GetFeaturePatches() => [];
57-
5836
private static async IAsyncEnumerable<DataFeedItem> EnumerateConfigAsync(EnumerateDataFeedParameters<SettingsDataFeed> parameters, Config config)
5937
{
6038
foreach (var configSection in config.Sections.Where(section => !section.InternalAccessOnly && section.Keys.Any(key => !key.InternalAccessOnly)))
6139
{
40+
foreach (var configKey in configSection.Keys)
41+
{
42+
// Do this here since the actual item generation code doesn't have access to the data feed anymore
43+
if (configKey.ValueType.IsInjectableEditorType())
44+
parameters.DataFeed.RunSynchronously(() => parameters.DataFeed.GetViewData().EnsureDataFeedValueFieldTemplate(configKey.ValueType));
45+
}
46+
6247
var sectionGroup = new DataFeedResettableGroup();
6348
sectionGroup.InitBase(configSection.Id, parameters.Path, parameters.GroupKeys, configSection.GetLocaleString("Name"));
6449
sectionGroup.InitResetAction(syncDelegate =>
6550
{
66-
if (syncDelegate.Parent is not ButtonActionTrigger actionTrigger
67-
|| syncDelegate.Slot.GetComponent<Button>() is not Button button)
51+
if (syncDelegate.Parent is not ButtonActionTrigger actionTrigger)
52+
return;
53+
54+
if (syncDelegate.Slot.GetComponent<Button>() is not Button button)
6855
return;
6956

7057
button.LocalPressed += (_, _) =>
@@ -77,245 +64,13 @@ private static async IAsyncEnumerable<DataFeedItem> EnumerateConfigAsync(Enumera
7764

7865
var sectionGrouping = parameters.GroupKeys.Concat(configSection.Id).ToArray();
7966

80-
if (configSection is ICustomDataFeedItems customItems)
81-
{
82-
await foreach (var item in customItems.Enumerate(parameters.Path, sectionGrouping, parameters.SearchPhrase, parameters.ViewData))
83-
yield return item;
84-
}
85-
else
86-
{
87-
foreach (var configKey in configSection.Keys.Where(key => !key.InternalAccessOnly))
88-
{
89-
var configKeyItems = (IAsyncEnumerable<DataFeedItem>)_generateItemsForConfigKey
90-
.MakeGenericMethod(configKey.ValueType)
91-
.Invoke(null, [parameters, sectionGrouping, configKey])!;
92-
93-
await foreach (var item in configKeyItems)
94-
yield return item;
95-
}
96-
}
97-
}
98-
}
99-
100-
private static async IAsyncEnumerable<DataFeedItem> GenerateEnumItemsAsync<T>(IReadOnlyList<string> path, IReadOnlyList<string> groupKeys, IDefiningConfigKey configKey)
101-
where T : unmanaged, Enum
102-
{
103-
await Task.CompletedTask;
104-
105-
if (typeof(T).GetCustomAttribute<FlagsAttribute>() is null)
106-
{
107-
var enumField = new DataFeedEnum<T>();
108-
enumField.InitBase(path, groupKeys, configKey);
109-
enumField.InitSetupValue(field => field.SetupConfigKeyField(configKey));
110-
111-
yield return enumField;
112-
yield break;
113-
}
114-
115-
var items = (IAsyncEnumerable<DataFeedItem>)_generateFlagsEnumFieldsAsync
116-
.MakeGenericMethod(typeof(T))
117-
.Invoke(null, [path, groupKeys, configKey])!;
118-
119-
await foreach (var item in items)
120-
yield return item;
121-
}
122-
123-
private static async IAsyncEnumerable<DataFeedItem> GenerateFlagsEnumFieldsAsync<T>(IReadOnlyList<string> path, IReadOnlyList<string> groupKeys, IDefiningConfigKey configKey)
124-
where T : unmanaged, Enum
125-
{
126-
await Task.CompletedTask;
127-
128-
var flagsEnumGroup = new DataFeedGroup();
129-
flagsEnumGroup.InitBase(configKey.FullId + ".Flags", path, groupKeys, Mod.GetLocaleString("EnumFlags.Name", ("KeyId", configKey.Id)));
130-
flagsEnumGroup.InitDescription(configKey.GetLocaleKey("Description").AsLocaleKey());
131-
yield return flagsEnumGroup;
132-
133-
var flagsGrouping = groupKeys.Concat([configKey.FullId + ".Flags"]).ToArray();
134-
135-
var enumType = typeof(T);
136-
137-
foreach (var value in Enum.GetValues(enumType).Cast<T>())
138-
{
139-
var name = value.ToString();
140-
var longValue = Convert.ToInt64(value);
141-
142-
var flagToggle = new DataFeedToggle();
143-
flagToggle.InitBase($"{configKey.FullId}.{name}", path, flagsGrouping, name);
144-
flagToggle.InitDescription(Mod.GetLocaleString("EnumToggle.Description", ("EnumName", enumType.Name), ("FlagName", name)));
145-
flagToggle.InitSetupValue(field =>
146-
{
147-
var slot = field.FindNearestParent<Slot>();
148-
149-
if (slot.GetComponentInParents<FeedItemInterface>() is FeedItemInterface feedItemInterface)
150-
{
151-
// Adding the config key's full id to make it easier to create standalone facets
152-
var comment = feedItemInterface.Slot.AttachComponent<Comment>();
153-
comment.Text.Value = configKey.FullId;
154-
155-
var longField = feedItemInterface.Slot.AttachComponent<ValueField<long>>();
156-
longField.Value.Value = longValue;
157-
}
158-
159-
field.SyncWithConfigKeyEnumFlagUntyped(configKey, value);
160-
});
161-
162-
yield return flagToggle;
163-
}
164-
}
165-
166-
private static DataFeedIndicator<T> GenerateIndicator<T>(IReadOnlyList<string> path, IReadOnlyList<string> groupKeys, IDefiningConfigKey<T> configKey)
167-
{
168-
var indicator = new DataFeedIndicator<T>();
169-
indicator.InitBase(path, groupKeys, configKey);
170-
indicator.InitSetupValue(field => field.SetupConfigKeyField(configKey));
171-
172-
return indicator;
173-
}
174-
175-
private static IAsyncEnumerable<DataFeedItem> GenerateItemsForConfigKey<T>(EnumerateDataFeedParameters<SettingsDataFeed> parameters, IReadOnlyList<string> groupKeys, IEntity<IDefiningConfigKey<T>> configKeyEntity)
176-
{
177-
var configKey = configKeyEntity.Self;
178-
var path = parameters.Path;
179-
180-
if (configKeyEntity.Components.TryGet<IConfigKeyCustomDataFeedItems<T>>(out var customItems))
181-
return customItems.Enumerate(path, groupKeys, parameters.SearchPhrase, parameters.ViewData);
182-
183-
//if (setting is SettingIndicatorProperty)
184-
//{
185-
// return (DataFeedItem)_generateIndicator.MakeGenericMethod(type).Invoke(null, new object[4] { identity, setting, path, grouping });
186-
//}
187-
188-
if (configKey.ValueType == _dummyType)
189-
{
190-
var dummyField = new DataFeedValueField<dummy>();
191-
dummyField.InitBase(configKey.FullId, path, groupKeys, configKey.HasDescription ? configKey.GetLocaleString("Description") : " ");
192-
return dummyField.YieldAsync();
193-
}
194-
195-
if (configKey.ValueType == typeof(bool))
196-
return GenerateToggle(path, groupKeys, (IDefiningConfigKey<bool>)configKey).YieldAsync();
197-
198-
if (configKey.ValueType.IsEnum)
199-
{
200-
var enumItems = (IAsyncEnumerable<DataFeedItem>)_generateEnumItemsAsync
201-
.MakeGenericMethod(configKey.ValueType)
202-
.Invoke(null, [path, groupKeys, configKey])!;
203-
204-
return enumItems;
205-
}
206-
207-
if (configKey.ValueType.IsNullable())
208-
{
209-
var nullableType = configKey.ValueType.GetGenericArguments()[0];
210-
if (nullableType.IsEnum)
211-
{
212-
var nullableEnumItems = (IAsyncEnumerable<DataFeedItem>)_generateNullableEnumItemsAsync
213-
.MakeGenericMethod(nullableType)
214-
.Invoke(null, [path, groupKeys, configKey])!;
215-
216-
return nullableEnumItems;
217-
}
218-
}
67+
var sectionItems = configSection is ICustomDataFeedItems customItemsSection
68+
? customItemsSection.Enumerate(parameters.Path, sectionGrouping, parameters.SearchPhrase, parameters.ViewData)
69+
: configSection.EnumerateDefaultItemsAsync(parameters.Path, sectionGrouping, parameters.SearchPhrase, parameters.ViewData);
21970

220-
if (configKeyEntity.Components.TryGet<IConfigKeyRange<T>>(out var range))
221-
{
222-
if (configKeyEntity.Components.TryGet<IConfigKeyQuantity<T>>(out var quantity))
223-
{
224-
var quantityField = (DataFeedItem)_generateQuantityField
225-
.MakeGenericMethod(configKey.ValueType, quantity.QuantityType)
226-
.Invoke(null, [parameters.Path, groupKeys, configKey, quantity])!;
227-
228-
return quantityField.YieldAsync();
229-
}
230-
231-
var slider = GenerateSlider(parameters.Path, groupKeys, configKey, range);
232-
return slider.YieldAsync();
71+
await foreach (var item in sectionItems)
72+
yield return item;
23373
}
234-
235-
var valueField = GenerateValueField(parameters, groupKeys, configKey);
236-
return valueField.YieldAsync();
237-
}
238-
239-
private static async IAsyncEnumerable<DataFeedItem> GenerateNullableEnumItemsAsync<T>(IReadOnlyList<string> path, IReadOnlyList<string> groupKeys, IDefiningConfigKey<T?> configKey)
240-
where T : unmanaged, Enum
241-
{
242-
await Task.CompletedTask;
243-
244-
var nullableEnumGroup = new DataFeedGroup();
245-
nullableEnumGroup.InitBase(configKey.FullId + ".NullableGroup", path, groupKeys, configKey.GetLocaleKey("Name").AsLocaleKey());
246-
nullableEnumGroup.InitDescription(configKey.GetLocaleKey("Description").AsLocaleKey());
247-
yield return nullableEnumGroup;
248-
249-
var nullableGroupKeys = groupKeys.Concat([configKey.FullId + ".NullableGroup"]).ToArray();
250-
251-
var nullableToggle = new DataFeedToggle();
252-
253-
nullableToggle.InitBase(configKey.FullId + ".HasValue", path, nullableGroupKeys, Mod.GetLocaleString("NullableEnumHasValue.Name"));
254-
nullableToggle.InitDescription(configKey.GetLocaleKey("HasValue").AsLocaleKey());
255-
nullableToggle.InitSetupValue(field =>
256-
{
257-
var slot = field.FindNearestParent<Slot>();
258-
259-
if (slot.GetComponentInParents<FeedItemInterface>() is FeedItemInterface feedItemInterface)
260-
{
261-
// Adding the config key's full id to make it easier to create standalone facets
262-
feedItemInterface.Slot.AttachComponent<Comment>().Text.Value = configKey.FullId;
263-
}
264-
265-
field.SyncWithNullableConfigKeyHasValue(configKey);
266-
});
267-
yield return nullableToggle;
268-
269-
var enumItems = (IAsyncEnumerable<DataFeedItem>)_generateEnumItemsAsync
270-
.MakeGenericMethod(typeof(T))
271-
.Invoke(null, [path, nullableGroupKeys, configKey])!;
272-
273-
await foreach (var item in enumItems)
274-
yield return item;
275-
}
276-
277-
private static DataFeedQuantityField<TQuantity, T> GenerateQuantityField<T, TQuantity>(IReadOnlyList<string> path, IReadOnlyList<string> groupKeys, IDefiningConfigKey<T> configKey, IConfigKeyQuantity<T> quantity)
278-
where TQuantity : unmanaged, IQuantity<TQuantity>
279-
{
280-
var quantityField = new DataFeedQuantityField<TQuantity, T>();
281-
quantityField.InitBase(path, groupKeys, configKey);
282-
quantityField.InitUnitConfiguration(quantity.DefaultConfiguration, quantity.ImperialConfiguration!);
283-
quantityField.InitSetup(quantityField => quantityField.SetupConfigKeyField(configKey), quantity.Min, quantity.Max);
284-
285-
return quantityField;
286-
}
287-
288-
private static DataFeedSlider<T> GenerateSlider<T>(IReadOnlyList<string> path, IReadOnlyList<string> groupKeys, IDefiningConfigKey<T> configKey, IConfigKeyRange<T> range)
289-
{
290-
var slider = new DataFeedSlider<T>();
291-
slider.InitBase(path, groupKeys, configKey);
292-
slider.InitSetup(field => field.SetupConfigKeyField(configKey), range.Min, range.Max);
293-
294-
//if (!string.IsNullOrWhiteSpace(configKey.TextFormat))
295-
// slider.InitFormatting(configKey.TextFormat);
296-
297-
return slider;
298-
}
299-
300-
private static DataFeedToggle GenerateToggle(IReadOnlyList<string> path, IReadOnlyList<string> groupKeys, IDefiningConfigKey<bool> configKey)
301-
{
302-
var toggle = new DataFeedToggle();
303-
toggle.InitBase(path, groupKeys, configKey);
304-
toggle.InitSetupValue(field => field.SetupConfigKeyField(configKey));
305-
306-
return toggle;
307-
}
308-
309-
private static DataFeedValueField<T> GenerateValueField<T>(EnumerateDataFeedParameters<SettingsDataFeed> parameters, IReadOnlyList<string> groupKeys, IDefiningConfigKey<T> configKey)
310-
{
311-
var valueField = new DataFeedValueField<T>();
312-
valueField.InitBase(parameters.Path, groupKeys, configKey);
313-
valueField.InitSetupValue(field => field.SetupConfigKeyField(configKey));
314-
315-
if (configKey.ValueType.IsInjectableEditorType())
316-
parameters.DataFeed.RunSynchronously(() => parameters.DataFeed.GetViewData().EnsureDataFeedValueFieldTemplate(configKey.ValueType));
317-
318-
return valueField;
31974
}
32075
}
32176
}

0 commit comments

Comments
 (0)