I thought I was having an issue with saving specific information but apparently I just can’t save or load my game at all… I have followed many different tutorials (Reuben Ward - “Unreal Engine C++ Tutorial - Creating Savegames” on YouTube, DevSquad “Save/Load Game System Intro - #66 Unreal Engine 4 Beginner Tutorial Series” on YouTube, and even the c++ tutorial “Saving and Loading your game” in the Unreal Engine Documentation) and am able to get this working in blueprint but for some reason not c++. I have had other projects save with no issue and am really confused to what I am doing wrong.
I originally thought I was having an issue setting my boolean arrays so I made the UpdateArray function to empty and then refill arrays with a for loop.
When there is no SaveGame.sav present it appears to work correctly. Here are the specific logs that tell me that.
LogTemp: Warning: Game Saved from GameSave
LogTemp: Warning: GAME SAVED FROM GAME INSTANCE. local Hair bool array lenghth was 14. savegame value is 13
LogTemp: Warning: GAME SAVE CREATED FROM GAMEMODE
LogTemp: Warning: GAME MODE BEGIN PLAY CALLED. Hair bool Array length is 14
Closing the game saves the game again, all the values are still correct. When I re-open the game the values have all reset to 0 (of if I try having default values set in the code for DDSaveGame the values are reset to those instead). Here’s the related logs.
LogTemp: Warning: GAME LOADED FROM GAME INSTANCE! Lenght of hair bool array is 0
LogTemp: Warning: GAME LOADED FROM GAMEMODE
LogTemp: Warning: GAME MODE BEGIN PLAY CALLED. Hair bool Array length is 0
I’m sorry to include so much code to read, I have tried making it as neat as possible for ease of reading. I have also limited it to what I believe to be the root of the issue. Thanks in advance for any assistance in fixing this!
DDGameInstance.cpp (all references of ‘this->’ was the last thing I added in efforts to fix things, I thought it was unnecessary and it fixed nothing)
void UDDGameInstance::SaveGame()
{
UDDSaveGame* SaveGameRef = Cast<UDDSaveGame>(UGameplayStatics::CreateSaveGameObject(UDDSaveGame::StaticClass()));
if(SaveGameRef)
{
//Send game instance variables to SaveGameRef to be updated there.
SaveGameRef->FullSave(bHasChest, bHasLegs, bHasFace, bHasHands, bHasHair, bHasBeard, bHasEyebrows, bMaleCharacter, CurrentCoins, SelectedChest, SelectedLegs, SelectedFace, SelectedHands, SelectedHair, SelectedBeard, SelectedEyebrows, SelectedMenuMusic, SelectedGameMusic);
UGameplayStatics::SaveGameToSlot(SaveGameRef, TEXT("SaveGame"), 0);
UE_LOG(LogTemp, Warning, TEXT("GAME SAVED FROM GAME INSTANCE. local Hair bool array lenghth was %i. savegame value is %i"), bHasHair.Num(), SaveGameRef->LenghtOfHairArray());
}
else{UE_LOG(LogTemp, Error, TEXT("SAVE GAME IS NULL"));}
}
void UDDGameInstance::LoadGame()
{
UDDSaveGame* SaveGameRef = Cast<UDDSaveGame>(UGameplayStatics::CreateSaveGameObject(UDDSaveGame::StaticClass()));
SaveGameRef = Cast<UDDSaveGame>(UGameplayStatics::LoadGameFromSlot(TEXT("SaveGame"), 0));
TArray<bool> TempChest, TempLegs, TempFace, TempHands, TempHair, TempBeard, TempEyebrows;
bool TempMale;
int TempCoin, TempChestIndex, TempLegsIndex, TempFaceIndex, TempHandsIndex, TempHairIndex, TempBeardIndex, TempEyebrowsIndex, TempGameMusic, TempMenuMusic;
// The operation was successful, so LoadedGame now contains the data we saved earlier.
SaveGameRef->LoadGame(TempChest, TempLegs, TempFace, TempHands, TempHair, TempBeard, TempEyebrows, TempMale, TempCoin, TempChestIndex, TempLegsIndex, TempFaceIndex, TempHandsIndex, TempHairIndex, TempBeardIndex, TempEyebrowsIndex, TempGameMusic, TempMenuMusic);
this->UpdateArray(bHasChest, TempChest);
this->UpdateArray(bHasLegs, TempLegs);
this->UpdateArray(bHasFace, TempFace);
this->UpdateArray(bHasHands, TempHands);
this->UpdateArray(bHasHair, TempHair);
this->UpdateArray(bHasBeard, TempBeard);
this->UpdateArray(bHasEyebrows, TempEyebrows);
this->bMaleCharacter = TempMale;
this->CurrentCoins = TempCoin;
this->SelectedChest = TempChestIndex;
this->SelectedLegs = TempLegsIndex;
this->SelectedFace = TempFaceIndex;
this->SelectedHands = TempHandsIndex;
this->SelectedHair = TempHairIndex;
this->SelectedBeard = TempBeardIndex;
this->SelectedEyebrows = TempEyebrowsIndex;
this->SelectedGameMusic = TempGameMusic;
this->SelectedMenuMusic = TempMenuMusic;
UE_LOG(LogTemp, Warning, TEXT("GAME LOADED FROM GAME INSTANCE! Lenght of hair bool array is %i"), bHasHair.Num());
}
void UDDGameInstance::UpdateArray(TArray<bool>& ArrayToUpdate, TArray<bool> NewValues)
{
ArrayToUpdate.Empty();
for(int i = 0; i < NewValues.Num() - 1; i++)
{
ArrayToUpdate.Add(NewValues[i]);
UE_LOG(LogTemp, Warning, TEXT("Value is %s at %i"), ArrayToUpdate[i] ? TEXT("true") : TEXT("false"), i);
}
UE_LOG(LogTemp, Warning, TEXT("New Array length is %i"), ArrayToUpdate.Num());
}
I’m also including my entire DDSaveGame class code just in case I have done something fundamentally wrong.
DDSaveGame.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/SaveGame.h"
#include "DDSaveGame.generated.h"
/**
*
*/
UCLASS()
class DESERTDASH_API UDDSaveGame : public USaveGame
{
GENERATED_BODY()
public:
UDDSaveGame();
void FullSave(TArray<bool> Chests, TArray<bool> Legs, TArray<bool> Faces, TArray<bool> Hands, TArray<bool> Hairs, TArray<bool> Beards, TArray<bool> Eyebrows, bool MaleCharacter, int Coins, int Chest, int Leg, int Face, int Hand, int Hair, int Beard, int Eyebrow, int GameMusic, int MenuMusic);
void CoinSave(int Coins);
void LoadGame(TArray<bool>& ChestsOUT, TArray<bool>& LegsOUT, TArray<bool>& FacesOUT, TArray<bool>& HandsOUT, TArray<bool>& HairsOUT, TArray<bool>& BeardsOUT, TArray<bool>& EyebrowsOUT, bool& MaleCharacterOUT, int& CoinsOUT, int& ChestOUT, int& LegOUT, int& FaceOUT, int& HandOUT, int& HairOUT, int& BeardOUT, int& EyebrowOUT, int& GameMusicOUT, int& MenuMusicOUT);
int LenghtOfHairArray();
void UpdateArray(TArray<bool>& ArrayToUpdate, TArray<bool> NewValues);
private:
TArray<bool> SavedChests;
TArray<bool> SavedLegs;
TArray<bool> SavedFaces;
TArray<bool> SavedHands;
TArray<bool> SavedHairs;
TArray<bool> SavedBeards;
TArray<bool> SavedEyebrows;
bool bSaveMaleCharacter;
int CurrentCoins;
int SelectedChest;
int SelectedLegs;
int SelectedFace;
int SelectedHands;
int SelectedHair;
int SelectedBeard;
int SelectedEyebrows;
int SelectedGameMusic;
int SelectedMenuMusic;
};
DDSaveGame.cpp (I have commented out the default values as this just hides the issue until changes are made, changes are not saved and will reset to defaults)
#include "System/DDSaveGame.h"
UDDSaveGame::UDDSaveGame()
{
SavedChests;/* = {true, false, false, false, false, false, false, true, false, false, false, false};*/
SavedLegs;/* = {true, false, false, false, false, false, false, true, false, false, false, false};*/
SavedFaces;/* = {true, true, true, false, false, true, true, true, false, false};*/
SavedHands;/* = {true, false, false, true, false};*/
SavedHairs;/* = {false, false, false, false, false, false, false, false, false, false, false, false, false, true};*/
SavedBeards;/* = {false, false, false, false, true};*/
SavedEyebrows;/* = {false, false, false, false, false, false, false, true};*/
bSaveMaleCharacter;/* = true;*/
CurrentCoins;/* = 0;*/
SelectedChest;/* = 0;*/
SelectedLegs;/* = 0;*/
SelectedFace;/* = 0;*/
SelectedHands;/* = 0;*/
SelectedHair;/* = 13;*/
SelectedBeard;/* = 4;*/
SelectedEyebrows;/* = 7;*/
SelectedGameMusic;/* = 3;*/
SelectedMenuMusic;/* = 0;*/
}
void UDDSaveGame::FullSave(TArray<bool> Chests, TArray<bool> Legs, TArray<bool> Faces, TArray<bool> Hands, TArray<bool> Hairs, TArray<bool> Beards, TArray<bool> Eyebrows, bool MaleCharacter, int Coins, int Chest, int Leg, int Face, int Hand, int Hair, int Beard, int Eyebrow, int GameMusic, int MenuMusic)
{
UpdateArray(SavedChests, Chests);
UpdateArray(SavedLegs, Legs);
UpdateArray(SavedFaces, Faces);
UpdateArray(SavedHands, Hands);
UpdateArray(SavedHairs, Hairs);
UpdateArray(SavedBeards, Beards);
UpdateArray(SavedEyebrows, Eyebrows);
bSaveMaleCharacter = MaleCharacter;
CurrentCoins = Coins;
SelectedChest = Chest;
SelectedLegs = Leg;
SelectedFace = Face;
SelectedHands = Hand;
SelectedHair = Hair;
SelectedBeard = Beard;
SelectedEyebrows = Eyebrow;
SelectedGameMusic = GameMusic;
SelectedMenuMusic = MenuMusic;
UE_LOG(LogTemp, Warning, TEXT("Game Saved from GameSave"));
}
void UDDSaveGame::CoinSave(int Coins)
{
CurrentCoins = Coins;
}
void UDDSaveGame::LoadGame(TArray<bool>& ChestsOUT, TArray<bool>& LegsOUT, TArray<bool>& FacesOUT, TArray<bool>& HandsOUT, TArray<bool>& HairsOUT, TArray<bool>& BeardsOUT, TArray<bool>& EyebrowsOUT, bool& MaleCharacterOUT, int& CoinsOUT, int& ChestOUT, int& LegOUT, int& FaceOUT, int& HandOUT, int& HairOUT, int& BeardOUT, int& EyebrowOUT, int& GameMusicOUT, int& MenuMusicOUT)
{
UpdateArray(ChestsOUT, SavedChests);
UpdateArray(LegsOUT, SavedLegs);
UpdateArray(FacesOUT, SavedFaces);
UpdateArray(HandsOUT, SavedHands);
UpdateArray(HairsOUT, SavedHairs);
UpdateArray(BeardsOUT, SavedBeards);
UpdateArray(EyebrowsOUT, SavedEyebrows);
MaleCharacterOUT = bSaveMaleCharacter;
CoinsOUT = CurrentCoins;
ChestOUT = SelectedChest;
LegOUT = SelectedLegs;
FaceOUT = SelectedFace;
HandOUT = SelectedHands;
HairOUT = SelectedHair;
BeardOUT = SelectedBeard;
EyebrowOUT = SelectedEyebrows;
GameMusicOUT = SelectedGameMusic;
MenuMusicOUT = SelectedMenuMusic;
UE_LOG(LogTemp, Warning, TEXT("GameMusic Value is %i and should be 3"), SelectedGameMusic);
}
int UDDSaveGame::LenghtOfHairArray()
{
return SavedHairs.Num();
}
void UDDSaveGame::UpdateArray(TArray<bool>& ArrayToUpdate, TArray<bool> NewValues)
{
ArrayToUpdate.Empty();
for(int i = 0; i < NewValues.Num() - 1; i++)
{
ArrayToUpdate.Add(NewValues[i]);
UE_LOG(LogTemp, Warning, TEXT("Value is %s at %i"), ArrayToUpdate[i] ? TEXT("true") : TEXT("false"), i);
}
UE_LOG(LogTemp, Warning, TEXT("New Array length is %i"), ArrayToUpdate.Num());
}
Thank you again for any assistance you can provide! I am unfortunately quite stuck with this issue and don’t know what to do next.