From bdbb2397c1f0e3d587559ff0f6740b24ca7d7098 Mon Sep 17 00:00:00 2001 From: Oleg Petruny Date: Thu, 24 Apr 2025 16:13:56 +0200 Subject: [PATCH] wip --- .../Movies/Images/T_StartupImageA.uasset | 3 + .../Movies/Images/T_StartupImageB.uasset | 3 + .../Source/Lost_Edge/Lost_Edge.Build.cs | 7 +- .../Lost_Edge/Source/Lost_Edge/Lost_Edge.cpp | 2 +- .../Source/Lost_Edge/Private/CommonData.h | 24 +++++ .../Lost_Edge/Private/CustomGameInstance.cpp | 12 ++- .../Lost_Edge/Private/CustomGameInstance.h | 2 + .../Private/Graphics/GrassGenerator.cpp | 12 ++- .../Private/LoadingScreen/LoadingScreen.cpp | 42 ++++++++ .../Private/LoadingScreen/LoadingScreen.h | 23 +++++ .../LoadingScreen/SLoadingScreenWidget.cpp | 97 +++++++++++++++++++ .../LoadingScreen/SLoadingScreenWidget.h | 35 +++++++ 12 files changed, 256 insertions(+), 6 deletions(-) create mode 100644 UnrealProject/Lost_Edge/Content/Movies/Images/T_StartupImageA.uasset create mode 100644 UnrealProject/Lost_Edge/Content/Movies/Images/T_StartupImageB.uasset create mode 100644 UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CommonData.h create mode 100644 UnrealProject/Lost_Edge/Source/Lost_Edge/Private/LoadingScreen/LoadingScreen.cpp create mode 100644 UnrealProject/Lost_Edge/Source/Lost_Edge/Private/LoadingScreen/LoadingScreen.h create mode 100644 UnrealProject/Lost_Edge/Source/Lost_Edge/Private/LoadingScreen/SLoadingScreenWidget.cpp create mode 100644 UnrealProject/Lost_Edge/Source/Lost_Edge/Private/LoadingScreen/SLoadingScreenWidget.h diff --git a/UnrealProject/Lost_Edge/Content/Movies/Images/T_StartupImageA.uasset b/UnrealProject/Lost_Edge/Content/Movies/Images/T_StartupImageA.uasset new file mode 100644 index 0000000..cadbe6f --- /dev/null +++ b/UnrealProject/Lost_Edge/Content/Movies/Images/T_StartupImageA.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9a72cea60b2614badcb3f4fd06b8da8b6fd9648bcdd677df9ca33250a0c941b1 +size 191408 diff --git a/UnrealProject/Lost_Edge/Content/Movies/Images/T_StartupImageB.uasset b/UnrealProject/Lost_Edge/Content/Movies/Images/T_StartupImageB.uasset new file mode 100644 index 0000000..68c652e --- /dev/null +++ b/UnrealProject/Lost_Edge/Content/Movies/Images/T_StartupImageB.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e38340ad683d35542b6153be865655e24dcbb862b4e431f3c993b8f3b36480c +size 221120 diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Lost_Edge.Build.cs b/UnrealProject/Lost_Edge/Source/Lost_Edge/Lost_Edge.Build.cs index 9bf1e96..0d596d6 100644 --- a/UnrealProject/Lost_Edge/Source/Lost_Edge/Lost_Edge.Build.cs +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Lost_Edge.Build.cs @@ -12,7 +12,12 @@ public class Lost_Edge : ModuleRules PrivateDependencyModuleNames.AddRange(new string[] { "EnhancedInput", "UMG", "RHI", "RenderCore", "Lost_EdgeShaders", "PakFile", //"TextureCompressor", "LevelSequence", "MovieScene", "HTTP", "Json", "ApplicationCore", "ProceduralMeshComponent", "Landscape", "MeshDescription", "StaticMeshDescription", - "AssetRegistry", "UnrealEd", "LevelEditor" }); // "Slate", "SlateCore" + "AssetRegistry", "LevelEditor", "MoviePlayer", "Slate", "SlateCore" }); + + if (Target.bBuildEditor) + { + PrivateDependencyModuleNames.AddRange(new string[] { "UnrealEd" }); + } // UE_LOG(LogTemp, Log, TEXT("capture: %s"), (capture ? TEXT("true") : TEXT("false"))); // GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Yellow, TEXT("1")); diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Lost_Edge.cpp b/UnrealProject/Lost_Edge/Source/Lost_Edge/Lost_Edge.cpp index c2e27ec..dbc5323 100644 --- a/UnrealProject/Lost_Edge/Source/Lost_Edge/Lost_Edge.cpp +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Lost_Edge.cpp @@ -3,4 +3,4 @@ #include "Lost_Edge.h" #include "Modules/ModuleManager.h" -IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, Lost_Edge, "Lost_Edge" ); +IMPLEMENT_PRIMARY_GAME_MODULE(FDefaultGameModuleImpl, Lost_Edge, "Lost_Edge"); diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CommonData.h b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CommonData.h new file mode 100644 index 0000000..9230e97 --- /dev/null +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CommonData.h @@ -0,0 +1,24 @@ +// Oleg Petruny proprietary. + +#pragma once + +#include "Kismet/BlueprintFunctionLibrary.h" + +#include "CommonData.generated.h" + +/** + * Collection of common/universal/without own scope/specific data values. + */ +UCLASS() +class UCommonData : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +public: + static const TSharedPtr KindaBlackColorBrush() + { + static auto brush = MakeShared(FLinearColor(0.01f, 0.01f, 0.01f)); + return brush; + } + +}; diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CustomGameInstance.cpp b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CustomGameInstance.cpp index 60769f0..cedf822 100644 --- a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CustomGameInstance.cpp +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CustomGameInstance.cpp @@ -8,6 +8,7 @@ #include "ContentLoader.h" #include "CustomGameSettings.h" #include "Levels/LevelBase.h" +#include "LoadingScreen/LoadingScreen.h" #include "PlayerBase.h" #include "SaveData.h" @@ -21,11 +22,14 @@ UCustomGameInstance* UCustomGameInstance::instance = nullptr; void UCustomGameInstance::Init() { + // init game instance UGameInstance::Init(); - instance = this; + // setup content loader contentLoader = NewObject(this); + + // setup global singletons for(auto& _class : globalInstancesClasses) { UObject* gi = NewObject(_class); @@ -34,10 +38,16 @@ void UCustomGameInstance::Init() } globalInstancesClasses.Empty(); + // set current save if(auto save = UGameplayStatics::LoadGameFromSlot(saveName, saveIndex)) saveData = Cast(save); else saveData = Cast(UGameplayStatics::CreateSaveGameObject(USaveData::StaticClass())); + + // setup loading screen + loadingScreen = NewObject(this); + FCoreUObjectDelegates::PreLoadMap.AddUObject(loadingScreen, &ULoadingScreen::BeginLoadingScreen); + FCoreUObjectDelegates::PostLoadMapWithWorld.AddUObject(loadingScreen, &ULoadingScreen::EndLoadingScreen); } void UCustomGameInstance::Shutdown() diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CustomGameInstance.h b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CustomGameInstance.h index d2cd197..a78eca2 100644 --- a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CustomGameInstance.h +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/CustomGameInstance.h @@ -52,6 +52,8 @@ public: protected: UPROPERTY() class UContentLoader* contentLoader; + UPROPERTY() + class ULoadingScreen* loadingScreen; UPROPERTY(EditDefaultsOnly) TSet> globalInstancesClasses; diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Graphics/GrassGenerator.cpp b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Graphics/GrassGenerator.cpp index 40da12f..e084e3c 100644 --- a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Graphics/GrassGenerator.cpp +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/Graphics/GrassGenerator.cpp @@ -4,7 +4,6 @@ #include "AssetRegistry/AssetRegistryModule.h" #include "Components/BoxComponent.h" -#include "Editor/EditorEngine.h" #include "Engine/SkyLight.h" #include "Engine/StaticMeshActor.h" #include "Landscape.h" @@ -15,6 +14,9 @@ #include "ProceduralMeshComponent.h" #include "ProceduralMeshConversion.h" #include "StaticMeshDescription.h" +#if WITH_EDITOR +#include "Editor/EditorEngine.h" +#endif AGrassGenerator::AGrassGenerator() { @@ -44,6 +46,7 @@ void AGrassGenerator::PostEditChangeProperty(FPropertyChangedEvent& PropertyChan void AGrassGenerator::Generate() { +#if WITH_EDITOR Clear(); FVector loc = GetActorLocation(); @@ -177,16 +180,20 @@ void AGrassGenerator::Generate() mesh->CreateMeshSection(sectionsCount++, vertices, triangles, normals, UVs, {}, {}, false); Update(); +#endif } void AGrassGenerator::Clear() { +#if WITH_EDITOR mesh->ClearAllMeshSections(); sectionsCount = 0; +#endif } void AGrassGenerator::Export() { +#if WITH_EDITOR const FString actorName = GetName(); const FString levelName = GetWorld()->GetMapName().RightChop(2); const FString levelPath = FPaths::GetPath(GEditor->GetEditorSubsystem()->GetCurrentLevel()->GetPathName()); @@ -205,9 +212,7 @@ void AGrassGenerator::Export() smeshDesc->SetMeshDescription(meshDesc); smesh->BuildFromStaticMeshDescriptions({ smeshDesc }, false, true); smesh->GetStaticMaterials().Add({ grassMaterial.LoadSynchronous() }); -#if WITH_EDITOR smesh->PostEditChange(); -#endif smesh->MarkPackageDirty(); FAssetRegistryModule::AssetCreated(smesh); @@ -225,6 +230,7 @@ void AGrassGenerator::Export() GEditor->SelectNone(false, true); GEditor->SelectActor(smeshActor, true, true); GEditor->RedrawAllViewports(); +#endif } void AGrassGenerator::Update() diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/LoadingScreen/LoadingScreen.cpp b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/LoadingScreen/LoadingScreen.cpp new file mode 100644 index 0000000..06621a6 --- /dev/null +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/LoadingScreen/LoadingScreen.cpp @@ -0,0 +1,42 @@ +// Oleg Petruny proprietary. + +#include "LoadingScreen.h" + +#include "MoviePlayer.h" + +#include "SLoadingScreenWidget.h" + +void ULoadingScreen::BeginLoadingScreen(const FString& mapName) +{ + if(active || IsRunningDedicatedServer()) + return; + active = true; + + FLoadingScreenAttributes params; + params.bAutoCompleteWhenLoadingCompletes = false; + params.MinimumLoadingScreenDisplayTime = 2.0f; + if(first) + { + // Game init loading screen + first = false; + params.bMoviesAreSkippable = true; + params.WidgetLoadingScreen = SNew(SStartupImageWidget) + .FadeDuration(params.MinimumLoadingScreenDisplayTime); + } + else + { + // Game level loading screen + params.WidgetLoadingScreen = SNew(SStartupImageWidget) + .FadeDuration(params.MinimumLoadingScreenDisplayTime); + } + + GetMoviePlayer()->SetupLoadingScreen(params); +} + +void ULoadingScreen::EndLoadingScreen(UWorld* inLoadedWorld) +{ + if(!active) + return; + active = false; + +} diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/LoadingScreen/LoadingScreen.h b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/LoadingScreen/LoadingScreen.h new file mode 100644 index 0000000..98eeacb --- /dev/null +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/LoadingScreen/LoadingScreen.h @@ -0,0 +1,23 @@ +// Oleg Petruny proprietary. + +#pragma once + +#include "UObject/Object.h" + +#include "LoadingScreen.generated.h" + +UCLASS() +class ULoadingScreen : public UObject +{ + GENERATED_BODY() + +public: + UFUNCTION() + void BeginLoadingScreen(const FString& mapName); + UFUNCTION() + void EndLoadingScreen(UWorld* inLoadedWorld); + +private: + bool active = false; + bool first = true; +}; \ No newline at end of file diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/LoadingScreen/SLoadingScreenWidget.cpp b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/LoadingScreen/SLoadingScreenWidget.cpp new file mode 100644 index 0000000..169abcf --- /dev/null +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/LoadingScreen/SLoadingScreenWidget.cpp @@ -0,0 +1,97 @@ +// Oleg Petruny proprietary. + +#include "SLoadingScreenWidget.h" + +#include "Engine/Texture2D.h" +#include "Slate/DeferredCleanupSlateBrush.h" +#include "Widgets/Images/SImage.h" +#include "Widgets/Layout/SBorder.h" +#include "Widgets/Layout/SScaleBox.h" + +#include "CommonData.h" + +namespace +{ + constexpr auto startupImageA = TEXT("/Script/Engine.Texture2D'/Game/Movies/Images/T_StartupImageA.T_StartupImageA'"); + constexpr auto startupImageB = TEXT("/Script/Engine.Texture2D'/Game/Movies/Images/T_StartupImageB.T_StartupImageB'"); +} + +void SStartupImageWidget::Construct(const FArguments& inArgs) +{ + FSoftObjectPath assetA{ startupImageA }; + UTexture2D* imageA = Cast(assetA.TryLoad()); + check(imageA); // image A loading failed + FSoftObjectPath assetB{ startupImageB }; + UTexture2D* imageB = Cast(assetB.TryLoad()); + check(imageB); // image B loading failed + + // cache brushes into memory + imageABrush = FDeferredCleanupSlateBrush::CreateBrush(imageA); + imageBBrush = FDeferredCleanupSlateBrush::CreateBrush(imageB); + imageAWidget = SNew(SImage).Image(imageABrush->GetSlateBrush()).RenderOpacity(1.0f); + imageBWidget = SNew(SImage).Image(imageBBrush->GetSlateBrush()).RenderOpacity(0.0f); + + // construct widget + ChildSlot + [ + SNew(SBorder) + .HAlign(HAlign_Fill) + .VAlign(VAlign_Fill) + .Padding(0) + .BorderImage(UCommonData::KindaBlackColorBrush().Get()) + [ + SNew(SScaleBox) + .HAlign(HAlign_Fill) + .VAlign(VAlign_Fill) + .Stretch(EStretch::ScaleToFitY) + .StretchDirection(EStretchDirection::Both) + [ + SNew(SOverlay) + + SOverlay::Slot() + [ + imageAWidget.ToSharedRef() + ] + + SOverlay::Slot() + [ + imageBWidget.ToSharedRef() + ] + + SOverlay::Slot() + [ + SNew(STextBlock).Text(FText::FromString(TEXT("Loading..."))) + ] + ] + ] + ]; + + // start fading + isFading = true; + fadeDuration = inArgs._FadeDuration; + currentTime = 0.0f; + fadeTickHandle = FTSTicker::GetCoreTicker().AddTicker( + FTickerDelegate::CreateRaw(this, &SStartupImageWidget::FadeTick), + 0.0f); +} + +SStartupImageWidget::~SStartupImageWidget() +{ + isFading = false; + FTSTicker::GetCoreTicker().RemoveTicker(fadeTickHandle); +} + +bool SStartupImageWidget::FadeTick(float deltaTime) +{ + currentTime += deltaTime; + float fade = currentTime / fadeDuration; + + if(fade > 1.0f) + { + fade = 1.0f; + isFading = false; + FTSTicker::GetCoreTicker().RemoveTicker(fadeTickHandle); + } + + imageAWidget->SetRenderOpacity(1.0f - fade); + imageBWidget->SetRenderOpacity(fade); + + return isFading; +} diff --git a/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/LoadingScreen/SLoadingScreenWidget.h b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/LoadingScreen/SLoadingScreenWidget.h new file mode 100644 index 0000000..e344214 --- /dev/null +++ b/UnrealProject/Lost_Edge/Source/Lost_Edge/Private/LoadingScreen/SLoadingScreenWidget.h @@ -0,0 +1,35 @@ +// Oleg Petruny proprietary. + +#pragma once + +#include "Widgets/SCompoundWidget.h" + +struct FLoadingScreenWidgetArguments +{ + float fadeDuration = 2.0f; +}; + +class SStartupImageWidget : public SCompoundWidget +{ +public: + SLATE_BEGIN_ARGS(SStartupImageWidget) {} + SLATE_ARGUMENT(float, FadeDuration) + SLATE_END_ARGS() + + void Construct(const FArguments& inArgs); + + virtual ~SStartupImageWidget(); + +private: + bool FadeTick(float deltaTime); + + TSharedPtr imageABrush; + TSharedPtr imageBBrush; + TSharedPtr imageAWidget; + TSharedPtr imageBWidget; + + float fadeDuration; + float currentTime; + bool isFading = false; + FTSTicker::FDelegateHandle fadeTickHandle; +}; \ No newline at end of file