Hello. This is my solution.
Short description.
Short code.
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FOnVolumeChanged, USoundBase*, Sound, const TArray&, NewVolume, FVector, Vector, int, Id);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnSoundAdded, USoundBase*, Sound, FVector, Vector, int, Id);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FOnSoundRemoved, USoundBase*, Sound, FVector, Vector, int, Id);
UCLASS(Blueprintable)
class MAGIC_API UMySoundListenerSubsystem : public UAudioEngineSubsystem
, public IActiveSoundUpdateInterface
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintAssignable, Category = "Audio")
FOnVolumeChanged OnVolumeChanged;
UPROPERTY(BlueprintAssignable, Category = "Audio")
FOnSoundAdded OnSoundAdded;
UPROPERTY(BlueprintAssignable, Category = "Audio")
FOnSoundRemoved OnSoundRemoved;
virtual bool ShouldCreateSubsystem(UObject* Outer) const override
{
return !IsRunningDedicatedServer();
}
virtual void Update() override;
virtual void OnNotifyAddActiveSound(FActiveSound& ActiveSound) override;
virtual void OnNotifyPendingDelete(const FActiveSound& ActiveSound) override;
TArray<FActiveSound*> ActiveSounds;
};
void UMySoundListenerSubsystem::Update()
{
for (FActiveSound* ActiveSound : ActiveSounds)
{
uint32 ID = ActiveSound->GetObjectId();
FVector Position = ActiveSound->LastLocation;
USoundBase* SoundBase = ActiveSound->GetSound();
TArray Volumes;
TMap<UPTRINT, FWaveInstance*> Waves = ActiveSound->GetWaveInstances();
for (TPair<UPTRINT, FWaveInstance*> Pair : Waves)
{
Volumes.Add(Pair.Value->GetActualVolume());
}
AsyncTask(ENamedThreads::GameThread, [this, Volumes, SoundBase, Position, ID]()
{
OnVolumeChanged.Broadcast(SoundBase, Volumes, Position, ID);
});
}
}
void UMySoundListenerSubsystem::OnNotifyAddActiveSound(FActiveSound& ActiveSound)
{
uint32 ID = ActiveSound.GetObjectId();
FVector Position = ActiveSound.LastLocation;
USoundBase* SoundBase = ActiveSound.GetSound();
if (!SoundBase)
{
UE_LOG(LogTemp, Warning, TEXT("ActiveSound does not have a valid SoundBase!"));
return;
}
ActiveSounds.Add(&ActiveSound);
AsyncTask(ENamedThreads::GameThread, [this, SoundBase, Position, ID]()
{
OnSoundAdded.Broadcast(SoundBase, Position, ID);
});
}
void UMySoundListenerSubsystem::OnNotifyPendingDelete(const FActiveSound& ActiveSound)
{
uint32 ID = ActiveSound.GetObjectId();
FVector Position = ActiveSound.LastLocation;
USoundBase* SoundBase = ActiveSound.GetSound();
if (!SoundBase)
{
UE_LOG(LogTemp, Warning, TEXT("ActiveSound does not have a valid SoundBase!"));
return;
}
FActiveSound* RemoveActiveSound = const_cast<FActiveSound*>(&ActiveSound);
ActiveSounds.Remove(RemoveActiveSound);
AsyncTask(ENamedThreads::GameThread, [this, SoundBase, Position, ID]()
{
OnSoundRemoved.Broadcast(SoundBase, Position, ID);
});
}