Skip to content
Snippets Groups Projects
Commit 329f22fb authored by Malte Christian Kögel's avatar Malte Christian Kögel
Browse files

Store "WasStarted" properties per condition in LastParticipant.txt and recover...

Store "WasStarted" properties per condition in LastParticipant.txt and recover it when choosing "Continue Participant". That way, restarting a condition with and without closing the game in between is handled in the same way. Create backups when restarting condition. closes #94
parent 64df67dc
No related branches found
No related tags found
No related merge requests found
......@@ -26,7 +26,7 @@ void USFCondition::Generate(const FString& InPhaseName, const TArray<int>& Condi
if (Factor->IsA(USFMapFactor::StaticClass()))
{
Map = FactorLevel;
//for better readybility strip path!
//for better readability strip path!
FactorLevel = FPaths::GetBaseFilename(FactorLevel);
}
FactorLevels.Add(Factor->FactorName, FactorLevel);
......@@ -232,6 +232,11 @@ bool USFCondition::HasRequiredVariables() const
return false;
}
void USFCondition::SetbStarted(bool WasStarted)
{
bStarted = WasStarted;
}
bool USFCondition::WasStarted() const
{
return bStarted;
......
......@@ -529,6 +529,8 @@ void USFGameInstance::HandleGoToConditionSynced(FString ConditionName, bool bFor
{
LogComment("Restarting Condition " + NextCondition->UniqueName + ", so we delete all gathered data for that condition.");
FString BackUpFolderName = "Restart_" + NextCondition->UniqueName + "_BackUp-" + FDateTime::Now().ToString();
Participant->SetCurrentBackUpFolderName(BackUpFolderName);
//so remove already stored data!
Participant->DeleteStoredDataForConditionFromLongTable(NextCondition);
for (USFDependentVariable* DV : NextCondition->DependentVariables)
......
......@@ -10,6 +10,7 @@
#include "Help/SFUtils.h"
#include "Logging/SFLoggingBPLibrary.h"
#include "Logging/SFLoggingUtils.h"
#include "JsonUtilities.h"
USFParticipant::USFParticipant()
{
......@@ -335,6 +336,7 @@ void USFParticipant::RemoveLinesOfConditionAndWriteToFile(USFCondition* Conditio
}
CleanedLines.Add(Lines[0]);
bool bHasRemovedLines = false;
for (int i = 1; i < Lines.Num(); ++i)
{
TArray<FString> Entries;
......@@ -356,6 +358,11 @@ void USFParticipant::RemoveLinesOfConditionAndWriteToFile(USFCondition* Conditio
{
CleanedLines.Add(Lines[i]);
}
//At least this line will be removed
else if(!bHasRemovedLines)
{
bHasRemovedLines = true;
}
}
else
{
......@@ -363,6 +370,12 @@ void USFParticipant::RemoveLinesOfConditionAndWriteToFile(USFCondition* Conditio
CleanedLines.Add(Lines[i]);
}
}
if(bHasRemovedLines)
{
CreateLongTableBackUp(Filename);
}
FFileHelper::SaveStringArrayToFile(CleanedLines, *Filename, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM,
&IFileManager::Get(), EFileWrite::FILEWRITE_None);
}
......@@ -451,6 +464,15 @@ TArray<USFCondition*> USFParticipant::GetLastParticipantsConditions()
TArray<USFCondition*> LoadedConditions;
TMap<USFIndependentVariable*, FString> LoadedIndependentVariablesValues;
ReadExecutionJsonFile(GetLastParticipantID(), LoadedConditions, LoadedIndependentVariablesValues);
//Load WasStarted-Values from JSON, to ensure data is not overwritten without backups, if conditions are restarted
TMap<FString, bool> LastParticipantHasStartedConditionValues = GetLastParticipantHasStartedConditionValues();
for(int i = 0; i<LoadedConditions.Num(); i++)
{
if(LastParticipantHasStartedConditionValues.Contains(LoadedConditions[i]->CreateIdentifiableName()))
{
LoadedConditions[i]->SetbStarted(LastParticipantHasStartedConditionValues[LoadedConditions[i]->CreateIdentifiableName()]);
}
}
return LoadedConditions;
}
......@@ -487,6 +509,27 @@ int USFParticipant::GetLastParticipantLastConditionStarted()
return ParticipantJson->GetNumberField("CurrentConditionIdx");
}
TMap<FString, bool> USFParticipant::GetLastParticipantHasStartedConditionValues()
{
TMap<FString, bool> ConditionsStarted;
TSharedPtr<FJsonObject> ParticipantJson = FSFUtils::ReadJsonFromFile("StudyRuns/LastParticipant.txt");
if (ParticipantJson != nullptr)
{
TArray<TSharedPtr<FJsonValue>> StartedConditionsArray = ParticipantJson->GetArrayField("StartedConditions");
for(auto& JsonValue : StartedConditionsArray)
{
TSharedPtr<FJsonObject> Entry = JsonValue->AsObject();
if(Entry.IsValid())
{
ConditionsStarted.Add(Entry->GetStringField("Condition"), Entry->GetBoolField("WasStarted"));
}
}
}
return ConditionsStarted;
}
bool USFParticipant::GetLastParticipantFinished()
{
TSharedPtr<FJsonObject> ParticipantJson = FSFUtils::ReadJsonFromFile("StudyRuns/LastParticipant.txt");
......@@ -649,6 +692,16 @@ void USFParticipant::RecoverStudyResultsOfFinishedConditions()
}
}
void USFParticipant::CreateLongTableBackUp(const FString PathToSrcFile) const
{
IFileManager& FileManager = IFileManager::Get();
const FString ReplaceWith = "StudyFramework/StudyLogs/RecyclingBin/" + CurrentBackUpFolderName + "/";
const FString PathToDestFile = PathToSrcFile.Replace(TEXT("StudyFramework/StudyLogs/"), *ReplaceWith);
FileManager.Copy( *PathToDestFile, *PathToSrcFile);
FSFLoggingUtils::Log("Created Backup: " + PathToDestFile);
}
void USFParticipant::ClearPhaseLongtables(ASFStudySetup* StudySetup)
{
const FString LongTableFolder = FPaths::ProjectDir() + "StudyFramework/StudyLogs/";
......@@ -667,6 +720,12 @@ void USFParticipant::ClearPhaseLongtables(ASFStudySetup* StudySetup)
FSFLoggingUtils::Log("Moved .csv files: " + NewParentFolderPath);
}
void USFParticipant::SetCurrentBackUpFolderName(FString BackUpFolderName)
{
CurrentBackUpFolderName = BackUpFolderName;
}
bool USFParticipant::SetCondition(const USFCondition* NextCondition)
{
if (!NextCondition)
......@@ -707,10 +766,16 @@ void USFParticipant::LogCurrentParticipant() const
Json->SetNumberField("ParticipantSequenceNumber", ParticipantSequenceNumber);
Json->SetStringField("ParticipantID", ParticipantID);
bool bFinished = true;
TArray<TSharedPtr<FJsonValue>> StartedConditions; //Cannot use TMap because we want to save to JSON
for (USFCondition* Condition : Conditions)
{
bFinished = bFinished && (Condition->IsFinished() || !Condition->HasRequiredVariables());
TSharedPtr<FJsonObject> JsonObject = MakeShared<FJsonObject>();
JsonObject->SetStringField("Condition", Condition->CreateIdentifiableName());
JsonObject->SetBoolField("WasStarted", Condition->WasStarted());
StartedConditions.Add(MakeShared<FJsonValueObject>(JsonObject));
}
Json->SetArrayField("StartedConditions", StartedConditions);
Json->SetBoolField("Finished", bFinished);
Json->SetNumberField("CurrentConditionIdx", CurrentConditionIdx);
if (USFGameInstance::Get() && USFGameInstance::Get()->GetStudySetup())
......
......@@ -37,6 +37,7 @@ public:
bool IsFinished() const;
bool HasRequiredVariables() const;
bool WasStarted() const;
void SetbStarted(bool WasStarted);
//this is used to recover study results from the phase long table if a participant's run is continued
//return false if this entry does not match this condition
......
......@@ -50,6 +50,7 @@ public:
static int GetLastParticipantSequenceNumber();
static FString GetLastParticipantID();
static int GetLastParticipantLastConditionStarted();
static TMap<FString, bool> GetLastParticipantHasStartedConditionValues();
static bool GetLastParticipantFinished();
static ASFStudySetup* GetLastParticipantSetup();
void LoadLastParticipantsIndependentVariables();
......@@ -69,15 +70,21 @@ public:
void RecoverStudyResultsOfFinishedConditions();
// the results of all participants are stored in a file per phase (called longtable)
// for the data to be ready to use in statistics software, this methods clears all
// of that data (e.g. if study is entirely restarted)
// So: USE WITH CARE!
// The results of all participants are stored in a file per phase (called longtable)
// for the data to be ready to use in statistics software. This methods clears all
// of that data (e.g. if study is entirely restarted).
// The data can be recovered from /StudyLogs/RecyclingBin
static void ClearPhaseLongtables(ASFStudySetup* StudySetup);
// Whenever we delete data in a file (e.g. with by restarting a condition),
// we want to create a backup, to enable data recovery
// EditOperation reflects the reason (e.g. restart condition), which appears in
// recycling bin file name
void CreateLongTableBackUp(const FString PathToSrcFile) const;
void StoreTrialInTrialDVLongTable(USFMultipleTrialDependentVariable* DependentVariable, TArray<FString> Values) const;
void DeleteStoredDataForConditionFromLongTable(USFCondition* Condition);
void DeleteStoredTrialDataForCondition(USFCondition* Condition, USFMultipleTrialDependentVariable* DependentVariable);
void SetCurrentBackUpFolderName(FString BackUpFolderName);
protected:
bool SetCondition(const USFCondition* NextCondition);
......@@ -93,7 +100,13 @@ protected:
void StoreInIndependentVarLongTable() const;
void RemoveLinesOfConditionAndWriteToFile(USFCondition* Condition, FString Filename);
// This is the parent folder within RecyclingBin, where backups
// of the current operation will be stored.
// E.g. "RestartConditionBackUp-TIMESTAMP"
// Whenever we delete lines within a .csv file we should update this.
// We want to store all files related to one operation in the same
// backup folder, this is why we need this variable.
FString CurrentBackUpFolderName;
FString ParticipantID;
//sequence number is used for randomization etc. it is also unique per participant and starts at 0
int ParticipantSequenceNumber;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment