Save system

This commit is contained in:
Oleg Petruny 2024-07-18 21:46:41 +02:00
parent a432dcbbf7
commit f7b9942b5a
14 changed files with 215 additions and 31 deletions

Binary file not shown.

Binary file not shown.

View File

@ -4,8 +4,11 @@
#include "GameFramework/Actor.h"
#include "InputCoreTypes.h"
#include "Kismet/GameplayStatics.h"
#include "UObject/Object.h"
#include "Levels/LevelBase.h"
#include "PlayerBase.h"
bool UCommonFunctions::IsNonGameObject(UObject* object)
{
@ -34,3 +37,20 @@ void UCommonFunctions::DestroyActorRecursively(AActor* actor)
child->Destroy();
actor->Destroy();
}
ALevelBase* UCommonFunctions::GetCurrentLevelScript(UObject* obj)
{
if(auto world = obj->GetWorld())
if(auto level = world->GetCurrentLevel())
if(auto script = level->GetLevelScriptActor())
return Cast<ALevelBase>(script);
return nullptr;
}
APlayerBase* UCommonFunctions::GetPlayer(UObject* obj)
{
if(auto pc = UGameplayStatics::GetPlayerController(obj->GetWorld(), 0))
if(auto pawn = pc->GetPawn())
return Cast<APlayerBase>(pawn);
return nullptr;
}

View File

@ -17,4 +17,10 @@ public:
UFUNCTION(BlueprintCallable, Category = Actor)
static void DestroyActorRecursively(class AActor* actor);
UFUNCTION(BlueprintCallable, Category = Level)
static class ALevelBase* GetCurrentLevelScript(class UObject* obj);
UFUNCTION(BlueprintCallable, Category = Player)
static class APlayerBase* GetPlayer(class UObject* obj);
};

View File

@ -8,14 +8,22 @@
#include "InputMappingContext.h"
#include "Kismet/GameplayStatics.h"
#include "CommonFunctions.h"
#include "CustomGameUserSettings.h"
#include "Interactable/Activators/InCameraInteractableActivator.h"
#include "Interactable/Activators/RaycastInteractableActivator.h"
#include "Interactable/Modificators/ActivateInteractableModificator.h"
#include "Interactable/Modificators/SawInteractableModificator.h"
#include "Levels/LevelBase.h"
#include "PlayerBase.h"
#include "SaveData.h"
UCustomGameInstanceBase* UCustomGameInstanceBase::instance = nullptr;
void UCustomGameInstanceBase::Init()
{
instance = this;
UGameInstance::Init();
// IN FUTURE ASSIGN FROM CONTENT LOADER MEMBER
@ -31,6 +39,13 @@ void UCustomGameInstanceBase::Init()
}
ApplyMouseSettings();
saveData = Cast<USaveData>(UGameplayStatics::CreateSaveGameObject(USaveData::StaticClass()));
}
UCustomGameInstanceBase* UCustomGameInstanceBase::GetGameInstance()
{
return instance;
}
void UCustomGameInstanceBase::ApplyMouseSettings()
@ -83,3 +98,32 @@ void UCustomGameInstanceBase::AppendInteractableModificatorClass(TSubclassOf<cla
}
}
}
void UCustomGameInstanceBase::SaveGame(FName checkpointName)
{
auto levelScript = UCommonFunctions::GetCurrentLevelScript(this);
if(!levelScript)
return;
auto player = UCommonFunctions::GetPlayer(this);
if(!player)
return;
saveData->level = GetWorld()->GetFName();
saveData->state = levelScript->GetState();
saveData->checkpoint = checkpointName;
if(player->leftPocketItem)
saveData->playerLeftPocketItem = player->leftPocketItem->GetFName();
if(player->rightPocketItem)
saveData->playerRightPocketItem = player->rightPocketItem->GetFName();
UGameplayStatics::SaveGameToSlot(saveData, TEXT("Save"), 0);
}
void UCustomGameInstanceBase::LoadGame()
{
saveData = Cast<USaveData>(UGameplayStatics::LoadGameFromSlot(TEXT("Save"), 0));
if(!saveData)
return;
UGameplayStatics::OpenLevel(this, saveData->level);
}

View File

@ -2,7 +2,6 @@
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "CustomGameInstanceBase.generated.h"
@ -17,11 +16,21 @@ class UCustomGameInstanceBase : public UGameInstance
public:
virtual void Init() override;
UFUNCTION(BlueprintPure)
static UCustomGameInstanceBase* GetGameInstance();
UFUNCTION(BlueprintCallable, Category = Settings)
void ApplyMouseSettings();
void AppendInteractableModificatorClass(TSubclassOf<class UInteractableModificator> modificator);
UFUNCTION(BlueprintCallable, Category = Save)
void SaveGame(FName checkpointName);
UFUNCTION(BlueprintCallable, Category = Save)
void LoadGame();
static UCustomGameInstanceBase* instance;
FLevelBeginnedDelegate OnLevelBeginned;
UPROPERTY(EditDefaultsOnly)
@ -31,4 +40,6 @@ public:
UPROPERTY(EditDefaultsOnly)
TSet<TSoftObjectPtr<class UInputMappingContext>> inputContexts;
UPROPERTY(VisibleAnywhere)
class USaveData* saveData = nullptr;
};

