Code & git cleanup #6

Merged
oleg.petruny merged 15 commits from Documentation into master 2024-12-15 13:32:54 +00:00
45 changed files with 494 additions and 440 deletions
Showing only changes of commit ac44138607 - Show all commits

View File

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

View File

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

Binary file not shown.

Binary file not shown.

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary.
#include "CameraModeBase.h"
#include "Camera/CameraComponent.h"
@ -10,12 +9,16 @@
#include "InputMappingContext.h"
#include "Kismet/GameplayStatics.h"
#include "CustomGameUserSettings.h"
#include "CustomGameSettings.h"
#include "CustomPlayerController.h"
#include "MainGameModeBase.h"
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;
}
@ -25,11 +28,12 @@ void ACameraModeBase::BeginPlay()
auto world = GetWorld();
auto gameSettings = UCustomGameUserSettings::GetCustomGameUserSettings();
if(auto camera = FindComponentByClass<UCameraComponent>())
if(auto gameSettings = UCustomGameSettings::Get())
{
camera->PostProcessSettings.MotionBlurAmount = gameSettings->bUseMotionBlur ? 1.0f : 0.0f;
if(auto camera = FindComponentByClass<UCameraComponent>())
{
camera->PostProcessSettings.MotionBlurAmount = gameSettings->bUseMotionBlur ? 1.0f : 0.0f;
}
}
}
@ -48,13 +52,8 @@ void ACameraModeBase::SetupPlayerInputComponent(UInputComponent* PlayerInputComp
void ACameraModeBase::SwitchToPlayerPawn()
{
if(auto gamemode_base = UGameplayStatics::GetGameMode(GetWorld()))
{
if(auto gamemode = Cast<AMainGameModeBase>(gamemode_base))
{
gamemode->SwitchCameraMode();
}
}
if(auto gamemode = AMainGameModeBase::Get())
gamemode->SwitchCameraMode();
}
void ACameraModeBase::ElevatePawn(float value)

View File

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

View File

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

View File

@ -21,8 +21,8 @@ public:
/** Instantiates content loader, dummy save data and applies settings */
virtual void Init() override;
UFUNCTION(BlueprintPure)
static UCustomGameInstance* GetGameInstance();
UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Custom Game Instance"))
static UCustomGameInstance* Get();
UFUNCTION(BlueprintPure)
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 "InputMappingContext.h"
#include "CustomGameUserSettings.h"
#include "CustomGameInstance.h"
#include "CustomGameSettings.h"
ACustomPlayerController* ACustomPlayerController::instance = nullptr;
UEnhancedInputLocalPlayerSubsystem* ACustomPlayerController::subsystem = 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)
@ -31,6 +39,13 @@ void ACustomPlayerController::BeginPlay()
instance = this;
for(auto& context : contextsBeforeInit)
{
ApplyMouseSettings(context);
contexts.Add(context);
}
contextsBeforeInit.Empty();
subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer());
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)
{
auto gameSettings = UCustomGameUserSettings::GetCustomGameUserSettings();
auto gameSettings = UCustomGameSettings::Get();
if(!gameSettings)
return;

View File

@ -20,7 +20,7 @@ class ACustomPlayerController : public APlayerController
GENERATED_BODY()
public:
UFUNCTION(BlueprintPure, meta = (DisplayName = "GetCustomPlayerController"))
UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Custom Player Controller"))
static ACustomPlayerController* Get() { return instance; }
UFUNCTION(BlueprintPure)
static class UEnhancedInputComponent* GetInput() { return input; }
@ -35,6 +35,7 @@ public:
protected:
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
private:
static void ApplyMouseSettings(TSoftObjectPtr<class UInputMappingContext>& context);
@ -46,4 +47,6 @@ private:
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

@ -19,8 +19,8 @@
UCutsceneManager::UCutsceneManager()
{
static ConstructorHelpers::FObjectFinder<UInputMappingContext> asset{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/IMC_Cutscene.IMC_Cutscene'") };
_inputContext = asset.Object;
ACustomPlayerController::AppendInputContext(_inputContext);
context = asset.Object;
ACustomPlayerController::AppendInputContext(context);
}
void UCutsceneManager::EnqueueSequence(ULevelSequence* sequence, FCutsceneEndCallback endCallback)
@ -28,107 +28,82 @@ void UCutsceneManager::EnqueueSequence(ULevelSequence* sequence, FCutsceneEndCal
if(!sequence)
return;
FScopeLock lock1(&_sequencesLock);
FScopeLock lock2(&_callbacksLock);
FScopeLock lock1(&sequencesLock);
FScopeLock lock2(&callbacksLock);
if(_endCallbacks.IsEmpty()) // most first sequence, so widgets and binds don't exist
{
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 });
OnFirstCutsceneInit();
auto& mapping = _inputContext.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);
}
}
}
}
_nextSequences.Enqueue(sequence);
_endCallbacks.Enqueue(endCallback);
nextSequences.Enqueue(sequence);
endCallbacks.Enqueue(endCallback);
PlayNextSequence();
}
void UCutsceneManager::PlayNextSequence()
{
if(_sequencePlayer)
if(sequencePlayer)
{
if(_sequencePlayer->IsPlaying())
if(sequencePlayer->IsPlaying())
return;
else
_sequencePlayer->MarkAsGarbage();
sequencePlayer->MarkAsGarbage();
}
FScopeLock lock(&_sequencesLock);
FScopeLock lock(&sequencesLock);
ULevelSequence* sequence;
_nextSequences.Dequeue(sequence);
_sequencePlayer = ULevelSequencePlayer::CreateLevelSequencePlayer(GetWorld(), sequence, FMovieSceneSequencePlaybackSettings{}, _sequencePlayerActor);
_sequencePlayer->OnStop.AddDynamic(this, &UCutsceneManager::OnSequenceEnd);
_sequencePlayer->Play();
nextSequences.Dequeue(sequence);
sequencePlayer = ULevelSequencePlayer::CreateLevelSequencePlayer(GetWorld(), sequence, FMovieSceneSequencePlaybackSettings{}, sequencePlayerActor);
sequencePlayer->OnStop.AddDynamic(this, &UCutsceneManager::OnSequenceEnd);
sequencePlayer->Play();
}
void UCutsceneManager::SkipSequence()
{
if(!_sequencePlayer || !_sequencePlayer->IsPlaying())
if(!sequencePlayer || !sequencePlayer->IsPlaying())
return;
_lastlySkipped = true;
_sequencePlayer->GoToEndAndStop();
lastlySkipped = true;
sequencePlayer->GoToEndAndStop();
}
void UCutsceneManager::ClearQueue()
{
FScopeLock lock1(&_sequencesLock);
FScopeLock lock2(&_callbacksLock);
if(!_nextSequences.IsEmpty())
_nextSequences.Empty();
if(!_endCallbacks.IsEmpty())
_endCallbacks.Empty();
FScopeLock lock1(&sequencesLock);
FScopeLock lock2(&callbacksLock);
if(!nextSequences.IsEmpty())
nextSequences.Empty();
if(!endCallbacks.IsEmpty())
endCallbacks.Empty();
}
void UCutsceneManager::LockCallback(bool lock)
{
_lockCallback = lock;
lockCallback = lock;
}
void UCutsceneManager::OnSequenceEnd()
{
if(_lockCallback)
if(lockCallback)
return;
_sequencePlayer->MarkAsGarbage();
_sequencePlayer = nullptr;
sequencePlayer->MarkAsGarbage();
sequencePlayer = nullptr;
FScopeLock lock(&_callbacksLock);
FScopeLock lock(&callbacksLock);
FCutsceneEndCallback callback;
_endCallbacks.Dequeue(callback);
endCallbacks.Dequeue(callback);
if(callback.IsBound())
callback.Execute();
if(!_nextSequences.IsEmpty())
if(!nextSequences.IsEmpty())
{
PlayNextSequence();
if(_lastlySkipped)
if(lastlySkipped)
{
_lastlySkipped = false;
if(_holding)
lastlySkipped = false;
if(holding)
{
OnInputHold();
}
@ -142,37 +117,63 @@ void UCutsceneManager::OnSequenceEnd()
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();
input->RemoveBindingByHandle(_handlers.Key);
input->RemoveBindingByHandle(_handlers.Value);
input->RemoveBindingByHandle(handlers.Key);
input->RemoveBindingByHandle(handlers.Value);
_lastPlayer = nullptr;
lastPlayer = nullptr;
}
_lastlySkipped = false;
_holding = false;
lastlySkipped = 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()
{
_holding = true;
holding = true;
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->AnimateCutsceneWidget(EInputAnimatedWidgetAnimation::Hold);
}
}
void UCutsceneManager::OnInputUnhold()
{
_holding = false;
holding = false;
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->AnimateCutsceneWidget(EInputAnimatedWidgetAnimation::Unhold);
}
}

