Still working on event handling for hotkey widgets

This commit is contained in:
2025-05-23 15:33:18 -04:00
parent 28f1c4c819
commit 40da211985
32 changed files with 254 additions and 158 deletions

View File

@@ -105,7 +105,7 @@ void UlxAssetLookup::LogMaybeError(bool Error, const TCHAR *Message, const TCHAR
}
}
UStaticMesh *UlxAssetLookup::GetStaticMeshByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound)
UStaticMesh *UlxAssetLookup::LoadStaticMeshAsset(const UObject *Context, const FString &Name, bool ErrorIfNotFound)
{
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(Context);
FString Path = mode->GetAssetLookup()->StaticMeshLoadPath(FName(FString("SM_") + Name));
@@ -124,7 +124,7 @@ UStaticMesh *UlxAssetLookup::GetStaticMeshByName(const UObject *Context, const F
return Result;
}
TSubclassOf<AActor> UlxAssetLookup::GetTangibleClassByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound) {
TSubclassOf<AActor> UlxAssetLookup::LoadTangibleBlueprintAsset(const UObject *Context, const FString &Name, bool ErrorIfNotFound) {
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(Context);
FString Path = mode->GetAssetLookup()->TangibleLoadPath(FName(FString("TAN_") + Name));
if (Path.IsEmpty())
@@ -152,7 +152,7 @@ TSubclassOf<AActor> UlxAssetLookup::GetTangibleClassByName(const UObject *Contex
return Result;
}
TSubclassOf<UUserWidget> UlxAssetLookup::GetWidgetByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound) {
TSubclassOf<UUserWidget> UlxAssetLookup::LoadUserWidgetAsset(const UObject *Context, const FString &Name, bool ErrorIfNotFound) {
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(Context);
FString Path = mode->GetAssetLookup()->WidgetLoadPath(FName(FString("WB_") + Name));
if (Path.IsEmpty())
@@ -168,13 +168,13 @@ TSubclassOf<UUserWidget> UlxAssetLookup::GetWidgetByName(const UObject *Context,
}
if (!Result->IsChildOf(UUserWidget::StaticClass()))
{
LogMaybeError(ErrorIfNotFound, TEXT("Blueprint is not a Widget Blueprint"), *Path);
LogMaybeError(ErrorIfNotFound, TEXT("Blueprint does not derive from UUserWidget"), *Path);
return nullptr;
}
return Result;
}
TSubclassOf<UlxLookAtWidget> UlxAssetLookup::GetLookAtWidgetByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound) {
TSubclassOf<UlxLuaWidget> UlxAssetLookup::LoadLuaWidgetAsset(const UObject *Context, const FString &Name, bool ErrorIfNotFound) {
ALuprexGameModeBase *mode = ALuprexGameModeBase::FromContext(Context);
FString Path = mode->GetAssetLookup()->WidgetLoadPath(FName(FString("WB_") + Name));
if (Path.IsEmpty())
@@ -188,9 +188,9 @@ TSubclassOf<UlxLookAtWidget> UlxAssetLookup::GetLookAtWidgetByName(const UObject
LogMaybeError(ErrorIfNotFound, TEXT("Cannot load widget blueprint"), *Path);
return nullptr;
}
if (!Result->IsChildOf(UlxLookAtWidget::StaticClass()))
if (!Result->IsChildOf(UlxLuaWidget::StaticClass()))
{
LogMaybeError(ErrorIfNotFound, TEXT("Blueprint is not a Luprex Look-At Widget"), *Path);
LogMaybeError(ErrorIfNotFound, TEXT("Blueprint does not derive from UlxLuaWidget"), *Path);
return nullptr;
}
return Result;

View File

@@ -49,18 +49,18 @@ public:
FString WidgetLoadPath(const FName &AssetName) const;
// Get a static mesh by name
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Miscellaneous")
static UStaticMesh *GetStaticMeshByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound = false);
UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context"), Category = "Luprex|Asset Loading")
static UStaticMesh *LoadStaticMeshAsset(const UObject *Context, const FString &Name, bool ErrorIfNotFound = false);
// Get a tangible class by name
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Miscellaneous")
static TSubclassOf<AActor> GetTangibleClassByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound = false);
UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context"), Category = "Luprex|Asset Loading")
static TSubclassOf<AActor> LoadTangibleBlueprintAsset(const UObject *Context, const FString &Name, bool ErrorIfNotFound = false);
// Get a widget blueprint by name
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Miscellaneous")
static TSubclassOf<UUserWidget> GetWidgetByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound = false);
UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context"), Category = "Luprex|Asset Loading")
static TSubclassOf<UUserWidget> LoadUserWidgetAsset(const UObject *Context, const FString &Name, bool ErrorIfNotFound = false);
// Get a look-at widget blueprint by name
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Miscellaneous")
static TSubclassOf<UlxLookAtWidget> GetLookAtWidgetByName(const UObject *Context, const FString &Name, bool ErrorIfNotFound = false);
UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context"), Category = "Luprex|Asset Loading")
static TSubclassOf<UlxLuaWidget> LoadLuaWidgetAsset(const UObject *Context, const FString &Name, bool ErrorIfNotFound = false);
};