View File

@ -0,0 +1,12 @@
// Oleg Petruny proprietary.
#include "Checkpoint.h"
#include "CustomGameInstanceBase.h"
void ACheckpoint::SaveGame()
{
if(auto GI = Cast<UCustomGameInstanceBase>(GetWorld()->GetGameInstance()))
GI->SaveGame(GetFName());
}

View File

@ -0,0 +1,18 @@
// Oleg Petruny proprietary.
#pragma once
#include "GameFramework/Actor.h"
#include "Checkpoint.generated.h"
UCLASS(Blueprintable, BlueprintType, MinimalAPI)
class ACheckpoint : public AActor
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable)
void SaveGame();
};

View File

@ -3,19 +3,39 @@
#include "LevelBase.h"
#include "EngineUtils.h"
#include "LevelSequencePlayer.h"
#include "CommonFunctions.h"
#include "CustomGameInstanceBase.h"
#include "Interactable/Interactable.h"
#include "Levels/Checkpoint.h"
#include "PlayerBase.h"
#include "SaveData.h"
void ALevelBase::BeginPlay()
{
ALevelScriptActor::BeginPlay();
//=== broadcast new level begin play
BroadcastNewLevelBeginPlay();
StartLevelAnimations();
ApplySaveData();
}
void ALevelBase::IterateToState(int32 to)
{
while(state < to)
CallNextState();
}
void ALevelBase::BroadcastNewLevelBeginPlay()
{
if(auto GI = Cast<UCustomGameInstanceBase>(GetWorld()->GetGameInstance()))
GI->OnLevelBeginned.Broadcast(GetFName());
}
//=== start level animations
void ALevelBase::StartLevelAnimations()
{
FMovieSceneSequencePlaybackSettings playbackSettings;
playbackSettings.bAutoPlay = true;
FMovieSceneSequenceLoopCount playbackLoopCount;
@ -27,6 +47,46 @@ void ALevelBase::BeginPlay()
auto sequencePlayer = ULevelSequencePlayer::CreateLevelSequencePlayer(GetWorld(), sequence.LoadSynchronous(), playbackSettings, sequenceActor);
onBeginPlaySequencesActors.Add(sequenceActor);
}
}
void ALevelBase::ApplySaveData()
{
auto GI = UCustomGameInstanceBase::GetGameInstance();
if(!GI || !GI->saveData || GI->saveData->level != GetWorld()->GetFName())
return;
IterateToState(GI->saveData->state);
auto player = UCommonFunctions::GetPlayer(this);
if(!player)
return;
for(TActorIterator<ACheckpoint> it(GetWorld()); it; ++it)
{
if(it->GetFName() == GI->saveData->checkpoint)
{
player->SetActorLocation(it->GetActorLocation(), false, nullptr, ETeleportType::ResetPhysics);
player->Controller->SetControlRotation(it->GetActorRotation());
break;
}
}
int pocketItems = 0;
for(TActorIterator<AInteractable> it(GetWorld()); it; ++it)
{
if(it->GetFName() == GI->saveData->playerLeftPocketItem)
{
++pocketItems;
player->TakeItemToLeftHand(*it);
}
else if(it->GetFName() == GI->saveData->playerRightPocketItem)
{
++pocketItems;
player->TakeItemToRightHand(*it);
}
if(pocketItems > 1)
{
break;
}
}
}

View File

@ -15,12 +15,21 @@ public:
UFUNCTION(BlueprintCallable)
inline void CallNextState() { ++state; NextState(); }
inline int32 GetState() { return state; };
protected:
virtual void BeginPlay() override;
UFUNCTION(BlueprintImplementableEvent)
void NextState();
UFUNCTION(BlueprintCallable)
void IterateToState(int32 to);
void BroadcastNewLevelBeginPlay();
void StartLevelAnimations();
void ApplySaveData();
UPROPERTY(EditDefaultsOnly)
TArray<TSoftObjectPtr<class ULevelSequence>> onBeginPlaySequences;
TArray<class ALevelSequenceActor*> onBeginPlaySequencesActors;

View File

@ -0,0 +1,29 @@
// Oleg Petruny proprietary.
#pragma once
#include "GameFramework/SaveGame.h"
#include "SaveData.generated.h"
UCLASS(BlueprintType)
class USaveData : public USaveGame
{
GENERATED_BODY()
public:
UPROPERTY(VisibleAnywhere)
FName level;
UPROPERTY(VisibleAnywhere)
int32 state;
UPROPERTY(VisibleAnywhere)
FName checkpoint;
UPROPERTY(VisibleAnywhere)
FName playerLeftPocketItem;
UPROPERTY(VisibleAnywhere)
FName playerRightPocketItem;
};

View File

@ -1,6 +0,0 @@
// Oleg Petruny proprietary.
#include "SaveManager.h"

View File

@ -1,19 +0,0 @@
// Oleg Petruny proprietary.
#pragma once
#include "UObject/Object.h"
#include "SaveManager.generated.h"
UCLASS(BlueprintType)
class USaveManager : public UObject
{
GENERATED_BODY()
public:
private:
};