Code & git cleanup #6

Merged
oleg.petruny merged 15 commits from Documentation into master 2024-12-15 13:32:54 +00:00
108 changed files with 1188 additions and 948 deletions

4
.gitattributes vendored
View File

@ -1,4 +0,0 @@
ReleaseBuilds/** filter=lfs diff=lfs merge=lfs -text
Images/** filter=lfs diff=lfs merge=lfs -text
Fonts/** filter=lfs diff=lfs merge=lfs -text
Audio/** filter=lfs diff=lfs merge=lfs -text

1
Audio/.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
./** filter=lfs diff=lfs merge=lfs -text

3
Documentation/README.md Normal file
View File

@ -0,0 +1,3 @@
# Documentation
The always actual documentation is on [google drive](https://drive.google.com/drive/folders/1o40kh_8BgrMI3BzPyfNT0ZLG_5mrIjEy?usp=sharing). \
There is only a dump/backup.

Binary file not shown.

1
Fonts/.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
./** filter=lfs diff=lfs merge=lfs -text

1
Images/.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
./** filter=lfs diff=lfs merge=lfs -text

1
Models/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.blend1

View File

@ -1,15 +1,31 @@
# Repo structure # Repo structure
This repository contains all sources and data. The current unreal project is located in UnrealProject/Lost_Edge/. This repository contains all sources and data for project Lost_Edge excluding server and network deploy configs. \
Most of subdirectories represents individual modules and contains their own README.
# Documentation Lost_Edge/ \
Actualised documentation is on [google drive](https://drive.google.com/drive/folders/1o40kh_8BgrMI3BzPyfNT0ZLG_5mrIjEy?usp=sharing). ├─ [Audio/](Audio) ---> Audio data (e.g. music, sounds, dialogues) \
├─ [Documentation/](Documentation) ---> Documentation (e.g. game and level design) \
├─ [Fonts/](Fonts) ---> Fonts used in project \
├─ [Images/](Images) ---> Image data (e.g. textures, postures, logo) \
├─ [Models/](Models) ---> Models data (e.g. characters, decorations, foliages) \
├─ [ReleaseBuilds/](ReleaseBuilds) \
│ ├─ Legacy/ ---> Legacy build created as high school project \
│ └─ vX.X/ ---> Current builds of Lost_Edge (university project) \
├─ UnrealProject/ \
│ ├─ [Lost_Edge/](UnrealProject/Lost_Edge) ---> Current unreal project of Lost_Edge \
│ └─ Lost_Edge_Legacy/ ---> Legacy unreal project created as high school project \
└─[VoiceGenerator/](VoiceGenerator) ---> AI voice generation module
# How to compile # Building your own project copy
It's recommended to work in Unreal Engine 5.4 and to install Visual Studio with the necessary packages as it described in the [official documentation](https://dev.epicgames.com/documentation/en-us/unreal-engine/setting-up-visual-studio-development-environment-for-cplusplus-projects-in-unreal-engine) (recommended settings aren't needed). \ Building a copy of the game requires only [UnrealProject/LostEdge/](UnrealProject/Lost_Edge) directory. \
After repo cloning, the Visual Studio project files needs to be generated. It can be done in the explorer RMB context menu of file "UnrealProject/Lost_Edge/Lost_Edge.uproject". Or by typing "%UE5PATH%\Engine\Build\BatchFiles\GenerateProjectFiles.bat" "%REPOPATH%\UnrealProject\Lost_Edge\Lost_Edge.uproject". \ For that purposes you can download the directory as archive or do a sparse checkout via commands below.
After generating, "Lost_Edge.sln" can be opened and project can start building for the first time, which will fail. This is because of using OpenCV plugin that together with UnrealEngine implement their own "check()" function. This error can be used to determine that in the file "%UE5PATH%\Engine\Plugins\Runtime\OpenCV\Source\ThirdParty\OpenCV\include\opencv2\core\utility.hpp" it is necessary to comment out the warning macro on lines 52-54 and rename the function itself on line 957 to, for example, "checkcv()". - git clone --no-checkout https://pixelyfier.com/git/Pixelyfier/Lost_Edge.git
After this modification, the build should run fine and it is possible to open the project in UnrealEngine. - cd Lost_Edge/
- git sparse-checkout init
- git sparse-checkout set UnrealProject/Lost_Edge
- git checkout master
# Git lfs common issues # Git lfs common issues
The download can be sometimes too long which make git lfs drop the connection with error "LFS: Put "https://pixelyfier.com/git/Pixelyfier/Lost_Edge.git/info/lfs/objects/HASH": read tcp IP:PORT->pixelyfier.com:443: i/o timeout" \ The download can be sometimes too long which makes git lfs drop the connection with error \
`"LFS: Put "https://pixelyfier.com/git/Pixelyfier/Lost_Edge.git/info/lfs/objects/HASH": read tcp IP:PORT->pixelyfier.com:443: i/o timeout"`
- To fix this set local/global repo config `git config lfs.activitytimeout 240` - To fix this set local/global repo config `git config lfs.activitytimeout 240`

1
ReleaseBuilds/.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
./** filter=lfs diff=lfs merge=lfs -text

View File

@ -84,7 +84,7 @@ CommandletClass=Class'/Script/UnrealEd.WorldPartitionConvertCommandlet'
+ActiveGameNameRedirects=(OldGameName="TP_Blank",NewGameName="/Script/Lost_Edge") +ActiveGameNameRedirects=(OldGameName="TP_Blank",NewGameName="/Script/Lost_Edge")
+ActiveGameNameRedirects=(OldGameName="/Script/TP_Blank",NewGameName="/Script/Lost_Edge") +ActiveGameNameRedirects=(OldGameName="/Script/TP_Blank",NewGameName="/Script/Lost_Edge")
+ActiveClassRedirects=(OldClassName="TP_BlankGameModeBase",NewClassName="Lost_EdgeGameModeBase") +ActiveClassRedirects=(OldClassName="TP_BlankGameModeBase",NewClassName="Lost_EdgeGameModeBase")
GameUserSettingsClassName=/Script/Lost_Edge.CustomGameUserSettings GameUserSettingsClassName=/Script/Lost_Edge.CustomGameSettings
LevelScriptActorClassName=/Script/Lost_Edge.LevelBase LevelScriptActorClassName=/Script/Lost_Edge.LevelBase
[/Script/AndroidFileServerEditor.AndroidFileServerRuntimeSettings] [/Script/AndroidFileServerEditor.AndroidFileServerRuntimeSettings]

View File

@ -1,4 +1,4 @@
[/Script/Lost_Edge.CustomGameUserSettings] [/Script/Lost_Edge.CustomGameSettings]
bUseMotionBlur=False bUseMotionBlur=False
bShowFps=False bShowFps=False
bMouseInverted=False bMouseInverted=False

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,5 @@
# How to compile
It's recommended to work in Unreal Engine 5.4 and to install Visual Studio with the necessary packages as it described in the [official documentation](https://dev.epicgames.com/documentation/en-us/unreal-engine/setting-up-visual-studio-development-environment-for-cplusplus-projects-in-unreal-engine) (recommended settings aren't needed). \
After repo cloning, the Visual Studio project files needs to be generated. It can be done in the explorer RMB context menu of file "UnrealProject/Lost_Edge/Lost_Edge.uproject". Or by typing "%UE5PATH%\Engine\Build\BatchFiles\GenerateProjectFiles.bat" "%REPOPATH%\UnrealProject\Lost_Edge\Lost_Edge.uproject". \
After generating, "Lost_Edge.sln" can be opened and project can start building for the first time, which will fail. This is because of using OpenCV plugin that together with UnrealEngine implement their own "check()" function. This error can be used to determine that in the file "%UE5PATH%\Engine\Plugins\Runtime\OpenCV\Source\ThirdParty\OpenCV\include\opencv2\core\utility.hpp" it is necessary to comment out the warning macro on lines 52-54 and rename the function itself on line 957 to, for example, "checkcv()".
After this modification, the build should run fine and it is possible to open the project in UnrealEngine.

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "CameraModeBase.h" #include "CameraModeBase.h"
#include "Camera/CameraComponent.h" #include "Camera/CameraComponent.h"
@ -10,12 +9,16 @@
#include "InputMappingContext.h" #include "InputMappingContext.h"
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
#include "CustomGameInstanceBase.h" #include "CustomGameSettings.h"
#include "CustomGameUserSettings.h" #include "CustomPlayerController.h"
#include "MainGameModeBase.h" #include "MainGameModeBase.h"
ACameraModeBase::ACameraModeBase() ACameraModeBase::ACameraModeBase()
{ {
static ConstructorHelpers::FObjectFinder<UInputMappingContext> asset{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/IMC_CameraMode.IMC_CameraMode'") };
context = asset.Object;
ACustomPlayerController::AppendInputContext(context);
PrimaryActorTick.bCanEverTick = true; PrimaryActorTick.bCanEverTick = true;
} }
@ -25,29 +28,12 @@ void ACameraModeBase::BeginPlay()
auto world = GetWorld(); auto world = GetWorld();
//GetMovementComponent()->speed if(auto gameSettings = UCustomGameSettings::Get())
// GetCharacterMovement()->MaxWalkSpeed = moveSpeed; {
auto gameSettings = UCustomGameUserSettings::GetCustomGameUserSettings();
if(auto camera = FindComponentByClass<UCameraComponent>()) if(auto camera = FindComponentByClass<UCameraComponent>())
{ {
camera->PostProcessSettings.MotionBlurAmount = gameSettings->bUseMotionBlur ? 1.0f : 0.0f; camera->PostProcessSettings.MotionBlurAmount = gameSettings->bUseMotionBlur ? 1.0f : 0.0f;
} }
if(auto PC = Cast<APlayerController>(GetController()))
{
if(auto inputSubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer()))
{
if(auto GI = Cast<UCustomGameInstanceBase>(GetWorld()->GetGameInstance()))
{
inputSubsystem->ClearAllMappings();
for(auto& inputContext : GI->inputContexts)
{
inputSubsystem->AddMappingContext(inputContext.LoadSynchronous(), 0);
}
}
}
} }
} }
@ -66,13 +52,8 @@ void ACameraModeBase::SetupPlayerInputComponent(UInputComponent* PlayerInputComp
void ACameraModeBase::SwitchToPlayerPawn() void ACameraModeBase::SwitchToPlayerPawn()
{ {
if(auto gamemode_base = UGameplayStatics::GetGameMode(GetWorld())) if(auto gamemode = AMainGameModeBase::Get())
{
if(auto gamemode = Cast<AMainGameModeBase>(gamemode_base))
{
gamemode->SwitchCameraMode(); gamemode->SwitchCameraMode();
}
}
} }
void ACameraModeBase::ElevatePawn(float value) void ACameraModeBase::ElevatePawn(float value)

View File

@ -2,11 +2,13 @@
#pragma once #pragma once
#include "CoreMinimal.h"
#include "GameFramework/SpectatorPawn.h" #include "GameFramework/SpectatorPawn.h"
#include "CameraModeBase.generated.h" #include "CameraModeBase.generated.h"
/**
* Cheap copy of PlayerBase for level fly spectating purposes.
*/
UCLASS() UCLASS()
class ACameraModeBase : public ASpectatorPawn class ACameraModeBase : public ASpectatorPawn
{ {
@ -33,4 +35,8 @@ protected:
float moveSpeed = 200; float moveSpeed = 200;
UPROPERTY(EditDefaultsOnly) UPROPERTY(EditDefaultsOnly)
float runSpeedMultiplier = 4; float runSpeedMultiplier = 4;
private:
TSoftObjectPtr<class UInputMappingContext> context;
}; };

View File

@ -7,7 +7,7 @@
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
#include "UObject/Object.h" #include "UObject/Object.h"
#include "CustomGameInstanceBase.h" #include "CustomGameInstance.h"
#include "Levels/LevelBase.h" #include "Levels/LevelBase.h"
#include "PlayerBase.h" #include "PlayerBase.h"
@ -53,25 +53,6 @@ TArray<int32> UCommonFunctions::GetRandomIntArray(int32 size, int32 min, int32 m
ALevelBase* UCommonFunctions::GetCurrentLevelScript(UObject* obj)
{
if(auto world = obj->GetWorld())
if(auto level = world->GetCurrentLevel())
if(auto script = level->GetLevelScriptActor())
return Cast<ALevelBase>(script);
return nullptr;
}
APlayerBase* UCommonFunctions::GetPlayer(UObject* obj)
{
if(auto pc = UGameplayStatics::GetPlayerController(obj->GetWorld(), 0))
if(auto pawn = pc->GetPawn())
return Cast<APlayerBase>(pawn);
return nullptr;
}
namespace SlowMotion namespace SlowMotion
{ {
FTimerHandle timer; FTimerHandle timer;
@ -86,7 +67,7 @@ void UCommonFunctions::EnterSlowMotion(float duration)
SlowMotion::targetDilation = SlowMotion::slowDilation; SlowMotion::targetDilation = SlowMotion::slowDilation;
auto GI = UCustomGameInstanceBase::GetGameInstance(); auto GI = UCustomGameInstance::Get();
if(!GI) if(!GI)
return; return;
@ -101,7 +82,7 @@ void UCommonFunctions::ExitSlowMotion(float duration)
SlowMotion::targetDilation = SlowMotion::normalDilation; SlowMotion::targetDilation = SlowMotion::normalDilation;
auto GI = UCustomGameInstanceBase::GetGameInstance(); auto GI = UCustomGameInstance::Get();
if(!GI) if(!GI)
return; return;
@ -116,7 +97,7 @@ FWorldDilationChangedDelegate& UCommonFunctions::GetWorldDilationChangedDelegate
void UCommonFunctions::SlowMotionTick() void UCommonFunctions::SlowMotionTick()
{ {
const UWorld* world = UCustomGameInstanceBase::GetGameInstance()->GetWorld(); const UWorld* world = UCustomGameInstance::Get()->GetWorld();
const float currentDilation = UGameplayStatics::GetGlobalTimeDilation(world); const float currentDilation = UGameplayStatics::GetGlobalTimeDilation(world);
float newDilation = FMath::FInterpTo(currentDilation, SlowMotion::targetDilation, 1, SlowMotion::interpolationSpeed); float newDilation = FMath::FInterpTo(currentDilation, SlowMotion::targetDilation, 1, SlowMotion::interpolationSpeed);

View File

@ -2,34 +2,33 @@
#pragma once #pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h" #include "Kismet/BlueprintFunctionLibrary.h"
#include "CommonFunctions.generated.h" #include "CommonFunctions.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FWorldDilationChangedDelegate, float, newDilation); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FWorldDilationChangedDelegate, float, newDilation);
/**
* Collection of common/universal/without own scope/specific functions.
*/
UCLASS() UCLASS()
class UCommonFunctions : public UBlueprintFunctionLibrary class UCommonFunctions : public UBlueprintFunctionLibrary
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
/** Returns true if the object is UE class template (used for copy/archetype/meta system but not on the level) */
UFUNCTION(BlueprintPure)
static bool IsNonGameObject(class UObject* object); static bool IsNonGameObject(class UObject* object);
/** "Overload" of the built-in keys translator (to not build own engine copy) */
UFUNCTION(BlueprintPure)
static FText GetKeyDisplayName(struct FKey key); static FText GetKeyDisplayName(struct FKey key);
/** Recursively destroy actor and all its childs (the default Destroy doesn't have consistent behavior) */
UFUNCTION(BlueprintCallable, Category = Actor) UFUNCTION(BlueprintCallable, Category = Actor)
static void DestroyActorRecursively(class AActor* actor); static void DestroyActorRecursively(class AActor* actor);
UFUNCTION(BlueprintPure)
static TArray<int32> GetRandomIntArray(int32 size = 16, int32 min = 0, int32 max = 16);
UFUNCTION(BlueprintCallable, Category = Level)
static class ALevelBase* GetCurrentLevelScript(class UObject* obj);
UFUNCTION(BlueprintCallable, Category = Player)
static class APlayerBase* GetPlayer(class UObject* obj);
UFUNCTION(BlueprintCallable, Category = World) UFUNCTION(BlueprintCallable, Category = World)
@ -41,6 +40,10 @@ public:
static FWorldDilationChangedDelegate& GetWorldDilationChangedDelegate(); static FWorldDilationChangedDelegate& GetWorldDilationChangedDelegate();
UFUNCTION(BlueprintPure)
static TArray<int32> GetRandomIntArray(int32 size = 16, int32 min = 0, int32 max = 16);
template<typename T> template<typename T>
static TArray<T> ArrayDiff(const TArray<T>& a, const TArray<T>& b); static TArray<T> ArrayDiff(const TArray<T>& a, const TArray<T>& b);
template<typename T> template<typename T>

View File

@ -1,12 +1,12 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "ContentLoader.h" #include "ContentLoader.h"
#include "CommonFunctions.h"
#include "IPlatformFilePak.h" #include "IPlatformFilePak.h"
#include "Misc/FileHelper.h" #include "Misc/FileHelper.h"
#include "CommonFunctions.h"
#include <regex> #include <regex>
#include <string> #include <string>
#include <vector> #include <vector>

View File

@ -10,13 +10,16 @@
UENUM(BlueprintType) UENUM(BlueprintType)
enum class EContentDownloadMethod : uint8 enum class EContentDownloadMethod : uint8
{ {
ClearRandom = 0, ClearRandom = 0, //!< Always random from 0 to n
NonRepeatRandom, NonRepeatRandom, //!< Download the one that isn't downloaded in current runtime (Reset on full set)
RatingOftenRandom RatingOftenRandom //!< NonRepeatRandom combined with asset rating [WIP]
}; };
DECLARE_DYNAMIC_DELEGATE_OneParam(FContentDownloadedCallback, FString, pakFilePath); DECLARE_DYNAMIC_DELEGATE_OneParam(FContentDownloadedCallback, FString, pakFilePath);
/*
* High language wrapper for Paks(Assets) download and loading.
*/
UCLASS(BlueprintType) UCLASS(BlueprintType)
class UContentLoader : public UObject class UContentLoader : public UObject
{ {
@ -35,12 +38,18 @@ public:
protected: protected:
virtual void BeginDestroy() override; virtual void BeginDestroy() override;
/** Sends http get request */
void HttpGet(const FString& url, FHttpRequestCompleteDelegate requestCompleteCallback); void HttpGet(const FString& url, FHttpRequestCompleteDelegate requestCompleteCallback);
/** Parses assets html/json index */
TArray<FString> ParseDirectoryIndex(const TArray<uint8>& content, const FString& contentType); TArray<FString> ParseDirectoryIndex(const TArray<uint8>& content, const FString& contentType);
/** Selects item by desired method */
FString SelectContentByMethod(const TArray<FString>& content, const EContentDownloadMethod method); FString SelectContentByMethod(const TArray<FString>& content, const EContentDownloadMethod method);
/** Reads Pak content */
FString GetPakMountContent(const FString& pakFilePath, TArray<FString>* content = nullptr); FString GetPakMountContent(const FString& pakFilePath, TArray<FString>* content = nullptr);
/** Returns mount path to desired content item */
UClass* GetPakClass(const FString& pakContentPath); UClass* GetPakClass(const FString& pakContentPath);
/** Cache of already downloaded content at runtime (used by EContentDownloadMethod::NonRepeatRandom)*/
TArray<FString> downloadedContent; TArray<FString> downloadedContent;
}; };

View File

@ -0,0 +1,74 @@
// Oleg Petruny proprietary.
#include "CustomGameInstance.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetSystemLibrary.h"
#include "ContentLoader.h"
#include "Levels/LevelBase.h"
#include "PlayerBase.h"
#include "SaveData.h"
UCustomGameInstance* UCustomGameInstance::instance = nullptr;
void UCustomGameInstance::Init()
{
UGameInstance::Init();
instance = this;
contentLoader = NewObject<UContentLoader>(this);
saveData = Cast<USaveData>(UGameplayStatics::CreateSaveGameObject(USaveData::StaticClass()));
}
UCustomGameInstance* UCustomGameInstance::Get()
{
return instance;
}
UContentLoader* UCustomGameInstance::GetContentLoader()
{
if(auto GI = Get())
return GI->contentLoader;
return nullptr;
}
void UCustomGameInstance::SaveGame(FName checkpointName)
{
auto levelScript = ALevelBase::Get();
if(!levelScript)
return;
auto player = APlayerBase::Get();
if(!player)
return;
saveData->level = GetWorld()->GetFName();
saveData->state = levelScript->GetState();
saveData->checkpoint = checkpointName;
if(player->leftPocketItem)
saveData->playerLeftPocketItem = player->leftPocketItem->GetFName();
else
saveData->playerLeftPocketItem = FName(TEXT(""));
if(player->rightPocketItem)
saveData->playerRightPocketItem = player->rightPocketItem->GetFName();
else
saveData->playerRightPocketItem = FName(TEXT(""));
UGameplayStatics::SaveGameToSlot(saveData, TEXT("Save"), 0);
}
void UCustomGameInstance::LoadGame()
{
saveData = Cast<USaveData>(UGameplayStatics::LoadGameFromSlot(TEXT("Save"), 0));
if(!saveData)
return;
UGameplayStatics::OpenLevel(this, saveData->level);
}
void UCustomGameInstance::ExitGame()
{
UKismetSystemLibrary::QuitGame(GetWorld(), nullptr, EQuitPreference::Quit, true);
}

View File

@ -4,29 +4,29 @@
#include "Engine/GameInstance.h" #include "Engine/GameInstance.h"
#include "CustomGameInstanceBase.generated.h" #include "CustomGameInstance.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FLevelBeginnedDelegate, FName, levelName); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FLevelBeginnedDelegate, FName, levelName);
/**
* Expands basic UE game instance.
* Manages saves, handles content loader and can shutdown the game.
*/
UCLASS() UCLASS()
class UCustomGameInstanceBase : public UGameInstance class UCustomGameInstance : public UGameInstance
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
/** Instantiates content loader, dummy save data and applies settings */
virtual void Init() override; virtual void Init() override;
UFUNCTION(BlueprintPure) UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Custom Game Instance"))
static UCustomGameInstanceBase* GetGameInstance(); static UCustomGameInstance* Get();
UFUNCTION(BlueprintPure) UFUNCTION(BlueprintPure)
static class UContentLoader* GetContentLoader(); static class UContentLoader* GetContentLoader();
UFUNCTION(BlueprintCallable, Category = Settings)
void ApplyMouseSettings();
void AppendInteractableModificatorClass(TSubclassOf<class UInteractableModificator> modificator);
UFUNCTION(BlueprintCallable, Category = Save) UFUNCTION(BlueprintCallable, Category = Save)
void SaveGame(FName checkpointName); void SaveGame(FName checkpointName);
UFUNCTION(BlueprintCallable, Category = Save) UFUNCTION(BlueprintCallable, Category = Save)
@ -34,17 +34,11 @@ public:
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
void ExitGame(); void ExitGame();
static UCustomGameInstanceBase* instance; static UCustomGameInstance* instance;
/** Public delegate called by ALevelBase instance on instantiation */
FLevelBeginnedDelegate OnLevelBeginned; FLevelBeginnedDelegate OnLevelBeginned;
UPROPERTY(EditDefaultsOnly)
TSet<TSubclassOf<class UInteractableActivator>> interactionsActivators;
TSet<TSubclassOf<class UInteractableModificator>> interactionsModificators;
UPROPERTY(EditDefaultsOnly)
TSet<TSoftObjectPtr<class UInputMappingContext>> inputContexts;
UPROPERTY(VisibleAnywhere) UPROPERTY(VisibleAnywhere)
class USaveData* saveData = nullptr; class USaveData* saveData = nullptr;

View File

@ -1,149 +0,0 @@
// Oleg Petruny proprietary.
#include "CustomGameInstanceBase.h"
#include "EnhancedInputLibrary.h"
#include "EnhancedInputSubsystems.h"
#include "InputMappingContext.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetSystemLibrary.h"
#include "CommonFunctions.h"
#include "ContentLoader.h"
#include "CustomGameUserSettings.h"
#include "Interactable/Activators/InCameraInteractableActivator.h"
#include "Interactable/Activators/RaycastInteractableActivator.h"
#include "Interactable/Modificators/ActivateInteractableModificator.h"
#include "Interactable/Modificators/SawInteractableModificator.h"
#include "Levels/LevelBase.h"
#include "PlayerBase.h"
#include "SaveData.h"
UCustomGameInstanceBase* UCustomGameInstanceBase::instance = nullptr;
void UCustomGameInstanceBase::Init()
{
UGameInstance::Init();
instance = this;
contentLoader = NewObject<UContentLoader>(this);
interactionsActivators.Add(URaycastInteractableActivator::StaticClass());
interactionsActivators.Add(UInCameraInteractableActivator::StaticClass());
for(auto& modificator : interactionsModificators)
{
if(modificator.GetDefaultObject()->GetMappingContext())
{
inputContexts.Add(modificator.GetDefaultObject()->GetMappingContext());
}
}
ApplyMouseSettings();
saveData = Cast<USaveData>(UGameplayStatics::CreateSaveGameObject(USaveData::StaticClass()));
}
UCustomGameInstanceBase* UCustomGameInstanceBase::GetGameInstance()
{
return instance;
}
UContentLoader* UCustomGameInstanceBase::GetContentLoader()
{
if(auto GI = GetGameInstance())
return GI->contentLoader;
return nullptr;
}
void UCustomGameInstanceBase::ApplyMouseSettings()
{
if(auto gameSettings = UCustomGameUserSettings::GetCustomGameUserSettings())
{
for(auto& context : inputContexts)
{
if(!context.LoadSynchronous())
continue;
for(auto& mapping : context.LoadSynchronous()->GetMappings())
{
if(mapping.Key == EKeys::Mouse2D)
{
for(auto& modifier : mapping.Modifiers)
{
if(auto negate_modifier = Cast<UInputModifierNegate>(modifier))
{
negate_modifier->bY = !gameSettings->bMouseInverted;
}
if(auto scalar_modifier = Cast<UInputModifierScalar>(modifier))
{
scalar_modifier->Scalar = FVector{ gameSettings->GetMouseSensetivity() * 0.5 };
}
}
}
}
UEnhancedInputLibrary::RequestRebuildControlMappingsUsingContext(context.LoadSynchronous());
}
}
}
void UCustomGameInstanceBase::AppendInteractableModificatorClass(TSubclassOf<class UInteractableModificator> modificator)
{
bool alreadyPresent = false;
interactionsModificators.Add(modificator, &alreadyPresent);
if(!alreadyPresent)
{
if(auto IC = modificator.GetDefaultObject()->GetMappingContext())
{
inputContexts.Add(IC);
if(auto PC = UGameplayStatics::GetPlayerController(GetWorld(), 0))
{
if(auto inputSubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer()))
{
inputSubsystem->AddMappingContext(IC, 0);
}
}
}
}
}
void UCustomGameInstanceBase::SaveGame(FName checkpointName)
{
auto levelScript = UCommonFunctions::GetCurrentLevelScript(this);
if(!levelScript)
return;
auto player = UCommonFunctions::GetPlayer(this);
if(!player)
return;
saveData->level = GetWorld()->GetFName();
saveData->state = levelScript->GetState();
saveData->checkpoint = checkpointName;
if(player->leftPocketItem)
saveData->playerLeftPocketItem = player->leftPocketItem->GetFName();
else
saveData->playerLeftPocketItem = FName(TEXT(""));
if(player->rightPocketItem)
saveData->playerRightPocketItem = player->rightPocketItem->GetFName();
else
saveData->playerRightPocketItem = FName(TEXT(""));
UGameplayStatics::SaveGameToSlot(saveData, TEXT("Save"), 0);
}
void UCustomGameInstanceBase::LoadGame()
{
saveData = Cast<USaveData>(UGameplayStatics::LoadGameFromSlot(TEXT("Save"), 0));
if(!saveData)
return;
UGameplayStatics::OpenLevel(this, saveData->level);
}
void UCustomGameInstanceBase::ExitGame()
{
UKismetSystemLibrary::QuitGame(GetWorld(), nullptr, EQuitPreference::Quit, true);
}

View File

@ -0,0 +1,28 @@
// Oleg Petruny proprietary.
#include "CustomGameSettings.h"
#include "Kismet/GameplayStatics.h"
UCustomGameSettings::UCustomGameSettings(const FObjectInitializer& ObjectInitializer) :Super(ObjectInitializer)
{
bUseMotionBlur = false;
bShowFps = false;
bMouseInverted = false;
fMouseSensetivity = 1.0f;
}
UCustomGameSettings* UCustomGameSettings::Get()
{
return Cast<UCustomGameSettings>(UGameUserSettings::GetGameUserSettings());
}
void UCustomGameSettings::SetMouseSensetivity(float value)
{
fMouseSensetivity = FMath::Clamp(value, 0.1f, 2.0f);
}
float UCustomGameSettings::GetMouseSensetivity() const
{
return fMouseSensetivity;
}

View File

@ -0,0 +1,49 @@
// Oleg Petruny proprietary.
#pragma once
#include "GameFramework/GameUserSettings.h"
#include "CustomGameSettings.generated.h"
/**
* Manages custom game settings.
* Mouse sensetivity and inversion, motion blur usage, fps show.
*/
UCLASS(Config = Game, defaultconfig)
class UCustomGameSettings : public UGameUserSettings
{
GENERATED_UCLASS_BODY()
public:
// Is auto defined by UE but implementation is in cpp
//UCustomGameSettings(const FObjectInitializer& ObjectInitializer);
UFUNCTION(BlueprintPure, Category = Settings, meta = (DisplayName = "Get Custom Game Settings"))
static UCustomGameSettings* Get();
/**
* Sets mouse sensetivity multiplier
* @param value [0.1 - 2.0]
*/
UFUNCTION(BlueprintCallable, Category = Settings)
void SetMouseSensetivity(float value);
/** Returns mouse sensetivity multiplier in [0.1 - 2.0] */
UFUNCTION(BlueprintCallable, Category = Settings)
float GetMouseSensetivity() const;
UPROPERTY(Config, BlueprintReadWrite)
bool bUseMotionBlur;
UPROPERTY(Config, BlueprintReadWrite)
bool bShowFps;
UPROPERTY(Config, BlueprintReadWrite)
bool bMouseInverted;
protected:
UPROPERTY(Config)
float fMouseSensetivity;
};

View File

@ -1,29 +0,0 @@
// Oleg Petruny proprietary.
#include "CustomGameUserSettings.h"
#include "Kismet/GameplayStatics.h"
UCustomGameUserSettings::UCustomGameUserSettings(const FObjectInitializer& ObjectInitializer) :Super(ObjectInitializer)
{
bUseMotionBlur = false;
bShowFps = false;
bMouseInverted = false;
fMouseSensetivity = 1.0f;
}
UCustomGameUserSettings* UCustomGameUserSettings::GetCustomGameUserSettings()
{
return Cast<UCustomGameUserSettings>(UGameUserSettings::GetGameUserSettings());
}
void UCustomGameUserSettings::SetMouseSensetivity(float value)
{
fMouseSensetivity = FMath::Clamp(value, 0.1f, 2.0f);
}
float UCustomGameUserSettings::GetMouseSensetivity() const
{
return fMouseSensetivity;
}

View File

@ -1,41 +0,0 @@
// Oleg Petruny proprietary.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameUserSettings.h"
#include "CustomGameUserSettings.generated.h"
UCLASS()
class UCustomGameUserSettings : public UGameUserSettings
{
GENERATED_UCLASS_BODY()
public:
UFUNCTION(BlueprintCallable, Category = Settings)
static UCustomGameUserSettings* GetCustomGameUserSettings();
// Sets mouse sensetivity multiplier
// @param value [0.1 - 2.0]
UFUNCTION(BlueprintCallable, Category = Settings)
void SetMouseSensetivity(float value);
// Returns mouse sensetivity multiplier in [0.1 - 2.0]
UFUNCTION(BlueprintCallable, Category = Settings)
float GetMouseSensetivity() const;
UPROPERTY(Config, BlueprintReadWrite)
bool bUseMotionBlur;
UPROPERTY(Config, BlueprintReadWrite)
bool bShowFps;
UPROPERTY(Config, BlueprintReadWrite)
bool bMouseInverted;
protected:
UPROPERTY(Config)
float fMouseSensetivity;
};

View File

@ -0,0 +1,116 @@
// Oleg Petruny proprietary.
#include "CustomPlayerController.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputLibrary.h"
#include "EnhancedInputSubsystems.h"
#include "InputMappingContext.h"
#include "CustomGameInstance.h"
#include "CustomGameSettings.h"
ACustomPlayerController* ACustomPlayerController::instance = nullptr;
UEnhancedInputComponent* ACustomPlayerController::input = nullptr;
UEnhancedInputLocalPlayerSubsystem* ACustomPlayerController::subsystem = nullptr;
TSet<TSoftObjectPtr<UInputMappingContext>> ACustomPlayerController::contexts = {};
TSet<TSoftObjectPtr<UInputMappingContext>> ACustomPlayerController::contextsBeforeInit = {};
void ACustomPlayerController::AppendInputContext(TSoftObjectPtr<class UInputMappingContext> context)
{
if(!context.IsValid())
return;
if(!UCustomGameInstance::Get()) //game settings not initialized yet
{
contextsBeforeInit.Add(context);
return;
}
ApplyMouseSettings(context);
contexts.Add(context);
if(subsystem)
subsystem->AddMappingContext(context.LoadSynchronous(), 0);
}
void ACustomPlayerController::BeginPlay()
{
Super::BeginPlay();
instance = this;
for(auto& context : contextsBeforeInit)
{
ApplyMouseSettings(context);
contexts.Add(context);
}
contextsBeforeInit.Empty();
subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer());
if(subsystem)
{
subsystem->ClearAllMappings();
for(auto& inputContext : contexts)
subsystem->AddMappingContext(inputContext.LoadSynchronous(), 0);
}
input = Cast<UEnhancedInputComponent>(InputComponent);
if(input)
{
((UInputComponent*)input)->BindAction(TEXT("AnyKey"), IE_Pressed, this, &ACustomPlayerController::OnAnyKeyPressed);
((UInputComponent*)input)->BindAction(TEXT("AnyKey"), IE_Released, this, &ACustomPlayerController::OnAnyKeyReleased);
}
}
void ACustomPlayerController::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
instance = nullptr;
input = nullptr;
subsystem = nullptr;
Super::EndPlay(EndPlayReason);
}
void ACustomPlayerController::ApplyMouseSettings(TSoftObjectPtr<class UInputMappingContext>& context)
{
auto gameSettings = UCustomGameSettings::Get();
if(!gameSettings)
return;
if(!context.LoadSynchronous())
return;
for(auto& mapping : context.LoadSynchronous()->GetMappings())
{
if(mapping.Key != EKeys::Mouse2D)
continue;
for(auto& modifier : mapping.Modifiers)
{
if(gameSettings->bMouseInverted)
{
if(auto negate_modifier = Cast<UInputModifierNegate>(modifier))
{
negate_modifier->bY = !negate_modifier->bY;
continue;
}
}
if(auto scalar_modifier = Cast<UInputModifierScalar>(modifier))
scalar_modifier->Scalar = FVector{ gameSettings->GetMouseSensetivity() * 0.5 };
}
}
UEnhancedInputLibrary::RequestRebuildControlMappingsUsingContext(context.LoadSynchronous());
}
void ACustomPlayerController::OnAnyKeyPressed(FKey key)
{
if(onAnyKeyPressed.IsBound())
onAnyKeyPressed.Broadcast(key);
}
void ACustomPlayerController::OnAnyKeyReleased(FKey key)
{
if(onAnyKeyReleased.IsBound())
onAnyKeyReleased.Broadcast(key);
}

View File

@ -0,0 +1,52 @@
// Oleg Petruny proprietary.
#pragma once
#include "GameFramework/PlayerController.h"
#include "CustomPlayerController.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FPlayerAnyKeyPressedDelegate, FKey, key);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FPlayerAnyKeyReleasedDelegate, FKey, key);
/**
* De-facto wrapper/interface of all usefull shortcuts and automatization around input system.
* Append new input context here for auto init on BeginPlay and apply user input settings.
* Also, has delegates onAnyKeyPressed/Released.
*/
UCLASS()
class ACustomPlayerController : public APlayerController
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Custom Player Controller"))
static ACustomPlayerController* Get() { return instance; }
UFUNCTION(BlueprintPure)
static class UEnhancedInputComponent* GetInput() { return input; }
UFUNCTION(BlueprintPure)
static class UEnhancedInputLocalPlayerSubsystem* GetInputSubsystem() { return subsystem; }
UFUNCTION(BlueprintCallable)
static void AppendInputContext(TSoftObjectPtr<class UInputMappingContext> context);
FPlayerAnyKeyPressedDelegate onAnyKeyPressed;
FPlayerAnyKeyReleasedDelegate onAnyKeyReleased;
protected:
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
private:
static void ApplyMouseSettings(TSoftObjectPtr<class UInputMappingContext>& context);
void OnAnyKeyPressed(FKey key);
void OnAnyKeyReleased(FKey key);
static ACustomPlayerController* instance;
static class UEnhancedInputLocalPlayerSubsystem* subsystem;
static class UEnhancedInputComponent* input;
static TSet<TSoftObjectPtr<class UInputMappingContext>> contexts;
/** Contexts added before game instance fully initialized cannot apply game settings because not fully initialized game */
static TSet<TSoftObjectPtr<class UInputMappingContext>> contextsBeforeInit;
};

View File

@ -9,7 +9,7 @@
#include "LevelSequence.h" #include "LevelSequence.h"
#include "LevelSequencePlayer.h" #include "LevelSequencePlayer.h"
#include "CustomGameInstanceBase.h" #include "CustomPlayerController.h"
#include "MainGameModeBase.h" #include "MainGameModeBase.h"
#include "PlayerBase.h" #include "PlayerBase.h"
#include "Widgets/CutsceneSkipWidget.h" #include "Widgets/CutsceneSkipWidget.h"
@ -19,14 +19,8 @@
UCutsceneManager::UCutsceneManager() UCutsceneManager::UCutsceneManager()
{ {
static ConstructorHelpers::FObjectFinder<UInputMappingContext> asset{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/IMC_Cutscene.IMC_Cutscene'") }; static ConstructorHelpers::FObjectFinder<UInputMappingContext> asset{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/IMC_Cutscene.IMC_Cutscene'") };
_inputContext = asset.Object; context = asset.Object;
if(auto world = GetWorld()) ACustomPlayerController::AppendInputContext(context);
{
if(auto GI = Cast<UCustomGameInstanceBase>(world->GetGameInstance()))
{
GI->inputContexts.Add(_inputContext);
}
}
} }
void UCutsceneManager::EnqueueSequence(ULevelSequence* sequence, FCutsceneEndCallback endCallback) void UCutsceneManager::EnqueueSequence(ULevelSequence* sequence, FCutsceneEndCallback endCallback)
@ -34,106 +28,82 @@ void UCutsceneManager::EnqueueSequence(ULevelSequence* sequence, FCutsceneEndCal
if(!sequence) if(!sequence)
return; return;
FScopeLock lock1(&_sequencesLock); FScopeLock lock1(&sequencesLock);
FScopeLock lock2(&_callbacksLock); FScopeLock lock2(&callbacksLock);
if(_endCallbacks.IsEmpty()) // most first sequence, so widgets and binds don't exist OnFirstCutsceneInit();
{
if(auto PC = UGameplayStatics::GetPlayerController(GetWorld(), 0))
{
_lastPlayer = Cast<APlayerBase>(PC->GetPawn());
if(_lastPlayer)
{
_lastPlayer->LockPlayer({ .walk = true, .jump = true, .run = true, .interaction = true, .camera = true });
auto& mapping = _inputContext.LoadSynchronous()->GetMapping(0); nextSequences.Enqueue(sequence);
int32 handler1 = _lastPlayer->inputComponent->BindAction(mapping.Action, ETriggerEvent::Started, this, &UCutsceneManager::OnInputHold).GetHandle(); endCallbacks.Enqueue(endCallback);
int32 handler2 = _lastPlayer->inputComponent->BindAction(mapping.Action, ETriggerEvent::Completed, this, &UCutsceneManager::OnInputUnhold).GetHandle();
_handlers = { handler1, handler2 };
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->HideWidgets();
static FSkipCutsceneDelegate skipCutsceneDelegate;
if(!skipCutsceneDelegate.IsBound())
skipCutsceneDelegate.BindDynamic(this, &UCutsceneManager::SkipSequence);
WM->EnableCutsceneWidget(skipCutsceneDelegate);
}
}
}
}
_nextSequences.Enqueue(sequence);
_endCallbacks.Enqueue(endCallback);
PlayNextSequence(); PlayNextSequence();
} }
void UCutsceneManager::PlayNextSequence() void UCutsceneManager::PlayNextSequence()
{ {
if(_sequencePlayer) if(sequencePlayer)
{ {
if(_sequencePlayer->IsPlaying()) if(sequencePlayer->IsPlaying())
return; return;
else else
_sequencePlayer->MarkAsGarbage(); sequencePlayer->MarkAsGarbage();
} }
FScopeLock lock(&_sequencesLock); FScopeLock lock(&sequencesLock);
ULevelSequence* sequence; ULevelSequence* sequence;
_nextSequences.Dequeue(sequence); nextSequences.Dequeue(sequence);
_sequencePlayer = ULevelSequencePlayer::CreateLevelSequencePlayer(GetWorld(), sequence, FMovieSceneSequencePlaybackSettings{}, _sequencePlayerActor); sequencePlayer = ULevelSequencePlayer::CreateLevelSequencePlayer(GetWorld(), sequence, FMovieSceneSequencePlaybackSettings{}, sequencePlayerActor);
_sequencePlayer->OnStop.AddDynamic(this, &UCutsceneManager::OnSequenceEnd); sequencePlayer->OnStop.AddDynamic(this, &UCutsceneManager::OnSequenceEnd);
_sequencePlayer->Play(); sequencePlayer->Play();
} }
void UCutsceneManager::SkipSequence() void UCutsceneManager::SkipSequence()
{ {
if(!_sequencePlayer || !_sequencePlayer->IsPlaying()) if(!sequencePlayer || !sequencePlayer->IsPlaying())
return; return;
_lastlySkipped = true; lastlySkipped = true;
_sequencePlayer->GoToEndAndStop(); sequencePlayer->GoToEndAndStop();
} }
void UCutsceneManager::ClearQueue() void UCutsceneManager::ClearQueue()
{ {
FScopeLock lock1(&_sequencesLock); FScopeLock lock1(&sequencesLock);
FScopeLock lock2(&_callbacksLock); FScopeLock lock2(&callbacksLock);
if(!_nextSequences.IsEmpty()) if(!nextSequences.IsEmpty())
_nextSequences.Empty(); nextSequences.Empty();
if(!_endCallbacks.IsEmpty()) if(!endCallbacks.IsEmpty())
_endCallbacks.Empty(); endCallbacks.Empty();
} }
void UCutsceneManager::LockCallback(bool lock) void UCutsceneManager::LockCallback(bool lock)
{ {
_lockCallback = lock; lockCallback = lock;
} }
void UCutsceneManager::OnSequenceEnd() void UCutsceneManager::OnSequenceEnd()
{ {
if(_lockCallback) if(lockCallback)
return; return;
_sequencePlayer->MarkAsGarbage(); sequencePlayer->MarkAsGarbage();
_sequencePlayer = nullptr; sequencePlayer = nullptr;
FScopeLock lock(&_callbacksLock); FScopeLock lock(&callbacksLock);
FCutsceneEndCallback callback; FCutsceneEndCallback callback;
_endCallbacks.Dequeue(callback); endCallbacks.Dequeue(callback);
if(callback.IsBound()) if(callback.IsBound())
callback.Execute(); callback.Execute();
if(!_nextSequences.IsEmpty()) if(!nextSequences.IsEmpty())
{ {
PlayNextSequence(); PlayNextSequence();
if(_lastlySkipped) if(lastlySkipped)
{ {
_lastlySkipped = false; lastlySkipped = false;
if(_holding) if(holding)
{ {
OnInputHold(); OnInputHold();
} }
@ -147,36 +117,63 @@ void UCutsceneManager::OnSequenceEnd()
WM->ShowWidgets(); WM->ShowWidgets();
} }
if(_lastPlayer) if(lastPlayer)
{ {
_lastPlayer->UnlockPlayer({ .walk = true, .jump = true, .run = true, .interaction = true, .camera = true }); lastPlayer->UnlockPlayer({ .walk = true, .jump = true, .run = true, .interaction = true, .camera = true });
_lastPlayer->inputComponent->RemoveBindingByHandle(_handlers.Key); auto input = ACustomPlayerController::GetInput();
_lastPlayer->inputComponent->RemoveBindingByHandle(_handlers.Value); input->RemoveBindingByHandle(handlers.Key);
input->RemoveBindingByHandle(handlers.Value);
_lastPlayer = nullptr; lastPlayer = nullptr;
} }
_lastlySkipped = false; lastlySkipped = false;
_holding = false; holding = false;
}
void UCutsceneManager::OnFirstCutsceneInit() // most first sequence, so widgets and binds don't exist
{
if(!endCallbacks.IsEmpty())
return;
if(auto PC = UGameplayStatics::GetPlayerController(GetWorld(), 0))
{
lastPlayer = Cast<APlayerBase>(PC->GetPawn());
if(lastPlayer)
{
lastPlayer->LockPlayer({ .walk = true, .jump = true, .run = true, .interaction = true, .camera = true });
auto& mapping = context.LoadSynchronous()->GetMapping(0);
auto input = ACustomPlayerController::GetInput();
int32 handler1 = input->BindAction(mapping.Action, ETriggerEvent::Started, this, &UCutsceneManager::OnInputHold).GetHandle();
int32 handler2 = input->BindAction(mapping.Action, ETriggerEvent::Completed, this, &UCutsceneManager::OnInputUnhold).GetHandle();
handlers = { handler1, handler2 };
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->HideWidgets();
static FSkipCutsceneDelegate skipCutsceneDelegate;
if(!skipCutsceneDelegate.IsBound())
skipCutsceneDelegate.BindDynamic(this, &UCutsceneManager::SkipSequence);
WM->EnableCutsceneWidget(skipCutsceneDelegate);
}
}
}
} }
void UCutsceneManager::OnInputHold() void UCutsceneManager::OnInputHold()
{ {
_holding = true; holding = true;
if(auto WM = AMainGameModeBase::GetWidgetsManager()) if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->AnimateCutsceneWidget(EInputAnimatedWidgetAnimation::Hold); WM->AnimateCutsceneWidget(EInputAnimatedWidgetAnimation::Hold);
}
} }
void UCutsceneManager::OnInputUnhold() void UCutsceneManager::OnInputUnhold()
{ {
_holding = false; holding = false;
if(auto WM = AMainGameModeBase::GetWidgetsManager()) if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->AnimateCutsceneWidget(EInputAnimatedWidgetAnimation::Unhold); WM->AnimateCutsceneWidget(EInputAnimatedWidgetAnimation::Unhold);
}
} }

View File

@ -32,22 +32,23 @@ private:
void PlayNextSequence(); void PlayNextSequence();
UFUNCTION() UFUNCTION()
void OnSequenceEnd(); void OnSequenceEnd();
void OnFirstCutsceneInit();
void OnInputHold(); void OnInputHold();
void OnInputUnhold(); void OnInputUnhold();
class ULevelSequencePlayer* _sequencePlayer = nullptr; class ULevelSequencePlayer* sequencePlayer = nullptr;
class ALevelSequenceActor* _sequencePlayerActor = nullptr; class ALevelSequenceActor* sequencePlayerActor = nullptr;
TQueue<class ULevelSequence*> _nextSequences; TQueue<class ULevelSequence*> nextSequences;
FCriticalSection _sequencesLock; FCriticalSection sequencesLock;
TQueue<FCutsceneEndCallback> _endCallbacks; TQueue<FCutsceneEndCallback> endCallbacks;
FCriticalSection _callbacksLock; FCriticalSection callbacksLock;
class APlayerBase* _lastPlayer = nullptr; class APlayerBase* lastPlayer = nullptr;
TSoftObjectPtr<class UInputMappingContext> _inputContext; TSoftObjectPtr<class UInputMappingContext> context;
TPair<int32, int32> _handlers; TPair<int32, int32> handlers;
bool _lockCallback = false; bool lockCallback = false;
bool _lastlySkipped = false; bool lastlySkipped = false;
bool _holding = false; bool holding = false;
}; };

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "DialogueManager.h" #include "DialogueManager.h"
#include "Components/AudioComponent.h" #include "Components/AudioComponent.h"
@ -11,7 +10,7 @@
#include "Kismet/KismetMathLibrary.h" #include "Kismet/KismetMathLibrary.h"
#include "Sound/SoundWave.h" #include "Sound/SoundWave.h"
#include "CustomGameInstanceBase.h" #include "CustomPlayerController.h"
#include "MainGameModeBase.h" #include "MainGameModeBase.h"
#include "PlayerBase.h" #include "PlayerBase.h"
#include "Widgets/DialogueSkipWidget.h" #include "Widgets/DialogueSkipWidget.h"
@ -21,14 +20,8 @@
UDialogueManager::UDialogueManager() UDialogueManager::UDialogueManager()
{ {
static ConstructorHelpers::FObjectFinder<UInputMappingContext> asset{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/IMC_Dialogue.IMC_Dialogue'") }; static ConstructorHelpers::FObjectFinder<UInputMappingContext> asset{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/IMC_Dialogue.IMC_Dialogue'") };
_inputContext = asset.Object; context = asset.Object;
if(auto world = GetWorld()) ACustomPlayerController::AppendInputContext(context);
{
if(auto GI = Cast<UCustomGameInstanceBase>(world->GetGameInstance()))
{
GI->inputContexts.Add(_inputContext);
}
}
} }
void UDialogueManager::PlayDialogue(FDialogueEnqueProperties properties, FDialogueEndCallback endCallback) void UDialogueManager::PlayDialogue(FDialogueEnqueProperties properties, FDialogueEndCallback endCallback)
@ -49,32 +42,28 @@ void UDialogueManager::PlayDialogue(FDialogueEnqueProperties properties, FDialog
FTimerHandle timer; FTimerHandle timer;
int32 timerId; int32 timerId;
_timersLock.Lock(); timersLock.Lock();
timerId = _timers.Num(); timerId = timers.Num();
_timers.Add(timer); timers.Add(timer);
_timersLock.Unlock(); timersLock.Unlock();
UGameplayStatics::PlaySound2D(this, row->wave.LoadSynchronous()); UGameplayStatics::PlaySound2D(this, row->wave.LoadSynchronous());
if(auto WM = AMainGameModeBase::GetWidgetsManager()) if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->ShowDialogueWidget(*row); WM->ShowDialogueWidget(*row);
}
auto func = [properties = properties, auto func = [properties,
timerId = timerId, timerId,
_timersLock = &_timersLock, timersLock = &timersLock,
_timers = &_timers, timers = &timers,
endCallback = endCallback]() endCallback]()
{ {
FDialogueRow* row = reinterpret_cast<FDialogueRow*>(properties.dialogue.LoadSynchronous()->FindRowUnchecked(properties.rowName)); FDialogueRow* row = reinterpret_cast<FDialogueRow*>(properties.dialogue.LoadSynchronous()->FindRowUnchecked(properties.rowName));
if(auto WM = AMainGameModeBase::GetWidgetsManager()) if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->HideDialogueWidget(*row); WM->HideDialogueWidget(*row);
}
_timersLock->Lock(); timersLock->Lock();
_timers->RemoveAt(timerId); timers->RemoveAt(timerId);
_timersLock->Unlock(); timersLock->Unlock();
endCallback.Execute(); endCallback.Execute();
}; };
@ -88,51 +77,30 @@ void UDialogueManager::EnqueDialogue(FDialogueEnqueProperties properties, FDialo
if(!properties.dialogue.LoadSynchronous()) if(!properties.dialogue.LoadSynchronous())
return; return;
FScopeLock lock1(&_dialoguesLock); FScopeLock lock1(&dialoguesLock);
FScopeLock lock2(&_callbacksLock); FScopeLock lock2(&callbacksLock);
if(_endCallbacks.IsEmpty()) // most first dialogue, so widgets and binds don't exist OnFirstDialogueInit();
{
if(auto PC = UGameplayStatics::GetPlayerController(GetWorld(), 0))
{
_lastPlayer = Cast<APlayerBase>(PC->GetPawn());
if(_lastPlayer)
{
auto& mapping = _inputContext.LoadSynchronous()->GetMapping(0);
_inputHandler = _lastPlayer->inputComponent->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &UDialogueManager::OnInputPress).GetHandle();
if(auto WM = AMainGameModeBase::GetWidgetsManager()) nextDialogues.Enqueue(properties);
{ endCallbacks.Enqueue(endCallback);
static FDialogueSkipDelegate skipDialogueDelegate;
if(!skipDialogueDelegate.IsBound())
{
skipDialogueDelegate.BindDynamic(this, &UDialogueManager::SkipDialogue);
WM->SetInputDialogueWidget(mapping.Key, mapping.Action->ActionDescription, skipDialogueDelegate);
}
}
}
}
}
_nextDialogues.Enqueue(properties);
_endCallbacks.Enqueue(endCallback);
PlayNextDialogue(); PlayNextDialogue();
} }
void UDialogueManager::PlayNextDialogue() void UDialogueManager::PlayNextDialogue()
{ {
_dialoguesLock.Lock(); dialoguesLock.Lock();
auto properties = _nextDialogues.Peek(); auto properties = nextDialogues.Peek();
TArray<FName> rows = properties->dialogue.LoadSynchronous()->GetRowNames(); TArray<FName> rows = properties->dialogue.LoadSynchronous()->GetRowNames();
if(rows.Num() == 0) if(rows.Num() == 0)
{ {
FDialogueEndCallback callback; FDialogueEndCallback callback;
if(_endCallbacks.Dequeue(callback)) if(endCallbacks.Dequeue(callback))
callback.Execute(); callback.Execute();
_nextDialogues.Pop(); nextDialogues.Pop();
return; return;
} }
@ -146,23 +114,21 @@ void UDialogueManager::PlayNextDialogue()
if(!row) if(!row)
{ {
FDialogueEndCallback callback; FDialogueEndCallback callback;
_endCallbacks.Dequeue(callback); endCallbacks.Dequeue(callback);
callback.ExecuteIfBound(); callback.ExecuteIfBound();
_nextDialogues.Pop(); nextDialogues.Pop();
return; return;
} }
if(properties->playMode == EDialoguePlayMode::Sequential) if(properties->playMode == EDialoguePlayMode::Sequential
&& !properties->rowName.ToString().IsNumeric())
{ {
if(!properties->rowName.ToString().IsNumeric()) nextDialogues.Pop();
{
_nextDialogues.Pop();
FDialogueEndCallback callback; FDialogueEndCallback callback;
if(_endCallbacks.Dequeue(callback)) if(endCallbacks.Dequeue(callback))
callback.Execute(); callback.Execute();
return; return;
} }
}
if(row->wave.LoadSynchronous()) if(row->wave.LoadSynchronous())
leadDialogueAudio = UGameplayStatics::SpawnSound2D(this, row->wave.LoadSynchronous()); leadDialogueAudio = UGameplayStatics::SpawnSound2D(this, row->wave.LoadSynchronous());
@ -170,9 +136,7 @@ void UDialogueManager::PlayNextDialogue()
leadDialogueAudio = nullptr; leadDialogueAudio = nullptr;
if(auto WM = AMainGameModeBase::GetWidgetsManager()) if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->ShowDialogueWidget(*row); WM->ShowDialogueWidget(*row);
}
FTimerHandle timer; FTimerHandle timer;
int32 timerId; int32 timerId;
@ -180,27 +144,53 @@ void UDialogueManager::PlayNextDialogue()
const float duration = row->wave ? row->wave->GetDuration() : row->duration; const float duration = row->wave ? row->wave->GetDuration() : row->duration;
GetWorld()->GetTimerManager().SetTimer(timer, [&]() { OnDialogueEnd(); }, duration, false); GetWorld()->GetTimerManager().SetTimer(timer, [&]() { OnDialogueEnd(); }, duration, false);
_timersLock.Lock(); timersLock.Lock();
timerId = _timers.Num(); timerId = timers.Num();
_timers.Add(timer); timers.Add(timer);
_timersLock.Unlock(); timersLock.Unlock();
leadDialogueTimerId = timerId; leadDialogueTimerId = timerId;
leadDialogueProperties = properties; leadDialogueProperties = properties;
_dialoguesLock.Unlock(); dialoguesLock.Unlock();
}
void UDialogueManager::OnFirstDialogueInit() // most first dialogue, so widgets and binds don't exist
{
if(!endCallbacks.IsEmpty())
return;
if(auto PC = UGameplayStatics::GetPlayerController(GetWorld(), 0))
{
lastPlayer = Cast<APlayerBase>(PC->GetPawn());
if(lastPlayer)
{
auto& mapping = context.LoadSynchronous()->GetMapping(0);
inputHandler = ACustomPlayerController::GetInput()->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &UDialogueManager::OnInputPress).GetHandle();
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
static FDialogueSkipDelegate skipDialogueDelegate;
if(!skipDialogueDelegate.IsBound())
{
skipDialogueDelegate.BindDynamic(this, &UDialogueManager::SkipDialogue);
WM->SetInputDialogueWidget(mapping.Key, mapping.Action->ActionDescription, skipDialogueDelegate);
}
}
}
}
} }
void UDialogueManager::SkipDialogue() void UDialogueManager::SkipDialogue()
{ {
if(_timers.Num() == 0 || leadDialogueTimerId < 0) if(timers.Num() == 0 || leadDialogueTimerId < 0)
return; return;
_timersLock.Lock(); timersLock.Lock();
GetWorld()->GetTimerManager().ClearTimer(_timers[leadDialogueTimerId]); GetWorld()->GetTimerManager().ClearTimer(timers[leadDialogueTimerId]);
_timers.RemoveAt(leadDialogueTimerId); timers.RemoveAt(leadDialogueTimerId);
leadDialogueTimerId = -1; leadDialogueTimerId = -1;
_timersLock.Unlock(); timersLock.Unlock();
if(leadDialogueAudio) if(leadDialogueAudio)
leadDialogueAudio->Stop(); leadDialogueAudio->Stop();
@ -210,25 +200,25 @@ void UDialogueManager::SkipDialogue()
void UDialogueManager::ClearQueue() void UDialogueManager::ClearQueue()
{ {
if(!_nextDialogues.IsEmpty()) if(!nextDialogues.IsEmpty())
_nextDialogues.Empty(); nextDialogues.Empty();
if(!_endCallbacks.IsEmpty()) if(!endCallbacks.IsEmpty())
_endCallbacks.Empty(); endCallbacks.Empty();
} }
void UDialogueManager::LockCallback(bool lock) void UDialogueManager::LockCallback(bool lock)
{ {
_lockCallback = lock; lockCallback = lock;
} }
void UDialogueManager::BeginDestroy() void UDialogueManager::BeginDestroy()
{ {
if(auto world = GetWorld()) if(auto world = GetWorld())
{ {
_timersLock.Lock(); timersLock.Lock();
for(auto& timer : _timers) for(auto& timer : timers)
world->GetTimerManager().ClearTimer(timer); world->GetTimerManager().ClearTimer(timer);
_timersLock.Unlock(); timersLock.Unlock();
} }
UObject::BeginDestroy(); UObject::BeginDestroy();
@ -236,41 +226,35 @@ void UDialogueManager::BeginDestroy()
void UDialogueManager::OnDialogueEnd() void UDialogueManager::OnDialogueEnd()
{ {
_dialoguesLock.Lock(); dialoguesLock.Lock();
FDialogueRow* row = reinterpret_cast<FDialogueRow*>(leadDialogueProperties->dialogue.LoadSynchronous()->FindRowUnchecked(leadDialogueProperties->rowName)); FDialogueRow* row = reinterpret_cast<FDialogueRow*>(leadDialogueProperties->dialogue.LoadSynchronous()->FindRowUnchecked(leadDialogueProperties->rowName));
if(auto WM = AMainGameModeBase::GetWidgetsManager()) if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->HideDialogueWidget(*row); WM->HideDialogueWidget(*row);
}
if(leadDialogueProperties->playMode == EDialoguePlayMode::Sequential) if(leadDialogueProperties->playMode == EDialoguePlayMode::Sequential
{ && leadDialogueProperties->rowName.ToString().IsNumeric())
if(leadDialogueProperties->rowName.ToString().IsNumeric())
{ {
leadDialogueProperties->rowName = FName(FString::FromInt(FCString::Atoi(*(leadDialogueProperties->rowName.ToString())) + 1)); leadDialogueProperties->rowName = FName(FString::FromInt(FCString::Atoi(*(leadDialogueProperties->rowName.ToString())) + 1));
} }
}
_dialoguesLock.Unlock(); dialoguesLock.Unlock();
if(!_endCallbacks.IsEmpty()) if(!endCallbacks.IsEmpty())
PlayNextDialogue(); PlayNextDialogue();
_dialoguesLock.Lock(); dialoguesLock.Lock();
if(_endCallbacks.IsEmpty() && _lastPlayer) if(endCallbacks.IsEmpty() && lastPlayer)
{ {
_lastPlayer->inputComponent->RemoveBindingByHandle(_inputHandler); ACustomPlayerController::GetInput()->RemoveBindingByHandle(inputHandler);
_lastPlayer = nullptr; lastPlayer = nullptr;
} }
_dialoguesLock.Unlock(); dialoguesLock.Unlock();
} }
void UDialogueManager::OnInputPress() void UDialogueManager::OnInputPress()
{ {
if(auto WM = AMainGameModeBase::GetWidgetsManager()) if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->AnimateDialogueWidget(EInputAnimatedWidgetAnimation::Click); WM->AnimateDialogueWidget(EInputAnimatedWidgetAnimation::Click);
}
} }

View File

@ -68,7 +68,7 @@ class UDialogueManager : public UObject
public: public:
UDialogueManager(); UDialogueManager();
// Ignores play mode and force pushing dialogue /** Ignores play mode and force pushing dialogue */
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
void PlayDialogue(FDialogueEnqueProperties properties, FDialogueEndCallback endCallback); void PlayDialogue(FDialogueEnqueProperties properties, FDialogueEndCallback endCallback);
@ -89,26 +89,28 @@ protected:
private: private:
void PlayNextDialogue(); void PlayNextDialogue();
void OnFirstDialogueInit();
UFUNCTION() UFUNCTION()
void OnDialogueEnd(); void OnDialogueEnd();
void OnInputPress(); void OnInputPress();
TQueue<FDialogueEnqueProperties> _nextDialogues; TQueue<FDialogueEnqueProperties> nextDialogues;
FCriticalSection _dialoguesLock; FCriticalSection dialoguesLock;
TQueue<FDialogueEndCallback> _endCallbacks; TQueue<FDialogueEndCallback> endCallbacks;
FCriticalSection _callbacksLock; FCriticalSection callbacksLock;
TArray<FTimerHandle> _timers; TArray<FTimerHandle> timers;
FCriticalSection _timersLock; FCriticalSection timersLock;
int32 leadDialogueTimerId = -1; int32 leadDialogueTimerId = -1;
FDialogueEnqueProperties* leadDialogueProperties; FDialogueEnqueProperties* leadDialogueProperties;
class UAudioComponent* leadDialogueAudio; class UAudioComponent* leadDialogueAudio;
class APlayerBase* _lastPlayer = nullptr; class APlayerBase* lastPlayer = nullptr;
TSoftObjectPtr<class UInputMappingContext> _inputContext; TSoftObjectPtr<class UInputMappingContext> context;
int32 _inputHandler; int32 inputHandler;
bool _lockCallback = false; bool lockCallback = false;
}; };

View File

@ -1,9 +1,9 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "InCameraInteractableActivator.h" #include "InCameraInteractableActivator.h"
#include "CommonFunctions.h" #include "CommonFunctions.h"
#include "Interactable/Interactable.h"
#include "InteractableScreenCapturer.h" #include "InteractableScreenCapturer.h"
UInCameraInteractableActivator::UInCameraInteractableActivator(const FObjectInitializer& ObjectInitializer) UInCameraInteractableActivator::UInCameraInteractableActivator(const FObjectInitializer& ObjectInitializer)
@ -20,10 +20,10 @@ UInCameraInteractableActivator::UInCameraInteractableActivator(const FObjectInit
activatorType = EActivatorType::Saw; activatorType = EActivatorType::Saw;
scanDistance = 7000; scanDistance = 7000;
_capturer = CreateDefaultSubobject<UInteractableScreenCapturer>(TEXT("UInCameraInteractableActivator_UInteractableScreenCapturer")); capturer = CreateDefaultSubobject<UInteractableScreenCapturer>(TEXT("UInCameraInteractableActivator_UInteractableScreenCapturer"));
_capturer->interactableInScreenDelegate.BindUObject(this, &UInCameraInteractableActivator::NewSeenInteractable_Implementation); capturer->interactableInScreenDelegate.BindUObject(this, &UInCameraInteractableActivator::NewSeenInteractable);
_capturer->SetupAttachment(this); capturer->SetupAttachment(this);
_capturer->scanDistance = scanDistance; capturer->scanDistance = scanDistance;
PrimaryComponentTick.bCanEverTick = true; PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.bStartWithTickEnabled = false; PrimaryComponentTick.bStartWithTickEnabled = false;
@ -31,27 +31,28 @@ UInCameraInteractableActivator::UInCameraInteractableActivator(const FObjectInit
void UInCameraInteractableActivator::OnRegister() void UInCameraInteractableActivator::OnRegister()
{ {
UInteractableActivator::OnRegister(); Super::OnRegister();
_capturer->RegisterComponent(); capturer->RegisterComponent();
_capturer->Activate(); capturer->Activate();
} }
void UInCameraInteractableActivator::NewSeenInteractable_Implementation(AInteractable* interactable) void UInCameraInteractableActivator::NewSeenInteractable(AInteractable* interactable)
{ {
_interactablesToActivate.Enqueue(interactable); interactablesToActivate.Enqueue(interactable);
SetComponentTickEnabled(true); SetComponentTickEnabled(true);
} }
void UInCameraInteractableActivator::Scan_Implementation() void UInCameraInteractableActivator::Scan_Implementation()
{ {
SetComponentTickEnabled(false); SetComponentTickEnabled(false);
while(!_interactablesToActivate.IsEmpty()) while(!interactablesToActivate.IsEmpty())
{ {
AInteractable* interactable; AInteractable* interactable;
_interactablesToActivate.Dequeue(interactable); interactablesToActivate.Dequeue(interactable);
if(interactableActivatedDelegate.IsBound()) if(interactableActivatedDelegate.IsBound())
{ {
interactableActivatedDelegate.Execute(interactable, activatorType); interactableActivatedDelegate.Execute(interactable, activatorType);
OnNewSeenInteractable(interactable);
} }
} }
} }

View File

@ -2,13 +2,14 @@
#pragma once #pragma once
#include "CoreMinimal.h"
#include "InteractableActivator.h" #include "InteractableActivator.h"
#include "InCameraInteractableActivator.generated.h" #include "InCameraInteractableActivator.generated.h"
UCLASS(Blueprintable, BlueprintType) /**
* Activates interactable only once if is in a camera view
*/
UCLASS(Blueprintable, BlueprintType, ClassGroup = InteractableActivator, meta = (BlueprintSpawnableComponent, ShortTooltip = "Activates interactable only once if is in a camera view"), MinimalAPI)
class UInCameraInteractableActivator : public UInteractableActivator class UInCameraInteractableActivator : public UInteractableActivator
{ {
GENERATED_BODY() GENERATED_BODY()
@ -19,14 +20,30 @@ public:
protected: protected:
virtual void OnRegister() override; virtual void OnRegister() override;
virtual bool AutoInstantiateInPlayer() override { return true; }
/**
* Scan is performed independently by _capturer member object.
* This implementation just activates interactables in the game thread.
*/
virtual void Scan_Implementation() override; virtual void Scan_Implementation() override;
UFUNCTION(BlueprintNativeEvent, BlueprintCallable) /**
LOST_EDGE_API void NewSeenInteractable(class AInteractable* interactable); * Thread safe enques interactable for activation in the next game tick
virtual void NewSeenInteractable_Implementation(class AInteractable* interactable); * @param interactable .. interactable to activate
*/
UFUNCTION(BlueprintCallable)
void NewSeenInteractable(class AInteractable* interactable);
/**
* Called after interactable activation
* @param interactable .. interactable activated
*/
UFUNCTION(BlueprintImplementableEvent)
void OnNewSeenInteractable(class AInteractable* interactable);
private: private:
UPROPERTY() UPROPERTY()
class UInteractableScreenCapturer* _capturer; class UInteractableScreenCapturer* capturer;
TQueue<class AInteractable*> _interactablesToActivate; TQueue<class AInteractable*> interactablesToActivate;
}; };

View File

@ -1,19 +1,23 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "InteractableActivator.h" #include "InteractableActivator.h"
#include "Engine/CollisionProfile.h" #include "Engine/CollisionProfile.h"
#include "Interactable/Interactable.h"
#include "PlayerBase.h" #include "PlayerBase.h"
UInteractableActivator::UInteractableActivator(const FObjectInitializer& ObjectInitializer) UInteractableActivator::UInteractableActivator(const FObjectInitializer& ObjectInitializer)
: USceneComponent(ObjectInitializer) : USceneComponent(ObjectInitializer)
{ {
if(HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject)) if(GetClass() != UInteractableActivator::StaticClass())
{ {
return; AInteractable::AppendActivatorClass(GetClass());
} }
if(HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))
return;
world = GetWorld(); world = GetWorld();
player = Cast<APlayerBase>(GetOwner()); player = Cast<APlayerBase>(GetOwner());

View File

@ -3,7 +3,6 @@
#pragma once #pragma once
#include "Components/SceneComponent.h" #include "Components/SceneComponent.h"
#include "CoreMinimal.h"
#include "Interactable/Interactable.h" #include "Interactable/Interactable.h"
@ -12,15 +11,22 @@
DECLARE_DELEGATE_TwoParams(FInteractableActivated, AInteractable*, EActivatorType); DECLARE_DELEGATE_TwoParams(FInteractableActivated, AInteractable*, EActivatorType);
DECLARE_DELEGATE_TwoParams(FInteractableDeactivated, AInteractable*, EActivatorType); DECLARE_DELEGATE_TwoParams(FInteractableDeactivated, AInteractable*, EActivatorType);
UCLASS(Abstract, Blueprintable, BlueprintType) /**
* Activates interactable based on type
*/
UCLASS(Abstract, Blueprintable, BlueprintType, ClassGroup = InteractableActivator, meta = (ShortTooltip = "Activates interactable based on type"), MinimalAPI)
class UInteractableActivator : public USceneComponent class UInteractableActivator : public USceneComponent
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
/** Append itself to CustomGameInstance modificators registry */
UInteractableActivator(const FObjectInitializer& ObjectInitializer); UInteractableActivator(const FObjectInitializer& ObjectInitializer);
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
virtual bool AutoInstantiateInPlayer() { return false; }
/** Resets activator state forcing to rescan */
UFUNCTION(BlueprintNativeEvent, BlueprintCallable) UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
LOST_EDGE_API void Rescan(); LOST_EDGE_API void Rescan();
virtual void Rescan_Implementation() {} virtual void Rescan_Implementation() {}
@ -29,6 +35,7 @@ public:
FInteractableActivated interactableDeactivatedDelegate; FInteractableActivated interactableDeactivatedDelegate;
protected: protected:
/** Activator scan function in game thread tick */
UFUNCTION(BlueprintNativeEvent, BlueprintCallable) UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
LOST_EDGE_API void Scan(); LOST_EDGE_API void Scan();
virtual void Scan_Implementation() PURE_VIRTUAL(UInteractableActivator::Scan_Implementation, ); virtual void Scan_Implementation() PURE_VIRTUAL(UInteractableActivator::Scan_Implementation, );

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "InteractableScreenCapturer.h" #include "InteractableScreenCapturer.h"
#include "Engine/Texture.h" #include "Engine/Texture.h"
@ -16,9 +15,12 @@
#include "Interactable/Interactable.h" #include "Interactable/Interactable.h"
#include "InteractableScreenCapturerBitMapCS.h" #include "InteractableScreenCapturerBitMapCS.h"
constexpr float tickInterval = 1.0f / 5; namespace
constexpr float textureWidth = 1280 / 2; {
constexpr float textureHeight = 720 / 2; constexpr float tickInterval = 1.0f / 5;
constexpr float textureWidth = 1280 / 2;
constexpr float textureHeight = 720 / 2;
}
UInteractableScreenCapturer::UInteractableScreenCapturer(const FObjectInitializer& ObjectInitializer) UInteractableScreenCapturer::UInteractableScreenCapturer(const FObjectInitializer& ObjectInitializer)
: USceneCaptureComponent2D(ObjectInitializer) : USceneCaptureComponent2D(ObjectInitializer)
@ -85,7 +87,7 @@ void UInteractableScreenCapturer::TickComponent(float DeltaTime, enum ELevelTick
{ {
USceneCaptureComponent2D::TickComponent(DeltaTime, TickType, ThisTickFunction); USceneCaptureComponent2D::TickComponent(DeltaTime, TickType, ThisTickFunction);
CaptureScene(); CaptureScene();
GetCameraView(DeltaTime, _view); GetCameraView(DeltaTime, view);
Process(); Process();
} }
break; break;
@ -104,7 +106,7 @@ void UInteractableScreenCapturer::Process()
[ [
capture = TextureTarget->GetResource()->TextureRHI, capture = TextureTarget->GetResource()->TextureRHI,
world = GetWorld(), world = GetWorld(),
view = _view, view = view,
//output = _output->GetResource()->TextureRHI, //output = _output->GetResource()->TextureRHI,
this this
] ]
@ -262,6 +264,7 @@ void UInteractableScreenCapturer::Process()
AsyncTask(ENamedThreads::GameThread, [=, this]() AsyncTask(ENamedThreads::GameThread, [=, this]()
{ {
interactableInScreenDelegate.Execute(interactable); interactableInScreenDelegate.Execute(interactable);
OnInteractableInScreen(interactable);
}); });
} }
} }

View File

@ -9,7 +9,10 @@
DECLARE_DELEGATE_OneParam(FInteractableInScreen, class AInteractable*); DECLARE_DELEGATE_OneParam(FInteractableInScreen, class AInteractable*);
UCLASS(hidecategories = (Collision, Object, Physics, SceneComponent), ClassGroup = Rendering, editinlinenew, meta = (BlueprintSpawnableComponent), MinimalAPI) /**
* Notifies only once about interactable is in a camera view
*/
UCLASS(BlueprintType, hidecategories = (Collision, Object, Physics, SceneComponent), ClassGroup = Rendering, editinlinenew, meta = (BlueprintSpawnableComponent, ShortTooltip = "Notifies only once about interactable is in a camera view"), MinimalAPI)
class UInteractableScreenCapturer : public USceneCaptureComponent2D class UInteractableScreenCapturer : public USceneCaptureComponent2D
{ {
GENERATED_BODY() GENERATED_BODY()
@ -19,15 +22,18 @@ public:
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
FInteractableInScreen interactableInScreenDelegate; FInteractableInScreen interactableInScreenDelegate;
UFUNCTION(BlueprintImplementableEvent)
void OnInteractableInScreen(class AInteractable* interactable);
UPROPERTY(EditAnywhere) UPROPERTY(EditAnywhere)
float scanDistance = 7000; float scanDistance = 7000;
protected: protected:
/** Enques render thread task to find obect on screen */
void Process(); void Process();
private: private:
FMinimalViewInfo _view; FMinimalViewInfo view; //!< Camera view cache
TSet<class AInteractable*> _sawInteractables; TSet<class AInteractable*> _sawInteractables;
//class UTextureRenderTarget2D* _output; //class UTextureRenderTarget2D* _output;
}; };

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "RaycastInteractableActivator.h" #include "RaycastInteractableActivator.h"
#include "DrawDebugHelpers.h" #include "DrawDebugHelpers.h"
@ -14,12 +13,12 @@ URaycastInteractableActivator::URaycastInteractableActivator(const FObjectInitia
void URaycastInteractableActivator::Rescan_Implementation() void URaycastInteractableActivator::Rescan_Implementation()
{ {
_last = nullptr; lastInteractable = nullptr;
} }
void URaycastInteractableActivator::Scan_Implementation() void URaycastInteractableActivator::Scan_Implementation()
{ {
FHitResult result{}; FHitResult result;
FVector startLocation = GetComponentLocation(); FVector startLocation = GetComponentLocation();
FVector endLocation = startLocation + (GetComponentRotation().Vector() * scanDistance); FVector endLocation = startLocation + (GetComponentRotation().Vector() * scanDistance);
@ -32,17 +31,17 @@ void URaycastInteractableActivator::Scan_Implementation()
if(result.bBlockingHit) if(result.bBlockingHit)
{ {
if(_last != result.GetActor()) if(lastInteractable != result.GetActor())
{ {
if(_last) if(lastInteractable)
{ {
interactableDeactivatedDelegate.Execute(_last, activatorType); interactableDeactivatedDelegate.Execute(lastInteractable, activatorType);
_last = nullptr; lastInteractable = nullptr;
} }
_activated = true; activated = true;
if(auto interactable = Cast<AInteractable>(result.GetActor())) if(auto interactable = Cast<AInteractable>(result.GetActor()))
{ {
_last = interactable; lastInteractable = interactable;
if(interactableActivatedDelegate.IsBound()) if(interactableActivatedDelegate.IsBound())
{ {
interactableActivatedDelegate.Execute(interactable, activatorType); interactableActivatedDelegate.Execute(interactable, activatorType);
@ -56,18 +55,18 @@ void URaycastInteractableActivator::Scan_Implementation()
} }
else else
{ {
if(_activated) if(activated)
{ {
if(interactableDeactivatedDelegate.IsBound()) if(interactableDeactivatedDelegate.IsBound())
{ {
interactableDeactivatedDelegate.Execute(_last, activatorType); interactableDeactivatedDelegate.Execute(lastInteractable, activatorType);
} }
_activated = false; activated = false;
_last = nullptr; lastInteractable = nullptr;
} }
#ifdef INTERACTABLE_ACTIVATOR_DEBUG #ifdef INTERACTABLE_ACTIVATOR_DEBUG
DrawDebugLine(GetWorld(), startLocation, endLocation, FColor::Red, false, PrimaryComponentTick.TickInterval, 10, 0.1f); DrawDebugLine(GetWorld(), startLocation, endLocation, FColor::Red, false, PrimaryComponentTick.TickInterval, 10, 0.1f);
#endif // INTERACTABLE_ACTIVATOR_DEBUG #endif // INTERACTABLE_ACTIVATOR_DEBUG
} }
} }

View File

@ -2,12 +2,14 @@
#pragma once #pragma once
#include "CoreMinimal.h"
#include "InteractableActivator.h" #include "InteractableActivator.h"
#include "RaycastInteractableActivator.generated.h" #include "RaycastInteractableActivator.generated.h"
UCLASS(Blueprintable, BlueprintType) /**
* Activates interactable with a single raycast from a camera center
*/
UCLASS(Blueprintable, BlueprintType, ClassGroup = InteractableActivator, meta = (BlueprintSpawnableComponent, ShortTooltip = "Activates interactable with a single raycast from a camera center"), MinimalAPI)
class URaycastInteractableActivator : public UInteractableActivator class URaycastInteractableActivator : public UInteractableActivator
{ {
GENERATED_BODY() GENERATED_BODY()
@ -15,12 +17,14 @@ class URaycastInteractableActivator : public UInteractableActivator
public: public:
URaycastInteractableActivator(const FObjectInitializer& ObjectInitializer); URaycastInteractableActivator(const FObjectInitializer& ObjectInitializer);
virtual bool AutoInstantiateInPlayer() override { return true; }
virtual void Rescan_Implementation() override; virtual void Rescan_Implementation() override;
protected: protected:
virtual void Scan_Implementation() override; virtual void Scan_Implementation() override;
private: private:
class AInteractable* _last = nullptr; class AInteractable* lastInteractable = nullptr;
bool _activated = false; bool activated = false;
}; };

View File

@ -1,15 +1,38 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "Interactable.h" #include "Interactable.h"
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
#include "Activators/InteractableActivator.h"
#include "CustomPlayerController.h"
#include "MainGameModeBase.h" #include "MainGameModeBase.h"
#include "Modificators/InteractableModificator.h" #include "Modificators/InteractableModificator.h"
#include "PlayerBase.h" #include "PlayerBase.h"
#include "Widgets/WidgetsManager.h" #include "Widgets/WidgetsManager.h"
TSet<TSubclassOf<class UInteractableActivator>> AInteractable::interactionActivators = {};
TSet<TSubclassOf<class UInteractableModificator>> AInteractable::interactionModificators = {};
void AInteractable::AppendActivatorClass(TSubclassOf<class UInteractableActivator> activator)
{
if(interactionActivators.Contains(activator))
return;
interactionActivators.Add(activator);
}
void AInteractable::AppendModificatorClass(TSubclassOf<class UInteractableModificator> modificator)
{
if(interactionModificators.Contains(modificator))
return;
interactionModificators.Add(modificator);
auto IC = modificator.GetDefaultObject()->GetMappingContext();
ACustomPlayerController::AppendInputContext(IC);
}
int32 AInteractable::GetActivatedFlags() int32 AInteractable::GetActivatedFlags()
{ {
return activated; return activated;
@ -86,13 +109,13 @@ void AInteractable::EndPlay(const EEndPlayReason::Type EndPlayReason)
if(activated) if(activated)
{ {
activationLockers.Empty(); activationLockers.Empty();
_Deactivate(static_cast<EActivatorType>(activated)); Deactivate(static_cast<EActivatorType>(activated));
} }
Super::EndPlay(EndPlayReason); Super::EndPlay(EndPlayReason);
} }
void AInteractable::_Activate(EActivatorType type) void AInteractable::Activate(EActivatorType type)
{ {
#ifdef INTERACTABLE_DEBUG #ifdef INTERACTABLE_DEBUG
GEngine->AddOnScreenDebugMessage(30 + (int)type, 5.0f, FColor::Cyan, TEXT("Player activate: ") + this->GetName() GEngine->AddOnScreenDebugMessage(30 + (int)type, 5.0f, FColor::Cyan, TEXT("Player activate: ") + this->GetName()
@ -113,7 +136,7 @@ void AInteractable::_Activate(EActivatorType type)
if(static_cast<uint8>(modificator.Value->GetActivatorTypes()) & static_cast<uint8>(type)) if(static_cast<uint8>(modificator.Value->GetActivatorTypes()) & static_cast<uint8>(type))
{ {
WM->ShowInteractionHints(modificator.Value); WM->ShowInteractionHints(modificator.Value);
modificator.Value->Bind(player->inputComponent); modificator.Value->Bind(ACustomPlayerController::GetInput());
} }
} }
} }
@ -124,10 +147,10 @@ void AInteractable::_Activate(EActivatorType type)
collision->SetCustomDepthStencilValue(132); collision->SetCustomDepthStencilValue(132);
} }
Activate(type); OnActivate(type);
} }
void AInteractable::_Deactivate(EActivatorType type) void AInteractable::Deactivate(EActivatorType type)
{ {
#ifdef INTERACTABLE_DEBUG #ifdef INTERACTABLE_DEBUG
GEngine->AddOnScreenDebugMessage(30 + (int)type, 5.0f, FColor::Magenta, TEXT("Player deactivate: ") + this->GetName() GEngine->AddOnScreenDebugMessage(30 + (int)type, 5.0f, FColor::Magenta, TEXT("Player deactivate: ") + this->GetName()
@ -159,5 +182,5 @@ void AInteractable::_Deactivate(EActivatorType type)
collision->SetCustomDepthStencilValue(0); collision->SetCustomDepthStencilValue(0);
} }
Deactivate(type); OnDeactivate(type);
} }

View File

@ -2,15 +2,18 @@
#pragma once #pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h" #include "GameFramework/Actor.h"
#include "Interactable.generated.h" #include "Interactable.generated.h"
/** Turns on debug of interactable objects */
//#define INTERACTABLE_DEBUG //#define INTERACTABLE_DEBUG
/** Turns on debug of interactable activator components */
//#define INTERACTABLE_ACTIVATOR_DEBUG //#define INTERACTABLE_ACTIVATOR_DEBUG
/** Turns on debug of interactable modificator components */
//#define INTERACTABLE_MODIFICATOR_DEBUG //#define INTERACTABLE_MODIFICATOR_DEBUG
/** Defines activation types */
UENUM(BlueprintType, meta = (Bitflags, UseEnumValuesAsMaskValuesInEditor = "true")) UENUM(BlueprintType, meta = (Bitflags, UseEnumValuesAsMaskValuesInEditor = "true"))
enum class EActivatorType : uint8 enum class EActivatorType : uint8
{ {
@ -27,38 +30,61 @@ enum class EActivatorType : uint8
}; };
ENUM_CLASS_FLAGS(EActivatorType); ENUM_CLASS_FLAGS(EActivatorType);
/**
* Object capable of reacting to activators and execute modificators.
* Sets all needed settings as collision layers on begin play.
*/
UCLASS(Blueprintable, BlueprintType, MinimalAPI) UCLASS(Blueprintable, BlueprintType, MinimalAPI)
class AInteractable : public AActor class AInteractable : public AActor
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
static void AppendActivatorClass(TSubclassOf<class UInteractableActivator> activator);
static void AppendModificatorClass(TSubclassOf<class UInteractableModificator> modificator);
/** Interactables shared cache */
static TSet<TSubclassOf<class UInteractableActivator>> interactionActivators;
static TSet<TSubclassOf<class UInteractableModificator>> interactionModificators;
public:
/** Returns flags mask of activated types */
int32 GetActivatedFlags(); int32 GetActivatedFlags();
void _Activate(EActivatorType type); /** Receives activate signal from activator of specific type and activates all modificators of that type */
UFUNCTION(BlueprintNativeEvent, BlueprintCallable) UFUNCTION(BlueprintCallable)
void Activate(EActivatorType type); void Activate(EActivatorType type);
virtual void Activate_Implementation(EActivatorType type) {}
void _Deactivate(EActivatorType type); /** Receives deactivate signal from activator of specific type and deactivates all modificators of that type */
UFUNCTION(BlueprintNativeEvent, BlueprintCallable) UFUNCTION(BlueprintCallable)
void Deactivate(EActivatorType type); void Deactivate(EActivatorType type);
virtual void Deactivate_Implementation(EActivatorType type) {}
/**
* All modificators that requires (de)activation lock for current interactable.
* Used manually by modificators to handle operations which can be continued after physical deactivation.
* Eg. MoveModificator movement while mouse buttons are down even if player don't activating interactable anymore.
*/
TSet<class UInteractableModificator*> activationLockers; TSet<class UInteractableModificator*> activationLockers;
protected: protected:
virtual void BeginPlay() override; virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
UFUNCTION(BlueprintImplementableEvent)
void OnActivate(EActivatorType type);
UFUNCTION(BlueprintImplementableEvent)
void OnDeactivate(EActivatorType type);
/** Mask of active activator types */
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (Bitmask, BitmaskEnum = "EActivatorType")) UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (Bitmask, BitmaskEnum = "EActivatorType"))
int32 activated = 0; int32 activated = 0;
/** Map of modificators to activator types initialized on BeginPlay */
UPROPERTY() UPROPERTY()
TMap<EActivatorType, class UInteractableModificator*> modificators; TMap<EActivatorType, class UInteractableModificator*> modificators;
class APlayerBase* player = nullptr;
TArray<UPrimitiveComponent*> collisions; TArray<UPrimitiveComponent*> collisions;
class APlayerBase* player = nullptr;
}; };

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "ActivateInteractableModificator.h" #include "ActivateInteractableModificator.h"
#include "EnhancedInputComponent.h" #include "EnhancedInputComponent.h"

View File

@ -2,14 +2,16 @@
#pragma once #pragma once
#include "CoreMinimal.h"
#include "InteractableModificator.h" #include "InteractableModificator.h"
#include "ActivateInteractableModificator.generated.h" #include "ActivateInteractableModificator.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FActivateInteractableModificatorActivatedDelegate); DECLARE_DYNAMIC_MULTICAST_DELEGATE(FActivateInteractableModificatorActivatedDelegate);
UCLASS(ClassGroup = InteractableModificator, meta = (BlueprintSpawnableComponent), Blueprintable, BlueprintType) /**
* Basic modificator for type Use
*/
UCLASS(Blueprintable, BlueprintType, ClassGroup = InteractableModificator, meta = (BlueprintSpawnableComponent, ShortTooltip = "Basic modificator for type Use"), MinimalAPI)
class UActivateInteractableModificator : public UInteractableModificator class UActivateInteractableModificator : public UInteractableModificator
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@ -1,14 +1,11 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "EditInteractableModificator.h" #include "EditInteractableModificator.h"
#include "Interactable/Interactable.h" #include "Interactable/Interactable.h"
UEditInteractableModificator::UEditInteractableModificator(const FObjectInitializer& ObjectInitializer) //UEditInteractableModificator::UEditInteractableModificator(const FObjectInitializer& ObjectInitializer)
: UInteractableModificator(ObjectInitializer) // : UInteractableModificator(ObjectInitializer)
{ //{
activatorTypes |= static_cast<uint8>(EActivatorType::Collide); // activatorTypes |= static_cast<uint8>(EActivatorType::Collide);
//}
}

View File

@ -2,17 +2,20 @@
#pragma once #pragma once
#include "CoreMinimal.h"
#include "InteractableModificator.h" #include "InteractableModificator.h"
#include "EditInteractableModificator.generated.h" //#include "EditInteractableModificator.generated.h"
UCLASS(ClassGroup = InteractableModificator, meta = (BlueprintSpawnableComponent), Blueprintable, BlueprintType) /**
class UEditInteractableModificator : public UInteractableModificator * <WIP>
{ * Edits object topology on collision
GENERATED_BODY() */
//UCLASS(Blueprintable, BlueprintType, ClassGroup = InteractableModificator, meta = (BlueprintSpawnableComponent, ShortTooltip = "Edits object topology on collision"), MinimalAPI)
public: //class UEditInteractableModificator : public UInteractableModificator
UEditInteractableModificator(const FObjectInitializer& ObjectInitializer); //{
// GENERATED_BODY()
}; //
//public:
// UEditInteractableModificator(const FObjectInitializer& ObjectInitializer);
//
//};

View File

@ -1,29 +1,20 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "InteractableModificator.h" #include "InteractableModificator.h"
#include "InputMappingContext.h" #include "Interactable/Interactable.h"
#include "CustomGameInstanceBase.h"
#include "Widgets/InteractableHintWidget.h" #include "Widgets/InteractableHintWidget.h"
void UInteractableModificator::OnRegister() void UInteractableModificator::OnRegister()
{ {
UActorComponent::OnRegister(); UActorComponent::OnRegister();
if(auto world = GetWorld()) AInteractable::AppendModificatorClass(GetClass());
{
if(auto GI = Cast<UCustomGameInstanceBase>(world->GetGameInstance()))
{
GI->AppendInteractableModificatorClass(this->GetClass());
}
}
} }
const UInputMappingContext* UInteractableModificator::GetMappingContext() const const TSoftObjectPtr<class UInputMappingContext> UInteractableModificator::GetMappingContext() const
{ {
return inputMapping.LoadSynchronous(); return inputMapping;
} }
EActivatorType UInteractableModificator::GetActivatorTypes() const EActivatorType UInteractableModificator::GetActivatorTypes() const

View File

@ -3,29 +3,37 @@
#pragma once #pragma once
#include "Components/ActorComponent.h" #include "Components/ActorComponent.h"
#include "CoreMinimal.h"
#include "InteractableModificator.generated.h" #include "InteractableModificator.generated.h"
enum class EActivatorType : uint8; enum class EActivatorType : uint8;
UCLASS(Abstract, Blueprintable, BlueprintType) /**
* Do something on activation by specified activator types
*/
UCLASS(Abstract, Blueprintable, BlueprintType, ClassGroup = InteractableModificator, meta = (BlueprintSpawnableComponent, ShortTooltip = "Do something on activation by specified activator types"), MinimalAPI)
class UInteractableModificator : public UActorComponent class UInteractableModificator : public UActorComponent
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
void OnRegister() override; /** Append itself to CustomGameInstance modificators registry */
virtual void OnRegister() override;
/** Returns input mappings assigned in constructor */
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
const class UInputMappingContext* GetMappingContext() const; const TSoftObjectPtr<class UInputMappingContext> GetMappingContext() const;
/** Filters activation type in interractable */
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
EActivatorType GetActivatorTypes() const; EActivatorType GetActivatorTypes() const;
/** Called from interactable on activation (mostly used to bind input context to internal modificator functions) */
UFUNCTION(BlueprintNativeEvent, BlueprintCallable) UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
void Bind(class UEnhancedInputComponent* input); void Bind(class UEnhancedInputComponent* input);
virtual void Bind_Implementation(class UEnhancedInputComponent* input) {} virtual void Bind_Implementation(class UEnhancedInputComponent* input) {}
/** Called from interactable on deactivation (mostly used to unbind input context from internal functions) */
UFUNCTION(BlueprintNativeEvent, BlueprintCallable) UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
void Unbind(); void Unbind();
virtual void Unbind_Implementation() {} virtual void Unbind_Implementation() {}

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "InventoryInteractableModificator.h" #include "InventoryInteractableModificator.h"
#include "EnhancedInputComponent.h" #include "EnhancedInputComponent.h"

View File

@ -2,12 +2,14 @@
#pragma once #pragma once
#include "CoreMinimal.h"
#include "InteractableModificator.h" #include "InteractableModificator.h"
#include "InventoryInteractableModificator.generated.h" #include "InventoryInteractableModificator.generated.h"
UCLASS(ClassGroup = InteractableModificator, meta = (BlueprintSpawnableComponent), Blueprintable, BlueprintType) /**
* Modificator of type Use for storing items in a APlayerBase
*/
UCLASS(Blueprintable, BlueprintType, ClassGroup = InteractableModificator, meta = (BlueprintSpawnableComponent, ShortTooltip = "Modificator of type Use for storing items in a APlayerBase"), MinimalAPI)
class UInventoryInteractableModificator : public UInteractableModificator class UInventoryInteractableModificator : public UInteractableModificator
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "MoveInteractableModificator.h" #include "MoveInteractableModificator.h"
#include "EnhancedInputComponent.h" #include "EnhancedInputComponent.h"
@ -90,7 +89,7 @@ void UMoveInteractableModificator::Unbind_Implementation()
bindindingHandlers.Empty(); bindindingHandlers.Empty();
SetComponentTickEnabled(false); SetComponentTickEnabled(false);
actor->_Deactivate(GetActivatorTypes()); actor->Deactivate(GetActivatorTypes());
OnMoveDeactivated.Broadcast(); OnMoveDeactivated.Broadcast();
} }

View File

@ -2,7 +2,6 @@
#pragma once #pragma once
#include "CoreMinimal.h"
#include "InputActionValue.h" #include "InputActionValue.h"
#include "InteractableModificator.h" #include "InteractableModificator.h"
@ -13,7 +12,10 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDeactivateMoveInteractableModificatorActivat
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FHoldingMoveInteractableModificatorActivatedDelegate); DECLARE_DYNAMIC_MULTICAST_DELEGATE(FHoldingMoveInteractableModificatorActivatedDelegate);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FRotatingMoveInteractableModificatorActivatedDelegate); DECLARE_DYNAMIC_MULTICAST_DELEGATE(FRotatingMoveInteractableModificatorActivatedDelegate);
UCLASS(ClassGroup = InteractableModificator, meta = (BlueprintSpawnableComponent), Blueprintable, BlueprintType) /**
* Basic modificator for Move type activator
*/
UCLASS(Blueprintable, BlueprintType, ClassGroup = InteractableModificator, meta = (BlueprintSpawnableComponent, ShortTooltip = "Basic modificator for Move type activator"), MinimalAPI)
class UMoveInteractableModificator : public UInteractableModificator class UMoveInteractableModificator : public UInteractableModificator
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "SawInteractableModificator.h" #include "SawInteractableModificator.h"
#include "Interactable/Interactable.h" #include "Interactable/Interactable.h"

View File

