Close Roux Bound3 diagnostic packet
This commit is contained in:
parent
5afb58f31a
commit
45164a7790
11 changed files with 908 additions and 0 deletions
|
|
@ -538,6 +538,100 @@ FHyperTwistTrainingDrillCaseModeCompatibility UHyperTwistContractLibrary::MakeSa
|
|||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillDiagnosticPacket UHyperTwistContractLibrary::MakeSampleMethodDrillDiagnosticPacket()
|
||||
{
|
||||
const FHyperTwistTrainingMethodDrillDefinition DrillDefinition = MakeSampleMethodDrillDefinition();
|
||||
if (!DrillDefinition.IsStructurallyValid())
|
||||
{
|
||||
return FHyperTwistTrainingMethodDrillDiagnosticPacket();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillRunState RunState = UHyperTwistTrainingLibrary::StartMethodDrillRun(
|
||||
DrillDefinition,
|
||||
TEXT("local-user"),
|
||||
TEXT("method_drill_run_diagnostics_01")
|
||||
);
|
||||
if (!RunState.IsStructurallyValid())
|
||||
{
|
||||
return FHyperTwistTrainingMethodDrillDiagnosticPacket();
|
||||
}
|
||||
|
||||
RunState.StartedAtUtc = TEXT("2026-04-29T09:00:00Z");
|
||||
RunState.LastUpdatedAtUtc = RunState.StartedAtUtc;
|
||||
RunState = UHyperTwistTrainingLibrary::StartNextMethodDrillCase(RunState);
|
||||
if (!RunState.IsStructurallyValid())
|
||||
{
|
||||
return FHyperTwistTrainingMethodDrillDiagnosticPacket();
|
||||
}
|
||||
|
||||
RunState = UHyperTwistTrainingLibrary::RevealMethodDrillCase(RunState);
|
||||
|
||||
FHyperTwistTrainingMethodDrillResponseRecord AssistedResponse;
|
||||
AssistedResponse.ResponseId = TEXT("method_drill_diag_response_01");
|
||||
AssistedResponse.DrillRunId = RunState.RunId;
|
||||
AssistedResponse.CaseId = RunState.CurrentCase.CaseId;
|
||||
AssistedResponse.PresentedAtUtc = TEXT("2026-04-29T09:00:05Z");
|
||||
AssistedResponse.RespondedAtUtc = TEXT("2026-04-29T09:00:17Z");
|
||||
AssistedResponse.DrillMode = RunState.DrillDefinition.DrillMode;
|
||||
AssistedResponse.VisibilityPolicy = RunState.DrillDefinition.VisibilityPolicy;
|
||||
AssistedResponse.bAnswerWasRevealed = true;
|
||||
AssistedResponse.bMarkedCorrect = true;
|
||||
AssistedResponse.bWasRepeat = false;
|
||||
AssistedResponse.ElapsedMs = 1700;
|
||||
AssistedResponse.ResponseText = TEXT("recognized left block after reveal");
|
||||
RunState.Responses.Add(AssistedResponse);
|
||||
RunState.LastUpdatedAtUtc = AssistedResponse.RespondedAtUtc;
|
||||
RunState = UHyperTwistTrainingLibrary::AdvanceMethodDrillCase(RunState);
|
||||
RunState = UHyperTwistTrainingLibrary::StartNextMethodDrillCase(RunState);
|
||||
if (!RunState.IsStructurallyValid())
|
||||
{
|
||||
return FHyperTwistTrainingMethodDrillDiagnosticPacket();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillResponseRecord RepeatResponseA;
|
||||
RepeatResponseA.ResponseId = TEXT("method_drill_diag_response_02");
|
||||
RepeatResponseA.DrillRunId = RunState.RunId;
|
||||
RepeatResponseA.CaseId = RunState.CurrentCase.CaseId;
|
||||
RepeatResponseA.PresentedAtUtc = TEXT("2026-04-29T09:00:20Z");
|
||||
RepeatResponseA.RespondedAtUtc = TEXT("2026-04-29T09:00:31Z");
|
||||
RepeatResponseA.DrillMode = RunState.DrillDefinition.DrillMode;
|
||||
RepeatResponseA.VisibilityPolicy = RunState.DrillDefinition.VisibilityPolicy;
|
||||
RepeatResponseA.bAnswerWasRevealed = false;
|
||||
RepeatResponseA.bMarkedCorrect = false;
|
||||
RepeatResponseA.bWasRepeat = false;
|
||||
RepeatResponseA.ElapsedMs = 2400;
|
||||
RepeatResponseA.ResponseText = TEXT("missed block anchor on first pass");
|
||||
RunState.Responses.Add(RepeatResponseA);
|
||||
RunState.LastUpdatedAtUtc = RepeatResponseA.RespondedAtUtc;
|
||||
RunState = UHyperTwistTrainingLibrary::RepeatMethodDrillCase(RunState);
|
||||
|
||||
FHyperTwistTrainingMethodDrillResponseRecord RepeatResponseB;
|
||||
RepeatResponseB.ResponseId = TEXT("method_drill_diag_response_03");
|
||||
RepeatResponseB.DrillRunId = RunState.RunId;
|
||||
RepeatResponseB.CaseId = RunState.CurrentCase.CaseId;
|
||||
RepeatResponseB.PresentedAtUtc = TEXT("2026-04-29T09:00:35Z");
|
||||
RepeatResponseB.RespondedAtUtc = TEXT("2026-04-29T09:00:42Z");
|
||||
RepeatResponseB.DrillMode = RunState.DrillDefinition.DrillMode;
|
||||
RepeatResponseB.VisibilityPolicy = RunState.DrillDefinition.VisibilityPolicy;
|
||||
RepeatResponseB.bAnswerWasRevealed = false;
|
||||
RepeatResponseB.bMarkedCorrect = true;
|
||||
RepeatResponseB.bWasRepeat = true;
|
||||
RepeatResponseB.ElapsedMs = 1900;
|
||||
RepeatResponseB.ResponseText = TEXT("corrected block anchor after repeat");
|
||||
RunState.Responses.Add(RepeatResponseB);
|
||||
RunState.LastUpdatedAtUtc = RepeatResponseB.RespondedAtUtc;
|
||||
|
||||
return UHyperTwistTrainingLibrary::DeriveMethodDrillDiagnosticPacket(RunState);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingSessionTemplate UHyperTwistContractLibrary::MakeSampleMethodDrillFollowUpTemplate()
|
||||
{
|
||||
return UHyperTwistTrainingRepositoryLibrary::BuildMethodDrillFollowUpTemplate(
|
||||
MakeSampleMethodDrillDiagnosticPacket(),
|
||||
TEXT("method_drill_follow_up_template_01")
|
||||
);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRunStepResult UHyperTwistContractLibrary::MakeSampleTrainingRunStepResult()
|
||||
{
|
||||
const FHyperTwistTrainingRunState RunState = MakeSampleTrainingRunState();
|
||||
|
|
|
|||
|
|
@ -637,6 +637,297 @@ namespace HyperTwistTrainingLibraryInternal
|
|||
Summary.LastUpdatedAtUtc = RunState.LastUpdatedAtUtc;
|
||||
return Summary;
|
||||
}
|
||||
|
||||
struct FMethodDrillCaseMetrics
|
||||
{
|
||||
int32 AttemptCount = 0;
|
||||
int32 CorrectResponseCount = 0;
|
||||
int32 IncorrectResponseCount = 0;
|
||||
int32 RevealCount = 0;
|
||||
int32 RepeatCount = 0;
|
||||
int64 ElapsedAccumulator = 0;
|
||||
int32 ElapsedSampleCount = 0;
|
||||
int32 BestElapsedMs = 0;
|
||||
int32 WorstElapsedMs = 0;
|
||||
};
|
||||
|
||||
TArray<FString> BuildKnownDrillCaseIds(const FHyperTwistTrainingMethodDrillRunState& RunState)
|
||||
{
|
||||
TArray<FString> KnownCaseIds = BuildDrillCaseIds(RunState.DrillDefinition);
|
||||
for (const FString& CaseId : RunState.PendingCaseIds)
|
||||
{
|
||||
if (!CaseId.IsEmpty())
|
||||
{
|
||||
KnownCaseIds.AddUnique(CaseId);
|
||||
}
|
||||
}
|
||||
for (const FString& CaseId : RunState.CompletedCaseIds)
|
||||
{
|
||||
if (!CaseId.IsEmpty())
|
||||
{
|
||||
KnownCaseIds.AddUnique(CaseId);
|
||||
}
|
||||
}
|
||||
if (!RunState.CurrentCase.CaseId.IsEmpty())
|
||||
{
|
||||
KnownCaseIds.AddUnique(RunState.CurrentCase.CaseId);
|
||||
}
|
||||
for (const FHyperTwistTrainingMethodDrillResponseRecord& Response : RunState.Responses)
|
||||
{
|
||||
if (!Response.CaseId.IsEmpty())
|
||||
{
|
||||
KnownCaseIds.AddUnique(Response.CaseId);
|
||||
}
|
||||
}
|
||||
|
||||
return KnownCaseIds;
|
||||
}
|
||||
|
||||
FMethodDrillCaseMetrics CollectMethodDrillCaseMetrics(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState,
|
||||
const FString& CaseId
|
||||
)
|
||||
{
|
||||
FMethodDrillCaseMetrics Metrics;
|
||||
for (const FHyperTwistTrainingMethodDrillResponseRecord& Response : RunState.Responses)
|
||||
{
|
||||
if (Response.CaseId != CaseId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Metrics.AttemptCount += 1;
|
||||
Metrics.CorrectResponseCount += Response.bMarkedCorrect ? 1 : 0;
|
||||
Metrics.IncorrectResponseCount += Response.bMarkedCorrect ? 0 : 1;
|
||||
Metrics.RevealCount += Response.bAnswerWasRevealed ? 1 : 0;
|
||||
Metrics.RepeatCount += Response.bWasRepeat ? 1 : 0;
|
||||
|
||||
if (Response.ElapsedMs > 0)
|
||||
{
|
||||
Metrics.ElapsedAccumulator += Response.ElapsedMs;
|
||||
Metrics.ElapsedSampleCount += 1;
|
||||
Metrics.BestElapsedMs = Metrics.BestElapsedMs == 0
|
||||
? Response.ElapsedMs
|
||||
: FMath::Min(Metrics.BestElapsedMs, Response.ElapsedMs);
|
||||
Metrics.WorstElapsedMs = FMath::Max(Metrics.WorstElapsedMs, Response.ElapsedMs);
|
||||
}
|
||||
}
|
||||
|
||||
return Metrics;
|
||||
}
|
||||
|
||||
EHyperTwistTrainingMethodDrillDiagnosticState ResolveMethodDrillCaseDiagnosticState(
|
||||
const FMethodDrillCaseMetrics& Metrics,
|
||||
bool bCompleted,
|
||||
bool bStillPending
|
||||
)
|
||||
{
|
||||
if (bStillPending)
|
||||
{
|
||||
return EHyperTwistTrainingMethodDrillDiagnosticState::Deferred;
|
||||
}
|
||||
if (Metrics.RepeatCount > 0 || Metrics.IncorrectResponseCount > 0)
|
||||
{
|
||||
return EHyperTwistTrainingMethodDrillDiagnosticState::RepeatBurden;
|
||||
}
|
||||
if (Metrics.RevealCount > 0)
|
||||
{
|
||||
return EHyperTwistTrainingMethodDrillDiagnosticState::AssistedCompletion;
|
||||
}
|
||||
if (bCompleted)
|
||||
{
|
||||
return EHyperTwistTrainingMethodDrillDiagnosticState::CleanCompletion;
|
||||
}
|
||||
|
||||
return EHyperTwistTrainingMethodDrillDiagnosticState::Unknown;
|
||||
}
|
||||
|
||||
EHyperTwistTrainingReviewGrade ResolveMethodDrillCaseReviewGrade(
|
||||
const FMethodDrillCaseMetrics& Metrics,
|
||||
bool bCompleted,
|
||||
bool bStillPending,
|
||||
bool bWasCarryoverCase
|
||||
)
|
||||
{
|
||||
if (bStillPending)
|
||||
{
|
||||
return EHyperTwistTrainingReviewGrade::Again;
|
||||
}
|
||||
if (Metrics.RepeatCount > 1 || Metrics.IncorrectResponseCount > 0)
|
||||
{
|
||||
return EHyperTwistTrainingReviewGrade::Again;
|
||||
}
|
||||
if (Metrics.RepeatCount == 1 || Metrics.RevealCount > 0)
|
||||
{
|
||||
return EHyperTwistTrainingReviewGrade::Hard;
|
||||
}
|
||||
if (bWasCarryoverCase)
|
||||
{
|
||||
return EHyperTwistTrainingReviewGrade::Good;
|
||||
}
|
||||
if (bCompleted && Metrics.AttemptCount > 0 && Metrics.CorrectResponseCount == Metrics.AttemptCount)
|
||||
{
|
||||
return EHyperTwistTrainingReviewGrade::Easy;
|
||||
}
|
||||
if (bCompleted)
|
||||
{
|
||||
return EHyperTwistTrainingReviewGrade::Good;
|
||||
}
|
||||
|
||||
return EHyperTwistTrainingReviewGrade::Hard;
|
||||
}
|
||||
|
||||
FString BuildMethodDrillCaseBoundaryReason(
|
||||
const FMethodDrillCaseMetrics& Metrics,
|
||||
bool bCompleted,
|
||||
bool bStillPending,
|
||||
bool bWasCarryoverCase
|
||||
)
|
||||
{
|
||||
if (bStillPending)
|
||||
{
|
||||
return TEXT("case remains pending or active and should stay in follow-up focus");
|
||||
}
|
||||
if (Metrics.RepeatCount > 1 || Metrics.IncorrectResponseCount > 0)
|
||||
{
|
||||
return TEXT("case required repeated or incorrect responses before stabilization");
|
||||
}
|
||||
if (Metrics.RepeatCount == 1)
|
||||
{
|
||||
return TEXT("case required an immediate repeat before closure");
|
||||
}
|
||||
if (Metrics.RevealCount > 0)
|
||||
{
|
||||
return TEXT("case depended on answer reveal assistance");
|
||||
}
|
||||
if (bWasCarryoverCase)
|
||||
{
|
||||
return TEXT("case closed cleanly after resuming carried-over drill work");
|
||||
}
|
||||
if (bCompleted)
|
||||
{
|
||||
return TEXT("case closed cleanly without reveal or repeat pressure");
|
||||
}
|
||||
|
||||
return TEXT("case has no actionable diagnostic boundary");
|
||||
}
|
||||
|
||||
float BuildMethodDrillCasePriorityScore(
|
||||
const FMethodDrillCaseMetrics& Metrics,
|
||||
bool bStillPending,
|
||||
bool bWasCarryoverCase
|
||||
)
|
||||
{
|
||||
float Score = 0.0f;
|
||||
if (bStillPending)
|
||||
{
|
||||
Score += 100.0f;
|
||||
}
|
||||
|
||||
Score += static_cast<float>(Metrics.RepeatCount) * 45.0f;
|
||||
Score += static_cast<float>(Metrics.IncorrectResponseCount) * 30.0f;
|
||||
if (Metrics.RevealCount > 0)
|
||||
{
|
||||
Score += 20.0f;
|
||||
}
|
||||
if (bWasCarryoverCase)
|
||||
{
|
||||
Score += 10.0f;
|
||||
}
|
||||
|
||||
return Score;
|
||||
}
|
||||
|
||||
FString BuildMethodDrillRunBoundaryReason(const FHyperTwistTrainingMethodDrillDiagnosticPacket& Packet)
|
||||
{
|
||||
if (Packet.bBoundaryTriggeredByPendingCases)
|
||||
{
|
||||
return TEXT("deferred drill work remains open and should be revisited first");
|
||||
}
|
||||
if (Packet.bBoundaryTriggeredByRepeatBurden)
|
||||
{
|
||||
return TEXT("repeat burden or incorrect responses still dominate the follow-up set");
|
||||
}
|
||||
if (Packet.bBoundaryTriggeredByAssistance)
|
||||
{
|
||||
return TEXT("answer reveal assistance was needed on completed drill cases");
|
||||
}
|
||||
if (Packet.bBoundaryTriggeredByResumeCarryover)
|
||||
{
|
||||
return TEXT("resumed carryover work closed cleanly but should remain reviewable");
|
||||
}
|
||||
if (Packet.CompletedCaseCount > 0 && Packet.CompletedCaseCount == Packet.TotalCaseCount)
|
||||
{
|
||||
return TEXT("drill completed cleanly without reveal or repeat pressure");
|
||||
}
|
||||
|
||||
return TEXT("drill diagnostic packet is neutral");
|
||||
}
|
||||
|
||||
EHyperTwistTrainingReviewGrade ResolveMethodDrillRunReviewGrade(
|
||||
const FHyperTwistTrainingMethodDrillDiagnosticPacket& Packet
|
||||
)
|
||||
{
|
||||
if (Packet.bBoundaryTriggeredByPendingCases)
|
||||
{
|
||||
return EHyperTwistTrainingReviewGrade::Again;
|
||||
}
|
||||
|
||||
const bool bHasAgainCase = Packet.CasePackets.ContainsByPredicate(
|
||||
[](const FHyperTwistTrainingMethodDrillCaseComparisonPacket& CasePacket)
|
||||
{
|
||||
return CasePacket.RecommendedReviewGrade == EHyperTwistTrainingReviewGrade::Again;
|
||||
}
|
||||
);
|
||||
if (bHasAgainCase)
|
||||
{
|
||||
return EHyperTwistTrainingReviewGrade::Again;
|
||||
}
|
||||
if (Packet.bBoundaryTriggeredByRepeatBurden || Packet.bBoundaryTriggeredByAssistance)
|
||||
{
|
||||
return EHyperTwistTrainingReviewGrade::Hard;
|
||||
}
|
||||
if (Packet.bBoundaryTriggeredByResumeCarryover)
|
||||
{
|
||||
return EHyperTwistTrainingReviewGrade::Good;
|
||||
}
|
||||
if (Packet.CompletedCaseCount > 0
|
||||
&& Packet.CompletedCaseCount == Packet.TotalCaseCount
|
||||
&& Packet.ResponseCount >= Packet.CompletedCaseCount)
|
||||
{
|
||||
return EHyperTwistTrainingReviewGrade::Easy;
|
||||
}
|
||||
if (Packet.CompletedCaseCount == Packet.TotalCaseCount)
|
||||
{
|
||||
return EHyperTwistTrainingReviewGrade::Good;
|
||||
}
|
||||
|
||||
return EHyperTwistTrainingReviewGrade::Hard;
|
||||
}
|
||||
|
||||
EHyperTwistTrainingMethodDrillDiagnosticState ResolveMethodDrillRunDiagnosticState(
|
||||
const FHyperTwistTrainingMethodDrillDiagnosticPacket& Packet
|
||||
)
|
||||
{
|
||||
if (Packet.bBoundaryTriggeredByPendingCases)
|
||||
{
|
||||
return EHyperTwistTrainingMethodDrillDiagnosticState::Deferred;
|
||||
}
|
||||
if (Packet.bBoundaryTriggeredByRepeatBurden)
|
||||
{
|
||||
return EHyperTwistTrainingMethodDrillDiagnosticState::RepeatBurden;
|
||||
}
|
||||
if (Packet.bBoundaryTriggeredByAssistance)
|
||||
{
|
||||
return EHyperTwistTrainingMethodDrillDiagnosticState::AssistedCompletion;
|
||||
}
|
||||
if (Packet.CompletedCaseCount > 0 && Packet.CompletedCaseCount == Packet.TotalCaseCount)
|
||||
{
|
||||
return EHyperTwistTrainingMethodDrillDiagnosticState::CleanCompletion;
|
||||
}
|
||||
|
||||
return EHyperTwistTrainingMethodDrillDiagnosticState::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
FHyperTwistContentPack UHyperTwistTrainingLibrary::MakeSampleClassicContentPack()
|
||||
|
|
@ -1936,6 +2227,160 @@ FHyperTwistTrainingMethodDrillSummary UHyperTwistTrainingLibrary::DeriveMethodDr
|
|||
return HyperTwistTrainingLibraryInternal::BuildDrillSummaryInternal(RunState);
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillDiagnosticPacket UHyperTwistTrainingLibrary::DeriveMethodDrillDiagnosticPacket(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingMethodDrillDiagnosticPacket Packet;
|
||||
if (!RunState.IsStructurallyValid())
|
||||
{
|
||||
return Packet;
|
||||
}
|
||||
|
||||
Packet.RunId = RunState.RunId;
|
||||
Packet.UserId = RunState.UserId;
|
||||
Packet.DrillId = RunState.DrillDefinition.DrillId;
|
||||
Packet.SourceDeckId = RunState.DrillDefinition.SourceDeckId;
|
||||
Packet.MethodSegmentId = RunState.DrillDefinition.MethodDescriptor.SegmentId;
|
||||
Packet.StageId = RunState.DrillDefinition.StageId;
|
||||
Packet.StageLabel = RunState.DrillDefinition.StageLabel;
|
||||
Packet.SourceBatchId = RunState.SourceBatchId;
|
||||
Packet.ReferenceUtc = HyperTwistTrainingLibraryInternal::ResolveDrillTimestamp(RunState.LastUpdatedAtUtc);
|
||||
Packet.DrillMode = RunState.DrillDefinition.DrillMode;
|
||||
Packet.VisibilityPolicy = RunState.DrillDefinition.VisibilityPolicy;
|
||||
Packet.LifecycleState = RunState.LifecycleState;
|
||||
Packet.ResponseCount = RunState.Responses.Num();
|
||||
Packet.bWasResumedRun = !RunState.SourceBatchId.IsEmpty();
|
||||
|
||||
const TArray<FString> KnownCaseIds = HyperTwistTrainingLibraryInternal::BuildKnownDrillCaseIds(RunState);
|
||||
TSet<FString> CompletedCaseSet(RunState.CompletedCaseIds);
|
||||
TSet<FString> UnresolvedCaseSet;
|
||||
for (const FString& CaseId : RunState.PendingCaseIds)
|
||||
{
|
||||
if (!CaseId.IsEmpty())
|
||||
{
|
||||
UnresolvedCaseSet.Add(CaseId);
|
||||
}
|
||||
}
|
||||
if (!RunState.CurrentCase.CaseId.IsEmpty())
|
||||
{
|
||||
UnresolvedCaseSet.Add(RunState.CurrentCase.CaseId);
|
||||
}
|
||||
for (const FString& CompletedCaseId : RunState.CompletedCaseIds)
|
||||
{
|
||||
UnresolvedCaseSet.Remove(CompletedCaseId);
|
||||
}
|
||||
|
||||
Packet.TotalCaseCount = KnownCaseIds.Num();
|
||||
Packet.CompletedCaseCount = CompletedCaseSet.Num();
|
||||
Packet.PendingCaseCount = UnresolvedCaseSet.Num();
|
||||
|
||||
float MaxCasePriority = 0.0f;
|
||||
for (const FString& CaseId : KnownCaseIds)
|
||||
{
|
||||
const HyperTwistTrainingLibraryInternal::FMethodDrillCaseMetrics Metrics =
|
||||
HyperTwistTrainingLibraryInternal::CollectMethodDrillCaseMetrics(RunState, CaseId);
|
||||
const bool bCompleted = CompletedCaseSet.Contains(CaseId);
|
||||
const bool bStillPending = UnresolvedCaseSet.Contains(CaseId);
|
||||
const bool bWasCarryoverCase = Packet.bWasResumedRun;
|
||||
|
||||
FHyperTwistTrainingMethodDrillCaseComparisonPacket CasePacket;
|
||||
CasePacket.CaseId = CaseId;
|
||||
CasePacket.AttemptCount = Metrics.AttemptCount;
|
||||
CasePacket.CorrectResponseCount = Metrics.CorrectResponseCount;
|
||||
CasePacket.IncorrectResponseCount = Metrics.IncorrectResponseCount;
|
||||
CasePacket.RevealCount = Metrics.RevealCount;
|
||||
CasePacket.RepeatCount = Metrics.RepeatCount;
|
||||
CasePacket.AverageElapsedMs = Metrics.ElapsedSampleCount > 0
|
||||
? static_cast<int32>(Metrics.ElapsedAccumulator / Metrics.ElapsedSampleCount)
|
||||
: 0;
|
||||
CasePacket.BestElapsedMs = Metrics.BestElapsedMs;
|
||||
CasePacket.WorstElapsedMs = Metrics.WorstElapsedMs;
|
||||
CasePacket.bCompleted = bCompleted;
|
||||
CasePacket.bStillPending = bStillPending;
|
||||
CasePacket.bWasCarryoverCase = bWasCarryoverCase;
|
||||
CasePacket.DiagnosticState = HyperTwistTrainingLibraryInternal::ResolveMethodDrillCaseDiagnosticState(
|
||||
Metrics,
|
||||
bCompleted,
|
||||
bStillPending
|
||||
);
|
||||
CasePacket.RecommendedReviewGrade = HyperTwistTrainingLibraryInternal::ResolveMethodDrillCaseReviewGrade(
|
||||
Metrics,
|
||||
bCompleted,
|
||||
bStillPending,
|
||||
bWasCarryoverCase
|
||||
);
|
||||
CasePacket.bBoundaryTriggeredByReveal = Metrics.RevealCount > 0;
|
||||
CasePacket.bBoundaryTriggeredByRepeat = Metrics.RepeatCount > 0 || Metrics.IncorrectResponseCount > 0;
|
||||
CasePacket.bBoundaryTriggeredByDeferredState = bStillPending;
|
||||
CasePacket.bBoundaryTriggeredByCarryover = bWasCarryoverCase;
|
||||
CasePacket.BoundaryReason = HyperTwistTrainingLibraryInternal::BuildMethodDrillCaseBoundaryReason(
|
||||
Metrics,
|
||||
bCompleted,
|
||||
bStillPending,
|
||||
bWasCarryoverCase
|
||||
);
|
||||
CasePacket.PriorityScore = HyperTwistTrainingLibraryInternal::BuildMethodDrillCasePriorityScore(
|
||||
Metrics,
|
||||
bStillPending,
|
||||
bWasCarryoverCase
|
||||
);
|
||||
|
||||
Packet.CorrectResponseCount += Metrics.CorrectResponseCount;
|
||||
Packet.IncorrectResponseCount += Metrics.IncorrectResponseCount;
|
||||
Packet.RevealedCaseCount += Metrics.RevealCount > 0 ? 1 : 0;
|
||||
Packet.AssistedCompletionCount += CasePacket.bBoundaryTriggeredByReveal && bCompleted ? 1 : 0;
|
||||
Packet.RepeatBurdenCaseCount += CasePacket.bBoundaryTriggeredByRepeat ? 1 : 0;
|
||||
Packet.DeferredCaseCount +=
|
||||
CasePacket.DiagnosticState == EHyperTwistTrainingMethodDrillDiagnosticState::Deferred ? 1 : 0;
|
||||
Packet.ResolvedCarryoverCaseCount += bWasCarryoverCase && bCompleted ? 1 : 0;
|
||||
MaxCasePriority = FMath::Max(MaxCasePriority, CasePacket.PriorityScore);
|
||||
Packet.CasePackets.Add(CasePacket);
|
||||
}
|
||||
|
||||
Packet.CasePackets.Sort([](
|
||||
const FHyperTwistTrainingMethodDrillCaseComparisonPacket& Left,
|
||||
const FHyperTwistTrainingMethodDrillCaseComparisonPacket& Right
|
||||
)
|
||||
{
|
||||
if (!FMath::IsNearlyEqual(Left.PriorityScore, Right.PriorityScore))
|
||||
{
|
||||
return Left.PriorityScore > Right.PriorityScore;
|
||||
}
|
||||
return Left.CaseId < Right.CaseId;
|
||||
});
|
||||
|
||||
for (const FHyperTwistTrainingMethodDrillCaseComparisonPacket& CasePacket : Packet.CasePackets)
|
||||
{
|
||||
if (CasePacket.PriorityScore > 0.0f)
|
||||
{
|
||||
Packet.FocusCaseIds.Add(CasePacket.CaseId);
|
||||
}
|
||||
}
|
||||
|
||||
Packet.CompletionFraction = Packet.TotalCaseCount > 0
|
||||
? static_cast<float>(Packet.CompletedCaseCount) / static_cast<float>(Packet.TotalCaseCount)
|
||||
: 0.0f;
|
||||
const int32 AssistanceCaseCount = Packet.AssistedCompletionCount + Packet.RepeatBurdenCaseCount;
|
||||
Packet.AssistanceFraction = Packet.TotalCaseCount > 0
|
||||
? static_cast<float>(AssistanceCaseCount) / static_cast<float>(Packet.TotalCaseCount)
|
||||
: 0.0f;
|
||||
Packet.bBoundaryTriggeredByPendingCases = Packet.DeferredCaseCount > 0;
|
||||
Packet.bBoundaryTriggeredByRepeatBurden = Packet.RepeatBurdenCaseCount > 0;
|
||||
Packet.bBoundaryTriggeredByAssistance = Packet.AssistedCompletionCount > 0;
|
||||
Packet.bBoundaryTriggeredByResumeCarryover = Packet.bWasResumedRun;
|
||||
Packet.bNeedsFollowUpTemplate = Packet.FocusCaseIds.Num() > 0;
|
||||
Packet.bNeedsReviewPlanBridge = Packet.FocusCaseIds.Num() > 0 && !Packet.bBoundaryTriggeredByPendingCases;
|
||||
Packet.PriorityScore = MaxCasePriority
|
||||
+ static_cast<float>(Packet.DeferredCaseCount * 10)
|
||||
+ static_cast<float>(Packet.RepeatBurdenCaseCount * 5)
|
||||
+ static_cast<float>(Packet.AssistedCompletionCount * 2);
|
||||
Packet.DiagnosticState = HyperTwistTrainingLibraryInternal::ResolveMethodDrillRunDiagnosticState(Packet);
|
||||
Packet.RecommendedReviewGrade = HyperTwistTrainingLibraryInternal::ResolveMethodDrillRunReviewGrade(Packet);
|
||||
Packet.BoundaryReason = HyperTwistTrainingLibraryInternal::BuildMethodDrillRunBoundaryReason(Packet);
|
||||
return Packet;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillBatch UHyperTwistTrainingLibrary::BuildMethodDrillBatch(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState,
|
||||
const FString& BatchId,
|
||||
|
|
|
|||
|
|
@ -3158,6 +3158,82 @@ FHyperTwistTrainingMethodDrillDefinition UHyperTwistTrainingRepositoryLibrary::B
|
|||
return Result;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingSessionTemplate UHyperTwistTrainingRepositoryLibrary::BuildMethodDrillFollowUpTemplate(
|
||||
const FHyperTwistTrainingMethodDrillDiagnosticPacket& DiagnosticPacket,
|
||||
const FString& TemplateId
|
||||
)
|
||||
{
|
||||
FHyperTwistTrainingSessionTemplate SessionTemplate;
|
||||
if (!DiagnosticPacket.IsStructurallyValid()
|
||||
|| !DiagnosticPacket.bNeedsFollowUpTemplate
|
||||
|| DiagnosticPacket.SourceDeckId.IsEmpty())
|
||||
{
|
||||
return SessionTemplate;
|
||||
}
|
||||
|
||||
SessionTemplate.UserId = DiagnosticPacket.UserId;
|
||||
SessionTemplate.TemplateId = TemplateId.IsEmpty()
|
||||
? FString::Printf(TEXT("method_drill_follow_up_%s"), *DiagnosticPacket.RunId)
|
||||
: TemplateId;
|
||||
SessionTemplate.Title = !DiagnosticPacket.StageLabel.IsEmpty()
|
||||
? FString::Printf(TEXT("%s Drill Follow-Up"), *DiagnosticPacket.StageLabel)
|
||||
: TEXT("Method Drill Follow-Up");
|
||||
SessionTemplate.TemplateKind =
|
||||
DiagnosticPacket.bBoundaryTriggeredByPendingCases || DiagnosticPacket.bBoundaryTriggeredByRepeatBurden
|
||||
? EHyperTwistTrainingSessionTemplateKind::Recovery
|
||||
: EHyperTwistTrainingSessionTemplateKind::ReviewPlan;
|
||||
SessionTemplate.FocusDeckId = DiagnosticPacket.SourceDeckId;
|
||||
SessionTemplate.MethodSegmentId = DiagnosticPacket.MethodSegmentId;
|
||||
|
||||
switch (DiagnosticPacket.DrillMode)
|
||||
{
|
||||
case EHyperTwistTrainingDrillModeKind::Recognition:
|
||||
case EHyperTwistTrainingDrillModeKind::Reconstruction:
|
||||
SessionTemplate.SuggestedMode = EHyperTwistTrainingDeliveryMode::RecognitionAssisted;
|
||||
break;
|
||||
case EHyperTwistTrainingDrillModeKind::Execution:
|
||||
SessionTemplate.SuggestedMode = EHyperTwistTrainingDeliveryMode::VirtualCube;
|
||||
break;
|
||||
case EHyperTwistTrainingDrillModeKind::Recall:
|
||||
default:
|
||||
SessionTemplate.SuggestedMode = EHyperTwistTrainingDeliveryMode::Timer;
|
||||
break;
|
||||
}
|
||||
|
||||
SessionTemplate.SuggestedSelectionPolicy =
|
||||
DiagnosticPacket.bBoundaryTriggeredByPendingCases
|
||||
? EHyperTwistTrainingSelectionPolicy::Scripted
|
||||
: EHyperTwistTrainingSelectionPolicy::Weighted;
|
||||
SessionTemplate.FocusCaseIds =
|
||||
HyperTwistTrainingRepositoryLibraryInternal::DeduplicateTemplateCaseIds(DiagnosticPacket.FocusCaseIds);
|
||||
if (SessionTemplate.FocusCaseIds.Num() == 0)
|
||||
{
|
||||
return FHyperTwistTrainingSessionTemplate();
|
||||
}
|
||||
|
||||
SessionTemplate.RecommendedCaseCount = FMath::Max(
|
||||
1,
|
||||
FMath::Min(
|
||||
SessionTemplate.FocusCaseIds.Num(),
|
||||
DiagnosticPacket.RecommendedReviewGrade == EHyperTwistTrainingReviewGrade::Again ? 6 : 4
|
||||
)
|
||||
);
|
||||
SessionTemplate.GuidanceLabel = !DiagnosticPacket.BoundaryReason.IsEmpty()
|
||||
? DiagnosticPacket.BoundaryReason
|
||||
: TEXT("method-drill follow-up");
|
||||
SessionTemplate.bPreferReviewRun =
|
||||
DiagnosticPacket.bNeedsReviewPlanBridge
|
||||
|| DiagnosticPacket.RecommendedReviewGrade != EHyperTwistTrainingReviewGrade::Easy;
|
||||
SessionTemplate.bCoachReview = false;
|
||||
SessionTemplate.bPreferShortReviewSet = SessionTemplate.RecommendedCaseCount <= 4;
|
||||
SessionTemplate.bUserEditable = false;
|
||||
SessionTemplate.bUserCustomized = false;
|
||||
SessionTemplate.bUserCreated = false;
|
||||
SessionTemplate.LastUpdatedAtUtc =
|
||||
HyperTwistTrainingRepositoryLibraryInternal::ResolveReferenceUtc(DiagnosticPacket.ReferenceUtc);
|
||||
return SessionTemplate.IsStructurallyValid() ? SessionTemplate : FHyperTwistTrainingSessionTemplate();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRepositoryState UHyperTwistTrainingRepositoryLibrary::UpsertRunRecord(
|
||||
const FHyperTwistTrainingRepositoryState& RepositoryState,
|
||||
const FHyperTwistTrainingRunRecord& RunRecord
|
||||
|
|
|
|||
|
|
@ -92,6 +92,28 @@ FHyperTwistTrainingMethodDrillSummary UHyperTwistTrainingRuntimeLibrary::GetActi
|
|||
return FHyperTwistTrainingMethodDrillSummary();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillDiagnosticPacket
|
||||
UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingMethodDrillDiagnosticPacket(UObject* WorldContextObject)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->GetActiveMethodDrillDiagnosticPacket();
|
||||
}
|
||||
|
||||
return FHyperTwistTrainingMethodDrillDiagnosticPacket();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingSessionTemplate
|
||||
UHyperTwistTrainingRuntimeLibrary::GetActiveTrainingMethodDrillFollowUpTemplate(UObject* WorldContextObject)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
{
|
||||
return TrainingSubsystem->GetActiveMethodDrillFollowUpTemplate();
|
||||
}
|
||||
|
||||
return FHyperTwistTrainingSessionTemplate();
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRepositoryState UHyperTwistTrainingRuntimeLibrary::GetTrainingRepositoryState(UObject* WorldContextObject)
|
||||
{
|
||||
if (UHyperTwistTrainingSubsystem* TrainingSubsystem = GetTrainingSubsystem(WorldContextObject))
|
||||
|
|
|
|||
|
|
@ -425,6 +425,16 @@ FHyperTwistTrainingMethodDrillSummary UHyperTwistTrainingSubsystem::GetActiveMet
|
|||
return ActiveMethodDrillSummary;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingMethodDrillDiagnosticPacket UHyperTwistTrainingSubsystem::GetActiveMethodDrillDiagnosticPacket() const
|
||||
{
|
||||
return ActiveMethodDrillDiagnosticPacket;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingSessionTemplate UHyperTwistTrainingSubsystem::GetActiveMethodDrillFollowUpTemplate() const
|
||||
{
|
||||
return ActiveMethodDrillFollowUpTemplate;
|
||||
}
|
||||
|
||||
FHyperTwistTrainingRepositoryState UHyperTwistTrainingSubsystem::GetTrainingRepositoryState() const
|
||||
{
|
||||
return TrainingRepositoryState;
|
||||
|
|
@ -2364,6 +2374,8 @@ void UHyperTwistTrainingSubsystem::ClearActiveMethodDrillRun()
|
|||
{
|
||||
ActiveMethodDrillRunState = FHyperTwistTrainingMethodDrillRunState();
|
||||
ActiveMethodDrillSummary = FHyperTwistTrainingMethodDrillSummary();
|
||||
ActiveMethodDrillDiagnosticPacket = FHyperTwistTrainingMethodDrillDiagnosticPacket();
|
||||
ActiveMethodDrillFollowUpTemplate = FHyperTwistTrainingSessionTemplate();
|
||||
bHasActiveMethodDrillRun = false;
|
||||
}
|
||||
|
||||
|
|
@ -2386,12 +2398,23 @@ void UHyperTwistTrainingSubsystem::RefreshMethodDrillSummary()
|
|||
if (!ActiveMethodDrillRunState.IsStructurallyValid())
|
||||
{
|
||||
ActiveMethodDrillSummary = FHyperTwistTrainingMethodDrillSummary();
|
||||
ActiveMethodDrillDiagnosticPacket = FHyperTwistTrainingMethodDrillDiagnosticPacket();
|
||||
ActiveMethodDrillFollowUpTemplate = FHyperTwistTrainingSessionTemplate();
|
||||
return;
|
||||
}
|
||||
|
||||
ActiveMethodDrillSummary = UHyperTwistTrainingLibrary::DeriveMethodDrillSummary(
|
||||
ActiveMethodDrillRunState
|
||||
);
|
||||
ActiveMethodDrillDiagnosticPacket = UHyperTwistTrainingLibrary::DeriveMethodDrillDiagnosticPacket(
|
||||
ActiveMethodDrillRunState
|
||||
);
|
||||
ActiveMethodDrillFollowUpTemplate = ActiveMethodDrillDiagnosticPacket.IsStructurallyValid()
|
||||
? UHyperTwistTrainingRepositoryLibrary::BuildMethodDrillFollowUpTemplate(
|
||||
ActiveMethodDrillDiagnosticPacket,
|
||||
FString()
|
||||
)
|
||||
: FHyperTwistTrainingSessionTemplate();
|
||||
}
|
||||
|
||||
void UHyperTwistTrainingSubsystem::RefreshRepositoryViews()
|
||||
|
|
|
|||
|
|
@ -92,6 +92,12 @@ public:
|
|||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingDrillCaseModeCompatibility MakeSampleMethodDrillCaseModeCompatibility();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingMethodDrillDiagnosticPacket MakeSampleMethodDrillDiagnosticPacket();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingSessionTemplate MakeSampleMethodDrillFollowUpTemplate();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
|
||||
static FHyperTwistTrainingRunStepResult MakeSampleTrainingRunStepResult();
|
||||
|
||||
|
|
|
|||
|
|
@ -201,6 +201,11 @@ public:
|
|||
const FHyperTwistTrainingMethodDrillRunState& RunState
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingMethodDrillDiagnosticPacket DeriveMethodDrillDiagnosticPacket(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
static FHyperTwistTrainingMethodDrillBatch BuildMethodDrillBatch(
|
||||
const FHyperTwistTrainingMethodDrillRunState& RunState,
|
||||
|
|
|
|||
|
|
@ -124,6 +124,12 @@ public:
|
|||
int32 MaxFavoriteCases
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Repository|Drill")
|
||||
static FHyperTwistTrainingSessionTemplate BuildMethodDrillFollowUpTemplate(
|
||||
const FHyperTwistTrainingMethodDrillDiagnosticPacket& DiagnosticPacket,
|
||||
const FString& TemplateId
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Repository")
|
||||
static FHyperTwistTrainingRepositoryState UpsertRunRecord(
|
||||
const FHyperTwistTrainingRepositoryState& RepositoryState,
|
||||
|
|
|
|||
|
|
@ -37,6 +37,16 @@ public:
|
|||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingMethodDrillSummary GetActiveMethodDrillSummary(UObject* WorldContextObject);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingMethodDrillDiagnosticPacket GetActiveTrainingMethodDrillDiagnosticPacket(
|
||||
UObject* WorldContextObject
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingSessionTemplate GetActiveTrainingMethodDrillFollowUpTemplate(
|
||||
UObject* WorldContextObject
|
||||
);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training", meta = (WorldContext = "WorldContextObject"))
|
||||
static FHyperTwistTrainingRepositoryState GetTrainingRepositoryState(UObject* WorldContextObject);
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,12 @@ public:
|
|||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
FHyperTwistTrainingMethodDrillSummary GetActiveMethodDrillSummary() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
FHyperTwistTrainingMethodDrillDiagnosticPacket GetActiveMethodDrillDiagnosticPacket() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training|Drill")
|
||||
FHyperTwistTrainingSessionTemplate GetActiveMethodDrillFollowUpTemplate() const;
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "HyperTwist|Training")
|
||||
FHyperTwistTrainingRepositoryState GetTrainingRepositoryState() const;
|
||||
|
||||
|
|
@ -467,6 +473,12 @@ private:
|
|||
UPROPERTY()
|
||||
FHyperTwistTrainingMethodDrillSummary ActiveMethodDrillSummary;
|
||||
|
||||
UPROPERTY()
|
||||
FHyperTwistTrainingMethodDrillDiagnosticPacket ActiveMethodDrillDiagnosticPacket;
|
||||
|
||||
UPROPERTY()
|
||||
FHyperTwistTrainingSessionTemplate ActiveMethodDrillFollowUpTemplate;
|
||||
|
||||
UPROPERTY()
|
||||
FHyperTwistTrainingRepositoryState TrainingRepositoryState;
|
||||
|
||||
|
|
|
|||
|
|
@ -155,6 +155,16 @@ enum class EHyperTwistTrainingDrillLifecycleState : uint8
|
|||
Aborted UMETA(DisplayName = "Aborted")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EHyperTwistTrainingMethodDrillDiagnosticState : uint8
|
||||
{
|
||||
Unknown UMETA(DisplayName = "Unknown"),
|
||||
CleanCompletion UMETA(DisplayName = "Clean Completion"),
|
||||
AssistedCompletion UMETA(DisplayName = "Assisted Completion"),
|
||||
RepeatBurden UMETA(DisplayName = "Repeat Burden"),
|
||||
Deferred UMETA(DisplayName = "Deferred")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EHyperTwistTrainingDrillEntrySource : uint8
|
||||
{
|
||||
|
|
@ -2460,6 +2470,205 @@ struct FHyperTwistTrainingDrillCaseModeCompatibility
|
|||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingMethodDrillCaseComparisonPacket
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString CaseId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 AttemptCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 CorrectResponseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 IncorrectResponseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 RevealCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 RepeatCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 AverageElapsedMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 BestElapsedMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 WorstElapsedMs = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bCompleted = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bStillPending = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bWasCarryoverCase = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingMethodDrillDiagnosticState DiagnosticState =
|
||||
EHyperTwistTrainingMethodDrillDiagnosticState::Unknown;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingReviewGrade RecommendedReviewGrade = EHyperTwistTrainingReviewGrade::Good;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bBoundaryTriggeredByReveal = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bBoundaryTriggeredByRepeat = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bBoundaryTriggeredByDeferredState = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bBoundaryTriggeredByCarryover = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString BoundaryReason;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float PriorityScore = 0.0f;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !CaseId.IsEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingMethodDrillDiagnosticPacket
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString RunId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString UserId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString DrillId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SourceDeckId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString MethodSegmentId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString StageId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString StageLabel;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString SourceBatchId;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString ReferenceUtc;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingDrillModeKind DrillMode = EHyperTwistTrainingDrillModeKind::Recognition;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingDrillVisibilityPolicy VisibilityPolicy =
|
||||
EHyperTwistTrainingDrillVisibilityPolicy::FullInformation;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingDrillLifecycleState LifecycleState = EHyperTwistTrainingDrillLifecycleState::Ready;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 TotalCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 CompletedCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 PendingCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ResponseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 CorrectResponseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 IncorrectResponseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 RevealedCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 AssistedCompletionCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 RepeatBurdenCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 DeferredCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
int32 ResolvedCarryoverCaseCount = 0;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float CompletionFraction = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float AssistanceFraction = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bWasResumedRun = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bNeedsFollowUpTemplate = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bNeedsReviewPlanBridge = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingMethodDrillDiagnosticState DiagnosticState =
|
||||
EHyperTwistTrainingMethodDrillDiagnosticState::Unknown;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
EHyperTwistTrainingReviewGrade RecommendedReviewGrade = EHyperTwistTrainingReviewGrade::Good;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bBoundaryTriggeredByPendingCases = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bBoundaryTriggeredByRepeatBurden = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bBoundaryTriggeredByAssistance = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
bool bBoundaryTriggeredByResumeCarryover = false;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
FString BoundaryReason;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
float PriorityScore = 0.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FString> FocusCaseIds;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist")
|
||||
TArray<FHyperTwistTrainingMethodDrillCaseComparisonPacket> CasePackets;
|
||||
|
||||
bool IsStructurallyValid() const
|
||||
{
|
||||
return !RunId.IsEmpty() && !UserId.IsEmpty() && !DrillId.IsEmpty();
|
||||
}
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FHyperTwistTrainingLearnerPreset
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue