#include "Core/DescentEnvQuery.h" #include "Core/DescentMath.h" #include "Debug/DescentStateRegistry.h" #include "TheDescent.h" #include "Engine/World.h" UDescentEnvQuerySubsystem* UDescentEnvQuerySubsystem::Get(const UWorld* World) { return World ? World->GetSubsystem() : nullptr; } FDescentHandle UDescentEnvQuerySubsystem::RegisterDryVolume(FName Owner, FDryVolumeFn IsInside, double TemperatureC) { FDescentHandle Handle; if (!IsInside) { UE_LOG(LogDescent, Error, TEXT("EnvQuery: dry volume of '%s' has an empty function"), *Owner.ToString()); return Handle; } FVolume V; V.Id = NextId++; V.Owner = Owner; V.IsInside = MoveTemp(IsInside); V.TemperatureC = TemperatureC; Handle.Id = V.Id; Volumes.Add(MoveTemp(V)); Volumes.StableSort([](const FVolume& A, const FVolume& B) { const int32 C = A.Owner.Compare(B.Owner); return C != 0 ? C < 0 : A.Id < B.Id; }); return Handle; } bool UDescentEnvQuerySubsystem::UnregisterDryVolume(FDescentHandle Handle) { if (!Handle.IsValid()) { return false; } return Volumes.RemoveAll([&](const FVolume& V) { return V.Id == Handle.Id; }) > 0; } TArray UDescentEnvQuerySubsystem::GetDryVolumeOwners() const { TArray Out; for (const FVolume& V : Volumes) { Out.Add(V.Owner); } return Out; } bool UDescentEnvQuerySubsystem::IsDry(const FVector& WorldUU) const { for (const FVolume& V : Volumes) { if (V.IsInside(WorldUU)) { return true; } } return false; } bool UDescentEnvQuerySubsystem::IsDryAtMetres(const FVector& WorldM) const { return IsDry(Descent::MetresToUU(WorldM)); } double UDescentEnvQuerySubsystem::AmbientTemperatureC(const FVector& WorldUU) const { for (const FVolume& V : Volumes) { if (V.IsInside(WorldUU)) { return V.TemperatureC; } } return WaterTemperatureC(Descent::DepthOfWorldUU(WorldUU)); } double UDescentEnvQuerySubsystem::AmbientTemperatureAtMetres(const FVector& WorldM) const { return AmbientTemperatureC(Descent::MetresToUU(WorldM)); } double UDescentEnvQuerySubsystem::WaterTemperatureC(double DepthM) { namespace T = Descent::Tune::Env; return T::WaterBaseC + T::WaterRiseC * Descent::Clamp((DepthM - T::WaterRiseStartDepthM) / T::WaterRiseSpanM, 0.0, 1.0) + (DepthM > T::WaterStepDepthM ? T::WaterStepAddC : 0.0); } namespace Descent { bool IsDry(const UWorld* World, const FVector& WorldUU) { const UDescentEnvQuerySubsystem* Q = UDescentEnvQuerySubsystem::Get(World); return Q && Q->IsDry(WorldUU); } double AmbientTemperatureAt(const UWorld* World, const FVector& WorldUU) { const UDescentEnvQuerySubsystem* Q = UDescentEnvQuerySubsystem::Get(World); return Q ? Q->AmbientTemperatureC(WorldUU) : UDescentEnvQuerySubsystem::WaterTemperatureC(DepthOfWorldUU(WorldUU)); } } // --------------------------------------------------------------------------------------------------------- // State section "env_query": who provides dry space. (The `env` section of the design is the look track's.) // --------------------------------------------------------------------------------------------------------- static FDescentStateProviderRegistrar GEnvQuerySection(TEXT("env_query"), [](UWorld* World, FJsonObject& Out) { const UDescentEnvQuerySubsystem* Q = UDescentEnvQuerySubsystem::Get(World); Out.SetBoolField(TEXT("available"), Q != nullptr); TArray> Owners; if (Q) { for (const FName& Owner : Q->GetDryVolumeOwners()) { Owners.Add(MakeShared(Owner.ToString())); } } Out.SetArrayField(TEXT("dry_volume_owners"), Owners); Out.SetNumberField(TEXT("dry_cabin_temperature_c"), Descent::Tune::Env::DryCabinTemperatureC); });