diff --git a/Content/Blueprints/BP_Checkpoint.uasset b/Content/Blueprints/BP_Checkpoint.uasset new file mode 100644 index 0000000..c888c5a Binary files /dev/null and b/Content/Blueprints/BP_Checkpoint.uasset differ diff --git a/Content/Levels/Test/Actors/SaveTest/BP_Test_Load.uasset b/Content/Levels/Test/Actors/SaveTest/BP_Test_Load.uasset new file mode 100644 index 0000000..ca86f3a Binary files /dev/null and b/Content/Levels/Test/Actors/SaveTest/BP_Test_Load.uasset differ diff --git a/Content/Levels/Test/L_Test.umap b/Content/Levels/Test/L_Test.umap index b99fa9a..9d2f8c6 100644 Binary files a/Content/Levels/Test/L_Test.umap and b/Content/Levels/Test/L_Test.umap differ diff --git a/Source/Lost_Edge/Private/CommonFunctions.cpp b/Source/Lost_Edge/Private/CommonFunctions.cpp index 811f74c..7199156 100644 --- a/Source/Lost_Edge/Private/CommonFunctions.cpp +++ b/Source/Lost_Edge/Private/CommonFunctions.cpp @@ -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(script); + return nullptr; +} + +APlayerBase* UCommonFunctions::GetPlayer(UObject* obj) +{ + if(auto pc = UGameplayStatics::GetPlayerController(obj->GetWorld(), 0)) + if(auto pawn = pc->GetPawn()) + return Cast(pawn); + return nullptr; +} diff --git a/Source/Lost_Edge/Private/CommonFunctions.h b/Source/Lost_Edge/Private/CommonFunctions.h index 07edd46..94d9a4e 100644 --- a/Source/Lost_Edge/Private/CommonFunctions.h +++ b/Source/Lost_Edge/Private/CommonFunctions.h @@ -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); }; diff --git a/Source/Lost_Edge/Private/CustomGameInstanceBase.cpp b/Source/Lost_Edge/Private/CustomGameInstanceBase.cpp index 8fcb7ae..cd8c1c2 100644 --- a/Source/Lost_Edge/Private/CustomGameInstanceBase.cpp +++ b/Source/Lost_Edge/Private/CustomGameInstanceBase.cpp @@ -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(UGameplayStatics::CreateSaveGameObject(USaveData::StaticClass())); +} + +UCustomGameInstanceBase* UCustomGameInstanceBase::GetGameInstance() +{ + return instance; } void UCustomGameInstanceBase::ApplyMouseSettings() @@ -82,4 +97,33 @@ void UCustomGameInstanceBase::AppendInteractableModificatorClass(TSubclassOflevel = 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(UGameplayStatics::LoadGameFromSlot(TEXT("Save"), 0)); + if(!saveData) + return; + + UGameplayStatics::OpenLevel(this, saveData->level); +} diff --git a/Source/Lost_Edge/Private/CustomGameInstanceBase.h b/Source/Lost_Edge/Private/CustomGameInstanceBase.h index a0adb28..b70a536 100644 --- a/Source/Lost_Edge/Private/CustomGameInstanceBase.h +++ b/Source/Lost_Edge/Private/CustomGameInstanceBase.h @@ -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 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> inputContexts; + UPROPERTY(VisibleAnywhere) + class USaveData* saveData = nullptr; }; diff --git a/Source/Lost_Edge/Private/Levels/Checkpoint.cpp b/Source/Lost_Edge/Private/Levels/Checkpoint.cpp new file mode 100644 index 0000000..7cca7d5 --- /dev/null +++ b/Source/Lost_Edge/Private/Levels/Checkpoint.cpp @@ -0,0 +1,12 @@ +// Oleg Petruny proprietary. + + +#include "Checkpoint.h" + +#include "CustomGameInstanceBase.h" + +void ACheckpoint::SaveGame() +{ + if(auto GI = Cast(GetWorld()->GetGameInstance())) + GI->SaveGame(GetFName()); +} diff --git a/Source/Lost_Edge/Private/Levels/Checkpoint.h b/Source/Lost_Edge/Private/Levels/Checkpoint.h new file mode 100644 index 0000000..6f452f8 --- /dev/null +++ b/Source/Lost_Edge/Private/Levels/Checkpoint.h @@ -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(); +}; + diff --git a/Source/Lost_Edge/Private/Levels/LevelBase.cpp b/Source/Lost_Edge/Private/Levels/LevelBase.cpp index bbd4457..5f05724 100644 --- a/Source/Lost_Edge/Private/Levels/LevelBase.cpp +++ b/Source/Lost_Edge/Private/Levels/LevelBase.cpp @@ -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(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 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 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; + } + } } diff --git a/Source/Lost_Edge/Private/Levels/LevelBase.h b/Source/Lost_Edge/Private/Levels/LevelBase.h index 7ef3045..2778375 100644 --- a/Source/Lost_Edge/Private/Levels/LevelBase.h +++ b/Source/Lost_Edge/Private/Levels/LevelBase.h @@ -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> onBeginPlaySequences; TArray onBeginPlaySequencesActors; diff --git a/Source/Lost_Edge/Private/SaveData.h b/Source/Lost_Edge/Private/SaveData.h new file mode 100644 index 0000000..d356364 --- /dev/null +++ b/Source/Lost_Edge/Private/SaveData.h @@ -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; +}; diff --git a/Source/Lost_Edge/Private/SaveManager.cpp b/Source/Lost_Edge/Private/SaveManager.cpp deleted file mode 100644 index 0e4aedc..0000000 --- a/Source/Lost_Edge/Private/SaveManager.cpp +++ /dev/null @@ -1,6 +0,0 @@ -// Oleg Petruny proprietary. - - -#include "SaveManager.h" - - diff --git a/Source/Lost_Edge/Private/SaveManager.h b/Source/Lost_Edge/Private/SaveManager.h deleted file mode 100644 index 594ca6d..0000000 --- a/Source/Lost_Edge/Private/SaveManager.h +++ /dev/null @@ -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: - -};