Add method-stage drill backend packet
This commit is contained in:
parent
ca345ec5b6
commit
0bc79a8173
11 changed files with 2619 additions and 1 deletions
|
|
@ -20,6 +20,80 @@ namespace HyperTwistContractLibraryInternal
|
|||
{
|
||||
return FJsonObjectConverter::JsonObjectStringToUStruct(Json, &OutValue, 0, 0);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingSourceAttribution MakeMethodDrillCleanRoomAttribution()
|
||||
{
|
||||
FHyperTwistTrainingSourceAttribution Attribution;
|
||||
Attribution.SourceMode = EHyperTwistTrainingSourceMode::CleanRoom;
|
||||
Attribution.SourceRepo = TEXT("onionhoney/roux-trainers");
|
||||
Attribution.SourceLicense = TEXT("GPLv3 clean-room behavioral handoff");
|
||||
Attribution.SourceNotes = TEXT("First-party HyperTwist method-stage drill sample built from scrubbed clean-room guidance.");
|
||||
return Attribution;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingDeck MakeSampleMethodDrillDeck()
|
||||
{
|
||||
const FHyperTwistTrainingSourceAttribution Attribution = MakeMethodDrillCleanRoomAttribution();
|
||||
|
||||
FHyperTwistTrainingCase RecognitionCaseA;
|
||||
RecognitionCaseA.CaseId = TEXT("roux-block-case-01");
|
||||
RecognitionCaseA.PuzzleId = TEXT("cube/3x3x3");
|
||||
RecognitionCaseA.PromptKind = EHyperTwistTrainingPromptKind::Recognition;
|
||||
RecognitionCaseA.PromptLabel = TEXT("Left Block Recognition A");
|
||||
RecognitionCaseA.CanonicalStateRef = TEXT("cube/3x3x3:roux:first-block:left:a");
|
||||
RecognitionCaseA.CanonicalNotation = TEXT("R U R'");
|
||||
RecognitionCaseA.ScrambleNotation = TEXT("U R U' L' U");
|
||||
RecognitionCaseA.SubsetId = TEXT("first-block");
|
||||
RecognitionCaseA.Difficulty = 0.45f;
|
||||
RecognitionCaseA.Tags = {
|
||||
TEXT("classic"),
|
||||
TEXT("roux"),
|
||||
TEXT("block-building"),
|
||||
TEXT("subset:first-block"),
|
||||
TEXT("stage-recognition")
|
||||
};
|
||||
RecognitionCaseA.AllowedDeliveryModes = {
|
||||
EHyperTwistTrainingDeliveryMode::VirtualCube,
|
||||
EHyperTwistTrainingDeliveryMode::RecognitionAssisted,
|
||||
EHyperTwistTrainingDeliveryMode::CoachReviewed
|
||||
};
|
||||
RecognitionCaseA.TimeTargetMs = 0;
|
||||
RecognitionCaseA.SourceAttribution = Attribution;
|
||||
|
||||
FHyperTwistTrainingCase RecognitionCaseB = RecognitionCaseA;
|
||||
RecognitionCaseB.CaseId = TEXT("roux-block-case-02");
|
||||
RecognitionCaseB.PromptLabel = TEXT("Left Block Recognition B");
|
||||
RecognitionCaseB.CanonicalStateRef = TEXT("cube/3x3x3:roux:first-block:left:b");
|
||||
RecognitionCaseB.CanonicalNotation = TEXT("r U' r'");
|
||||
RecognitionCaseB.ScrambleNotation = TEXT("R U2 R' F U'");
|
||||
RecognitionCaseB.Difficulty = 0.62f;
|
||||
|
||||
FHyperTwistTrainingDeck DrillDeck;
|
||||
DrillDeck.DeckId = TEXT("roux-first-block-recognition");
|
||||
DrillDeck.Title = TEXT("First Block Recognition");
|
||||
DrillDeck.DeliveryModes = {
|
||||
EHyperTwistTrainingDeliveryMode::VirtualCube,
|
||||
EHyperTwistTrainingDeliveryMode::RecognitionAssisted,
|
||||
EHyperTwistTrainingDeliveryMode::CoachReviewed
|
||||
};
|
||||
DrillDeck.SelectionPolicy = EHyperTwistTrainingSelectionPolicy::Scripted;
|
||||
DrillDeck.bUsesRealScrambles = false;
|
||||
DrillDeck.bSupportsAlgorithmReveal = true;
|
||||
DrillDeck.bSupportsVirtualCube = true;
|
||||
DrillDeck.bSupportsSmartCube = false;
|
||||
DrillDeck.Cases = {RecognitionCaseA, RecognitionCaseB};
|
||||
DrillDeck.DifficultyBand = TEXT("stage");
|
||||
DrillDeck.Tags = {
|
||||
TEXT("classic"),
|
||||
TEXT("roux"),
|
||||
TEXT("block-building"),
|
||||
TEXT("subset:first-block"),
|
||||
TEXT("method-drill")
|
||||
};
|
||||
DrillDeck.SubsetId = TEXT("first-block");
|
||||
DrillDeck.SourceAttribution = Attribution;
|
||||
return DrillDeck;
|
||||
}
|
||||
}
|
||||
|
||||
FHyperTwistPuzzleDefinitionRef UHyperTwistContractLibrary::MakeSampleClassicPuzzleDefinition()
|
||||
|
|
@ -329,6 +403,96 @@ FHyperTwistTrainingRunState UHyperTwistContractLibrary::MakeSampleTrainingRunSta
|
|||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillDefinition UHyperTwistContractLibrary::MakeSampleMethodDrillDefinition()
|
||||
{
|
||||
FHyperTwistTrainingMethodDrillDefinition DrillDefinition =
|
||||
UHyperTwistTrainingLibrary::BuildMethodDrillDefinitionFromDeck(
|
||||
HyperTwistContractLibraryInternal::MakeSampleMethodDrillDeck(),
|
||||
EHyperTwistTrainingDrillModeKind::Recognition,
|
||||
EHyperTwistTrainingDrillVisibilityPolicy::MaskedState,
|
||||
true,
|
||||
EHyperTwistTrainingDrillEntrySource::Catalog
|
||||
);
|
||||
DrillDefinition.Title = TEXT("Roux First Block Recognition Drill");
|
||||
DrillDefinition.StageId = TEXT("first-block");
|
||||
DrillDefinition.StageLabel = TEXT("First Block");
|
||||
return DrillDefinition;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistContractLibrary::MakeSampleMethodDrillRunState()
|
||||
{
|
||||
const FHyperTwistTrainingMethodDrillDefinition DrillDefinition = MakeSampleMethodDrillDefinition();
|
||||
if (!DrillDefinition.IsStructurallyValid())
|
||||
{
|
||||
return FHyperTwistTrainingMethodDrillRunState();
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingMethodDrillRunState ReadyRun = UHyperTwistTrainingLibrary::StartMethodDrillRun(
|
||||
DrillDefinition,
|
||||
TEXT("local-user"),
|
||||
TEXT("method_drill_run_01")
|
||||
);
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState ActiveRun = UHyperTwistTrainingLibrary::StartNextMethodDrillCase(ReadyRun);
|
||||
if (!ActiveRun.IsStructurallyValid())
|
||||
{
|
||||
return FHyperTwistTrainingMethodDrillRunState();
|
||||
}
|
||||
|
||||
ActiveRun.StartedAtUtc = TEXT("2026-04-25T12:12:00Z");
|
||||
ActiveRun.LastUpdatedAtUtc = TEXT("2026-04-25T12:12:05Z");
|
||||
return ActiveRun;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillSummary UHyperTwistContractLibrary::MakeSampleMethodDrillSummary()
|
||||
{
|
||||
return UHyperTwistTrainingLibrary::DeriveMethodDrillSummary(MakeSampleMethodDrillRunState());
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillFavoriteEntry UHyperTwistContractLibrary::MakeSampleMethodDrillFavoriteEntry()
|
||||
{
|
||||
return UHyperTwistTrainingRepositoryLibrary::MakeMethodDrillFavoriteEntry(
|
||||
MakeSampleMethodDrillDefinition(),
|
||||
TEXT("local-user"),
|
||||
TEXT("roux-block-case-01"),
|
||||
TEXT("2026-04-25T12:11:00Z")
|
||||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillBatch UHyperTwistContractLibrary::MakeSampleMethodDrillBatch()
|
||||
{
|
||||
FHyperTwistTrainingMethodDrillRunState RunState = MakeSampleMethodDrillRunState();
|
||||
if (!RunState.IsStructurallyValid())
|
||||
{
|
||||
return FHyperTwistTrainingMethodDrillBatch();
|
||||
}
|
||||
|
||||
RunState = UHyperTwistTrainingLibrary::RevealMethodDrillCase(RunState);
|
||||
|
||||
FHyperTwistTrainingMethodDrillResponseRecord ResponseRecord;
|
||||
ResponseRecord.ResponseId = TEXT("method_drill_response_01");
|
||||
ResponseRecord.DrillRunId = RunState.RunId;
|
||||
ResponseRecord.CaseId = RunState.CurrentCase.CaseId;
|
||||
ResponseRecord.PresentedAtUtc = RunState.StartedAtUtc;
|
||||
ResponseRecord.RespondedAtUtc = TEXT("2026-04-25T12:13:00Z");
|
||||
ResponseRecord.DrillMode = RunState.DrillDefinition.DrillMode;
|
||||
ResponseRecord.VisibilityPolicy = RunState.DrillDefinition.VisibilityPolicy;
|
||||
ResponseRecord.bAnswerWasRevealed = true;
|
||||
ResponseRecord.bMarkedCorrect = true;
|
||||
ResponseRecord.bWasRepeat = false;
|
||||
ResponseRecord.ElapsedMs = 1850;
|
||||
ResponseRecord.ResponseText = TEXT("identified left block anchor and follow-up pair");
|
||||
RunState.Responses.Add(ResponseRecord);
|
||||
RunState.LastUpdatedAtUtc = ResponseRecord.RespondedAtUtc;
|
||||
|
||||
return UHyperTwistTrainingLibrary::BuildMethodDrillBatch(
|
||||
RunState,
|
||||
TEXT("method_drill_batch_01"),
|
||||
TEXT("Pinned Roux Recognition Queue"),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunStepResult UHyperTwistContractLibrary::MakeSampleTrainingRunStepResult()
|
||||
{
|
||||
const FHyperTwistTrainingRunState RunState = MakeSampleTrainingRunState();
|
||||
|
|
@ -434,6 +598,24 @@ FHyperTwistTrainingRepositoryState UHyperTwistContractLibrary::MakeSampleTrainin
|
|||
);
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingMethodDrillFavoriteEntry FavoriteEntry = MakeSampleMethodDrillFavoriteEntry();
|
||||
if (FavoriteEntry.IsStructurallyValid())
|
||||
{
|
||||
RepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertMethodDrillFavorite(
|
||||
RepositoryState,
|
||||
FavoriteEntry
|
||||
);
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingMethodDrillBatch DrillBatch = MakeSampleMethodDrillBatch();
|
||||
if (DrillBatch.IsStructurallyValid())
|
||||
{
|
||||
RepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertMethodDrillBatch(
|
||||
RepositoryState,
|
||||
DrillBatch
|
||||
);
|
||||
}
|
||||
|
||||
return RepositoryState;
|
||||
}
|
||||
|
||||
|
|
@ -468,6 +650,22 @@ FHyperTwistTrainingRepositoryIntegrityReport UHyperTwistContractLibrary::MakeSam
|
|||
}
|
||||
RepositoryState.StoredSessionTemplates.Add(FHyperTwistTrainingSessionTemplate());
|
||||
|
||||
const FHyperTwistTrainingMethodDrillFavoriteEntry FavoriteEntry = MakeSampleMethodDrillFavoriteEntry();
|
||||
if (FavoriteEntry.IsStructurallyValid())
|
||||
{
|
||||
RepositoryState.StoredMethodDrillFavorites.Add(FavoriteEntry);
|
||||
RepositoryState.StoredMethodDrillFavorites.Add(FavoriteEntry);
|
||||
}
|
||||
RepositoryState.StoredMethodDrillFavorites.Add(FHyperTwistTrainingMethodDrillFavoriteEntry());
|
||||
|
||||
const FHyperTwistTrainingMethodDrillBatch DrillBatch = MakeSampleMethodDrillBatch();
|
||||
if (DrillBatch.IsStructurallyValid())
|
||||
{
|
||||
RepositoryState.StoredMethodDrillBatches.Add(DrillBatch);
|
||||
RepositoryState.StoredMethodDrillBatches.Add(DrillBatch);
|
||||
}
|
||||
RepositoryState.StoredMethodDrillBatches.Add(FHyperTwistTrainingMethodDrillBatch());
|
||||
|
||||
return UHyperTwistTrainingRepositoryLibrary::DeriveRepositoryIntegrityReport(RepositoryState);
|
||||
}
|
||||
|
||||
|
|
@ -845,6 +1043,34 @@ FString UHyperTwistContractLibrary::SerializeContentPackToJson(const FHyperTwist
|
|||
return HyperTwistContractLibraryInternal::SerializeStructToJson(ContentPack);
|
||||
}
|
||||
|
||||
FString UHyperTwistContractLibrary::SerializeMethodDrillDefinitionToJson(
|
||||
const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition
|
||||
)
|
||||
{
|
||||
return HyperTwistContractLibraryInternal::SerializeStructToJson(DrillDefinition);
|
||||
}
|
||||
|
||||
FString UHyperTwistContractLibrary::SerializeMethodDrillRunStateToJson(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState
|
||||
)
|
||||
{
|
||||
return HyperTwistContractLibraryInternal::SerializeStructToJson(RunState);
|
||||
}
|
||||
|
||||
FString UHyperTwistContractLibrary::SerializeMethodDrillFavoriteEntryToJson(
|
||||
const FHyperTwistTrainingMethodDrillFavoriteEntry& FavoriteEntry
|
||||
)
|
||||
{
|
||||
return HyperTwistContractLibraryInternal::SerializeStructToJson(FavoriteEntry);
|
||||
}
|
||||
|
||||
FString UHyperTwistContractLibrary::SerializeMethodDrillBatchToJson(
|
||||
const FHyperTwistTrainingMethodDrillBatch& DrillBatch
|
||||
)
|
||||
{
|
||||
return HyperTwistContractLibraryInternal::SerializeStructToJson(DrillBatch);
|
||||
}
|
||||
|
||||
FString UHyperTwistContractLibrary::SerializeTrainingRepositoryStateToJson(const FHyperTwistTrainingRepositoryState& RepositoryState)
|
||||
{
|
||||
return HyperTwistContractLibraryInternal::SerializeStructToJson(RepositoryState);
|
||||
|
|
@ -872,6 +1098,38 @@ bool UHyperTwistContractLibrary::DeserializeContentPackFromJson(const FString& J
|
|||
return HyperTwistContractLibraryInternal::DeserializeStructFromJson(Json, OutContentPack);
|
||||
}
|
||||
|
||||
bool UHyperTwistContractLibrary::DeserializeMethodDrillDefinitionFromJson(
|
||||
const FString& Json,
|
||||
FHyperTwistTrainingMethodDrillDefinition& OutDrillDefinition
|
||||
)
|
||||
{
|
||||
return HyperTwistContractLibraryInternal::DeserializeStructFromJson(Json, OutDrillDefinition);
|
||||
}
|
||||
|
||||
bool UHyperTwistContractLibrary::DeserializeMethodDrillRunStateFromJson(
|
||||
const FString& Json,
|
||||
FHyperTwistTrainingMethodDrillRunState& OutRunState
|
||||
)
|
||||
{
|
||||
return HyperTwistContractLibraryInternal::DeserializeStructFromJson(Json, OutRunState);
|
||||
}
|
||||
|
||||
bool UHyperTwistContractLibrary::DeserializeMethodDrillFavoriteEntryFromJson(
|
||||
const FString& Json,
|
||||
FHyperTwistTrainingMethodDrillFavoriteEntry& OutFavoriteEntry
|
||||
)
|
||||
{
|
||||
return HyperTwistContractLibraryInternal::DeserializeStructFromJson(Json, OutFavoriteEntry);
|
||||
}
|
||||
|
||||
bool UHyperTwistContractLibrary::DeserializeMethodDrillBatchFromJson(
|
||||
const FString& Json,
|
||||
FHyperTwistTrainingMethodDrillBatch& OutDrillBatch
|
||||
)
|
||||
{
|
||||
return HyperTwistContractLibraryInternal::DeserializeStructFromJson(Json, OutDrillBatch);
|
||||
}
|
||||
|
||||
bool UHyperTwistContractLibrary::DeserializeTrainingRepositoryStateFromJson(const FString& Json, FHyperTwistTrainingRepositoryState& OutRepositoryState)
|
||||
{
|
||||
return HyperTwistContractLibraryInternal::DeserializeStructFromJson(Json, OutRepositoryState);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "HyperTwistTraining/HyperTwistTrainingLibrary.h"
|
||||
|
||||
#include "HyperTwistTraining/HyperTwistTrainingCatalogLibrary.h"
|
||||
#include "HyperTwistReplay/HyperTwistReplayLibrary.h"
|
||||
#include "JsonObjectConverter.h"
|
||||
|
||||
|
|
@ -471,6 +472,171 @@ namespace HyperTwistTrainingLibraryInternal
|
|||
FJsonObjectConverter::UStructToJsonObjectString(Payload, PayloadJson);
|
||||
return PayloadJson;
|
||||
}
|
||||
|
||||
FString ResolveDrillTimestamp(const FString& Value)
|
||||
{
|
||||
return Value.IsEmpty() ? FDateTime::UtcNow().ToIso8601() : Value;
|
||||
}
|
||||
|
||||
FString DrillModeToToken(EHyperTwistTrainingDrillModeKind DrillMode)
|
||||
{
|
||||
switch (DrillMode)
|
||||
{
|
||||
case EHyperTwistTrainingDrillModeKind::Recognition:
|
||||
return TEXT("recognition");
|
||||
case EHyperTwistTrainingDrillModeKind::Recall:
|
||||
return TEXT("recall");
|
||||
case EHyperTwistTrainingDrillModeKind::Execution:
|
||||
return TEXT("execution");
|
||||
case EHyperTwistTrainingDrillModeKind::Reconstruction:
|
||||
return TEXT("reconstruction");
|
||||
default:
|
||||
return TEXT("drill");
|
||||
}
|
||||
}
|
||||
|
||||
FString DrillVisibilityToToken(EHyperTwistTrainingDrillVisibilityPolicy VisibilityPolicy)
|
||||
{
|
||||
switch (VisibilityPolicy)
|
||||
{
|
||||
case EHyperTwistTrainingDrillVisibilityPolicy::FullInformation:
|
||||
return TEXT("full");
|
||||
case EHyperTwistTrainingDrillVisibilityPolicy::PromptOnly:
|
||||
return TEXT("prompt-only");
|
||||
case EHyperTwistTrainingDrillVisibilityPolicy::MaskedState:
|
||||
return TEXT("masked");
|
||||
case EHyperTwistTrainingDrillVisibilityPolicy::PartialState:
|
||||
return TEXT("partial");
|
||||
default:
|
||||
return TEXT("visibility");
|
||||
}
|
||||
}
|
||||
|
||||
TArray<FString> BuildDrillCaseIds(const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition)
|
||||
{
|
||||
TArray<FString> CaseIds;
|
||||
if (!DrillDefinition.SourceDeck.IsStructurallyValid())
|
||||
{
|
||||
return CaseIds;
|
||||
}
|
||||
|
||||
if (DrillDefinition.FocusCaseIds.Num() > 0)
|
||||
{
|
||||
for (const FString& CaseId : DrillDefinition.FocusCaseIds)
|
||||
{
|
||||
const FHyperTwistTrainingCase* MatchingCase = FindCaseById(DrillDefinition.SourceDeck, CaseId);
|
||||
if (MatchingCase != nullptr && MatchingCase->IsStructurallyValid())
|
||||
{
|
||||
CaseIds.AddUnique(CaseId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CaseIds.Num() == 0)
|
||||
{
|
||||
for (const FHyperTwistTrainingCase& TrainingCase : DrillDefinition.SourceDeck.Cases)
|
||||
{
|
||||
if (TrainingCase.IsStructurallyValid())
|
||||
{
|
||||
CaseIds.AddUnique(TrainingCase.CaseId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CaseIds;
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingCase* FindDrillCaseById(
|
||||
const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
|
||||
const FString& CaseId
|
||||
)
|
||||
{
|
||||
return FindCaseById(DrillDefinition.SourceDeck, CaseId);
|
||||
}
|
||||
|
||||
void NormalizeDrillQueueAgainstDefinition(
|
||||
const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
|
||||
TArray<FString>& PendingCaseIds,
|
||||
TArray<FString>& CompletedCaseIds,
|
||||
FString& CurrentCaseId
|
||||
)
|
||||
{
|
||||
const TArray<FString> AllowedCaseIds = BuildDrillCaseIds(DrillDefinition);
|
||||
TSet<FString> AllowedCaseSet(AllowedCaseIds);
|
||||
|
||||
TArray<FString> NormalizedPending;
|
||||
for (const FString& CaseId : PendingCaseIds)
|
||||
{
|
||||
if (AllowedCaseSet.Contains(CaseId))
|
||||
{
|
||||
NormalizedPending.AddUnique(CaseId);
|
||||
}
|
||||
}
|
||||
|
||||
TArray<FString> NormalizedCompleted;
|
||||
for (const FString& CaseId : CompletedCaseIds)
|
||||
{
|
||||
if (AllowedCaseSet.Contains(CaseId))
|
||||
{
|
||||
NormalizedCompleted.AddUnique(CaseId);
|
||||
}
|
||||
}
|
||||
|
||||
PendingCaseIds = MoveTemp(NormalizedPending);
|
||||
CompletedCaseIds = MoveTemp(NormalizedCompleted);
|
||||
|
||||
if (!CurrentCaseId.IsEmpty())
|
||||
{
|
||||
if (!AllowedCaseSet.Contains(CurrentCaseId))
|
||||
{
|
||||
CurrentCaseId.Reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
CompletedCaseIds.Remove(CurrentCaseId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillSummary BuildDrillSummaryInternal(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingMethodDrillSummary Summary;
|
||||
if (!RunState.IsStructurallyValid())
|
||||
{
|
||||
return Summary;
|
||||
}
|
||||
|
||||
TSet<FString> KnownCaseIds;
|
||||
for (const FString& CaseId : RunState.PendingCaseIds)
|
||||
{
|
||||
KnownCaseIds.Add(CaseId);
|
||||
}
|
||||
for (const FString& CaseId : RunState.CompletedCaseIds)
|
||||
{
|
||||
KnownCaseIds.Add(CaseId);
|
||||
}
|
||||
if (!RunState.CurrentCase.CaseId.IsEmpty())
|
||||
{
|
||||
KnownCaseIds.Add(RunState.CurrentCase.CaseId);
|
||||
}
|
||||
|
||||
Summary.RunId = RunState.RunId;
|
||||
Summary.DrillId = RunState.DrillDefinition.DrillId;
|
||||
Summary.UserId = RunState.UserId;
|
||||
Summary.LifecycleState = RunState.LifecycleState;
|
||||
Summary.TotalCaseCount = KnownCaseIds.Num();
|
||||
Summary.PendingCaseCount = RunState.PendingCaseIds.Num();
|
||||
Summary.CompletedCaseCount = RunState.CompletedCaseIds.Num();
|
||||
Summary.ResponseCount = RunState.Responses.Num();
|
||||
Summary.RevealCount = RunState.RevealCount;
|
||||
Summary.RepeatCount = RunState.RepeatCount;
|
||||
Summary.bAnswerHiddenUntilReveal = RunState.DrillDefinition.bAnswerHiddenUntilReveal;
|
||||
Summary.CurrentCaseId = RunState.CurrentCase.CaseId;
|
||||
Summary.LastUpdatedAtUtc = RunState.LastUpdatedAtUtc;
|
||||
return Summary;
|
||||
}
|
||||
}
|
||||
|
||||
FHyperTwistContentPack UHyperTwistTrainingLibrary::MakeSampleClassicContentPack()
|
||||
|
|
@ -1449,3 +1615,351 @@ FHyperTwistTrainingRunStepResult UHyperTwistTrainingLibrary::ResolveTrainingRunA
|
|||
);
|
||||
return StepResult;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillDefinition UHyperTwistTrainingLibrary::BuildMethodDrillDefinitionFromDeck(
|
||||
const FHyperTwistTrainingDeck& Deck,
|
||||
EHyperTwistTrainingDrillModeKind DrillMode,
|
||||
EHyperTwistTrainingDrillVisibilityPolicy VisibilityPolicy,
|
||||
bool bAnswerHiddenUntilReveal,
|
||||
EHyperTwistTrainingDrillEntrySource EntrySource
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingMethodDrillDefinition DrillDefinition;
|
||||
if (!Deck.IsStructurallyValid())
|
||||
{
|
||||
return DrillDefinition;
|
||||
}
|
||||
|
||||
DrillDefinition.MethodDescriptor = UHyperTwistTrainingCatalogLibrary::DescribeTrainingDeckMethod(Deck);
|
||||
if (!DrillDefinition.MethodDescriptor.IsStructurallyValid())
|
||||
{
|
||||
return DrillDefinition;
|
||||
}
|
||||
|
||||
DrillDefinition.SourceDeckId = Deck.DeckId;
|
||||
DrillDefinition.SourceDeck = Deck;
|
||||
DrillDefinition.FocusCaseIds = HyperTwistTrainingLibraryInternal::BuildDrillCaseIds(DrillDefinition);
|
||||
DrillDefinition.DrillMode = DrillMode;
|
||||
DrillDefinition.VisibilityPolicy = VisibilityPolicy;
|
||||
DrillDefinition.EntrySource = EntrySource;
|
||||
DrillDefinition.bAnswerHiddenUntilReveal = bAnswerHiddenUntilReveal;
|
||||
DrillDefinition.bAllowImmediateRepeat = true;
|
||||
DrillDefinition.SourceAttribution = Deck.SourceAttribution;
|
||||
DrillDefinition.StageId = !Deck.SubsetId.IsEmpty()
|
||||
? Deck.SubsetId.ToLower()
|
||||
: DrillDefinition.MethodDescriptor.SegmentId;
|
||||
DrillDefinition.StageLabel = !Deck.SubsetId.IsEmpty()
|
||||
? Deck.SubsetId
|
||||
: DrillDefinition.MethodDescriptor.MethodLabel;
|
||||
DrillDefinition.DrillId = FString::Printf(
|
||||
TEXT("%s/drill/%s/%s"),
|
||||
*Deck.DeckId,
|
||||
*HyperTwistTrainingLibraryInternal::DrillModeToToken(DrillMode),
|
||||
*HyperTwistTrainingLibraryInternal::DrillVisibilityToToken(VisibilityPolicy)
|
||||
);
|
||||
DrillDefinition.Title = FString::Printf(TEXT("%s Drill"), *Deck.Title);
|
||||
DrillDefinition.Tags = Deck.Tags;
|
||||
DrillDefinition.Tags.AddUnique(TEXT("method-drill"));
|
||||
DrillDefinition.Tags.AddUnique(FString::Printf(
|
||||
TEXT("drill-mode:%s"),
|
||||
*HyperTwistTrainingLibraryInternal::DrillModeToToken(DrillMode)
|
||||
));
|
||||
DrillDefinition.Tags.AddUnique(FString::Printf(
|
||||
TEXT("visibility:%s"),
|
||||
*HyperTwistTrainingLibraryInternal::DrillVisibilityToToken(VisibilityPolicy)
|
||||
));
|
||||
DrillDefinition.Tags.AddUnique(FString::Printf(
|
||||
TEXT("method-segment:%s"),
|
||||
*DrillDefinition.MethodDescriptor.SegmentId.ToLower()
|
||||
));
|
||||
return DrillDefinition;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingLibrary::StartMethodDrillRun(
|
||||
const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
|
||||
const FString& UserId,
|
||||
const FString& RunId
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingMethodDrillRunState RunState;
|
||||
if (!DrillDefinition.IsStructurallyValid())
|
||||
{
|
||||
return RunState;
|
||||
}
|
||||
|
||||
RunState.DrillDefinition = DrillDefinition;
|
||||
RunState.RunId = RunId.IsEmpty()
|
||||
? FString::Printf(TEXT("method_drill_%s"), *DrillDefinition.DrillId)
|
||||
: RunId;
|
||||
RunState.UserId = UserId.IsEmpty() ? TEXT("local-user") : UserId;
|
||||
RunState.StartedAtUtc = FDateTime::UtcNow().ToIso8601();
|
||||
RunState.LastUpdatedAtUtc = RunState.StartedAtUtc;
|
||||
RunState.LifecycleState = EHyperTwistTrainingDrillLifecycleState::Ready;
|
||||
RunState.PendingCaseIds = HyperTwistTrainingLibraryInternal::BuildDrillCaseIds(DrillDefinition);
|
||||
if (RunState.PendingCaseIds.Num() == 0)
|
||||
{
|
||||
return FHyperTwistTrainingMethodDrillRunState();
|
||||
}
|
||||
|
||||
return RunState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingLibrary::ResumeMethodDrillRunFromBatch(
|
||||
const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
|
||||
const FHyperTwistTrainingMethodDrillBatch& DrillBatch,
|
||||
const FString& RunId
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingMethodDrillRunState RunState;
|
||||
if (!DrillDefinition.IsStructurallyValid()
|
||||
|| !DrillBatch.IsStructurallyValid()
|
||||
|| DrillBatch.DrillId != DrillDefinition.DrillId
|
||||
|| DrillBatch.SourceDeckId != DrillDefinition.SourceDeckId)
|
||||
{
|
||||
return RunState;
|
||||
}
|
||||
|
||||
RunState.DrillDefinition = DrillDefinition;
|
||||
RunState.RunId = RunId.IsEmpty()
|
||||
? FString::Printf(TEXT("method_drill_resume_%s"), *DrillBatch.BatchId)
|
||||
: RunId;
|
||||
RunState.UserId = DrillBatch.UserId;
|
||||
RunState.SourceBatchId = DrillBatch.BatchId;
|
||||
RunState.LifecycleState = DrillBatch.SavedLifecycleState;
|
||||
RunState.StartedAtUtc = HyperTwistTrainingLibraryInternal::ResolveDrillTimestamp(DrillBatch.CreatedAtUtc);
|
||||
RunState.LastUpdatedAtUtc = HyperTwistTrainingLibraryInternal::ResolveDrillTimestamp(DrillBatch.LastUpdatedAtUtc);
|
||||
RunState.PendingCaseIds = DrillBatch.PendingCaseIds;
|
||||
RunState.CompletedCaseIds = DrillBatch.CompletedCaseIds;
|
||||
RunState.Responses = DrillBatch.Responses;
|
||||
RunState.RevealCount = DrillBatch.RevealCount;
|
||||
RunState.RepeatCount = DrillBatch.RepeatCount;
|
||||
RunState.bAnswerVisible = RunState.LifecycleState == EHyperTwistTrainingDrillLifecycleState::Revealed;
|
||||
|
||||
FString CurrentCaseId = DrillBatch.CurrentCaseId;
|
||||
HyperTwistTrainingLibraryInternal::NormalizeDrillQueueAgainstDefinition(
|
||||
RunState.DrillDefinition,
|
||||
RunState.PendingCaseIds,
|
||||
RunState.CompletedCaseIds,
|
||||
CurrentCaseId
|
||||
);
|
||||
|
||||
if (!CurrentCaseId.IsEmpty())
|
||||
{
|
||||
const FHyperTwistTrainingCase* CurrentCase = HyperTwistTrainingLibraryInternal::FindDrillCaseById(
|
||||
RunState.DrillDefinition,
|
||||
CurrentCaseId
|
||||
);
|
||||
if (CurrentCase != nullptr && CurrentCase->IsStructurallyValid())
|
||||
{
|
||||
RunState.CurrentCase = *CurrentCase;
|
||||
}
|
||||
}
|
||||
|
||||
if ((RunState.LifecycleState == EHyperTwistTrainingDrillLifecycleState::Active
|
||||
|| RunState.LifecycleState == EHyperTwistTrainingDrillLifecycleState::Revealed)
|
||||
&& !RunState.CurrentCase.IsStructurallyValid())
|
||||
{
|
||||
RunState.LifecycleState = EHyperTwistTrainingDrillLifecycleState::Ready;
|
||||
RunState.bAnswerVisible = false;
|
||||
}
|
||||
|
||||
if (RunState.LifecycleState == EHyperTwistTrainingDrillLifecycleState::Completed
|
||||
|| RunState.LifecycleState == EHyperTwistTrainingDrillLifecycleState::Aborted)
|
||||
{
|
||||
RunState.EndedAtUtc = RunState.LastUpdatedAtUtc;
|
||||
RunState.CurrentCase = FHyperTwistTrainingCase();
|
||||
RunState.bAnswerVisible = false;
|
||||
}
|
||||
|
||||
return RunState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingLibrary::StartNextMethodDrillCase(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingMethodDrillRunState UpdatedRunState = RunState;
|
||||
if (!UpdatedRunState.IsStructurallyValid()
|
||||
|| UpdatedRunState.LifecycleState != EHyperTwistTrainingDrillLifecycleState::Ready)
|
||||
{
|
||||
return UpdatedRunState;
|
||||
}
|
||||
|
||||
FString CurrentCaseId = UpdatedRunState.CurrentCase.CaseId;
|
||||
HyperTwistTrainingLibraryInternal::NormalizeDrillQueueAgainstDefinition(
|
||||
UpdatedRunState.DrillDefinition,
|
||||
UpdatedRunState.PendingCaseIds,
|
||||
UpdatedRunState.CompletedCaseIds,
|
||||
CurrentCaseId
|
||||
);
|
||||
|
||||
if (UpdatedRunState.PendingCaseIds.Num() == 0)
|
||||
{
|
||||
return FinishMethodDrillRun(UpdatedRunState, false);
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingCase* NextCase = HyperTwistTrainingLibraryInternal::FindDrillCaseById(
|
||||
UpdatedRunState.DrillDefinition,
|
||||
UpdatedRunState.PendingCaseIds[0]
|
||||
);
|
||||
if (NextCase == nullptr || !NextCase->IsStructurallyValid())
|
||||
{
|
||||
UpdatedRunState.PendingCaseIds.RemoveAt(0);
|
||||
return StartNextMethodDrillCase(UpdatedRunState);
|
||||
}
|
||||
|
||||
UpdatedRunState.CurrentCase = *NextCase;
|
||||
UpdatedRunState.LifecycleState = EHyperTwistTrainingDrillLifecycleState::Active;
|
||||
UpdatedRunState.bAnswerVisible = !UpdatedRunState.DrillDefinition.bAnswerHiddenUntilReveal;
|
||||
UpdatedRunState.LastUpdatedAtUtc = FDateTime::UtcNow().ToIso8601();
|
||||
return UpdatedRunState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingLibrary::RevealMethodDrillCase(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingMethodDrillRunState UpdatedRunState = RunState;
|
||||
if (!UpdatedRunState.IsStructurallyValid()
|
||||
|| UpdatedRunState.LifecycleState != EHyperTwistTrainingDrillLifecycleState::Active
|
||||
|| !UpdatedRunState.CurrentCase.IsStructurallyValid())
|
||||
{
|
||||
return UpdatedRunState;
|
||||
}
|
||||
|
||||
if (!UpdatedRunState.bAnswerVisible)
|
||||
{
|
||||
UpdatedRunState.RevealCount += 1;
|
||||
}
|
||||
|
||||
UpdatedRunState.bAnswerVisible = true;
|
||||
UpdatedRunState.LifecycleState = EHyperTwistTrainingDrillLifecycleState::Revealed;
|
||||
UpdatedRunState.LastUpdatedAtUtc = FDateTime::UtcNow().ToIso8601();
|
||||
return UpdatedRunState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingLibrary::RepeatMethodDrillCase(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingMethodDrillRunState UpdatedRunState = RunState;
|
||||
if (!UpdatedRunState.IsStructurallyValid()
|
||||
|| (UpdatedRunState.LifecycleState != EHyperTwistTrainingDrillLifecycleState::Active
|
||||
&& UpdatedRunState.LifecycleState != EHyperTwistTrainingDrillLifecycleState::Revealed)
|
||||
|| !UpdatedRunState.CurrentCase.IsStructurallyValid()
|
||||
|| !UpdatedRunState.DrillDefinition.bAllowImmediateRepeat)
|
||||
{
|
||||
return UpdatedRunState;
|
||||
}
|
||||
|
||||
UpdatedRunState.RepeatCount += 1;
|
||||
UpdatedRunState.bAnswerVisible = !UpdatedRunState.DrillDefinition.bAnswerHiddenUntilReveal;
|
||||
UpdatedRunState.LifecycleState = EHyperTwistTrainingDrillLifecycleState::Active;
|
||||
UpdatedRunState.LastUpdatedAtUtc = FDateTime::UtcNow().ToIso8601();
|
||||
return UpdatedRunState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingLibrary::AdvanceMethodDrillCase(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingMethodDrillRunState UpdatedRunState = RunState;
|
||||
if (!UpdatedRunState.IsStructurallyValid()
|
||||
|| (UpdatedRunState.LifecycleState != EHyperTwistTrainingDrillLifecycleState::Active
|
||||
&& UpdatedRunState.LifecycleState != EHyperTwistTrainingDrillLifecycleState::Revealed)
|
||||
|| !UpdatedRunState.CurrentCase.IsStructurallyValid())
|
||||
{
|
||||
return UpdatedRunState;
|
||||
}
|
||||
|
||||
const FString CompletedCaseId = UpdatedRunState.CurrentCase.CaseId;
|
||||
UpdatedRunState.PendingCaseIds.Remove(CompletedCaseId);
|
||||
UpdatedRunState.CompletedCaseIds.AddUnique(CompletedCaseId);
|
||||
UpdatedRunState.CurrentCase = FHyperTwistTrainingCase();
|
||||
UpdatedRunState.bAnswerVisible = false;
|
||||
UpdatedRunState.LastUpdatedAtUtc = FDateTime::UtcNow().ToIso8601();
|
||||
|
||||
FString CurrentCaseId;
|
||||
HyperTwistTrainingLibraryInternal::NormalizeDrillQueueAgainstDefinition(
|
||||
UpdatedRunState.DrillDefinition,
|
||||
UpdatedRunState.PendingCaseIds,
|
||||
UpdatedRunState.CompletedCaseIds,
|
||||
CurrentCaseId
|
||||
);
|
||||
|
||||
UpdatedRunState.LifecycleState = UpdatedRunState.PendingCaseIds.Num() > 0
|
||||
? EHyperTwistTrainingDrillLifecycleState::Ready
|
||||
: EHyperTwistTrainingDrillLifecycleState::Completed;
|
||||
|
||||
if (UpdatedRunState.LifecycleState == EHyperTwistTrainingDrillLifecycleState::Completed)
|
||||
{
|
||||
UpdatedRunState.EndedAtUtc = UpdatedRunState.LastUpdatedAtUtc;
|
||||
}
|
||||
|
||||
return UpdatedRunState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingLibrary::FinishMethodDrillRun(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState,
|
||||
bool bAbortRun
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingMethodDrillRunState UpdatedRunState = RunState;
|
||||
if (!UpdatedRunState.IsStructurallyValid())
|
||||
{
|
||||
return UpdatedRunState;
|
||||
}
|
||||
|
||||
UpdatedRunState.LifecycleState = bAbortRun
|
||||
? EHyperTwistTrainingDrillLifecycleState::Aborted
|
||||
: EHyperTwistTrainingDrillLifecycleState::Completed;
|
||||
UpdatedRunState.EndedAtUtc = FDateTime::UtcNow().ToIso8601();
|
||||
UpdatedRunState.LastUpdatedAtUtc = UpdatedRunState.EndedAtUtc;
|
||||
UpdatedRunState.CurrentCase = FHyperTwistTrainingCase();
|
||||
UpdatedRunState.bAnswerVisible = false;
|
||||
return UpdatedRunState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillSummary UHyperTwistTrainingLibrary::DeriveMethodDrillSummary(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState
|
||||
)
|
||||
{
|
||||
return HyperTwistTrainingLibraryInternal::BuildDrillSummaryInternal(RunState);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillBatch UHyperTwistTrainingLibrary::BuildMethodDrillBatch(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState,
|
||||
const FString& BatchId,
|
||||
const FString& Title,
|
||||
bool bPinnedFavoritesOnly
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingMethodDrillBatch DrillBatch;
|
||||
if (!RunState.IsStructurallyValid())
|
||||
{
|
||||
return DrillBatch;
|
||||
}
|
||||
|
||||
DrillBatch.UserId = RunState.UserId;
|
||||
DrillBatch.BatchId = BatchId.IsEmpty()
|
||||
? FString::Printf(TEXT("method_drill_batch_%s"), *RunState.RunId)
|
||||
: BatchId;
|
||||
DrillBatch.Title = Title.IsEmpty() ? RunState.DrillDefinition.Title : Title;
|
||||
DrillBatch.DrillId = RunState.DrillDefinition.DrillId;
|
||||
DrillBatch.SourceDeckId = RunState.DrillDefinition.SourceDeckId;
|
||||
DrillBatch.MethodDescriptor = RunState.DrillDefinition.MethodDescriptor;
|
||||
DrillBatch.DrillMode = RunState.DrillDefinition.DrillMode;
|
||||
DrillBatch.VisibilityPolicy = RunState.DrillDefinition.VisibilityPolicy;
|
||||
DrillBatch.bAnswerHiddenUntilReveal = RunState.DrillDefinition.bAnswerHiddenUntilReveal;
|
||||
DrillBatch.SavedLifecycleState = RunState.LifecycleState;
|
||||
DrillBatch.PendingCaseIds = RunState.PendingCaseIds;
|
||||
DrillBatch.CompletedCaseIds = RunState.CompletedCaseIds;
|
||||
DrillBatch.CurrentCaseId = RunState.CurrentCase.CaseId;
|
||||
DrillBatch.Responses = RunState.Responses;
|
||||
DrillBatch.RevealCount = RunState.RevealCount;
|
||||
DrillBatch.RepeatCount = RunState.RepeatCount;
|
||||
DrillBatch.CreatedAtUtc = HyperTwistTrainingLibraryInternal::ResolveDrillTimestamp(RunState.StartedAtUtc);
|
||||
DrillBatch.LastUpdatedAtUtc = HyperTwistTrainingLibraryInternal::ResolveDrillTimestamp(RunState.LastUpdatedAtUtc);
|
||||
DrillBatch.bPinnedFavoritesOnly = bPinnedFavoritesOnly;
|
||||
return DrillBatch;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -282,6 +282,54 @@ namespace HyperTwistTrainingRepositoryLibraryInternal
|
|||
return UserId + CaseKeySeparator + TemplateId;
|
||||
}
|
||||
|
||||
FString MakeMethodDrillFavoriteKey(
|
||||
const FString& UserId,
|
||||
const FString& DrillId,
|
||||
const FString& CaseId
|
||||
)
|
||||
{
|
||||
return UserId + CaseKeySeparator + DrillId + CaseKeySeparator + CaseId;
|
||||
}
|
||||
|
||||
FString MakeMethodDrillBatchKey(const FString& UserId, const FString& BatchId)
|
||||
{
|
||||
return UserId + CaseKeySeparator + BatchId;
|
||||
}
|
||||
|
||||
TArray<FString> DeduplicateCaseIds(const TArray<FString>& CaseIds)
|
||||
{
|
||||
TArray<FString> UniqueCaseIds;
|
||||
for (const FString& CaseId : CaseIds)
|
||||
{
|
||||
if (!CaseId.IsEmpty())
|
||||
{
|
||||
UniqueCaseIds.AddUnique(CaseId);
|
||||
}
|
||||
}
|
||||
|
||||
return UniqueCaseIds;
|
||||
}
|
||||
|
||||
TArray<FHyperTwistTrainingMethodDrillResponseRecord> DeduplicateMethodDrillResponses(
|
||||
const TArray<FHyperTwistTrainingMethodDrillResponseRecord>& Responses
|
||||
)
|
||||
{
|
||||
TArray<FHyperTwistTrainingMethodDrillResponseRecord> UniqueResponses;
|
||||
TSet<FString> SeenResponseIds;
|
||||
for (const FHyperTwistTrainingMethodDrillResponseRecord& Response : Responses)
|
||||
{
|
||||
if (!Response.IsStructurallyValid() || SeenResponseIds.Contains(Response.ResponseId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
SeenResponseIds.Add(Response.ResponseId);
|
||||
UniqueResponses.Add(Response);
|
||||
}
|
||||
|
||||
return UniqueResponses;
|
||||
}
|
||||
|
||||
bool SplitCaseKey(const FString& CaseKey, FString& OutUserId, FString& OutDeckId, FString& OutCaseId)
|
||||
{
|
||||
TArray<FString> Parts;
|
||||
|
|
@ -308,6 +356,45 @@ namespace HyperTwistTrainingRepositoryLibraryInternal
|
|||
}
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillFavoriteEntry NormalizeMethodDrillFavoriteEntry(
|
||||
const FHyperTwistTrainingMethodDrillFavoriteEntry& FavoriteEntry
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingMethodDrillFavoriteEntry NormalizedFavorite = FavoriteEntry;
|
||||
NormalizedFavorite.Tags = DeduplicateTemplateCaseIds(FavoriteEntry.Tags);
|
||||
NormalizedFavorite.Tags.AddUnique(TEXT("favorite"));
|
||||
if (NormalizedFavorite.AddedAtUtc.IsEmpty())
|
||||
{
|
||||
NormalizedFavorite.AddedAtUtc = FDateTime::UtcNow().ToIso8601();
|
||||
}
|
||||
|
||||
return NormalizedFavorite;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillBatch NormalizeMethodDrillBatch(
|
||||
const FHyperTwistTrainingMethodDrillBatch& DrillBatch
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingMethodDrillBatch NormalizedBatch = DrillBatch;
|
||||
NormalizedBatch.PendingCaseIds = DeduplicateCaseIds(DrillBatch.PendingCaseIds);
|
||||
NormalizedBatch.CompletedCaseIds = DeduplicateCaseIds(DrillBatch.CompletedCaseIds);
|
||||
if (!NormalizedBatch.CurrentCaseId.IsEmpty())
|
||||
{
|
||||
NormalizedBatch.CompletedCaseIds.Remove(NormalizedBatch.CurrentCaseId);
|
||||
}
|
||||
NormalizedBatch.Responses = DeduplicateMethodDrillResponses(DrillBatch.Responses);
|
||||
if (NormalizedBatch.CreatedAtUtc.IsEmpty())
|
||||
{
|
||||
NormalizedBatch.CreatedAtUtc = FDateTime::UtcNow().ToIso8601();
|
||||
}
|
||||
if (NormalizedBatch.LastUpdatedAtUtc.IsEmpty())
|
||||
{
|
||||
NormalizedBatch.LastUpdatedAtUtc = NormalizedBatch.CreatedAtUtc;
|
||||
}
|
||||
|
||||
return NormalizedBatch;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingCaseLearnerState DeriveLearnerStateFromReviewHistory(
|
||||
const FString& UserId,
|
||||
const FString& DeckId,
|
||||
|
|
@ -1369,6 +1456,273 @@ FHyperTwistTrainingRunRecord UHyperTwistTrainingRepositoryLibrary::BuildRunRecor
|
|||
return RunRecord;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillFavoriteEntry UHyperTwistTrainingRepositoryLibrary::MakeMethodDrillFavoriteEntry(
|
||||
const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
|
||||
const FString& UserId,
|
||||
const FString& CaseId,
|
||||
const FString& AddedAtUtc
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingMethodDrillFavoriteEntry FavoriteEntry;
|
||||
if (!DrillDefinition.IsStructurallyValid() || UserId.IsEmpty() || CaseId.IsEmpty())
|
||||
{
|
||||
return FavoriteEntry;
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingCase* MatchingCase = DrillDefinition.SourceDeck.Cases.FindByPredicate(
|
||||
[&CaseId](const FHyperTwistTrainingCase& TrainingCase)
|
||||
{
|
||||
return TrainingCase.CaseId == CaseId;
|
||||
}
|
||||
);
|
||||
if (MatchingCase == nullptr || !MatchingCase->IsStructurallyValid())
|
||||
{
|
||||
return FavoriteEntry;
|
||||
}
|
||||
|
||||
FavoriteEntry.UserId = UserId;
|
||||
FavoriteEntry.DrillId = DrillDefinition.DrillId;
|
||||
FavoriteEntry.CaseId = CaseId;
|
||||
FavoriteEntry.SourceDeckId = DrillDefinition.SourceDeckId;
|
||||
FavoriteEntry.MethodDescriptor = DrillDefinition.MethodDescriptor;
|
||||
FavoriteEntry.AddedAtUtc = AddedAtUtc.IsEmpty() ? FDateTime::UtcNow().ToIso8601() : AddedAtUtc;
|
||||
FavoriteEntry.Tags = DrillDefinition.Tags;
|
||||
for (const FString& Tag : MatchingCase->Tags)
|
||||
{
|
||||
FavoriteEntry.Tags.AddUnique(Tag);
|
||||
}
|
||||
FavoriteEntry.Tags.AddUnique(TEXT("favorite"));
|
||||
return FavoriteEntry;
|
||||
}
|
||||
|
||||
TArray<FHyperTwistTrainingMethodDrillFavoriteEntry> UHyperTwistTrainingRepositoryLibrary::ListMethodDrillFavorites(
|
||||
const FHyperTwistTrainingRepositoryState& RepositoryState,
|
||||
const FString& UserId,
|
||||
const FString& MethodSegmentId
|
||||
)
|
||||
{
|
||||
TArray<FHyperTwistTrainingMethodDrillFavoriteEntry> Favorites;
|
||||
for (const FHyperTwistTrainingMethodDrillFavoriteEntry& FavoriteEntry : RepositoryState.StoredMethodDrillFavorites)
|
||||
{
|
||||
if (!FavoriteEntry.IsStructurallyValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool bMatchesUser = UserId.IsEmpty() || FavoriteEntry.UserId == UserId;
|
||||
const bool bMatchesSegment = MethodSegmentId.IsEmpty()
|
||||
|| FavoriteEntry.MethodDescriptor.SegmentId == MethodSegmentId;
|
||||
if (bMatchesUser && bMatchesSegment)
|
||||
{
|
||||
Favorites.Add(FavoriteEntry);
|
||||
}
|
||||
}
|
||||
|
||||
Favorites.Sort([](
|
||||
const FHyperTwistTrainingMethodDrillFavoriteEntry& Left,
|
||||
const FHyperTwistTrainingMethodDrillFavoriteEntry& Right
|
||||
)
|
||||
{
|
||||
const int32 AddedAtCompare = HyperTwistTrainingRepositoryLibraryInternal::CompareUtcStrings(
|
||||
Left.AddedAtUtc,
|
||||
Right.AddedAtUtc
|
||||
);
|
||||
if (AddedAtCompare != 0)
|
||||
{
|
||||
return AddedAtCompare > 0;
|
||||
}
|
||||
if (Left.DrillId != Right.DrillId)
|
||||
{
|
||||
return Left.DrillId < Right.DrillId;
|
||||
}
|
||||
return Left.CaseId < Right.CaseId;
|
||||
});
|
||||
|
||||
return Favorites;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRepositoryState UHyperTwistTrainingRepositoryLibrary::UpsertMethodDrillFavorite(
|
||||
const FHyperTwistTrainingRepositoryState& RepositoryState,
|
||||
const FHyperTwistTrainingMethodDrillFavoriteEntry& FavoriteEntry
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingRepositoryState UpdatedRepositoryState = RepositoryState;
|
||||
if (!FavoriteEntry.IsStructurallyValid())
|
||||
{
|
||||
return UpdatedRepositoryState;
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingMethodDrillFavoriteEntry NormalizedFavorite =
|
||||
HyperTwistTrainingRepositoryLibraryInternal::NormalizeMethodDrillFavoriteEntry(FavoriteEntry);
|
||||
FHyperTwistTrainingMethodDrillFavoriteEntry* ExistingFavorite =
|
||||
UpdatedRepositoryState.StoredMethodDrillFavorites.FindByPredicate(
|
||||
[&NormalizedFavorite](const FHyperTwistTrainingMethodDrillFavoriteEntry& Candidate)
|
||||
{
|
||||
return Candidate.UserId == NormalizedFavorite.UserId
|
||||
&& Candidate.DrillId == NormalizedFavorite.DrillId
|
||||
&& Candidate.CaseId == NormalizedFavorite.CaseId;
|
||||
}
|
||||
);
|
||||
|
||||
if (ExistingFavorite != nullptr)
|
||||
{
|
||||
*ExistingFavorite = NormalizedFavorite;
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdatedRepositoryState.StoredMethodDrillFavorites.Add(NormalizedFavorite);
|
||||
}
|
||||
|
||||
return UpdatedRepositoryState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRepositoryState UHyperTwistTrainingRepositoryLibrary::RemoveMethodDrillFavorite(
|
||||
const FHyperTwistTrainingRepositoryState& RepositoryState,
|
||||
const FString& UserId,
|
||||
const FString& DrillId,
|
||||
const FString& CaseId
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingRepositoryState UpdatedRepositoryState = RepositoryState;
|
||||
if (UserId.IsEmpty() || DrillId.IsEmpty() || CaseId.IsEmpty())
|
||||
{
|
||||
return UpdatedRepositoryState;
|
||||
}
|
||||
|
||||
UpdatedRepositoryState.StoredMethodDrillFavorites.RemoveAll(
|
||||
[&UserId, &DrillId, &CaseId](const FHyperTwistTrainingMethodDrillFavoriteEntry& Candidate)
|
||||
{
|
||||
return Candidate.UserId == UserId
|
||||
&& Candidate.DrillId == DrillId
|
||||
&& Candidate.CaseId == CaseId;
|
||||
}
|
||||
);
|
||||
return UpdatedRepositoryState;
|
||||
}
|
||||
|
||||
TArray<FHyperTwistTrainingMethodDrillBatch> UHyperTwistTrainingRepositoryLibrary::ListMethodDrillBatches(
|
||||
const FHyperTwistTrainingRepositoryState& RepositoryState,
|
||||
const FString& UserId,
|
||||
const FString& MethodSegmentId
|
||||
)
|
||||
{
|
||||
TArray<FHyperTwistTrainingMethodDrillBatch> Batches;
|
||||
for (const FHyperTwistTrainingMethodDrillBatch& DrillBatch : RepositoryState.StoredMethodDrillBatches)
|
||||
{
|
||||
if (!DrillBatch.IsStructurallyValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool bMatchesUser = UserId.IsEmpty() || DrillBatch.UserId == UserId;
|
||||
const bool bMatchesSegment = MethodSegmentId.IsEmpty()
|
||||
|| DrillBatch.MethodDescriptor.SegmentId == MethodSegmentId;
|
||||
if (bMatchesUser && bMatchesSegment)
|
||||
{
|
||||
Batches.Add(DrillBatch);
|
||||
}
|
||||
}
|
||||
|
||||
Batches.Sort([](const FHyperTwistTrainingMethodDrillBatch& Left, const FHyperTwistTrainingMethodDrillBatch& Right)
|
||||
{
|
||||
const int32 UpdatedAtCompare = HyperTwistTrainingRepositoryLibraryInternal::CompareUtcStrings(
|
||||
Left.LastUpdatedAtUtc,
|
||||
Right.LastUpdatedAtUtc
|
||||
);
|
||||
if (UpdatedAtCompare != 0)
|
||||
{
|
||||
return UpdatedAtCompare > 0;
|
||||
}
|
||||
return Left.BatchId < Right.BatchId;
|
||||
});
|
||||
|
||||
return Batches;
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingRepositoryLibrary::TryGetMethodDrillBatch(
|
||||
const FHyperTwistTrainingRepositoryState& RepositoryState,
|
||||
const FString& UserId,
|
||||
const FString& BatchId,
|
||||
FHyperTwistTrainingMethodDrillBatch& OutBatch
|
||||
)
|
||||
{
|
||||
OutBatch = FHyperTwistTrainingMethodDrillBatch();
|
||||
if (UserId.IsEmpty() || BatchId.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingMethodDrillBatch* MatchingBatch =
|
||||
RepositoryState.StoredMethodDrillBatches.FindByPredicate(
|
||||
[&UserId, &BatchId](const FHyperTwistTrainingMethodDrillBatch& Candidate)
|
||||
{
|
||||
return Candidate.UserId == UserId && Candidate.BatchId == BatchId;
|
||||
}
|
||||
);
|
||||
if (MatchingBatch == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
OutBatch = *MatchingBatch;
|
||||
return OutBatch.IsStructurallyValid();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRepositoryState UHyperTwistTrainingRepositoryLibrary::UpsertMethodDrillBatch(
|
||||
const FHyperTwistTrainingRepositoryState& RepositoryState,
|
||||
const FHyperTwistTrainingMethodDrillBatch& DrillBatch
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingRepositoryState UpdatedRepositoryState = RepositoryState;
|
||||
if (!DrillBatch.IsStructurallyValid())
|
||||
{
|
||||
return UpdatedRepositoryState;
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingMethodDrillBatch NormalizedBatch =
|
||||
HyperTwistTrainingRepositoryLibraryInternal::NormalizeMethodDrillBatch(DrillBatch);
|
||||
FHyperTwistTrainingMethodDrillBatch* ExistingBatch =
|
||||
UpdatedRepositoryState.StoredMethodDrillBatches.FindByPredicate(
|
||||
[&NormalizedBatch](const FHyperTwistTrainingMethodDrillBatch& Candidate)
|
||||
{
|
||||
return Candidate.UserId == NormalizedBatch.UserId
|
||||
&& Candidate.BatchId == NormalizedBatch.BatchId;
|
||||
}
|
||||
);
|
||||
|
||||
if (ExistingBatch != nullptr)
|
||||
{
|
||||
*ExistingBatch = NormalizedBatch;
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdatedRepositoryState.StoredMethodDrillBatches.Add(NormalizedBatch);
|
||||
}
|
||||
|
||||
return UpdatedRepositoryState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRepositoryState UHyperTwistTrainingRepositoryLibrary::RemoveMethodDrillBatch(
|
||||
const FHyperTwistTrainingRepositoryState& RepositoryState,
|
||||
const FString& UserId,
|
||||
const FString& BatchId
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingRepositoryState UpdatedRepositoryState = RepositoryState;
|
||||
if (UserId.IsEmpty() || BatchId.IsEmpty())
|
||||
{
|
||||
return UpdatedRepositoryState;
|
||||
}
|
||||
|
||||
UpdatedRepositoryState.StoredMethodDrillBatches.RemoveAll(
|
||||
[&UserId, &BatchId](const FHyperTwistTrainingMethodDrillBatch& Candidate)
|
||||
{
|
||||
return Candidate.UserId == UserId && Candidate.BatchId == BatchId;
|
||||
}
|
||||
);
|
||||
return UpdatedRepositoryState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRepositoryState UHyperTwistTrainingRepositoryLibrary::UpsertRunRecord(
|
||||
const FHyperTwistTrainingRepositoryState& RepositoryState,
|
||||
const FHyperTwistTrainingRunRecord& RunRecord
|
||||
|
|
@ -2176,6 +2530,53 @@ FHyperTwistTrainingRepositoryIntegrityReport UHyperTwistTrainingRepositoryLibrar
|
|||
SeenStoredTemplateKeys.Add(TemplateKey);
|
||||
}
|
||||
|
||||
Report.TotalMethodDrillFavoriteCount = RepositoryState.StoredMethodDrillFavorites.Num();
|
||||
TSet<FString> SeenMethodDrillFavoriteKeys;
|
||||
for (const FHyperTwistTrainingMethodDrillFavoriteEntry& FavoriteEntry : RepositoryState.StoredMethodDrillFavorites)
|
||||
{
|
||||
if (!FavoriteEntry.IsStructurallyValid())
|
||||
{
|
||||
Report.InvalidMethodDrillFavoriteCount += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
const FString FavoriteKey = HyperTwistTrainingRepositoryLibraryInternal::MakeMethodDrillFavoriteKey(
|
||||
FavoriteEntry.UserId,
|
||||
FavoriteEntry.DrillId,
|
||||
FavoriteEntry.CaseId
|
||||
);
|
||||
if (SeenMethodDrillFavoriteKeys.Contains(FavoriteKey))
|
||||
{
|
||||
Report.DuplicateMethodDrillFavoriteCount += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
SeenMethodDrillFavoriteKeys.Add(FavoriteKey);
|
||||
}
|
||||
|
||||
Report.TotalMethodDrillBatchCount = RepositoryState.StoredMethodDrillBatches.Num();
|
||||
TSet<FString> SeenMethodDrillBatchKeys;
|
||||
for (const FHyperTwistTrainingMethodDrillBatch& DrillBatch : RepositoryState.StoredMethodDrillBatches)
|
||||
{
|
||||
if (!DrillBatch.IsStructurallyValid())
|
||||
{
|
||||
Report.InvalidMethodDrillBatchCount += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
const FString BatchKey = HyperTwistTrainingRepositoryLibraryInternal::MakeMethodDrillBatchKey(
|
||||
DrillBatch.UserId,
|
||||
DrillBatch.BatchId
|
||||
);
|
||||
if (SeenMethodDrillBatchKeys.Contains(BatchKey))
|
||||
{
|
||||
Report.DuplicateMethodDrillBatchCount += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
SeenMethodDrillBatchKeys.Add(BatchKey);
|
||||
}
|
||||
|
||||
if (Report.InvalidRunRecordCount > 0)
|
||||
{
|
||||
HyperTwistTrainingRepositoryLibraryInternal::AppendRepairAction(
|
||||
|
|
@ -2235,6 +2636,34 @@ FHyperTwistTrainingRepositoryIntegrityReport UHyperTwistTrainingRepositoryLibrar
|
|||
TEXT("normalize-and-deduplicate-stored-session-templates")
|
||||
);
|
||||
}
|
||||
if (Report.InvalidMethodDrillFavoriteCount > 0)
|
||||
{
|
||||
HyperTwistTrainingRepositoryLibraryInternal::AppendRepairAction(
|
||||
Report.RepairActions,
|
||||
TEXT("drop-invalid-method-drill-favorites")
|
||||
);
|
||||
}
|
||||
if (Report.DuplicateMethodDrillFavoriteCount > 0)
|
||||
{
|
||||
HyperTwistTrainingRepositoryLibraryInternal::AppendRepairAction(
|
||||
Report.RepairActions,
|
||||
TEXT("normalize-and-deduplicate-method-drill-favorites")
|
||||
);
|
||||
}
|
||||
if (Report.InvalidMethodDrillBatchCount > 0)
|
||||
{
|
||||
HyperTwistTrainingRepositoryLibraryInternal::AppendRepairAction(
|
||||
Report.RepairActions,
|
||||
TEXT("drop-invalid-method-drill-batches")
|
||||
);
|
||||
}
|
||||
if (Report.DuplicateMethodDrillBatchCount > 0)
|
||||
{
|
||||
HyperTwistTrainingRepositoryLibraryInternal::AppendRepairAction(
|
||||
Report.RepairActions,
|
||||
TEXT("normalize-and-deduplicate-method-drill-batches")
|
||||
);
|
||||
}
|
||||
|
||||
return Report;
|
||||
}
|
||||
|
|
@ -2375,6 +2804,120 @@ FHyperTwistTrainingRepositoryState UHyperTwistTrainingRepositoryLibrary::RepairR
|
|||
return Left.TemplateId < Right.TemplateId;
|
||||
});
|
||||
|
||||
TMap<FString, int32> MethodDrillFavoriteIndexByKey;
|
||||
for (const FHyperTwistTrainingMethodDrillFavoriteEntry& FavoriteEntry : RepositoryState.StoredMethodDrillFavorites)
|
||||
{
|
||||
if (!FavoriteEntry.IsStructurallyValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingMethodDrillFavoriteEntry NormalizedFavorite =
|
||||
HyperTwistTrainingRepositoryLibraryInternal::NormalizeMethodDrillFavoriteEntry(FavoriteEntry);
|
||||
if (!NormalizedFavorite.IsStructurallyValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const FString FavoriteKey = HyperTwistTrainingRepositoryLibraryInternal::MakeMethodDrillFavoriteKey(
|
||||
NormalizedFavorite.UserId,
|
||||
NormalizedFavorite.DrillId,
|
||||
NormalizedFavorite.CaseId
|
||||
);
|
||||
if (const int32* ExistingIndex = MethodDrillFavoriteIndexByKey.Find(FavoriteKey))
|
||||
{
|
||||
RepairedState.StoredMethodDrillFavorites[*ExistingIndex] = NormalizedFavorite;
|
||||
}
|
||||
else
|
||||
{
|
||||
MethodDrillFavoriteIndexByKey.Add(
|
||||
FavoriteKey,
|
||||
RepairedState.StoredMethodDrillFavorites.Add(NormalizedFavorite)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
RepairedState.StoredMethodDrillFavorites.Sort([](
|
||||
const FHyperTwistTrainingMethodDrillFavoriteEntry& Left,
|
||||
const FHyperTwistTrainingMethodDrillFavoriteEntry& Right
|
||||
)
|
||||
{
|
||||
if (Left.UserId != Right.UserId)
|
||||
{
|
||||
return Left.UserId < Right.UserId;
|
||||
}
|
||||
|
||||
const int32 UtcCompare = HyperTwistTrainingRepositoryLibraryInternal::CompareUtcStrings(
|
||||
Left.AddedAtUtc,
|
||||
Right.AddedAtUtc
|
||||
);
|
||||
if (UtcCompare != 0)
|
||||
{
|
||||
return UtcCompare > 0;
|
||||
}
|
||||
|
||||
if (Left.DrillId != Right.DrillId)
|
||||
{
|
||||
return Left.DrillId < Right.DrillId;
|
||||
}
|
||||
|
||||
return Left.CaseId < Right.CaseId;
|
||||
});
|
||||
|
||||
TMap<FString, int32> MethodDrillBatchIndexByKey;
|
||||
for (const FHyperTwistTrainingMethodDrillBatch& DrillBatch : RepositoryState.StoredMethodDrillBatches)
|
||||
{
|
||||
if (!DrillBatch.IsStructurallyValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const FHyperTwistTrainingMethodDrillBatch NormalizedBatch =
|
||||
HyperTwistTrainingRepositoryLibraryInternal::NormalizeMethodDrillBatch(DrillBatch);
|
||||
if (!NormalizedBatch.IsStructurallyValid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const FString BatchKey = HyperTwistTrainingRepositoryLibraryInternal::MakeMethodDrillBatchKey(
|
||||
NormalizedBatch.UserId,
|
||||
NormalizedBatch.BatchId
|
||||
);
|
||||
if (const int32* ExistingIndex = MethodDrillBatchIndexByKey.Find(BatchKey))
|
||||
{
|
||||
RepairedState.StoredMethodDrillBatches[*ExistingIndex] = NormalizedBatch;
|
||||
}
|
||||
else
|
||||
{
|
||||
MethodDrillBatchIndexByKey.Add(
|
||||
BatchKey,
|
||||
RepairedState.StoredMethodDrillBatches.Add(NormalizedBatch)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
RepairedState.StoredMethodDrillBatches.Sort([](
|
||||
const FHyperTwistTrainingMethodDrillBatch& Left,
|
||||
const FHyperTwistTrainingMethodDrillBatch& Right
|
||||
)
|
||||
{
|
||||
if (Left.UserId != Right.UserId)
|
||||
{
|
||||
return Left.UserId < Right.UserId;
|
||||
}
|
||||
|
||||
const int32 UtcCompare = HyperTwistTrainingRepositoryLibraryInternal::CompareUtcStrings(
|
||||
Left.LastUpdatedAtUtc,
|
||||
Right.LastUpdatedAtUtc
|
||||
);
|
||||
if (UtcCompare != 0)
|
||||
{
|
||||
return UtcCompare > 0;
|
||||
}
|
||||
|
||||
return Left.BatchId < Right.BatchId;
|
||||
});
|
||||
|
||||
return RepairedState;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,16 @@ bool UHyperTwistTrainingRuntimeLibrary::HasActiveTrainingRun(UObject* WorldConte
|
|||
return false;
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingRuntimeLibrary::HasActiveMethodDrillRun(UObject* WorldContextObject)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->HasActiveMethodDrillRun();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunState UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingRunState(UObject* WorldContextObject)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
|
|
@ -48,6 +58,18 @@ FHyperTwistTrainingRunState UHyperTwistTrainingRuntimeLibrary::GetActiveTraining
|
|||
return FHyperTwistTrainingRunState();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingRuntimeLibrary::GetActiveMethodDrillRunState(
|
||||
UObject* WorldContextObject
|
||||
)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->GetActiveMethodDrillRunState();
|
||||
}
|
||||
|
||||
return FHyperTwistTrainingMethodDrillRunState();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingSessionSummary UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingRunSummary(UObject* WorldContextObject)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
|
|
@ -58,6 +80,18 @@ FHyperTwistTrainingSessionSummary UHyperTwistTrainingRuntimeLibrary::GetActiveTr
|
|||
return FHyperTwistTrainingSessionSummary();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillSummary UHyperTwistTrainingRuntimeLibrary::GetActiveMethodDrillSummary(
|
||||
UObject* WorldContextObject
|
||||
)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->GetActiveMethodDrillSummary();
|
||||
}
|
||||
|
||||
return FHyperTwistTrainingMethodDrillSummary();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRepositoryState UHyperTwistTrainingRuntimeLibrary::GetTrainingRepositoryState(UObject* WorldContextObject)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
|
|
@ -204,6 +238,34 @@ TArray<FHyperTwistTrainingSessionTemplate> UHyperTwistTrainingRuntimeLibrary::Ge
|
|||
return TArray<FHyperTwistTrainingSessionTemplate>();
|
||||
}
|
||||
|
||||
TArray<FHyperTwistTrainingMethodDrillFavoriteEntry> UHyperTwistTrainingRuntimeLibrary::GetMethodDrillFavoritesForUser(
|
||||
UObject* WorldContextObject,
|
||||
const FString& UserId,
|
||||
const FString& MethodSegmentId
|
||||
)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->GetMethodDrillFavoritesForUser(UserId, MethodSegmentId);
|
||||
}
|
||||
|
||||
return TArray<FHyperTwistTrainingMethodDrillFavoriteEntry>();
|
||||
}
|
||||
|
||||
TArray<FHyperTwistTrainingMethodDrillBatch> UHyperTwistTrainingRuntimeLibrary::GetMethodDrillBatchesForUser(
|
||||
UObject* WorldContextObject,
|
||||
const FString& UserId,
|
||||
const FString& MethodSegmentId
|
||||
)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->GetMethodDrillBatchesForUser(UserId, MethodSegmentId);
|
||||
}
|
||||
|
||||
return TArray<FHyperTwistTrainingMethodDrillBatch>();
|
||||
}
|
||||
|
||||
TArray<FHyperTwistTrainingCaseRecommendation> UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingCaseRecommendations(UObject* WorldContextObject)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
|
|
@ -335,6 +397,77 @@ bool UHyperTwistTrainingRuntimeLibrary::SaveTrainingSessionTemplate(
|
|||
return false;
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingRuntimeLibrary::SaveMethodDrillFavorite(
|
||||
UObject* WorldContextObject,
|
||||
const FHyperTwistTrainingMethodDrillFavoriteEntry& FavoriteEntry
|
||||
)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->SaveMethodDrillFavorite(FavoriteEntry);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingRuntimeLibrary::RemoveMethodDrillFavorite(
|
||||
UObject* WorldContextObject,
|
||||
const FString& UserId,
|
||||
const FString& DrillId,
|
||||
const FString& CaseId
|
||||
)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->RemoveMethodDrillFavorite(UserId, DrillId, CaseId);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingRuntimeLibrary::TryGetStoredMethodDrillBatch(
|
||||
UObject* WorldContextObject,
|
||||
const FString& UserId,
|
||||
const FString& BatchId,
|
||||
FHyperTwistTrainingMethodDrillBatch& OutBatch
|
||||
)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->TryGetStoredMethodDrillBatch(UserId, BatchId, OutBatch);
|
||||
}
|
||||
|
||||
OutBatch = FHyperTwistTrainingMethodDrillBatch();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingRuntimeLibrary::SaveMethodDrillBatch(
|
||||
UObject* WorldContextObject,
|
||||
const FHyperTwistTrainingMethodDrillBatch& DrillBatch
|
||||
)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->SaveMethodDrillBatch(DrillBatch);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingRuntimeLibrary::RemoveMethodDrillBatch(
|
||||
UObject* WorldContextObject,
|
||||
const FString& UserId,
|
||||
const FString& BatchId
|
||||
)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->RemoveMethodDrillBatch(UserId, BatchId);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingRuntimeLibrary::RemoveTrainingSessionTemplate(
|
||||
UObject* WorldContextObject,
|
||||
const FString& UserId,
|
||||
|
|
@ -548,6 +681,122 @@ FHyperTwistTrainingRunStepResult UHyperTwistTrainingRuntimeLibrary::SubmitTraini
|
|||
return FHyperTwistTrainingRunStepResult();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingRuntimeLibrary::StartMethodDrillRun(
|
||||
UObject* WorldContextObject,
|
||||
const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
|
||||
const FString& UserId,
|
||||
const FString& RunId
|
||||
)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->StartMethodDrillRun(DrillDefinition, UserId, RunId);
|
||||
}
|
||||
|
||||
return FHyperTwistTrainingMethodDrillRunState();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingRuntimeLibrary::StartMethodDrillRunFromDeck(
|
||||
UObject* WorldContextObject,
|
||||
const FHyperTwistTrainingDeck& Deck,
|
||||
const FString& UserId,
|
||||
const FString& RunId,
|
||||
EHyperTwistTrainingDrillModeKind DrillMode,
|
||||
EHyperTwistTrainingDrillVisibilityPolicy VisibilityPolicy,
|
||||
bool bAnswerHiddenUntilReveal
|
||||
)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->StartMethodDrillRunFromDeck(
|
||||
Deck,
|
||||
UserId,
|
||||
RunId,
|
||||
DrillMode,
|
||||
VisibilityPolicy,
|
||||
bAnswerHiddenUntilReveal
|
||||
);
|
||||
}
|
||||
|
||||
return FHyperTwistTrainingMethodDrillRunState();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingRuntimeLibrary::ResumeMethodDrillRunFromBatch(
|
||||
UObject* WorldContextObject,
|
||||
const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
|
||||
const FHyperTwistTrainingMethodDrillBatch& DrillBatch,
|
||||
const FString& RunId
|
||||
)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->ResumeMethodDrillRunFromBatch(DrillDefinition, DrillBatch, RunId);
|
||||
}
|
||||
|
||||
return FHyperTwistTrainingMethodDrillRunState();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingRuntimeLibrary::StartNextActiveMethodDrillCase(
|
||||
UObject* WorldContextObject
|
||||
)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->StartNextActiveMethodDrillCase();
|
||||
}
|
||||
|
||||
return FHyperTwistTrainingMethodDrillRunState();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingRuntimeLibrary::RevealActiveMethodDrillCase(
|
||||
UObject* WorldContextObject
|
||||
)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->RevealActiveMethodDrillCase();
|
||||
}
|
||||
|
||||
return FHyperTwistTrainingMethodDrillRunState();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingRuntimeLibrary::RepeatActiveMethodDrillCase(
|
||||
UObject* WorldContextObject
|
||||
)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->RepeatActiveMethodDrillCase();
|
||||
}
|
||||
|
||||
return FHyperTwistTrainingMethodDrillRunState();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingRuntimeLibrary::AdvanceActiveMethodDrillCase(
|
||||
UObject* WorldContextObject
|
||||
)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->AdvanceActiveMethodDrillCase();
|
||||
}
|
||||
|
||||
return FHyperTwistTrainingMethodDrillRunState();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingRuntimeLibrary::FinishActiveMethodDrillRun(
|
||||
UObject* WorldContextObject,
|
||||
bool bAbortRun
|
||||
)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->FinishActiveMethodDrillRun(bAbortRun);
|
||||
}
|
||||
|
||||
return FHyperTwistTrainingMethodDrillRunState();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingSession UHyperTwistTrainingRuntimeLibrary::CompleteActiveTrainingRun(
|
||||
UObject* WorldContextObject,
|
||||
bool bAbortSession
|
||||
|
|
@ -568,3 +817,11 @@ void UHyperTwistTrainingRuntimeLibrary::ClearActiveTrainingRun(UObject* WorldCon
|
|||
TrainingSubsystem->ClearActiveRun();
|
||||
}
|
||||
}
|
||||
|
||||
void UHyperTwistTrainingRuntimeLibrary::ClearActiveMethodDrillRun(UObject* WorldContextObject)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
TrainingSubsystem->ClearActiveMethodDrillRun();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,16 +10,31 @@ bool UHyperTwistTrainingSubsystem::HasActiveRun() const
|
|||
return bHasActiveRun && ActiveRunState.IsStructurallyValid();
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingSubsystem::HasActiveMethodDrillRun() const
|
||||
{
|
||||
return bHasActiveMethodDrillRun && ActiveMethodDrillRunState.IsStructurallyValid();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::GetActiveRunState() const
|
||||
{
|
||||
return ActiveRunState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::GetActiveMethodDrillRunState() const
|
||||
{
|
||||
return ActiveMethodDrillRunState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingSessionSummary UHyperTwistTrainingSubsystem::GetActiveRunSummary() const
|
||||
{
|
||||
return ActiveRunSummary;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillSummary UHyperTwistTrainingSubsystem::GetActiveMethodDrillSummary() const
|
||||
{
|
||||
return ActiveMethodDrillSummary;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRepositoryState UHyperTwistTrainingSubsystem::GetTrainingRepositoryState() const
|
||||
{
|
||||
return TrainingRepositoryState;
|
||||
|
|
@ -93,6 +108,30 @@ TArray<FHyperTwistTrainingSessionTemplate> UHyperTwistTrainingSubsystem::GetTrai
|
|||
return BuildTrainingSessionTemplatesForUser(UserId, ReferenceUtc);
|
||||
}
|
||||
|
||||
TArray<FHyperTwistTrainingMethodDrillFavoriteEntry> UHyperTwistTrainingSubsystem::GetMethodDrillFavoritesForUser(
|
||||
const FString& UserId,
|
||||
const FString& MethodSegmentId
|
||||
) const
|
||||
{
|
||||
return UHyperTwistTrainingRepositoryLibrary::ListMethodDrillFavorites(
|
||||
TrainingRepositoryState,
|
||||
UserId,
|
||||
MethodSegmentId
|
||||
);
|
||||
}
|
||||
|
||||
TArray<FHyperTwistTrainingMethodDrillBatch> UHyperTwistTrainingSubsystem::GetMethodDrillBatchesForUser(
|
||||
const FString& UserId,
|
||||
const FString& MethodSegmentId
|
||||
) const
|
||||
{
|
||||
return UHyperTwistTrainingRepositoryLibrary::ListMethodDrillBatches(
|
||||
TrainingRepositoryState,
|
||||
UserId,
|
||||
MethodSegmentId
|
||||
);
|
||||
}
|
||||
|
||||
TArray<FHyperTwistTrainingCaseRecommendation> UHyperTwistTrainingSubsystem::GetActiveCaseRecommendations() const
|
||||
{
|
||||
return ActiveCaseRecommendations;
|
||||
|
|
@ -201,6 +240,94 @@ bool UHyperTwistTrainingSubsystem::SaveTrainingSessionTemplate(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingSubsystem::SaveMethodDrillFavorite(
|
||||
const FHyperTwistTrainingMethodDrillFavoriteEntry& FavoriteEntry
|
||||
)
|
||||
{
|
||||
if (!FavoriteEntry.IsStructurallyValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertMethodDrillFavorite(
|
||||
TrainingRepositoryState,
|
||||
FavoriteEntry
|
||||
);
|
||||
RefreshRepositoryViews();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingSubsystem::RemoveMethodDrillFavorite(
|
||||
const FString& UserId,
|
||||
const FString& DrillId,
|
||||
const FString& CaseId
|
||||
)
|
||||
{
|
||||
if (UserId.IsEmpty() || DrillId.IsEmpty() || CaseId.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RemoveMethodDrillFavorite(
|
||||
TrainingRepositoryState,
|
||||
UserId,
|
||||
DrillId,
|
||||
CaseId
|
||||
);
|
||||
RefreshRepositoryViews();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingSubsystem::TryGetStoredMethodDrillBatch(
|
||||
const FString& UserId,
|
||||
const FString& BatchId,
|
||||
FHyperTwistTrainingMethodDrillBatch& OutBatch
|
||||
) const
|
||||
{
|
||||
return UHyperTwistTrainingRepositoryLibrary::TryGetMethodDrillBatch(
|
||||
TrainingRepositoryState,
|
||||
UserId,
|
||||
BatchId,
|
||||
OutBatch
|
||||
);
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingSubsystem::SaveMethodDrillBatch(
|
||||
const FHyperTwistTrainingMethodDrillBatch& DrillBatch
|
||||
)
|
||||
{
|
||||
if (!DrillBatch.IsStructurallyValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::UpsertMethodDrillBatch(
|
||||
TrainingRepositoryState,
|
||||
DrillBatch
|
||||
);
|
||||
RefreshRepositoryViews();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingSubsystem::RemoveMethodDrillBatch(
|
||||
const FString& UserId,
|
||||
const FString& BatchId
|
||||
)
|
||||
{
|
||||
if (UserId.IsEmpty() || BatchId.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TrainingRepositoryState = UHyperTwistTrainingRepositoryLibrary::RemoveMethodDrillBatch(
|
||||
TrainingRepositoryState,
|
||||
UserId,
|
||||
BatchId
|
||||
);
|
||||
RefreshRepositoryViews();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UHyperTwistTrainingSubsystem::RemoveTrainingSessionTemplate(
|
||||
const FString& UserId,
|
||||
const FString& TemplateId
|
||||
|
|
@ -502,6 +629,118 @@ FHyperTwistTrainingRunState UHyperTwistTrainingSubsystem::StartSampleClassicTrai
|
|||
return StartTrainingRunFromDeck(DefaultDeck, UserId, SessionId, Mode);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::StartMethodDrillRun(
|
||||
const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
|
||||
const FString& UserId,
|
||||
const FString& RunId
|
||||
)
|
||||
{
|
||||
ActiveMethodDrillRunState = UHyperTwistTrainingLibrary::StartMethodDrillRun(DrillDefinition, UserId, RunId);
|
||||
bHasActiveMethodDrillRun = ActiveMethodDrillRunState.IsStructurallyValid();
|
||||
RefreshMethodDrillSummary();
|
||||
return ActiveMethodDrillRunState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::StartMethodDrillRunFromDeck(
|
||||
const FHyperTwistTrainingDeck& Deck,
|
||||
const FString& UserId,
|
||||
const FString& RunId,
|
||||
EHyperTwistTrainingDrillModeKind DrillMode,
|
||||
EHyperTwistTrainingDrillVisibilityPolicy VisibilityPolicy,
|
||||
bool bAnswerHiddenUntilReveal
|
||||
)
|
||||
{
|
||||
const FHyperTwistTrainingMethodDrillDefinition DrillDefinition =
|
||||
UHyperTwistTrainingLibrary::BuildMethodDrillDefinitionFromDeck(
|
||||
Deck,
|
||||
DrillMode,
|
||||
VisibilityPolicy,
|
||||
bAnswerHiddenUntilReveal,
|
||||
EHyperTwistTrainingDrillEntrySource::Catalog
|
||||
);
|
||||
return StartMethodDrillRun(DrillDefinition, UserId, RunId);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::ResumeMethodDrillRunFromBatch(
|
||||
const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
|
||||
const FHyperTwistTrainingMethodDrillBatch& DrillBatch,
|
||||
const FString& RunId
|
||||
)
|
||||
{
|
||||
ActiveMethodDrillRunState = UHyperTwistTrainingLibrary::ResumeMethodDrillRunFromBatch(
|
||||
DrillDefinition,
|
||||
DrillBatch,
|
||||
RunId
|
||||
);
|
||||
bHasActiveMethodDrillRun = ActiveMethodDrillRunState.IsStructurallyValid();
|
||||
RefreshMethodDrillSummary();
|
||||
return ActiveMethodDrillRunState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::StartNextActiveMethodDrillCase()
|
||||
{
|
||||
if (!HasActiveMethodDrillRun())
|
||||
{
|
||||
return FHyperTwistTrainingMethodDrillRunState();
|
||||
}
|
||||
|
||||
ActiveMethodDrillRunState = UHyperTwistTrainingLibrary::StartNextMethodDrillCase(ActiveMethodDrillRunState);
|
||||
bHasActiveMethodDrillRun = ActiveMethodDrillRunState.IsStructurallyValid();
|
||||
RefreshMethodDrillSummary();
|
||||
return ActiveMethodDrillRunState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::RevealActiveMethodDrillCase()
|
||||
{
|
||||
if (!HasActiveMethodDrillRun())
|
||||
{
|
||||
return FHyperTwistTrainingMethodDrillRunState();
|
||||
}
|
||||
|
||||
ActiveMethodDrillRunState = UHyperTwistTrainingLibrary::RevealMethodDrillCase(ActiveMethodDrillRunState);
|
||||
RefreshMethodDrillSummary();
|
||||
return ActiveMethodDrillRunState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::RepeatActiveMethodDrillCase()
|
||||
{
|
||||
if (!HasActiveMethodDrillRun())
|
||||
{
|
||||
return FHyperTwistTrainingMethodDrillRunState();
|
||||
}
|
||||
|
||||
ActiveMethodDrillRunState = UHyperTwistTrainingLibrary::RepeatMethodDrillCase(ActiveMethodDrillRunState);
|
||||
RefreshMethodDrillSummary();
|
||||
return ActiveMethodDrillRunState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::AdvanceActiveMethodDrillCase()
|
||||
{
|
||||
if (!HasActiveMethodDrillRun())
|
||||
{
|
||||
return FHyperTwistTrainingMethodDrillRunState();
|
||||
}
|
||||
|
||||
ActiveMethodDrillRunState = UHyperTwistTrainingLibrary::AdvanceMethodDrillCase(ActiveMethodDrillRunState);
|
||||
RefreshMethodDrillSummary();
|
||||
return ActiveMethodDrillRunState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState UHyperTwistTrainingSubsystem::FinishActiveMethodDrillRun(bool bAbortRun)
|
||||
{
|
||||
if (!HasActiveMethodDrillRun())
|
||||
{
|
||||
return FHyperTwistTrainingMethodDrillRunState();
|
||||
}
|
||||
|
||||
ActiveMethodDrillRunState = UHyperTwistTrainingLibrary::FinishMethodDrillRun(
|
||||
ActiveMethodDrillRunState,
|
||||
bAbortRun
|
||||
);
|
||||
RefreshMethodDrillSummary();
|
||||
return ActiveMethodDrillRunState;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunStepResult UHyperTwistTrainingSubsystem::SubmitTrainingAttempt(
|
||||
const FHyperTwistTrainingAttempt& Attempt,
|
||||
int32 TimeMs
|
||||
|
|
@ -595,6 +834,13 @@ void UHyperTwistTrainingSubsystem::ClearActiveRun()
|
|||
RefreshRepositoryViews();
|
||||
}
|
||||
|
||||
void UHyperTwistTrainingSubsystem::ClearActiveMethodDrillRun()
|
||||
{
|
||||
ActiveMethodDrillRunState = FHyperTwistTrainingMethodDrillRunState();
|
||||
ActiveMethodDrillSummary = FHyperTwistTrainingMethodDrillSummary();
|
||||
bHasActiveMethodDrillRun = false;
|
||||
}
|
||||
|
||||
void UHyperTwistTrainingSubsystem::RefreshSummary()
|
||||
{
|
||||
if (!ActiveRunState.Session.IsStructurallyValid())
|
||||
|
|
@ -609,6 +855,19 @@ void UHyperTwistTrainingSubsystem::RefreshSummary()
|
|||
);
|
||||
}
|
||||
|
||||
void UHyperTwistTrainingSubsystem::RefreshMethodDrillSummary()
|
||||
{
|
||||
if (!ActiveMethodDrillRunState.IsStructurallyValid())
|
||||
{
|
||||
ActiveMethodDrillSummary = FHyperTwistTrainingMethodDrillSummary();
|
||||
return;
|
||||
}
|
||||
|
||||
ActiveMethodDrillSummary = UHyperTwistTrainingLibrary::DeriveMethodDrillSummary(
|
||||
ActiveMethodDrillRunState
|
||||
);
|
||||
}
|
||||
|
||||
void UHyperTwistTrainingSubsystem::RefreshRepositoryViews()
|
||||
{
|
||||
ActiveRepositoryIntegrityReport = UHyperTwistTrainingRepositoryLibrary::DeriveRepositoryIntegrityReport(
|
||||
|
|
|
|||
|
|
@ -65,6 +65,21 @@ public:
|
|||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
|
||||
static FHyperTwistTrainingRunState MakeSampleTrainingRunState();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingMethodDrillDefinition MakeSampleMethodDrillDefinition();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingMethodDrillRunState MakeSampleMethodDrillRunState();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingMethodDrillSummary MakeSampleMethodDrillSummary();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingMethodDrillFavoriteEntry MakeSampleMethodDrillFavoriteEntry();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingMethodDrillBatch MakeSampleMethodDrillBatch();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
|
||||
static FHyperTwistTrainingRunStepResult MakeSampleTrainingRunStepResult();
|
||||
|
||||
|
|
@ -161,6 +176,26 @@ public:
|
|||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Serialization")
|
||||
static FString SerializeContentPackToJson(const FHyperTwistContentPack& ContentPack);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Serialization")
|
||||
static FString SerializeMethodDrillDefinitionToJson(
|
||||
const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Serialization")
|
||||
static FString SerializeMethodDrillRunStateToJson(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Serialization")
|
||||
static FString SerializeMethodDrillFavoriteEntryToJson(
|
||||
const FHyperTwistTrainingMethodDrillFavoriteEntry& FavoriteEntry
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Serialization")
|
||||
static FString SerializeMethodDrillBatchToJson(
|
||||
const FHyperTwistTrainingMethodDrillBatch& DrillBatch
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Serialization")
|
||||
static FString SerializeTrainingRepositoryStateToJson(const FHyperTwistTrainingRepositoryState& RepositoryState);
|
||||
|
||||
|
|
@ -176,6 +211,30 @@ public:
|
|||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Serialization")
|
||||
static bool DeserializeContentPackFromJson(const FString& Json, FHyperTwistContentPack& OutContentPack);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Serialization")
|
||||
static bool DeserializeMethodDrillDefinitionFromJson(
|
||||
const FString& Json,
|
||||
FHyperTwistTrainingMethodDrillDefinition& OutDrillDefinition
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Serialization")
|
||||
static bool DeserializeMethodDrillRunStateFromJson(
|
||||
const FString& Json,
|
||||
FHyperTwistTrainingMethodDrillRunState& OutRunState
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Serialization")
|
||||
static bool DeserializeMethodDrillFavoriteEntryFromJson(
|
||||
const FString& Json,
|
||||
FHyperTwistTrainingMethodDrillFavoriteEntry& OutFavoriteEntry
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Serialization")
|
||||
static bool DeserializeMethodDrillBatchFromJson(
|
||||
const FString& Json,
|
||||
FHyperTwistTrainingMethodDrillBatch& OutDrillBatch
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Serialization")
|
||||
static bool DeserializeTrainingRepositoryStateFromJson(const FString& Json, FHyperTwistTrainingRepositoryState& OutRepositoryState);
|
||||
|
||||
|
|
|
|||
|
|
@ -146,4 +146,66 @@ public:
|
|||
const FHyperTwistTrainingAttempt& Attempt,
|
||||
int32 TimeMs
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingMethodDrillDefinition BuildMethodDrillDefinitionFromDeck(
|
||||
const FHyperTwistTrainingDeck& Deck,
|
||||
EHyperTwistTrainingDrillModeKind DrillMode,
|
||||
EHyperTwistTrainingDrillVisibilityPolicy VisibilityPolicy,
|
||||
bool bAnswerHiddenUntilReveal,
|
||||
EHyperTwistTrainingDrillEntrySource EntrySource
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingMethodDrillRunState StartMethodDrillRun(
|
||||
const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
|
||||
const FString& UserId,
|
||||
const FString& RunId
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingMethodDrillRunState ResumeMethodDrillRunFromBatch(
|
||||
const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
|
||||
const FHyperTwistTrainingMethodDrillBatch& DrillBatch,
|
||||
const FString& RunId
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingMethodDrillRunState StartNextMethodDrillCase(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingMethodDrillRunState RevealMethodDrillCase(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingMethodDrillRunState RepeatMethodDrillCase(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingMethodDrillRunState AdvanceMethodDrillCase(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingMethodDrillRunState FinishMethodDrillRun(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState,
|
||||
bool bAbortRun
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingMethodDrillSummary DeriveMethodDrillSummary(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingMethodDrillBatch BuildMethodDrillBatch(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState,
|
||||
const FString& BatchId,
|
||||
const FString& Title,
|
||||
bool bPinnedFavoritesOnly
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -40,6 +40,63 @@ public:
|
|||
const FHyperTwistTrainingRunState& RunState
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Repository|Drill")
|
||||
static FHyperTwistTrainingMethodDrillFavoriteEntry MakeMethodDrillFavoriteEntry(
|
||||
const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
|
||||
const FString& UserId,
|
||||
const FString& CaseId,
|
||||
const FString& AddedAtUtc
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Repository|Drill")
|
||||
static TArray<FHyperTwistTrainingMethodDrillFavoriteEntry> ListMethodDrillFavorites(
|
||||
const FHyperTwistTrainingRepositoryState& RepositoryState,
|
||||
const FString& UserId,
|
||||
const FString& MethodSegmentId
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Repository|Drill")
|
||||
static FHyperTwistTrainingRepositoryState UpsertMethodDrillFavorite(
|
||||
const FHyperTwistTrainingRepositoryState& RepositoryState,
|
||||
const FHyperTwistTrainingMethodDrillFavoriteEntry& FavoriteEntry
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Repository|Drill")
|
||||
static FHyperTwistTrainingRepositoryState RemoveMethodDrillFavorite(
|
||||
const FHyperTwistTrainingRepositoryState& RepositoryState,
|
||||
const FString& UserId,
|
||||
const FString& DrillId,
|
||||
const FString& CaseId
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Repository|Drill")
|
||||
static TArray<FHyperTwistTrainingMethodDrillBatch> ListMethodDrillBatches(
|
||||
const FHyperTwistTrainingRepositoryState& RepositoryState,
|
||||
const FString& UserId,
|
||||
const FString& MethodSegmentId
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Repository|Drill")
|
||||
static bool TryGetMethodDrillBatch(
|
||||
const FHyperTwistTrainingRepositoryState& RepositoryState,
|
||||
const FString& UserId,
|
||||
const FString& BatchId,
|
||||
FHyperTwistTrainingMethodDrillBatch& OutBatch
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Repository|Drill")
|
||||
static FHyperTwistTrainingRepositoryState UpsertMethodDrillBatch(
|
||||
const FHyperTwistTrainingRepositoryState& RepositoryState,
|
||||
const FHyperTwistTrainingMethodDrillBatch& DrillBatch
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Repository|Drill")
|
||||
static FHyperTwistTrainingRepositoryState RemoveMethodDrillBatch(
|
||||
const FHyperTwistTrainingRepositoryState& RepositoryState,
|
||||
const FString& UserId,
|
||||
const FString& BatchId
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Repository")
|
||||
static FHyperTwistTrainingRepositoryState UpsertRunRecord(
|
||||
const FHyperTwistTrainingRepositoryState& RepositoryState,
|
||||
|
|
|
|||
|
|
@ -19,12 +19,21 @@ public:
|
|||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training", meta = (WorldContext = "WorldContextObject"))
|
||||
static bool HasActiveTrainingRun(UObject* WorldContextObject);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static bool HasActiveMethodDrillRun(UObject* WorldContextObject);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingRunState GetActiveTrainingRunState(UObject* WorldContextObject);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingMethodDrillRunState GetActiveMethodDrillRunState(UObject* WorldContextObject);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingSessionSummary GetActiveTrainingRunSummary(UObject* WorldContextObject);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingMethodDrillSummary GetActiveMethodDrillSummary(UObject* WorldContextObject);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingRepositoryState GetTrainingRepositoryState(UObject* WorldContextObject);
|
||||
|
||||
|
|
@ -73,6 +82,20 @@ public:
|
|||
const FString& ReferenceUtc
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static TArray<FHyperTwistTrainingMethodDrillFavoriteEntry> GetMethodDrillFavoritesForUser(
|
||||
UObject* WorldContextObject,
|
||||
const FString& UserId,
|
||||
const FString& MethodSegmentId
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static TArray<FHyperTwistTrainingMethodDrillBatch> GetMethodDrillBatchesForUser(
|
||||
UObject* WorldContextObject,
|
||||
const FString& UserId,
|
||||
const FString& MethodSegmentId
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training", meta = (WorldContext = "WorldContextObject"))
|
||||
static TArray<FHyperTwistTrainingCaseRecommendation> GetActiveTrainingCaseRecommendations(UObject* WorldContextObject);
|
||||
|
||||
|
|
@ -130,6 +153,41 @@ public:
|
|||
const FHyperTwistTrainingSessionTemplate& SessionTemplate
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static bool SaveMethodDrillFavorite(
|
||||
UObject* WorldContextObject,
|
||||
const FHyperTwistTrainingMethodDrillFavoriteEntry& FavoriteEntry
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static bool RemoveMethodDrillFavorite(
|
||||
UObject* WorldContextObject,
|
||||
const FString& UserId,
|
||||
const FString& DrillId,
|
||||
const FString& CaseId
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static bool TryGetStoredMethodDrillBatch(
|
||||
UObject* WorldContextObject,
|
||||
const FString& UserId,
|
||||
const FString& BatchId,
|
||||
FHyperTwistTrainingMethodDrillBatch& OutBatch
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static bool SaveMethodDrillBatch(
|
||||
UObject* WorldContextObject,
|
||||
const FHyperTwistTrainingMethodDrillBatch& DrillBatch
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static bool RemoveMethodDrillBatch(
|
||||
UObject* WorldContextObject,
|
||||
const FString& UserId,
|
||||
const FString& BatchId
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training", meta = (WorldContext = "WorldContextObject"))
|
||||
static bool RemoveTrainingSessionTemplate(
|
||||
UObject* WorldContextObject,
|
||||
|
|
@ -234,6 +292,54 @@ public:
|
|||
int32 TimeMs
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingMethodDrillRunState StartMethodDrillRun(
|
||||
UObject* WorldContextObject,
|
||||
const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
|
||||
const FString& UserId,
|
||||
const FString& RunId
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingMethodDrillRunState StartMethodDrillRunFromDeck(
|
||||
UObject* WorldContextObject,
|
||||
const FHyperTwistTrainingDeck& Deck,
|
||||
const FString& UserId,
|
||||
const FString& RunId,
|
||||
EHyperTwistTrainingDrillModeKind DrillMode,
|
||||
EHyperTwistTrainingDrillVisibilityPolicy VisibilityPolicy,
|
||||
bool bAnswerHiddenUntilReveal
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingMethodDrillRunState ResumeMethodDrillRunFromBatch(
|
||||
UObject* WorldContextObject,
|
||||
const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
|
||||
const FHyperTwistTrainingMethodDrillBatch& DrillBatch,
|
||||
const FString& RunId
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingMethodDrillRunState StartNextActiveMethodDrillCase(UObject* WorldContextObject);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingMethodDrillRunState RevealActiveMethodDrillCase(UObject* WorldContextObject);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingMethodDrillRunState RepeatActiveMethodDrillCase(UObject* WorldContextObject);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingMethodDrillRunState AdvanceActiveMethodDrillCase(UObject* WorldContextObject);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingMethodDrillRunState FinishActiveMethodDrillRun(
|
||||
UObject* WorldContextObject,
|
||||
bool bAbortRun
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static void ClearActiveMethodDrillRun(UObject* WorldContextObject);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingSession CompleteActiveTrainingRun(
|
||||
UObject* WorldContextObject,
|
||||
|
|
|
|||
|
|
@ -14,12 +14,21 @@ public:
|
|||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
|
||||
bool HasActiveRun() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
bool HasActiveMethodDrillRun() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
|
||||
FHyperTwistTrainingRunState GetActiveRunState() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
FHyperTwistTrainingMethodDrillRunState GetActiveMethodDrillRunState() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
|
||||
FHyperTwistTrainingSessionSummary GetActiveRunSummary() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
FHyperTwistTrainingMethodDrillSummary GetActiveMethodDrillSummary() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
|
||||
FHyperTwistTrainingRepositoryState GetTrainingRepositoryState() const;
|
||||
|
||||
|
|
@ -65,6 +74,18 @@ public:
|
|||
const FString& ReferenceUtc
|
||||
) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
TArray<FHyperTwistTrainingMethodDrillFavoriteEntry> GetMethodDrillFavoritesForUser(
|
||||
const FString& UserId,
|
||||
const FString& MethodSegmentId
|
||||
) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
TArray<FHyperTwistTrainingMethodDrillBatch> GetMethodDrillBatchesForUser(
|
||||
const FString& UserId,
|
||||
const FString& MethodSegmentId
|
||||
) const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
|
||||
TArray<FHyperTwistTrainingCaseRecommendation> GetActiveCaseRecommendations() const;
|
||||
|
||||
|
|
@ -114,6 +135,32 @@ public:
|
|||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training")
|
||||
bool SaveTrainingSessionTemplate(const FHyperTwistTrainingSessionTemplate& SessionTemplate);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill")
|
||||
bool SaveMethodDrillFavorite(const FHyperTwistTrainingMethodDrillFavoriteEntry& FavoriteEntry);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill")
|
||||
bool RemoveMethodDrillFavorite(
|
||||
const FString& UserId,
|
||||
const FString& DrillId,
|
||||
const FString& CaseId
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill")
|
||||
bool TryGetStoredMethodDrillBatch(
|
||||
const FString& UserId,
|
||||
const FString& BatchId,
|
||||
FHyperTwistTrainingMethodDrillBatch& OutBatch
|
||||
) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill")
|
||||
bool SaveMethodDrillBatch(const FHyperTwistTrainingMethodDrillBatch& DrillBatch);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill")
|
||||
bool RemoveMethodDrillBatch(
|
||||
const FString& UserId,
|
||||
const FString& BatchId
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training")
|
||||
bool RemoveTrainingSessionTemplate(
|
||||
const FString& UserId,
|
||||
|
|
@ -190,6 +237,48 @@ public:
|
|||
EHyperTwistTrainingDeliveryMode Mode
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill")
|
||||
FHyperTwistTrainingMethodDrillRunState StartMethodDrillRun(
|
||||
const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
|
||||
const FString& UserId,
|
||||
const FString& RunId
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill")
|
||||
FHyperTwistTrainingMethodDrillRunState StartMethodDrillRunFromDeck(
|
||||
const FHyperTwistTrainingDeck& Deck,
|
||||
const FString& UserId,
|
||||
const FString& RunId,
|
||||
EHyperTwistTrainingDrillModeKind DrillMode,
|
||||
EHyperTwistTrainingDrillVisibilityPolicy VisibilityPolicy,
|
||||
bool bAnswerHiddenUntilReveal
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill")
|
||||
FHyperTwistTrainingMethodDrillRunState ResumeMethodDrillRunFromBatch(
|
||||
const FHyperTwistTrainingMethodDrillDefinition& DrillDefinition,
|
||||
const FHyperTwistTrainingMethodDrillBatch& DrillBatch,
|
||||
const FString& RunId
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill")
|
||||
FHyperTwistTrainingMethodDrillRunState StartNextActiveMethodDrillCase();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill")
|
||||
FHyperTwistTrainingMethodDrillRunState RevealActiveMethodDrillCase();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill")
|
||||
FHyperTwistTrainingMethodDrillRunState RepeatActiveMethodDrillCase();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill")
|
||||
FHyperTwistTrainingMethodDrillRunState AdvanceActiveMethodDrillCase();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill")
|
||||
FHyperTwistTrainingMethodDrillRunState FinishActiveMethodDrillRun(bool bAbortRun);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training|Drill")
|
||||
void ClearActiveMethodDrillRun();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "HyperTwist|Training")
|
||||
FHyperTwistTrainingRunStepResult SubmitTrainingAttempt(
|
||||
const FHyperTwistTrainingAttempt& Attempt,
|
||||
|
|
@ -204,6 +293,7 @@ public:
|
|||
|
||||
private:
|
||||
void RefreshSummary();
|
||||
void RefreshMethodDrillSummary();
|
||||
void RefreshRepositoryViews();
|
||||
TArray<FHyperTwistTrainingSessionTemplate> BuildTrainingSessionTemplatesForUser(
|
||||
const FString& UserId,
|
||||
|
|
@ -216,6 +306,12 @@ private:
|
|||
UPROPERTY()
|
||||
FHyperTwistTrainingSessionSummary ActiveRunSummary;
|
||||
|
||||
UPROPERTY()
|
||||
FHyperTwistTrainingMethodDrillRunState ActiveMethodDrillRunState;
|
||||
|
||||
UPROPERTY()
|
||||
FHyperTwistTrainingMethodDrillSummary ActiveMethodDrillSummary;
|
||||
|
||||
UPROPERTY()
|
||||
FHyperTwistTrainingRepositoryState TrainingRepositoryState;
|
||||
|
||||
|
|
@ -269,4 +365,7 @@ private:
|
|||
|
||||
UPROPERTY()
|
||||
bool bHasActiveRun = false;
|
||||
|
||||
UPROPERTY()
|
||||
bool bHasActiveMethodDrillRun = false;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -102,6 +102,43 @@ enum class EHyperTwistTrainingSourceMode : uint8
|
|||
Benchmark UMETA(DisplayName = "Benchmark")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EHyperTwistTrainingDrillModeKind : uint8
|
||||
{
|
||||
Recognition UMETA(DisplayName = "Recognition"),
|
||||
Recall UMETA(DisplayName = "Recall"),
|
||||
Execution UMETA(DisplayName = "Execution"),
|
||||
Reconstruction UMETA(DisplayName = "Reconstruction")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EHyperTwistTrainingDrillVisibilityPolicy : uint8
|
||||
{
|
||||
FullInformation UMETA(DisplayName = "Full Information"),
|
||||
PromptOnly UMETA(DisplayName = "Prompt Only"),
|
||||
MaskedState UMETA(DisplayName = "Masked State"),
|
||||
PartialState UMETA(DisplayName = "Partial State")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EHyperTwistTrainingDrillLifecycleState : uint8
|
||||
{
|
||||
Ready UMETA(DisplayName = "Ready"),
|
||||
Active UMETA(DisplayName = "Active"),
|
||||
Revealed UMETA(DisplayName = "Revealed"),
|
||||
Completed UMETA(DisplayName = "Completed"),
|
||||
Aborted UMETA(DisplayName = "Aborted")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EHyperTwistTrainingDrillEntrySource : uint8
|
||||
{
|
||||
Catalog UMETA(DisplayName = "Catalog"),
|
||||
Favorites UMETA(DisplayName = "Favorites"),
|
||||
QueuedBatch UMETA(DisplayName = "Queued Batch"),
|
||||
Generated UMETA(DisplayName = "Generated")
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingSourceAttribution
|
||||
{
|
||||
|
|
@ -1825,6 +1862,345 @@ struct FHyperTwistTrainingMethodSegment
|
|||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingMethodDrillDefinition
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DrillId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Title;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString StageId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString StageLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FHyperTwistTrainingMethodDescriptor MethodDescriptor;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SourceDeckId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FHyperTwistTrainingDeck SourceDeck;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> FocusCaseIds;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingDrillModeKind DrillMode = EHyperTwistTrainingDrillModeKind::Recognition;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingDrillVisibilityPolicy VisibilityPolicy =
|
||||
EHyperTwistTrainingDrillVisibilityPolicy::FullInformation;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingDrillEntrySource EntrySource = EHyperTwistTrainingDrillEntrySource::Catalog;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bAnswerHiddenUntilReveal = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bAllowImmediateRepeat = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> Tags;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FHyperTwistTrainingSourceAttribution SourceAttribution;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !DrillId.IsEmpty()
|
||||
&& !Title.IsEmpty()
|
||||
&& MethodDescriptor.IsStructurallyValid()
|
||||
&& SourceDeck.IsStructurallyValid();
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingMethodDrillResponseRecord
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ResponseId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DrillRunId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CaseId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString PresentedAtUtc;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString RespondedAtUtc;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingDrillModeKind DrillMode = EHyperTwistTrainingDrillModeKind::Recognition;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingDrillVisibilityPolicy VisibilityPolicy =
|
||||
EHyperTwistTrainingDrillVisibilityPolicy::FullInformation;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bAnswerWasRevealed = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bMarkedCorrect = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bWasRepeat = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ElapsedMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ResponseText;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Notes;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !ResponseId.IsEmpty() && !DrillRunId.IsEmpty() && !CaseId.IsEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingMethodDrillRunState
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FHyperTwistTrainingMethodDrillDefinition DrillDefinition;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString RunId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString UserId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SourceBatchId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingDrillLifecycleState LifecycleState = EHyperTwistTrainingDrillLifecycleState::Ready;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString StartedAtUtc;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString EndedAtUtc;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString LastUpdatedAtUtc;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FHyperTwistTrainingCase CurrentCase;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bAnswerVisible = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> PendingCaseIds;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> CompletedCaseIds;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FHyperTwistTrainingMethodDrillResponseRecord> Responses;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 RevealCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 RepeatCount = 0;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
const bool bNeedsCurrentCase =
|
||||
LifecycleState == EHyperTwistTrainingDrillLifecycleState::Active
|
||||
|| LifecycleState == EHyperTwistTrainingDrillLifecycleState::Revealed;
|
||||
const bool bHasValidCurrentCase = CurrentCase.CaseId.IsEmpty()
|
||||
? !bNeedsCurrentCase
|
||||
: CurrentCase.IsStructurallyValid();
|
||||
return DrillDefinition.IsStructurallyValid()
|
||||
&& !RunId.IsEmpty()
|
||||
&& !UserId.IsEmpty()
|
||||
&& bHasValidCurrentCase;
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingMethodDrillSummary
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString RunId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DrillId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString UserId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingDrillLifecycleState LifecycleState = EHyperTwistTrainingDrillLifecycleState::Ready;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 TotalCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 PendingCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 CompletedCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ResponseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 RevealCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 RepeatCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bAnswerHiddenUntilReveal = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CurrentCaseId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString LastUpdatedAtUtc;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !RunId.IsEmpty() && !DrillId.IsEmpty() && !UserId.IsEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingMethodDrillFavoriteEntry
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString UserId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DrillId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CaseId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SourceDeckId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FHyperTwistTrainingMethodDescriptor MethodDescriptor;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString AddedAtUtc;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> Tags;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Note;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !UserId.IsEmpty()
|
||||
&& !DrillId.IsEmpty()
|
||||
&& !CaseId.IsEmpty()
|
||||
&& !SourceDeckId.IsEmpty()
|
||||
&& MethodDescriptor.IsStructurallyValid();
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingMethodDrillBatch
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString UserId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString BatchId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString Title;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DrillId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SourceDeckId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FHyperTwistTrainingMethodDescriptor MethodDescriptor;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingDrillModeKind DrillMode = EHyperTwistTrainingDrillModeKind::Recognition;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingDrillVisibilityPolicy VisibilityPolicy =
|
||||
EHyperTwistTrainingDrillVisibilityPolicy::FullInformation;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bAnswerHiddenUntilReveal = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingDrillLifecycleState SavedLifecycleState = EHyperTwistTrainingDrillLifecycleState::Ready;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> PendingCaseIds;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> CompletedCaseIds;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CurrentCaseId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FHyperTwistTrainingMethodDrillResponseRecord> Responses;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 RevealCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 RepeatCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CreatedAtUtc;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString LastUpdatedAtUtc;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bPinnedFavoritesOnly = false;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !UserId.IsEmpty()
|
||||
&& !BatchId.IsEmpty()
|
||||
&& !DrillId.IsEmpty()
|
||||
&& !SourceDeckId.IsEmpty()
|
||||
&& MethodDescriptor.IsStructurallyValid()
|
||||
&& (!CurrentCaseId.IsEmpty() || PendingCaseIds.Num() > 0 || CompletedCaseIds.Num() > 0);
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingLearnerPreset
|
||||
{
|
||||
|
|
@ -2279,6 +2655,12 @@ struct FHyperTwistTrainingRepositoryState
|
|||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FHyperTwistTrainingSessionTemplate> StoredSessionTemplates;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FHyperTwistTrainingMethodDrillFavoriteEntry> StoredMethodDrillFavorites;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FHyperTwistTrainingMethodDrillBatch> StoredMethodDrillBatches;
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
|
|
@ -2322,6 +2704,24 @@ struct FHyperTwistTrainingRepositoryIntegrityReport
|
|||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 DuplicateStoredSessionTemplateCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 TotalMethodDrillFavoriteCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 InvalidMethodDrillFavoriteCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 DuplicateMethodDrillFavoriteCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 TotalMethodDrillBatchCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 InvalidMethodDrillBatchCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 DuplicateMethodDrillBatchCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> RepairActions;
|
||||
|
||||
|
|
@ -2334,6 +2734,10 @@ struct FHyperTwistTrainingRepositoryIntegrityReport
|
|||
|| InvalidReviewPlanCount > 0
|
||||
|| DuplicateReviewPlanCount > 0
|
||||
|| InvalidStoredSessionTemplateCount > 0
|
||||
|| DuplicateStoredSessionTemplateCount > 0;
|
||||
|| DuplicateStoredSessionTemplateCount > 0
|
||||
|| InvalidMethodDrillFavoriteCount > 0
|
||||
|| DuplicateMethodDrillFavoriteCount > 0
|
||||
|| InvalidMethodDrillBatchCount > 0
|
||||
|| DuplicateMethodDrillBatchCount > 0;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue