this documents weird things I've seen (or friends of mine have seen) in decompilation of Resonite. I will try to focus on more higher-level stuff rather than specific code flow, since specific code flow is very subject to decompilation artifacts
there isn't any real intent in this page. some of this stuff I can confidently wonder why it was done, others I am not confident. it's more like a... bookmark kind of thing? things to look and delve into later, since I'm endlessly learning the very expansive language that is C# and decompilation provides zero comments and artifacts that make following flow a bit harder than source.
FrooxEngine
SettingsDataFeed
there appears to be some private static MethodInfo fields on this component:
private static MethodInfo _generateValueField;
private static MethodInfo _generateEnumField;
private static MethodInfo _generateSlider;
private static MethodInfo _generateQuantityField;
private static MethodInfo _generateIndicator;
these are only used within SettingsDataFeed
itself, built during the constructor:
static SettingsDataFeed()
{
Type typeFromHandle = typeof(SettingsDataFeed);
BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
_generateValueField = typeFromHandle.GetMethod("GenerateValueField", bindingAttr);
_generateEnumField = typeFromHandle.GetMethod("GenerateEnumField", bindingAttr);
_generateSlider = typeFromHandle.GetMethod("GenerateSlider", bindingAttr);
_generateQuantityField = typeFromHandle.GetMethod("GenerateQuantityField", bindingAttr);
_generateIndicator = typeFromHandle.GetMethod("GenerateIndicator", bindingAttr);
}
and only used in the static GenerateItem
function:
private static DataFeedItem GenerateItem(FieldIdentity identity, SettingPropertyAttribute setting, IReadOnlyList<string> path, IReadOnlyList<string> grouping)
{
Type fieldType = identity.field.FieldType;
if (setting is SettingSubcategoryListAttribute settingSubcategoryListAttribute) {
DataFeedCategory dataFeedCategory = new DataFeedCategory();
InitBase(dataFeedCategory, identity, setting, path, grouping);
dataFeedCategory.SetOverrideSubpath(identity.settingType.Name + "." + identity.field.Name);
if (settingSubcategoryListAttribute.EnabledProperty != null) {
FieldIdentity fieldIdentity = new FieldIdentity();
fieldIdentity.InitBaseFrom(identity);
fieldIdentity.field = identity.settingType.GetField(settingSubcategoryListAttribute.EnabledProperty);
dataFeedCategory.InitEnabled(GenerateFieldSync<bool>(fieldIdentity));
}
return dataFeedCategory;
}
foreach (Type item in fieldType.EnumerateInterfacesRecursively()) {
if (item.IsGenericType && item.GetGenericTypeDefinition() == typeof(IField<>)) {
Type type = item.GetGenericArguments()[0];
if (setting is SettingIndicatorProperty) {
return (DataFeedItem)_generateIndicator.MakeGenericMethod(type).Invoke(null, new object[4] { identity, setting, path, grouping });
}
if (type == typeof(bool)) {
DataFeedToggle dataFeedToggle = new DataFeedToggle();
InitBase(dataFeedToggle, identity, setting, path, grouping);
dataFeedToggle.InitSetupValue(GenerateFieldSync<bool>(identity));
return dataFeedToggle;
}
if (type.IsEnum) {
return (DataFeedItem)_generateEnumField.MakeGenericMethod(type).Invoke(null, new object[4] { identity, setting, path, grouping });
}
RangeAttribute customAttribute = identity.field.GetCustomAttribute<RangeAttribute>();
QuantityAttribute customAttribute2 = identity.field.GetCustomAttribute<QuantityAttribute>();
if (customAttribute2 != null) {
return (DataFeedItem)_generateQuantityField.MakeGenericMethod(customAttribute2.QuantityType, type).Invoke(null, new object[6] { identity, setting, customAttribute2, customAttribute, path, grouping });
}
if (customAttribute != null) {
return (DataFeedItem)_generateSlider.MakeGenericMethod(type).Invoke(null, new object[5] { identity, setting, customAttribute, path, grouping });
}
return (DataFeedItem)_generateValueField.MakeGenericMethod(type).Invoke(null, new object[4] { identity, setting, path, grouping });
}
}
return new DataFeedLabel(identity.field.Name, path, grouping, "<color=red>" + identity.field.Name + " (" + identity.field.FieldType.GetNiceName() + ")</color>");
}
since type
is dynamic, these things ~do~ need to be reflected in a local sense--you can't invoke a function<T>()
dynamically, but I do wonder if there's a slightly more elegant way to go about it than this