@ -2,14 +2,16 @@
#pragma once #pragma once
#include "CoreMinimal.h"
#include "InteractableModificator.h" #include "InteractableModificator.h"
#include "SawInteractableModificator.generated.h" #include "SawInteractableModificator.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FSawInteractableModificatorActivatedDelegate); DECLARE_DYNAMIC_MULTICAST_DELEGATE(FSawInteractableModificatorActivatedDelegate);
UCLASS(ClassGroup = InteractableModificator, meta = (BlueprintSpawnableComponent), Blueprintable, BlueprintType) /**
* Basic modificator for Saw type activator
*/
UCLASS(Blueprintable, BlueprintType, ClassGroup = InteractableModificator, meta = (BlueprintSpawnableComponent, ShortTooltip = "Basic modificator for Saw type activator"), MinimalAPI)
class USawInteractableModificator : public UInteractableModificator class USawInteractableModificator : public UInteractableModificator
{ {
GENERATED_BODY() GENERATED_BODY()

View File

@ -1,12 +1,11 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "Checkpoint.h" #include "Checkpoint.h"
#include "CustomGameInstanceBase.h" #include "CustomGameInstance.h"
void ACheckpoint::SaveGame() void ACheckpoint::SaveGame()
{ {
if(auto GI = Cast<UCustomGameInstanceBase>(GetWorld()->GetGameInstance())) if(auto GI = UCustomGameInstance::Get())
GI->SaveGame(GetFName()); GI->SaveGame(GetFName());
} }

View File

@ -6,6 +6,7 @@
#include "Checkpoint.generated.h" #include "Checkpoint.generated.h"
/** Simple actor for game save */
UCLASS(Blueprintable, BlueprintType, MinimalAPI) UCLASS(Blueprintable, BlueprintType, MinimalAPI)
class ACheckpoint : public AActor class ACheckpoint : public AActor
{ {

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "Level1.h" #include "Level1.h"
#include "Atmosphere/AtmosphericFog.h" #include "Atmosphere/AtmosphericFog.h"

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "Level2.h" #include "Level2.h"
void ALevel2::BeginPlay() void ALevel2::BeginPlay()

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "Level3.h" #include "Level3.h"
#include "Atmosphere/AtmosphericFog.h" #include "Atmosphere/AtmosphericFog.h"

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "Level4.h" #include "Level4.h"
#include "Atmosphere/AtmosphericFog.h" #include "Atmosphere/AtmosphericFog.h"

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "Level5.h" #include "Level5.h"
#include "Atmosphere/AtmosphericFog.h" #include "Atmosphere/AtmosphericFog.h"

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "LevelBase.h" #include "LevelBase.h"
#include "Engine/StaticMesh.h" #include "Engine/StaticMesh.h"
@ -10,8 +9,8 @@
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
#include "LevelSequencePlayer.h" #include "LevelSequencePlayer.h"
#include "CommonFunctions.h" #include "CustomGameInstance.h"
#include "CustomGameInstanceBase.h" #include "CustomPlayerController.h"
#include "Interactable/Interactable.h" #include "Interactable/Interactable.h"
#include "Levels/Checkpoint.h" #include "Levels/Checkpoint.h"
#include "MainGameModeBase.h" #include "MainGameModeBase.h"
@ -19,21 +18,17 @@
#include "PlayerBase.h" #include "PlayerBase.h"
#include "SaveData.h" #include "SaveData.h"
ALevelBase* ALevelBase::Get()
{
if(auto GM = AMainGameModeBase::Get())
return GM->leadLevel.Get();
return nullptr;
}
void ALevelBase::BeginPlay() void ALevelBase::BeginPlay()
{ {
AMainGameModeBase::leadLevel = TStrongObjectPtr<ALevelBase>{ this }; AMainGameModeBase::leadLevel = TStrongObjectPtr<ALevelBase>{ this };
if(auto world = GetWorld())
{
if(auto GI = Cast<UCustomGameInstanceBase>(world->GetGameInstance()))
{
for(TActorIterator<AMinigame> it(GetWorld()); it; ++it)
{
GI->inputContexts.Add(it->GetInputMappings());
}
}
}
ALevelScriptActor::BeginPlay(); ALevelScriptActor::BeginPlay();
BroadcastNewLevelBeginPlay(); BroadcastNewLevelBeginPlay();
@ -62,7 +57,7 @@ void ALevelBase::IterateToState(int32 to)
void ALevelBase::BroadcastNewLevelBeginPlay() void ALevelBase::BroadcastNewLevelBeginPlay()
{ {
if(auto GI = Cast<UCustomGameInstanceBase>(GetWorld()->GetGameInstance())) if(auto GI = UCustomGameInstance::Get())
GI->OnLevelBeginned.Broadcast(GetFName()); GI->OnLevelBeginned.Broadcast(GetFName());
} }
@ -83,13 +78,13 @@ void ALevelBase::StartLevelAnimations()
void ALevelBase::ApplySaveData() void ALevelBase::ApplySaveData()
{ {
auto GI = UCustomGameInstanceBase::GetGameInstance(); auto GI = UCustomGameInstance::Get();
if(!GI || !GI->saveData || GI->saveData->level != GetWorld()->GetFName()) if(!GI || !GI->saveData || GI->saveData->level != GetWorld()->GetFName())
return; return;
IterateToState(GI->saveData->state); IterateToState(GI->saveData->state);
auto player = UCommonFunctions::GetPlayer(this); auto player = APlayerBase::Get();
if(!player) if(!player)
return; return;

View File

@ -6,15 +6,28 @@
#include "LevelBase.generated.h" #include "LevelBase.generated.h"
/**
* Expands basic UE level script actor.
* Has int type level states and events.
* Brodcasts level instantiation by CustomGameInstance::OnLevelBeginned(FName).
* On BeginPlay applies last save data if valid,
* and instantiate all sequencers from array onBeginPlaySequences.
*/
UCLASS(BlueprintType) UCLASS(BlueprintType)
class ALevelBase : public ALevelScriptActor class ALevelBase : public ALevelScriptActor
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
/** Returns lead level script */
UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Lead Level Script"))
static ALevelBase* Get();
/** Iterates throught level states */
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
inline void CallNextState() { ++state; NextState(); } inline void CallNextState() { ++state; NextState(); }
/** Calls specific event id in level */
UFUNCTION(BlueprintImplementableEvent) UFUNCTION(BlueprintImplementableEvent)
void CallEvent(int32 id); void CallEvent(int32 id);
@ -23,9 +36,11 @@ public:
protected: protected:
virtual void BeginPlay() override; virtual void BeginPlay() override;
/** Notifies level to process current state */
UFUNCTION(BlueprintImplementableEvent) UFUNCTION(BlueprintImplementableEvent)
void NextState(); void NextState();
/** Shortcut for iterating from current to expected state */
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
void IterateToState(int32 to); void IterateToState(int32 to);
@ -33,12 +48,13 @@ protected:
void StartLevelAnimations(); void StartLevelAnimations();
void ApplySaveData(); void ApplySaveData();
/** List of level animations for instantiation on level BeginPlay */
UPROPERTY(EditDefaultsOnly) UPROPERTY(EditDefaultsOnly)
TArray<TSoftObjectPtr<class ULevelSequence>> onBeginPlaySequences; TArray<TSoftObjectPtr<class ULevelSequence>> onBeginPlaySequences;
/** Cache of actors that hold instantiated animations on BeginPlay */
TArray<class ALevelSequenceActor*> onBeginPlaySequencesActors; TArray<class ALevelSequenceActor*> onBeginPlaySequencesActors;
/** Current state of level */
UPROPERTY(BlueprintReadOnly) UPROPERTY(BlueprintReadOnly)
int32 state = -1; int32 state = -1;
UPROPERTY(EditDefaultsOnly)
TArray<TSoftObjectPtr<class ULevelSequence>> stateSequences;
}; };

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "MainGameModeBase.h" #include "MainGameModeBase.h"
#include "Engine/World.h" #include "Engine/World.h"
@ -8,7 +7,6 @@
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
#include "UObject/ScriptInterface.h" #include "UObject/ScriptInterface.h"
#include "CustomGameInstanceBase.h"
#include "CutsceneManager.h" #include "CutsceneManager.h"
#include "DialogueManager.h" #include "DialogueManager.h"
#include "Levels/LevelBase.h" #include "Levels/LevelBase.h"
@ -16,66 +14,71 @@
#include "QuickTimeEvent.h" #include "QuickTimeEvent.h"
#include "Widgets/WidgetsManager.h" #include "Widgets/WidgetsManager.h"
AMainGameModeBase* AMainGameModeBase::_instance = nullptr; AMainGameModeBase* AMainGameModeBase::instance = nullptr;
TStrongObjectPtr<UWidgetsManager> AMainGameModeBase::_widgetsManager = nullptr; TStrongObjectPtr<UWidgetsManager> AMainGameModeBase::widgetsManager = nullptr;
TStrongObjectPtr<UCutsceneManager> AMainGameModeBase::_cutsceneManager = nullptr; TStrongObjectPtr<UCutsceneManager> AMainGameModeBase::cutsceneManager = nullptr;
TStrongObjectPtr<UQuickTimeEventManager> AMainGameModeBase::_quickTimeEventManager = nullptr; TStrongObjectPtr<UQuickTimeEventManager> AMainGameModeBase::quickTimeEventManager = nullptr;
TStrongObjectPtr<UDialogueManager> AMainGameModeBase::_dialogueManager = nullptr; TStrongObjectPtr<UDialogueManager> AMainGameModeBase::dialogueManager = nullptr;
TStrongObjectPtr<ALevelBase> AMainGameModeBase::leadLevel = nullptr; TStrongObjectPtr<ALevelBase> AMainGameModeBase::leadLevel = nullptr;
void AMainGameModeBase::StartPlay() void AMainGameModeBase::StartPlay()
{ {
_instance = this; instance = this;
_widgetsManager = TStrongObjectPtr<UWidgetsManager>{ NewObject<UWidgetsManager>(this, widgetManagerClass) }; widgetsManager = TStrongObjectPtr<UWidgetsManager>{ NewObject<UWidgetsManager>(this, widgetManagerClass) };
_cutsceneManager = TStrongObjectPtr<UCutsceneManager>{ NewObject<UCutsceneManager>(this) }; cutsceneManager = TStrongObjectPtr<UCutsceneManager>{ NewObject<UCutsceneManager>(this) };
_quickTimeEventManager = TStrongObjectPtr<UQuickTimeEventManager>{ NewObject<UQuickTimeEventManager>(this) }; quickTimeEventManager = TStrongObjectPtr<UQuickTimeEventManager>{ NewObject<UQuickTimeEventManager>(this) };
_dialogueManager = TStrongObjectPtr<UDialogueManager>{ NewObject<UDialogueManager>(this) }; dialogueManager = TStrongObjectPtr<UDialogueManager>{ NewObject<UDialogueManager>(this) };
AGameModeBase::StartPlay(); AGameModeBase::StartPlay();
_widgetsManager->Init(); widgetsManager->Init();
} }
void AMainGameModeBase::EndPlay(const EEndPlayReason::Type EndPlayReason) void AMainGameModeBase::EndPlay(const EEndPlayReason::Type EndPlayReason)
{ {
_cutsceneManager->LockCallback(true); cutsceneManager->LockCallback(true);
//_cutsceneManager->ClearQueue(); //cutsceneManager->ClearQueue(); // condition race segfault?
} }
bool AMainGameModeBase::SetPause(APlayerController* PC, FCanUnpause CanUnpauseDelegate) bool AMainGameModeBase::SetPause(APlayerController* PC, FCanUnpause CanUnpauseDelegate)
{ {
if(_widgetsManager) if(widgetsManager)
{ {
if(IsPaused()) if(IsPaused())
{ {
_widgetsManager->HideWidgets(); widgetsManager->HideWidgets();
} }
else else
{ {
_widgetsManager->ShowWidgets(); widgetsManager->ShowWidgets();
} }
} }
return AGameModeBase::SetPause(PC, CanUnpauseDelegate); return AGameModeBase::SetPause(PC, CanUnpauseDelegate);
} }
AMainGameModeBase* AMainGameModeBase::Get()
{
return instance;
}
UWidgetsManager* AMainGameModeBase::GetWidgetsManager() UWidgetsManager* AMainGameModeBase::GetWidgetsManager()
{ {
return _widgetsManager.Get(); return widgetsManager.Get();
} }
UCutsceneManager* AMainGameModeBase::GetCutsceneManager() UCutsceneManager* AMainGameModeBase::GetCutsceneManager()
{ {
return _cutsceneManager.Get(); return cutsceneManager.Get();
} }
UQuickTimeEventManager* AMainGameModeBase::GetQuickTimeEventManager() UQuickTimeEventManager* AMainGameModeBase::GetQuickTimeEventManager()
{ {
return _quickTimeEventManager.Get(); return quickTimeEventManager.Get();
} }
UDialogueManager* AMainGameModeBase::GetDialogueManager() UDialogueManager* AMainGameModeBase::GetDialogueManager()
{ {
return _dialogueManager.Get(); return dialogueManager.Get();
} }
void AMainGameModeBase::CallNextLevelState() void AMainGameModeBase::CallNextLevelState()
@ -92,39 +95,37 @@ void AMainGameModeBase::CallLevelEvent(int32 id)
void AMainGameModeBase::UpdateQuests(TArray<FText> items) void AMainGameModeBase::UpdateQuests(TArray<FText> items)
{ {
if(_instance && _instance->questsUpdateDelegate.IsBound()) if(instance && instance->questsUpdateDelegate.IsBound())
_instance->questsUpdateDelegate.Broadcast(items); instance->questsUpdateDelegate.Broadcast(items);
} }
void AMainGameModeBase::SwitchCameraMode() void AMainGameModeBase::SwitchCameraMode()
{ {
static TWeakObjectPtr<APawn> _playerPawn = nullptr; static TWeakObjectPtr<APawn> playerPawn = nullptr;
if(auto PC = UGameplayStatics::GetPlayerController(GetWorld(), 0)) if(auto PC = UGameplayStatics::GetPlayerController(GetWorld(), 0))
{ {
if(auto pawn = PC->GetPawn()) if(auto pawn = PC->GetPawn())
{ {
if(!_playerPawn.IsValid()) if(!playerPawn.IsValid())
{ {
auto spawnLoc = pawn->GetActorLocation(); auto spawnLoc = pawn->GetActorLocation();
auto spawnRot = pawn->GetActorRotation(); auto spawnRot = pawn->GetActorRotation();
if(auto cameraPawn = GetWorld()->SpawnActor<APawn>(SpectatorClass, spawnLoc, spawnRot)) if(auto cameraPawn = GetWorld()->SpawnActor<APawn>(SpectatorClass, spawnLoc, spawnRot))
{ {
_playerPawn = pawn; playerPawn = pawn;
PC->Possess(cameraPawn); PC->Possess(cameraPawn);
} }
} }
else else
{ {
PC->Possess(_playerPawn.Get()); PC->Possess(playerPawn.Get());
pawn->Destroy(); pawn->Destroy();
_playerPawn = nullptr; playerPawn = nullptr;
} }
} }
} }
if(_widgetsManager) if(widgetsManager.IsValid())
{ widgetsManager->UpdateWidgetsOwner();
_widgetsManager->UpdateWidgetsOwner();
}
} }

View File

@ -8,6 +8,11 @@
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FQuestsUpdateDelegate, TArray<FText>, quests); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FQuestsUpdateDelegate, TArray<FText>, quests);
/*
* Manager of most gameplay systems.
* Widgets, custcenes, QTE, dialogues, quests, camera mode, level.
* Please, use MainGameMode SetPause to pause the game.
*/
UCLASS() UCLASS()
class AMainGameModeBase : public AGameModeBase class AMainGameModeBase : public AGameModeBase
{ {
@ -18,6 +23,8 @@ public:
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual bool SetPause(APlayerController* PC, FCanUnpause CanUnpauseDelegate = FCanUnpause()) override; virtual bool SetPause(APlayerController* PC, FCanUnpause CanUnpauseDelegate = FCanUnpause()) override;
UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Main Game Mode"))
static AMainGameModeBase* Get();
UFUNCTION(BlueprintPure) UFUNCTION(BlueprintPure)
static class UWidgetsManager* GetWidgetsManager(); static class UWidgetsManager* GetWidgetsManager();
UFUNCTION(BlueprintPure) UFUNCTION(BlueprintPure)
@ -46,9 +53,9 @@ protected:
TSubclassOf<class UWidgetsManager> widgetManagerClass; TSubclassOf<class UWidgetsManager> widgetManagerClass;
private: private:
static AMainGameModeBase* _instance; static AMainGameModeBase* instance;
static TStrongObjectPtr<class UWidgetsManager> _widgetsManager; static TStrongObjectPtr<class UWidgetsManager> widgetsManager;
static TStrongObjectPtr<class UCutsceneManager> _cutsceneManager; static TStrongObjectPtr<class UCutsceneManager> cutsceneManager;
static TStrongObjectPtr<class UQuickTimeEventManager> _quickTimeEventManager; static TStrongObjectPtr<class UQuickTimeEventManager> quickTimeEventManager;
static TStrongObjectPtr<class UDialogueManager> _dialogueManager; static TStrongObjectPtr<class UDialogueManager> dialogueManager;
}; };

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "AgeOfWarManager.h" #include "AgeOfWarManager.h"
#include "Camera/CameraComponent.h" #include "Camera/CameraComponent.h"

View File

@ -1,12 +1,11 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "AgeOfWarUnit.h" #include "AgeOfWarUnit.h"
#include "Components/BoxComponent.h"
#include "Components/StaticMeshComponent.h" #include "Components/StaticMeshComponent.h"
#include "AgeOfWarManager.h" #include "AgeOfWarManager.h"
#include <Components/BoxComponent.h>
namespace namespace
{ {

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "CrossyRoadManager.h" #include "CrossyRoadManager.h"
#include "Camera/CameraComponent.h" #include "Camera/CameraComponent.h"
@ -10,7 +9,7 @@
#include "InputMappingContext.h" #include "InputMappingContext.h"
#include "CrossyRoadObstacle.h" #include "CrossyRoadObstacle.h"
#include "CustomGameInstanceBase.h" #include "CustomPlayerController.h"
#include "MainGameModeBase.h" #include "MainGameModeBase.h"
#include "PlayerBase.h" #include "PlayerBase.h"
#include "Widgets/WidgetsManager.h" #include "Widgets/WidgetsManager.h"
@ -19,7 +18,7 @@ ACrossyRoadManager::ACrossyRoadManager()
: AMinigame() : AMinigame()
{ {
static ConstructorHelpers::FObjectFinder<UInputMappingContext> asset{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/Minigame/IMC_Minigame_CrossyRoad.IMC_Minigame_CrossyRoad'") }; static ConstructorHelpers::FObjectFinder<UInputMappingContext> asset{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/Minigame/IMC_Minigame_CrossyRoad.IMC_Minigame_CrossyRoad'") };
input = asset.Object; context = asset.Object;
auto root = CreateDefaultSubobject<USceneComponent>(TEXT("Scene")); auto root = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
@ -43,16 +42,17 @@ void ACrossyRoadManager::Start(APlayerBase* playerPawn, FMinigameEndCallback del
player->LockPlayer(FPlayerLock::All()); player->LockPlayer(FPlayerLock::All());
player->SwitchToView(this); player->SwitchToView(this);
for(auto& mapping : input.LoadSynchronous()->GetMappings()) auto input = ACustomPlayerController::GetInput();
for(auto& mapping : context.LoadSynchronous()->GetMappings())
{ {
if(mapping.Action->ActionDescription.EqualTo(FText::AsCultureInvariant(TEXT("Up")))) if(mapping.Action->ActionDescription.EqualTo(FText::AsCultureInvariant(TEXT("Up"))))
inputHandlers.Add(player->inputComponent->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &ACrossyRoadManager::Up).GetHandle()); inputHandlers.Add(input->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &ACrossyRoadManager::Up).GetHandle());
else if(mapping.Action->ActionDescription.EqualTo(FText::AsCultureInvariant(TEXT("Down")))) else if(mapping.Action->ActionDescription.EqualTo(FText::AsCultureInvariant(TEXT("Down"))))
inputHandlers.Add(player->inputComponent->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &ACrossyRoadManager::Down).GetHandle()); inputHandlers.Add(input->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &ACrossyRoadManager::Down).GetHandle());
else if(mapping.Action->ActionDescription.EqualTo(FText::AsCultureInvariant(TEXT("Left")))) else if(mapping.Action->ActionDescription.EqualTo(FText::AsCultureInvariant(TEXT("Left"))))
inputHandlers.Add(player->inputComponent->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &ACrossyRoadManager::Left).GetHandle()); inputHandlers.Add(input->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &ACrossyRoadManager::Left).GetHandle());
else if(mapping.Action->ActionDescription.EqualTo(FText::AsCultureInvariant(TEXT("Right")))) else if(mapping.Action->ActionDescription.EqualTo(FText::AsCultureInvariant(TEXT("Right"))))
inputHandlers.Add(player->inputComponent->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &ACrossyRoadManager::Right).GetHandle()); inputHandlers.Add(input->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &ACrossyRoadManager::Right).GetHandle());
} }
playerPos->SetWorldLocation(lines[0]->GetLocationAtTime(lines[0]->Duration * playerLineTime, ESplineCoordinateSpace::World)); playerPos->SetWorldLocation(lines[0]->GetLocationAtTime(lines[0]->Duration * playerLineTime, ESplineCoordinateSpace::World));
@ -70,7 +70,7 @@ void ACrossyRoadManager::End()
PrimaryActorTick.SetTickFunctionEnable(false); PrimaryActorTick.SetTickFunctionEnable(false);
for(int32 handler : inputHandlers) for(int32 handler : inputHandlers)
player->inputComponent->RemoveBindingByHandle(handler); ACustomPlayerController::GetInput()->RemoveBindingByHandle(handler);
player->UnlockPlayer(FPlayerLock::All()); player->UnlockPlayer(FPlayerLock::All());
player->ReturnPlayerView(); player->ReturnPlayerView();

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "CrossyRoadObstacle.h" #include "CrossyRoadObstacle.h"
#include "CrossyRoadManager.h" #include "CrossyRoadManager.h"

View File

@ -1,18 +1,18 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "FishingManager.h" #include "FishingManager.h"
#include "EnhancedInputComponent.h" #include "EnhancedInputComponent.h"
#include "InputMappingContext.h" #include "InputMappingContext.h"
#include "CustomPlayerController.h"
#include "MainGameModeBase.h" #include "MainGameModeBase.h"
#include "PlayerBase.h" #include "PlayerBase.h"
AFishingManager::AFishingManager() AFishingManager::AFishingManager()
{ {
static ConstructorHelpers::FObjectFinder<UInputMappingContext> asset{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/Minigame/IMC_Minigame_Fishing.IMC_Minigame_Fishing'") }; static ConstructorHelpers::FObjectFinder<UInputMappingContext> asset{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/Minigame/IMC_Minigame_Fishing.IMC_Minigame_Fishing'") };
input = asset.Object; context = asset.Object;
} }
void AFishingManager::Start(APlayerBase* playerPawn, FMinigameEndCallback delegate) void AFishingManager::Start(APlayerBase* playerPawn, FMinigameEndCallback delegate)
@ -24,15 +24,17 @@ void AFishingManager::Start(APlayerBase* playerPawn, FMinigameEndCallback delega
player->LockPlayer(FPlayerLock::All()); player->LockPlayer(FPlayerLock::All());
auto& mapping = input.LoadSynchronous()->GetMapping(0); auto input = ACustomPlayerController::GetInput();
handler1 = player->inputComponent->BindAction(mapping.Action, ETriggerEvent::Started, this, &AFishingManager::OnInputHold).GetHandle(); auto& mapping = context.LoadSynchronous()->GetMapping(0);
handler2 = player->inputComponent->BindAction(mapping.Action, ETriggerEvent::Completed, this, &AFishingManager::OnInputUnhold).GetHandle(); handler1 = input->BindAction(mapping.Action, ETriggerEvent::Started, this, &AFishingManager::OnInputHold).GetHandle();
handler2 = input->BindAction(mapping.Action, ETriggerEvent::Completed, this, &AFishingManager::OnInputUnhold).GetHandle();
} }
void AFishingManager::End() void AFishingManager::End()
{ {
player->inputComponent->RemoveBindingByHandle(handler1); auto input = ACustomPlayerController::GetInput();
player->inputComponent->RemoveBindingByHandle(handler2); input->RemoveBindingByHandle(handler1);
input->RemoveBindingByHandle(handler2);
player->UnlockPlayer(FPlayerLock::All()); player->UnlockPlayer(FPlayerLock::All());

View File

@ -1,11 +1,10 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "Minigame.h" #include "Minigame.h"
#include "EnhancedInputSubsystems.h"
#include "InputMappingContext.h" #include "InputMappingContext.h"
#include "CustomPlayerController.h"
#include "PlayerBase.h" #include "PlayerBase.h"
AMinigame::AMinigame() AMinigame::AMinigame()
@ -22,23 +21,13 @@ void AMinigame::End()
OnEnd(); OnEnd();
} }
void AMinigame::Restart()
{}
UInputMappingContext* AMinigame::GetInputMappings()
{
return input.LoadSynchronous();
}
void AMinigame::Start(APlayerBase* playerPawn, FMinigameEndCallback delegate) void AMinigame::Start(APlayerBase* playerPawn, FMinigameEndCallback delegate)
{ {
player = playerPawn; player = playerPawn;
callback = delegate; callback = delegate;
if(input) if(context.IsValid())
if(auto PC = Cast<APlayerController>(playerPawn->GetController())) ACustomPlayerController::AppendInputContext(context);
if(auto inputSubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer()))
inputSubsystem->AddMappingContext(input.LoadSynchronous(), 0);
OnStart(); OnStart();
} }

View File

@ -15,7 +15,14 @@ enum class EMinigameResult : uint8
DECLARE_DYNAMIC_DELEGATE_TwoParams(FMinigameEndCallback, EMinigameResult, result, int32, score); DECLARE_DYNAMIC_DELEGATE_TwoParams(FMinigameEndCallback, EMinigameResult, result, int32, score);
UCLASS(Blueprintable, BlueprintType, MinimalAPI, Abstract) /**
* Interface for all minigame classes.
* Any minigame is started/ended/restarted by executing Start()/End()/Restart() on specific instance.
* Each call is after broadcasted into a blueprint event also.
* On start the caller can pass a OnEndCallback delegate to receive result and score on a minigame end.
* Each minigame can have its own contextInput
*/
UCLASS(Abstract, Blueprintable, BlueprintType, MinimalAPI)
class AMinigame : public AActor class AMinigame : public AActor
{ {
GENERATED_BODY() GENERATED_BODY()
@ -25,21 +32,21 @@ public:
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
virtual void Start(class APlayerBase* playerPawn, FMinigameEndCallback delegate); virtual void Start(class APlayerBase* playerPawn, FMinigameEndCallback delegate);
UFUNCTION(BlueprintImplementableEvent) UFUNCTION(BlueprintImplementableEvent)
void OnStart(); void OnStart();
UFUNCTION(BlueprintCallable) UFUNCTION(BlueprintCallable)
virtual void End(); virtual void End();
UFUNCTION(BlueprintCallable)
virtual void Restart();
UFUNCTION(BlueprintImplementableEvent) UFUNCTION(BlueprintImplementableEvent)
void OnEnd(); void OnEnd();
UFUNCTION(BlueprintCallable)
virtual void Restart() {}
UFUNCTION(BlueprintImplementableEvent)
void OnRestart();
UFUNCTION(BlueprintPure) UFUNCTION(BlueprintPure)
class UInputMappingContext* GetInputMappings(); TSoftObjectPtr<class UInputMappingContext> GetInputMappings() { return context; }
protected: protected:
FMinigameEndCallback callback; FMinigameEndCallback callback;
@ -55,6 +62,6 @@ protected:
bool ended = false; bool ended = false;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly) UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TSoftObjectPtr<class UInputMappingContext> input = nullptr; TSoftObjectPtr<class UInputMappingContext> context = nullptr;
}; };

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "RythmClickManager.h" #include "RythmClickManager.h"
#include "MainGameModeBase.h" #include "MainGameModeBase.h"

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "SubwaySurfManager.h" #include "SubwaySurfManager.h"
#include "Camera/CameraComponent.h" #include "Camera/CameraComponent.h"
@ -9,7 +8,7 @@
#include "EnhancedInputComponent.h" #include "EnhancedInputComponent.h"
#include "InputMappingContext.h" #include "InputMappingContext.h"
#include "CustomGameInstanceBase.h" #include "CustomPlayerController.h"
#include "MainGameModeBase.h" #include "MainGameModeBase.h"
#include "PlayerBase.h" #include "PlayerBase.h"
#include "SubwaySurfObstacle.h" #include "SubwaySurfObstacle.h"
@ -19,7 +18,7 @@ ASubwaySurfManager::ASubwaySurfManager()
: AMinigame() : AMinigame()
{ {
static ConstructorHelpers::FObjectFinder<UInputMappingContext> asset{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/Minigame/IMC_Minigame_SubwaySurf.IMC_Minigame_SubwaySurf'") }; static ConstructorHelpers::FObjectFinder<UInputMappingContext> asset{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/Minigame/IMC_Minigame_SubwaySurf.IMC_Minigame_SubwaySurf'") };
input = asset.Object; context = asset.Object;
auto root = CreateDefaultSubobject<USceneComponent>(TEXT("Scene")); auto root = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
@ -43,16 +42,17 @@ void ASubwaySurfManager::Start(APlayerBase* playerPawn, FMinigameEndCallback del
player->LockPlayer(FPlayerLock::All()); player->LockPlayer(FPlayerLock::All());
player->SwitchToView(this); player->SwitchToView(this);
for(auto& mapping : input.LoadSynchronous()->GetMappings()) auto input = ACustomPlayerController::GetInput();
for(auto& mapping : context.LoadSynchronous()->GetMappings())
{ {
if(mapping.Action->ActionDescription.EqualTo(FText::AsCultureInvariant(TEXT("Up")))) if(mapping.Action->ActionDescription.EqualTo(FText::AsCultureInvariant(TEXT("Up"))))
inputHandlers.Add(player->inputComponent->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &ASubwaySurfManager::Up).GetHandle()); inputHandlers.Add(input->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &ASubwaySurfManager::Up).GetHandle());
else if(mapping.Action->ActionDescription.EqualTo(FText::AsCultureInvariant(TEXT("Down")))) else if(mapping.Action->ActionDescription.EqualTo(FText::AsCultureInvariant(TEXT("Down"))))
inputHandlers.Add(player->inputComponent->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &ASubwaySurfManager::Down).GetHandle()); inputHandlers.Add(input->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &ASubwaySurfManager::Down).GetHandle());
else if(mapping.Action->ActionDescription.EqualTo(FText::AsCultureInvariant(TEXT("Left")))) else if(mapping.Action->ActionDescription.EqualTo(FText::AsCultureInvariant(TEXT("Left"))))
inputHandlers.Add(player->inputComponent->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &ASubwaySurfManager::Left).GetHandle()); inputHandlers.Add(input->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &ASubwaySurfManager::Left).GetHandle());
else if(mapping.Action->ActionDescription.EqualTo(FText::AsCultureInvariant(TEXT("Right")))) else if(mapping.Action->ActionDescription.EqualTo(FText::AsCultureInvariant(TEXT("Right"))))
inputHandlers.Add(player->inputComponent->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &ASubwaySurfManager::Right).GetHandle()); inputHandlers.Add(input->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &ASubwaySurfManager::Right).GetHandle());
} }
playerPos->SetRelativeLocation(lines[1]->GetLocationAtTime(lines[1]->Duration * 0.01f, ESplineCoordinateSpace::Local)); playerPos->SetRelativeLocation(lines[1]->GetLocationAtTime(lines[1]->Duration * 0.01f, ESplineCoordinateSpace::Local));
@ -66,7 +66,7 @@ void ASubwaySurfManager::End()
PrimaryActorTick.SetTickFunctionEnable(false); PrimaryActorTick.SetTickFunctionEnable(false);
for(int32 handler : inputHandlers) for(int32 handler : inputHandlers)
player->inputComponent->RemoveBindingByHandle(handler); ACustomPlayerController::GetInput()->RemoveBindingByHandle(handler);
player->UnlockPlayer(FPlayerLock::All()); player->UnlockPlayer(FPlayerLock::All());
player->ReturnPlayerView(); player->ReturnPlayerView();

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "SubwaySurfObstacle.h" #include "SubwaySurfObstacle.h"
#include "SubwaySurfManager.h" #include "SubwaySurfManager.h"

