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

@@ -1,3 +1,5 @@
[/Script/Engine.Engine]
+ActiveClassRedirects=(OldClassName="/Script/Integration.lxLookAtWidget",NewClassName="/Script/Integration.lxLuaWidget")
[/Script/EngineSettings.GameMapsSettings]

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.

BIN
Content/Widgets/WB_Root.uasset LFS Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -22,6 +22,10 @@
"TargetAllowList": [
"Editor"
]
},
{
"Name": "CommonUI",
"Enabled": true
}
]
}

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);
};

View File

@@ -21,11 +21,13 @@ end
function cube.lookhotkeys(keys)
keys:add("X", "Cube Hi", function () dprint("Cube Hi") end)
keys:add("A", "Cube Bye", function () dprint("Cube Bye") end)
keys:add("Y", "Cube Yo", function () dprint("Cube Yo") end)
end
function sphere.lookhotkeys(keys)
keys:add("X", "Sphere Hi", function () dprint("Sphere Hi") end)
keys:add("A", "Sphere Bye", function () dprint("Sphere Bye") end)
keys:add("Y", "Sphere Yo", function () dprint("Sphere Yo") end)
end