View File

@@ -16,6 +16,8 @@ public class Integration : ModuleRules
"Sockets",
"Networking",
"EnhancedInput",
"UMG",
"CommonUI"
});
PrivateDependencyModuleNames.AddRange(new string[] {

View File

@@ -233,12 +233,12 @@ bool UlxLuaCallLibrary::LuaCallProbe(UObject *context, AActor *place, UlxLuaValu
ReturnArray = nullptr;
return false;
}
ElxSuccessOrError Status;
ElxSuccessOrWrongType Status;
FString ErrorMessage;
ReturnArray->ReadString(Status, ErrorMessage);
if (Status != ElxSuccessOrError::Success)
ReturnArray->ReadString(Status, ErrorMessage, false);
if (Status != ElxSuccessOrWrongType::Success)
{
UE_LOG(LogLuprexIntegration, Error, TEXT("corruption in lua_probe"));
UE_LOG(LogLuprexIntegration, Error, TEXT("lua probe should always return an error message (possibly empty) as the first parameter"));
ReturnArray = nullptr;
return false;
}
@@ -408,16 +408,19 @@ FString UlxLuaValues::DebugString() const
return Output.ToString();
}
ElxSuccessOrError UlxLuaValues::CheckType(ElxLuaValueType Type, ElxLuaValueType Desired)
ElxSuccessOrWrongType UlxLuaValues::CheckType(bool LogErrorOnWrongType, ElxLuaValueType Type, ElxLuaValueType Desired)
{
if (Type != Desired)
{
FString TypeName = StaticEnum<ElxLuaValueType>()->GetDisplayNameTextByValue(int64(Type)).ToString();
FString DesiredName = StaticEnum<ElxLuaValueType>()->GetDisplayNameTextByValue(int64(Desired)).ToString();
UE_LOG(LogBlueprint, Error, TEXT("Expected a value of type %s, but found %s instead."), *DesiredName, *TypeName);
return ElxSuccessOrError::Error;
if (LogErrorOnWrongType)
{
FString TypeName = StaticEnum<ElxLuaValueType>()->GetDisplayNameTextByValue(int64(Type)).ToString();
FString DesiredName = StaticEnum<ElxLuaValueType>()->GetDisplayNameTextByValue(int64(Desired)).ToString();
UE_LOG(LogBlueprint, Error, TEXT("Expected a value of type %s, but found %s instead."), *DesiredName, *TypeName);
}
return ElxSuccessOrWrongType::WrongType;
}
return ElxSuccessOrError::Success;
return ElxSuccessOrWrongType::Success;
}
void UlxLuaValues::DiscardBeforeCursor()
@@ -437,40 +440,40 @@ ElxLuaValueType UlxLuaValues::NextType() const
return Types[Cursor];
}
void UlxLuaValues::ReadString(ElxSuccessOrError &Status, FString &Result)
void UlxLuaValues::ReadString(ElxSuccessOrWrongType &Status, FString &Result, bool LogErrorOnMismatch)
{
Status = CheckType(NextType(), ElxLuaValueType::String);
if (Status == ElxSuccessOrError::Error)
Status = CheckType(LogErrorOnMismatch, NextType(), ElxLuaValueType::String);
if (Status == ElxSuccessOrWrongType::WrongType)
{
Result.Empty(); return;
}
Result = FlxStreamBuffer(Data[Cursor++]).read_fstring();
}
void UlxLuaValues::ReadName(ElxSuccessOrError &Status, FName &Result)
void UlxLuaValues::ReadName(ElxSuccessOrWrongType &Status, FName &Result, bool LogErrorOnMismatch)
{
Status = CheckType(NextType(), ElxLuaValueType::Name);
if (Status == ElxSuccessOrError::Error)
Status = CheckType(LogErrorOnMismatch, NextType(), ElxLuaValueType::Name);
if (Status == ElxSuccessOrWrongType::WrongType)
{
Result = FName(); return;
}
Result = FlxStreamBuffer(Data[Cursor++]).read_fname();
}
void UlxLuaValues::ReadFloat(ElxSuccessOrError &Status, double &Result)
void UlxLuaValues::ReadFloat(ElxSuccessOrWrongType &Status, double &Result, bool LogErrorOnMismatch)
{
Status = CheckType(NextType(), ElxLuaValueType::Float);
if (Status == ElxSuccessOrError::Error)
Status = CheckType(LogErrorOnMismatch, NextType(), ElxLuaValueType::Float);
if (Status == ElxSuccessOrWrongType::WrongType)
{
Result = 0.0; return;
}
Result = FlxStreamBuffer(Data[Cursor++]).read_double();
}
void UlxLuaValues::ReadInt(ElxSuccessOrError &Status, int &Result)
void UlxLuaValues::ReadInt(ElxSuccessOrWrongType &Status, int &Result, bool LogErrorOnMismatch)
{
Status = CheckType(NextType(), ElxLuaValueType::Float);
if (Status == ElxSuccessOrError::Error)
Status = CheckType(LogErrorOnMismatch, NextType(), ElxLuaValueType::Float);
if (Status == ElxSuccessOrWrongType::WrongType)
{
Result = 0.0; return;
}
@@ -478,24 +481,24 @@ void UlxLuaValues::ReadInt(ElxSuccessOrError &Status, int &Result)
Result = int(dvalue);
if (double(Result) != dvalue)
{
Result = 0; Status = ElxSuccessOrError::Error; return;
Result = 0; Status = ElxSuccessOrWrongType::WrongType; return;
}
}
void UlxLuaValues::ReadVector(ElxSuccessOrError &Status, FVector &Result)
void UlxLuaValues::ReadVector(ElxSuccessOrWrongType &Status, FVector &Result, bool LogErrorOnMismatch)
{
Status = CheckType(NextType(), ElxLuaValueType::Vector);
if (Status == ElxSuccessOrError::Error)
Status = CheckType(LogErrorOnMismatch, NextType(), ElxLuaValueType::Vector);
if (Status == ElxSuccessOrWrongType::WrongType)
{
Result = FVector(); return;
}
Result = FlxStreamBuffer(Data[Cursor++]).read_fvector();
}
void UlxLuaValues::ReadVector2D(ElxSuccessOrError &Status, FVector2D &Result)
void UlxLuaValues::ReadVector2D(ElxSuccessOrWrongType &Status, FVector2D &Result, bool LogErrorOnMismatch)
{
Status = CheckType(NextType(), ElxLuaValueType::Vector);
if (Status == ElxSuccessOrError::Error)
Status = CheckType(LogErrorOnMismatch, NextType(), ElxLuaValueType::Vector);
if (Status == ElxSuccessOrWrongType::WrongType)
{
Result = FVector2D(); return;
}
@@ -503,10 +506,10 @@ void UlxLuaValues::ReadVector2D(ElxSuccessOrError &Status, FVector2D &Result)
Result = FVector2D(VValue.X, VValue.Y);
}
void UlxLuaValues::ReadBoolean(ElxSuccessOrError &Status, bool &Result)
void UlxLuaValues::ReadBoolean(ElxSuccessOrWrongType &Status, bool &Result, bool LogErrorOnMismatch)
{
Status = CheckType(NextType(), ElxLuaValueType::Boolean);
if (Status == ElxSuccessOrError::Error)
Status = CheckType(LogErrorOnMismatch, NextType(), ElxLuaValueType::Boolean);
if (Status == ElxSuccessOrWrongType::WrongType)
{
Result = false; return;
}

View File

@@ -43,6 +43,12 @@ enum class ElxFoundOrNotFound : uint8 {
NotFound,
};
UENUM(BlueprintType)
enum class ElxSuccessOrWrongType : uint8 {
Success,
WrongType,
};
/////////////////////////////////////////////////////////////////
//
// This is a little parser that parses Lua function 'prototypes'.
@@ -219,9 +225,9 @@ private:
//
void Empty();
// Compare two types. If they aren't equal, log an error and return false.
// Compare two types. If they aren't equal, possibly log an error, and return a status code.
//
static ElxSuccessOrError CheckType(ElxLuaValueType Type, ElxLuaValueType Desired);
static ElxSuccessOrWrongType CheckType(bool LogErrorOnWrongType, ElxLuaValueType Type, ElxLuaValueType Desired);
public:
UlxLuaValues() { Cursor = 0; }
@@ -256,23 +262,23 @@ public:
ElxLuaValueType SwitchNextType() { return NextType(); }
UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "Status"), Category = "Luprex|Lua Value Array")
void ReadString(ElxSuccessOrError &Status, FString &Result);
void ReadString(ElxSuccessOrWrongType &Status, FString &Result, bool LogErrorOnWrongType = false);
UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "Status"), Category = "Luprex|Lua Value Array")
void ReadName(ElxSuccessOrError &Status, FName &Result);
void ReadName(ElxSuccessOrWrongType &Status, FName &Result, bool LogErrorOnWrongType = false);
UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "Status"), Category = "Luprex|Lua Value Array")
void ReadFloat(ElxSuccessOrError &Status, double &Result);
void ReadFloat(ElxSuccessOrWrongType &Status, double &Result, bool LogErrorOnWrongType = false);
UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "Status"), Category = "Luprex|Lua Value Array")
void ReadInt(ElxSuccessOrError &Status, int &Result);
void ReadInt(ElxSuccessOrWrongType &Status, int &Result, bool LogErrorOnWrongType = false);
UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "Status"), Category = "Luprex|Lua Value Array")
void ReadVector(ElxSuccessOrError &Status, FVector &Result);
void ReadVector(ElxSuccessOrWrongType &Status, FVector &Result, bool LogErrorOnWrongType = false);
UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "Status"), Category = "Luprex|Lua Value Array")
void ReadVector2D(ElxSuccessOrError &Status, FVector2D &Result);
void ReadVector2D(ElxSuccessOrWrongType &Status, FVector2D &Result, bool LogErrorOnWrongType = false);
UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "Status"), Category = "Luprex|Lua Value Array")
void ReadBoolean(ElxSuccessOrError &Status, bool &Result);
void ReadBoolean(ElxSuccessOrWrongType &Status, bool &Result, bool LogErrorOnWrongType = false);
};

View File

@@ -426,7 +426,7 @@ void UK2Node_LuaInvoke::ExpandNode(class FKismetCompilerContext& CompilerContext
}
UK2Node_CallFunction *UnpackNode = MakeCallFunctionNode(UnpackingFunc);
ReturnArrayPin->MakeLinkTo(UnpackNode->FindPinChecked(UEdGraphSchema_K2::PN_Self));
CompilerContext.CopyPinLinksToIntermediate(*FindPinChecked(ErrorPinName), *UnpackNode->FindPinChecked(TEXT("Error")));
CompilerContext.CopyPinLinksToIntermediate(*FindPinChecked(ErrorPinName), *UnpackNode->FindPinChecked(TEXT("WrongType")));
CompilerContext.MovePinLinksToIntermediate(*Pin, *UnpackNode->FindPinChecked(TEXT("Result")));
ThenPin->MakeLinkTo(UnpackNode->GetExecPin());
ThenPin = UnpackNode->FindPinChecked(TEXT("Success"));

View File

@@ -349,48 +349,6 @@ ALuprexGameModeBase *ALuprexGameModeBase::FromContext(const UObject *context) {
return result;
}
void ALuprexGameModeBase::ClearLookAtWidget(const UObject *Context)
{
ALuprexGameModeBase *mode = FromContext(Context);
if (mode->LookAtWidget != nullptr)
{
mode->LookAtWidget->RemoveFromParent();
mode->LookAtWidget = nullptr;
}
}
void ALuprexGameModeBase::SetLookAtWidget(const UObject *Context, UlxLookAtWidget *Widget)
{
ALuprexGameModeBase *Mode = FromContext(Context);
if (Mode->LookAtWidget != Widget)
{
ClearLookAtWidget(Context);
}
Mode->LookAtWidget = Widget;
}
UlxLookAtWidget *ALuprexGameModeBase::CreateLookAtWidgetByName(UObject *Context, const FString &BlueprintName,
ElxFoundOrNotFound &Result, bool ErrorIfNotFound, bool AddToViewport, bool SetLookAtWidget)
{
ALuprexGameModeBase *Mode = FromContext(Context);
Result = ElxFoundOrNotFound::NotFound;
auto Blueprint = UlxAssetLookup::GetLookAtWidgetByName(Context, BlueprintName, ErrorIfNotFound);
if (Blueprint == nullptr) return nullptr;
APlayerController *pc = Context->GetWorld()->GetFirstPlayerController();
UlxLookAtWidget *Widget = Cast<UlxLookAtWidget>(UWidgetBlueprintLibrary::Create(Context, Blueprint, pc));
check(Widget != nullptr);
if (AddToViewport)
{
Widget->AddToViewport(100);
}
if (SetLookAtWidget)
{
Mode->SetLookAtWidget(Context, Widget);
}
Result = ElxFoundOrNotFound::Found;
return Widget;
}
void ALuprexGameModeBase::SetLookAt(const UObject *Context, const FHitResult &HitResult)
{
@@ -402,7 +360,6 @@ void ALuprexGameModeBase::SetLookAt(const UObject *Context, const FHitResult &Hi
Mode->CurrentLookAt = HitResult;
}
FVector2D ALuprexGameModeBase::GetLookAtPixel(const UObject *Context)
{
ALuprexGameModeBase *Mode = FromContext(Context);

View File

@@ -13,6 +13,8 @@
#include "TriggeredTask.h"
#include "BlueprintErrors.h"
#include "Blueprint/UserWidget.h"
#include "Widgets/CommonActivatableWidgetContainer.h"
#include "CommonActivatableWidget.h"
#include "LuprexGameModeBase.generated.h"
// Messages that come from inside the Luprex Core.
@@ -25,12 +27,12 @@ class UlxLuaValues;
UCLASS(BlueprintType)
class INTEGRATION_API UlxLookAtWidget : public UUserWidget
class INTEGRATION_API UlxLuaWidget : public UCommonActivatableWidget
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "Luprex|Look-At Detection")
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "Luprex|Miscellaneous")
void ReadLuaConfiguration(UlxLuaValues *Config);
};
@@ -79,36 +81,6 @@ public:
UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"),Category = "Luprex|Look-At Detection")
static FVector2D GetLookAtPixel(const UObject *Context);
UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context"), Category = "Luprex|Look-At Detection")
static void SetLookAtWidget(const UObject *Context, UlxLookAtWidget *Widget);
UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context"), Category = "Luprex|Look-At Detection")
static UlxLookAtWidget *GetLookAtWidget(const UObject *Context) { return FromContext(Context)->LookAtWidget; }
// Create a new Look-At Widget, given the blueprint's name.
//
// The prefix WB_ is added to the blueprint name, and the blueprint is
// searched for in the folder "Widgets".
//
// * If the specified blueprint is not found, execution continues
// on the "Not Found" pin.
//
// * If the flag "Error if Not Found" is true, and the widget blueprint
// is not found, logs an error.
//
// * If the flag "Add to Viewport" is true, the new widget is added
// to the viewport.
//
// * If the flag "Set Look at Widget" is true, the new widget is stored
// as the current look-at widget.
//
UFUNCTION(BlueprintCallable, meta = (ExpandEnumAsExecs = "Result", WorldContext = "Context"), Category = "Luprex|Look-At Detection")
static UlxLookAtWidget *CreateLookAtWidgetByName(UObject *Context, const FString &BlueprintName,
ElxFoundOrNotFound &Result, bool ErrorIfNotFound = true, bool AddToViewport = true, bool SetLookAtWidget = true);
UFUNCTION(BlueprintCallable, meta = (WorldContext = "Context"), Category = "Luprex|Look-At Detection")
static void ClearLookAtWidget(const UObject *Context);
//
// Look-At Related Events
//
@@ -183,9 +155,6 @@ public:
bool MustCallLookAtChanged;
UPROPERTY()
UlxLookAtWidget *LookAtWidget;
// The sensitivity level at which a log message triggers a debugger breakpoint.
UPROPERTY(EditAnywhere, Category="Debugging Tools")
ElxLogVerbosity BreakToDebuggerLogVerbosity;

