// 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 EDITORCONFIG_API FJsonPath { public: struct FPart { FString Name; int32 Index = INDEX_NONE; }; FJsonPath(); FJsonPath(const TCHAR* Path); FJsonPath(FStringView Path); FJsonPath(const FJsonPath& Other); FJsonPath(FJsonPath&& Other); bool IsValid() const { return Length() > 0; } const int32 Length() const { return PathParts.Num(); } void Append(FStringView Name); void SetArrayIndex(int32 Index); FJsonPath GetSubPath(int32 NumParts) const; FString ToString() const; const FPart& operator[](int32 Idx) const { return PathParts[Idx]; } const TArray& GetAll() const { return PathParts; } private: void ParsePath(const FString& InPath); private: TArray PathParts; }; using FJsonValuePair = TPair, TSharedPtr>; class EDITORCONFIG_API FJsonConfig { public: FJsonConfig(); void SetParent(const TSharedPtr& Parent); bool LoadFromFile(FStringView FilePath); bool LoadFromString(FStringView Content); bool SaveToFile(FStringView FilePath) const; bool SaveToString(FString& OutResult) const; bool IsValid() const { return MergedObject.IsValid(); } const FJsonConfig* GetParentConfig() const; template bool TryGetNumber(const FJsonPath& Path, T& OutValue) const; bool TryGetBool(const FJsonPath& Path, bool& OutValue) const; bool TryGetString(const FJsonPath& Path, FString& OutValue) const; bool TryGetString(const FJsonPath& Path, FName& OutValue) const; bool TryGetString(const FJsonPath& Path, FText& OutValue) const; bool TryGetJsonValue(const FJsonPath& Path, TSharedPtr& OutValue) const; bool TryGetJsonObject(const FJsonPath& Path, TSharedPtr& OutValue) const; bool TryGetArray(const FJsonPath& Path, TArray>& OutArray) const; 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 bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; bool TryGetArray(const FJsonPath& Path, TArray& OutArray) const; 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); bool SetBool(const FJsonPath& Path, bool Value); bool SetString(const FJsonPath& Path, FStringView Value); bool SetString(const FJsonPath& Path, const FText& Value); bool SetJsonValue(const FJsonPath& Path, const TSharedPtr& Value); bool SetJsonObject(const FJsonPath& Path, const TSharedPtr& Object); bool SetJsonArray(const FJsonPath& Path, const TArray>& Array); bool SetRootObject(const TSharedPtr& Object); 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; bool SetJsonValueInMerged(const FJsonPath& Path, const TSharedPtr& Value); bool SetJsonValueInOverride(const FJsonPath& Path, const TSharedPtr& NewValue, const TSharedPtr& PreviousValue, const TSharedPtr& ParentValue); bool SetArrayValueInOverride(const TSharedPtr& CurrentValue, const TArray>& NewArray, const TSharedPtr& ParentValue); bool SetObjectValueInOverride(const TSharedPtr& CurrentObject, const TSharedPtr& NewObject, const TSharedPtr& ParentValue); bool RemoveJsonValueFromOverride(const FJsonPath& Path, const TSharedPtr& PreviousValue); bool MergeThisWithParent(); void OnParentConfigChanged(); private: TFuture SaveFuture; FSimpleDelegate OnConfigChanged; TSharedPtr ParentConfig; TSharedPtr OverrideObject; TSharedPtr MergedObject; }; } #include "JsonConfig.inl" // IWYU pragma: export