Level3 #11

Merged
oleg.petruny merged 7 commits from Level3 into master 2025-02-07 13:45:00 +00:00
102 changed files with 422 additions and 156 deletions
Showing only changes of commit 5b44c8ad18 - Show all commits

BIN
Audio/Sounds/Click.wav Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Audio/Sounds/ServerFans.wav Normal file

Binary file not shown.

4
Audio/Sounds/source.txt Normal file
View File

@ -0,0 +1,4 @@
Click - https://freesound.org/people/ccr_fs/sounds/484719/
ElectricTransform - https://freesound.org/people/ShahruhAudio/sounds/336881/
ElectricZap - https://freesound.org/people/egomassive/sounds/536741/
ServerFans - https://freesound.org/people/Nox_Sound/sounds/465613/

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
UnrealProject/Lost_Edge/Content/Audio/Sounds/SW_Click.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -105,6 +105,16 @@ FWorldDilationChangedDelegate& UCommonFunctions::GetWorldDilationChangedDelegate
return SlowMotion::worldDilationChangedDelegate;
}
FIntByteView UCommonFunctions::MakeIntByteView(const int32 in)
{
return FIntByteView::Make(in);
}
int32 UCommonFunctions::IntByteViewAsInt(const FIntByteView in)
{
return in.AsInt();
}
TArray<FString> UCommonFunctions::IntArrayToStringArray(const TArray<int32>& in)
{
TArray<FString> result;
@ -161,6 +171,16 @@ TArray<FIntPoint> UCommonFunctions::StringArrayToIntPointArray(const TArray<FStr
return MoveTemp(result);
}
bool UCommonFunctions::ColorEquals(const FColor a, const FColor b)
{
return a == b;
}
uint8& UCommonFunctions::ByteIncerement(uint8& var)
{
return ++var;
}
int32 UCommonFunctions::GetLongestCharCount(TArray<FString>& in)
{
int32 result = 0;
@ -204,3 +224,18 @@ void UCommonFunctions::SlowMotionTick()
world->GetTimerManager().ClearTimer(SlowMotion::timer);
}
}
FIntByteView FIntByteView::Make(const int32 in)
{
FIntByteView result;
*reinterpret_cast<int32*>(&result) = in;
return result;
}
int32 FIntByteView::AsInt() const
{
int32 result;
// in standard, [this] not always points to the object beginning, so we use the address to the first member
result = *reinterpret_cast<const int32*>(&first);
return result;
}

View File

@ -3,11 +3,31 @@
#pragma once
#include "Kismet/BlueprintFunctionLibrary.h"
#include "Math/Color.h"
#include "CommonFunctions.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FWorldDilationChangedDelegate, float, newDilation);
USTRUCT(BlueprintType)
struct FIntByteView
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
uint8 first;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
uint8 second;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
uint8 third;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
uint8 fourth;
static FIntByteView Make(const int32 in);
int32 AsInt() const;
};
/**
* Collection of common/universal/without own scope/specific functions.
*/
@ -44,6 +64,12 @@ public:
UFUNCTION(BlueprintPure, Category = TypeCasts)
static FIntByteView MakeIntByteView(const int32 in);
UFUNCTION(BlueprintPure)
static int32 IntByteViewAsInt(const FIntByteView in);
UFUNCTION(BlueprintPure, Category = TypeCasts)
static TArray<FString> IntArrayToStringArray(const TArray<int32>& in);
UFUNCTION(BlueprintPure, Category = TypeCasts)
@ -62,6 +88,14 @@ public:
// like wtf this isn't in the engine?
UFUNCTION(BlueprintPure, Category = "Color|Operators", meta = (DisplayName = "Equal", CompactNodeTitle = "=="))
static bool ColorEquals(const FColor a, const FColor b);
UFUNCTION(BlueprintCallable, Category = "Byte|Operators", meta = (DisplayName = "Increment", CompactNodeTitle = "++"))
static UPARAM(ref) uint8& ByteIncerement(UPARAM(ref) uint8& var);
UFUNCTION(BlueprintPure, Category = String)
static int32 GetLongestCharCount(UPARAM(ref) TArray<FString>& in);

View File