View File

@ -1,19 +1,16 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "PlayerBase.h" #include "PlayerBase.h"
#include "Camera/CameraComponent.h" #include "Camera/CameraComponent.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "GameFramework/CharacterMovementComponent.h" #include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/SpringArmComponent.h" #include "GameFramework/SpringArmComponent.h"
#include "InputMappingContext.h" #include "InputMappingContext.h"
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
#include "Kismet/KismetMathLibrary.h" #include "Kismet/KismetMathLibrary.h"
#include "CustomGameInstanceBase.h" #include "CustomGameSettings.h"
#include "CustomGameUserSettings.h" #include "CustomPlayerController.h"
#include "Interactable/Activators/InteractableActivator.h" #include "Interactable/Activators/InteractableActivator.h"
#include "Interactable/Interactable.h" #include "Interactable/Interactable.h"
#include "Interactable/Modificators/InteractableModificator.h" #include "Interactable/Modificators/InteractableModificator.h"
@ -28,6 +25,10 @@ namespace
APlayerBase::APlayerBase() APlayerBase::APlayerBase()
: ACharacter() : ACharacter()
{ {
static ConstructorHelpers::FObjectFinder<UInputMappingContext> asset{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/IMC_Player.IMC_Player'") };
context = asset.Object;
ACustomPlayerController::AppendInputContext(context);
PrimaryActorTick.bCanEverTick = true; PrimaryActorTick.bCanEverTick = true;
camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera")); camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
@ -61,6 +62,13 @@ void APlayerBase::SetupPlayerInputComponent(UInputComponent* PlayerInputComponen
ACharacter::SetupPlayerInputComponent(PlayerInputComponent); ACharacter::SetupPlayerInputComponent(PlayerInputComponent);
} }
APlayerBase* APlayerBase::Get()
{
if(auto PC = ACustomPlayerController::Get())
return Cast<APlayerBase>(PC->GetPawn());
return nullptr;
}
void APlayerBase::BeginPlay() void APlayerBase::BeginPlay()
{ {
ACharacter::BeginPlay(); ACharacter::BeginPlay();
@ -77,51 +85,15 @@ void APlayerBase::BeginPlay()
cameraManager->ViewPitchMax = maxPitch; cameraManager->ViewPitchMax = maxPitch;
} }
auto gameSettings = UCustomGameUserSettings::GetCustomGameUserSettings(); auto gameSettings = UCustomGameSettings::Get();
if(gameSettings && camera)
if(camera)
{ {
camera->PostProcessSettings.MotionBlurAmount = gameSettings->bUseMotionBlur ? 1.0f : 0.0f; camera->PostProcessSettings.MotionBlurAmount = gameSettings->bUseMotionBlur ? 1.0f : 0.0f;
} }
playerController = Cast<APlayerController>(GetController());
if(playerController)
{
if(auto inputSubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(playerController->GetLocalPlayer()))
{
if(auto GI = Cast<UCustomGameInstanceBase>(GetWorld()->GetGameInstance()))
{
inputSubsystem->ClearAllMappings();
for(auto& inputContext : GI->inputContexts)
{
inputSubsystem->AddMappingContext(inputContext.LoadSynchronous(), 0);
}
}
}
inputComponent = Cast<UEnhancedInputComponent>(playerController->InputComponent);
if(inputComponent)
{
((UInputComponent*)inputComponent)->BindAction(TEXT("AnyKey"), IE_Pressed, this, &APlayerBase::OnAnyKeyPressed);
((UInputComponent*)inputComponent)->BindAction(TEXT("AnyKey"), IE_Released, this, &APlayerBase::OnAnyKeyReleased);
}
}
LoadInteractablesActivators(); LoadInteractablesActivators();
} }
void APlayerBase::OnAnyKeyPressed(FKey key)
{
if(onAnyKeyPressedDelegate.IsBound())
onAnyKeyPressedDelegate.Broadcast(key);
}
void APlayerBase::OnAnyKeyReleased(FKey key)
{
if(onAnyKeyReleasedDelegate.IsBound())
onAnyKeyReleasedDelegate.Broadcast(key);
}
bool APlayerBase::IsMoving() bool APlayerBase::IsMoving()
{ {
return bIsMoving; return bIsMoving;
@ -142,7 +114,7 @@ void APlayerBase::LockPlayer(FPlayerLock lock)
inventoryLocked += lock.inventory; inventoryLocked += lock.inventory;
if(interactionLocked) if(interactionLocked)
ResetIntractions(); ResetInteractions();
} }
void APlayerBase::UnlockPlayer(FPlayerLock lock) void APlayerBase::UnlockPlayer(FPlayerLock lock)
@ -155,7 +127,7 @@ void APlayerBase::UnlockPlayer(FPlayerLock lock)
inventoryLocked -= lock.inventory; inventoryLocked -= lock.inventory;
if(!interactionLocked) if(!interactionLocked)
ResetIntractions(); ResetInteractions();
} }
void APlayerBase::FlyMode(bool on) void APlayerBase::FlyMode(bool on)
@ -163,7 +135,7 @@ void APlayerBase::FlyMode(bool on)
GetCharacterMovement()->GravityScale = on ? 0.0f : 1.0f; GetCharacterMovement()->GravityScale = on ? 0.0f : 1.0f;
} }
void APlayerBase::ResetIntractions() void APlayerBase::ResetInteractions()
{ {
InteractableDeactivated(lastInteractable, static_cast<EActivatorType>(0xFF)); InteractableDeactivated(lastInteractable, static_cast<EActivatorType>(0xFF));
for(auto activator : interactableActivators) for(auto activator : interactableActivators)
@ -257,14 +229,17 @@ void APlayerBase::UpdatePitch(float min, float max)
void APlayerBase::LoadInteractablesActivators() void APlayerBase::LoadInteractablesActivators()
{ {
if(auto GI = Cast<UCustomGameInstanceBase>(GetWorld()->GetGameInstance()))
{
TSet<UClass*> instancedActivators; TSet<UClass*> instancedActivators;
for(auto& act : GI->interactionsActivators) for(auto& act : AInteractable::interactionActivators)
{ {
if(instancedActivators.Contains(act)) if(act.Get())
if(auto obj = Cast<UInteractableActivator>(act.Get()->GetDefaultObject()))
if(!obj->AutoInstantiateInPlayer())
continue; continue;
instancedActivators.Add(act);
if(instancedActivators.Contains(act.Get()))
continue;
instancedActivators.Add(act.Get());
auto component = NewObject<UInteractableActivator>(this, act); auto component = NewObject<UInteractableActivator>(this, act);
component->interactableActivatedDelegate.BindUObject(this, &APlayerBase::InteractableActivated); component->interactableActivatedDelegate.BindUObject(this, &APlayerBase::InteractableActivated);
@ -273,7 +248,6 @@ void APlayerBase::LoadInteractablesActivators()
component->RegisterComponent(); component->RegisterComponent();
interactableActivators.Add(component); interactableActivators.Add(component);
} }
}
} }
void APlayerBase::InteractableActivated(AInteractable* interactable, EActivatorType type) void APlayerBase::InteractableActivated(AInteractable* interactable, EActivatorType type)
@ -284,7 +258,7 @@ void APlayerBase::InteractableActivated(AInteractable* interactable, EActivatorT
if(interactionLocked || interactable->IsHidden()) if(interactionLocked || interactable->IsHidden())
return; return;
interactable->_Activate(type); interactable->Activate(type);
if(interactable != lastInteractable) if(interactable != lastInteractable)
lastInteractable = interactable; lastInteractable = interactable;
@ -295,7 +269,7 @@ void APlayerBase::InteractableDeactivated(AInteractable* interactable, EActivato
if(!interactable) if(!interactable)
return; return;
interactable->_Deactivate(type); interactable->Deactivate(type);
if(interactable->GetActivatedFlags() == 0) if(interactable->GetActivatedFlags() == 0)
lastInteractable = nullptr; lastInteractable = nullptr;

View File

@ -8,10 +8,9 @@
enum class EActivatorType : uint8; enum class EActivatorType : uint8;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FPlayerAnyKeyPressedDelegate, FKey, key); /**
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FPlayerAnyKeyReleasedDelegate, FKey, key); * Bit collection of player locks.
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FPlayerMovedDelegate); */
USTRUCT(BlueprintType) USTRUCT(BlueprintType)
struct FPlayerLock struct FPlayerLock
{ {
@ -27,17 +26,27 @@ struct FPlayerLock
static FPlayerLock All(); static FPlayerLock All();
}; };
/**
* Base class for player pawn.
* Synchronizes movement speed with fps, manages camera and inventory,
* prepares for work with interactables, and manages basic player input.
*/
UCLASS(Blueprintable, BlueprintType) UCLASS(Blueprintable, BlueprintType)
class APlayerBase : public ACharacter class APlayerBase : public ACharacter
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
/** setup input context, camera and inventory */
APlayerBase(); APlayerBase();
virtual void Tick(float DeltaTime) override; virtual void Tick(float DeltaTime) override;
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Player Base Pawn"))
static APlayerBase* Get();
UFUNCTION(BlueprintPure) UFUNCTION(BlueprintPure)
bool IsMoving(); bool IsMoving();
UFUNCTION(BlueprintPure) UFUNCTION(BlueprintPure)
@ -48,38 +57,35 @@ public:
void LockPlayer(const FPlayerLock lock); void LockPlayer(const FPlayerLock lock);
void UnlockPlayer(const FPlayerLock lock); void UnlockPlayer(const FPlayerLock lock);
void FlyMode(bool on); void FlyMode(bool on);
void ResetIntractions();
/** Force interactable activators reset */
void ResetInteractions();
/** Switch camera possesion to passed Actor */
UFUNCTION(BlueprintCallable, Category = Character) UFUNCTION(BlueprintCallable, Category = Character)
void SwitchToView(class AActor* target); void SwitchToView(class AActor* target);
/** Posess player camera */
UFUNCTION(BlueprintCallable, Category = Character) UFUNCTION(BlueprintCallable, Category = Character)
void ReturnPlayerView(); void ReturnPlayerView();
/** Place item into first inventory */
UFUNCTION(BlueprintCallable, Category = Character) UFUNCTION(BlueprintCallable, Category = Character)
void TakeItemToLeftHand(class AActor* actor); void TakeItemToLeftHand(class AActor* actor);
/** Place item into second inventory */
UFUNCTION(BlueprintCallable, Category = Character) UFUNCTION(BlueprintCallable, Category = Character)
void TakeItemToRightHand(class AActor* actor); void TakeItemToRightHand(class AActor* actor);
/** Check if Actor is in inventory */
UFUNCTION(BlueprintCallable, Category = Character) UFUNCTION(BlueprintCallable, Category = Character)
bool IsInInventory(const class AActor* actor); bool IsInInventory(const class AActor* actor);
UPROPERTY(BlueprintAssignable)
FPlayerMovedDelegate OnPlayerMoved;
FVector moveVector; FVector moveVector;
FPlayerAnyKeyPressedDelegate onAnyKeyPressedDelegate;
FPlayerAnyKeyReleasedDelegate onAnyKeyReleasedDelegate;
class UEnhancedInputComponent* inputComponent = nullptr;
class AActor* leftPocketItem = nullptr; class AActor* leftPocketItem = nullptr;
class AActor* rightPocketItem = nullptr; class AActor* rightPocketItem = nullptr;
protected: protected:
virtual void BeginPlay() override; virtual void BeginPlay() override;
void OnAnyKeyPressed(FKey key);
void OnAnyKeyReleased(FKey key);
UFUNCTION(BlueprintCallable, Category = CameraMode) UFUNCTION(BlueprintCallable, Category = CameraMode)
void SwitchToCameraPawn(); void SwitchToCameraPawn();
@ -91,6 +97,7 @@ protected:
UFUNCTION(BlueprintCallable, Category = Character) UFUNCTION(BlueprintCallable, Category = Character)
void SwitchRun(bool run); void SwitchRun(bool run);
/** Sets camera pitch range */
UFUNCTION(BlueprintCallable, Category = Character) UFUNCTION(BlueprintCallable, Category = Character)
void UpdatePitch(float min, float max); void UpdatePitch(float min, float max);
@ -153,4 +160,6 @@ private:
bool itemDropLocked = false; bool itemDropLocked = false;
FTimerHandle itemDropLockTimer; FTimerHandle itemDropLockTimer;
TSoftObjectPtr<class UInputMappingContext> context;
}; };

View File

@ -1,29 +1,19 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "QuestManager.h" #include "QuestManager.h"
#include "Kismet/GameplayStatics.h"
#include "Levels/LevelBase.h"
#include "MainGameModeBase.h" #include "MainGameModeBase.h"
#include "Widgets/WidgetsManager.h" #include "Widgets/WidgetsManager.h"
void AQuestManager::BeginPlay() void AQuestManager::BeginPlay()
{ {
if(auto gamemode_base = UGameplayStatics::GetGameMode(GetWorld())) if(auto gamemode = AMainGameModeBase::Get())
{
gamemode = Cast<AMainGameModeBase>(gamemode_base);
if(gamemode)
{
gamemode->questsUpdateDelegate.AddDynamic(this, &AQuestManager::Update); gamemode->questsUpdateDelegate.AddDynamic(this, &AQuestManager::Update);
}
}
} }
void AQuestManager::EndPlay(const EEndPlayReason::Type EndPlayReason) void AQuestManager::EndPlay(const EEndPlayReason::Type EndPlayReason)
{ {
if(gamemode) if(auto gamemode = AMainGameModeBase::Get())
gamemode->questsUpdateDelegate.RemoveDynamic(this, &AQuestManager::Update); gamemode->questsUpdateDelegate.RemoveDynamic(this, &AQuestManager::Update);
} }

View File

@ -6,6 +6,9 @@
#include "QuestManager.generated.h" #include "QuestManager.generated.h"
/**
* "Manages" quests. In fact takes string rows from a level and push them to Journal widget.
*/
UCLASS(Blueprintable, BlueprintType) UCLASS(Blueprintable, BlueprintType)
class AQuestManager : public AActor class AQuestManager : public AActor
{ {
@ -21,6 +24,4 @@ protected:
UFUNCTION() UFUNCTION()
void Update(TArray<FText> quests); void Update(TArray<FText> quests);
class AMainGameModeBase* gamemode = nullptr;
}; };

View File

@ -1,11 +1,11 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "QuickTimeEvent.h" #include "QuickTimeEvent.h"
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
#include "CommonFunctions.h" #include "CommonFunctions.h"
#include "CustomPlayerController.h"
#include "MainGameModeBase.h" #include "MainGameModeBase.h"
#include "PlayerBase.h" #include "PlayerBase.h"
#include "Widgets/WidgetsManager.h" #include "Widgets/WidgetsManager.h"
@ -14,7 +14,7 @@ int32 Event::counter = 0;
Event::Event() Event::Event()
{ {
_id = counter++; id = counter++;
} }
Event::Event(EQuickTimeEventType type, FKey& key, FQuickTimeEventEndCallback& callback, bool sequence) Event::Event(EQuickTimeEventType type, FKey& key, FQuickTimeEventEndCallback& callback, bool sequence)
@ -28,14 +28,14 @@ Event::Event(EQuickTimeEventType type, FKey& key, FQuickTimeEventEndCallback& ca
inline int32 Event::GetId() inline int32 Event::GetId()
{ {
return _id; return id;
} }
void UQuickTimeEventManager::ShowQuickTimeEvent(FQuickTimeEventEnqueProperties properties) void UQuickTimeEventManager::ShowQuickTimeEvent(FQuickTimeEventEnqueProperties properties)
{ {
UE_LOG(LogTemp, Log, TEXT("ShowQuickTimeEvent Start")); UE_LOG(LogTemp, Log, TEXT("ShowQuickTimeEvent Start"));
OnFirstEventInit(); OnFirstEventInit();
FScopeLock lock1(&_lock); FScopeLock lock1(&lock);
CreateEvent(properties, false); CreateEvent(properties, false);
UE_LOG(LogTemp, Log, TEXT("ShowQuickTimeEvent End")); UE_LOG(LogTemp, Log, TEXT("ShowQuickTimeEvent End"));
} }
@ -45,8 +45,8 @@ void UQuickTimeEventManager::EnqueQuickTimeEvent(FQuickTimeEventEnqueProperties
UE_LOG(LogTemp, Log, TEXT("EnqueQuickTimeEvent Start")); UE_LOG(LogTemp, Log, TEXT("EnqueQuickTimeEvent Start"));
OnFirstEventInit(); OnFirstEventInit();
{ {
FScopeLock lock1(&_lock); FScopeLock lock1(&lock);
_nextEvents.Enqueue(properties); nextEvents.Enqueue(properties);
} }
ShowNextEvent(); ShowNextEvent();
UE_LOG(LogTemp, Log, TEXT("EnqueQuickTimeEvent End")); UE_LOG(LogTemp, Log, TEXT("EnqueQuickTimeEvent End"));
@ -55,9 +55,9 @@ void UQuickTimeEventManager::EnqueQuickTimeEvent(FQuickTimeEventEnqueProperties
void UQuickTimeEventManager::ShowNextEvent() void UQuickTimeEventManager::ShowNextEvent()
{ {
UE_LOG(LogTemp, Log, TEXT("ShowNextEvent Start")); UE_LOG(LogTemp, Log, TEXT("ShowNextEvent Start"));
FScopeLock lock1(&_lock); FScopeLock lock1(&lock);
FQuickTimeEventEnqueProperties properties; FQuickTimeEventEnqueProperties properties;
_nextEvents.Dequeue(properties); nextEvents.Dequeue(properties);
CreateEvent(properties, true); CreateEvent(properties, true);
UE_LOG(LogTemp, Log, TEXT("ShowNextEvent End")); UE_LOG(LogTemp, Log, TEXT("ShowNextEvent End"));
} }
@ -65,9 +65,9 @@ void UQuickTimeEventManager::ShowNextEvent()
void UQuickTimeEventManager::OnEventEnd(int32 id, EQuickTimeEventResult result) void UQuickTimeEventManager::OnEventEnd(int32 id, EQuickTimeEventResult result)
{ {
UE_LOG(LogTemp, Log, TEXT("OnEventEnd Start")); UE_LOG(LogTemp, Log, TEXT("OnEventEnd Start"));
FScopeLock lock1(&_lock); FScopeLock lock1(&lock);
Event event; Event event;
if(!_events.RemoveAndCopyValue(id, event)) if(!events.RemoveAndCopyValue(id, event))
return; return;
GetWorld()->GetTimerManager().ClearTimer(event.timer); GetWorld()->GetTimerManager().ClearTimer(event.timer);
@ -75,19 +75,19 @@ void UQuickTimeEventManager::OnEventEnd(int32 id, EQuickTimeEventResult result)
if(event.callback.IsBound()) if(event.callback.IsBound())
event.callback.Execute(result); event.callback.Execute(result);
if(event.sequence && !_nextEvents.IsEmpty()) if(event.sequence && !nextEvents.IsEmpty())
{ {
ShowNextEvent(); ShowNextEvent();
UE_LOG(LogTemp, Log, TEXT("OnEventEnd End")); UE_LOG(LogTemp, Log, TEXT("OnEventEnd End"));
return; return;
} }
if(_events.IsEmpty()) if(events.IsEmpty())
{ {
if(auto player = UCommonFunctions::GetPlayer(this)) if(auto PC = ACustomPlayerController::Get())
{ {
player->onAnyKeyPressedDelegate.RemoveDynamic(this, &UQuickTimeEventManager::OnInputPressed); PC->onAnyKeyPressed.RemoveDynamic(this, &UQuickTimeEventManager::OnInputPressed);
player->onAnyKeyReleasedDelegate.RemoveDynamic(this, &UQuickTimeEventManager::OnInputReleased); PC->onAnyKeyReleased.RemoveDynamic(this, &UQuickTimeEventManager::OnInputReleased);
} }
UCommonFunctions::ExitSlowMotion(); UCommonFunctions::ExitSlowMotion();
} }
@ -96,10 +96,11 @@ void UQuickTimeEventManager::OnEventEnd(int32 id, EQuickTimeEventResult result)
void UQuickTimeEventManager::OnInput(const FKey& key, bool released) void UQuickTimeEventManager::OnInput(const FKey& key, bool released)
{ {
for(auto eventMapping : _events) for(auto eventMapping : events)
{
if(eventMapping.Value.key == key)
{ {
if(eventMapping.Value.key != key)
continue;
EQuickTimeEventResult result = EQuickTimeEventResult::Success; EQuickTimeEventResult result = EQuickTimeEventResult::Success;
if(auto WM = AMainGameModeBase::GetWidgetsManager()) if(auto WM = AMainGameModeBase::GetWidgetsManager())
@ -119,23 +120,22 @@ void UQuickTimeEventManager::OnInput(const FKey& key, bool released)
OnEventEnd(eventMapping.Key, result); OnEventEnd(eventMapping.Key, result);
return; return;
} }
}
if(released) if(released)
return; return;
if(auto WM = AMainGameModeBase::GetWidgetsManager()) if(auto WM = AMainGameModeBase::GetWidgetsManager())
{ {
while(_events.Num() > 0) while(events.Num() > 0)
{ {
WM->RemoveQuickTimeEvent(_events.begin()->Key); WM->RemoveQuickTimeEvent(events.begin()->Key);
OnEventEnd(_events.begin()->Key, EQuickTimeEventResult::FailedKey); OnEventEnd(events.begin()->Key, EQuickTimeEventResult::FailedKey);
} }
} }
else else
{ {
while(_events.Num() > 0) while(events.Num() > 0)
OnEventEnd(_events.begin()->Key, EQuickTimeEventResult::FailedKey); OnEventEnd(events.begin()->Key, EQuickTimeEventResult::FailedKey);
} }
} }
@ -151,31 +151,31 @@ void UQuickTimeEventManager::OnInputReleased(FKey key)
void UQuickTimeEventManager::OnFirstEventInit() void UQuickTimeEventManager::OnFirstEventInit()
{ {
if(_events.IsEmpty()) if(!events.IsEmpty())
return;
if(auto PC = ACustomPlayerController::Get())
{ {
if(auto player = UCommonFunctions::GetPlayer(this)) GetWorld()->GetTimerManager().SetTimerForNextTick([=, this]()
{ {
GetWorld()->GetTimerManager().SetTimerForNextTick([manager = this, player = player]() PC->onAnyKeyPressed.AddDynamic(this, &UQuickTimeEventManager::OnInputPressed);
{ PC->onAnyKeyReleased.AddDynamic(this, &UQuickTimeEventManager::OnInputReleased);
player->onAnyKeyPressedDelegate.AddDynamic(manager, &UQuickTimeEventManager::OnInputPressed);
player->onAnyKeyReleasedDelegate.AddDynamic(manager, &UQuickTimeEventManager::OnInputReleased);
}); });
} }
UCommonFunctions::EnterSlowMotion(); UCommonFunctions::EnterSlowMotion();
}
} }
void UQuickTimeEventManager::CreateEvent(FQuickTimeEventEnqueProperties& properties, bool sequence) void UQuickTimeEventManager::CreateEvent(FQuickTimeEventEnqueProperties& properties, bool sequence)
{ {
Event event{ properties.type, properties.key, properties.callback, sequence }; Event event{ properties.type, properties.key, properties.callback, sequence };
GetWorld()->GetTimerManager().SetTimer(event.timer, [id = event.GetId(), manager = this]() GetWorld()->GetTimerManager().SetTimer(event.timer, [id = event.GetId(), this]()
{ {
EQuickTimeEventResult result = EQuickTimeEventResult::FailedTime; EQuickTimeEventResult result = EQuickTimeEventResult::FailedTime;
if(auto WM = AMainGameModeBase::GetWidgetsManager()) if(auto WM = AMainGameModeBase::GetWidgetsManager())
result = WM->RemoveQuickTimeEvent(id); result = WM->RemoveQuickTimeEvent(id);
manager->OnEventEnd(id, result); this->OnEventEnd(id, result);
}, properties.duration, false); }, properties.duration, false);
_events.Add(event.GetId(), event); events.Add(event.GetId(), event);
if(auto WM = AMainGameModeBase::GetWidgetsManager()) if(auto WM = AMainGameModeBase::GetWidgetsManager())
WM->ShowQuickTimeEvent(event.GetId(), properties); WM->ShowQuickTimeEvent(event.GetId(), properties);

View File

@ -60,7 +60,7 @@ public:
bool sequence; bool sequence;
private: private:
int32 _id; int32 id;
static int32 counter; static int32 counter;
}; };
@ -89,7 +89,7 @@ protected:
void OnFirstEventInit(); void OnFirstEventInit();
void CreateEvent(FQuickTimeEventEnqueProperties& properties, bool sequence); void CreateEvent(FQuickTimeEventEnqueProperties& properties, bool sequence);
TQueue<FQuickTimeEventEnqueProperties> _nextEvents; TQueue<FQuickTimeEventEnqueProperties> nextEvents;
TMap<int32, Event> _events; TMap<int32, Event> events;
FCriticalSection _lock; FCriticalSection lock;
}; };

View File

@ -6,18 +6,24 @@
#include "SaveData.generated.h" #include "SaveData.generated.h"
/**
* Custom game save object
*/
UCLASS(BlueprintType) UCLASS(BlueprintType)
class USaveData : public USaveGame class USaveData : public USaveGame
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
/** Level to load */
UPROPERTY(VisibleAnywhere) UPROPERTY(VisibleAnywhere)
FName level; FName level;
/** State of the level */
UPROPERTY(VisibleAnywhere) UPROPERTY(VisibleAnywhere)
int32 state; int32 state;
/** Checkpoint object name in level */
UPROPERTY(VisibleAnywhere) UPROPERTY(VisibleAnywhere)
FName checkpoint; FName checkpoint;

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "AutohideWidget.h" #include "AutohideWidget.h"
#include "Animation/WidgetAnimation.h" #include "Animation/WidgetAnimation.h"

View File

@ -6,6 +6,9 @@
#include "AutohideWidget.generated.h" #include "AutohideWidget.generated.h"
/**
* Automatically hides itself after some period
*/
UCLASS() UCLASS()
class UAutohideWidget : public UResolutionResponsiveUserWidget class UAutohideWidget : public UResolutionResponsiveUserWidget
{ {

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "DialogueRowWidgetManager.h" #include "DialogueRowWidgetManager.h"
#include "Blueprint/WidgetTree.h" #include "Blueprint/WidgetTree.h"

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "InteractableHintWidgetManager.h" #include "InteractableHintWidgetManager.h"
#include "Blueprint/WidgetTree.h" #include "Blueprint/WidgetTree.h"
@ -23,10 +22,10 @@ void UInteractableHintWidgetManager::Append(const UInteractableModificator* modi
return; return;
} }
if(hintsMap.Contains(modificator) || !modificator->GetMappingContext()) if(hintsMap.Contains(modificator) || !modificator->GetMappingContext().IsValid())
return; return;
const auto& mappings = modificator->GetMappingContext()->GetMappings(); const auto& mappings = modificator->GetMappingContext().LoadSynchronous()->GetMappings();
for(int32 i = hints->GetChildrenCount() - count - mappings.Num(); i < 0; ++i) for(int32 i = hints->GetChildrenCount() - count - mappings.Num(); i < 0; ++i)
{ {

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "JournalWidget.h" #include "JournalWidget.h"
#include "Blueprint/WidgetTree.h" #include "Blueprint/WidgetTree.h"

View File

@ -1,5 +1,4 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "MainMenuButtonWidget.h" #include "MainMenuButtonWidget.h"

View File

@ -1,11 +1,10 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "MainMenuWidget.h" #include "MainMenuWidget.h"
#include "Animation/WidgetAnimation.h" #include "Animation/WidgetAnimation.h"
#include "CustomGameInstanceBase.h" #include "CustomGameInstance.h"
#include "MainGameModeBase.h" #include "MainGameModeBase.h"
#include "MainMenuButtonWidget.h" #include "MainMenuButtonWidget.h"
#include "Widgets/WidgetsManager.h" #include "Widgets/WidgetsManager.h"
@ -14,15 +13,13 @@ bool UMainMenuWidget::Initialize()
{ {
if(ButtonLoadLastSave) if(ButtonLoadLastSave)
{ {
if(auto GI = UCustomGameInstanceBase::GetGameInstance()) auto GI = UCustomGameInstance::Get();
{ if(GI && GI->saveData)
if(GI->saveData)
{ {
ButtonLoadLastSave->SetIsEnabled(true); ButtonLoadLastSave->SetIsEnabled(true);
ButtonLoadLastSave->SetRenderOpacity(1.0f); ButtonLoadLastSave->SetRenderOpacity(1.0f);
} }
} }
}
//FWidgetAnimationDynamicEvent closeFinished; //FWidgetAnimationDynamicEvent closeFinished;
//closeFinished.BindDynamic(this, &UMainMenuWidget::Closed); //closeFinished.BindDynamic(this, &UMainMenuWidget::Closed);

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "QuickTimeEventWidget.h" #include "QuickTimeEventWidget.h"
#include "Animation/WidgetAnimation.h" #include "Animation/WidgetAnimation.h"

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "QuickTimeEventWidgetManager.h" #include "QuickTimeEventWidgetManager.h"
#include "Animation/UMGSequencePlayer.h" #include "Animation/UMGSequencePlayer.h"

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "ResolutionResponsiveUserWidget.h" #include "ResolutionResponsiveUserWidget.h"
#include "Components/PanelSlot.h" #include "Components/PanelSlot.h"

View File

@ -3,17 +3,18 @@
#pragma once #pragma once
#include "Blueprint/UserWidget.h" #include "Blueprint/UserWidget.h"
#include "CoreMinimal.h"
#include "ResolutionResponsiveUserWidget.generated.h" #include "ResolutionResponsiveUserWidget.generated.h"
/**
* Automatically scale itself for current resolution to keep UI sizes universal.
*/
UCLASS() UCLASS()
class UResolutionResponsiveUserWidget : public UUserWidget class UResolutionResponsiveUserWidget : public UUserWidget
{ {
GENERATED_BODY() GENERATED_BODY()
public: public:
//UResolutionResponsiveUserWidget(const FObjectInitializer& ObjectInitializer);
virtual bool Initialize() override; virtual bool Initialize() override;
virtual void BeginDestroy() override; virtual void BeginDestroy() override;

Some files were not shown because too many files have changed in this diff Show More