View File

@@ -0,0 +1,56 @@
#include "StoreFNameInputModifier.h"
#include "EnhancedPlayerInput.h"
#include "LuprexGameModeBase.h"
static const int ENCODE_LIMIT = 0x00FFFFFF;
FInputActionValue UPassFNameAsAxis3D::ModifyRaw_Implementation(const UEnhancedPlayerInput* PlayerInput, FInputActionValue CurrentValue, float DeltaTime)
{
// Internally, an FName is stored as three integers:
// ComparisonIndex, DisplayIndex, and Number. These numbers
// are only valid within a single unreal process, but that's OK.
// We copy these three numbers into an Axis3D.
//
// Yes, that's ugly. It would be nicer if FName was one
// of the types explicitly allowed in an FInputActionValue.
// Maybe some day!
//
// Integers larger than ENCODE_LIMIT cannot be losslessly
// converted to float. Such numbers should never occur in
// practice: the string table should not contain that many
// strings!
//
uint32 cidx = FNameToStore.GetComparisonIndex().ToUnstableInt();
uint32 didx = FNameToStore.GetDisplayIndex().ToUnstableInt();
uint32 nidx = FNameToStore.GetNumber();
// Make sure the three integers will fit into three floats without rounding or overflow.
if ((cidx > ENCODE_LIMIT) || (didx > ENCODE_LIMIT) || (nidx > ENCODE_LIMIT))
{
UE_LOG(LogLuprexIntegration, Error, TEXT("Name cannot be converted to FInputActionValue: %s"), *FNameToStore.ToString());
return FInputActionValue(FVector());
}
return FInputActionValue(FVector(cidx, didx, nidx));
}
FName UPassFNameAsAxis3D::DecodeFNameFromAxis3D(const FVector &Vec)
{
uint32 cidx = static_cast<uint32>(Vec.X);
uint32 didx = static_cast<uint32>(Vec.Y);
uint32 nidx = static_cast<uint32>(Vec.Z);
FName Result(FNameEntryId::FromUnstableInt(cidx), FNameEntryId::FromUnstableInt(didx), nidx);
FName Inverse(FNameEntryId::FromUnstableInt(didx), FNameEntryId::FromUnstableInt(cidx), nidx);
if ((double(cidx) != Vec.X) || (double(didx) != Vec.Y) || (double(nidx) != Vec.Z) ||
(cidx > ENCODE_LIMIT) || (didx > ENCODE_LIMIT) || (nidx > ENCODE_LIMIT) ||
(!Result.IsValid()) || (!Inverse.IsValid()))
{
UE_LOG(LogLuprexIntegration, Error, TEXT("FVector is not an encoded FName."));
return NAME_None;
}
return Result;
}

