// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Engine/AssetManager.h" #include "Engine/DataAsset.h" #include "LyraAssetManagerStartupJob.h" #include "LyraAssetManager.generated.h" 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(Config = Game) class ULyraAssetManager : public UAssetManager { GENERATED_BODY() public: ULyraAssetManager(); // Returns the AssetManager singleton object. static 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 void DumpLoadedAssets(); const ULyraGameData& GetGameData(); const ULyraPawnData* GetDefaultPawnData() const; protected: template const GameDataClass& GetOrLoadTypedGameData(const TSoftObjectPtr& DataPath) { if (const UPrimaryDataAsset* 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 UObject* SynchronousLoadAsset(const FSoftObjectPath& AssetPath); static bool ShouldLogAssetLoads(); // Thread safe way of adding a loaded asset to keep in memory. void AddLoadedAsset(const UObject* Asset); //~UAssetManager interface virtual void StartInitialLoading() override; #if WITH_EDITOR virtual void PreBeginPIE(bool bStartSimulate) override; #endif //~End of UAssetManager interface 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 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. void DoAllStartupJobs(); // Sets up the ability system void InitializeAbilitySystem(); void InitializeGameplayCueManager(); // Called periodically during loads, could be used to feed the status to a loading screen 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; }