Files
Naked-Desire/Source/NakedDesire/NPC/NPCDirectorSubsystem.h
T
2026-06-03 15:17:10 +03:00

61 lines
1.9 KiB
C++

// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "NPCType.h"
#include "Subsystems/WorldSubsystem.h"
#include "NakedDesire/Global/TimeOfDaySubsystem.h"
#include "NPCDirectorSubsystem.generated.h"
class ANPC;
class APawn;
class UNPCDirectorConfig;
/**
* The GDD §17.1 NPCManager: single authority for the crowd around the player (§10.2, §19).
* A WorldSubsystem (like UMissionSubsystem / UTimeOfDaySubsystem) — it needs world access plus the
* day/night phase to drive density.
*
* Keeps a pool of NPC actors prewarmed from UNPCDirectorConfig::SpawnTable and, on a light timer,
* reconciles the live population: recycles NPCs past the despawn radius and activates pooled ones at
* NavMesh points in the spawn ring until the phase-appropriate target count is met. Mesh-agnostic —
* it never touches what an NPC looks like, only how many exist and where. Supersedes the BP spawner.
*/
UCLASS()
class NAKEDDESIRE_API UNPCDirectorSubsystem : public UWorldSubsystem
{
GENERATED_BODY()
public:
virtual void OnWorldBeginPlay(UWorld& InWorld) override;
virtual void Deinitialize() override;
private:
UFUNCTION()
void HandlePhaseChanged(EDayPhase NewPhase);
void PrewarmPool();
void UpdatePopulation(); // timer-driven reconcile
int32 CurrentTargetCount() const;
ANPC* TakeFromPool();
void ReturnToPool(ANPC* NPC);
ENPCType PickWeightedClass() const;
bool FindSpawnPoint(const FVector& Around, FVector& OutLocation) const;
TSubclassOf<ANPC> GetRandomNPCClass(TArray<TSubclassOf<ANPC>> InNPCClasses);
APawn* GetPlayerPawn() const;
UNPCDirectorConfig* GetConfig() const;
// Inactive (hidden) NPCs ready to activate.
UPROPERTY()
TArray<TObjectPtr<ANPC>> Pool;
// Currently live NPCs around the player.
UPROPERTY()
TArray<TObjectPtr<ANPC>> Active;
FTimerHandle UpdateTimerHandle;
EDayPhase CachedPhase = EDayPhase::Day;
};