// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Subsystems/GameInstanceSubsystem.h" #include "GameplayTagContainer.h" #include "Audio.h" #include "SoundscapeColorPoint.h" #include "SoundscapeSubsystem.generated.h" class USoundscapePalette; class UActiveSoundscapePalette; struct FStreamableHandle; DECLARE_LOG_CATEGORY_EXTERN(LogSoundscapeSubsystem, Log, All); // Struct USTRUCT(BlueprintType) struct SOUNDSCAPE_API FSoundscapePaletteCollection { GENERATED_BODY() // Soundscape Palette Collection UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Soundscape|Palette", meta = (AllowedClasses = "/Script/Soundscape.SoundscapePalette")) TSet SoundscapePaletteCollection; }; // Struct USTRUCT() struct SOUNDSCAPE_API FSoundscapePaletteCollectionLoaded { GENERATED_BODY() // Soundscape Palette Collection UPROPERTY(EditAnywhere, Category = "Soundscape|Palette") TSet> SoundscapePaletteCollection; }; // Struct USTRUCT(BlueprintType) struct SOUNDSCAPE_API FSoundscapeColorPointCollection { GENERATED_BODY() // Soundscape Color Point Collection UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Soundscape|ColorPoint") TArray ColorPointCollection; }; // Class UCLASS() class SOUNDSCAPE_API USoundscapeColorPointHashCellDensity : public UObject { GENERATED_BODY() public: // Soundscape Color Point Density for a Hash Cell UPROPERTY(EditAnywhere, Category = "Soundscape|ColorPoint") TMap ColorPointHashCellDensity; }; UCLASS() class SOUNDSCAPE_API USoundscapeColorPointHashMap : public UObject { GENERATED_BODY() public: // Clears and initializes hash map, sizes grid to HashCellWidth in Uunits UFUNCTION() void InitializeHash(float HashCellSizeIn, FVector GridCenterIn); // Clears hash map UFUNCTION() void ClearHash(); // Returns the number of ColorPoints in a Cell containing the Location UFUNCTION() int32 NumColorPointsInCell(const FVector& Location, const FGameplayTag ColorPoint); // Returns true if ColorPoint added to hash, false if failed (likely location is out of Hash Bounds) UFUNCTION() bool AddColorPointToHash(const FVector& Location, const FGameplayTag ColorPoint); // Returns true if ColorPoint added to hash, false if failed (likely location is out of Hash Bounds) UFUNCTION() void AddColorPointArrayToHash(const TArray& Locations, const FGameplayTag ColorPoint); // Calculates Hash Index UFUNCTION() uint64 CalculateHashIndex(const FVector& Location); // Sets ceterpoint of grid to Location UFUNCTION() void SetGridCenterpoint(const FVector& Location); TMap GetHashMapColorPointDensitySummary(); protected: // Returns ColorPointDensityMap from Hash Map given a Color Point USoundscapeColorPointHashCellDensity* GetColorPointDensityMap(FGameplayTag ColorPoint); private: // Color Point Hash Map UPROPERTY() TMap> ColorPointHashMap; // Cubic Root of the Max Value of int64 rounded down to the nearest million static const int32 MaxGridWidth = 2000000; static const int32 HalfMaxGridWidth = 1000000; // Hash Cell Width UPROPERTY() float HashCellSize = 500.0f; // MaxGridWidth / Hash Cell Size UPROPERTY() int32 GridWidth = 4000; // Grid Width Cubed UPROPERTY() int64 NumCells = 64000000000; // Cell Size Inverted UPROPERTY() float HashCellFactor = 0.002f; // Current Grid Centerpoint UPROPERTY() FVector GridCenter; // Grid Origin Offset UPROPERTY() FVector GridOriginOffset; public: const FVector GetHashCellCenterpoint(FVector Location); const float GetHashCellWidth(); }; UENUM() enum class ESoundscapeLOD : uint8 { LOD1 = 0 UMETA(DisplayName = "LOD 1"), LOD2 UMETA(DisplayName = "LOD 2"), LOD3 UMETA(DisplayName = "LOD 3") }; UCLASS() class SOUNDSCAPE_API USoundscapeColorPointHashMapCollection : public UObject { GENERATED_BODY() public: void InitializeCollection(); void AddColorPointArrayToHashMapCollection(const TArray& Locations, const FGameplayTag ColorPoint); void ClearColorPointHashMapCollection(); int32 GetColorPointHashMapCollectionDensity(const FVector Location, const FGameplayTag ColorPoint, const ESoundscapeLOD SoundscapeLOD); public: void CalculateTotalColorPointDensity(TMap& TotalHashMapColorPointDensity, ESoundscapeLOD SoundscapeLOD); private: // Color Point Hash Maps UPROPERTY() TObjectPtr ColorPointHashMapLOD1; UPROPERTY() TObjectPtr ColorPointHashMapLOD2; UPROPERTY() TObjectPtr ColorPointHashMapLOD3; // Hash Cell Width for LOD1 UPROPERTY() float LOD1ColorPointHashWidth = 500.0f; // Hash Cell LOD1 Max Distance UPROPERTY() float LOD1ColorPointHashDistance = 5000.0f; // Hash Cell Width for LOD2 UPROPERTY() float LOD2ColorPointHashWidth = 2500.0f; // Hash Cell LOD2 Max Distance UPROPERTY() float LOD2ColorPointHashDistance = 10000.0f; // Hash Cell Width for LOD3 UPROPERTY() float LOD3ColorPointHashWidth = 10000.0f; }; /** * */ UCLASS() class SOUNDSCAPE_API USoundscapeSubsystem : public UGameInstanceSubsystem { GENERATED_BODY() public: // Begin USubsystem virtual void Initialize(FSubsystemCollectionBase& Collection) override; virtual void Deinitialize() override; virtual bool ShouldCreateSubsystem(UObject* Outer) const override; // End USubsystem // Settings public: UFUNCTION(BlueprintCallable, Category = "Soundscape") void SetState(FGameplayTag SoundscapeState); UFUNCTION(BlueprintCallable, Category = "Soundscape") void ClearState(FGameplayTag SoundscapeState); UFUNCTION(BlueprintCallable, Category = "Soundscape") void RestartSoundscape(); UFUNCTION(BlueprintCallable, Category = "Soundscape") bool AddPaletteCollection(FName PaletteCollectionName, FSoundscapePaletteCollection PaletteCollection); UFUNCTION(BlueprintCallable, Category = "Soundscape") bool RemovePaletteCollection(FName PaletteCollectionName); bool bDebugMode = false; private: UPROPERTY() TSet> LoadedPaletteCollectionSet; UPROPERTY() TMap UnloadedPaletteCollections; FGameplayTagContainer SubsystemState; UPROPERTY() TMap, TObjectPtr> ActivePalettes; // Start Asynchronous Loading bool LoadPaletteCollection(FName PaletteCollectionName); void CompleteAsyncLoading(FName PaletteCollectionName); TMap> ActiveAssetLoadHandles; bool UnloadPaletteCollection(FName PaletteCollectionName); void UpdateState(); private: Audio::FDeviceId AudioDeviceID; // Soundscape Color Point system public: // Add a Color Point Collection to the Subsystem, returns true if successful UFUNCTION(BlueprintCallable, Category = "Soundscape") void AddColorPointCollection(FName ColorPointCollectionName, FSoundscapeColorPointCollection ColorPointCollection); // Remove a Color Point Collection from the Subsystem, returns true if successful UFUNCTION(BlueprintCallable, Category = "Soundscape") bool RemoveColorPointCollection(FName ColorPointCollectionName); // Check Color Point Density for a Location Cell UFUNCTION(BlueprintCallable, Category = "Soundscape") int32 CheckColorPointDensity(FVector Location, FGameplayTag ColorPoint); // Add Hash Map Collection void AddColorPointHashMapCollection(USoundscapeColorPointHashMapCollection* ColorPointHashMapCollection); // Add Hash Map Collection bool RemoveColorPointHashMapCollection(USoundscapeColorPointHashMapCollection* ColorPointHashMapCollection); // Draw Debug Cell void DrawDebugCell(FVector Location, bool bSuccess); // Calculate Debug Cell Dimensions TPair CalculateDebugCellDimensions(FVector Location, ESoundscapeLOD SoundscapeLOD); // Add Active Color Point void AddActiveColorPoint(const USoundscapeColorPointComponent* SoundscapeColorPointComponent); // Remove Active Color Point void RemoveActiveColorPoint(const USoundscapeColorPointComponent* SoundscapeColorPointComponent); private: // Stored Hash Map Collections UPROPERTY(Transient) TArray> ColorPointHashMapCollections; // Stored Color Point Collections TMap ColorPointCollections; // Active Color Point Collection FSoundscapeColorPointCollection ActiveColorPointCollection; // Color Point Hash Maps UPROPERTY() TObjectPtr ColorPointHashMapLOD1; UPROPERTY() TObjectPtr ColorPointHashMapLOD2; UPROPERTY() TObjectPtr ColorPointHashMapLOD3; UPROPERTY() TObjectPtr ActiveColorPointHashMap; // Hash Cell Width for LOD1 float LOD1ColorPointHashWidth = 500.0f; // Hash Cell LOD1 Max Distance float LOD1ColorPointHashDistance = 5000.0f; // Hash Cell Width for LOD2 float LOD2ColorPointHashWidth = 2500.0f; // Hash Cell LOD2 Max Distance float LOD2ColorPointHashDistance = 10000.0f; // Hash Cell Width for LOD3 float LOD3ColorPointHashWidth = 10000.0f; // Hash Cell Width for the Active Hash float ActiveColorPointHashWidth = 500.0f; // Hash Cell Update Timing for the Active Hash float ActiveColorPointHashUpdateTimeSeconds = 1.0f; // Update Hash Map void UpdateColorPointHashMap(USoundscapeColorPointHashMap& SoundscapeColorPointHashMap); // Update Active Hash Map void UpdateActiveColorPointHashMap(); // Timer delegate for amortized updates FTimerHandle ActiveColorPointUpdateTimer; // Active Color Point Components TArray ActiveSoundscapeColorPointComponents; };