View File

@@ -0,0 +1,54 @@
#pragma once
#include "CoreMinimal.h"
#include "InputModifiers.h"
#include "StoreFNameInputModifier.generated.h"
/**
* @brief Allows you to pass an FName into an event handler.
*
* This modifier allows you to type an FName directly into an input mapping in
* the InputMappingContext editor, and have that FName passed through to an
* enhanced input handler.
*
* This modifier has an FName UPROPERTY which is editable in the InputMappingContext
* editor. At runtime, it encodes the FName as an Axis3D. In the event handler,
* the Axis3D can be decoded back into an FName using DecodeFNameFromAxis3D.
*
* One use for this modifier is when you want to know exactly which
* keyboard key triggered an EnhancedInput event. You can put the key's FName
* into the InputMappingContext, and it will get passed through to the event
* handler.
*
*/
UCLASS()
class INTEGRATION_API UPassFNameAsAxis3D : public UInputModifier
{
GENERATED_BODY()
public:
/**
* @brief The FName to be encoded into the FInputActionValue.
*
* This property can be configured in the Input Mapping Context editor
* for each specific mapping.
*
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Modifier Settings")
FName FNameToStore;
protected:
virtual FInputActionValue ModifyRaw_Implementation(const UEnhancedPlayerInput* PlayerInput, FInputActionValue CurrentValue, float DeltaTime) override;
/**
* @brief Decodes an FName that was passed by the PassFnameAsAxis3D modifier.
*
* This function is used in an enhanced input event, where the PassFNameAsAxis3D
* modifier was used to pass an FName into the event. The value shows up as
* an Axis3D, which much be decoded back into an FName.
*
*/
UFUNCTION(BlueprintPure, Category = "Input|Enhanced")
static FName DecodeFNameFromAxis3D(const FVector& Encoded);
};

