GameSettings, GameInstance, Widgets, Others...

This commit is contained in:
Oleg Petruny 2024-12-14 01:16:12 +01:00
parent 3d69749caf
commit ac44138607
45 changed files with 494 additions and 440 deletions

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.

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 "CustomGameUserSettings.h" #include "CustomGameSettings.h"
#include "CustomPlayerController.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,13 +28,14 @@ void ACameraModeBase::BeginPlay()
auto world = GetWorld(); auto world = GetWorld();
auto gameSettings = UCustomGameUserSettings::GetCustomGameUserSettings(); if(auto gameSettings = UCustomGameSettings::Get())
{
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;
} }
} }
}
void ACameraModeBase::Tick(float DeltaTime) void ACameraModeBase::Tick(float DeltaTime)
{ {
@ -48,14 +52,9 @@ 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

@ -86,7 +86,7 @@ void UCommonFunctions::EnterSlowMotion(float duration)
SlowMotion::targetDilation = SlowMotion::slowDilation; SlowMotion::targetDilation = SlowMotion::slowDilation;
auto GI = UCustomGameInstance::GetGameInstance(); auto GI = UCustomGameInstance::Get();
if(!GI) if(!GI)
return; return;
@ -101,7 +101,7 @@ void UCommonFunctions::ExitSlowMotion(float duration)
SlowMotion::targetDilation = SlowMotion::normalDilation; SlowMotion::targetDilation = SlowMotion::normalDilation;
auto GI = UCustomGameInstance::GetGameInstance(); auto GI = UCustomGameInstance::Get();
if(!GI) if(!GI)
return; return;
@ -116,7 +116,7 @@ FWorldDilationChangedDelegate& UCommonFunctions::GetWorldDilationChangedDelegate
void UCommonFunctions::SlowMotionTick() void UCommonFunctions::SlowMotionTick()
{ {
const UWorld* world = UCustomGameInstance::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

@ -22,14 +22,14 @@ void UCustomGameInstance::Init()
saveData = Cast<USaveData>(UGameplayStatics::CreateSaveGameObject(USaveData::StaticClass())); saveData = Cast<USaveData>(UGameplayStatics::CreateSaveGameObject(USaveData::StaticClass()));
} }
UCustomGameInstance* UCustomGameInstance::GetGameInstance() UCustomGameInstance* UCustomGameInstance::Get()
{ {
return instance; return instance;
} }
UContentLoader* UCustomGameInstance::GetContentLoader() UContentLoader* UCustomGameInstance::GetContentLoader()
{ {
if(auto GI = GetGameInstance()) if(auto GI = Get())
return GI->contentLoader; return GI->contentLoader;
return nullptr; return nullptr;

View File

@ -21,8 +21,8 @@ public:
/** Instantiates content loader, dummy save data and applies settings */ /** 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 UCustomGameInstance* GetGameInstance(); static UCustomGameInstance* Get();
UFUNCTION(BlueprintPure) UFUNCTION(BlueprintPure)
static class UContentLoader* GetContentLoader(); static class UContentLoader* GetContentLoader();

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

@ -7,18 +7,26 @@
#include "EnhancedInputSubsystems.h" #include "EnhancedInputSubsystems.h"
#include "InputMappingContext.h" #include "InputMappingContext.h"
#include "CustomGameUserSettings.h" #include "CustomGameInstance.h"
#include "CustomGameSettings.h"
ACustomPlayerController* ACustomPlayerController::instance = nullptr; ACustomPlayerController* ACustomPlayerController::instance = nullptr;
UEnhancedInputLocalPlayerSubsystem* ACustomPlayerController::subsystem = nullptr;
UEnhancedInputComponent* ACustomPlayerController::input = nullptr; UEnhancedInputComponent* ACustomPlayerController::input = nullptr;
UEnhancedInputLocalPlayerSubsystem* ACustomPlayerController::subsystem = nullptr;
TSet<TSoftObjectPtr<UInputMappingContext>> ACustomPlayerController::contexts = {}; TSet<TSoftObjectPtr<UInputMappingContext>> ACustomPlayerController::contexts = {};
TSet<TSoftObjectPtr<UInputMappingContext>> ACustomPlayerController::contextsBeforeInit = {};
void ACustomPlayerController::AppendInputContext(TSoftObjectPtr<class UInputMappingContext> context) void ACustomPlayerController::AppendInputContext(TSoftObjectPtr<class UInputMappingContext> context)
{ {
if(!context.IsValid()) if(!context.IsValid())
return; return;
if(!UCustomGameInstance::Get()) //game settings not initialized yet
{
contextsBeforeInit.Add(context);
return;
}
ApplyMouseSettings(context); ApplyMouseSettings(context);
contexts.Add(context); contexts.Add(context);
if(subsystem) if(subsystem)
@ -31,6 +39,13 @@ void ACustomPlayerController::BeginPlay()
instance = this; instance = this;
for(auto& context : contextsBeforeInit)
{
ApplyMouseSettings(context);
contexts.Add(context);
}
contextsBeforeInit.Empty();
subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()); subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer());
if(subsystem) if(subsystem)
{ {
@ -47,9 +62,18 @@ void ACustomPlayerController::BeginPlay()
} }
} }
void ACustomPlayerController::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
instance = nullptr;
input = nullptr;
subsystem = nullptr;
Super::EndPlay(EndPlayReason);
}
void ACustomPlayerController::ApplyMouseSettings(TSoftObjectPtr<class UInputMappingContext>& context) void ACustomPlayerController::ApplyMouseSettings(TSoftObjectPtr<class UInputMappingContext>& context)
{ {
auto gameSettings = UCustomGameUserSettings::GetCustomGameUserSettings(); auto gameSettings = UCustomGameSettings::Get();
if(!gameSettings) if(!gameSettings)
return; return;

View File

@ -35,6 +35,7 @@ public:
protected: protected:
virtual void BeginPlay() override; virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
private: private:
static void ApplyMouseSettings(TSoftObjectPtr<class UInputMappingContext>& context); static void ApplyMouseSettings(TSoftObjectPtr<class UInputMappingContext>& context);
@ -46,4 +47,6 @@ private:
static class UEnhancedInputLocalPlayerSubsystem* subsystem; static class UEnhancedInputLocalPlayerSubsystem* subsystem;
static class UEnhancedInputComponent* input; static class UEnhancedInputComponent* input;
static TSet<TSoftObjectPtr<class UInputMappingContext>> contexts; 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

@ -19,8 +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;
ACustomPlayerController::AppendInputContext(_inputContext); ACustomPlayerController::AppendInputContext(context);
} }
void UCutsceneManager::EnqueueSequence(ULevelSequence* sequence, FCutsceneEndCallback endCallback) void UCutsceneManager::EnqueueSequence(ULevelSequence* sequence, FCutsceneEndCallback endCallback)
@ -28,107 +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);
auto input = ACustomPlayerController::GetInput(); endCallbacks.Enqueue(endCallback);
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);
}
}
}
}
_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();
} }
@ -142,37 +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 });
auto input = ACustomPlayerController::GetInput(); auto input = ACustomPlayerController::GetInput();
input->RemoveBindingByHandle(_handlers.Key); input->RemoveBindingByHandle(handlers.Key);
input->RemoveBindingByHandle(_handlers.Value); 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"
@ -21,8 +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;
ACustomPlayerController::AppendInputContext(_inputContext); ACustomPlayerController::AppendInputContext(context);
} }
void UDialogueManager::PlayDialogue(FDialogueEnqueProperties properties, FDialogueEndCallback endCallback) void UDialogueManager::PlayDialogue(FDialogueEnqueProperties properties, FDialogueEndCallback endCallback)
@ -43,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();
}; };
@ -82,18 +77,96 @@ 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();
nextDialogues.Enqueue(properties);
endCallbacks.Enqueue(endCallback);
PlayNextDialogue();
}
void UDialogueManager::PlayNextDialogue()
{ {
dialoguesLock.Lock();
auto properties = nextDialogues.Peek();
TArray<FName> rows = properties->dialogue.LoadSynchronous()->GetRowNames();
if(rows.Num() == 0)
{
FDialogueEndCallback callback;
if(endCallbacks.Dequeue(callback))
callback.Execute();
nextDialogues.Pop();
return;
}
if(properties->playMode == EDialoguePlayMode::Random)
{
properties->rowName = rows[FMath::RandRange(0, rows.Num() - 1)];
}
FDialogueRow* row = reinterpret_cast<FDialogueRow*>(properties->dialogue.LoadSynchronous()->FindRowUnchecked(properties->rowName));
if(!row)
{
FDialogueEndCallback callback;
endCallbacks.Dequeue(callback);
callback.ExecuteIfBound();
nextDialogues.Pop();
return;
}
if(properties->playMode == EDialoguePlayMode::Sequential
&& !properties->rowName.ToString().IsNumeric())
{
nextDialogues.Pop();
FDialogueEndCallback callback;
if(endCallbacks.Dequeue(callback))
callback.Execute();
return;
}
if(row->wave.LoadSynchronous())
leadDialogueAudio = UGameplayStatics::SpawnSound2D(this, row->wave.LoadSynchronous());
else
leadDialogueAudio = nullptr;
if(auto WM = AMainGameModeBase::GetWidgetsManager())
WM->ShowDialogueWidget(*row);
FTimerHandle timer;
int32 timerId;
const float duration = row->wave ? row->wave->GetDuration() : row->duration;
GetWorld()->GetTimerManager().SetTimer(timer, [&]() { OnDialogueEnd(); }, duration, false);
timersLock.Lock();
timerId = timers.Num();
timers.Add(timer);
timersLock.Unlock();
leadDialogueTimerId = timerId;
leadDialogueProperties = properties;
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)) if(auto PC = UGameplayStatics::GetPlayerController(GetWorld(), 0))
{ {
_lastPlayer = Cast<APlayerBase>(PC->GetPawn()); lastPlayer = Cast<APlayerBase>(PC->GetPawn());
if(_lastPlayer) if(lastPlayer)
{ {
auto& mapping = _inputContext.LoadSynchronous()->GetMapping(0); auto& mapping = context.LoadSynchronous()->GetMapping(0);
_inputHandler = ACustomPlayerController::GetInput()->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &UDialogueManager::OnInputPress).GetHandle(); inputHandler = ACustomPlayerController::GetInput()->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &UDialogueManager::OnInputPress).GetHandle();
if(auto WM = AMainGameModeBase::GetWidgetsManager()) if(auto WM = AMainGameModeBase::GetWidgetsManager())
{ {
@ -108,93 +181,16 @@ void UDialogueManager::EnqueDialogue(FDialogueEnqueProperties properties, FDialo
} }
} }
_nextDialogues.Enqueue(properties);
_endCallbacks.Enqueue(endCallback);
PlayNextDialogue();
}
void UDialogueManager::PlayNextDialogue()
{
_dialoguesLock.Lock();
auto properties = _nextDialogues.Peek();
TArray<FName> rows = properties->dialogue.LoadSynchronous()->GetRowNames();
if(rows.Num() == 0)
{
FDialogueEndCallback callback;
if(_endCallbacks.Dequeue(callback))
callback.Execute();
_nextDialogues.Pop();
return;
}
if(properties->playMode == EDialoguePlayMode::Random)
{
properties->rowName = rows[FMath::RandRange(0, rows.Num() - 1)];
}
FDialogueRow* row = reinterpret_cast<FDialogueRow*>(properties->dialogue.LoadSynchronous()->FindRowUnchecked(properties->rowName));
if(!row)
{
FDialogueEndCallback callback;
_endCallbacks.Dequeue(callback);
callback.ExecuteIfBound();
_nextDialogues.Pop();
return;
}
if(properties->playMode == EDialoguePlayMode::Sequential)
{
if(!properties->rowName.ToString().IsNumeric())
{
_nextDialogues.Pop();
FDialogueEndCallback callback;
if(_endCallbacks.Dequeue(callback))
callback.Execute();
return;
}
}
if(row->wave.LoadSynchronous())
leadDialogueAudio = UGameplayStatics::SpawnSound2D(this, row->wave.LoadSynchronous());
else
leadDialogueAudio = nullptr;
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->ShowDialogueWidget(*row);
}
FTimerHandle timer;
int32 timerId;
const float duration = row->wave ? row->wave->GetDuration() : row->duration;
GetWorld()->GetTimerManager().SetTimer(timer, [&]() { OnDialogueEnd(); }, duration, false);
_timersLock.Lock();
timerId = _timers.Num();
_timers.Add(timer);
_timersLock.Unlock();
leadDialogueTimerId = timerId;
leadDialogueProperties = properties;
_dialoguesLock.Unlock();
}
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();
@ -204,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();
@ -230,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)
{ {
ACustomPlayerController::GetInput()->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

@ -3,6 +3,7 @@
#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)

View File

@ -7,20 +7,17 @@
#include "Interactable/Interactable.h" #include "Interactable/Interactable.h"
#include "PlayerBase.h" #include "PlayerBase.h"
void UInteractableActivator::OnRegister()
{
Super::OnRegister();
AInteractable::AppendInteractableActivatorClass(GetClass());
}
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

@ -21,8 +21,6 @@ class UInteractableActivator : public USceneComponent
public: public:
/** Append itself to CustomGameInstance modificators registry */ /** Append itself to CustomGameInstance modificators registry */
virtual void OnRegister() override;
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;
@ -31,7 +29,7 @@ public:
/** Resets activator state forcing to rescan */ /** 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() PURE_VIRTUAL(UInteractableActivator::Scan_Implementation, ); virtual void Rescan_Implementation() {}
FInteractableActivated interactableActivatedDelegate; FInteractableActivated interactableActivatedDelegate;
FInteractableActivated interactableDeactivatedDelegate; FInteractableActivated interactableDeactivatedDelegate;

View File

@ -14,18 +14,21 @@
TSet<TSubclassOf<class UInteractableActivator>> AInteractable::interactionActivators = {}; TSet<TSubclassOf<class UInteractableActivator>> AInteractable::interactionActivators = {};
TSet<TSubclassOf<class UInteractableModificator>> AInteractable::interactionModificators = {}; TSet<TSubclassOf<class UInteractableModificator>> AInteractable::interactionModificators = {};
void AInteractable::AppendInteractableActivatorClass(TSubclassOf<class UInteractableActivator> activator) void AInteractable::AppendActivatorClass(TSubclassOf<class UInteractableActivator> activator)
{ {
if(interactionActivators.Contains(activator))
return;
interactionActivators.Add(activator); interactionActivators.Add(activator);
} }
void AInteractable::AppendInteractableModificatorClass(TSubclassOf<class UInteractableModificator> modificator) void AInteractable::AppendModificatorClass(TSubclassOf<class UInteractableModificator> modificator)
{ {
bool alreadyPresent = false; if(interactionModificators.Contains(modificator))
interactionModificators.Add(modificator, &alreadyPresent);
if(alreadyPresent)
return; return;
interactionModificators.Add(modificator);
auto IC = modificator.GetDefaultObject()->GetMappingContext(); auto IC = modificator.GetDefaultObject()->GetMappingContext();
ACustomPlayerController::AppendInputContext(IC); ACustomPlayerController::AppendInputContext(IC);
} }
@ -144,7 +147,7 @@ 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)
@ -179,5 +182,5 @@ void AInteractable::Deactivate(EActivatorType type)
collision->SetCustomDepthStencilValue(0); collision->SetCustomDepthStencilValue(0);
} }
Deactivate(type); OnDeactivate(type);
} }

View File

@ -40,8 +40,8 @@ class AInteractable : public AActor
GENERATED_BODY() GENERATED_BODY()
public: public:
static void AppendInteractableActivatorClass(TSubclassOf<class UInteractableActivator> activator); static void AppendActivatorClass(TSubclassOf<class UInteractableActivator> activator);
static void AppendInteractableModificatorClass(TSubclassOf<class UInteractableModificator> modificator); static void AppendModificatorClass(TSubclassOf<class UInteractableModificator> modificator);
/** Interactables shared cache */ /** Interactables shared cache */
static TSet<TSubclassOf<class UInteractableActivator>> interactionActivators; static TSet<TSubclassOf<class UInteractableActivator>> interactionActivators;

View File

@ -9,7 +9,7 @@ void UInteractableModificator::OnRegister()
{ {
UActorComponent::OnRegister(); UActorComponent::OnRegister();
AInteractable::AppendInteractableModificatorClass(GetClass()); AInteractable::AppendModificatorClass(GetClass());
} }
const TSoftObjectPtr<class UInputMappingContext> UInteractableModificator::GetMappingContext() const const TSoftObjectPtr<class UInputMappingContext> UInteractableModificator::GetMappingContext() const

View File

@ -6,6 +6,6 @@
void ACheckpoint::SaveGame() void ACheckpoint::SaveGame()
{ {
if(auto GI = UCustomGameInstance::GetGameInstance()) if(auto GI = UCustomGameInstance::Get())
GI->SaveGame(GetFName()); GI->SaveGame(GetFName());
} }

View File

@ -51,7 +51,7 @@ void ALevelBase::IterateToState(int32 to)
void ALevelBase::BroadcastNewLevelBeginPlay() void ALevelBase::BroadcastNewLevelBeginPlay()
{ {
if(auto GI = UCustomGameInstance::GetGameInstance()) if(auto GI = UCustomGameInstance::Get())
GI->OnLevelBeginned.Broadcast(GetFName()); GI->OnLevelBeginned.Broadcast(GetFName());
} }
@ -72,7 +72,7 @@ void ALevelBase::StartLevelAnimations()
void ALevelBase::ApplySaveData() void ALevelBase::ApplySaveData()
{ {
auto GI = UCustomGameInstance::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;

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 "CustomGameInstance.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

@ -10,7 +10,7 @@
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
#include "Kismet/KismetMathLibrary.h" #include "Kismet/KismetMathLibrary.h"
#include "CustomGameUserSettings.h" #include "CustomGameSettings.h"
#include "CustomPlayerController.h" #include "CustomPlayerController.h"
#include "Interactable/Activators/InteractableActivator.h" #include "Interactable/Activators/InteractableActivator.h"
#include "Interactable/Interactable.h" #include "Interactable/Interactable.h"
@ -26,6 +26,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"));
@ -75,9 +79,8 @@ 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;
} }
@ -105,7 +108,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)
@ -118,7 +121,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)
@ -126,7 +129,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)
@ -223,9 +226,9 @@ void APlayerBase::LoadInteractablesActivators()
TSet<UClass*> instancedActivators; TSet<UClass*> instancedActivators;
for(auto& act : AInteractable::interactionActivators) for(auto& act : AInteractable::interactionActivators)
{ {
if(instancedActivators.Contains(act)) if(instancedActivators.Contains(act.Get()))
continue; continue;
instancedActivators.Add(act); 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);

View File

@ -46,7 +46,7 @@ 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(); void ResetInteractions();
UFUNCTION(BlueprintCallable, Category = Character) UFUNCTION(BlueprintCallable, Category = Character)
void SwitchToView(class AActor* target); void SwitchToView(class AActor* target);
@ -143,4 +143,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,6 +1,5 @@
// Oleg Petruny proprietary. // Oleg Petruny proprietary.
#include "QuickTimeEvent.h" #include "QuickTimeEvent.h"
#include "Kismet/GameplayStatics.h" #include "Kismet/GameplayStatics.h"
@ -15,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)
@ -29,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"));
} }
@ -46,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"));
@ -56,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"));
} }
@ -66,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);
@ -76,14 +75,14 @@ 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 PC = ACustomPlayerController::Get()) if(auto PC = ACustomPlayerController::Get())
{ {
@ -97,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())
@ -120,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);
} }
} }
@ -152,8 +151,9 @@ 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 PC = ACustomPlayerController::Get())
{ {
GetWorld()->GetTimerManager().SetTimerForNextTick([=, this]() GetWorld()->GetTimerManager().SetTimerForNextTick([=, this]()
@ -164,7 +164,6 @@ void UQuickTimeEventManager::OnFirstEventInit()
} }
UCommonFunctions::EnterSlowMotion(); UCommonFunctions::EnterSlowMotion();
} }
}
void UQuickTimeEventManager::CreateEvent(FQuickTimeEventEnqueProperties& properties, bool sequence) void UQuickTimeEventManager::CreateEvent(FQuickTimeEventEnqueProperties& properties, bool sequence)
{ {
@ -176,7 +175,7 @@ void UQuickTimeEventManager::CreateEvent(FQuickTimeEventEnqueProperties& propert
result = WM->RemoveQuickTimeEvent(id); result = WM->RemoveQuickTimeEvent(id);
this->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

@ -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

@ -13,7 +13,7 @@ bool UMainMenuWidget::Initialize()
{ {
if(ButtonLoadLastSave) if(ButtonLoadLastSave)
{ {
auto GI = UCustomGameInstance::GetGameInstance(); auto GI = UCustomGameInstance::Get();
if(GI && GI->saveData) if(GI && GI->saveData)
{ {
ButtonLoadLastSave->SetIsEnabled(true); ButtonLoadLastSave->SetIsEnabled(true);

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;

View File

@ -9,6 +9,11 @@
enum class EInputAnimatedWidgetAnimation : uint8; enum class EInputAnimatedWidgetAnimation : uint8;
enum class EQuickTimeEventResult : uint8; enum class EQuickTimeEventResult : uint8;
/**
* Manager/Wrapper of most of UI widgets.
* Please, don't create your own widgets but instead append manager class and us it as upper layer.
* At Init instantiate (non)permanent overlays widgets.
*/
UCLASS(Blueprintable) UCLASS(Blueprintable)
class UWidgetsManager : public UObject class UWidgetsManager : public UObject
{ {

View File

@ -6,6 +6,9 @@
#include "WorldDilationResponsiveUserWidget.generated.h" #include "WorldDilationResponsiveUserWidget.generated.h"
/**
* Automatically update animations speed to sync with world time dilation
*/
UCLASS() UCLASS()
class UWorldDilationResponsiveUserWidget : public UUserWidget class UWorldDilationResponsiveUserWidget : public UUserWidget
{ {

View File

@ -28,4 +28,5 @@ The following packages/data aren't removed:
- Python - Python
- Visual Studio Installer - Visual Studio Installer
- voices/ - voices/
- _Something will of course left_
It's recommended to run uninstallat script as administrator and restart machine after uninstall completion. It's recommended to run uninstallat script as administrator and restart machine after uninstall completion.