#include "Core/DescentBoot.h" #include "Core/DescentGameMode.h" #include "Debug/DescentStateRegistry.h" #include "TheDescent.h" #include "Engine/World.h" #include "HAL/PlatformTime.h" FDescentBootRegistry& FDescentBootRegistry::Get() { static FDescentBootRegistry Instance; return Instance; } void FDescentBootRegistry::Register(const TCHAR* Name, int32 Order, FDescentBootFn Fn) { if (Steps.Contains(Name)) { UE_LOG(LogDescent, Warning, TEXT("Boot: step '%s' registered twice; the later one replaces the earlier"), Name); } FStep& S = Steps.FindOrAdd(Name); S.Name = Name; S.Order = Order; S.Fn = MoveTemp(Fn); } bool FDescentBootRegistry::Unregister(const FString& Name) { return Steps.Remove(Name) > 0; } TArray FDescentBootRegistry::GetOrdered() const { TArray Out; Steps.GenerateValueArray(Out); Out.Sort([](const FStep& A, const FStep& B) { return A.Order != B.Order ? A.Order < B.Order : A.Name < B.Name; }); return Out; } FDescentBootReport FDescentBootRegistry::Run(FDescentBootContext& Context) const { FDescentBootReport Report; Report.bRan = true; for (const FStep& Step : GetOrdered()) { Context.ResetFailure(); const double T0 = FPlatformTime::Seconds(); if (Step.Fn) { Step.Fn(Context); } FDescentBootReport::FEntry E; E.Name = Step.Name; E.Order = Step.Order; E.Ms = (FPlatformTime::Seconds() - T0) * 1000.0; E.bOk = !Context.HasFailed(); E.Error = Context.GetFailReason(); if (!E.bOk) { Report.bOk = false; UE_LOG(LogDescent, Error, TEXT("DESCENT_BOOT_FAIL step=%s order=%d reason=\"%s\""), *E.Name, E.Order, *E.Error); } else { UE_LOG(LogDescent, Display, TEXT("Boot: %-24s order %4d %.1f ms"), *E.Name, E.Order, E.Ms); } Report.Ran.Add(MoveTemp(E)); } Context.ResetFailure(); return Report; } // --------------------------------------------------------------------------------------------------------- // State section "boot": the steps that exist and what the last run did. // --------------------------------------------------------------------------------------------------------- static FDescentStateProviderRegistrar GBootSection(TEXT("boot"), [](UWorld* World, FJsonObject& Out) { TArray> Registered; for (const FDescentBootRegistry::FStep& S : FDescentBootRegistry::Get().GetOrdered()) { TSharedRef E = MakeShared(); E->SetStringField(TEXT("name"), S.Name); E->SetNumberField(TEXT("order"), S.Order); Registered.Add(MakeShared(E)); } Out.SetArrayField(TEXT("registered"), Registered); const ADescentGameMode* GM = World ? World->GetAuthGameMode() : nullptr; Out.SetBoolField(TEXT("ran"), GM && GM->GetBootReport().bRan); Out.SetBoolField(TEXT("ok"), !GM || GM->GetBootReport().bOk); TArray> Ran; if (GM) { for (const FDescentBootReport::FEntry& R : GM->GetBootReport().Ran) { TSharedRef E = MakeShared(); E->SetStringField(TEXT("name"), R.Name); E->SetNumberField(TEXT("order"), R.Order); E->SetNumberField(TEXT("ms"), Descent::Json::Round(R.Ms)); E->SetBoolField(TEXT("ok"), R.bOk); if (!R.bOk) { E->SetStringField(TEXT("error"), R.Error); } Ran.Add(MakeShared(E)); } } Out.SetArrayField(TEXT("ran_steps"), Ran); });