View File

@@ -33,10 +33,10 @@ void UlxTangible::SetActorBlueprint(const FString &XName) {
}
// Get the blueprint.
UClass *blueprint = UlxAssetLookup::GetTangibleClassByName(this, Name);
UClass *blueprint = UlxAssetLookup::LoadTangibleBlueprintAsset(this, Name);
if (blueprint == nullptr)
{
blueprint = UlxAssetLookup::GetTangibleClassByName(this, DEFAULT_BLUEPRINT);
blueprint = UlxAssetLookup::LoadTangibleBlueprintAsset(this, DEFAULT_BLUEPRINT);
check(blueprint != nullptr);
}

View File

@@ -8,6 +8,8 @@
#include "Kismet/GameplayStatics.h"
#include "Blueprint/UserWidget.h"
#include "Components/GridPanel.h"
#include "InputMappingContext.h"
#define LOCTEXT_NAMESPACE "Luprex Utility"
@@ -209,3 +211,21 @@ void UlxUtilityLibrary::GetPositionOfGridPanelMiddleCell(UGridPanel *GridPanel,
LowerRightXY.Y = (Row[0] + Row[1]) / TotalY;
}
}
void UlxUtilityLibrary::MapAllKeyboardKeysToOneInputAction(UInputMappingContext *IMC, UInputAction *Action)
{
TArray<FKey> AllKeys;
EKeys::GetAllKeys(AllKeys);
// Map every keyboard key to the provided LuaAction
for (const FKey& Key : AllKeys)
{
if ((Key.IsValid()) &&
(Key.IsBindableInBlueprints()) &&
(Key.GetMenuCategory() == EKeys::NAME_KeyboardCategory) &&
(!Key.IsModifierKey()))
{
IMC->MapKey(Action, Key);
}
}
}

View File

@@ -132,4 +132,13 @@ public:
UFUNCTION(BlueprintPure, Category="Widget")
static void GetPositionOfGridPanelMiddleCell(UGridPanel *GridPanel, FVector2D &UpperLeftXY, FVector2D &LowerRightXY);
// Create a mapping context that maps all keyboard keys to a single input action.
//
// This mapping context is usually meant to be used in conjunction with a
// hand-crafted mapping context, to act as a catch-all that catches all
// keys that aren't mapped in the hand-crafted mapping.
//
UFUNCTION(BlueprintCallable, Category="Input", meta=(WorldContext="WorldContextObject"))
static void MapAllKeyboardKeysToOneInputAction(UInputMappingContext *IMC, UInputAction *Action);
};