// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Async/Async.h" #include "Async/Future.h" #include "Concepts/EqualityComparable.h" #include "Containers/Array.h" #include "Containers/Map.h" #include "Containers/StringFwd.h" #include "Containers/StringView.h" #include "Containers/UnrealString.h" #include "CoreMinimal.h" #include "CoreTypes.h" #include "Delegates/Delegate.h" #include "Dom/JsonObject.h" #include "Templates/SharedPointer.h" class FJsonObject; class FJsonValue; class FName; class FText; namespace UE { class FJsonPath { public: struct FPart { FString Name; int32 Index = INDEX_NONE; }; EDITORCONFIG_API FJsonPath(); EDITORCONFIG_API FJsonPath(const TCHAR* Path); EDITORCONFIG_API FJsonPath(FStringView Path); EDITORCONFIG_API FJsonPath(const FJsonPath& Other); EDITORCONFIG_API FJsonPath(FJsonPath&& Other); bool IsValid() const { return Length() > 0; } const int32 Length() const { return PathParts.Num(); } EDITORCONFIG_API void Append(FStringView Name); EDITORCONFIG_API void SetArrayIndex(int32 Index); EDITORCONFIG_API FJsonPath GetSubPath(int32 NumParts) const; EDITORCONFIG_API FString ToString() const; const FPart& operator[](int32 Idx) const { return PathParts[Idx]; } const TArray& GetAll() const { return PathParts; } private: EDITORCONFIG_API void ParsePath(const FString& InPath); private: TArray PathParts; }; using FJsonValuePair = TPair, TSharedPtr>; class FJsonConfig { public: EDITORCONFIG_API FJsonConfig(); EDITORCONFIG_API void SetParent(const TSharedPtr& Parent); EDITORCONFIG_API bool LoadFromFile(FStringView FilePath); EDITORCONFIG_API bool LoadFromString(FStringView Content); EDITORCONFIG_API bool SaveToFile(FStringView FilePath) const; EDITORCONFIG_API bool SaveToString(FString& OutResult) const; bool IsValid() const { return MergedObject.IsValid(); } EDITORCONFIG_API const FJsonConfig* GetParentConfig() const; template bool TryGetNumber(const FJsonPath& Path, T& OutValue) const; EDITORCONFIG_API bool TryGetBool(const FJsonPath& Path, bool& OutValue) const; EDITORCONFIG_API bool TryGetString(const FJsonPath& Path, FString& OutValue) const; EDITORCONFIG_API bool TryGetString(const FJsonPath& Path, FName& OutValue) const; EDITORCONFIG_API bool TryGetString(const FJsonPath& Path, FText& OutValue) const; EDITORCONFIG_API bool TryGetJsonValue(const FJsonPath& Path, TSharedPtr& OutValue) const; EDITORCONFIG_API bool TryGetJsonObject(const FJsonPath& Path, TSharedPtr& OutValue) const; EDITORCONFIG_API bool TryGetArray(const FJsonPath& Path, TArray>& OutArray) const; EDITORCONFIG_API TSharedPtr GetRootObject() const; // these are specializations for arithmetic and string arrays // these could be templated with enable-ifs, // but it ended up being more lines of incomprehensible template SFINAE than this clear list of types is EDITORCONFIG_API bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; EDITORCONFIG_API bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; EDITORCONFIG_API bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; EDITORCONFIG_API bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; EDITORCONFIG_API bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; EDITORCONFIG_API bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; EDITORCONFIG_API bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; EDITORCONFIG_API bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; EDITORCONFIG_API bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; EDITORCONFIG_API bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; EDITORCONFIG_API bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; EDITORCONFIG_API bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; EDITORCONFIG_API bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; EDITORCONFIG_API bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; EDITORCONFIG_API bool TryGetMap(const FJsonPath& Path, TArray& OutMap) const; // try to set a number - returns false if: // - the path references an object that doesn't exist // - the path references an index in an array that doesn't exist template bool SetNumber(const FJsonPath& Path, T Value); EDITORCONFIG_API bool SetBool(const FJsonPath& Path, bool Value); EDITORCONFIG_API bool SetString(const FJsonPath& Path, FStringView Value); EDITORCONFIG_API bool SetString(const FJsonPath& Path, const FText& Value); EDITORCONFIG_API bool SetJsonValue(const FJsonPath& Path, const TSharedPtr& Value); EDITORCONFIG_API bool SetJsonObject(const FJsonPath& Path, const TSharedPtr& Object); EDITORCONFIG_API bool SetJsonArray(const FJsonPath& Path, const TArray>& Array); EDITORCONFIG_API bool SetRootObject(const TSharedPtr& Object); EDITORCONFIG_API bool HasOverride(const FJsonPath& Path) const; private: template bool TryGetArrayHelper(const FJsonPath& Path, TArray& OutArray, TGetter Getter) const; template bool TryGetNumericArrayHelper(const FJsonPath& Path, TArray& OutArray) const; EDITORCONFIG_API bool SetJsonValueInMerged(const FJsonPath& Path, const TSharedPtr& Value); EDITORCONFIG_API bool SetJsonValueInOverride(const FJsonPath& Path, const TSharedPtr& NewValue, const TSharedPtr& PreviousValue, const TSharedPtr& ParentValue); EDITORCONFIG_API bool SetArrayValueInOverride(const TSharedPtr& CurrentValue, const TArray>& NewArray, const TSharedPtr& ParentValue); EDITORCONFIG_API bool SetObjectValueInOverride(const TSharedPtr& CurrentObject, const TSharedPtr& NewObject, const TSharedPtr& ParentValue); EDITORCONFIG_API bool RemoveJsonValueFromOverride(const FJsonPath& Path, const TSharedPtr& PreviousValue); EDITORCONFIG_API bool MergeThisWithParent(); EDITORCONFIG_API void OnParentConfigChanged(); private: TFuture SaveFuture; FSimpleDelegate OnConfigChanged; TSharedPtr ParentConfig; TSharedPtr OverrideObject; TSharedPtr MergedObject; }; } #include "JsonConfig.inl" // IWYU pragma: export