View File

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

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary.
#include "DialogueManager.h"
#include "Components/AudioComponent.h"
@ -21,8 +20,8 @@
UDialogueManager::UDialogueManager()
{
static ConstructorHelpers::FObjectFinder<UInputMappingContext> asset{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/IMC_Dialogue.IMC_Dialogue'") };
_inputContext = asset.Object;
ACustomPlayerController::AppendInputContext(_inputContext);
context = asset.Object;
ACustomPlayerController::AppendInputContext(context);
}
void UDialogueManager::PlayDialogue(FDialogueEnqueProperties properties, FDialogueEndCallback endCallback)
@ -43,32 +42,28 @@ void UDialogueManager::PlayDialogue(FDialogueEnqueProperties properties, FDialog
FTimerHandle timer;
int32 timerId;
_timersLock.Lock();
timerId = _timers.Num();
_timers.Add(timer);
_timersLock.Unlock();
timersLock.Lock();
timerId = timers.Num();
timers.Add(timer);
timersLock.Unlock();
UGameplayStatics::PlaySound2D(this, row->wave.LoadSynchronous());
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->ShowDialogueWidget(*row);
}
auto func = [properties = properties,
timerId = timerId,
_timersLock = &_timersLock,
_timers = &_timers,
endCallback = endCallback]()
auto func = [properties,
timerId,
timersLock = &timersLock,
timers = &timers,
endCallback]()
{
FDialogueRow* row = reinterpret_cast<FDialogueRow*>(properties.dialogue.LoadSynchronous()->FindRowUnchecked(properties.rowName));
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->HideDialogueWidget(*row);
}
_timersLock->Lock();
_timers->RemoveAt(timerId);
_timersLock->Unlock();
timersLock->Lock();
timers->RemoveAt(timerId);
timersLock->Unlock();
endCallback.Execute();
};
@ -82,51 +77,30 @@ void UDialogueManager::EnqueDialogue(FDialogueEnqueProperties properties, FDialo
if(!properties.dialogue.LoadSynchronous())
return;
FScopeLock lock1(&_dialoguesLock);
FScopeLock lock2(&_callbacksLock);
FScopeLock lock1(&dialoguesLock);
FScopeLock lock2(&callbacksLock);
if(_endCallbacks.IsEmpty()) // most first dialogue, so widgets and binds don't exist
{
if(auto PC = UGameplayStatics::GetPlayerController(GetWorld(), 0))
{
_lastPlayer = Cast<APlayerBase>(PC->GetPawn());
if(_lastPlayer)
{
auto& mapping = _inputContext.LoadSynchronous()->GetMapping(0);
_inputHandler = ACustomPlayerController::GetInput()->BindAction(mapping.Action, ETriggerEvent::Triggered, this, &UDialogueManager::OnInputPress).GetHandle();
OnFirstDialogueInit();
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
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);
nextDialogues.Enqueue(properties);
endCallbacks.Enqueue(endCallback);
PlayNextDialogue();
}
void UDialogueManager::PlayNextDialogue()
{
_dialoguesLock.Lock();
dialoguesLock.Lock();
auto properties = _nextDialogues.Peek();
auto properties = nextDialogues.Peek();
TArray<FName> rows = properties->dialogue.LoadSynchronous()->GetRowNames();
if(rows.Num() == 0)
{
FDialogueEndCallback callback;
if(_endCallbacks.Dequeue(callback))
if(endCallbacks.Dequeue(callback))
callback.Execute();
_nextDialogues.Pop();
nextDialogues.Pop();
return;
}
@ -140,22 +114,20 @@ void UDialogueManager::PlayNextDialogue()
if(!row)
{
FDialogueEndCallback callback;
_endCallbacks.Dequeue(callback);
endCallbacks.Dequeue(callback);
callback.ExecuteIfBound();
_nextDialogues.Pop();
nextDialogues.Pop();
return;
}
if(properties->playMode == EDialoguePlayMode::Sequential)
if(properties->playMode == EDialoguePlayMode::Sequential
&& !properties->rowName.ToString().IsNumeric())
{
if(!properties->rowName.ToString().IsNumeric())
{
_nextDialogues.Pop();
FDialogueEndCallback callback;
if(_endCallbacks.Dequeue(callback))
callback.Execute();
return;
}
nextDialogues.Pop();
FDialogueEndCallback callback;
if(endCallbacks.Dequeue(callback))
callback.Execute();
return;
}
if(row->wave.LoadSynchronous())
@ -164,9 +136,7 @@ void UDialogueManager::PlayNextDialogue()
leadDialogueAudio = nullptr;
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->ShowDialogueWidget(*row);
}
FTimerHandle timer;
int32 timerId;
@ -174,27 +144,53 @@ void UDialogueManager::PlayNextDialogue()
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();
timersLock.Lock();
timerId = timers.Num();
timers.Add(timer);
timersLock.Unlock();
leadDialogueTimerId = timerId;
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()
{
if(_timers.Num() == 0 || leadDialogueTimerId < 0)
if(timers.Num() == 0 || leadDialogueTimerId < 0)
return;
_timersLock.Lock();
GetWorld()->GetTimerManager().ClearTimer(_timers[leadDialogueTimerId]);
_timers.RemoveAt(leadDialogueTimerId);
timersLock.Lock();
GetWorld()->GetTimerManager().ClearTimer(timers[leadDialogueTimerId]);
timers.RemoveAt(leadDialogueTimerId);
leadDialogueTimerId = -1;
_timersLock.Unlock();
timersLock.Unlock();
if(leadDialogueAudio)
leadDialogueAudio->Stop();
@ -204,25 +200,25 @@ void UDialogueManager::SkipDialogue()
void UDialogueManager::ClearQueue()
{
if(!_nextDialogues.IsEmpty())
_nextDialogues.Empty();
if(!_endCallbacks.IsEmpty())
_endCallbacks.Empty();
if(!nextDialogues.IsEmpty())
nextDialogues.Empty();
if(!endCallbacks.IsEmpty())
endCallbacks.Empty();
}
void UDialogueManager::LockCallback(bool lock)
{
_lockCallback = lock;
lockCallback = lock;
}
void UDialogueManager::BeginDestroy()
{
if(auto world = GetWorld())
{
_timersLock.Lock();
for(auto& timer : _timers)
timersLock.Lock();
for(auto& timer : timers)
world->GetTimerManager().ClearTimer(timer);
_timersLock.Unlock();
timersLock.Unlock();
}
UObject::BeginDestroy();
@ -230,41 +226,35 @@ void UDialogueManager::BeginDestroy()
void UDialogueManager::OnDialogueEnd()
{
_dialoguesLock.Lock();
dialoguesLock.Lock();
FDialogueRow* row = reinterpret_cast<FDialogueRow*>(leadDialogueProperties->dialogue.LoadSynchronous()->FindRowUnchecked(leadDialogueProperties->rowName));
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
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();
_dialoguesLock.Lock();
if(_endCallbacks.IsEmpty() && _lastPlayer)
dialoguesLock.Lock();
if(endCallbacks.IsEmpty() && lastPlayer)
{
ACustomPlayerController::GetInput()->RemoveBindingByHandle(_inputHandler);
_lastPlayer = nullptr;
ACustomPlayerController::GetInput()->RemoveBindingByHandle(inputHandler);
lastPlayer = nullptr;
}
_dialoguesLock.Unlock();
dialoguesLock.Unlock();
}
void UDialogueManager::OnInputPress()
{
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
WM->AnimateDialogueWidget(EInputAnimatedWidgetAnimation::Click);
}
}

View File

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

View File

@ -3,6 +3,7 @@
#include "InCameraInteractableActivator.h"
#include "CommonFunctions.h"
#include "Interactable/Interactable.h"
#include "InteractableScreenCapturer.h"
UInCameraInteractableActivator::UInCameraInteractableActivator(const FObjectInitializer& ObjectInitializer)

View File

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

View File

@ -21,8 +21,6 @@ class UInteractableActivator : public USceneComponent
public:
/** Append itself to CustomGameInstance modificators registry */
virtual void OnRegister() override;
UInteractableActivator(const FObjectInitializer& ObjectInitializer);
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
@ -31,7 +29,7 @@ public:
/** Resets activator state forcing to rescan */
UFUNCTION(BlueprintNativeEvent, BlueprintCallable)
LOST_EDGE_API void Rescan();
virtual void Rescan_Implementation() PURE_VIRTUAL(UInteractableActivator::Scan_Implementation, );
virtual void Rescan_Implementation() {}
FInteractableActivated interactableActivatedDelegate;
FInteractableActivated interactableDeactivatedDelegate;

View File

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

View File

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

View File

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

View File

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

View File

@ -51,7 +51,7 @@ void ALevelBase::IterateToState(int32 to)
void ALevelBase::BroadcastNewLevelBeginPlay()
{
if(auto GI = UCustomGameInstance::GetGameInstance())
if(auto GI = UCustomGameInstance::Get())
GI->OnLevelBeginned.Broadcast(GetFName());
}
@ -72,7 +72,7 @@ void ALevelBase::StartLevelAnimations()
void ALevelBase::ApplySaveData()
{
auto GI = UCustomGameInstance::GetGameInstance();
auto GI = UCustomGameInstance::Get();
if(!GI || !GI->saveData || GI->saveData->level != GetWorld()->GetFName())
return;

View File

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

View File

@ -8,6 +8,11 @@
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()
class AMainGameModeBase : public AGameModeBase
{
@ -18,6 +23,8 @@ public:
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
virtual bool SetPause(APlayerController* PC, FCanUnpause CanUnpauseDelegate = FCanUnpause()) override;
UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Main Game Mode"))
static AMainGameModeBase* Get();
UFUNCTION(BlueprintPure)
static class UWidgetsManager* GetWidgetsManager();
UFUNCTION(BlueprintPure)
@ -46,9 +53,9 @@ protected:
TSubclassOf<class UWidgetsManager> widgetManagerClass;
private:
static AMainGameModeBase* _instance;
static TStrongObjectPtr<class UWidgetsManager> _widgetsManager;
static TStrongObjectPtr<class UCutsceneManager> _cutsceneManager;
static TStrongObjectPtr<class UQuickTimeEventManager> _quickTimeEventManager;
static TStrongObjectPtr<class UDialogueManager> _dialogueManager;
static AMainGameModeBase* instance;
static TStrongObjectPtr<class UWidgetsManager> widgetsManager;
static TStrongObjectPtr<class UCutsceneManager> cutsceneManager;
static TStrongObjectPtr<class UQuickTimeEventManager> quickTimeEventManager;
static TStrongObjectPtr<class UDialogueManager> dialogueManager;
};

View File

@ -10,7 +10,7 @@
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetMathLibrary.h"
#include "CustomGameUserSettings.h"
#include "CustomGameSettings.h"
#include "CustomPlayerController.h"
#include "Interactable/Activators/InteractableActivator.h"
#include "Interactable/Interactable.h"
@ -26,6 +26,10 @@ namespace
APlayerBase::APlayerBase()
: 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;
camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
@ -75,9 +79,8 @@ void APlayerBase::BeginPlay()
cameraManager->ViewPitchMax = maxPitch;
}
auto gameSettings = UCustomGameUserSettings::GetCustomGameUserSettings();
if(camera)
auto gameSettings = UCustomGameSettings::Get();
if(gameSettings && camera)
{
camera->PostProcessSettings.MotionBlurAmount = gameSettings->bUseMotionBlur ? 1.0f : 0.0f;
}
@ -105,7 +108,7 @@ void APlayerBase::LockPlayer(FPlayerLock lock)
inventoryLocked += lock.inventory;
if(interactionLocked)
ResetIntractions();
ResetInteractions();
}
void APlayerBase::UnlockPlayer(FPlayerLock lock)
@ -118,7 +121,7 @@ void APlayerBase::UnlockPlayer(FPlayerLock lock)
inventoryLocked -= lock.inventory;
if(!interactionLocked)
ResetIntractions();
ResetInteractions();
}
void APlayerBase::FlyMode(bool on)
@ -126,7 +129,7 @@ void APlayerBase::FlyMode(bool on)
GetCharacterMovement()->GravityScale = on ? 0.0f : 1.0f;
}
void APlayerBase::ResetIntractions()
void APlayerBase::ResetInteractions()
{
InteractableDeactivated(lastInteractable, static_cast<EActivatorType>(0xFF));
for(auto activator : interactableActivators)
@ -223,9 +226,9 @@ void APlayerBase::LoadInteractablesActivators()
TSet<UClass*> instancedActivators;
for(auto& act : AInteractable::interactionActivators)
{
if(instancedActivators.Contains(act))
if(instancedActivators.Contains(act.Get()))
continue;
instancedActivators.Add(act);
instancedActivators.Add(act.Get());
auto component = NewObject<UInteractableActivator>(this, act);
component->interactableActivatedDelegate.BindUObject(this, &APlayerBase::InteractableActivated);

View File

@ -46,7 +46,7 @@ public:
void LockPlayer(const FPlayerLock lock);
void UnlockPlayer(const FPlayerLock lock);
void FlyMode(bool on);
void ResetIntractions();
void ResetInteractions();
UFUNCTION(BlueprintCallable, Category = Character)
void SwitchToView(class AActor* target);
@ -143,4 +143,6 @@ private:
bool itemDropLocked = false;
FTimerHandle itemDropLockTimer;
TSoftObjectPtr<class UInputMappingContext> context;
};

View File

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

View File

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

View File

@ -1,6 +1,5 @@
// Oleg Petruny proprietary.
#include "QuickTimeEvent.h"
#include "Kismet/GameplayStatics.h"
@ -15,7 +14,7 @@ int32 Event::counter = 0;
Event::Event()
{
_id = counter++;
id = counter++;
}
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()
{
return _id;
return id;
}
void UQuickTimeEventManager::ShowQuickTimeEvent(FQuickTimeEventEnqueProperties properties)
{
UE_LOG(LogTemp, Log, TEXT("ShowQuickTimeEvent Start"));
OnFirstEventInit();
FScopeLock lock1(&_lock);
FScopeLock lock1(&lock);
CreateEvent(properties, false);
UE_LOG(LogTemp, Log, TEXT("ShowQuickTimeEvent End"));
}
@ -46,8 +45,8 @@ void UQuickTimeEventManager::EnqueQuickTimeEvent(FQuickTimeEventEnqueProperties
UE_LOG(LogTemp, Log, TEXT("EnqueQuickTimeEvent Start"));
OnFirstEventInit();
{
FScopeLock lock1(&_lock);
_nextEvents.Enqueue(properties);
FScopeLock lock1(&lock);
nextEvents.Enqueue(properties);
}
ShowNextEvent();
UE_LOG(LogTemp, Log, TEXT("EnqueQuickTimeEvent End"));
@ -56,9 +55,9 @@ void UQuickTimeEventManager::EnqueQuickTimeEvent(FQuickTimeEventEnqueProperties
void UQuickTimeEventManager::ShowNextEvent()
{
UE_LOG(LogTemp, Log, TEXT("ShowNextEvent Start"));
FScopeLock lock1(&_lock);
FScopeLock lock1(&lock);
FQuickTimeEventEnqueProperties properties;
_nextEvents.Dequeue(properties);
nextEvents.Dequeue(properties);
CreateEvent(properties, true);
UE_LOG(LogTemp, Log, TEXT("ShowNextEvent End"));
}
@ -66,9 +65,9 @@ void UQuickTimeEventManager::ShowNextEvent()
void UQuickTimeEventManager::OnEventEnd(int32 id, EQuickTimeEventResult result)
{
UE_LOG(LogTemp, Log, TEXT("OnEventEnd Start"));
FScopeLock lock1(&_lock);
FScopeLock lock1(&lock);
Event event;
if(!_events.RemoveAndCopyValue(id, event))
if(!events.RemoveAndCopyValue(id, event))
return;
GetWorld()->GetTimerManager().ClearTimer(event.timer);
@ -76,14 +75,14 @@ void UQuickTimeEventManager::OnEventEnd(int32 id, EQuickTimeEventResult result)
if(event.callback.IsBound())
event.callback.Execute(result);
if(event.sequence && !_nextEvents.IsEmpty())
if(event.sequence && !nextEvents.IsEmpty())
{
ShowNextEvent();
UE_LOG(LogTemp, Log, TEXT("OnEventEnd End"));
return;
}
if(_events.IsEmpty())
if(events.IsEmpty())
{
if(auto PC = ACustomPlayerController::Get())
{
@ -97,29 +96,29 @@ void UQuickTimeEventManager::OnEventEnd(int32 id, EQuickTimeEventResult result)
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;
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
EQuickTimeEventResult result = EQuickTimeEventResult::Success;
result = WM->ProcessQuickTimeEvent(eventMapping.Key, released);
if(auto WM = AMainGameModeBase::GetWidgetsManager())
switch(result)
{
result = WM->ProcessQuickTimeEvent(eventMapping.Key, released);
switch(result)
{
case EQuickTimeEventResult::FailedKey: // its not a failed key, but special state to do nothing (eg. holding event)
return;
default:
// the result is success or failed time and widget is self removed
break;
}
case EQuickTimeEventResult::FailedKey: // its not a failed key, but special state to do nothing (eg. holding event)
return;
default:
// the result is success or failed time and widget is self removed
break;
}
OnEventEnd(eventMapping.Key, result);
return;
}
OnEventEnd(eventMapping.Key, result);
return;
}
if(released)
@ -127,16 +126,16 @@ void UQuickTimeEventManager::OnInput(const FKey& key, bool released)
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
while(_events.Num() > 0)
while(events.Num() > 0)
{
WM->RemoveQuickTimeEvent(_events.begin()->Key);
OnEventEnd(_events.begin()->Key, EQuickTimeEventResult::FailedKey);
WM->RemoveQuickTimeEvent(events.begin()->Key);
OnEventEnd(events.begin()->Key, EQuickTimeEventResult::FailedKey);
}
}
else
{
while(_events.Num() > 0)
OnEventEnd(_events.begin()->Key, EQuickTimeEventResult::FailedKey);
while(events.Num() > 0)
OnEventEnd(events.begin()->Key, EQuickTimeEventResult::FailedKey);
}
}
@ -152,18 +151,18 @@ void UQuickTimeEventManager::OnInputReleased(FKey key)
void UQuickTimeEventManager::OnFirstEventInit()
{
if(_events.IsEmpty())
if(!events.IsEmpty())
return;
if(auto PC = ACustomPlayerController::Get())
{
if(auto PC = ACustomPlayerController::Get())
{
GetWorld()->GetTimerManager().SetTimerForNextTick([=, this]()
{
PC->onAnyKeyPressed.AddDynamic(this, &UQuickTimeEventManager::OnInputPressed);
PC->onAnyKeyReleased.AddDynamic(this, &UQuickTimeEventManager::OnInputReleased);
});
}
UCommonFunctions::EnterSlowMotion();
GetWorld()->GetTimerManager().SetTimerForNextTick([=, this]()
{
PC->onAnyKeyPressed.AddDynamic(this, &UQuickTimeEventManager::OnInputPressed);
PC->onAnyKeyReleased.AddDynamic(this, &UQuickTimeEventManager::OnInputReleased);
});
}
UCommonFunctions::EnterSlowMotion();
}
void UQuickTimeEventManager::CreateEvent(FQuickTimeEventEnqueProperties& properties, bool sequence)
@ -176,7 +175,7 @@ void UQuickTimeEventManager::CreateEvent(FQuickTimeEventEnqueProperties& propert
result = WM->RemoveQuickTimeEvent(id);
this->OnEventEnd(id, result);
}, properties.duration, false);
_events.Add(event.GetId(), event);
events.Add(event.GetId(), event);
if(auto WM = AMainGameModeBase::GetWidgetsManager())
WM->ShowQuickTimeEvent(event.GetId(), properties);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,6 +9,11 @@
enum class EInputAnimatedWidgetAnimation : 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)
class UWidgetsManager : public UObject
{

View File

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

View File

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