1- using Elements . Assets ;
2- using Elements . Core ;
3- using Elements . Quantity ;
1+ using Elements . Core ;
42using EnumerableToolkit ;
53using FrooxEngine ;
64using FrooxEngine . UIX ;
7- using HarmonyLib ;
8- using MonkeyLoader . Components ;
95using MonkeyLoader . Configuration ;
106using 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
218namespace 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