Add placed actor persistence foundation

This commit is contained in:
2026-05-11 01:00:41 -07:00
parent e81138425b
commit 9a0a3608fb
7 changed files with 234 additions and 1 deletions
@@ -1,7 +1,10 @@
// Copyright Pacificao. All Rights Reserved.
#include "AgrarianPersistenceSubsystem.h"
#include "AgrarianPersistentActorComponent.h"
#include "AgrarianSaveGame.h"
#include "EngineUtils.h"
#include "Engine/World.h"
#include "Kismet/GameplayStatics.h"
UAgrarianSaveGame* UAgrarianPersistenceSubsystem::CreateEmptySave() const
@@ -31,3 +34,121 @@ bool UAgrarianPersistenceSubsystem::DoesSaveExist() const
{
return UGameplayStatics::DoesSaveGameExist(DefaultSlotName, UserIndex);
}
void UAgrarianPersistenceSubsystem::RegisterWorldActorClass(FName ActorTypeId, TSubclassOf<AActor> ActorClass)
{
if (ActorTypeId != NAME_None && ActorClass)
{
WorldActorClassRegistry.Add(ActorTypeId, ActorClass);
}
}
int32 UAgrarianPersistenceSubsystem::CaptureWorldActors(UAgrarianSaveGame* SaveGame) const
{
if (!SaveGame)
{
return 0;
}
TArray<UAgrarianPersistentActorComponent*> PersistentComponents;
FindPersistentComponents(PersistentComponents);
SaveGame->WorldActors.Reset();
for (const UAgrarianPersistentActorComponent* Component : PersistentComponents)
{
if (Component && Component->IsSaveable())
{
SaveGame->WorldActors.Add(Component->CaptureSaveState());
}
}
return SaveGame->WorldActors.Num();
}
int32 UAgrarianPersistenceSubsystem::RestoreWorldActors(const UAgrarianSaveGame* SaveGame, bool bClearExistingActors) const
{
UWorld* World = GetWorld();
if (!World || !SaveGame)
{
return 0;
}
if (bClearExistingActors)
{
TArray<UAgrarianPersistentActorComponent*> ExistingComponents;
FindPersistentComponents(ExistingComponents);
for (UAgrarianPersistentActorComponent* Component : ExistingComponents)
{
if (AActor* Owner = Component ? Component->GetOwner() : nullptr)
{
Owner->Destroy();
}
}
}
int32 RestoredCount = 0;
for (const FAgrarianSavedWorldActor& SavedActor : SaveGame->WorldActors)
{
const TSubclassOf<AActor>* ActorClass = WorldActorClassRegistry.Find(SavedActor.ActorTypeId);
if (!ActorClass || !(*ActorClass))
{
continue;
}
FActorSpawnParameters SpawnParams;
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
AActor* SpawnedActor = World->SpawnActor<AActor>(*ActorClass, SavedActor.Transform, SpawnParams);
if (!SpawnedActor)
{
continue;
}
if (UAgrarianPersistentActorComponent* Component = SpawnedActor->FindComponentByClass<UAgrarianPersistentActorComponent>())
{
Component->ApplySaveState(SavedActor);
}
RestoredCount++;
}
return RestoredCount;
}
bool UAgrarianPersistenceSubsystem::SaveCurrentWorld() const
{
UAgrarianSaveGame* SaveGame = LoadOrCreateSave();
if (!SaveGame)
{
return false;
}
CaptureWorldActors(SaveGame);
return WriteSave(SaveGame);
}
void UAgrarianPersistenceSubsystem::FindPersistentComponents(TArray<UAgrarianPersistentActorComponent*>& OutComponents) const
{
OutComponents.Reset();
UWorld* World = GetWorld();
if (!World)
{
return;
}
for (TActorIterator<AActor> ActorIt(World); ActorIt; ++ActorIt)
{
AActor* Actor = *ActorIt;
if (!Actor || Actor->IsPendingKillPending())
{
continue;
}
if (UAgrarianPersistentActorComponent* Component = Actor->FindComponentByClass<UAgrarianPersistentActorComponent>())
{
OutComponents.Add(Component);
}
}
}