// 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 { return Cast(UGameplayStatics::CreateSaveGameObject(UAgrarianSaveGame::StaticClass())); } UAgrarianSaveGame* UAgrarianPersistenceSubsystem::LoadOrCreateSave() const { if (UGameplayStatics::DoesSaveGameExist(DefaultSlotName, UserIndex)) { if (UAgrarianSaveGame* Loaded = Cast(UGameplayStatics::LoadGameFromSlot(DefaultSlotName, UserIndex))) { return Loaded; } } return CreateEmptySave(); } bool UAgrarianPersistenceSubsystem::WriteSave(UAgrarianSaveGame* SaveGame) const { return SaveGame ? UGameplayStatics::SaveGameToSlot(SaveGame, DefaultSlotName, UserIndex) : false; } bool UAgrarianPersistenceSubsystem::DoesSaveExist() const { return UGameplayStatics::DoesSaveGameExist(DefaultSlotName, UserIndex); } void UAgrarianPersistenceSubsystem::RegisterWorldActorClass(FName ActorTypeId, TSubclassOf ActorClass) { if (ActorTypeId != NAME_None && ActorClass) { WorldActorClassRegistry.Add(ActorTypeId, ActorClass); } } int32 UAgrarianPersistenceSubsystem::CaptureWorldActors(UAgrarianSaveGame* SaveGame) const { if (!SaveGame) { return 0; } TArray 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 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* ActorClass = WorldActorClassRegistry.Find(SavedActor.ActorTypeId); if (!ActorClass || !(*ActorClass)) { continue; } FActorSpawnParameters SpawnParams; SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; AActor* SpawnedActor = World->SpawnActor(*ActorClass, SavedActor.Transform, SpawnParams); if (!SpawnedActor) { continue; } if (UAgrarianPersistentActorComponent* Component = SpawnedActor->FindComponentByClass()) { 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& OutComponents) const { OutComponents.Reset(); UWorld* World = GetWorld(); if (!World) { return; } for (TActorIterator ActorIt(World); ActorIt; ++ActorIt) { AActor* Actor = *ActorIt; if (!Actor || Actor->IsPendingKillPending()) { continue; } if (UAgrarianPersistentActorComponent* Component = Actor->FindComponentByClass()) { OutComponents.Add(Component); } } }