// Copyright IHY. Vertical Partition Streaming plugin. // // Pure cell math shared by the editor builder and the runtime streamer. No state. #pragma once #include "CoreMinimal.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "VerticalPartitionTypes.h" #include "VerticalPartitionStatics.generated.h" /** Context the desired-state policy needs beyond the raw cell index. */ struct FVerticalStreamingContext { int32 PlayerCellZ = 0; int32 PlayerCellX = 0; int32 PlayerCellY = 0; float PlayerVelocityZ = 0.f; // cm/s, +up float PlayerWorldZ = 0.f; // cm, exact (for hysteresis at boundaries) float CameraPitchDeg = 0.f; // +looking up bool bUseXY = false; }; UCLASS() class VERTICALPARTITION_API UVerticalPartitionStatics : public UBlueprintFunctionLibrary { GENERATED_BODY() public: /** Z index of a world Z (cm) relative to the volume floor. */ UFUNCTION(BlueprintPure, Category="VerticalPartition") static int32 GetCellZFromWorldZ(float WorldZ, float VolumeMinZ, float CellHeight); UFUNCTION(BlueprintPure, Category="VerticalPartition") static int32 GetCellXFromWorldX(float WorldX, float VolumeMinX, float XYCellSize); UFUNCTION(BlueprintPure, Category="VerticalPartition") static int32 GetCellYFromWorldY(float WorldY, float VolumeMinY, float XYCellSize); /** Cell id for a single point (actor origin). */ static FVerticalCellId GetCellIdFromPoint(const FVector& Point, const FBox& VolumeBounds, const FVerticalPartitionSettings& S); /** Cell id for a bounds box. Uses the dominant-overlap cell (center of the * clamped intersection) so a box straddling a boundary lands deterministically. * bOutCrossesMultiple reports whether the box spans more than one cell. */ static FVerticalCellId GetCellIdFromBounds(const FBox& ActorBounds, const FBox& VolumeBounds, const FVerticalPartitionSettings& S, bool& bOutCrossesMultiple); /** World-space bounds of a cell, clamped to the volume when requested. */ static FBox GetCellBounds(const FVerticalCellId& Cell, const FBox& VolumeBounds, const FVerticalPartitionSettings& S); /** Number of Z cells the volume spans (>=1). */ static int32 GetNumZCells(const FBox& VolumeBounds, const FVerticalPartitionSettings& S); /** THE policy. Maps a cell relative to the player to its desired representation, * honouring full/preload/HLOD/unload bands, hysteresis, velocity prediction, * fall-risk-below, camera direction and the above-player priority bias. * CurrentState is the cell's live state and is what makes hysteresis sticky. */ static EVerticalCellDesiredState GetDesiredStateForCell( const FVerticalCellId& Cell, const FVerticalStreamingContext& Ctx, const FVerticalPartitionSettings& S, EVerticalCellState CurrentState = EVerticalCellState::Unloaded); /** True when a cell sits in the preload band (load full data, keep it hidden). */ static bool ShouldPreloadFull(const FVerticalCellId& Cell, const FVerticalStreamingContext& Ctx, const FVerticalPartitionSettings& S); /** Human-readable colour for a runtime state (debug draw / overlay). */ UFUNCTION(BlueprintPure, Category="VerticalPartition") static FLinearColor GetStateColor(EVerticalCellState State); UFUNCTION(BlueprintPure, Category="VerticalPartition") static FString WarningTypeToString(EVerticalWarningType Type); };