// © 2025 Naked People Team. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Subsystems/WorldSubsystem.h" #include "PlayerPreviewCaptureSubsystem.generated.h" DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnPreviewCaptureActiveChanged, bool, bActive); /** * Message bus between the equipment/inventory UI (C++) and the player-preview * sublevel that renders the impostor into a SceneCapture2D for the equipment panel. * * The capture is expensive, so it must run only while the panel is open. The preview * level's Level Blueprint owns the actual 30fps capture loop; it binds to * OnPreviewCaptureActiveChanged to start/stop that loop. The UI flips the state via * SetPreviewActive when the inventory screen activates / deactivates. * * A world subsystem is shared across the persistent level and its streamed sublevels, * so the preview level and the main UI talk through the same instance without either * needing a hard reference to the other. */ UCLASS() class NAKEDDESIRE_API UPlayerPreviewCaptureSubsystem : public UWorldSubsystem { GENERATED_BODY() public: // Called by the inventory/equipment UI on open (true) and close (false). UFUNCTION(BlueprintCallable, Category = "Preview") void SetPreviewActive(bool bActive); UFUNCTION(BlueprintPure, Category = "Preview") bool IsPreviewActive() const { return bPreviewActive; } // Bound by the preview level's Level Blueprint to start/stop its 30fps capture loop. // Read IsPreviewActive() on BeginPlay to sync initial state in case the panel was // somehow already open when the sublevel streamed in. UPROPERTY(BlueprintAssignable, Category = "Preview") FOnPreviewCaptureActiveChanged OnPreviewCaptureActiveChanged; private: bool bPreviewActive = false; };