// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "Engine/AssetManager.h" #include "LyraAssetManagerStartupJob.h" #include "Templates/SubclassOf.h" #include "LyraAssetManager.generated.h" #define UE_API LYRAGAME_API class UPrimaryDataAsset; class ULyraGameData; class ULyraPawnData; struct FLyraBundles { static const FName Equipped; }; /** * ULyraAssetManager * * Game implementation of the asset manager that overrides functionality and stores game-specific types. * It is expected that most games will want to override AssetManager as it provides a good place for game-specific loading logic. * This class is used by setting 'AssetManagerClassName' in DefaultEngine.ini. */ UCLASS(MinimalAPI, Config = Game) class ULyraAssetManager : public UAssetManager { GENERATED_BODY() public: UE_API ULyraAssetManager(); // Returns the AssetManager singleton object. static UE_API ULyraAssetManager& Get(); // Returns the asset referenced by a TSoftObjectPtr. This will synchronously load the asset if it's not already loaded. template static AssetType* GetAsset(const TSoftObjectPtr& AssetPointer, bool bKeepInMemory = true); // Returns the subclass referenced by a TSoftClassPtr. This will synchronously load the asset if it's not already loaded. template static TSubclassOf GetSubclass(const TSoftClassPtr& AssetPointer, bool bKeepInMemory = true); // Logs all assets currently loaded and tracked by the asset manager. static UE_API void DumpLoadedAssets(); UE_API const ULyraGameData& GetGameData(); UE_API const ULyraPawnData* GetDefaultPawnData() const; protected: template const GameDataClass& GetOrLoadTypedGameData(const TSoftObjectPtr& DataPath) { if (TObjectPtr const * pResult = GameDataMap.Find(GameDataClass::StaticClass())) { return *CastChecked(*pResult); } // Does a blocking load if needed return *CastChecked(LoadGameDataOfClass(GameDataClass::StaticClass(), DataPath, GameDataClass::StaticClass()->GetFName())); } static UE_API UObject* SynchronousLoadAsset(const FSoftObjectPath& AssetPath); static UE_API bool ShouldLogAssetLoads(); // Thread safe way of adding a loaded asset to keep in memory. UE_API void AddLoadedAsset(const UObject* Asset); //~UAssetManager interface UE_API virtual void StartInitialLoading() override; #if WITH_EDITOR UE_API virtual void PreBeginPIE(bool bStartSimulate) override; #endif //~End of UAssetManager interface UE_API UPrimaryDataAsset* LoadGameDataOfClass(TSubclassOf DataClass, const TSoftObjectPtr& DataClassPath, FPrimaryAssetType PrimaryAssetType); protected: // Global game data asset to use. UPROPERTY(Config) TSoftObjectPtr LyraGameDataPath; // Loaded version of the game data UPROPERTY(Transient) TMap, TObjectPtr> GameDataMap; // Pawn data used when spawning player pawns if there isn't one set on the player state. UPROPERTY(Config) TSoftObjectPtr DefaultPawnData; private: // Flushes the StartupJobs array. Processes all startup work. UE_API void DoAllStartupJobs(); // Sets up the ability system UE_API void InitializeGameplayCueManager(); // Called periodically during loads, could be used to feed the status to a loading screen UE_API void UpdateInitialGameContentLoadPercent(float GameContentPercent); // The list of tasks to execute on startup. Used to track startup progress. TArray StartupJobs; private: // Assets loaded and tracked by the asset manager. UPROPERTY() TSet> LoadedAssets; // Used for a scope lock when modifying the list of load assets. FCriticalSection LoadedAssetsCritical; }; template AssetType* ULyraAssetManager::GetAsset(const TSoftObjectPtr& AssetPointer, bool bKeepInMemory) { AssetType* LoadedAsset = nullptr; const FSoftObjectPath& AssetPath = AssetPointer.ToSoftObjectPath(); if (AssetPath.IsValid()) { LoadedAsset = AssetPointer.Get(); if (!LoadedAsset) { LoadedAsset = Cast(SynchronousLoadAsset(AssetPath)); ensureAlwaysMsgf(LoadedAsset, TEXT("Failed to load asset [%s]"), *AssetPointer.ToString()); } if (LoadedAsset && bKeepInMemory) { // Added to loaded asset list. Get().AddLoadedAsset(Cast(LoadedAsset)); } } return LoadedAsset; } template TSubclassOf ULyraAssetManager::GetSubclass(const TSoftClassPtr& AssetPointer, bool bKeepInMemory) { TSubclassOf LoadedSubclass; const FSoftObjectPath& AssetPath = AssetPointer.ToSoftObjectPath(); if (AssetPath.IsValid()) { LoadedSubclass = AssetPointer.Get(); if (!LoadedSubclass) { LoadedSubclass = Cast(SynchronousLoadAsset(AssetPath)); ensureAlwaysMsgf(LoadedSubclass, TEXT("Failed to load asset class [%s]"), *AssetPointer.ToString()); } if (LoadedSubclass && bKeepInMemory) { // Added to loaded asset list. Get().AddLoadedAsset(Cast(LoadedSubclass)); } } return LoadedSubclass; } #undef UE_API