@ -65,7 +65,7 @@ void UDialogueManager::PlayDialogue(FDialogueEnqueProperties properties, FDialog
timers->RemoveAt(timerId);
timersLock->Unlock();
endCallback.Execute();
endCallback.ExecuteIfBound();
};
float duration = row->wave ? row->wave->GetDuration() : row->duration;
@ -90,17 +90,15 @@ void UDialogueManager::EnqueDialogue(FDialogueEnqueProperties properties, FDialo
void UDialogueManager::PlayNextDialogue()
{
dialoguesLock.Lock();
FScopeLock lock1(&dialoguesLock);
FScopeLock lock2(&callbacksLock);
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();
QueueEnded();
return;
}
@ -113,20 +111,14 @@ void UDialogueManager::PlayNextDialogue()
if(!row)
{
FDialogueEndCallback callback;
endCallbacks.Dequeue(callback);
callback.ExecuteIfBound();
nextDialogues.Pop();
QueueEnded();
return;
}
if(properties->playMode == EDialoguePlayMode::Sequential
&& !properties->rowName.ToString().IsNumeric())
{
nextDialogues.Pop();
FDialogueEndCallback callback;
if(endCallbacks.Dequeue(callback))
callback.Execute();
QueueEnded();
return;
}
@ -151,8 +143,6 @@ void UDialogueManager::PlayNextDialogue()
leadDialogueTimerId = timerId;
leadDialogueProperties = properties;
dialoguesLock.Unlock();
}
void UDialogueManager::OnFirstDialogueInit() // most first dialogue, so widgets and binds don't exist
@ -181,6 +171,15 @@ void UDialogueManager::OnFirstDialogueInit() // most first dialogue, so widgets
}
}
void UDialogueManager::QueueEnded()
{
nextDialogues.Pop();
leadDialogueProperties = nullptr;
FDialogueEndCallback callback;
if(endCallbacks.Dequeue(callback))
callback.ExecuteIfBound();
}
void UDialogueManager::SkipDialogue()
{
if(timers.Num() == 0 || leadDialogueTimerId < 0)
@ -188,8 +187,6 @@ void UDialogueManager::SkipDialogue()
timersLock.Lock();
GetWorld()->GetTimerManager().ClearTimer(timers[leadDialogueTimerId]);
timers.RemoveAt(leadDialogueTimerId);
leadDialogueTimerId = -1;
timersLock.Unlock();
if(leadDialogueAudio)
@ -226,6 +223,10 @@ void UDialogueManager::BeginDestroy()
void UDialogueManager::OnDialogueEnd()
{
timersLock.Lock();
timers.RemoveAt(leadDialogueTimerId);
timersLock.Unlock();
dialoguesLock.Lock();
FDialogueRow* row = reinterpret_cast<FDialogueRow*>(leadDialogueProperties->dialogue.LoadSynchronous()->FindRowUnchecked(leadDialogueProperties->rowName));
@ -233,24 +234,26 @@ void UDialogueManager::OnDialogueEnd()
if(auto WM = AMainGameModeBase::GetWidgetsManager())
WM->HideDialogueWidget(*row);
if(leadDialogueProperties->playMode == EDialoguePlayMode::Sequential
&& leadDialogueProperties->rowName.ToString().IsNumeric())
if(leadDialogueProperties->playMode == EDialoguePlayMode::Sequential && !endCallbacks.IsEmpty())
{
leadDialogueProperties->rowName = FName(FString::FromInt(FCString::Atoi(*(leadDialogueProperties->rowName.ToString())) + 1));
}
dialoguesLock.Unlock();
if(!endCallbacks.IsEmpty())
dialoguesLock.Unlock();
PlayNextDialogue();
dialoguesLock.Lock();
if(endCallbacks.IsEmpty() && lastPlayer)
{
ACustomPlayerController::GetInput()->RemoveBindingByHandle(inputHandler);
lastPlayer = nullptr;
}
dialoguesLock.Unlock();
else
{
dialoguesLock.Unlock();
}
{
FScopeLock lock1(&dialoguesLock);
FScopeLock lock2(&callbacksLock);
if(endCallbacks.IsEmpty() && lastPlayer)
{
ACustomPlayerController::GetInput()->RemoveBindingByHandle(inputHandler);
lastPlayer = nullptr;
}
}
}
void UDialogueManager::OnInputPress()

View File

@ -90,6 +90,7 @@ protected:
private:
void PlayNextDialogue();
void OnFirstDialogueInit();
void QueueEnded();
UFUNCTION()
void OnDialogueEnd();

View File

@ -86,7 +86,10 @@ void AInteractable::BeginPlay()
switch(modificatorActivatorTypes & static_cast<uint8>(EActivatorType::Use))
{
case static_cast<uint8>(EActivatorType::Use):
modificators.Add({ EActivatorType::Use, modificator });
if(modificators.Contains(EActivatorType::Use))
modificators[EActivatorType::Use].modificators.Add(modificator);
else
modificators.Add({ EActivatorType::Use, FModificatorsArray{TArray<UInteractableModificator*>{modificator}} });
break;
default:
break;
@ -94,7 +97,10 @@ void AInteractable::BeginPlay()
switch(modificatorActivatorTypes & static_cast<uint8>(EActivatorType::Saw))
{
case static_cast<uint8>(EActivatorType::Saw):
modificators.Add({ EActivatorType::Saw, modificator });
if(modificators.Contains(EActivatorType::Saw))
modificators[EActivatorType::Saw].modificators.Add(modificator);
else
modificators.Add({ EActivatorType::Saw, FModificatorsArray{TArray<UInteractableModificator*>{modificator}} });
break;
default:
break;
@ -149,18 +155,16 @@ void AInteractable::Activate(EActivatorType type)
if(!player
|| modificators.IsEmpty()
|| !modificators.Contains(type)
|| !activationLockers.IsEmpty())
return;
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
for(const auto& modificator : modificators)
for(const auto& modificator : modificators[type].modificators)
{
if(static_cast<uint8>(modificator.Value->GetActivatorTypes()) & static_cast<uint8>(type))
{
WM->ShowInteractionHints(modificator.Value);
modificator.Value->Bind(ACustomPlayerController::GetInput());
}
WM->ShowInteractionHints(modificator);
modificator->Bind(ACustomPlayerController::GetInput());
}
}
@ -184,18 +188,16 @@ void AInteractable::Deactivate(EActivatorType type)
if(!player
|| modificators.IsEmpty()
|| !modificators.Contains(type)
|| !activationLockers.IsEmpty())
return;
if(auto WM = AMainGameModeBase::GetWidgetsManager())
{
for(const auto& modificator : modificators)
for(const auto& modificator : modificators[type].modificators)
{
if(static_cast<uint8>(modificator.Key) & static_cast<uint8>(type))
{
WM->HideInteractionHints(modificator.Value);
modificator.Value->Unbind();
}
WM->HideInteractionHints(modificator);
modificator->Unbind();
}
}
@ -211,3 +213,16 @@ void AInteractable::Deactivate(EActivatorType type)
OnDeactivate(type);
}
void AInteractable::Lock()
{
activationLockers.Empty();
for(int32 i = 1; i < 255; i <<= 1)
Deactivate(static_cast<EActivatorType>(i));
activationLockers.Add(nullptr);
}
void AInteractable::Unlock()
{
activationLockers.Empty();
}

View File

@ -62,6 +62,12 @@ public:
UFUNCTION(BlueprintCallable)
void Deactivate(EActivatorType type);
/** Locks any interactions and deactivates active activators if needed until Unlock() is called */
UFUNCTION(BlueprintCallable)
void Lock();
UFUNCTION(BlueprintCallable)
void Unlock();
/**
* All modificators that requires (de)activation lock for current interactable.
* Used manually by modificators to handle operations which can be continued after physical deactivation.
@ -82,9 +88,14 @@ protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (Bitmask, BitmaskEnum = "EActivatorType"))
int32 activated = 0;
/** TArray cannot be a value of a TMap */
struct FModificatorsArray
{
TArray<class UInteractableModificator*> modificators;
};
/** Map of modificators to activator types initialized on BeginPlay */
UPROPERTY()
TMap<EActivatorType, class UInteractableModificator*> modificators;
TMap<EActivatorType, FModificatorsArray> modificators;
TArray<UPrimitiveComponent*> collisions;
class APlayerBase* player = nullptr;

View File

@ -23,16 +23,21 @@ UMoveInteractableModificator::UMoveInteractableModificator(const FObjectInitiali
static ConstructorHelpers::FObjectFinder<UInputMappingContext> asset{ TEXT("/Script/EnhancedInput.InputMappingContext'/Game/Input/Interactables/IMC_InteractableMove.IMC_InteractableMove'") };
inputMapping = asset.Object;
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.bStartWithTickEnabled = false;
PrimaryComponentTick.TickGroup = ETickingGroup::TG_PostUpdateWork;
}
void UMoveInteractableModificator::OnRegister()
{
Super::OnRegister();
actor = Cast<AInteractable>(GetOwner());
if(actor)
{
shape = FCollisionShape::MakeBox(actor->GetComponentsBoundingBox().GetExtent());
primitive = actor->GetComponentByClass<UPrimitiveComponent>();
}
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.bStartWithTickEnabled = false;
PrimaryComponentTick.TickGroup = ETickingGroup::TG_PostUpdateWork;
}
void UMoveInteractableModificator::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
@ -47,9 +52,6 @@ void UMoveInteractableModificator::Bind_Implementation(class UEnhancedInputCompo
if(!input && !inputMapping)
return;
if(holding || rotating)
return;
for(auto& mapping : inputMapping->GetMappings())
{
if(mapping.Key == EKeys::LeftMouseButton)
@ -90,15 +92,20 @@ void UMoveInteractableModificator::Unbind_Implementation()
if(!lastInput || bindindingHandlers.IsEmpty())
return;
if(holding || rotating)
return;
for(auto handle : bindindingHandlers)
lastInput->RemoveBindingByHandle(handle);
bindindingHandlers.Empty();
SetComponentTickEnabled(false);
actor->Deactivate(GetActivatorTypes());
if(indicating)
{
indicating = false;
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 0, EInputAnimatedWidgetAnimation::TurnOffIndication);
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 1, EInputAnimatedWidgetAnimation::TurnOffIndication);
}
if(rotating)
player->UnlockPlayer({ .camera = true });
OnMoveDeactivated.Broadcast();
}
@ -160,15 +167,11 @@ void UMoveInteractableModificator::ProcessState()
else
{
actor->activationLockers.Remove(this);
if(indicating)
{
indicating = false;
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 0, EInputAnimatedWidgetAnimation::TurnOffIndication);
}
if((actor->GetActivatedFlags() & static_cast<int32>(GetActivatorTypes())) == 0
&& !bindindingHandlers.IsEmpty())
{
Unbind_Implementation();
actor->Deactivate(GetActivatorTypes());
}
}
}
@ -193,8 +196,8 @@ void UMoveInteractableModificator::UpdatePosition()
{
indicating = true;
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 0, EInputAnimatedWidgetAnimation::TurnOnIndication);
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 1, EInputAnimatedWidgetAnimation::TurnOnIndication);
}
return;
}
else
{
@ -202,6 +205,7 @@ void UMoveInteractableModificator::UpdatePosition()
{
indicating = false;
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 0, EInputAnimatedWidgetAnimation::TurnOffIndication);
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 1, EInputAnimatedWidgetAnimation::TurnOffIndication);
}
}
@ -239,10 +243,25 @@ void UMoveInteractableModificator::Rotating(const FInputActionValue& axis)
auto v = axis.Get<FVector>();
auto dir = player->GetCameraDirection();
auto addRot = FRotator{ v.Y * dir.X, v.X, v.Y * dir.Y * -1 };
auto newRot = (addRot.Quaternion() * actor->GetActorQuat()).Rotator();
// rotation sweep is unsupported for some reason
// if(MoveIsBlocked(actor->GetActorLocation(), newRot.Quaternion()))
// return;
auto newQuat = addRot.Quaternion() * actor->GetActorQuat();
auto newRot = newQuat.Rotator();
if(MoveIsBlocked(actor->GetActorLocation(), newQuat) && positionUpdateType != PositionUpdateType::Physics)
{
if(!indicating)
{
indicating = true;
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 0, EInputAnimatedWidgetAnimation::TurnOnIndication);
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 1, EInputAnimatedWidgetAnimation::TurnOnIndication);
}
else if(!indicating)
{
indicating = false;
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 0, EInputAnimatedWidgetAnimation::TurnOffIndication);
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 1, EInputAnimatedWidgetAnimation::TurnOffIndication);
}
return;
}
if(player->nearScanner->ComponentOverlapComponent(primitive, actor->GetActorLocation(), newRot, {})
|| player->feetScanner->ComponentOverlapComponent(primitive, actor->GetActorLocation(), newRot, {}))
@ -254,7 +273,7 @@ void UMoveInteractableModificator::Rotating(const FInputActionValue& axis)
player->physicsHandle->SetTargetRotation(newRot);
break;
default:
actor->SetActorRotation(newRot, ETeleportType::None);
actor->SetActorLocationAndRotation(actor->GetActorLocation(), newQuat, true, nullptr, ETeleportType::None);
break;
}
}

View File

@ -22,7 +22,8 @@ class UMoveInteractableModificator : public UInteractableModificator
public:
UMoveInteractableModificator(const FObjectInitializer& ObjectInitializer);
void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
virtual void OnRegister() override;
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
void Bind_Implementation(class UEnhancedInputComponent* input) override;
void Unbind_Implementation() override;

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