|
|
@ -339,7 +339,7 @@ void UBSettingsSystem::InitializeValues(TSharedPtr<FJsonObject> Destination, USt |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Helper: resolve enum value from a string using internal name, display name, and UUserDefinedEnum's DisplayNameMap
|
|
|
// Helper: resolve enum value from a string using internal name, display name, and UUserDefinedEnum's DisplayNameMap
|
|
|
static bool ResolveEnumValueFromString(const UEnum* Enum, const FString& InString, int64& OutValue) |
|
|
bool UBSettingsSystem::ResolveEnumValueFromString(const UEnum* Enum, const FString& InString, int64& OutValue) |
|
|
{ |
|
|
{ |
|
|
if (!Enum) return false; |
|
|
if (!Enum) return false; |
|
|
|
|
|
|
|
|
@ -1083,6 +1083,90 @@ void UBSettingsSystem::CollectEnumValues(const FProperty* Prop, TArray<FString>& |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Recursively builds a JSON schema description for a single property.
|
|
|
|
|
|
// Handles type, tooltip, enum values, struct sub-fields, and array items at any depth.
|
|
|
|
|
|
TSharedPtr<FJsonObject> UBSettingsSystem::BuildFieldSchema(const FProperty* Prop) |
|
|
|
|
|
{ |
|
|
|
|
|
TSharedPtr<FJsonObject> FieldObj = MakeShared<FJsonObject>(); |
|
|
|
|
|
const FString TypeStr = GetSchemaType(Prop); |
|
|
|
|
|
FieldObj->SetStringField(TEXT("type"), TypeStr); |
|
|
|
|
|
|
|
|
|
|
|
// Tooltip
|
|
|
|
|
|
const FString Tooltip = Prop->GetMetaData(TEXT("ToolTip")); |
|
|
|
|
|
if (!Tooltip.IsEmpty()) |
|
|
|
|
|
{ |
|
|
|
|
|
FieldObj->SetStringField(TEXT("tooltip"), Tooltip); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Enum: collect available values
|
|
|
|
|
|
if (TypeStr == TEXT("enum")) |
|
|
|
|
|
{ |
|
|
|
|
|
TArray<FString> EnumValues; |
|
|
|
|
|
CollectEnumValues(Prop, EnumValues); |
|
|
|
|
|
TArray<TSharedPtr<FJsonValue>> JsonEnumVals; |
|
|
|
|
|
for (const FString& Val : EnumValues) |
|
|
|
|
|
{ |
|
|
|
|
|
JsonEnumVals.Add(MakeShared<FJsonValueString>(Val)); |
|
|
|
|
|
} |
|
|
|
|
|
FieldObj->SetArrayField(TEXT("enum"), JsonEnumVals); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Struct: recurse into sub-fields
|
|
|
|
|
|
if (TypeStr == TEXT("struct")) |
|
|
|
|
|
{ |
|
|
|
|
|
if (const FStructProperty* StructProp = CastField<FStructProperty>(Prop)) |
|
|
|
|
|
{ |
|
|
|
|
|
TSharedPtr<FJsonObject> FieldsObj = MakeShared<FJsonObject>(); |
|
|
|
|
|
for (TFieldIterator<FProperty> It(StructProp->Struct); It; ++It) |
|
|
|
|
|
{ |
|
|
|
|
|
const FProperty* SubProp = *It; |
|
|
|
|
|
if (!SubProp || IsSchemaCategoryProperty(SubProp)) continue; |
|
|
|
|
|
FieldsObj->SetObjectField(SubProp->GetAuthoredName(), BuildFieldSchema(SubProp)); |
|
|
|
|
|
} |
|
|
|
|
|
FieldObj->SetObjectField(TEXT("fields"), FieldsObj); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Array: item type + recurse for enum/struct items
|
|
|
|
|
|
if (TypeStr == TEXT("array")) |
|
|
|
|
|
{ |
|
|
|
|
|
if (const FArrayProperty* ArrProp = CastField<FArrayProperty>(Prop)) |
|
|
|
|
|
{ |
|
|
|
|
|
const FProperty* Inner = ArrProp->Inner; |
|
|
|
|
|
const FString InnerType = GetSchemaType(Inner); |
|
|
|
|
|
FieldObj->SetStringField(TEXT("itemsType"), InnerType); |
|
|
|
|
|
|
|
|
|
|
|
if (InnerType == TEXT("enum")) |
|
|
|
|
|
{ |
|
|
|
|
|
TArray<FString> EnumValues; |
|
|
|
|
|
CollectEnumValues(Inner, EnumValues); |
|
|
|
|
|
TArray<TSharedPtr<FJsonValue>> JsonEnumVals; |
|
|
|
|
|
for (const FString& Val : EnumValues) |
|
|
|
|
|
{ |
|
|
|
|
|
JsonEnumVals.Add(MakeShared<FJsonValueString>(Val)); |
|
|
|
|
|
} |
|
|
|
|
|
FieldObj->SetArrayField(TEXT("itemsEnum"), JsonEnumVals); |
|
|
|
|
|
} |
|
|
|
|
|
else if (InnerType == TEXT("struct")) |
|
|
|
|
|
{ |
|
|
|
|
|
if (const FStructProperty* InnerStructProp = CastField<FStructProperty>(Inner)) |
|
|
|
|
|
{ |
|
|
|
|
|
TSharedPtr<FJsonObject> ItemsFieldsObj = MakeShared<FJsonObject>(); |
|
|
|
|
|
for (TFieldIterator<FProperty> It(InnerStructProp->Struct); It; ++It) |
|
|
|
|
|
{ |
|
|
|
|
|
const FProperty* SubProp = *It; |
|
|
|
|
|
if (!SubProp || IsSchemaCategoryProperty(SubProp)) continue; |
|
|
|
|
|
ItemsFieldsObj->SetObjectField(SubProp->GetAuthoredName(), BuildFieldSchema(SubProp)); |
|
|
|
|
|
} |
|
|
|
|
|
FieldObj->SetObjectField(TEXT("itemsFields"), ItemsFieldsObj); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return FieldObj; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// Exports a JSON schema file describing the structure of the provided UStruct.
|
|
|
// Exports a JSON schema file describing the structure of the provided UStruct.
|
|
|
bool UBSettingsSystem::StructToJsonSchema(const UStruct* StructType, const FString& ConfigName, const FString& SavedSubFolder, const uint8* DefaultDataOverride) |
|
|
bool UBSettingsSystem::StructToJsonSchema(const UStruct* StructType, const FString& ConfigName, const FString& SavedSubFolder, const uint8* DefaultDataOverride) |
|
|
{ |
|
|
{ |
|
|
@ -1165,299 +1249,27 @@ bool UBSettingsSystem::StructToJsonSchema(const UStruct* StructType, const FStri |
|
|
// Use authored variable name (no generated suffixes)
|
|
|
// Use authored variable name (no generated suffixes)
|
|
|
const FString VarName = Prop->GetAuthoredName(); |
|
|
const FString VarName = Prop->GetAuthoredName(); |
|
|
|
|
|
|
|
|
// Determine schema type for this property
|
|
|
// Build field schema recursively (type, tooltip, enum, struct fields, array items)
|
|
|
const FString TypeStr = GetSchemaType(Prop); |
|
|
TSharedPtr<FJsonObject> FieldObj = BuildFieldSchema(Prop); |
|
|
|
|
|
|
|
|
// Build JSON object for this variable (holds its attributes)
|
|
|
// Top-level only: export default value
|
|
|
TSharedPtr<FJsonObject> FieldObj = MakeShared<FJsonObject>(); |
|
|
|
|
|
|
|
|
|
|
|
FieldObj->SetStringField(TEXT("type"), TypeStr); |
|
|
|
|
|
|
|
|
|
|
|
// Export default value
|
|
|
|
|
|
if (TSharedPtr<FJsonValue> DefVal = Defaults->TryGetField(VarName)) |
|
|
if (TSharedPtr<FJsonValue> DefVal = Defaults->TryGetField(VarName)) |
|
|
{ |
|
|
{ |
|
|
FieldObj->SetField(TEXT("default"), DefVal); |
|
|
FieldObj->SetField(TEXT("default"), DefVal); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Tooltip: only include if explicitly set via UPROPERTY(meta = (ToolTip = "..."))
|
|
|
// Top-level only: SaveGame flag
|
|
|
const FString Tooltip = Prop->GetMetaData(TEXT("ToolTip")); |
|
|
if (Prop->HasAnyPropertyFlags(CPF_SaveGame)) |
|
|
if (!Tooltip.IsEmpty()) |
|
|
|
|
|
{ |
|
|
|
|
|
FieldObj->SetStringField(TEXT("tooltip"), Tooltip); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// SaveGame: only include if explicitly set
|
|
|
|
|
|
const bool SaveGame = Prop->HasAnyPropertyFlags(CPF_SaveGame); |
|
|
|
|
|
if (SaveGame) |
|
|
|
|
|
{ |
|
|
{ |
|
|
FieldObj->SetBoolField(TEXT("hotreload"), SaveGame); |
|
|
FieldObj->SetBoolField(TEXT("hotreload"), true); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// attach category name to each variable if a category context is active ---
|
|
|
// Top-level only: attach category if active
|
|
|
if (!CurrentCategory.IsEmpty()) |
|
|
if (!CurrentCategory.IsEmpty()) |
|
|
{ |
|
|
{ |
|
|
FieldObj->SetStringField(TEXT("category"), CurrentCategory); |
|
|
FieldObj->SetStringField(TEXT("category"), CurrentCategory); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// If this is a struct: list sub-variables and their types
|
|
|
|
|
|
if (TypeStr == TEXT("struct")) |
|
|
|
|
|
{ |
|
|
|
|
|
if (const FStructProperty* StructProp = CastField<FStructProperty>(Prop)) |
|
|
|
|
|
{ |
|
|
|
|
|
TSharedPtr<FJsonObject> FieldsObj = MakeShared<FJsonObject>(); |
|
|
|
|
|
|
|
|
|
|
|
for (TFieldIterator<FProperty> SubIt(StructProp->Struct); SubIt; ++SubIt) |
|
|
|
|
|
{ |
|
|
|
|
|
const FProperty* SubProp = *SubIt; |
|
|
|
|
|
if (!SubProp || IsSchemaCategoryProperty(SubProp)) |
|
|
|
|
|
{ |
|
|
|
|
|
continue; // Marker/Invalides Feld überspringen
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const FString SubName = SubProp->GetAuthoredName(); |
|
|
|
|
|
const FString SubType = GetSchemaType(SubProp); |
|
|
|
|
|
|
|
|
|
|
|
TSharedPtr<FJsonObject> SubFieldObj = MakeShared<FJsonObject>(); |
|
|
|
|
|
SubFieldObj->SetStringField(TEXT("type"), SubType); |
|
|
|
|
|
|
|
|
|
|
|
// --- Enums als direkte Struct-Subfelder (optional aber konsistent)
|
|
|
|
|
|
if (SubType == TEXT("enum")) |
|
|
|
|
|
{ |
|
|
|
|
|
TArray<FString> EnumValues; |
|
|
|
|
|
CollectEnumValues(SubProp, EnumValues); |
|
|
|
|
|
TArray<TSharedPtr<FJsonValue>> JsonEnumVals; |
|
|
|
|
|
for (const FString& V : EnumValues) |
|
|
|
|
|
{ |
|
|
|
|
|
JsonEnumVals.Add(MakeShared<FJsonValueString>(V)); |
|
|
|
|
|
} |
|
|
|
|
|
SubFieldObj->SetArrayField(TEXT("enum"), JsonEnumVals); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// --- Verschachteltes Struct als Subfeld: nur Felder (Name+Typ) auflisten
|
|
|
|
|
|
else if (SubType == TEXT("struct")) |
|
|
|
|
|
{ |
|
|
|
|
|
if (const FStructProperty* NestedStructProp = CastField<FStructProperty>(SubProp)) |
|
|
|
|
|
{ |
|
|
|
|
|
TSharedPtr<FJsonObject> NestedFieldsObj = MakeShared<FJsonObject>(); |
|
|
|
|
|
|
|
|
|
|
|
for (TFieldIterator<FProperty> NIt(NestedStructProp->Struct); NIt; ++NIt) |
|
|
|
|
|
{ |
|
|
|
|
|
const FProperty* NProp = *NIt; |
|
|
|
|
|
if (!NProp || IsSchemaCategoryProperty(NProp)) continue; |
|
|
|
|
|
|
|
|
|
|
|
const FString NName = NProp->GetAuthoredName(); |
|
|
|
|
|
const FString NType = GetSchemaType(NProp); |
|
|
|
|
|
|
|
|
|
|
|
TSharedPtr<FJsonObject> NFieldObj = MakeShared<FJsonObject>(); |
|
|
|
|
|
NFieldObj->SetStringField(TEXT("type"), NType); |
|
|
|
|
|
|
|
|
|
|
|
// Arrays innerhalb des verschachtelten Structs (1 Ebene)
|
|
|
|
|
|
if (NType == TEXT("array")) |
|
|
|
|
|
{ |
|
|
|
|
|
if (const FArrayProperty* DeepArr = CastField<FArrayProperty>(NProp)) |
|
|
|
|
|
{ |
|
|
|
|
|
const FProperty* DeepInner = DeepArr->Inner; |
|
|
|
|
|
const FString DeepInnerType = GetSchemaType(DeepInner); |
|
|
|
|
|
NFieldObj->SetStringField(TEXT("itemsType"), DeepInnerType); |
|
|
|
|
|
|
|
|
|
|
|
if (DeepInnerType == TEXT("enum")) |
|
|
|
|
|
{ |
|
|
|
|
|
TArray<FString> EV; |
|
|
|
|
|
CollectEnumValues(DeepInner, EV); |
|
|
|
|
|
TArray<TSharedPtr<FJsonValue>> JV; |
|
|
|
|
|
for (const FString& e : EV) JV.Add(MakeShared<FJsonValueString>(e)); |
|
|
|
|
|
NFieldObj->SetArrayField(TEXT("itemsEnum"), JV); |
|
|
|
|
|
} |
|
|
|
|
|
else if (DeepInnerType == TEXT("struct")) |
|
|
|
|
|
{ |
|
|
|
|
|
if (const FStructProperty* DeepInnerStruct = CastField<FStructProperty>(DeepInner)) |
|
|
|
|
|
{ |
|
|
|
|
|
TSharedPtr<FJsonObject> ItemsFieldsObj = MakeShared<FJsonObject>(); |
|
|
|
|
|
for (TFieldIterator<FProperty> SIt(DeepInnerStruct->Struct); SIt; ++SIt) |
|
|
|
|
|
{ |
|
|
|
|
|
const FProperty* SProp = *SIt; |
|
|
|
|
|
if (!SProp || IsSchemaCategoryProperty(SProp)) continue; |
|
|
|
|
|
|
|
|
|
|
|
const FString SName = SProp->GetAuthoredName(); |
|
|
|
|
|
const FString SType = GetSchemaType(SProp); |
|
|
|
|
|
|
|
|
|
|
|
TSharedPtr<FJsonObject> SObj = MakeShared<FJsonObject>(); |
|
|
|
|
|
SObj->SetStringField(TEXT("type"), SType); |
|
|
|
|
|
ItemsFieldsObj->SetObjectField(SName, SObj); |
|
|
|
|
|
} |
|
|
|
|
|
NFieldObj->SetObjectField(TEXT("itemsFields"), ItemsFieldsObj); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
NestedFieldsObj->SetObjectField(NName, NFieldObj); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
SubFieldObj->SetObjectField(TEXT("fields"), NestedFieldsObj); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// --- Array als Struct-Subfeld: itemsType (+ itemsEnum / itemsFields)
|
|
|
|
|
|
else if (SubType == TEXT("array")) |
|
|
|
|
|
{ |
|
|
|
|
|
if (const FArrayProperty* SubArr = CastField<FArrayProperty>(SubProp)) |
|
|
|
|
|
{ |
|
|
|
|
|
const FProperty* Inner = SubArr->Inner; |
|
|
|
|
|
const FString InnerType = GetSchemaType(Inner); |
|
|
|
|
|
SubFieldObj->SetStringField(TEXT("itemsType"), InnerType); |
|
|
|
|
|
|
|
|
|
|
|
if (InnerType == TEXT("enum")) |
|
|
|
|
|
{ |
|
|
|
|
|
TArray<FString> EnumValues; |
|
|
|
|
|
CollectEnumValues(Inner, EnumValues); |
|
|
|
|
|
TArray<TSharedPtr<FJsonValue>> JsonEnumVals; |
|
|
|
|
|
for (const FString& V : EnumValues) |
|
|
|
|
|
{ |
|
|
|
|
|
JsonEnumVals.Add(MakeShared<FJsonValueString>(V)); |
|
|
|
|
|
} |
|
|
|
|
|
SubFieldObj->SetArrayField(TEXT("itemsEnum"), JsonEnumVals); |
|
|
|
|
|
} |
|
|
|
|
|
else if (InnerType == TEXT("struct")) |
|
|
|
|
|
{ |
|
|
|
|
|
if (const FStructProperty* InnerStructProp = CastField<FStructProperty>(Inner)) |
|
|
|
|
|
{ |
|
|
|
|
|
TSharedPtr<FJsonObject> ItemsFieldsObj = MakeShared<FJsonObject>(); |
|
|
|
|
|
|
|
|
|
|
|
for (TFieldIterator<FProperty> SIt(InnerStructProp->Struct); SIt; ++SIt) |
|
|
|
|
|
{ |
|
|
|
|
|
const FProperty* SProp = *SIt; |
|
|
|
|
|
if (!SProp || IsSchemaCategoryProperty(SProp)) continue; |
|
|
|
|
|
|
|
|
|
|
|
const FString SName = SProp->GetAuthoredName(); |
|
|
|
|
|
const FString SType = GetSchemaType(SProp); |
|
|
|
|
|
|
|
|
|
|
|
TSharedPtr<FJsonObject> SObj = MakeShared<FJsonObject>(); |
|
|
|
|
|
SObj->SetStringField(TEXT("type"), SType); |
|
|
|
|
|
|
|
|
|
|
|
// Arrays innerhalb der Item-Structs (1 Ebene)
|
|
|
|
|
|
if (SType == TEXT("array")) |
|
|
|
|
|
{ |
|
|
|
|
|
if (const FArrayProperty* DeepArr = CastField<FArrayProperty>(SProp)) |
|
|
|
|
|
{ |
|
|
|
|
|
const FProperty* DeepInner = DeepArr->Inner; |
|
|
|
|
|
const FString DeepInnerType = GetSchemaType(DeepInner); |
|
|
|
|
|
SObj->SetStringField(TEXT("itemsType"), DeepInnerType); |
|
|
|
|
|
|
|
|
|
|
|
if (DeepInnerType == TEXT("enum")) |
|
|
|
|
|
{ |
|
|
|
|
|
TArray<FString> EV; |
|
|
|
|
|
CollectEnumValues(DeepInner, EV); |
|
|
|
|
|
TArray<TSharedPtr<FJsonValue>> JV; |
|
|
|
|
|
for (const FString& e : EV) JV.Add(MakeShared<FJsonValueString>(e)); |
|
|
|
|
|
SObj->SetArrayField(TEXT("itemsEnum"), JV); |
|
|
|
|
|
} |
|
|
|
|
|
else if (DeepInnerType == TEXT("struct")) |
|
|
|
|
|
{ |
|
|
|
|
|
if (const FStructProperty* DeepInnerStruct = CastField<FStructProperty>(DeepInner)) |
|
|
|
|
|
{ |
|
|
|
|
|
TSharedPtr<FJsonObject> ItemsFields2 = MakeShared<FJsonObject>(); |
|
|
|
|
|
for (TFieldIterator<FProperty> S2It(DeepInnerStruct->Struct); S2It; ++S2It) |
|
|
|
|
|
{ |
|
|
|
|
|
const FProperty* S2Prop = *S2It; |
|
|
|
|
|
if (!S2Prop || IsSchemaCategoryProperty(S2Prop)) continue; |
|
|
|
|
|
|
|
|
|
|
|
TSharedPtr<FJsonObject> S2Obj = MakeShared<FJsonObject>(); |
|
|
|
|
|
S2Obj->SetStringField(TEXT("type"), GetSchemaType(S2Prop)); |
|
|
|
|
|
ItemsFields2->SetObjectField(S2Prop->GetAuthoredName(), S2Obj); |
|
|
|
|
|
} |
|
|
|
|
|
SObj->SetObjectField(TEXT("itemsFields"), ItemsFields2); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ItemsFieldsObj->SetObjectField(SName, SObj); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
SubFieldObj->SetObjectField(TEXT("itemsFields"), ItemsFieldsObj); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Feld registrieren
|
|
|
|
|
|
FieldsObj->SetObjectField(SubName, SubFieldObj); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// struct-Felddefinitionen anhängen
|
|
|
|
|
|
FieldObj->SetObjectField(TEXT("fields"), FieldsObj); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Enums: collect available values and emit as array of strings
|
|
|
|
|
|
if (TypeStr == TEXT("enum")) |
|
|
|
|
|
{ |
|
|
|
|
|
TArray<FString> EnumValues; |
|
|
|
|
|
CollectEnumValues(Prop, EnumValues); |
|
|
|
|
|
|
|
|
|
|
|
TArray<TSharedPtr<FJsonValue>> JsonEnumVals; |
|
|
|
|
|
for (const FString& Val : EnumValues) |
|
|
|
|
|
{ |
|
|
|
|
|
JsonEnumVals.Add(MakeShared<FJsonValueString>(Val)); |
|
|
|
|
|
} |
|
|
|
|
|
FieldObj->SetArrayField(TEXT("enum"), JsonEnumVals); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Arrays: determine item type and add additional metadata
|
|
|
|
|
|
if (TypeStr == TEXT("array")) |
|
|
|
|
|
{ |
|
|
|
|
|
if (const FArrayProperty* ArrProp = CastField<FArrayProperty>(Prop)) |
|
|
|
|
|
{ |
|
|
|
|
|
const FProperty* Inner = ArrProp->Inner; |
|
|
|
|
|
const FString InnerType = GetSchemaType(Inner); |
|
|
|
|
|
|
|
|
|
|
|
// Always expose the item type
|
|
|
|
|
|
FieldObj->SetStringField(TEXT("itemsType"), InnerType); |
|
|
|
|
|
|
|
|
|
|
|
// If item is enum: export enum values for the array items
|
|
|
|
|
|
if (InnerType == TEXT("enum")) |
|
|
|
|
|
{ |
|
|
|
|
|
TArray<FString> EnumValues; |
|
|
|
|
|
CollectEnumValues(Inner, EnumValues); |
|
|
|
|
|
|
|
|
|
|
|
TArray<TSharedPtr<FJsonValue>> JsonEnumVals; |
|
|
|
|
|
for (const FString& V : EnumValues) |
|
|
|
|
|
{ |
|
|
|
|
|
JsonEnumVals.Add(MakeShared<FJsonValueString>(V)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Keep flat style: itemsEnum mirrors "enum" of single fields
|
|
|
|
|
|
FieldObj->SetArrayField(TEXT("itemsEnum"), JsonEnumVals); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// If item is a struct: list sub-variables + their types (no tooltips)
|
|
|
|
|
|
if (InnerType == TEXT("struct")) |
|
|
|
|
|
{ |
|
|
|
|
|
if (const FStructProperty* InnerStructProp = CastField<FStructProperty>(Inner)) |
|
|
|
|
|
{ |
|
|
|
|
|
TSharedPtr<FJsonObject> ItemsFieldsObj = MakeShared<FJsonObject>(); |
|
|
|
|
|
|
|
|
|
|
|
// Same as for single struct fields, but nested under itemsFields
|
|
|
|
|
|
for (TFieldIterator<FProperty> SubIt(InnerStructProp->Struct); SubIt; ++SubIt) |
|
|
|
|
|
{ |
|
|
|
|
|
const FProperty* SubProp = *SubIt; |
|
|
|
|
|
const FString SubName = SubProp->GetAuthoredName(); |
|
|
|
|
|
const FString SubType = GetSchemaType(SubProp); |
|
|
|
|
|
|
|
|
|
|
|
TSharedPtr<FJsonObject> SubFieldObj = MakeShared<FJsonObject>(); |
|
|
|
|
|
SubFieldObj->SetStringField(TEXT("type"), SubType); |
|
|
|
|
|
|
|
|
|
|
|
ItemsFieldsObj->SetObjectField(SubName, SubFieldObj); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Flat style to match arrays: provide fields for items
|
|
|
|
|
|
FieldObj->SetObjectField(TEXT("itemsFields"), ItemsFieldsObj); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// push this variable object wrapped under its variable name key
|
|
|
// push this variable object wrapped under its variable name key
|
|
|
{ |
|
|
{ |
|
|
TSharedPtr<FJsonObject> Wrapper = MakeShared<FJsonObject>(); |
|
|
TSharedPtr<FJsonObject> Wrapper = MakeShared<FJsonObject>(); |
|
|
|